diff --git a/Makefile b/Makefile
index 5080823..24813c5 100644
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,7 @@ flake8:
 .PHONY: coverage
 coverage:
 	coverage erase
-	tox -e coverage,coverage3
+	tox -p auto -e coverage,coverage3
 	coverage combine
 	coverage report -m --fail-under=100
 
diff --git a/setup.cfg b/setup.cfg
index 7c2b13f..8c168c8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -6,6 +6,20 @@ extend-ignore = E126,E501,E261,E226
 # E261: at least two spaces before inline comment
 # E226: missing whitespace around arithmetic operator
 
+[isort]
+# from X import (
+#   a,
+#   b,
+# )
+multi_line_output = 3
+include_trailing_comma = true
+lines_after_imports = 2
+reverse_relative = true
+default_section = THIRDPARTY
+known_first_party = pov_server_page
+# known_third_party = pytest, ...
+# skip = filename...
+
 [tool:pytest]
 testpaths = tests
 addopts = -ra
diff --git a/src/pov_server_page/update_ports_html.py b/src/pov_server_page/update_ports_html.py
index 573671b..6390564 100755
--- a/src/pov_server_page/update_ports_html.py
+++ b/src/pov_server_page/update_ports_html.py
@@ -4,6 +4,7 @@ Update TCP & UDP port assignments page in /var/www/HOSTNAME/ports/index.html.
 """
 
 import io
+import logging
 import optparse
 import os
 import pwd
@@ -25,6 +26,9 @@ __version__ = '0.10.1'
 __author__ = 'Marius Gedminas <marius@gedmin.as>'
 
 
+log = logging.getLogger(__name__)
+
+
 HOSTNAME = socket.getfqdn()
 OUTPUT = "/var/www/${hostname}/ports/index.html"
 
@@ -95,42 +99,68 @@ def pipe(*command):
 
 def netstat():
     with pipe('netstat', '-tunlvp') as f:
+        failures = []
         for line in f:
             if line.rstrip() == 'Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name':
                 break
+            failures.append(line)
+        else:
+            log.warning('Failed to find expected netstat header in\n%s'
+                        % ''.join(failures))
+            return
+        header = line
+        failures = []
         for line in f:
-            parts = line.split()
+            columns = 7 if line.startswith('tcp') else 6
+            parts = line.split(None, columns - 1)
+            if len(parts) != columns:
+                failures.append(line)
+                continue
             proto = parts[0]
             local_addr = parts[3]
             if proto in ('tcp', 'tcp6'):
                 state = parts[5]
-                pid_program = parts[6]
             else:
                 state = None
-                pid_program = parts[5]
+            pid_program = parts[-1].rstrip()
             if proto in ('tcp', 'tcp6') and state != 'LISTEN':
                 continue
-            ip, port = local_addr.rsplit(':', 1)
-            if '/' in pid_program:
-                pid, program = pid_program.split('/', 1)
-                pid = int(pid)
-            else:
-                pid = None
-                program = pid_program
+            try:
+                ip, port = local_addr.rsplit(':', 1)
+                if '/' in pid_program:
+                    pid, program = pid_program.split('/', 1)
+                    pid = int(pid)
+                else:
+                    pid = None
+                    program = pid_program
+            except ValueError:
+                failures.append(line)
+                continue
             yield NetStatTuple(proto, ip, int(port), pid, program)
+    if failures:
+        log.warning('Failed to parse netstat output:\n%s'
+                    % ''.join([header] + failures))
 
 
 def rpcinfo_dump():
     with pipe('rpcinfo', '-p') as f:
+        header = next(f)  # skip header
+        failures = []
         for line in f:
             # line is 'program vers proto port service'
             parts = line.split()
-            if not parts or parts[0] == 'program':
+            if not parts:
+                continue
+            if len(parts) not in (4, 5):
+                failures.append(line)
                 continue
             proto = parts[2]
             port = parts[3]
             program = parts[4] if len(parts) > 4 else '-'
             yield NetStatTuple(proto, None, int(port), None, program)
+    if failures:
+        log.warning('Failed to parse rpcinfo output:\n%s'
+                    % ''.join([header] + failures))
 
 
 def merge_portmap_data(mapping, pmap_list, open_ports_only=False):
@@ -141,20 +171,28 @@ def merge_portmap_data(mapping, pmap_list, open_ports_only=False):
 
 def systemctl_list_sockets():
     with pipe('systemctl', 'list-sockets', '--show-types') as f:
-        header = next(f)
+        header = next(f).rstrip()
         cols = [0] + [m.start() + 1 for m in re.finditer(r' [^ ]', header)] + [None]
-        cols = [slice(cols[i], cols[i + 1]) for i in range(len(cols) - 1)]
+        cols = [slice(col, nextcol) for col, nextcol in zip(cols, cols[1:])]
+        failures = []
         for line in f:
             line = line.rstrip()
             if not line:
                 break
             parts = [line[col].rstrip() for col in cols]
-            listen, type_, unit, activates = parts
-            proto = {'Stream': 'tcp', 'Datagram': 'udp'}.get(type_)
-            if not proto or ':' not in listen:
+            try:
+                listen, type_, unit, activates = parts
+                proto = {'Stream': 'tcp', 'Datagram': 'udp'}.get(type_)
+                if not proto or ':' not in listen:
+                    continue
+                ip, port = listen.rsplit(':', 1)
+            except ValueError:
+                failures.append(line)
                 continue
-            ip, port = listen.rsplit(':', 1)
             yield NetStatTuple(proto, ip, int(port), None, unit)
+    if failures:
+        log.warning('Failed to parse systemctl list-sockets output:\n%s'
+                    % '\n'.join([header] + failures))
 
 
 def get_owner(pid):
@@ -253,9 +291,10 @@ def get_port_mapping():
     if ('tcp', 111) in mapping: # portmap is used
         portmap_data = list(rpcinfo_dump())
         merge_portmap_data(mapping, portmap_data)
-    # XXX: if I switch from netstat to ss, then data.progam is no longer
+    # XXX: if I switch from netstat to ss, then data.program is no longer
     # available and this check will fail.  Maybe I should just unconditionally
-    # run systemctl_list_sockets()?
+    # run systemctl_list_sockets()?  or maybe I should check the existence
+    # of /run/systemd/system/
     if any(data.pid == 1 and data.program == 'systemd'
            for plist in mapping.values() for data in plist):
         systemd_sockets = list(systemctl_list_sockets())
@@ -336,7 +375,14 @@ def render_file(netstat_mapping, output, hostname=HOSTNAME):
         f.write(render_html(netstat_mapping, hostname=hostname))
 
 
+def init_logging():
+    root = logging.getLogger()
+    root.setLevel(logging.INFO)
+    root.addHandler(logging.StreamHandler())
+
+
 def main():
+    init_logging()
     parser = optparse.OptionParser(usage='usage: %prog [options]',
                                    version=__version__)
     parser.add_option('-H', '--hostname', default=HOSTNAME,
diff --git a/src/pov_server_page/update_server_page.py b/src/pov_server_page/update_server_page.py
index 69f898c..503a51a 100755
--- a/src/pov_server_page/update_server_page.py
+++ b/src/pov_server_page/update_server_page.py
@@ -20,9 +20,10 @@ file with htpasswd, enable the site with a2ensite and restart Apache::
 
 import datetime
 import errno
-import io
 import glob
 import grp
+import io
+import logging
 import optparse
 import os
 import pwd
@@ -658,7 +659,14 @@ class Builder(object):
             print("Please run service apache2 reload")
 
 
+def init_logging():
+    root = logging.getLogger()
+    root.setLevel(logging.INFO)
+    root.addHandler(logging.StreamHandler())
+
+
 def main():
+    init_logging()
     # Command-line options
     description = "Generate Apache configuration for a server page"
     parser = optparse.OptionParser('usage: %prog [options] [var=value ...]',
diff --git a/src/pov_server_page/utils.py b/src/pov_server_page/utils.py
index 8397ed1..ff68f22 100644
--- a/src/pov_server_page/utils.py
+++ b/src/pov_server_page/utils.py
@@ -47,8 +47,8 @@ COLORS = [
     for b in [0] + list(range(95, 256, 40))
 ] + [
     # 24 greyscale levels
-    '#%02x%02x%02x' % (l, l, l)
-    for l in range(8, 248, 10)
+    '#%02x%02x%02x' % (i, i, i)
+    for i in range(8, 248, 10)
 ]
 
 

ValueError in update-ports failure on Ubuntu 20.04 LTS
I've seen this on two machines.  After upgrading to Ubuntu 20.04 LTS (which removes pov-server-page), but before rebooting I do

```
# apt install pov-server-page
...
Tvarkomas paketas pov-server-page (1.8.5) ...
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pov_server_page/update_server_page.py", line 697, in main
    builder.build(verbose=opts.verbose, quick=opts.quick)
  File "/usr/lib/python3/dist-packages/pov_server_page/update_server_page.py", line 647, in build
    subbuilder.build(filename, self)
  File "/usr/lib/python3/dist-packages/pov_server_page/update_server_page.py", line 269, in build
    mapping = update_ports_html.get_port_mapping()
  File "/usr/lib/python3/dist-packages/pov_server_page/update_ports_html.py", line 261, in get_port_mappi
ng
    systemd_sockets = list(systemctl_list_sockets())
  File "/usr/lib/python3/dist-packages/pov_server_page/update_ports_html.py", line 152, in systemctl_list
_sockets
    listen, type_, unit, activates = parts
ValueError: too many values to unpack (expected 4)
```

NB: the installation itself doesn't fail somehow.

After rebooting I can no longer reproduce this.

The code that fails is trying to parse the output of `systemctl list-sockets --show-types`.
diff --git a/tests/test_update_ports_html.py b/tests/test_update_ports_html.py
index 3169017..21de66f 100644
--- a/tests/test_update_ports_html.py
+++ b/tests/test_update_ports_html.py
@@ -3,23 +3,35 @@ import os
 import sys
 import textwrap
 import unittest
-from io import BytesIO, TextIOWrapper
 from contextlib import closing
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from io import StringIO
+from io import BytesIO, TextIOWrapper
 
 import mock
 
 from pov_server_page.update_ports_html import (
-    main, get_owner, username, get_argv, format_arg, get_program,
-    get_html_cmdline, parse_services, render_row, NetStatTuple,
-    systemctl_list_sockets, get_port_mapping,
+    NetStatTuple,
+    format_arg,
+    get_argv,
+    get_html_cmdline,
+    get_owner,
+    get_port_mapping,
+    get_program,
+    main,
+    netstat,
+    parse_services,
+    render_row,
+    rpcinfo_dump,
+    systemctl_list_sockets,
+    username,
 )
 
 
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from io import StringIO
+
+
 CMDLINES = {
     1: b"/lib/systemd/systemd\0--system\0--deserialize\00023\0",
     540: b"/sbin/rpcbind\0-w\0",
@@ -38,6 +50,7 @@ CMDLINES = {
     9003: b"nginx: master process /opt/gitlab/embedded/sbin/nginx -p /var/opt/gitlab/nginx",
 }
 
+NETSTAT_COMMAND = ('netstat', '-tunlvp')
 NETSTAT_SAMPLE = b"""\
 Active Internet connections (only servers)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
@@ -79,6 +92,7 @@ udp        0      0 192.168.1.165:123       0.0.0.0:*
 udp        0      0 127.0.0.1:123           0.0.0.0:*                           -
 udp        0      0 0.0.0.0:123             0.0.0.0:*                           -
 udp        0      0 0.0.0.0:631             0.0.0.0:*                           -
+udp        0      0 224.0.0.251:5353        0.0.0.0:*                           9100/chrome --no-de
 udp6       0      0 :::5353                 :::*                                -
 udp6       0      0 :::38336                :::*                                -
 udp6       0      0 fe80::52ca:9cd0:ed7:123 :::*                                -
@@ -86,6 +100,7 @@ udp6       0      0 ::1:123                 :::*
 udp6       0      0 :::123                  :::*                                -
 """
 
+RPCINFO_COMMAND = ('rpcinfo', '-p')
 RPCINFO_SAMPLE = b"""\
    program vers proto   port  service
     100000    4   tcp    111  portmapper
@@ -118,25 +133,32 @@ RPCINFO_SAMPLE = b"""\
     100021    4   tcp  43461  nlockmgr
 """
 
+SYSTEMCTL_LIST_SOCKETS_COMMAND = ('systemctl', 'list-sockets', '--show-types')
+SYSTEMCTL_LIST_SOCKETS_SAMPLE = (
+    # NB: the trailing spaces are important
+    b"LISTEN                          TYPE             UNITS                           ACTIVATES               \n"
+    b"/run/apport.socket              Stream           apport-forward.socket                                   \n"
+    b"/run/spinta/socket              Stream           spinta.socket                   spinta.service          \n"
+    b"/run/systemd/initctl/fifo       FIFO             systemd-initctl.socket          systemd-initctl.service \n"
+    b"/run/systemd/journal/dev-log    Datagram         systemd-journald-dev-log.socket systemd-journald.service\n"
+    b"/run/systemd/journal/socket     Datagram         systemd-journald.socket         systemd-journald.service\n"
+    b"/run/systemd/journal/stdout     Stream           systemd-journald.socket         systemd-journald.service\n"
+    b"/run/systemd/journal/syslog     Datagram         syslog.socket                   rsyslog.service         \n"
+    b"/run/udev/control               SequentialPacket systemd-udevd-control.socket    systemd-udevd.service   \n"
+    b"/run/uuidd/request              Stream           uuidd.socket                    uuidd.service           \n"
+    b"/var/run/dbus/system_bus_socket Stream           dbus.socket                     dbus.service            \n"
+    b"127.0.0.1:8000                  Stream           spinta.socket                   spinta.service          \n"
+    b"kobject-uevent 1                Netlink          systemd-udevd-kernel.socket     systemd-udevd.service   \n"
+    b"\n"
+    b"12 sockets listed.\n"
+    b"Pass --all to see loaded but inactive sockets, too.\n"
+)
 
-SYSTEMCTL_LIST_SOCKETS_SAMPLE = b"""\
-LISTEN                          TYPE             UNIT                            ACTIVATES
-/run/apport.socket              Stream           apport-forward.socket
-/run/spinta/socket              Stream           spinta.socket                   spinta.service
-/run/systemd/initctl/fifo       FIFO             systemd-initctl.socket          systemd-initctl.service
-/run/systemd/journal/dev-log    Datagram         systemd-journald-dev-log.socket systemd-journald.service
-/run/systemd/journal/socket     Datagram         systemd-journald.socket         systemd-journald.service
-/run/systemd/journal/stdout     Stream           systemd-journald.socket         systemd-journald.service
-/run/systemd/journal/syslog     Datagram         syslog.socket                   rsyslog.service
-/run/udev/control               SequentialPacket systemd-udevd-control.socket    systemd-udevd.service
-/run/uuidd/request              Stream           uuidd.socket                    uuidd.service
-/var/run/dbus/system_bus_socket Stream           dbus.socket                     dbus.service
-127.0.0.1:8000                  Stream           spinta.socket                   spinta.service
-kobject-uevent 1                Netlink          systemd-udevd-kernel.socket     systemd-udevd.service
-
-12 sockets listed.
-Pass --all to see loaded but inactive sockets, too.
-"""  # NB: there should be trailins spaces on the apport.socket line, but I don't care
+DEFAULT_COMMANDS = {
+    NETSTAT_COMMAND: NETSTAT_SAMPLE,
+    RPCINFO_COMMAND: RPCINFO_SAMPLE,
+    SYSTEMCTL_LIST_SOCKETS_COMMAND: SYSTEMCTL_LIST_SOCKETS_SAMPLE,
+}
 
 
 SERVICES = """\
@@ -148,17 +170,20 @@ https\t\t443/tcp\t\t\t\t# http protocol over TLS/SSL
 
 
 class FakePopen(object):
-    def __init__(self, command, stdout=None, stderr=None):
-        if isinstance(command, tuple):
-            command = list(command)
-        if command == ['netstat', '-tunlvp']:
-            self.stdout = BytesIO(NETSTAT_SAMPLE)
-        elif command == ['rpcinfo', '-p']:
-            self.stdout = BytesIO(RPCINFO_SAMPLE)
-        elif command == ['systemctl', 'list-sockets', '--show-types']:
-            self.stdout = BytesIO(SYSTEMCTL_LIST_SOCKETS_SAMPLE)
-        else:
-            raise AssertionError('unexpected command: %s' % command)
+
+    def __init__(self, commands=None):
+        self._commands = DEFAULT_COMMANDS if commands is None else commands
+
+    def __call__(self, command, stdout=None, stderr=None):
+        try:
+            return _FakePopen(self._commands[tuple(command)])
+        except KeyError:
+            raise AssertionError('unexpected command: %r' % list(command))
+
+
+class _FakePopen(object):
+    def __init__(self, stdout):
+        self.stdout = BytesIO(stdout)
 
 
 def fake_open(filename, mode='r'):
@@ -186,16 +211,60 @@ class MockMixin:
         return retval
 
 
-class TestSystemctl(MockMixin, unittest.TestCase):
+class TestNetstat(MockMixin, unittest.TestCase):
 
-    def setUp(self):
-        self.patch('subprocess.Popen', FakePopen)
+    def test_netstat_failure_handling_no_header(self):
+        self.patch('subprocess.Popen', FakePopen({
+            NETSTAT_COMMAND: (
+                b"netstat: command not found\n"
+            ),
+        }))
+        self.assertEqual(list(netstat()), [])
+
+    def test_netstat_failure_handling(self):
+        self.patch('subprocess.Popen', FakePopen({
+            NETSTAT_COMMAND: (
+                b'Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name\n'
+                b'tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN\n'
+                b'tcp        0      0 127.0.0.1               0.0.0.0:*               LISTEN      851/redis-server 12\n'
+                b'tcp6       0      0 :::80                   :::*                    LISTEN      xyzzy/apache2\n'
+            ),
+        }))
+        self.assertEqual(list(netstat()), [])
+
+
+class TestRpcinfo(MockMixin, unittest.TestCase):
+
+    def test_rpcinfo_dump_sockets_error_handling(self):
+        self.patch('subprocess.Popen', FakePopen({
+            # imagine a couple of columns are randomly missing (unlikely, but)
+            RPCINFO_COMMAND: (
+                b"   proto   port  service\n"
+                b"     tcp    111  portmapper\n"
+                b"\n"
+            ),
+        }))
+        self.assertEqual(list(rpcinfo_dump()), [])
+
+
+class TestSystemctl(MockMixin, unittest.TestCase):
 
     def test_systemctl_list_sockets(self):
+        self.patch('subprocess.Popen', FakePopen())
         self.assertEqual(list(systemctl_list_sockets()), [
             NetStatTuple('tcp', '127.0.0.1', 8000, None, 'spinta.socket'),
         ])
 
+    def test_systemctl_list_sockets_error_handling(self):
+        self.patch('subprocess.Popen', FakePopen({
+            # imagine a column is randomly missing (unlikely, but)
+            SYSTEMCTL_LIST_SOCKETS_COMMAND: (
+                b"LISTEN             TYPE   UNITS                \n"
+                b"/run/apport.socket Stream apport-forward.socket\n"
+            ),
+        }))
+        self.assertEqual(list(systemctl_list_sockets()), [])
+
 
 class TestProcHelpers(unittest.TestCase):
 
@@ -232,7 +301,7 @@ class TestFormattingHelpers(unittest.TestCase):
 class TestGetPortMapping(MockMixin, unittest.TestCase):
 
     def setUp(self):
-        self.patch('subprocess.Popen', FakePopen)
+        self.patch('subprocess.Popen', FakePopen())
         self.patch('pov_server_page.update_ports_html.open', fake_open)
 
     def test_systemd_integration(self):
@@ -254,7 +323,7 @@ class TestParseServices(unittest.TestCase):
 class TestWithFakeEnvironment(MockMixin, unittest.TestCase):
 
     def setUp(self):
-        self.patch('subprocess.Popen', FakePopen)
+        self.patch('subprocess.Popen', FakePopen())
         self.patch('pov_server_page.update_ports_html.open', fake_open)
         self.stderr = self.patch('sys.stderr', StringIO())
 

pip install -e .[dev]
parse_log_pytest
pytest
pytest mock
apt-get update apt-get install -y gcc
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///croot/attrs_1668696182826/work
certifi @ file:///croot/certifi_1671487769961/work/certifi
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1648562407465/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Mako==1.2.4
MarkupSafe==2.1.5
mock==5.2.0
packaging @ file:///croot/packaging_1671697413597/work
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
-e git+https://github.com/ProgrammersOfVilnius/pov-server-page.git@fba20b13170c1ba14451411c677deb349e795bf3#egg=pov_server_page
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pytest==7.1.2
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions @ file:///croot/typing_extensions_1669924550328/work
zipp @ file:///croot/zipp_1672387121353/work

name: pov-server-page
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib-metadata=4.11.3=py37h06a4308_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py37h06a4308_0
  - typing_extensions=4.4.0=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - mako==1.2.4
      - markupsafe==2.1.5
      - mock==5.2.0
prefix: /opt/conda/envs/pov-server-page

tests/test_update_ports_html.py::TestNetstat::test_netstat_failure_handling tests/test_update_ports_html.py::TestRpcinfo::test_rpcinfo_dump_sockets_error_handling tests/test_update_ports_html.py::TestSystemctl::test_systemctl_list_sockets tests/test_update_ports_html.py::TestGetPortMapping::test_systemd_integration tests/test_update_ports_html.py::TestWithFakeEnvironment::test_main
tests/test_update_ports_html.py::TestWithFakeEnvironment::test_render_row_systemd_socket
tests/test_update_ports_html.py::TestNetstat::test_netstat_failure_handling_no_header tests/test_update_ports_html.py::TestSystemctl::test_systemctl_list_sockets_error_handling tests/test_update_ports_html.py::TestProcHelpers::test_get_owner tests/test_update_ports_html.py::TestProcHelpers::test_get_owner_process_is_gone tests/test_update_ports_html.py::TestProcHelpers::test_username tests/test_update_ports_html.py::TestProcHelpers::test_username_no_such_user tests/test_update_ports_html.py::TestProcHelpers::test_username_unknown_user tests/test_update_ports_html.py::TestFormattingHelpers::test_format_arg tests/test_update_ports_html.py::TestParseServices::test_etc_services_missing tests/test_update_ports_html.py::TestWithFakeEnvironment::test_get_html_cmdline tests/test_update_ports_html.py::TestWithFakeEnvironment::test_get_html_cmdline_pid_unknown tests/test_update_ports_html.py::TestWithFakeEnvironment::test_get_html_cmdline_program_disappeared tests/test_update_ports_html.py::TestWithFakeEnvironment::test_get_program tests/test_update_ports_html.py::TestWithFakeEnvironment::test_get_program_unknown_pid tests/test_update_ports_html.py::TestWithFakeEnvironment::test_getargv tests/test_update_ports_html.py::TestWithFakeEnvironment::test_getargv_no_trailing_nul tests/test_update_ports_html.py::TestWithFakeEnvironment::test_main_unexpected_arguments tests/test_update_ports_html.py::TestWithFakeEnvironment::test_render_row_pid_disappeared
Makefile src/pov_server_page/update_server_page.py src/pov_server_page/utils.py src/pov_server_page/update_ports_html.py setup.cfg
Makefile src/pov_server_page/update_server_page.py src/pov_server_page/utils.py src/pov_server_page/update_ports_html.py setup.cfg