[Git][NTPsec/ntpsec][ntp.util-codacy] 3 commits: INSTALL: Improve the Python 3 notes

James Browning gitlab at mg.gitlab.com
Fri Sep 11 01:10:50 UTC 2020



James Browning pushed to branch ntp.util-codacy at NTPsec / ntpsec


Commits:
6b2491a8 by Richard Laager at 2020-09-07T19:15:36-05:00
INSTALL: Improve the Python 3 notes

- - - - -
4e89dedf by James Browning at 2020-09-10T16:13:06-07:00
Codacy: mostly blow smoke -r1


- - - - -
224b136a by James Browning at 2020-09-10T18:06:36-07:00
thoolify


- - - - -


23 changed files:

- INSTALL.adoc
- devel/python_paths.py
- ntpclients/ntpdig.py
- ntpclients/ntpkeygen.py
- ntpclients/ntploggps.py
- ntpclients/ntplogtemp.py
- ntpclients/ntpmon.py
- ntpclients/ntpq.py
- ntpclients/ntpviz.py
- pylib/agentx.py
- pylib/agentx_packet.py
- pylib/packet.py
- pylib/poly.py
- pylib/statfiles.py
- pylib/util.py
- tests/pylib/test_ntpc.py
- wafhelpers/asciidoc.py
- wafhelpers/bin_test.py
- wafhelpers/check_sizeof.py
- wafhelpers/options.py
- wafhelpers/probes.py
- wafhelpers/refclock.py
- wafhelpers/waf.py


Changes:

=====================================
INSTALL.adoc
=====================================
@@ -49,10 +49,9 @@ different packages depending on whether your base Python version is
 Python 2.x, x >= 6, or Python 3.x, x >= 3::
    Required to build, and for various scripts such as ntpviz (but see
    the guidance for packagers in devel/packaging.adoc).  Our Python code
-   has been written polyglot to also run with production versions of
-   Python 3.  Note that you will need both the ordinary Python
-   installation and Python dev tools, if your OS makes such a
-   distinction.
+   has been written polyglot to run with either Python 2 or Python 3.
+   Note that you will need both the ordinary Python installation and
+   Python dev tools, if your OS makes such a distinction.
 
    Some OS distros won't find our installed python libraries.
    More info in README-PYTHON.
@@ -65,9 +64,9 @@ psutil::
    Optional for ntpviz.  Allows running with ionice()
    Debian: python-psutil or python3-psutil
    Ubuntu: python-psutil or python3-psutil
-   Fedora/CentOS: python-psutil
+   Fedora/CentOS: python-psutil or python3-psutil
    Gentoo: dev-python/psutil
-   SLES: python-psutil
+   SLES: python-psutil or python3-psutil
 
 sys/timepps.h::
    If you are building to supply Stratum 1 time service (that is, with


=====================================
devel/python_paths.py
=====================================
@@ -41,6 +41,7 @@ PYTHON_PREFIX_NAMES = 'sys-prefix std-prefix exec-prefix'.split()
 
 
 class BadReturn(Exception):
+
     """Bad return from subprocess."""
     pass
 


=====================================
ntpclients/ntpdig.py
=====================================
@@ -78,7 +78,7 @@ def read_append(s, packets, packet, sockaddr):
 
 
 def queryhost(server, concurrent, timeout=5, port=123):
-    "Query IP addresses associated with a specified host."
+    """Query IP addresses associated with a specified host."""
     try:
         iptuples = socket.getaddrinfo(server, port,
                                       af, socket.SOCK_DGRAM,
@@ -138,7 +138,7 @@ def queryhost(server, concurrent, timeout=5, port=123):
 
 
 def clock_select(packets):
-    "Select the pick-of-the-litter clock from the samples we've got."
+    """Select the pick-of-the-litter clock from the samples we've got."""
     # This is a slightly simplified version of the filter ntpdate used
     NTP_INFIN = 15          # max stratum, infinity a la Bellman-Ford
 
@@ -192,7 +192,7 @@ def clock_select(packets):
 
 
 def report(packet, json):
-    "Report on the SNTP packet selected for display, and its adjustment."
+    """Report on the SNTP packet selected for display, and its adjustment."""
     say = sys.stdout.write
 
     packet.posixize()


=====================================
ntpclients/ntpkeygen.py
=====================================
@@ -57,7 +57,7 @@ KEYSIZE = 16    # maximum key size
 
 
 def gen_keys(ident, groupname):
-    "Generate semi-random AES keys for versions of ntpd with CMAC support."
+    """Generate semi-random AES keys for versions of ntpd with CMAC support."""
     with fheader("AES", ident, groupname) as wp:
         for i in range(1, NUMKEYS+1):
             key = gen_key(KEYSIZE, True)
@@ -74,7 +74,7 @@ def fheader(fileid,     # file name id
             ulink,      # linkname
             owner       # owner name
             ):
-    "Generate file header and link"
+    """Generate file header and link."""
     try:
         filename = "ntpkey_%s_%s.%u" % (fileid, owner, int(time.time()))
         orig_umask = os.umask(stat.S_IWGRP | stat.S_IRWXO)


=====================================
ntpclients/ntploggps.py
=====================================
@@ -46,9 +46,11 @@ except ImportError as e:
 
 
 class logfile_header_class(logging.handlers.TimedRotatingFileHandler):
-    'A class to modify the file logging handler.'
+
+    """A class to modify the file logging handler."""
+
     def doRollover(self):
-        'function to add header to new file on rotation.'
+        """Add header to new file on rotation."""
         if str is bytes:
             super(logfile_header_class, self).doRollover()
         else:
@@ -57,7 +59,7 @@ class logfile_header_class(logging.handlers.TimedRotatingFileHandler):
 
 
 def logging_setup():
-    "Create logging object"
+    """Create logging object."""
     logFormat = logging.Formatter('%(message)s')
     # Create logger for gpsd
     Logger = logging.getLogger()
@@ -170,7 +172,7 @@ class GpsPoller(threading.Thread):
 
     @property
     def time(self):
-        "Return the gpsd time fix"
+        """Return the gpsd time fix."""
         t = self.gpsd.fix.time
         if isinstance(t, int):
             return t


=====================================
ntpclients/ntplogtemp.py
=====================================
@@ -33,9 +33,10 @@ import time
 
 
 class logfile_header_class(logging.handlers.TimedRotatingFileHandler):
-    'A class to modify the file logging handler.'
+
+    """A class to modify the file logging handler."""
     def doRollover(self):
-        'function to add header to new file on rotation.'
+        """Add header to new file on rotation."""
         if str is bytes:
             super(logfile_header_class, self).doRollover()
         else:
@@ -44,11 +45,7 @@ class logfile_header_class(logging.handlers.TimedRotatingFileHandler):
 
 
 def run_binary(cmd):
-    """\
-Run a binary
-Return output if good, None if bad
-"""
-
+    """Run a binary Return output if good, None if bad."""
     try:
         # sadly subprocess.check_output() is not in Python 2.6
         # so use Popen()
@@ -72,7 +69,8 @@ Return output if good, None if bad
 
 
 class CpuTemp:
-    "Sensors on the CPU Core"
+
+    """Sensors on the CPU Core."""
     has_sensors = False
 
     def __init__(self):
@@ -85,7 +83,7 @@ class CpuTemp:
         self._pattern = re.compile('^\s+temp\d+_input:\s+([\d\.]+).*$')
 
     def get_data(self):
-        "Collects the data and return the output as an array"
+        """Collects the data and return the output as an array."""
         if not self.has_sensors:
             return None
 
@@ -113,7 +111,8 @@ class CpuTemp:
 
 
 class SmartCtl:
-    "Sensor on the Hard Drive"
+
+    """Sensor on the Hard Drive."""
     _drives = []
     has_smartctl = False
 
@@ -129,7 +128,7 @@ class SmartCtl:
             self._drives = sorted(self._drives)
 
     def get_data(self):
-        "Collects the data and return the output as an array"
+        """Collects the data and return the output as an array."""
         if not self.has_smartctl:
             return None
 
@@ -150,13 +149,13 @@ class SmartCtl:
 
 
 class Temper:
-    """\
-    Reads 'temper-poll -c' for room temperature data.
+
+    """Reads 'temper-poll -c' for room temperature data.
 
     Before you can use this class you must have a TEMPer USB thermometer
-    plugged in, and the temper-python package must be installed and configured.
-    See their documentation for that procedure.
-"""
+    plugged in, and the temper-python package must be installed and
+    configured. See their documentation for that procedure.
+    """
     has_temper = False
 
     def __init__(self):
@@ -166,7 +165,7 @@ class Temper:
             self.has_temper = True
 
     def get_data(self):
-        "Collects the data and return the output as an array"
+        """Collects the data and return the output as an array."""
         if not self.has_temper:
             return None
 
@@ -194,8 +193,8 @@ class Temper:
 
 
 class ZoneTemp:
-    "Zone sensors"
 
+    """Zone sensors."""
     def __init__(self):
         base_dir = '/sys/class/thermal/thermal_zone?/'
         self.zones = []
@@ -203,7 +202,7 @@ class ZoneTemp:
             self.zones.append(child)
 
     def get_data(self):
-        "Collects the data and return the output as an array"
+        """Collects the data and return the output as an array."""
         _zone = 0
         _data = []
         for zone in self.zones:
@@ -249,7 +248,7 @@ args = parser.parse_args()
 
 
 def logging_setup():
-    "Create logging object"
+    """Create logging object."""
     logFormat = logging.Formatter('%(message)s')
     # Create logger for cpuTemp
     tempLogger = logging.getLogger()
@@ -275,14 +274,14 @@ def logging_setup():
 
 
 def logData(log, data):
-    "log the data"
+    """Log the data."""
     if data is not None:
         for _item in data:
             log.info(_item)
 
 
 def log_data():
-    "Write all temperature readings to one file"
+    """Write all temperature readings to one file."""
     # Create objects
     cpu = CpuTemp()
     zone = ZoneTemp()


=====================================
ntpclients/ntpmon.py
=====================================
@@ -2,8 +2,7 @@
 # -*- coding: utf-8 -*-
 
 # SPDX-License-Identifier: BSD-2-Clause
-'''\
-Any keystroke causes a poll and update. Keystroke commands:
+"""Any keystroke causes a poll and update. Keystroke commands:
 
 'a': Change peer display to apeers mode, showing association IDs.
 'd': Toggle detail mode (some peer will be reverse-video highlighted when on).
@@ -23,7 +22,7 @@ Any keystroke causes a poll and update. Keystroke commands:
 '+': Increase debugging level.  Output goes to ntpmon.log
 '-': Decrease debugging level.
 '?': Display helpscreen.
-'''
+"""
 
 from __future__ import print_function, division
 
@@ -71,12 +70,12 @@ stdscr = None
 
 
 def iso8601(t):
-    "ISO8601 string from Unix time."
+    """ISO8601 string from Unix time."""
     return time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(t))
 
 
 def statline(_peerlist, _mrulist, nyquist):
-    "Generate a status line"
+    """Generate a status line."""
     # We don't use stdversion here because the presence of a date is confusing
     leader = sysvars['version'][0]
     leader = re.sub(r" \([^\)]*\)", "", leader)
@@ -91,7 +90,7 @@ def statline(_peerlist, _mrulist, nyquist):
 
 
 def peer_detail(variables, showunits=False):
-    "Show the things a peer summary doesn't, cooked slightly differently"
+    """Show the things a peer summary doesn't, cooked slightly differently."""
     # All of an rv display except refid, reach, delay, offset, jitter.
     # One of the goals here is to emit field values at fixed positions
     # on the 2D display, so that changes in the details are easier to spot.
@@ -160,8 +159,8 @@ filtdisp   = %(filtdisp)s
 
 
 class Fatal(Exception):
-    "Unrecoverable error."
 
+    """Unrecoverable error."""
     def __init__(self, msg):
         Exception.__init__(self)
         self.msg = msg
@@ -172,7 +171,7 @@ class Fatal(Exception):
 
 class OutputContext:
     def __enter__(self):
-        "Begin critical region."
+        """Begin critical region."""
         if sys.version_info[0] < 3 and not disableunicode:
             # This appears to only be needed under python 2, it is only
             # activated when we already have UTF-8. Otherwise we drop


=====================================
ntpclients/ntpq.py
=====================================
@@ -56,8 +56,8 @@ NTP_FLOAT = 0xa   # Float value
 
 
 class Ntpq(cmd.Cmd):
-    "ntpq command interpreter"
 
+    """Ntpq command interpreter."""
     def __init__(self, session):
         cmd.Cmd.__init__(self)
         self.session = session
@@ -91,7 +91,7 @@ class Ntpq(cmd.Cmd):
                 for x in dir(self.__class__)]
 
     def emptyline(self):
-        "Called when an empty line is entered in response to the prompt."
+        """Called when an empty line is entered in response to the prompt."""
         pass
 
     def precmd(self, line):
@@ -102,7 +102,8 @@ class Ntpq(cmd.Cmd):
         return line
 
     def default(self, line):
-        "Called on an input line when the command prefix is not recognized."
+        """Called on an input line when the command prefix is not
+        recognized."""
         cmd, arg, line = self.parseline(line)
         try:
             dotext = 'do_'+cmd
@@ -264,7 +265,7 @@ usage: help [ command ]
             pass
 
     def __assoc_valid(self, line, required=False):
-        "Process a numeric associd or index."
+        """Process a numeric associd or index."""
         # FIXME: This does a useless call to __dogetassoc() when associd == 0
         # No big deal most of the time.  Just a useless packet exchange.
         if not line:
@@ -303,7 +304,7 @@ usage: help [ command ]
                 return associd
 
     def __assoc_range_valid(self, line):
-        "Try to get a range of assoc IDs."
+        """Try to get a range of assoc IDs."""
         tokens = line.split()
         if len(tokens) < 2:
             return ()
@@ -316,7 +317,7 @@ usage: help [ command ]
         return range(lo, hi+1)
 
     def printvars(self, variables, dtype, quiet):
-        "Dump variables in raw (actually, semi-cooked) mode."
+        """Dump variables in raw (actually, semi-cooked) mode."""
         if self.rawmode:
             if not quiet:
                 self.say("status=0x%04x,\n" % self.session.rstatus)
@@ -337,7 +338,7 @@ usage: help [ command ]
         self.say(text)
 
     def __dolist(self, varlist, associd, op, type, quiet=False):
-        "List variables associated with a specified peer."
+        """List variables associated with a specified peer."""
         try:
             variables = self.session.readvar(associd, varlist, op, raw=True)
         except ntp.packet.ControlException as e:
@@ -365,7 +366,7 @@ usage: help [ command ]
     # Unexposed helper tables and functions end here
 
     def do_units(self, _unused):
-        "toggle unit display"
+        """Toggle unit display."""
         self.showunits = not self.showunits
 
     def help_units(self):
@@ -375,12 +376,12 @@ usage: units
 """)
 
     def do_EOF(self, _unused):
-        "exit ntpq"
+        """Exit ntpq."""
         self.say("\n")
         return True
 
     def do_timeout(self, line):
-        "set the primary receive time out"
+        """Set the primary receive time out."""
         if line:
             try:
                 self.session.primary_timeout = int(line)
@@ -395,7 +396,7 @@ usage: timeout [ msec ]
 """)
 
     def collect_display(self, associd, variables, decodestatus):
-        "Query and display a collection of variables from the system."
+        """Query and display a collection of variables from the system."""
         try:
             queried = self.session.readvar(associd,
                                            [v[0] for v in variables],
@@ -480,7 +481,7 @@ usage: timeout [ msec ]
             self.warn("display interrupted")
 
     def do_delay(self, line):
-        "set the delay added to encryption time stamps"
+        """Set the delay added to encryption time stamps."""
         if not line:
             self.say("delay %d ms\n" % self.auth_delay)
         else:
@@ -498,7 +499,7 @@ usage: delay [ msec ]
 """)
 
     def do_host(self, line):
-        "specify the host whose NTP server we talk to"
+        """Specify the host whose NTP server we talk to."""
         if not line:
             if self.session.havehost():
                 self.say("current host is %s\n" % self.session.hostname)
@@ -532,7 +533,7 @@ usage: host [-4|-6] [hostname]
 """)
 
     def do_poll(self, line):
-        "poll an NTP server in client mode `n' times"
+        """Poll an NTP server in client mode `n' times."""
         # And it's not in the C version, so we're off the hook here
         self.warn("WARNING: poll not implemented yet")
 
@@ -543,7 +544,7 @@ usage: poll [n] [verbose]
 """)
 
     def do_passwd(self, line):
-        "specify a password to use for authenticated requests"
+        """Specify a password to use for authenticated requests."""
         try:
             self.session.password()
         except ntp.packet.ControlException as e:
@@ -558,7 +559,7 @@ usage: passwd []
 """)
 
     def do_hostnames(self, line):
-        "specify whether hostnames or net numbers are printed"
+        """Specify whether hostnames or net numbers are printed."""
         if not line:
             pass
         elif line == "yes":
@@ -588,7 +589,7 @@ usage: hostnames [yes|no|hostname|hostnum]
 """)
 
     def do_debug(self, line):
-        "set/change debugging level"
+        """Set/change debugging level."""
         if not line:
             pass
         elif line == "more":
@@ -607,8 +608,10 @@ usage: hostnames [yes|no|hostname|hostnum]
         self.say("debug level is %d\n" % self.debug)
 
     def do_logfile(self, line):
-        """view/change logfile. \"<stderr>\" will log to stderr
-           instead of a file"""
+        """View/change logfile.
+
+        \"<stderr>\" will log to stderr instead of a file
+        """
         if not line:
             self.say(repr(self.logfp.name) + "\n")
             return
@@ -631,7 +634,7 @@ usage: debug [no|more|less|n]
 """)
 
     def do_exit(self, line):
-        "exit ntpq"
+        """Exit ntpq."""
         return True
 
     def help_exit(self):
@@ -648,7 +651,7 @@ usage: quit
 """)
 
     def do_keyid(self, line):
-        "set keyid to use for authenticated requests"
+        """Set keyid to use for authenticated requests."""
         if line:
             try:
                 self.session.keyid = int(line)
@@ -666,7 +669,7 @@ usage: keyid [key#]
 """)
 
     def do_version(self, line):
-        "print version number"
+        """Print version number."""
         self.say(version + "\n")
 
     def help_version(self):
@@ -676,7 +679,7 @@ usage: version
 """)
 
     def do_direct(self, line):
-        "toggle direct mode output"
+        """Roggle direct mode output."""
         self.directmode = not self.directmode
         if self.directmode:
             self.say("Direct mode is on\n")
@@ -690,7 +693,7 @@ usage: direct
 """)
 
     def do_raw(self, line):
-        "do raw mode variable output"
+        """Do raw mode variable output."""
         self.rawmode = True
         self.say("Output set to raw\n")
 
@@ -701,7 +704,7 @@ usage: raw
 """)
 
     def do_cooked(self, line):
-        "do cooked mode variable output"
+        """Do cooked mode variable output."""
         self.rawmode = False
         self.say("Output set to cooked\n")
 
@@ -712,7 +715,7 @@ usage: cooked
 """)
 
     def do_authenticate(self, line):
-        "always authenticate requests to this server"
+        """Always authenticate requests to this server."""
         if not line:
             pass
         elif line == "yes":
@@ -733,7 +736,7 @@ usage: authenticate [yes|no]
 """)
 
     def do_ntpversion(self, line):
-        "set the NTP version number to use for requests"
+        """Set the NTP version number to use for requests."""
         if not line:
             pass
         else:
@@ -757,7 +760,7 @@ usage: ntpversion [version number]
 """)
 
     def do_keytype(self, line):
-        "set key type to use for authenticated requests"
+        """Set key type to use for authenticated requests."""
         if not line:
             self.say("Keytype: %s\n" % self.session.keytype)
         elif line.upper() in ['AES', 'AES128CMAC']:
@@ -775,7 +778,8 @@ usage: keytype [digest-name]
 """)
 
     def do_associations(self, line):
-        "print list of association IDs and statuses for the server's peers"
+        """Print list of association IDs and statuses for the server's
+        peers."""
         if self.__dogetassoc():
             self.__printassoc(showall=True)
 
@@ -786,7 +790,7 @@ usage: associations
 """)
 
     def do_passociations(self, line):
-        "print list of associations returned by last associations command"
+        """Print list of associations returned by last associations command."""
         self.__printassoc(showall=True)
 
     def help_passociations(self):
@@ -796,7 +800,7 @@ usage: passociations
 """)
 
     def do_lassociations(self, line):
-        "print list of associations including all client information"
+        """Print list of associations including all client information."""
         if self.__dogetassoc():
             self.__printassoc(showall=True)
 
@@ -807,9 +811,8 @@ usage: lassociations
 """)
 
     def do_lpassociations(self, line):
-        """\
-print last obtained list of associations, including client information
-"""
+        """\ print last obtained list of associations, including client
+        information."""
         self.__printassoc(showall=True)
 
     def help_lpassociations(self):
@@ -820,7 +823,7 @@ usage: lpassociations
 """)
 
     def do_addvars(self, line):
-        "add variables to the variable list or change their values"
+        """Add variables to the variable list or change their values."""
         if not line:
             self.warn("usage: addvars name[=value][,...]\n")
             return
@@ -839,7 +842,7 @@ usage: addvars name[=value][,...]
 """)
 
     def do_rmvars(self, line):
-        "remove variables from the variable list"
+        """Remove variables from the variable list."""
         if not line:
             self.warn("usage: rmvars name[,...]\n")
             return
@@ -857,7 +860,7 @@ usage: rmvars name[,...]
 """)
 
     def do_clearvars(self, line):
-        "remove all variables from the variable list"
+        """Remove all variables from the variable list."""
         self.uservars.clear()
 
     def help_clearvars(self):
@@ -867,7 +870,7 @@ usage: clearvars
 """)
 
     def do_showvars(self, line):
-        "print variables on the variable list"
+        """Print variables on the variable list."""
         if not self.uservars:
             self.say("No variables on list.\n")
         for (name, value) in self.uservars.items():
@@ -883,7 +886,7 @@ usage: showvars
 """)
 
     def do_readlist(self, line):
-        "read the system or peer variables included in the variable list"
+        """Read the system or peer variables included in the variable list."""
         associd = self.__assoc_valid(line)
         if associd >= 0:
             qtype = ntp.ntpc.TYPE_SYS if associd == 0 else ntp.ntpc.TYPE_PEER
@@ -897,7 +900,7 @@ usage: readlist [assocID]
 """)
 
     def do_rl(self, line):
-        "read the system or peer variables included in the variable list"
+        """Read the system or peer variables included in the variable list."""
         self.do_readlist(line)
 
     def help_rl(self):
@@ -907,7 +910,7 @@ usage: rl [assocID]
 """)
 
     def do_writelist(self, line):
-        "write the system or peer variables included in the variable list"
+        """Write the system or peer variables included in the variable list."""
         pass
 
     def help_writelist(self):
@@ -917,7 +920,7 @@ usage: writelist [ assocID ]
 """)
 
     def do_readvar(self, line):
-        "read system or peer variables"
+        """Read system or peer variables."""
         associd = self.__assoc_valid(line)
         if associd >= 0:
             qtype = ntp.ntpc.TYPE_SYS if associd == 0 else ntp.ntpc.TYPE_PEER
@@ -931,7 +934,7 @@ usage: readvar [assocID] [varname1] [varname2] [varname3]
 """)
 
     def do_rv(self, line):
-        "read system or peer variables"
+        """Read system or peer variables."""
         self.do_readvar(line)
 
     def help_rv(self):
@@ -941,7 +944,7 @@ usage: rv [assocID] [varname1] [varname2] [varname3]
 """)
 
     def do_writevar(self, line):
-        "write system or peer variables"
+        """Write system or peer variables."""
         pass
 
     def help_writevar(self):
@@ -951,7 +954,7 @@ usage: writevar assocID name=value,[...]
 """)
 
     def do_mreadlist(self, line):
-        "read the peer variables in the variable list for multiple peers"
+        """Read the peer variables in the variable list for multiple peers."""
         if not line:
             self.warn("usage: mreadlist assocIDlow assocIDhigh\n")
             return
@@ -973,7 +976,7 @@ usage: mreadlist assocIDlow assocIDhigh
 """)
 
     def do_mrl(self, line):
-        "read the peer variables in the variable list for multiple peers"
+        """Read the peer variables in the variable list for multiple peers."""
         if not line:
             self.warn("usage: mrl assocIDlow assocIDhigh")
             return
@@ -986,7 +989,7 @@ usage: mrl assocIDlow assocIDhigh
 """)
 
     def do_mreadvar(self, line):
-        "read peer variables from multiple peers"
+        """Read peer variables from multiple peers."""
         if not line:
             self.warn("usage: mreadvar assocIDlow assocIDhigh  "
                       "[ name=value[,...] ]")
@@ -1010,7 +1013,7 @@ usage: mreadvar assocIDlow assocIDhigh [name=value[,...]]
 """)
 
     def do_mrv(self, line):
-        "read peer variables from multiple peers"
+        """Read peer variables from multiple peers."""
         if not line:
             self.warn(
                 "usage: mrv assocIDlow assocIDhigh [name=value[,...]]")
@@ -1024,7 +1027,7 @@ usage: mrv assocIDlow assocIDhigh [name=value[,...]]
 """)
 
     def do_clocklist(self, line):
-        "read the clock variables included in the variable list"
+        """Read the clock variables included in the variable list."""
         assoc = self.__assoc_valid(line)
         if assoc >= 0:
             self.__dolist(self.uservars.keys(),
@@ -1038,7 +1041,7 @@ usage: clocklist [assocID]
 """)
 
     def do_cl(self, line):
-        "read the clock variables included in the variable list"
+        """Read the clock variables included in the variable list."""
         self.do_clocklist(line)
 
     def help_cl(self):
@@ -1048,7 +1051,7 @@ usage: cl [assocID]
 """)
 
     def do_clockvar(self, line):
-        "read clock variables"
+        """Read clock variables."""
         assoc = self.__assoc_valid(line)
         if assoc == 0:
             self.warn("This command requires the association ID of a clock.")
@@ -1063,7 +1066,7 @@ usage: clockvar [assocID] [name=value[,...]]
 """)
 
     def do_cv(self, line):
-        "read clock variables"
+        """Read clock variables."""
         self.do_clockvar(line)
 
     def help_cv(self):
@@ -1073,7 +1076,7 @@ usage: cv [ assocID ] [ name=value[,...] ]
 """)
 
     def do_pstats(self, line):
-        "show statistics for a peer"
+        """Show statistics for a peer."""
         pstats = (
             ("srcadr", "remote host:          ", NTP_ADD),
             ("dstadr", "local address:        ", NTP_ADD),
@@ -1105,7 +1108,7 @@ usage: pstats assocID
 """)
 
     def do_peers(self, line):
-        "obtain and print a list of the server's peers [IP version]"
+        """Obtain and print a list of the server's peers [IP version]"""
         self.__dopeers(showall=True, mode="peers")
 
     def help_peers(self):
@@ -1115,9 +1118,8 @@ usage: peers
 """)
 
     def do_apeers(self, line):
-        """
-obtain and print a list of the server's peers and their assocIDs [IP version]
-"""
+        """Obtain and print a list of the server's peers and their assocIDs [IP
+        version]"""
         self.__dopeers(showall=True, mode="apeers")
 
     def help_apeers(self):
@@ -1128,7 +1130,7 @@ usage: apeers
 """)
 
     def do_lpeers(self, line):
-        "obtain and print a list of all peers and clients [IP version]"
+        """Obtain and print a list of all peers and clients [IP version]"""
         self.__dopeers(showall=True, mode="peers")
 
     def help_lpeers(self):
@@ -1138,9 +1140,8 @@ usage: lpeers
 """)
 
     def do_opeers(self, line):
-        """
-print peer list the old way, with dstadr shown rather than refid [IP version]
-"""
+        """Print peer list the old way, with dstadr shown rather than refid [IP
+        version]"""
         self.__dopeers(showall=True, mode="opeers")
 
     def help_opeers(self):
@@ -1151,8 +1152,8 @@ usage: opeers
 """)
 
     def do_lopeers(self, line):
-        """obtain and print a list of all peers and clients showing
-        dstadr [IP version]"""
+        """Obtain and print a list of all peers and clients showing dstadr [IP
+        version]"""
         self.__dopeers(showall=True, mode="opeers")
 
     def help_lopeers(self):
@@ -1163,7 +1164,7 @@ usage: lopeers
 """)
 
     def do_hot_config(self, line):
-        "send a remote configuration command to ntpd"
+        """Send a remote configuration command to ntpd."""
         try:
             self.session.password()
         except ntp.packet.ControlException as e:
@@ -1198,7 +1199,7 @@ usage: config <configuration command line>
 """)
 
     def do_config_from_file(self, line):
-        "configure ntpd using the configuration filename"
+        """Configure ntpd using the configuration filename."""
         try:
             with open(line) as rfp:
                 self.say("%s\n" % self.session.config(rfp.read()))
@@ -1216,8 +1217,11 @@ usage: config_from_file <configuration filename>
             self.say(self.formatter.summary(entry) + "\n")
 
     def do_mrulist(self, line):
-        """display the list of most recently seen source addresses,
-           tags mincount=... resall=0x... resany=0x..."""
+        """Display the list of most recently seen source addresses, tags
+        mincount=...
+
+        resall=0x... resany=0x...
+        """
         cmdvars = {}
         for item in line.split(" "):
             if not item:
@@ -1304,7 +1308,7 @@ usage: mrulist [tag=value] [tag=value] [tag=value] [tag=value]
 """)
 
     def do_ifstats(self, line):
-        "show statistics for each local address ntpd is using"
+        """Show statistics for each local address ntpd is using."""
         try:
             self.session.password()
             entries = self.session.ifstats()
@@ -1329,7 +1333,7 @@ usage: ifstats
 """)
 
     def do_reslist(self, line):
-        "show ntpd access control list"
+        """Show ntpd access control list."""
         try:
             self.session.password()
             entries = self.session.reslist()
@@ -1356,7 +1360,7 @@ usage: reslist
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_sysinfo(self, _line):
-        "display system summary"
+        """Display system summary."""
         sysinfo = (
             ("peeradr", "system peer:      ", NTP_ADP),
             ("peermode", "system peer mode: ", NTP_MODE),
@@ -1384,7 +1388,7 @@ usage: sysinfo
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_kerninfo(self, _line):
-        "display kernel loop and PPS statistics"
+        """Display kernel loop and PPS statistics."""
         kerninfo = (
             ("koffset", "pll offset:          ", NTP_FLOAT),
             ("kfreq", "pll frequency:       ", NTP_FLOAT),
@@ -1414,7 +1418,7 @@ usage: kerninfo
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_sysstats(self, _line):
-        "display system uptime and packet counts"
+        """Display system uptime and packet counts."""
         sysstats = (
             ("ss_uptime", "uptime:               ", NTP_INT),
             ("ss_reset", "sysstats reset:       ", NTP_INT),
@@ -1441,7 +1445,7 @@ usage: sysstats
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_monstats(self, _line):
-        "display monitor (mrulist) counters and limits"
+        """Display monitor (mrulist) counters and limits."""
         monstats = (
             ("mru_enabled",     "enabled:              ", NTP_INT),
             ("mru_hashslots",   "hash slots in use:    ", NTP_INT),
@@ -1471,7 +1475,7 @@ usage: monstats
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_authinfo(self, _line):
-        "display symmetric authentication counters"
+        """Display symmetric authentication counters."""
         authinfo = (
             ("authreset",          "time since reset:    ", NTP_INT),
             ("authkeys",           "stored keys:         ", NTP_INT),
@@ -1502,7 +1506,7 @@ usage: authinfo
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_ntsinfo(self, _line):
-        "display NTS authentication counters"
+        """Display NTS authentication counters."""
         ntsinfo = (
    ("nts_client_send",           "NTS client sends:          ", NTP_INT),
    ("nts_client_recv_good",      "NTS client recvs good:     ", NTP_INT),
@@ -1532,7 +1536,7 @@ usage: ntsinfo
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_iostats(self, _line):
-        "display network input and output counters"
+        """Display network input and output counters."""
         iostats = (
             ("iostats_reset", "time since reset:     ", NTP_INT),
             ("total_rbuf", "receive buffers:      ", NTP_INT),
@@ -1558,7 +1562,7 @@ usage: iostats
 # FIXME: This table should move to ntpd
 #          so the answers track when ntpd is updated
     def do_timerstats(self, line):
-        "display interval timer counters"
+        """Display interval timer counters."""
         timerstats = (
             ("timerstats_reset", "time since reset:  ", NTP_INT),
             ("timer_overruns", "timer overruns:    ", NTP_INT),


=====================================
ntpclients/ntpviz.py
=====================================
@@ -69,7 +69,7 @@ if sys.version_info[0] == 2:
     sys.setdefaultencoding('utf8')
 
     def open(file, mode='r', buffering=-1, encoding=None, errors=None):
-        "Redefine open()"
+        """Redefine open()"""
         return(codecs.open(filename=file, mode=mode, encoding=encoding,
                errors=errors, buffering=buffering))
 
@@ -103,8 +103,8 @@ refclock_name = {'127.127.20.0': 'NMEA(0)',
 # Gack, python before 3.2 has no defined tzinfo for utc...
 # define our own
 class UTC(datetime.tzinfo):
-    """UTC"""
 
+    """UTC."""
     def utcoffset(self, dt):
         return datetime.timedelta(0)
 
@@ -132,10 +132,10 @@ if (3 > sys.version_info[0]) and (7 > sys.version_info[1]):
 
 # overload ArgumentParser
 class MyArgumentParser(argparse.ArgumentParser):
-    "class to parse arguments"
 
+    """class to parse arguments."""
     def convert_arg_line_to_args(self, arg_line):
-        '''Make options file more tolerant'''
+        """Make options file more tolerant."""
         # strip out trailing comments
         arg_line = re.sub('\s+#.*$', '', arg_line)
 
@@ -150,7 +150,7 @@ class MyArgumentParser(argparse.ArgumentParser):
 
 
 def print_profile():
-    """called by atexit() on normal exit to print profile data"""
+    """called by atexit() on normal exit to print profile data."""
     pr.disable()
     pr.print_stats('tottime')
     pr.print_stats('cumtime')
@@ -164,8 +164,8 @@ def print_profile():
 #   Mean, Variance, Standard Deviation, Skewness and Kurtosis
 
 class RunningStats(object):
-    "Calculate mean, variance, sigma, skewness and kurtosis"
 
+    """Calculate mean, variance, sigma, skewness and kurtosis."""
     def __init__(self, values):
         self.num = len(values)     # number of samples
         self.mu = 0.0              # simple arithmetic mean
@@ -202,8 +202,8 @@ class RunningStats(object):
 
 # class for calced values
 class VizStats(ntp.statfiles.NTPStats):
-    "Class for calculated values"
 
+    """Class for calculated values."""
     percs = {}          # dictionary of percentages
     title = ''          # title
     unit = 's'          # display units: s, ppm, etc.
@@ -373,7 +373,7 @@ class VizStats(ntp.statfiles.NTPStats):
 
 
 def gnuplot_fmt(min_val, max_val):
-    "return optimal gnuplot format"
+    """return optimal gnuplot format."""
     span = max_val - min_val
     if 6 <= span:
         fmt = '%.0f'
@@ -392,7 +392,7 @@ def gnuplot_fmt(min_val, max_val):
 # Investigate.
 
 def gnuplot(template, outfile=None):
-    "Run a specified gnuplot program."
+    """Run a specified gnuplot program."""
 
     if not template:
         # silently ignore empty plots
@@ -444,8 +444,8 @@ def gnuplot(template, outfile=None):
 
 
 class NTPViz(ntp.statfiles.NTPStats):
-    "Class for visualizing statistics from a single server."
 
+    """Class for visualizing statistics from a single server."""
     # Python takes single quotes here. Since no % substitution
     Common = """\
 set grid
@@ -468,7 +468,7 @@ set rmargin 10
                                         endtime=endtime)
 
     def plot_slice(self, rows, item1, item2=None):
-        "slice 0,item1, maybe item2, from rows, ready for gnuplot"
+        """slice 0,item1, maybe item2, from rows, ready for gnuplot."""
         # speed up by only sending gnuplot the data it will actually use
         # WARNING: this is hot code, only modify if you profile
         # since we are looping the data, get the values too
@@ -515,7 +515,7 @@ set rmargin 10
         return (plot_data, values1)
 
     def local_offset_gnuplot(self):
-        "Generate gnuplot code graphing local clock loop statistics"
+        """Generate gnuplot code graphing local clock loop statistics."""
         if not self.loopstats:
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
@@ -578,7 +578,7 @@ file.</p>
         return ret
 
     def local_freq_temps_plot(self):
-        "Generate gnuplot code graphing local frequency and temps"
+        """Generate gnuplot code graphing local frequency and temps."""
         if not self.loopstats:
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
@@ -671,7 +671,7 @@ file, and field 3 from the tempstats log file.</p>
         return ret
 
     def local_temps_gnuplot(self):
-        "Generate gnuplot code graphing local temperature statistics"
+        """Generate gnuplot code graphing local temperature statistics."""
         sitename = self.sitename
         tempsmap = self.tempssplit()
         tempslist = list(tempsmap.keys())
@@ -733,7 +733,7 @@ component of frequency drift.</p>
         return ret
 
     def local_gps_gnuplot(self):
-        "Generate gnuplot code graphing local GPS statistics"
+        """Generate gnuplot code graphing local GPS statistics."""
         sitename = self.sitename
         gpsmap = self.gpssplit()
         gpslist = list(gpsmap.keys())
@@ -816,7 +816,7 @@ impossible.</p>
         return ret
 
     def local_error_gnuplot(self):
-        "Plot the local clock frequency error."
+        """Plot the local clock frequency error."""
         if not self.loopstats:
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
@@ -875,7 +875,7 @@ line at 0ppm.  Expected values of 99%-1% percentiles: 0.4ppm</p>
         return ret
 
     def loopstats_gnuplot(self, fld, title, legend, freq):
-        "Generate gnuplot code of a given loopstats field"
+        """Generate gnuplot code of a given loopstats field."""
         if not self.loopstats:
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
@@ -943,16 +943,16 @@ plot \
         return ret
 
     def local_offset_jitter_gnuplot(self):
-        "Generate gnuplot code of local clock loop standard deviation"
+        """Generate gnuplot code of local clock loop standard deviation."""
         return self.loopstats_gnuplot(4, "Local RMS Time Jitter", "Jitter", 0)
 
     def local_offset_stability_gnuplot(self):
-        "Generate gnuplot code graphing local clock stability"
+        """Generate gnuplot code graphing local clock stability."""
         return self.loopstats_gnuplot(5, "Local RMS Frequency Jitter",
                                       "Stability", 1)
 
     def peerstats_gnuplot(self, peerlist, fld, title, ptype):
-        "Plot a specified field from peerstats."
+        """Plot a specified field from peerstats."""
 
         peerdict = self.peersplit()
         if not peerlist:
@@ -1167,17 +1167,17 @@ plot \
         return ret
 
     def peer_offsets_gnuplot(self, peerlist=None):
-        "gnuplot Peer Offsets"
+        """gnuplot Peer Offsets."""
         return self.peerstats_gnuplot(peerlist, 4, "Server Offset",
                                       "offset")
 
     def peer_jitters_gnuplot(self, peerlist=None):
-        "gnuplot Peer Jitters"
+        """gnuplot Peer Jitters."""
         return self.peerstats_gnuplot(peerlist, 7, "Server Jitter",
                                       "jitter")
 
     def local_offset_histogram_gnuplot(self):
-        "Plot a histogram of clock offset values from loopstats."
+        """Plot a histogram of clock offset values from loopstats."""
         if not self.loopstats:
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
@@ -1286,7 +1286,7 @@ plot \
 
 
 def local_offset_multiplot(statlist):
-    "Plot comparative local offsets for a list of NTPViz objects."
+    """Plot comparative local offsets for a list of NTPViz objects."""
 
     out = {}
     out['size'] = args.img_size


=====================================
pylib/agentx.py
=====================================
@@ -106,15 +106,15 @@ class MIBControl:
 
     # These exist instead of just using getOID_core so semantics are clearer
     def getOID(self, searchoid, returnGenerator=False):
-        "Get the requested OID"
+        """Get the requested OID."""
         return self.getOID_core(False, searchoid, returnGenerator)
 
     def getNextOID(self, searchoid, returnGenerator=False):
-        "Get the next lexicographical OID"
+        """Get the next lexicographical OID."""
         return self.getOID_core(True, searchoid, returnGenerator)
 
     def getOIDsInRange(self, oidrange, firstOnly=False):
-        "Get a list of every (optionally the first) OID in a range"
+        """Get a list of every (optionally the first) OID in a range."""
         oids = []
         gen = walkMIBTree(self.oidTree, self.mibRoot)
         # Find the first OID
@@ -246,7 +246,8 @@ class PacketControl:
         self.stillConnected = True
 
     def waitForResponse(self, opkt, ignoreSID=False):
-        "Wait for a response to a specific packet, dropping everything else"
+        """Wait for a response to a specific packet, dropping everything
+        else."""
         while True:
             self.packetEater()
             while self.receivedPackets:
@@ -263,7 +264,7 @@ class PacketControl:
             time.sleep(self.spinGap)
 
     def checkResponses(self):
-        "Check for expected responses that have timed out"
+        """Check for expected responses that have timed out."""
         currentTime = time.time()
         for key in list(self.packetLog.keys()):
             expiration, originalPkt, callback = self.packetLog[key]
@@ -273,7 +274,8 @@ class PacketControl:
                 del self.packetLog[key]
 
     def packetEater(self):
-        "Slurps data from the input buffer and tries to parse packets from it"
+        """Slurps data from the input buffer and tries to parse packets from
+        it."""
         self.pollSocket()
         while True:
             datalen = len(self.receivedData)
@@ -345,7 +347,7 @@ class PacketControl:
         self.sendPacket(err, False)
 
     def pollSocket(self):
-        "Reads all currently available data from the socket, non-blocking"
+        """Reads all currently available data from the socket, non-blocking."""
         data = b""
         while True:
             tmp = select.select([self.socket], [], [], 0)[0]


=====================================
pylib/agentx_packet.py
=====================================
@@ -86,7 +86,8 @@ class AgentXPDU:
         self._hascontext = hascontext
 
     def packetVars(self):
-        "Assembles a list of class variables that it is desirable to print"
+        """Assembles a list of class variables that it is desirable to
+        print."""
         pktvars = {}
         names = dir(self)
         names.remove("context")
@@ -730,7 +731,8 @@ class ResponsePDU(AgentXPDU):
 
 
 def classifyOID(oid):
-    "Utility function to allow the user to send a bare tuple for some cases"
+    """Utility function to allow the user to send a bare tuple for some
+    cases."""
     if isinstance(oid, OID):
         return oid
     return OID(oid, False)


=====================================
pylib/packet.py
=====================================
@@ -262,7 +262,8 @@ MAX_BARE_MAC_LENGTH = 20
 
 
 class Packet:
-    "Encapsulate an NTP fragment"
+
+    """Encapsulate an NTP fragment."""
     # The following two methods are copied from macros in includes/control.h
     @staticmethod
     def VN_MODE(v, m):
@@ -311,7 +312,8 @@ class SyncException(BaseException):  # pragma: no cover
 
 
 class SyncPacket(Packet):
-    "Mode 1-5 time-synchronization packet, including SNTP."
+
+    """Mode 1-5 time-synchronization packet, including SNTP."""
     format = "!BBBbIIIQQQQ"
     HEADER_LEN = 48
     UNIX_EPOCH = 2208988800     # Midnight 1 Jan 1970 in secs since NTP epoch
@@ -384,19 +386,19 @@ class SyncPacket(Packet):
 
     @staticmethod
     def ntp_to_posix(t):
-        "Scale from NTP time to POSIX time"
+        """Scale from NTP time to POSIX time."""
         # Note: assumes we're in the same NTP era as the transmitter...
         return (t / (2**32)) - SyncPacket.UNIX_EPOCH
 
     @staticmethod
     def posix_to_ntp(t):
-        "Scale from POSIX time to NTP time"
+        """Scale from POSIX time to NTP time."""
         # Note: assumes we're in the same NTP era as the transmitter...
         # This receives floats, can't use shifts
         return int((t + SyncPacket.UNIX_EPOCH) * 2**32)
 
     def posixize(self):
-        "Rescale all timestamps to POSIX time."
+        """Rescale all timestamps to POSIX time."""
         if not self.rescaled:
             self.rescaled = True
             self.root_delay >>= 16
@@ -424,16 +426,16 @@ class SyncPacket(Packet):
         return self.received
 
     def delta(self):
-        "Packet flight time"
+        """Packet flight time."""
         return (self.t4() - self.t1()) - (self.t3() - self.t2())
 
     def epsilon(self):
-        "Residual error due to clock imprecision."
+        """Residual error due to clock imprecision."""
         # FIXME: Include client imprecision.
         return SyncPacket.PHI * (self.t4() - self.t1()) + 2**self.precision
 
     def synchd(self):
-        "Synchronization distance, estimates worst-case error in seconds"
+        """Synchronization distance, estimates worst-case error in seconds."""
         # This is "lambda" in NTP-speak, but that's a Python keyword
         return abs(self.delta()/2 + self.epsilon())
 
@@ -442,7 +444,7 @@ class SyncPacket(Packet):
         return ((self.t2()-self.t1())+(self.t3()-self.t4()))/2
 
     def flatten(self):
-        "Flatten the packet into an octet sequence."
+        """Flatten the packet into an octet sequence."""
         body = struct.pack(SyncPacket.format,
                            self.li_vn_mode,
                            self.stratum,
@@ -458,18 +460,18 @@ class SyncPacket(Packet):
         return body + self.extension
 
     def refid_octets(self):
-        "Analyze refid into octets."
+        """Analyze refid into octets."""
         return ((self.refid >> 24) & 0xff,
                 (self.refid >> 16) & 0xff,
                 (self.refid >> 8) & 0xff,
                 self.refid & 0xff)
 
     def refid_as_string(self):
-        "Sometimes it's a clock name or KOD type"
+        """Sometimes it's a clock name or KOD type."""
         return ntp.poly.polystr(struct.pack(*(("BBBB",) + self.refid_octets())))
 
     def refid_as_address(self):
-        "Sometimes it's an IPV4 address."
+        """Sometimes it's an IPV4 address."""
         return ntp.poly.polystr("%d.%d.%d.%d" % self.refid_octets())
 
     def is_crypto_nak(self):
@@ -482,7 +484,7 @@ class SyncPacket(Packet):
         return len(self.mac) == 24
 
     def __repr__(self):
-        "Represent a posixized sync packet in an eyeball-friendly format."
+        """Represent a posixized sync packet in an eyeball-friendly format."""
         r = "<NTP:%s:%d:%d:" % (self.leap(), self.version(), self.mode())
         r += "%f:%f" % (self.root_delay, self.root_dispersion)
         rs = self.refid_as_string()
@@ -506,7 +508,8 @@ class SyncPacket(Packet):
 
 
 class ControlPacket(Packet):
-    "Mode 6 request/response."
+
+    """Mode 6 request/response."""
 
     def __init__(self, session, opcode=0, associd=0, qdata=''):
         Packet.__init__(self, mode=ntp.magic.MODE_CONTROL,
@@ -541,7 +544,7 @@ class ControlPacket(Packet):
         return self.count + self.offset
 
     def stats(self):
-        "Return statistics on a fragment."
+        """Return statistics on a fragment."""
         return "%5d %5d\t%3d octets\n" % (self.offset, self.end(), self.count)
 
     def analyze(self, rawdata):
@@ -558,7 +561,7 @@ class ControlPacket(Packet):
         return (self.sequence, self.status, self.associd, self.offset)
 
     def flatten(self):
-        "Flatten the packet into an octet sequence."
+        """Flatten the packet into an octet sequence."""
         body = struct.pack(ControlPacket.format,
                            self.li_vn_mode,
                            self.r_e_m_op,
@@ -574,7 +577,8 @@ class ControlPacket(Packet):
 
 
 class Peer:
-    "The information we have about an NTP peer."
+
+    """The information we have about an NTP peer."""
 
     def __init__(self, session, associd, status):
         self.session = session
@@ -618,7 +622,7 @@ SERR_NOTRUST = "***No trusted keys have been declared"
 
 
 def dump_hex_printable(xdata, outfp=sys.stdout):
-    "Dump a packet in hex, in a familiar hex format"
+    """Dump a packet in hex, in a familiar hex format."""
     rowsize = 16
     while xdata:
         # Slice one row off of our data
@@ -638,7 +642,8 @@ def dump_hex_printable(xdata, outfp=sys.stdout):
 
 
 class MRUEntry:
-    "A traffic entry for an MRU list."
+
+    """A traffic entry for an MRU list."""
 
     def __init__(self):
         self.addr = None        # text of IPv4 or IPv6 address and port
@@ -678,14 +683,16 @@ class MRUEntry:
 
 
 class MRUList:
-    "A sequence of address-timespan pairs returned by ntpd in one response."
+
+    """A sequence of address-timespan pairs returned by ntpd in one
+    response."""
 
     def __init__(self):
         self.entries = []       # A list of MRUEntry objects
         self.now = None         # server timestamp marking end of operation
 
     def is_complete(self):
-        "Is the server done shipping entries for this span?"
+        """Is the server done shipping entries for this span?"""
         return self.now is not None
 
     def __repr__(self):
@@ -703,7 +710,8 @@ class ControlException(BaseException):
 
 
 class ControlSession:
-    "A session to a host"
+
+    """A session to a host."""
     MRU_ROW_LIMIT = 256
     _authpass = True
     server_errors = {
@@ -750,11 +758,11 @@ class ControlSession:
             self.sock = None
 
     def havehost(self):
-        "Is the session connected to a host?"
+        """Is the session connected to a host?"""
         return self.sock is not None
 
     def __lookuphost(self, hname, fam):
-        "Try different ways to interpret an address and family"
+        """Try different ways to interpret an address and family."""
         if hname.startswith("["):
             hname = hname[1:-1]
         # First try to resolve it as an ip address and if that fails,
@@ -838,7 +846,7 @@ class ControlSession:
         return True
 
     def password(self):
-        "Get a keyid and the password if we don't have one."
+        """Get a keyid and the password if we don't have one."""
         if self.keyid is None:
             if self.auth is None:
                 try:
@@ -879,7 +887,7 @@ class ControlSession:
             self.passwd = passwd
 
     def sendpkt(self, xdata):
-        "Send a packet to the host."
+        """Send a packet to the host."""
         while len(xdata) % 4:
             xdata += b"\x00"
         ntp.util.dolog(self.logfp,
@@ -899,7 +907,7 @@ class ControlSession:
         return 0
 
     def sendrequest(self, opcode, associd, qdata, auth=False):
-        "Ship an ntpq request packet to a server."
+        """Ship an ntpq request packet to a server."""
         if (self.debug >= 1) and (self.logfp is not None):
             # special, not replacing with dolog()
             if self.debug >= 3:
@@ -952,7 +960,7 @@ class ControlSession:
         return pkt.send()
 
     def getresponse(self, opcode, associd, timeo):
-        "Get a response expected to match a given opcode and associd."
+        """Get a response expected to match a given opcode and associd."""
         # This is pretty tricky.  We may get between 1 and MAXFRAG packets
         # back in response to the request.  We peel the data out of
         # each packet and collect it in one long block.  When the last
@@ -1194,7 +1202,7 @@ class ControlSession:
         return True
 
     def doquery(self, opcode, associd=0, qdata="", auth=False):
-        "send a request and save the response"
+        """Send a request and save the response."""
         if not self.havehost():
             raise ControlException(SERR_NOHOST)
         retry = True
@@ -1215,7 +1223,7 @@ class ControlSession:
         return res
 
     def readstat(self, associd=0):
-        "Read peer status, or throw an exception."
+        """Read peer status, or throw an exception."""
         self.doquery(opcode=ntp.control.CTL_OP_READSTAT, associd=associd)
         if len(self.response) % 4:
             raise ControlException(SERR_BADLENGTH)
@@ -1229,7 +1237,7 @@ class ControlSession:
         return idlist
 
     def __parse_varlist(self, raw=False):
-        "Parse a response as a textual varlist."
+        """Parse a response as a textual varlist."""
         # Strip out NULs and binary garbage from text;
         # ntpd seems prone to generate these, especially
         # in reslist responses.
@@ -1283,7 +1291,7 @@ class ControlSession:
 
     def readvar(self, associd=0, varlist=None,
                 opcode=ntp.control.CTL_OP_READVAR, raw=False):
-        "Read system vars from the host as a dict, or throw an exception."
+        """Read system vars from the host as a dict, or throw an exception."""
         if varlist is None:
             qdata = ""
         else:
@@ -1292,7 +1300,10 @@ class ControlSession:
         return self.__parse_varlist(raw)
 
     def config(self, configtext):
-        "Send configuration text to the daemon. Return True if accepted."
+        """Send configuration text to the daemon.
+
+        Return True if accepted.
+        """
         self.doquery(opcode=ntp.control.CTL_OP_CONFIGURE,
                      qdata=configtext, auth=True)
         # Copes with an implementation error - ntpd uses putdata without
@@ -1305,10 +1316,10 @@ class ControlSession:
         return self.response == ntp.poly.polybytes("Config Succeeded")
 
     def fetch_nonce(self):
+        """Ask for, and get, a nonce that can be replayed.
+
+        This combats source address spoofing
         """
-Ask for, and get, a nonce that can be replayed.
-This combats source address spoofing
-"""
         for i in range(4):
             # retry 4 times
             self.doquery(opcode=ntp.control.CTL_OP_REQ_NONCE)
@@ -1327,7 +1338,7 @@ This combats source address spoofing
         raise ControlException(SERR_BADNONCE)
 
     def __mru_analyze(self, variables, span, direct):
-        """Extracts data from the key/value list into a more useful form"""
+        """Extracts data from the key/value list into a more useful form."""
         mru = None
         nonce = None
         items = list(variables.items())
@@ -1417,7 +1428,7 @@ This combats source address spoofing
         return restarted_count, cap_frags, limit, frags
 
     def mrulist(self, variables=None, rawhook=None, direct=None):
-        "Retrieve MRU list data"
+        """Retrieve MRU list data."""
         restarted_count = 0
         cap_frags = True
         sorter = None
@@ -1523,7 +1534,7 @@ This combats source address spoofing
         return span
 
     def __ordlist(self, listtype):
-        "Retrieve ordered-list data."
+        """Retrieve ordered-list data."""
         self.doquery(opcode=ntp.control.CTL_OP_READ_ORDLIST_A,
                      qdata=listtype, auth=True)
         stanzas = []
@@ -1538,11 +1549,11 @@ This combats source address spoofing
         return stanzas
 
     def reslist(self):
-        "Retrieve reslist data."
+        """Retrieve reslist data."""
         return self.__ordlist("addr_restrictions")
 
     def ifstats(self):
-        "Retrieve ifstats data."
+        """Retrieve ifstats data."""
         return self.__ordlist("ifstats")
 
 
@@ -1681,7 +1692,8 @@ def mru_kv_key(token):
 
 
 class Authenticator:
-    "MAC authentication manager for NTP packets."
+
+    """MAC authentication manager for NTP packets."""
 
     def __init__(self, keyfile=None):
         # We allow I/O and permission errors upward deliberately
@@ -1703,15 +1715,15 @@ class Authenticator:
                 self.passwords[int(keyid)] = (keytype, passwd)
 
     def __len__(self):
-        'return the number of keytype/passwd tuples stored'
+        """Return the number of keytype/passwd tuples stored."""
         return len(self.passwords)
 
     def __getitem__(self, keyid):
-        'get a keytype/passwd tuple by keyid'
+        """Get a keytype/passwd tuple by keyid."""
         return self.passwords.get(keyid)
 
     def control(self, keyid=None):
-        "Get the keytype/passwd tuple that controls localhost and its id"
+        """Get the keytype/passwd tuple that controls localhost and its id."""
         if keyid is not None:
             if keyid in self.passwords:
                 return (keyid,) + self.passwords[keyid]
@@ -1732,7 +1744,7 @@ class Authenticator:
 
     @staticmethod
     def compute_mac(payload, keyid, keytype, passwd):
-        'Create the authentication payload to send'
+        """Create the authentication payload to send."""
         if not ntp.ntpc.checkname(keytype):
             return False
         mac2 = ntp.ntpc.mac(ntp.poly.polybytes(payload),
@@ -1743,14 +1755,15 @@ class Authenticator:
 
     @staticmethod
     def have_mac(packet):
-        "Does this packet have a MAC?"
+        """Does this packet have a MAC?"""
         # According to RFC 5909 7.5 the MAC is always present when an extension
         # field is present. Note: this crude test will fail on Mode 6 packets.
         # On those you have to go in and look at the count.
         return len(packet) > ntp.magic.LEN_PKT_NOMAC
 
     def verify_mac(self, packet, packet_end=48, mac_begin=48):
-        "Does the MAC on this packet verify according to credentials we have?"
+        """Does the MAC on this packet verify according to credentials we
+        have?"""
         payload = packet[:packet_end]
         keyid = packet[mac_begin:mac_begin+KEYID_LENGTH]
         mac = packet[mac_begin+KEYID_LENGTH:]


=====================================
pylib/poly.py
=====================================
@@ -2,7 +2,7 @@
 # SPDX-License-Identifier: BSD-2-Clause
 """Handle bytes and strings in a polyglot fashion.
 
-copied from ../ntpclient/ntpq.py  which got it from
+This is copied from ../ntpclient/ntpq.py  which got it from
 https://gitlab.com/esr/practical-python-porting/blob/master/polystr-inclusion.py
 see http://www.catb.org/esr/faqs/practical-python-porting/ for more information.
 """
@@ -70,18 +70,16 @@ else:  # Python 3
         return bytes(s, encoding=master_encoding)
 
     def polyord(c):
-        "Polymorphic ord() function"
+        """Polymorphic ord() function."""
         if isinstance(c, str):
             return ord(c)
-        else:
-            return c
+        return c
 
     def polychr(c):
-        "Polymorphic chr() function"
+        """Polymorphic chr() function."""
         if isinstance(c, int):
             return chr(c)
-        else:
-            return c
+        return c
 
     def string_escape(s):
         """Polymorphic string_escape/unicode_escape."""


=====================================
pylib/statfiles.py
=====================================
@@ -19,7 +19,8 @@ import time
 
 
 class NTPStats:
-    "Gather statistics for a specified NTP site"
+
+    """Gather statistics for a specified NTP site."""
     SecondsInDay = 24*60*60
     DefaultPeriod = 7*24*60*60  # default 7 days, 604800 secs
     peermap = {}    # cached result of peersplit()
@@ -31,8 +32,10 @@ class NTPStats:
     @staticmethod
     def unixize(lines, starttime, endtime):
         """Extract first two fields, MJD and seconds past midnight.
+
         convert timestamp (MJD & seconds past midnight) to Unix time
-        Replace MJD+second with Unix time."""
+        Replace MJD+second with Unix time.
+        """
         # HOT LOOP!  Do not change w/o profiling before and after
         lines1 = []
         for line in lines:
@@ -56,13 +59,15 @@ class NTPStats:
 
     @staticmethod
     def timestamp(line):
-        "get Unix time from converted line."
+        """Get Unix time from converted line."""
         return float(line.split()[0])
 
     @staticmethod
     def percentiles(percents, values):
         """Return given percentiles of a given row in a given set of entries.
-        assuming values are already split and sorted"""
+
+        assuming values are already split and sorted
+        """
         ret = {}
         length = len(values)
         if 1 >= length:
@@ -85,7 +90,7 @@ class NTPStats:
 
     @staticmethod
     def ip_label(key):
-        "Produce appropriate label for an IP address."
+        """Produce appropriate label for an IP address."""
         # If it's a new-style NTPsep clock label, pass it through,
         # Otherwise we expect it to be an IP address and the next guard fires
         if key[0].isdigit():
@@ -108,7 +113,7 @@ class NTPStats:
 
     def __init__(self, statsdir, sitename=None,
                  period=None, starttime=None, endtime=None):
-        "Grab content of logfiles, sorted by timestamp."
+        """Grab content of logfiles, sorted by timestamp."""
         if period is None:
             period = NTPStats.DefaultPeriod
         self.period = period
@@ -201,7 +206,9 @@ class NTPStats:
 
     def peersplit(self):
         """Return a dictionary mapping peerstats IPs to entry subsets.
-        This is very expensive, so cache the result"""
+
+        This is very expensive, so cache the result
+        """
         if self.peermap:
             return self.peermap
 
@@ -217,7 +224,7 @@ class NTPStats:
         return self.peermap
 
     def gpssplit(self):
-        "Return a dictionary mapping gps sources to entry subsets."
+        """Return a dictionary mapping gps sources to entry subsets."""
         gpsmap = {}
         for row in self.gpsd:
             try:
@@ -231,7 +238,7 @@ class NTPStats:
         return gpsmap
 
     def tempssplit(self):
-        "Return a dictionary mapping temperature sources to entry subsets."
+        """Return a dictionary mapping temperature sources to entry subsets."""
         tempsmap = {}
         for row in self.temps:
             try:
@@ -246,7 +253,10 @@ class NTPStats:
 
 
 def iso_to_posix(time_string):
-    "Accept timestamps in ISO 8661 format or numeric POSIX time. UTC only."
+    """Accept timestamps in ISO 8661 format or numeric POSIX time.
+
+    UTC only.
+    """
     if str(time_string).isdigit():
         return int(time_string)
     time_struct = time.strptime(time_string, "%Y-%m-%dT%H:%M:%S")
@@ -255,7 +265,7 @@ def iso_to_posix(time_string):
 
 
 def posix_to_iso(unix_time):
-    "ISO 8601 string in UTC from Unix time."
+    """ISO 8601 string in UTC from Unix time."""
     return time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(unix_time))
 
 # end


=====================================
pylib/util.py
=====================================
@@ -1,10 +1,11 @@
 # -*- coding: utf-8 -*-
-"Common utility functions"
+"""Common utility functions."""
 # SPDX-License-Identifier: BSD-2-Clause
 
 from __future__ import print_function, division
 
 
+import ast
 import collections
 import os
 import re
@@ -59,6 +60,7 @@ def check_unicode():  # pragma: no cover
 
 def deunicode_units():  # pragma: no cover
     """Under certain conditions it is not possible to force unicode output,
+
     this overwrites units that contain unicode with safe versions"""
     global UNIT_US
     global UNIT_PPK
@@ -85,6 +87,7 @@ PPM_VARS = ("frequency", "clk_wander")
 
 def dolog(logfp, text, debug, threshold):
     """debug is the current debug value
+
     threshold is the trigger for the current log"""
     if logfp is None:
         return  # can turn off logging by supplying a None file descriptor
@@ -96,8 +99,10 @@ def dolog(logfp, text, debug, threshold):
 
 def safeargcast(arg, castfunc, errtext, usage):
     """Attempts to typecast an argument, prints and dies on failure.
+
     errtext must contain a %s for splicing in the argument, and be
-    newline terminated."""
+    newline terminated.
+    """
     try:
         casted = castfunc(arg)
     except ValueError:
@@ -108,12 +113,12 @@ def safeargcast(arg, castfunc, errtext, usage):
 
 
 def stdversion():
-    "Returns the NTPsec version string in a standard format"
+    """Returns the NTPsec version string in a standard format."""
     return "ntpsec-%s" % "@NTPSEC_VERSION_EXTENDED@"
 
 
 def rfc3339(t):
-    "RFC 3339 string from Unix time, including fractional second."
+    """RFC 3339 string from Unix time, including fractional second."""
     rep = time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(t))
     t = str(t)
     if "." in t:
@@ -141,7 +146,7 @@ def hexstr2octets(hexstr):
 
 
 def slicedata(data, slicepoint):
-    "Breaks a sequence into two pieces at the slice point"
+    """Breaks a sequence into two pieces at the slice point."""
     return data[:slicepoint], data[slicepoint:]
 
 
@@ -199,7 +204,7 @@ def parseConf(text):
             elif text[i] == "\\":  # Starting an escape sequence
                 i += 1
                 if text[i] in "'\"n\\":
-                    current.append(eval("\'\\" + text[i] + "\'"))
+                    current.append(ast.literal_eval("\'\\" + text[i] + "\'"))
             else:
                 current.append(text[i])
         else:
@@ -229,7 +234,7 @@ def parseConf(text):
 
 
 def stringfilt(data):
-    "Pretty print string of space separated numbers"
+    """Pretty print string of space separated numbers."""
     parts = data.split()
 
     cooked = []
@@ -244,14 +249,15 @@ def stringfilt(data):
 
 
 def stringfiltcooker(data):
-    "Cooks a filt* string of space separated numbers, expects milliseconds"
+    """Cooks a filt* string of space separated numbers, expects
+    milliseconds."""
     parts = data.split()
     oomcount = {}
     minscale = -100000  # Keep track of the maxdownscale for each value
     # Find out what the 'natural' unit of each value is
     for part in parts:
         # Only care about OOMs, the real scaling happens later
-        value, oom = scalestring(part)
+        oom = scalestring(part)[1]
         # Track the highest maxdownscale so we do not invent precision
         ds = maxdownscale(part)
         minscale = max(ds, minscale)
@@ -278,14 +284,14 @@ def stringfiltcooker(data):
 
 
 def getunitgroup(unit):
-    "Returns the unit group which contains a given unit"
+    """Returns the unit group which contains a given unit."""
     for group in unitgroups:
         if unit in group:
             return group
 
 
 def oomsbetweenunits(a, b):
-    "Calculates how many orders of magnitude separate two units"
+    """Calculates how many orders of magnitude separate two units."""
     group = getunitgroup(a)
     if b is None:  # Caller is asking for the distance from the base unit
         return group.index(a) * 3
@@ -297,7 +303,7 @@ def oomsbetweenunits(a, b):
 
 
 def breaknumberstring(value):
-    "Breaks a number string into (aboveDecimal, belowDecimal, isNegative?)"
+    """Breaks a number string into (aboveDecimal, belowDecimal, isNegative?)"""
     if value[0] == "-":
         value = value[1:]
         negative = True
@@ -312,7 +318,7 @@ def breaknumberstring(value):
 
 
 def gluenumberstring(above, below, isnegative):
-    "Glues together parts of a number string"
+    """Glues together parts of a number string."""
     if above == "":
         above = "0"
     if below:
@@ -325,18 +331,17 @@ def gluenumberstring(above, below, isnegative):
 
 
 def maxdownscale(value):
-    "Maximum units a value can be scaled down without inventing data"
+    """Maximum units a value can be scaled down without inventing data."""
     if "." in value:
         digitcount = len(value.split(".")[1])
         # Return a negative so it can be fed directly to a scaling function
         return -(digitcount // 3)
-    else:
-        # No decimals, the value is already at the maximum down-scale
-        return 0
+    # No decimals, the value is already at the maximum down-scale
+    return 0
 
 
 def rescalestring(value, unitsscaled):
-    "Rescale a number string by a given number of units"
+    """Rescale a number string by a given number of units."""
     whole, dec, negative = breaknumberstring(value)
     if unitsscaled == 0:
         # This may seem redundant, but glue forces certain formatting details
@@ -371,14 +376,14 @@ def rescalestring(value, unitsscaled):
 
 
 def formatzero(value):
-    "Scale a zero value for the unit with the highest available precision"
+    """Scale a zero value for the unit with the highest available precision."""
     scale = maxdownscale(value)
     newvalue = rescalestring(value, scale).lstrip("-")
     return (newvalue, scale)
 
 
 def scalestring(value):
-    "Scales a number string to fit in the range 1.0-999.9"
+    """Scales a number string to fit in the range 1.0-999.9."""
     if isstringzero(value):
         return formatzero(value)
     whole, dec, negative = breaknumberstring(value)
@@ -414,7 +419,8 @@ def scalestring(value):
 
 
 def fitinfield(value, fieldsize):
-    "Attempt to fit value into a field, preserving as much data as possible"
+    """Attempt to fit value into a field, preserving as much data as
+    possible."""
     vallen = len(value)
     if fieldsize is None:
         newvalue = value
@@ -444,7 +450,7 @@ def fitinfield(value, fieldsize):
 
 
 def cropprecision(value, ooms):
-    "Crops digits below the maximum precision"
+    """Crops digits below the maximum precision."""
     if "." not in value:  # No decimals, nothing to crop
         return value
     if ooms == 0:  # We are at the baseunit, crop it all
@@ -459,7 +465,7 @@ def cropprecision(value, ooms):
 
 
 def isstringzero(value):
-    "Detects whether a string is equal to zero"
+    """Detects whether a string is equal to zero."""
     for i in value:
         if i not in ("-", ".", "0"):
             return False
@@ -467,23 +473,21 @@ def isstringzero(value):
 
 
 def unitrelativeto(unit, move):
-    "Returns a unit at a different scale from the input unit"
+    """Returns a unit at a different scale from the input unit."""
     for group in unitgroups:
         if unit in group:
             if move is None:  # asking for the base unit
                 return group[0]
-            else:
-                index = group.index(unit)
-                index += move  # index of the new unit
-                if 0 <= index < len(group):  # found the new unit
-                    return group[index]
-                else:  # not in range
-                    return None
+            index = group.index(unit)
+            index += move  # index of the new unit
+            if 0 <= index < len(group):  # found the new unit
+                return group[index]
+            return None
     return None  # couldn't find anything
 
 
 def unitifyvar(value, varname, baseunit=None, width=8, unitSpace=False):
-    "Call unitify() with the correct units for varname"
+    """Call unitify() with the correct units for varname."""
     if varname in S_VARS:
         start = UNIT_S
     elif varname in MS_VARS:
@@ -496,7 +500,10 @@ def unitifyvar(value, varname, baseunit=None, width=8, unitSpace=False):
 
 
 def unitify(value, startingunit, baseunit=None, width=8, unitSpace=False):
-    "Formats a numberstring with relevant units. Attempts to fit in width."
+    """Formats a numberstring with relevant units.
+
+    Attempts to fit in width.
+    """
     if baseunit is None:
         baseunit = getunitgroup(startingunit)[0]
     ooms = oomsbetweenunits(startingunit, baseunit)
@@ -525,46 +532,9 @@ def unitify(value, startingunit, baseunit=None, width=8, unitSpace=False):
     return newvalue
 
 
-def f8dot4(f):
-    "Scaled floating point formatting to fit in 8 characters"
-
-    if isinstance(f, str):
-        # a string? pass it on as a signal
-        return "%8s" % f
-    if not isinstance(f, (int, float)):
-        # huh?
-        return "       X"
-    if str(float(f)).lower() == 'nan':
-        # yes, this is a better test than math.isnan()
-        # it also catches None, strings, etc.
-        return "     nan"
-
-    fmt = "%8d"          # xxxxxxxx or -xxxxxxx
-    if f >= 0:
-        if f < 1000.0:
-            fmt = "%8.4f"    # xxx.xxxx  normal case
-        elif f < 10000.0:
-            fmt = "%8.3f"    # xxxx.xxx
-        elif f < 100000.0:
-            fmt = "%8.2f"    # xxxxx.xx
-        elif f < 1000000.0:
-            fmt = "%8.1f"    # xxxxxx.x
-    else:
-        # negative number, account for minus sign
-        if f > -100.0:
-            fmt = "%8.4f"      # -xx.xxxx  normal case
-        elif f > -1000.0:
-            fmt = "%8.3f"      # -xxx.xxx
-        elif f > -10000.0:
-            fmt = "%8.2f"      # -xxxx.xx
-        elif f > -100000.0:
-            fmt = "%8.1f"      # -xxxxx.x
-
-    return fmt % f
-
+def f8poly(f, clip):
+    """Scaled floating point formatting to fit in 8 characters."""
 
-def f8dot3(f):
-    "Scaled floating point formatting to fit in 8 characters"
     if isinstance(f, str):
         # a string? pass it on as a signal
         return "%8s" % f
@@ -575,29 +545,21 @@ def f8dot3(f):
         # yes, this is a better test than math.isnan()
         # it also catches None, strings, etc.
         return "     nan"
+    # The following chunk is thool code
+    digits = 8 if f >= 0 else 7
+    fab = abs(f)
+    for _ in range(5, 0, -1):
+        if fab < 10 ** (digits - _ - 1):
+            return '{:8.{}f}'.format(f, min(clip, _))
+    return '%8d' % f
 
-    fmt = "%8d"          # xxxxxxxx or -xxxxxxx
-    if f >= 0:
-        if f < 10000.0:
-            fmt = "%8.3f"    # xxxx.xxx  normal case
-        elif f < 100000.0:
-            fmt = "%8.2f"    # xxxxx.xx
-        elif f < 1000000.0:
-            fmt = "%8.1f"    # xxxxxx.x
-    else:
-        # negative number, account for minus sign
-        if f > -1000.0:
-            fmt = "%8.3f"    # -xxx.xxx  normal case
-        elif f > -10000.0:
-            fmt = "%8.2f"    # -xxxx.xx
-        elif f > -100000.0:
-            fmt = "%8.1f"    # -xxxxx.x
 
-    return fmt % f
+f8dot4 = lambda f: f8poly(f, 4)
+f8dot3 = lambda f: f8poly(f, 3)
 
 
 def monoclock():
-    "Try to get a monotonic clock value unaffected by NTP stepping."
+    """Try to get a monotonic clock value unaffected by NTP stepping."""
     try:
         # Available in Python 3.3 and up.
         return time.monotonic()
@@ -606,8 +568,11 @@ def monoclock():
 
 
 class Cache:
+
     "Simple time-based cache"
 
+    """Simple time-based cache."""
+
     def __init__(self, defaultTimeout=300):  # 5 min default TTL
         self.defaultTimeout = defaultTimeout
         self._cache = {}
@@ -617,11 +582,9 @@ class Cache:
             value, settime, ttl = self._cache[key]
             if settime >= monoclock() - ttl:
                 return value
-            else:  # key expired, delete it
-                del self._cache[key]
-                return None
-        else:
+            del self._cache[key]  # key expired, delete it
             return None
+        return None
 
     def set(self, key, value, customTTL=None):
         ttl = customTTL if customTTL is not None else self.defaultTimeout
@@ -633,7 +596,7 @@ canonicalization_cache = Cache()
 
 
 def canonicalize_dns(inhost, family=socket.AF_UNSPEC):
-    "Canonicalize a hostname or numeric IP address."
+    """Canonicalize a hostname or numeric IP address."""
     resname = canonicalization_cache.get(inhost)
     if resname is not None:
         return resname
@@ -647,7 +610,7 @@ def canonicalize_dns(inhost, family=socket.AF_UNSPEC):
                                 socket.AI_CANONNAME)
     except socket.gaierror:
         return "DNSFAIL:%s" % hostname
-    (family, socktype, proto, canonname, sockaddr) = ai[0]
+    (family, socktype, _, canonname, sockaddr) = ai[0]
     try:
         name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
         result = name[0].lower() + portsuffix
@@ -674,7 +637,7 @@ if str is bytes:  # We are on python 2.x
 
 
 def termsize():  # pragma: no cover
-    "Return the current terminal size."
+    """Return the current terminal size."""
     # Alternatives at http://stackoverflow.com/questions/566746
     # The way this is used makes it not a big deal if the default is wrong.
     size = (80, 24)
@@ -687,7 +650,7 @@ def termsize():  # pragma: no cover
         else:
             try:
                 # OK, Python version < 3.3, cope
-                h, w, hp, wp = struct.unpack(
+                h, w, hp, _ = struct.unpack(
                     'HHHH',
                     fcntl.ioctl(2, termios.TIOCGWINSZ,
                                 struct.pack('HHHH', 0, 0, 0, 0)))
@@ -698,8 +661,11 @@ def termsize():  # pragma: no cover
 
 
 class PeerStatusWord:
+
     "A peer status word from readstats(), dissected for display"
 
+    """A peer status word from readstats(), dissected for display."""
+
     def __init__(self, status, pktversion=ntp.magic.NTP_VERSION):
         # Event
         self.event = ntp.control.CTL_PEER_EVENT(status)
@@ -775,7 +741,7 @@ class PeerStatusWord:
 
 
 def cook(variables, showunits=False, sep=", "):
-    "Cooked-mode variable display."
+    """Cooked-mode variable display."""
     width = ntp.util.termsize().width - 2
     text = ""
     specials = ("filtdelay", "filtoffset", "filtdisp", "filterror")
@@ -825,7 +791,7 @@ def cook(variables, showunits=False, sep=", "):
                     "peer_loop",        # BOGON12
                     "peer_unreach"      # BOGON13
                 )
-                for (i, n) in enumerate(tstflagnames):
+                for (i, _) in enumerate(tstflagnames):
                     if (1 << i) & value:
                         item += tstflagnames[i] + " "
             item = item[:-1]
@@ -866,8 +832,8 @@ def cook(variables, showunits=False, sep=", "):
 
 
 class PeerSummary:
-    "Reusable report generator for peer statistics"
 
+    """Reusable report generator for peer statistics."""
     def __init__(self, displaymode, pktversion, showhostnames,
                  wideremote, showunits=False, termwidth=None,
                  debug=0, logfp=sys.stderr):
@@ -899,7 +865,7 @@ class PeerSummary:
 
     @staticmethod
     def prettyinterval(diff):
-        "Print an interval in natural time units."
+        """Print an interval in natural time units."""
         if not isinstance(diff, int) or diff <= 0:
             return '-'
         if diff <= 2048:
@@ -915,20 +881,19 @@ class PeerSummary:
 
     @staticmethod
     def high_truncate(hostname, maxlen):
-        "Truncate on the left using leading _ to indicate 'more'."
+        """Truncate on the left using leading _ to indicate 'more'."""
         # Used for local IPv6 addresses, best distinguished by low bits
         if len(hostname) <= maxlen:
             return hostname
-        else:
-            return '-' + hostname[-maxlen+1:]
+        return '-' + hostname[-maxlen+1:]
 
     @staticmethod
     def is_clock(variables):
-        "Does a set of variables look like it returned from a clock?"
+        """Does a set of variables look like it returned from a clock?"""
         return "srchost" in variables and '(' in variables["srchost"][0]
 
     def header(self):
-        "Column headers for peer display"
+        """Column headers for peer display."""
         if self.displaymode == "apeers":
             self.__header = self.__remote + \
                 "   refid   assid  ".ljust(self.refidwidth) + \
@@ -944,11 +909,11 @@ class PeerSummary:
         return self.__header
 
     def width(self):
-        "Width of display"
+        """Width of display."""
         return 79 + self.horizontal_slack
 
     def summary(self, rstatus, variables, associd):
-        "Peer status summary line."
+        """Peer status summary line."""
         clock_name = ''
         dstadr_refid = ""
         dstport = 0
@@ -1219,14 +1184,15 @@ class PeerSummary:
         return line
 
     def intervals(self):
-        "Return and flush the list of actual poll intervals."
+        """Return and flush the list of actual poll intervals."""
         res = self.polls[:]
         self.polls = []
         return res
 
 
 class MRUSummary:
-    "Reusable class for MRU entry summary generation."
+
+    """Reusable class for MRU entry summary generation."""
 
     def __init__(self, showhostnames, wideremote=False,
                  debug=0, logfp=sys.stderr):
@@ -1317,7 +1283,8 @@ class MRUSummary:
 
 
 class ReslistSummary:
-    "Reusable class for reslist entry summary generation."
+
+    """Reusable class for reslist entry summary generation."""
     header = """\
    hits    addr/prefix or addr mask
            restrictions
@@ -1357,7 +1324,8 @@ class ReslistSummary:
 
 
 class IfstatsSummary:
-    "Reusable class for ifstats entry summary generation."
+
+    """Reusable class for ifstats entry summary generation."""
     header = """\
     interface name                                  send
  #  address/broadcast     drop flag received sent failed peers   uptime
@@ -1416,7 +1384,8 @@ try:
     from collections import OrderedDict
 except ImportError:  # pragma: no cover
     class OrderedDict(dict):
-        "A stupid simple implementation in order to be back-portable to 2.6"
+        """A stupid simple implementation in order to be back-portable to
+        2.6."""
 
         # This can be simple because it doesn't need to be fast.
         # The programs that use it only have to run at human speed,


=====================================
tests/pylib/test_ntpc.py
=====================================
@@ -1,3 +1,4 @@
+"""Pytest module for ntp.ntpc module."""
 #! /usr/bin/env python
 # -*- coding: utf-8 -*-
 # SPDX-License-Identifier: BSD-2-Clause
@@ -6,6 +7,9 @@ import ntp.ntpc
 
 
 class TestPylibNtpc(unittest.TestCase):
+
+    """Add test class for ntp.ntpc module."""
+
     lfp_set = [
         ("0xcfba1ce0.80000000", 1276092000.5,
          "cfba1ce0.80000000 2010-06-09T14:00:00.500Z"),
@@ -14,17 +18,19 @@ class TestPylibNtpc(unittest.TestCase):
         ]
 
     def test_statustoa(self):
+        """Test that statustoa works correctly."""
         self.assertEqual("leap_add_sec, sync_22, 7 events, no_sys_peer",
-                         ntp.ntpc.statustoa(ntp.ntpc.TYPE_SYS, 0x12345678));
+                         ntp.ntpc.statustoa(ntp.ntpc.TYPE_SYS, 0x12345678))
         self.assertEqual("authenb, reach, sel_sys.peer, 7 events, access_denied",
-                         ntp.ntpc.statustoa(ntp.ntpc.TYPE_PEER, 0x12345678));
+                         ntp.ntpc.statustoa(ntp.ntpc.TYPE_PEER, 0x12345678))
         self.assertEqual("7 events, clk_8",
-                         ntp.ntpc.statustoa(ntp.ntpc.TYPE_CLOCK, 0x12345678));
+                         ntp.ntpc.statustoa(ntp.ntpc.TYPE_CLOCK, 0x12345678))
 
     def test_lfp(self):
+        """Test that prettydate and lfptofloat work properly."""
         for (in_string, to_float, to_string) in self.lfp_set:
-            self.assertEqual(ntp.ntpc.prettydate(in_string), to_string);
-            self.assertAlmostEqual(ntp.ntpc.lfptofloat(in_string), to_float);
+            self.assertEqual(ntp.ntpc.prettydate(in_string), to_string)
+            self.assertAlmostEqual(ntp.ntpc.lfptofloat(in_string), to_float)
 
 
 if __name__ == '__main__':


=====================================
wafhelpers/asciidoc.py
=====================================
@@ -1,4 +1,4 @@
-'''Most of the functionality for building HTML and man pages from AsciiDoc.'''
+"""Most of the functionality for building HTML and man pages from AsciiDoc."""
 
 import re
 
@@ -7,7 +7,7 @@ from waflib.TaskGen import extension  # pylint: disable=import-error
 
 
 def options(opt):
-    'Add command line options for AsciiDoc processing.'
+    """Add command line options for AsciiDoc processing."""
     grp = opt.add_option_group('NTP documentation configure options')
     grp.add_option('--disable-doc', action='store_true',
                    default=False, help='Disable HTML document building.')
@@ -20,8 +20,7 @@ def options(opt):
 
 
 def configure(ctx):
-    'Set options from the extended environment and command line arguments.'
-
+    """Set options from the extended environment and command line arguments."""
     if ctx.options.disable_doc and ctx.options.enable_doc:
         ctx.fatal('--disable-doc and --enable-doc conflict.')
     if ctx.options.disable_manpage and ctx.options.enable_manpage:
@@ -128,7 +127,7 @@ def configure(ctx):
 
 
 def build(ctx):
-    'Set processor noise level and set HTML pages to build.'
+    """Set processor noise level and set HTML pages to build."""
     from waflib.Logs import verbose  # pylint: disable=import-error
     if verbose > 1:  # Pass verbosity to AsciiDoc toolchain
         if ctx.env.ARGS_DOC:
@@ -140,7 +139,8 @@ def build(ctx):
 
 
 class html(Task.Task):
-    'Define HTML build process.'
+
+    """Define HTML build process."""
     # Optional weight to tune the priority for task instances.
     # The higher, the earlier. The weight only applies to single task objects.
     weight = 3  # set arbitrarily high to be first as to not slow down later tasks
@@ -149,14 +149,15 @@ class html(Task.Task):
 
 
 class man(Task.Task):
-    'Define manpage build process.'
+
+    """Define manpage build process."""
     weight = 2  # set arbitrarily high to be second as to not slow down later tasks (Failed)
     run_str = '${ARGS_MAN} ${SRC[0].abspath()}'
 
 
 @extension('.adoc')
 def run_html(self, node):
-    'Add HTML build caller function.'
+    """Add HTML build caller function."""
     out = node.change_ext('.html')
     tsk = self.create_task('html', node, [out])
     tsk.cwd = node.parent.get_bld().abspath()
@@ -164,7 +165,7 @@ def run_html(self, node):
 
 @extension('.man-tmp')
 def run_manpage(self, node):
-    'Add manpage build caller function.'
+    """Add manpage build caller function."""
     n_file = node.path_from(self.bld.bldnode)
     out = '%s.%s' % (n_file.replace('-man.adoc.man-tmp', ''), self.section)
     out_n = self.bld.path.find_or_declare(out)


=====================================
wafhelpers/bin_test.py
=====================================
@@ -41,12 +41,14 @@ test_logs = []
 
 
 def addLog(color, text):
-    test_logs.append((color, text))
+    """Append to the test logs."""
+    test_logs.append((color, text.rstrip()))
 
 
-def bin_test_summary(ctx):
+def bin_test_summary(_):
+    """Print out the test logs."""
     for i in test_logs:
-        waflib.Logs.pprint(i[0], i[1])
+        waflib.Logs.pprint(*i)
 
 
 def run(cmd, reg, pythonic):
@@ -85,7 +87,7 @@ def run(cmd, reg, pythonic):
     return False
 
 
-def cmd_bin_test(ctx, config):
+def cmd_bin_test(ctx, _):
     """Run a suite of binary tests."""
     fails = 0
 


=====================================
wafhelpers/check_sizeof.py
=====================================
@@ -10,32 +10,6 @@ int main(void) {
 }
 """
 
-
-def check_sizeof_host(ctx, header, sizeof, mandatory=True):
-    sizeof_ns = sizeof.replace(" ", "_")
-    name = "NTP_SIZEOF_%s" % sizeof_ns.upper()
-
-    header_snippet = ""
-    if header:
-        ctx.start_msg("Checking sizeof %s (%s)" % (sizeof, header))
-        header_snippet = "#include <%s>" % header
-    else:
-        ctx.start_msg("Checking sizeof %s" % (sizeof))
-
-    ctx.check_cc(
-        fragment=SIZE_FRAG % (header_snippet, sizeof),
-        define_name=name,
-        execute=True,
-        define_ret=True,
-        quote=False,
-        mandatory=mandatory,
-        comment="Size of %s from <%s>" % (sizeof, header)
-    )
-    ctx.end_msg(ctx.get_define(name))
-
-
-# Cross compile check.  Much slower so we do not run it all the time.
-
 SIZE_FRAG_CROSS = """
 %s
 #include <sys/stat.h>
@@ -47,19 +21,8 @@ int main(void) {
 """
 
 
-def check_sizeof_cross(ctx, header, sizeof, mandatory=True):
-    sizeof_ns = sizeof.replace(" ", "_")
-    name = "NTP_SIZEOF_%s" % sizeof_ns.upper()
-
-    header_snippet = ""
-    if header:
-        ctx.start_msg("Checking sizeof %s (%s)" % (sizeof, header))
-        header_snippet = "#include <%s>" % header
-    else:
-        ctx.start_msg("Checking sizeof %s" % (sizeof))
-
+def check_sizeof_c(ctx, header, header_snippet, sizeof, name, mandatory=True):
     for size in range(2, 13):
-
         try:
             ctx.check_cc(
                 fragment=SIZE_FRAG_CROSS % (header_snippet, sizeof, size),
@@ -73,13 +36,38 @@ def check_sizeof_cross(ctx, header, sizeof, mandatory=True):
             return
         except Errors.ConfigurationError:
             pass
-
+    ctx.end_msg('Error')
     raise     # never reached.
 
 
+def check_sizeof_n(ctx, header, header_snippet, sizeof, name, mandatory=True):
+    ctx.check_cc(
+        fragment=SIZE_FRAG % (header_snippet, sizeof),
+        define_name=name,
+        execute=True,
+        define_ret=True,
+        quote=False,
+        mandatory=mandatory,
+        comment="Size of %s from <%s>" % (sizeof, header)
+    )
+    ctx.end_msg(ctx.get_define(name))
+
+
 @conf
-def check_sizeof(*kwargs):
-    if kwargs[0].env.ENABLE_CROSS:
-        check_sizeof_cross(*kwargs)
+def check_sizeof(ctx, header, sizeof):
+    """Check and  return the length of a type.
+    
+    The cross compile check is O(n) slower so we do not run it all the time.
+    """
+    sizeof_ns = sizeof.replace(" ", "_")
+    name = "NTP_SIZEOF_%s" % sizeof_ns.upper()
+
+    header_snippet = ""
+    if header:
+        ctx.start_msg("Checking sizeof %s (%s)" % (sizeof, header))
+        header_snippet = "#include <%s>" % header
     else:
-        check_sizeof_host(*kwargs)
+        ctx.start_msg("Checking sizeof %s" % (sizeof))
+
+    cb = check_sizeof_c if ctx.env.ENABLE_CROSS else check_sizeof_n
+    cb(ctx, header, header_snippet, sizeof, name, mandatory=True)


=====================================
wafhelpers/options.py
=====================================
@@ -1,10 +1,12 @@
 def options_cmd(ctx, config):
+    """Add most options for NTPsec to optparse derivative."""
     ctx.load("compiler_c")
     ctx.load("msvc")
     ctx.load('waf_unit_test')
     ctx.load('gnu_dirs')
 
-    def callback_flags(option, opt, value, parser):
+    def callback_flags(option, opt, value, _):
+        """Store some command line options into config."""
         config["OPT_STORE"].setdefault(opt, []).append(value)
 
     grp = ctx.add_option_group("NTP configure options")
@@ -35,7 +37,7 @@ def options_cmd(ctx, config):
     grp = ctx.add_option_group("NTP cross compile options")
     grp.add_option('--cross-compiler', type='string',
                    help="Path to cross compiler CC. (enables cross-compiling)")
-    grp.add_option('--cross-cflags', type='string',  action="callback",
+    grp.add_option('--cross-cflags', type='string', action="callback",
                    callback=callback_flags, help="Cross compiler CFLAGS.")
     grp.add_option('--cross-ldflags', type='string', action="callback",
                    callback=callback_flags, help="Cross compiler LDFLAGS.")


=====================================
wafhelpers/probes.py
=====================================
@@ -1,11 +1,9 @@
-"""
-This module exists to contain custom probe functions so they don't clutter
-up the logic in the main configure.py.
-"""
+"""This module exists to contain custom probe functions so they don't clutter
+up the logic in the main configure.py."""
 
 
 def probe_header(ctx, header, prerequisites, mandatory=False, use=None):
-    "Check that a header (with its prerequisites) compiles."
+    """Check that a header (with its prerequisites) compiles."""
     src = ""
     for hdr in prerequisites + [header]:
         src += "#include <%s>\n" % hdr
@@ -24,7 +22,7 @@ def probe_header(ctx, header, prerequisites, mandatory=False, use=None):
 
 
 def probe_function(ctx, function, prerequisites, mandatory=False, use=None):
-    "Check that a function (with its prerequisites) compiles."
+    """Check that a function (with its prerequisites) compiles."""
     src = ""
     for hdr in prerequisites:
         src += "#include <%s>\n" % hdr


=====================================
wafhelpers/refclock.py
=====================================
@@ -1,3 +1,4 @@
+"""Add refclock backing and handle refclock options."""
 from waflib.Configure import conf
 from waflib.Logs import pprint
 
@@ -105,6 +106,7 @@ refclock_map = {
 
 @conf
 def refclock_config(ctx):
+    """Handle refclock options."""
     if ctx.options.refclocks == "all":
         ids = refclock_map.keys()
     else:
@@ -118,11 +120,11 @@ def refclock_config(ctx):
     [unique_id.append(x) for x in ids if x not in unique_id]
 
     refclock = False
-    for id in unique_id:
-        if id not in refclock_map:
-            ctx.fatal("'%s' is not a valid Refclock ID" % id)
+    for ident in unique_id:
+        if ident not in refclock_map:
+            ctx.fatal("'%s' is not a valid Refclock ID" % ident)
 
-        rc = refclock_map[id]
+        rc = refclock_map[ident]
 
         if rc['define'] == "CLOCK_GENERIC":
             parse_clocks = (
@@ -142,22 +144,21 @@ def refclock_config(ctx):
             for subtype in parse_clocks:
                 ctx.define(subtype, 1, comment="Enable individual parse clock")
 
-        ctx.start_msg("Enabling Refclock %s (%s):" % (rc["descr"], id))
+        ctx.start_msg("Enabling Refclock %s (%s):" % (rc["descr"], ident))
 
-        if "require" in rc:
-            if "ppsapi" in rc["require"]:
-                if not ctx.get_define("HAVE_PPSAPI"):
-                    ctx.end_msg("No")
-                    pprint("RED",
-                           "Refclock \"%s\" disabled, PPS API has not "
-                           "been detected as working." % rc["descr"])
-                    continue
+        if not ctx.get_define("HAVE_PPSAPI"):
+            if "ppsapi" in rc.get("require", {}):
+                ctx.end_msg("No")
+                pprint("RED",
+                       "Refclock \"%s\" disabled, PPS API has not "
+                       "been detected as working." % rc["descr"])
+                continue
 
         ctx.env.REFCLOCK_SOURCE.append((rc["file"], rc["define"]))
         ctx.env["REFCLOCK_%s" % rc["file"].upper()] = True
         ctx.define(rc["define"], 1,
                    comment="Enable '%s' refclock" % rc["descr"])
-        ctx.env.REFCLOCK_LIST += [str(id)]
+        ctx.env.REFCLOCK_LIST += [str(ident)]
 
         ctx.end_msg("Yes")
 


=====================================
wafhelpers/waf.py
=====================================
@@ -1,8 +1,10 @@
+"""Add three miscelaneous tools."""
 from waflib.Configure import conf
 from waflib.TaskGen import re_m4
 
 
 def manpage_subst_fun(self, code):
+    """Convert asciidoc source for manpage."""
     # Since we are providing a custom substitution method, we must implement
     # the default behavior, since we want that too.
     global re_m4
@@ -14,6 +16,7 @@ def manpage_subst_fun(self, code):
     lst = []
 
     def repl(match):
+        """Change @foo@ to %(foo) for (not) str.format()."""
         g = match.group
         if g(1):
             lst.append(g(1))
@@ -40,7 +43,7 @@ def manpage_subst_fun(self, code):
 
 @conf
 def manpage(ctx, section, source):
-
+    """Build a man page in a section."""
     if not ctx.env.BUILD_MAN:
         return
 
@@ -54,6 +57,7 @@ def manpage(ctx, section, source):
 
 @conf
 def ntp_test(ctx, **kwargs):
+    """Run a (Python?) test."""
     bldnode = ctx.bldnode.abspath()
     tg = ctx(**kwargs)
 



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/9f0f2eefb91d796efeb8696335e65ef35a589bb1...224b136a8ebe78063e975245f002f4902264275f

-- 
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/9f0f2eefb91d796efeb8696335e65ef35a589bb1...224b136a8ebe78063e975245f002f4902264275f
You're receiving this email because of your account on gitlab.com.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20200911/5ccfa351/attachment-0001.htm>


More information about the vc mailing list