<NME> _version.py.do
<BEF> redo-ifchange vars
echo "# pylint: disable=bad-whitespace"
cat vars

<MSG> Add a bunch of missing python docstrings.

This appeases pylint, so un-disable its docstring warning.

<DFF> @@ -1,3 +1,4 @@
 redo-ifchange vars
+echo '"""Auto-generated file with git version information."""'
 echo "# pylint: disable=bad-whitespace"
 cat vars

{'commit': 'diff --git a/.pylintrc b/.pylintrc\nindex 59cbbf6..0eae01b 100644\n--- a/.pylintrc\n+++ b/.pylintrc\n@@ -11,7 +11,7 @@ jobs=1\n \n # We probably want to fix these eventually, but in the meantime, these\n # ones are relatively harmless.\n-disable=multiple-imports,missing-docstring,locally-disabled,invalid-name,unused-argument,fixme,global-statement,redefined-variable-type,using-constant-test,unused-variable,file-ignored,simplifiable-if-statement\n+disable=multiple-imports,locally-disabled,invalid-name,unused-argument,fixme,global-statement,redefined-variable-type,using-constant-test,unused-variable,file-ignored,simplifiable-if-statement\n \n \n [REPORTS]\n@@ -159,7 +159,7 @@ method-name-hint=[a-z_][a-z0-9_]{2,30}$\n \n # Regular expression which should only match function or class names that do\n # not require a docstring.\n-no-docstring-rgx=^_\n+no-docstring-rgx=^_|^main$\n \n # Minimum line length for functions/classes that require docstrings, shorter\n # ones are exempt.\ndiff --git a/redo/atoi.py b/redo/atoi.py\nindex e53ec92..b6a2582 100644\n--- a/redo/atoi.py\n+++ b/redo/atoi.py\n@@ -1,5 +1,7 @@\n+"""Simple integer conversion helper."""\n \n def atoi(v):\n+    """Convert v to an integer, or return 0 on error, like C\'s atoi()."""\n     try:\n         return int(v or 0)\n     except ValueError:\ndiff --git a/redo/cmd_always.py b/redo/cmd_always.py\nindex 31b7c6a..51fdd14 100644\n--- a/redo/cmd_always.py\n+++ b/redo/cmd_always.py\n@@ -1,3 +1,4 @@\n+"""redo-always: tell redo that the current target is always out of date."""\n import sys, os\n from . import env, logs, state\n \ndiff --git a/redo/cmd_ifchange.py b/redo/cmd_ifchange.py\nindex b621e2f..eca6516 100644\n--- a/redo/cmd_ifchange.py\n+++ b/redo/cmd_ifchange.py\n@@ -1,3 +1,4 @@\n+"""redo-ifchange: build the given targets if they have changed."""\n import os, sys, traceback\n from . import env, builder, deps, jobserver, logs, state\n from .logs import debug2, err\ndiff --git a/redo/cmd_ifcreate.py b/redo/cmd_ifcreate.py\nindex 554ba30..86d1a28 100644\n--- a/redo/cmd_ifcreate.py\n+++ b/redo/cmd_ifcreate.py\n@@ -1,3 +1,4 @@\n+"""redo-ifcreate: build the current target if these targets are created."""\n import sys, os\n from . import env, logs, state\n from .logs import err\ndiff --git a/redo/cmd_log.py b/redo/cmd_log.py\nindex b741dbb..402a5f4 100644\n--- a/redo/cmd_log.py\n+++ b/redo/cmd_log.py\n@@ -1,3 +1,4 @@\n+"""redo-log: print past build logs. """\n import errno, fcntl, os, re, struct, sys, time\n import termios\n from .atoi import atoi\n@@ -60,6 +61,10 @@ def _rel(top, mydir, path):\n \n \n def catlog(t):\n+    """Copy the given log content to our current log output device.\n+\n+    Note: this function\'s behaviour depends on global command-line options.\n+    """\n     global total_lines, status\n     if t in already:\n         return\ndiff --git a/redo/cmd_ood.py b/redo/cmd_ood.py\nindex 3a455ce..fec0064 100644\n--- a/redo/cmd_ood.py\n+++ b/redo/cmd_ood.py\n@@ -1,3 +1,4 @@\n+"""redo-ood: list out-of-date (ood) targets."""\n import sys, os\n from . import deps, env, logs, state\n \ndiff --git a/redo/cmd_redo.py b/redo/cmd_redo.py\nindex 6a0e6f2..88735f0 100644\n--- a/redo/cmd_redo.py\n+++ b/redo/cmd_redo.py\n@@ -1,3 +1,4 @@\n+"""redo: build the listed targets whether they need it or not."""\n #\n # Copyright 2010-2018 Avery Pennarun and contributors\n #\ndiff --git a/redo/cmd_sources.py b/redo/cmd_sources.py\nindex ffc45d1..b9fba09 100644\n--- a/redo/cmd_sources.py\n+++ b/redo/cmd_sources.py\n@@ -1,3 +1,4 @@\n+"""redo-sources: list the known source (not target) files."""\n import sys, os\n from . import env, logs, state\n \ndiff --git a/redo/cmd_stamp.py b/redo/cmd_stamp.py\nindex 8de2257..48f12bf 100644\n--- a/redo/cmd_stamp.py\n+++ b/redo/cmd_stamp.py\n@@ -1,3 +1,4 @@\n+"""redo-stamp: tell redo to use a checksum when considering this target."""\n import sys, os\n from . import env, logs, state\n from .logs import debug2\ndiff --git a/redo/cmd_targets.py b/redo/cmd_targets.py\nindex 98f2c50..887e202 100644\n--- a/redo/cmd_targets.py\n+++ b/redo/cmd_targets.py\n@@ -1,3 +1,4 @@\n+"""redo-targets: list the known targets (not sources)."""\n import sys, os\n from . import env, logs, state\n \ndiff --git a/redo/cmd_unlocked.py b/redo/cmd_unlocked.py\nindex 4ce4780..81da28e 100644\n--- a/redo/cmd_unlocked.py\n+++ b/redo/cmd_unlocked.py\n@@ -1,3 +1,4 @@\n+"""redo-unlocked: internal tool for building dependencies."""\n import sys, os\n from . import env, logs, state\n \ndiff --git a/redo/cmd_whichdo.py b/redo/cmd_whichdo.py\nindex 1c63617..ad580c2 100644\n--- a/redo/cmd_whichdo.py\n+++ b/redo/cmd_whichdo.py\n@@ -1,3 +1,4 @@\n+"""redo-whichdo: list the set of .do files considered to build a target."""\n import sys, os\n from . import env, logs, paths\n from .logs import err\ndiff --git a/redo/deps.py b/redo/deps.py\nindex a1aa6f1..0ce53d3 100644\n--- a/redo/deps.py\n+++ b/redo/deps.py\n@@ -1,3 +1,4 @@\n+"""Code for checking redo target dependencies."""\n import os\n from . import cycles, env, state\n from .logs import debug\n@@ -10,6 +11,29 @@ def isdirty(f, depth, max_changed,\n             is_checked=state.File.is_checked,\n             set_checked=state.File.set_checked_save,\n             log_override=state.warn_override):\n+    """Determine if the given state.File needs to be built.\n+\n+    Args:\n+      f: a state.File representing the target to check.\n+      depth: a string of whitespace representing the recursion depth\n+        (initially \'\')\n+      max_changed: initially the current runid.  If a target is newer than\n+        this, anything that depends on it is considered outdated.\n+      already_checked: initially [].  A list of dependencies already\n+        checked in this recursive cycle, to avoid infinite loops.\n+      is_checked: a function that returns whether a given state.File has\n+        already been checked for dirtiness.\n+      set_checked: a function that marks a given state.File as having now\n+        been checked for dirtiness.\n+      log_override: a function that logs a "manual override" warning when\n+        needed.  (redo-ood replaces this with a no-op.)\n+\n+    Returns:\n+      [targets...] if we won\'t be sure until the given list of targets has\n+        been built.\n+      DIRTY if the given target is definitely dirty.\n+      CLEAN if the given target is definitely not dirty.\n+    """\n     if f.id in already_checked:\n         raise cycles.CyclicDependencyError()\n     # make a copy of the list, so upon returning, our parent\'s copy\ndiff --git a/redo/env.py b/redo/env.py\nindex 5724b7d..2d8a338 100644\n--- a/redo/env.py\n+++ b/redo/env.py\n@@ -1,3 +1,4 @@\n+"""Manage redo-related environment variables."""\n import os, sys\n from .atoi import atoi\n \ndiff --git a/redo/helpers.py b/redo/helpers.py\nindex 64fdf44..70fbfc9 100644\n--- a/redo/helpers.py\n+++ b/redo/helpers.py\n@@ -1,3 +1,4 @@\n+"""Some helper functions that don\'t fit anywhere else."""\n import os, errno, fcntl\n \n \ndiff --git a/redo/jobserver.py b/redo/jobserver.py\nindex 46f4cfa..90af08b 100644\n--- a/redo/jobserver.py\n+++ b/redo/jobserver.py\n@@ -1,5 +1,4 @@\n-#\n-# Implementation of a GNU make-compatible jobserver.\n+"""Implementation of a GNU make-compatible jobserver."""\n #\n # The basic idea is that both ends of a pipe (tokenfds) are shared with all\n # subprocesses.  At startup, we write one "token" into the pipe for each\n@@ -201,6 +200,7 @@ def _try_read_all(fd, n):\n \n \n def setup(maxjobs):\n+    """Start the jobserver (if it isn\'t already) with the given token count."""\n     global _tokenfds, _cheatfds, _toplevel\n     assert maxjobs > 0\n     assert not _tokenfds\ndiff --git a/redo/logs.py b/redo/logs.py\nindex ecaf577..3d3a4df 100644\n--- a/redo/logs.py\n+++ b/redo/logs.py\n@@ -1,3 +1,4 @@\n+"""Code for writing log-formatted messages to stderr."""\n import os, re, sys, time\n from . import env\n \n@@ -24,6 +25,8 @@ def _check_tty(tty, color):\n \n \n class RawLog(object):\n+    """A log printer for machine-readable logs, suitable for redo-log."""\n+\n     def __init__(self, tty):\n         self.file = tty\n \n@@ -39,6 +42,8 @@ REDO_RE = re.compile(r\'@@REDO:([^@]+)@@ (.*)$\')\n \n \n class PrettyLog(object):\n+    """A log printer for human-readable logs."""\n+\n     def __init__(self, tty):\n         self.topdir = os.getcwd()\n         self.file = tty\n@@ -53,6 +58,7 @@ class PrettyLog(object):\n                      BOLD if color else \'\', s, PLAIN, \'\\n\']))\n \n     def write(self, s):\n+        """Write the string \'s\' to the log."""\n         assert \'\\n\' not in s\n         sys.stdout.flush()\n         sys.stderr.flush()\ndiff --git a/redo/paths.py b/redo/paths.py\nindex 5600089..a966af2 100644\n--- a/redo/paths.py\n+++ b/redo/paths.py\n@@ -1,3 +1,4 @@\n+"""Code for manipulating file paths."""\n import os\n from . import env\n from .logs import debug2\n@@ -14,6 +15,7 @@ def _default_do_files(filename):\n \n \n def possible_do_files(t):\n+    """Yield a list of tuples describing the .do file needed to build t."""\n     dirname, filename = os.path.split(t)\n     yield (os.path.join(env.v.BASE, dirname), "%s.do" % filename,\n            \'\', filename, \'\')\ndiff --git a/redo/state.py b/redo/state.py\nindex 8e3cdb7..b2270d7 100644\n--- a/redo/state.py\n+++ b/redo/state.py\n@@ -1,3 +1,4 @@\n+"""Code for manipulating redo\'s state database."""\n import sys, os, errno, stat, fcntl, sqlite3\n from . import cycles, env\n from .helpers import unlink, close_on_exec, join\n@@ -31,6 +32,7 @@ _lockfile = None\n \n _db = None\n def db():\n+    """Initialize the state database and return its object."""\n     global _db, _lockfile\n     if _db:\n         return _db\n@@ -151,6 +153,7 @@ def check_sane():\n \n _cwd = None\n def relpath(t, base):\n+    """Given a relative or absolute path t, express it relative to base."""\n     global _cwd\n     if not _cwd:\n         _cwd = os.getcwd()\n@@ -210,6 +213,8 @@ _file_cols = [\'rowid\', \'name\', \'is_generated\', \'is_override\',\n               \'checked_runid\', \'changed_runid\', \'failed_runid\',\n               \'stamp\', \'csum\']\n class File(object):\n+    """An object representing a source or target in the redo database."""\n+\n     # use this mostly to avoid accidentally assigning to typos\n     __slots__ = [\'id\'] + _file_cols[1:]\n \n@@ -324,6 +329,7 @@ class File(object):\n             self.set_changed()\n \n     def is_source(self):\n+        """Returns true if this object represents a source (not a target)."""\n         if self.name.startswith(\'//\'):\n             return False  # special name, ignore\n         newstamp = self.read_stamp()\n@@ -341,6 +347,7 @@ class File(object):\n         return True\n \n     def is_target(self):\n+        """Returns true if this object represents a target (not a source)."""\n         if not self.is_generated:\n             return False\n         if self.is_source():\n@@ -357,6 +364,7 @@ class File(object):\n         return self.failed_runid and self.failed_runid >= env.v.RUNID\n \n     def deps(self):\n+        """Return the list of objects that this object depends on."""\n         if self.is_override or not self.is_generated:\n             return\n         q = (\'select Deps.mode, Deps.source, %s \'\n@@ -370,10 +378,21 @@ class File(object):\n             yield mode, File(cols=cols)\n \n     def zap_deps1(self):\n+        """Mark the list of dependencies of this object as deprecated.\n+\n+        We do this when starting a new build of the current target.  We don\'t\n+        delete them right away, because if the build fails, we still want to\n+        know the old deps.\n+        """\n         debug2(\'zap-deps1: %r\\n\' % self.name)\n         _write(\'update Deps set delete_me=? where target=?\', [True, self.id])\n \n     def zap_deps2(self):\n+        """Delete any deps that were *not* referenced in the current run.\n+\n+        Dependencies of a given target can change from one build to the next.\n+        We forget old dependencies only after a build completes successfully.\n+        """\n         debug2(\'zap-deps2: %r\\n\' % self.name)\n         _write(\'delete from Deps where target=? and delete_me=1\', [self.id])\n \n@@ -438,7 +457,10 @@ def logname(fid):\n # The makes debugging a bit harder.  When we someday port to C, we can do that.\n _locks = {}\n class Lock(object):\n+    """An object representing a lock on a redo target file."""\n+\n     def __init__(self, fid):\n+        """Initialize a lock, given the target\'s state.File.id."""\n         self.owned = False\n         self.fid = fid\n         assert _lockfile >= 0\n@@ -451,10 +473,12 @@ class Lock(object):\n             self.unlock()\n \n     def check(self):\n+        """Check that this lock is in a sane state."""\n         assert not self.owned\n         cycles.check(self.fid)\n \n     def trylock(self):\n+        """Non-blocking try to acquire our lock; returns true if it worked."""\n         self.check()\n         assert not self.owned\n         try:\n@@ -469,6 +493,12 @@ class Lock(object):\n         return self.owned\n \n     def waitlock(self, shared=False):\n+        """Try to acquire our lock, and wait if it\'s currently locked.\n+\n+        If shared=True, acquires a shared lock (which can be shared with\n+        other shared locks; used by redo-log).  Otherwise, acquires an\n+        exclusive lock.\n+        """\n         self.check()\n         assert not self.owned\n         fcntl.lockf(\n@@ -478,6 +508,7 @@ class Lock(object):\n         self.owned = True\n \n     def unlock(self):\n+        """Release the lock, which we must currently own."""\n         if not self.owned:\n             raise Exception("can\'t unlock %r - we don\'t own it"\n                             % self.fid)\ndiff --git a/redo/title.py b/redo/title.py\nindex 8cdf40d..05ac98b 100644\n--- a/redo/title.py\n+++ b/redo/title.py\n@@ -1,3 +1,4 @@\n+"""Code for manipulating the Unix process title."""\n import os, sys\n \n # FIXME: setproctitle module is only usable if *not* using python -S,\ndiff --git a/redo/version/__init__.py b/redo/version/__init__.py\nindex 581c2ec..a5e70e8 100644\n--- a/redo/version/__init__.py\n+++ b/redo/version/__init__.py\n@@ -1 +1,2 @@\n+"""A module which provides current redo version information from git."""\n from ._version import COMMIT, TAG, DATE\ndiff --git a/redo/version/_version.py.do b/redo/version/_version.py.do\nindex 42dbfce..1edace6 100644\n--- a/redo/version/_version.py.do\n+++ b/redo/version/_version.py.do\n@@ -1,3 +1,4 @@\n redo-ifchange vars\n+echo \'"""Auto-generated file with git version information."""\'\n echo "# pylint: disable=bad-whitespace"\n cat vars\n', 'commit_subject': 'Add a bunch of missing python docstrings.', 'repo_name': 'apenwarr/redo', 'committer': {'name': 'Avery Pennarun', 'email': 'e03ccfb89d416c4697ad6970ce86a92c1c28a78e@gmail.com', 'time_sec': '1544778233', 'tz_offset': '0', 'date': {'seconds': '1544778233'}}, 'commit_tree': '91194d6b12a9c37e7429fecef9d75dfb800c08b5', 'commit_message': 'Add a bunch of missing python docstrings.\n\nThis appeases pylint, so un-disable its docstring warning.\n', 'language_name': 'C', 'license': 'apache-2.0', 'hunks': '@@ -1,3 +1,4 @@\n redo-ifchange vars\n+echo \'"""Auto-generated file with git version information."""\'\n echo "# pylint: disable=bad-whitespace"\n cat vars\n', 'addition_count': 1, 'deletion_count': 0, 'src_file': 'a/redo/version/_version.py.do', 'tgt_file': 'b/redo/version/_version.py.do', 'file_extension': '.do', 'before_file': 'redo-ifchange vars\necho "# pylint: disable=bad-whitespace"\ncat vars\n', 'message': 'Add a bunch of missing python docstrings.\n\nThis appeases pylint, so un-disable its docstring warning.\n', 'author_name': 'Avery Pennarun', 'lang': 'py'}