contrib/testparseutil.py
changeset 43076 2372284d9457
parent 42391 c2deb2512823
child 43091 127cc1f72e70
--- a/contrib/testparseutil.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/contrib/testparseutil.py	Sun Oct 06 09:45:02 2019 -0400
@@ -14,11 +14,13 @@
 ####################
 # for Python3 compatibility (almost comes from mercurial/pycompat.py)
 
-ispy3 = (sys.version_info[0] >= 3)
+ispy3 = sys.version_info[0] >= 3
+
 
 def identity(a):
     return a
 
+
 def _rapply(f, xs):
     if xs is None:
         # assume None means non-value of optional data
@@ -29,12 +31,14 @@
         return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items())
     return f(xs)
 
+
 def rapply(f, xs):
     if f is identity:
         # fast path mainly for py2
         return xs
     return _rapply(f, xs)
 
+
 if ispy3:
     import builtins
 
@@ -49,29 +53,37 @@
 
     def opentext(f):
         return open(f, 'r')
+
+
 else:
     bytestr = str
     sysstr = identity
 
     opentext = open
 
+
 def b2s(x):
     # convert BYTES elements in "x" to SYSSTR recursively
     return rapply(sysstr, x)
 
+
 def writeout(data):
     # write "data" in BYTES into stdout
     sys.stdout.write(data)
 
+
 def writeerr(data):
     # write "data" in BYTES into stderr
     sys.stderr.write(data)
 
+
 ####################
 
+
 class embeddedmatcher(object):
     """Base class to detect embedded code fragments in *.t test script
     """
+
     __metaclass__ = abc.ABCMeta
 
     def __init__(self, desc):
@@ -126,6 +138,7 @@
     def codeinside(self, ctx, line):
         """Return actual code at line inside embedded code"""
 
+
 def embedded(basefile, lines, errors, matchers):
     """pick embedded code fragments up from given lines
 
@@ -168,12 +181,12 @@
 
     """
     matcher = None
-    ctx = filename = code = startline = None # for pyflakes
+    ctx = filename = code = startline = None  # for pyflakes
 
     for lineno, line in enumerate(lines, 1):
         if not line.endswith('\n'):
-            line += '\n' # to normalize EOF line
-        if matcher: # now, inside embedded code
+            line += '\n'  # to normalize EOF line
+        if matcher:  # now, inside embedded code
             if matcher.endsat(ctx, line):
                 codeatend = matcher.codeatend(ctx, line)
                 if codeatend is not None:
@@ -185,8 +198,10 @@
             elif not matcher.isinside(ctx, line):
                 # this is an error of basefile
                 # (if matchers are implemented correctly)
-                errors.append('%s:%d: unexpected line for "%s"'
-                              % (basefile, lineno, matcher.desc))
+                errors.append(
+                    '%s:%d: unexpected line for "%s"'
+                    % (basefile, lineno, matcher.desc)
+                )
                 # stop extracting embedded code by current 'matcher',
                 # because appearance of unexpected line might mean
                 # that expected end-of-embedded-code line might never
@@ -208,10 +223,14 @@
         if matched:
             if len(matched) > 1:
                 # this is an error of matchers, maybe
-                errors.append('%s:%d: ambiguous line for %s' %
-                              (basefile, lineno,
-                               ', '.join(['"%s"' % m.desc
-                                           for m, c in matched])))
+                errors.append(
+                    '%s:%d: ambiguous line for %s'
+                    % (
+                        basefile,
+                        lineno,
+                        ', '.join(['"%s"' % m.desc for m, c in matched]),
+                    )
+                )
                 # omit extracting embedded code, because choosing
                 # arbitrary matcher from matched ones might fail to
                 # detect the end of embedded code as expected.
@@ -238,8 +257,11 @@
         else:
             # this is an error of basefile
             # (if matchers are implemented correctly)
-            errors.append('%s:%d: unexpected end of file for "%s"'
-                          % (basefile, lineno, matcher.desc))
+            errors.append(
+                '%s:%d: unexpected end of file for "%s"'
+                % (basefile, lineno, matcher.desc)
+            )
+
 
 # heredoc limit mark to ignore embedded code at check-code.py or so
 heredocignorelimit = 'NO_CHECK_EOF'
@@ -252,6 +274,7 @@
 # - << 'LIMITMARK'
 heredoclimitpat = r'\s*<<\s*(?P<lquote>["\']?)(?P<limit>\w+)(?P=lquote)'
 
+
 class fileheredocmatcher(embeddedmatcher):
     """Detect "cat > FILE << LIMIT" style embedded code
 
@@ -290,6 +313,7 @@
     >>> matcher.ignores(ctx)
     True
     """
+
     _prefix = '  > '
 
     def __init__(self, desc, namepat):
@@ -302,8 +326,9 @@
         # - > NAMEPAT
         # - > "NAMEPAT"
         # - > 'NAMEPAT'
-        namepat = (r'\s*>>?\s*(?P<nquote>["\']?)(?P<name>%s)(?P=nquote)'
-                   % namepat)
+        namepat = (
+            r'\s*>>?\s*(?P<nquote>["\']?)(?P<name>%s)(?P=nquote)' % namepat
+        )
         self._fileres = [
             # "cat > NAME << LIMIT" case
             re.compile(r'  \$ \s*cat' + namepat + heredoclimitpat),
@@ -316,8 +341,10 @@
         for filere in self._fileres:
             matched = filere.match(line)
             if matched:
-                return (matched.group('name'),
-                        '  > %s\n' % matched.group('limit'))
+                return (
+                    matched.group('name'),
+                    '  > %s\n' % matched.group('limit'),
+                )
 
     def endsat(self, ctx, line):
         return ctx[1] == line
@@ -332,17 +359,19 @@
         return ctx[0]
 
     def codeatstart(self, ctx, line):
-        return None # no embedded code at start line
+        return None  # no embedded code at start line
 
     def codeatend(self, ctx, line):
-        return None # no embedded code at end line
+        return None  # no embedded code at end line
 
     def codeinside(self, ctx, line):
-        return line[len(self._prefix):] # strip prefix
+        return line[len(self._prefix) :]  # strip prefix
+
 
 ####
 # for embedded python script
 
+
 class pydoctestmatcher(embeddedmatcher):
     """Detect ">>> code" style embedded python code
 
@@ -395,6 +424,7 @@
     True
     >>> matcher.codeatend(ctx, end)
     """
+
     _prefix = '  >>> '
     _prefixre = re.compile(r'  (>>>|\.\.\.) ')
 
@@ -419,24 +449,25 @@
         return not (self._prefixre.match(line) or self._outputre.match(line))
 
     def isinside(self, ctx, line):
-        return True # always true, if not yet ended
+        return True  # always true, if not yet ended
 
     def ignores(self, ctx):
-        return False # should be checked always
+        return False  # should be checked always
 
     def filename(self, ctx):
-        return None # no filename
+        return None  # no filename
 
     def codeatstart(self, ctx, line):
-        return line[len(self._prefix):] # strip prefix '  >>> '/'  ... '
+        return line[len(self._prefix) :]  # strip prefix '  >>> '/'  ... '
 
     def codeatend(self, ctx, line):
-        return None # no embedded code at end line
+        return None  # no embedded code at end line
 
     def codeinside(self, ctx, line):
         if self._prefixre.match(line):
-            return line[len(self._prefix):] # strip prefix '  >>> '/'  ... '
-        return '\n' # an expected output line is treated as an empty line
+            return line[len(self._prefix) :]  # strip prefix '  >>> '/'  ... '
+        return '\n'  # an expected output line is treated as an empty line
+
 
 class pyheredocmatcher(embeddedmatcher):
     """Detect "python << LIMIT" style embedded python code
@@ -474,10 +505,12 @@
     >>> matcher.ignores(ctx)
     True
     """
+
     _prefix = '  > '
 
-    _startre = re.compile(r'  \$ (\$PYTHON|"\$PYTHON"|python).*' +
-                          heredoclimitpat)
+    _startre = re.compile(
+        r'  \$ (\$PYTHON|"\$PYTHON"|python).*' + heredoclimitpat
+    )
 
     def __init__(self):
         super(pyheredocmatcher, self).__init__("heredoc python invocation")
@@ -498,16 +531,17 @@
         return '  > %s\n' % heredocignorelimit == ctx
 
     def filename(self, ctx):
-        return None # no filename
+        return None  # no filename
 
     def codeatstart(self, ctx, line):
-        return None # no embedded code at start line
+        return None  # no embedded code at start line
 
     def codeatend(self, ctx, line):
-        return None # no embedded code at end line
+        return None  # no embedded code at end line
 
     def codeinside(self, ctx, line):
-        return line[len(self._prefix):] # strip prefix
+        return line[len(self._prefix) :]  # strip prefix
+
 
 _pymatchers = [
     pydoctestmatcher(),
@@ -517,9 +551,11 @@
     fileheredocmatcher('heredoc .py file', r'[^<]+\.py'),
 ]
 
+
 def pyembedded(basefile, lines, errors):
     return embedded(basefile, lines, errors, _pymatchers)
 
+
 ####
 # for embedded shell script
 
@@ -529,22 +565,27 @@
     fileheredocmatcher('heredoc .sh file', r'[^<]+\.sh'),
 ]
 
+
 def shembedded(basefile, lines, errors):
     return embedded(basefile, lines, errors, _shmatchers)
 
+
 ####
 # for embedded hgrc configuration
 
 _hgrcmatchers = [
     # use '[^<]+' instead of '\S+', in order to match against
     # paths including whitespaces
-    fileheredocmatcher('heredoc hgrc file',
-                       r'(([^/<]+/)+hgrc|\$HGRCPATH|\${HGRCPATH})'),
+    fileheredocmatcher(
+        'heredoc hgrc file', r'(([^/<]+/)+hgrc|\$HGRCPATH|\${HGRCPATH})'
+    ),
 ]
 
+
 def hgrcembedded(basefile, lines, errors):
     return embedded(basefile, lines, errors, _hgrcmatchers)
 
+
 ####
 
 if __name__ == "__main__":
@@ -558,8 +599,7 @@
                 name = '<anonymous>'
             writeout("%s:%d: %s starts\n" % (basefile, starts, name))
             if opts.verbose and code:
-                writeout("  |%s\n" %
-                         "\n  |".join(l for l in code.splitlines()))
+                writeout("  |%s\n" % "\n  |".join(l for l in code.splitlines()))
             writeout("%s:%d: %s ends\n" % (basefile, ends, name))
         for e in errors:
             writeerr("%s\n" % e)
@@ -579,9 +619,11 @@
         return ret
 
     commands = {}
+
     def command(name, desc):
         def wrap(func):
             commands[name] = (desc, func)
+
         return wrap
 
     @command("pyembedded", "detect embedded python script")
@@ -596,21 +638,29 @@
     def hgrcembeddedcmd(args, opts):
         return applyembedded(args, hgrcembedded, opts)
 
-    availablecommands = "\n".join(["  - %s: %s" % (key, value[0])
-                                   for key, value in commands.items()])
+    availablecommands = "\n".join(
+        ["  - %s: %s" % (key, value[0]) for key, value in commands.items()]
+    )
 
-    parser = optparse.OptionParser("""%prog COMMAND [file ...]
+    parser = optparse.OptionParser(
+        """%prog COMMAND [file ...]
 
 Pick up embedded code fragments from given file(s) or stdin, and list
 up start/end lines of them in standard compiler format
 ("FILENAME:LINENO:").
 
 Available commands are:
-""" + availablecommands + """
-""")
-    parser.add_option("-v", "--verbose",
-                      help="enable additional output (e.g. actual code)",
-                      action="store_true")
+"""
+        + availablecommands
+        + """
+"""
+    )
+    parser.add_option(
+        "-v",
+        "--verbose",
+        help="enable additional output (e.g. actual code)",
+        action="store_true",
+    )
     (opts, args) = parser.parse_args()
 
     if not args or args[0] not in commands: