D6342: style: run a patched black on a subset of mercurial

durin42 (Augie Fackler) phabricator at mercurial-scm.org
Wed May 8 15:31:25 EDT 2019


durin42 updated this revision to Diff 15039.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D6342?vs=15009&id=15039

REVISION DETAIL
  https://phab.mercurial-scm.org/D6342

AFFECTED FILES
  contrib/import-checker.py
  mercurial/cacheutil.py
  mercurial/diffhelper.py
  mercurial/dirstateguard.py
  mercurial/httpconnection.py
  mercurial/minifileset.py
  mercurial/node.py
  mercurial/policy.py
  mercurial/pushkey.py
  mercurial/rcutil.py
  mercurial/rewriteutil.py
  mercurial/scmposix.py
  mercurial/scmwindows.py
  mercurial/stack.py
  pyproject.toml

CHANGE DETAILS

diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[tool.black]
+line-length = 80
+exclude = 'build/|wheelhouse/|dist/|packages/|\.hg/|\.mypy_cache/|\.venv/|mercurial/thirdparty/|hgext/fsmonitor/pywatchman/|contrib/python-zstandard/'
diff --git a/mercurial/stack.py b/mercurial/stack.py
--- a/mercurial/stack.py
+++ b/mercurial/stack.py
@@ -12,17 +12,18 @@
     scmutil,
 )
 
+
 def getstack(repo, rev=None):
     """return a sorted smartrev of the stack containing either rev if it is
     not None or the current working directory parent.
 
     The stack will always contain all drafts changesets which are ancestors to
     the revision and are not merges.
     """
     if rev is None:
-        rev = '.'
+        rev = "."
 
-    revspec = 'reverse(only(%s) and not public() and not ::merge())'
+    revspec = "reverse(only(%s) and not public() and not ::merge())"
     revset = revsetlang.formatspec(revspec, rev)
     revisions = scmutil.revrange(repo, [revset])
     revisions.sort()
diff --git a/mercurial/scmwindows.py b/mercurial/scmwindows.py
--- a/mercurial/scmwindows.py
+++ b/mercurial/scmwindows.py
@@ -11,51 +11,55 @@
 
 try:
     import _winreg as winreg
+
     winreg.CloseKey
 except ImportError:
     import winreg
 
 # MS-DOS 'more' is the only pager available by default on Windows.
-fallbackpager = 'more'
+fallbackpager = "more"
+
 
 def systemrcpath():
-    '''return default os-specific hgrc search path'''
+    """return default os-specific hgrc search path"""
     rcpath = []
     filename = win32.executablepath()
     # Use mercurial.ini found in directory with hg.exe
-    progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+    progrc = os.path.join(os.path.dirname(filename), "mercurial.ini")
     rcpath.append(progrc)
     # Use hgrc.d found in directory with hg.exe
-    progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
+    progrcd = os.path.join(os.path.dirname(filename), "hgrc.d")
     if os.path.isdir(progrcd):
         for f, kind in util.listdir(progrcd):
-            if f.endswith('.rc'):
+            if f.endswith(".rc"):
                 rcpath.append(os.path.join(progrcd, f))
     # else look for a system rcpath in the registry
-    value = util.lookupreg('SOFTWARE\\Mercurial', None,
-                           winreg.HKEY_LOCAL_MACHINE)
+    value = util.lookupreg(
+        "SOFTWARE\\Mercurial", None, winreg.HKEY_LOCAL_MACHINE
+    )
     if not isinstance(value, str) or not value:
         return rcpath
     value = util.localpath(value)
     for p in value.split(pycompat.ospathsep):
-        if p.lower().endswith('mercurial.ini'):
+        if p.lower().endswith("mercurial.ini"):
             rcpath.append(p)
         elif os.path.isdir(p):
             for f, kind in util.listdir(p):
-                if f.endswith('.rc'):
+                if f.endswith(".rc"):
                     rcpath.append(os.path.join(p, f))
     return rcpath
 
+
 def userrcpath():
-    '''return os-specific hgrc search path to the user dir'''
-    home = os.path.expanduser('~')
-    path = [os.path.join(home, 'mercurial.ini'),
-            os.path.join(home, '.hgrc')]
-    userprofile = encoding.environ.get('USERPROFILE')
+    """return os-specific hgrc search path to the user dir"""
+    home = os.path.expanduser("~")
+    path = [os.path.join(home, "mercurial.ini"), os.path.join(home, ".hgrc")]
+    userprofile = encoding.environ.get("USERPROFILE")
     if userprofile and userprofile != home:
-        path.append(os.path.join(userprofile, 'mercurial.ini'))
-        path.append(os.path.join(userprofile, '.hgrc'))
+        path.append(os.path.join(userprofile, "mercurial.ini"))
+        path.append(os.path.join(userprofile, ".hgrc"))
     return path
 
+
 def termsize(ui):
     return win32.termsize()
diff --git a/mercurial/scmposix.py b/mercurial/scmposix.py
--- a/mercurial/scmposix.py
+++ b/mercurial/scmposix.py
@@ -16,49 +16,60 @@
 # $MORE variable, but there's no compatible option with Linux 'more'. Given
 # OS X is widely used and most modern Unix systems would have 'less', setting
 # 'less' as the default seems reasonable.
-fallbackpager = 'less'
+fallbackpager = "less"
+
 
 def _rcfiles(path):
-    rcs = [os.path.join(path, 'hgrc')]
-    rcdir = os.path.join(path, 'hgrc.d')
+    rcs = [os.path.join(path, "hgrc")]
+    rcdir = os.path.join(path, "hgrc.d")
     try:
-        rcs.extend([os.path.join(rcdir, f)
-                    for f, kind in util.listdir(rcdir)
-                    if f.endswith(".rc")])
+        rcs.extend(
+            [
+                os.path.join(rcdir, f)
+                for f, kind in util.listdir(rcdir)
+                if f.endswith(".rc")
+            ]
+        )
     except OSError:
         pass
     return rcs
 
+
 def systemrcpath():
     path = []
-    if pycompat.sysplatform == 'plan9':
-        root = 'lib/mercurial'
+    if pycompat.sysplatform == "plan9":
+        root = "lib/mercurial"
     else:
-        root = 'etc/mercurial'
+        root = "etc/mercurial"
     # old mod_python does not set sys.argv
-    if len(getattr(sys, 'argv', [])) > 0:
+    if len(getattr(sys, "argv", [])) > 0:
         p = os.path.dirname(os.path.dirname(pycompat.sysargv[0]))
-        if p != '/':
+        if p != "/":
             path.extend(_rcfiles(os.path.join(p, root)))
-    path.extend(_rcfiles('/' + root))
+    path.extend(_rcfiles("/" + root))
     return path
 
+
 def userrcpath():
-    if pycompat.sysplatform == 'plan9':
-        return [encoding.environ['home'] + '/lib/hgrc']
+    if pycompat.sysplatform == "plan9":
+        return [encoding.environ["home"] + "/lib/hgrc"]
     elif pycompat.isdarwin:
-        return [os.path.expanduser('~/.hgrc')]
+        return [os.path.expanduser("~/.hgrc")]
     else:
-        confighome = encoding.environ.get('XDG_CONFIG_HOME')
+        confighome = encoding.environ.get("XDG_CONFIG_HOME")
         if confighome is None or not os.path.isabs(confighome):
-            confighome = os.path.expanduser('~/.config')
+            confighome = os.path.expanduser("~/.config")
 
-        return [os.path.expanduser('~/.hgrc'),
-                os.path.join(confighome, 'hg', 'hgrc')]
+        return [
+            os.path.expanduser("~/.hgrc"),
+            os.path.join(confighome, "hg", "hgrc"),
+        ]
+
 
 def termsize(ui):
     try:
         import termios
+
         TIOCGWINSZ = termios.TIOCGWINSZ  # unavailable on IRIX (issue3449)
     except (AttributeError, ImportError):
         return 80, 24
@@ -71,8 +82,8 @@
                 continue
             if not os.isatty(fd):
                 continue
-            arri = fcntl.ioctl(fd, TIOCGWINSZ, '\0' * 8)
-            height, width = array.array(r'h', arri)[:2]
+            arri = fcntl.ioctl(fd, TIOCGWINSZ, "\0" * 8)
+            height, width = array.array(r"h", arri)[:2]
             if width > 0 and height > 0:
                 return width, height
         except ValueError:
diff --git a/mercurial/rewriteutil.py b/mercurial/rewriteutil.py
--- a/mercurial/rewriteutil.py
+++ b/mercurial/rewriteutil.py
@@ -16,7 +16,8 @@
     revset,
 )
 
-def precheck(repo, revs, action='rewrite'):
+
+def precheck(repo, revs, action="rewrite"):
     """check if revs can be rewritten
     action is used to control the error message.
 
@@ -30,7 +31,7 @@
     if len(repo[None].parents()) > 1:
         raise error.Abort(_("cannot %s while merging") % action)
 
-    publicrevs = repo.revs('%ld and public()', revs)
+    publicrevs = repo.revs("%ld and public()", revs)
     if publicrevs:
         msg = _("cannot %s public changesets") % (action)
         hint = _("see 'hg help phases' for details")
@@ -40,6 +41,7 @@
     if newunstable:
         raise error.Abort(_("cannot %s changeset with children") % action)
 
+
 def disallowednewunstable(repo, revs):
     """Checks whether editing the revs will create new unstable changesets and
     are we allowed to create them.
diff --git a/mercurial/rcutil.py b/mercurial/rcutil.py
--- a/mercurial/rcutil.py
+++ b/mercurial/rcutil.py
@@ -24,47 +24,52 @@
 systemrcpath = scmplatform.systemrcpath
 userrcpath = scmplatform.userrcpath
 
+
 def _expandrcpath(path):
-    '''path could be a file or a directory. return a list of file paths'''
+    """path could be a file or a directory. return a list of file paths"""
     p = util.expandpath(path)
     if os.path.isdir(p):
         join = os.path.join
-        return sorted(join(p, f) for f, k in util.listdir(p)
-                      if f.endswith('.rc'))
+        return sorted(
+            join(p, f) for f, k in util.listdir(p) if f.endswith(".rc")
+        )
     return [p]
 
+
 def envrcitems(env=None):
-    '''Return [(section, name, value, source)] config items.
+    """Return [(section, name, value, source)] config items.
 
     The config items are extracted from environment variables specified by env,
     used to override systemrc, but not userrc.
 
     If env is not provided, encoding.environ will be used.
-    '''
+    """
     if env is None:
         env = encoding.environ
     checklist = [
-        ('EDITOR', 'ui', 'editor'),
-        ('VISUAL', 'ui', 'editor'),
-        ('PAGER', 'pager', 'pager'),
+        ("EDITOR", "ui", "editor"),
+        ("VISUAL", "ui", "editor"),
+        ("PAGER", "pager", "pager"),
     ]
     result = []
     for envname, section, configname in checklist:
         if envname not in env:
             continue
-        result.append((section, configname, env[envname], '$%s' % envname))
+        result.append((section, configname, env[envname], "$%s" % envname))
     return result
 
+
 def defaultrcpath():
-    '''return rc paths in default.d'''
+    """return rc paths in default.d"""
     path = []
-    defaultpath = os.path.join(util.datapath, 'default.d')
+    defaultpath = os.path.join(util.datapath, "default.d")
     if os.path.isdir(defaultpath):
         path = _expandrcpath(defaultpath)
     return path
 
+
 def rccomponents():
-    '''return an ordered [(type, obj)] about where to load configs.
+    """return an ordered [(type, obj)] about where to load configs.
 
     respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is
     used. if $HGRCPATH is not set, the platform default will be used.
@@ -74,26 +79,27 @@
     type could be either 'path' or 'items', if type is 'path', obj is a string,
     and is the config file path. if type is 'items', obj is a list of (section,
     name, value, source) that should fill the config directly.
-    '''
-    envrc = ('items', envrcitems())
+    """
+    envrc = ("items", envrcitems())
 
-    if 'HGRCPATH' in encoding.environ:
+    if "HGRCPATH" in encoding.environ:
         # assume HGRCPATH is all about user configs so environments can be
         # overridden.
         _rccomponents = [envrc]
-        for p in encoding.environ['HGRCPATH'].split(pycompat.ospathsep):
+        for p in encoding.environ["HGRCPATH"].split(pycompat.ospathsep):
             if not p:
                 continue
-            _rccomponents.extend(('path', p) for p in _expandrcpath(p))
+            _rccomponents.extend(("path", p) for p in _expandrcpath(p))
     else:
-        normpaths = lambda paths: [('path', os.path.normpath(p)) for p in paths]
+        normpaths = lambda paths: [("path", os.path.normpath(p)) for p in paths]
         _rccomponents = normpaths(defaultrcpath() + systemrcpath())
         _rccomponents.append(envrc)
         _rccomponents.extend(normpaths(userrcpath()))
     return _rccomponents
 
+
 def defaultpagerenv():
-    '''return a dict of default environment variables and their values,
+    """return a dict of default environment variables and their values,
     intended to be set before starting a pager.
-    '''
-    return {'LESS': 'FRX', 'LV': '-c'}
+    """
+    return {"LESS": "FRX", "LV": "-c"}
diff --git a/mercurial/pushkey.py b/mercurial/pushkey.py
--- a/mercurial/pushkey.py
+++ b/mercurial/pushkey.py
@@ -14,48 +14,58 @@
     phases,
 )
 
+
 def _nslist(repo):
     n = {}
     for k in _namespaces:
         n[k] = ""
     if not obsolete.isenabled(repo, obsolete.exchangeopt):
-        n.pop('obsolete')
+        n.pop("obsolete")
     return n
 
-_namespaces = {"namespaces": (lambda *x: False, _nslist),
-               "bookmarks": (bookmarks.pushbookmark, bookmarks.listbookmarks),
-               "phases": (phases.pushphase, phases.listphases),
-               "obsolete": (obsolete.pushmarker, obsolete.listmarkers),
-              }
+
+_namespaces = {
+    "namespaces": (lambda *x: False, _nslist),
+    "bookmarks": (bookmarks.pushbookmark, bookmarks.listbookmarks),
+    "phases": (phases.pushphase, phases.listphases),
+    "obsolete": (obsolete.pushmarker, obsolete.listmarkers),
+}
+
 
 def register(namespace, pushkey, listkeys):
     _namespaces[namespace] = (pushkey, listkeys)
 
+
 def _get(namespace):
     return _namespaces.get(namespace, (lambda *x: False, lambda *x: {}))
 
+
 def push(repo, namespace, key, old, new):
-    '''should succeed iff value was old'''
+    """should succeed iff value was old"""
     pk = _get(namespace)[0]
     return pk(repo, key, old, new)
 
+
 def list(repo, namespace):
-    '''return a dict'''
+    """return a dict"""
     lk = _get(namespace)[1]
     return lk(repo)
 
+
 encode = encoding.fromlocal
 
 decode = encoding.tolocal
 
+
 def encodekeys(keys):
     """encode the content of a pushkey namespace for exchange over the wire"""
-    return '\n'.join(['%s\t%s' % (encode(k), encode(v)) for k, v in keys])
+    return "\n".join(["%s\t%s" % (encode(k), encode(v)) for k, v in keys])
+
 
 def decodekeys(data):
     """decode the content of a pushkey namespace from exchange over the wire"""
     result = {}
     for l in data.splitlines():
-        k, v = l.split('\t')
+        k, v = l.split("\t")
         result[decode(k)] = decode(v)
     return result
diff --git a/mercurial/policy.py b/mercurial/policy.py
--- a/mercurial/policy.py
+++ b/mercurial/policy.py
@@ -21,79 +21,86 @@
 # By default, fall back to the pure modules so the in-place build can
 # run without recompiling the C extensions. This will be overridden by
 # __modulepolicy__ generated by setup.py.
-policy = b'allow'
+policy = b"allow"
 _packageprefs = {
     # policy: (versioned package, pure package)
-    b'c': (r'cext', None),
-    b'allow': (r'cext', r'pure'),
-    b'cffi': (r'cffi', None),
-    b'cffi-allow': (r'cffi', r'pure'),
-    b'py': (None, r'pure'),
+    b"c": (r"cext", None),
+    b"allow": (r"cext", r"pure"),
+    b"cffi": (r"cffi", None),
+    b"cffi-allow": (r"cffi", r"pure"),
+    b"py": (None, r"pure"),
 }
 
 try:
     from . import __modulepolicy__
+
     policy = __modulepolicy__.modulepolicy
 except ImportError:
     pass
 
 # PyPy doesn't load C extensions.
 #
 # The canonical way to do this is to test platform.python_implementation().
 # But we don't import platform and don't bloat for it here.
-if r'__pypy__' in sys.builtin_module_names:
-    policy = b'cffi'
+if r"__pypy__" in sys.builtin_module_names:
+    policy = b"cffi"
 
 # Environment variable can always force settings.
 if sys.version_info[0] >= 3:
-    if r'HGMODULEPOLICY' in os.environ:
-        policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8')
+    if r"HGMODULEPOLICY" in os.environ:
+        policy = os.environ[r"HGMODULEPOLICY"].encode(r"utf-8")
 else:
-    policy = os.environ.get(r'HGMODULEPOLICY', policy)
+    policy = os.environ.get(r"HGMODULEPOLICY", policy)
+
 
 def _importfrom(pkgname, modname):
     # from .<pkgname> import <modname> (where . is looked through this module)
     fakelocals = {}
     pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
     try:
         fakelocals[modname] = mod = getattr(pkg, modname)
     except AttributeError:
-        raise ImportError(r'cannot import name %s' % modname)
+        raise ImportError(r"cannot import name %s" % modname)
     # force import; fakelocals[modname] may be replaced with the real module
-    getattr(mod, r'__doc__', None)
+    getattr(mod, r"__doc__", None)
     return fakelocals[modname]
 
+
 # keep in sync with "version" in C modules
 _cextversions = {
-    (r'cext', r'base85'): 1,
-    (r'cext', r'bdiff'): 3,
-    (r'cext', r'mpatch'): 1,
-    (r'cext', r'osutil'): 4,
-    (r'cext', r'parsers'): 12,
+    (r"cext", r"base85"): 1,
+    (r"cext", r"bdiff"): 3,
+    (r"cext", r"mpatch"): 1,
+    (r"cext", r"osutil"): 4,
+    (r"cext", r"parsers"): 12,
 }
 
 # map import request to other package or module
 _modredirects = {
-    (r'cext', r'charencode'): (r'cext', r'parsers'),
-    (r'cffi', r'base85'): (r'pure', r'base85'),
-    (r'cffi', r'charencode'): (r'pure', r'charencode'),
-    (r'cffi', r'parsers'): (r'pure', r'parsers'),
+    (r"cext", r"charencode"): (r"cext", r"parsers"),
+    (r"cffi", r"base85"): (r"pure", r"base85"),
+    (r"cffi", r"charencode"): (r"pure", r"charencode"),
+    (r"cffi", r"parsers"): (r"pure", r"parsers"),
 }
 
+
 def _checkmod(pkgname, modname, mod):
     expected = _cextversions.get((pkgname, modname))
-    actual = getattr(mod, r'version', None)
+    actual = getattr(mod, r"version", None)
     if actual != expected:
-        raise ImportError(r'cannot import module %s.%s '
-                          r'(expected version: %d, actual: %r)'
-                          % (pkgname, modname, expected, actual))
+        raise ImportError(
+            r"cannot import module %s.%s "
+            r"(expected version: %d, actual: %r)"
+            % (pkgname, modname, expected, actual)
+        )
+
 
 def importmod(modname):
     """Import module according to policy and check API version"""
     try:
         verpkg, purepkg = _packageprefs[policy]
     except KeyError:
-        raise ImportError(r'invalid HGMODULEPOLICY %r' % policy)
+        raise ImportError(r"invalid HGMODULEPOLICY %r" % policy)
     assert verpkg or purepkg
     if verpkg:
         pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
diff --git a/mercurial/node.py b/mercurial/node.py
--- a/mercurial/node.py
+++ b/mercurial/node.py
@@ -20,28 +20,30 @@
     except binascii.Error as e:
         raise TypeError(e)
 
+
 nullrev = -1
 # In hex, this is '0000000000000000000000000000000000000000'
 nullid = b"\0" * 20
 nullhex = hex(nullid)
 
 # Phony node value to stand-in for new files in some uses of
 # manifests.
 # In hex, this is '2121212121212121212121212121212121212121'
-newnodeid = '!!!!!!!!!!!!!!!!!!!!'
+newnodeid = "!!!!!!!!!!!!!!!!!!!!"
 # In hex, this is '3030303030303030303030303030306164646564'
-addednodeid = '000000000000000added'
+addednodeid = "000000000000000added"
 # In hex, this is '3030303030303030303030306d6f646966696564'
-modifiednodeid = '000000000000modified'
+modifiednodeid = "000000000000modified"
 
 wdirfilenodeids = {newnodeid, addednodeid, modifiednodeid}
 
 # pseudo identifiers for working directory
 # (they are experimental, so don't add too many dependencies on them)
-wdirrev = 0x7fffffff
+wdirrev = 0x7FFFFFFF
 # In hex, this is 'ffffffffffffffffffffffffffffffffffffffff'
 wdirid = b"\xff" * 20
 wdirhex = hex(wdirid)
 
+
 def short(node):
     return hex(node[:6])
diff --git a/mercurial/minifileset.py b/mercurial/minifileset.py
--- a/mercurial/minifileset.py
+++ b/mercurial/minifileset.py
@@ -15,62 +15,70 @@
     pycompat,
 )
 
+
 def _sizep(x):
     # i18n: "size" is a keyword
     expr = filesetlang.getstring(x, _("size requires an expression"))
     return fileset.sizematcher(expr)
 
+
 def _compile(tree):
     if not tree:
         raise error.ParseError(_("missing argument"))
     op = tree[0]
-    if op == 'withstatus':
+    if op == "withstatus":
         return _compile(tree[1])
-    elif op in {'symbol', 'string', 'kindpat'}:
-        name = filesetlang.getpattern(tree, {'path'}, _('invalid file pattern'))
-        if name.startswith('**'): # file extension test, ex. "**.tar.gz"
+    elif op in {"symbol", "string", "kindpat"}:
+        name = filesetlang.getpattern(tree, {"path"}, _("invalid file pattern"))
+        if name.startswith("**"):  # file extension test, ex. "**.tar.gz"
             ext = name[2:]
             for c in pycompat.bytestr(ext):
-                if c in '*{}[]?/\\':
-                    raise error.ParseError(_('reserved character: %s') % c)
+                if c in "*{}[]?/\\":
+                    raise error.ParseError(_("reserved character: %s") % c)
             return lambda n, s: n.endswith(ext)
-        elif name.startswith('path:'): # directory or full path test
-            p = name[5:] # prefix
+        elif name.startswith("path:"):  # directory or full path test
+            p = name[5:]  # prefix
             pl = len(p)
-            f = lambda n, s: n.startswith(p) and (len(n) == pl
-                                                  or n[pl:pl + 1] == '/')
+            f = lambda n, s: n.startswith(p) and (
+                len(n) == pl or n[pl : pl + 1] == "/"
+            )
             return f
-        raise error.ParseError(_("unsupported file pattern: %s") % name,
-                               hint=_('paths must be prefixed with "path:"'))
-    elif op in {'or', 'patterns'}:
+        raise error.ParseError(
+            _("unsupported file pattern: %s") % name,
+            hint=_('paths must be prefixed with "path:"'),
+        )
+    elif op in {"or", "patterns"}:
         funcs = [_compile(x) for x in tree[1:]]
         return lambda n, s: any(f(n, s) for f in funcs)
-    elif op == 'and':
+    elif op == "and":
         func1 = _compile(tree[1])
         func2 = _compile(tree[2])
         return lambda n, s: func1(n, s) and func2(n, s)
-    elif op == 'not':
+    elif op == "not":
         return lambda n, s: not _compile(tree[1])(n, s)
-    elif op == 'func':
+    elif op == "func":
         symbols = {
-            'all': lambda n, s: True,
-            'none': lambda n, s: False,
-            'size': lambda n, s: _sizep(tree[2])(s),
+            "all": lambda n, s: True,
+            "none": lambda n, s: False,
+            "size": lambda n, s: _sizep(tree[2])(s),
         }
 
         name = filesetlang.getsymbol(tree[1])
         if name in symbols:
             return symbols[name]
 
         raise error.UnknownIdentifier(name, symbols.keys())
-    elif op == 'minus':     # equivalent to 'x and not y'
+    elif op == "minus":  # equivalent to 'x and not y'
         func1 = _compile(tree[1])
         func2 = _compile(tree[2])
         return lambda n, s: func1(n, s) and not func2(n, s)
-    elif op == 'list':
-        raise error.ParseError(_("can't use a list in this context"),
-                               hint=_('see \'hg help "filesets.x or y"\''))
-    raise error.ProgrammingError('illegal tree: %r' % (tree,))
+    elif op == "list":
+        raise error.ParseError(
+            _("can't use a list in this context"),
+            hint=_("see 'hg help \"filesets.x or y\"'"),
+        )
+    raise error.ProgrammingError("illegal tree: %r" % (tree,))
+
 
 def compile(text):
     """generate a function (path, size) -> bool from filter specification.
diff --git a/mercurial/httpconnection.py b/mercurial/httpconnection.py
--- a/mercurial/httpconnection.py
+++ b/mercurial/httpconnection.py
@@ -43,8 +43,9 @@
         # requires authentication. Since we can't know until we try
         # once whether authentication will be required, just lie to
         # the user and maybe the push succeeds suddenly at 50%.
-        self._progress = ui.makeprogress(_('sending'), unit=_('kb'),
-                                         total=(self.length // 1024 * 2))
+        self._progress = ui.makeprogress(
+            _("sending"), unit=_("kb"), total=(self.length // 1024 * 2)
+        )
 
     def read(self, *args, **kwargs):
         ret = self._data.read(*args, **kwargs)
@@ -61,35 +62,36 @@
     def __exit__(self, exc_type, exc_val, exc_tb):
         self.close()
 
+
 # moved here from url.py to avoid a cycle
 def readauthforuri(ui, uri, user):
     uri = pycompat.bytesurl(uri)
     # Read configuration
     groups = {}
-    for key, val in ui.configitems('auth'):
-        if key in ('cookiefile',):
+    for key, val in ui.configitems("auth"):
+        if key in ("cookiefile",):
             continue
 
-        if '.' not in key:
+        if "." not in key:
             ui.warn(_("ignoring invalid [auth] key '%s'\n") % key)
             continue
-        group, setting = key.rsplit('.', 1)
+        group, setting = key.rsplit(".", 1)
         gdict = groups.setdefault(group, {})
-        if setting in ('username', 'cert', 'key'):
+        if setting in ("username", "cert", "key"):
             val = util.expandpath(val)
         gdict[setting] = val
 
     # Find the best match
-    scheme, hostpath = uri.split('://', 1)
+    scheme, hostpath = uri.split("://", 1)
     bestuser = None
     bestlen = 0
     bestauth = None
     for group, auth in groups.iteritems():
-        if user and user != auth.get('username', user):
+        if user and user != auth.get("username", user):
             # If a username was set in the URI, the entry username
             # must either match it or be unset
             continue
-        prefix = auth.get('prefix')
+        prefix = auth.get("prefix")
         if not prefix:
             continue
 
@@ -104,18 +106,26 @@
         prefixurl.user = None
         prefix = bytes(prefixurl)
 
-        p = prefix.split('://', 1)
+        p = prefix.split("://", 1)
         if len(p) > 1:
             schemes, prefix = [p[0]], p[1]
         else:
-            schemes = (auth.get('schemes') or 'https').split()
-        if ((prefix == '*' or hostpath.startswith(prefix)) and
-            (len(prefix) > bestlen or (len(prefix) == bestlen and
-                                       not bestuser and 'username' in auth))
-            and scheme in schemes):
+            schemes = (auth.get("schemes") or "https").split()
+        if (
+            (prefix == "*" or hostpath.startswith(prefix))
+            and (
+                len(prefix) > bestlen
+                or (
+                    len(prefix) == bestlen
+                    and not bestuser
+                    and "username" in auth
+                )
+            )
+            and scheme in schemes
+        ):
             bestlen = len(prefix)
             bestauth = group, auth
-            bestuser = auth.get('username')
+            bestuser = auth.get("username")
             if user and not bestuser:
-                auth['username'] = user
+                auth["username"] = user
     return bestauth
diff --git a/mercurial/dirstateguard.py b/mercurial/dirstateguard.py
--- a/mercurial/dirstateguard.py
+++ b/mercurial/dirstateguard.py
@@ -15,8 +15,9 @@
     util,
 )
 
+
 class dirstateguard(util.transactional):
-    '''Restore dirstate at unexpected failure.
+    """Restore dirstate at unexpected failure.
 
     At the construction, this class does:
 
@@ -27,49 +28,57 @@
     is invoked before ``close()``.
 
     This just removes the backup file at ``close()`` before ``release()``.
-    '''
+    """
 
     def __init__(self, repo, name):
         self._repo = repo
         self._active = False
         self._closed = False
-        self._backupname = 'dirstate.backup.%s.%d' % (name, id(self))
-        self._narrowspecbackupname = ('narrowspec.backup.%s.%d' %
-                                      (name, id(self)))
+        self._backupname = "dirstate.backup.%s.%d" % (name, id(self))
+        self._narrowspecbackupname = "narrowspec.backup.%s.%d" % (
+            name,
+            id(self),
+        )
         repo.dirstate.savebackup(repo.currenttransaction(), self._backupname)
         narrowspec.savewcbackup(repo, self._narrowspecbackupname)
         self._active = True
 
     def __del__(self):
-        if self._active: # still active
+        if self._active:  # still active
             # this may occur, even if this class is used correctly:
             # for example, releasing other resources like transaction
             # may raise exception before ``dirstateguard.release`` in
             # ``release(tr, ....)``.
             self._abort()
 
     def close(self):
-        if not self._active: # already inactivated
-            msg = (_("can't close already inactivated backup: %s")
-                   % self._backupname)
+        if not self._active:  # already inactivated
+            msg = (
+                _("can't close already inactivated backup: %s")
+                % self._backupname
+            )
             raise error.Abort(msg)
 
-        self._repo.dirstate.clearbackup(self._repo.currenttransaction(),
-                                         self._backupname)
+        self._repo.dirstate.clearbackup(
+            self._repo.currenttransaction(), self._backupname
+        )
         narrowspec.clearwcbackup(self._repo, self._narrowspecbackupname)
         self._active = False
         self._closed = True
 
     def _abort(self):
         narrowspec.restorewcbackup(self._repo, self._narrowspecbackupname)
-        self._repo.dirstate.restorebackup(self._repo.currenttransaction(),
-                                           self._backupname)
+        self._repo.dirstate.restorebackup(
+            self._repo.currenttransaction(), self._backupname
+        )
         self._active = False
 
     def release(self):
         if not self._closed:
-            if not self._active: # already inactivated
-                msg = (_("can't release already inactivated backup: %s")
-                       % self._backupname)
+            if not self._active:  # already inactivated
+                msg = (
+                    _("can't release already inactivated backup: %s")
+                    % self._backupname
+                )
                 raise error.Abort(msg)
             self._abort()
diff --git a/mercurial/diffhelper.py b/mercurial/diffhelper.py
--- a/mercurial/diffhelper.py
+++ b/mercurial/diffhelper.py
@@ -14,6 +14,7 @@
     pycompat,
 )
 
+
 def addlines(fp, hunk, lena, lenb, a, b):
     """Read lines from fp into the hunk
 
@@ -30,38 +31,40 @@
         for i in pycompat.xrange(num):
             s = fp.readline()
             if not s:
-                raise error.ParseError(_('incomplete hunk'))
+                raise error.ParseError(_("incomplete hunk"))
             if s == "\\ No newline at end of file\n":
                 fixnewline(hunk, a, b)
                 continue
-            if s == '\n' or s == '\r\n':
+            if s == "\n" or s == "\r\n":
                 # Some patches may be missing the control char
                 # on empty lines. Supply a leading space.
-                s = ' ' + s
+                s = " " + s
             hunk.append(s)
-            if s.startswith('+'):
+            if s.startswith("+"):
                 b.append(s[1:])
-            elif s.startswith('-'):
+            elif s.startswith("-"):
                 a.append(s)
             else:
                 b.append(s[1:])
                 a.append(s)
 
+
 def fixnewline(hunk, a, b):
     """Fix up the last lines of a and b when the patch has no newline at EOF"""
     l = hunk[-1]
     # tolerate CRLF in last line
-    if l.endswith('\r\n'):
+    if l.endswith("\r\n"):
         hline = l[:-2]
     else:
         hline = l[:-1]
 
-    if hline.startswith((' ', '+')):
+    if hline.startswith((" ", "+")):
         b[-1] = hline[1:]
-    if hline.startswith((' ', '-')):
+    if hline.startswith((" ", "-")):
         a[-1] = hline
     hunk[-1] = hline
 
+
 def testhunk(a, b, bstart):
     """Compare the lines in a with the lines in b
 
diff --git a/mercurial/cacheutil.py b/mercurial/cacheutil.py
--- a/mercurial/cacheutil.py
+++ b/mercurial/cacheutil.py
@@ -8,14 +8,15 @@
 
 from . import repoview
 
+
 def cachetocopy(srcrepo):
     """return the list of cache file valuable to copy during a clone"""
     # In local clones we're copying all nodes, not just served
     # ones. Therefore copy all branch caches over.
-    cachefiles = ['branch2']
-    cachefiles += ['branch2-%s' % f for f in repoview.filtertable]
-    cachefiles += ['rbc-names-v1', 'rbc-revs-v1']
-    cachefiles += ['tags2']
-    cachefiles += ['tags2-%s' % f for f in repoview.filtertable]
-    cachefiles += ['hgtagsfnodes1']
+    cachefiles = ["branch2"]
+    cachefiles += ["branch2-%s" % f for f in repoview.filtertable]
+    cachefiles += ["rbc-names-v1", "rbc-revs-v1"]
+    cachefiles += ["tags2"]
+    cachefiles += ["tags2-%s" % f for f in repoview.filtertable]
+    cachefiles += ["hgtagsfnodes1"]
     return cachefiles
diff --git a/contrib/import-checker.py b/contrib/import-checker.py
--- a/contrib/import-checker.py
+++ b/contrib/import-checker.py
@@ -10,7 +10,7 @@
 # Import a minimal set of stdlib modules needed for list_stdlib_modules()
 # to work when run from a virtualenv.  The modules were chosen empirically
 # so that the return value matches the return value without virtualenv.
-if True: # disable lexical sorting checks
+if True:  # disable lexical sorting checks
     try:
         import BaseHTTPServer as basehttpserver
     except ImportError:
@@ -21,54 +21,54 @@
 
 # Whitelist of modules that symbols can be directly imported from.
 allowsymbolimports = (
-    '__future__',
-    'bzrlib',
-    'hgclient',
-    'mercurial',
-    'mercurial.hgweb.common',
-    'mercurial.hgweb.request',
-    'mercurial.i18n',
-    'mercurial.node',
+    "__future__",
+    "bzrlib",
+    "hgclient",
+    "mercurial",
+    "mercurial.hgweb.common",
+    "mercurial.hgweb.request",
+    "mercurial.i18n",
+    "mercurial.node",
     # for revlog to re-export constant to extensions
-    'mercurial.revlogutils.constants',
+    "mercurial.revlogutils.constants",
     # for cffi modules to re-export pure functions
-    'mercurial.pure.base85',
-    'mercurial.pure.bdiff',
-    'mercurial.pure.mpatch',
-    'mercurial.pure.osutil',
-    'mercurial.pure.parsers',
+    "mercurial.pure.base85",
+    "mercurial.pure.bdiff",
+    "mercurial.pure.mpatch",
+    "mercurial.pure.osutil",
+    "mercurial.pure.parsers",
     # third-party imports should be directly imported
-    'mercurial.thirdparty',
-    'mercurial.thirdparty.attr',
-    'mercurial.thirdparty.zope',
-    'mercurial.thirdparty.zope.interface',
+    "mercurial.thirdparty",
+    "mercurial.thirdparty.attr",
+    "mercurial.thirdparty.zope",
+    "mercurial.thirdparty.zope.interface",
 )
 
 # Whitelist of symbols that can be directly imported.
-directsymbols = (
-    'demandimport',
-)
+directsymbols = ("demandimport",)
 
 # Modules that must be aliased because they are commonly confused with
 # common variables and can create aliasing and readability issues.
 requirealias = {
-    'ui': 'uimod',
+    "ui": "uimod",
 }
 
+
 def usingabsolute(root):
     """Whether absolute imports are being used."""
     if sys.version_info[0] >= 3:
         return True
 
     for node in ast.walk(root):
         if isinstance(node, ast.ImportFrom):
-            if node.module == '__future__':
+            if node.module == "__future__":
                 for n in node.names:
-                    if n.name == 'absolute_import':
+                    if n.name == "absolute_import":
                         return True
 
     return False
 
+
 def walklocal(root):
     """Recursively yield all descendant nodes but not in a different scope"""
     todo = collections.deque(ast.iter_child_nodes(root))
@@ -80,19 +80,21 @@
             todo.extend(ast.iter_child_nodes(node))
         yield node, newscope
 
+
 def dotted_name_of_path(path):
     """Given a relative path to a source file, return its dotted module name.
 
     >>> dotted_name_of_path('mercurial/error.py')
     'mercurial.error'
     >>> dotted_name_of_path('zlibmodule.so')
     'zlib'
     """
-    parts = path.replace(os.sep, '/').split('/')
-    parts[-1] = parts[-1].split('.', 1)[0] # remove .py and .so and .ARCH.so
-    if parts[-1].endswith('module'):
+    parts = path.replace(os.sep, "/").split("/")
+    parts[-1] = parts[-1].split(".", 1)[0]  # remove .py and .so and .ARCH.so
+    if parts[-1].endswith("module"):
         parts[-1] = parts[-1][:-6]
-    return '.'.join(parts)
+    return ".".join(parts)
+
 
 def fromlocalfunc(modulename, localmods):
     """Get a function to examine which locally defined module the
@@ -158,43 +160,48 @@
     ('foo.bar', 'foo.bar.__init__', True)
     """
     if not isinstance(modulename, str):
-        modulename = modulename.decode('ascii')
-    prefix = '.'.join(modulename.split('.')[:-1])
+        modulename = modulename.decode("ascii")
+    prefix = ".".join(modulename.split(".")[:-1])
     if prefix:
-        prefix += '.'
+        prefix += "."
+
     def fromlocal(name, level=0):
         # name is false value when relative imports are used.
         if not name:
             # If relative imports are used, level must not be absolute.
             assert level > 0
-            candidates = ['.'.join(modulename.split('.')[:-level])]
+            candidates = [".".join(modulename.split(".")[:-level])]
         else:
             if not level:
                 # Check relative name first.
                 candidates = [prefix + name, name]
             else:
-                candidates = ['.'.join(modulename.split('.')[:-level]) +
-                              '.' + name]
+                candidates = [
+                    ".".join(modulename.split(".")[:-level]) + "." + name
+                ]
 
         for n in candidates:
             if n in localmods:
                 return (n, n, False)
-            dottedpath = n + '.__init__'
+            dottedpath = n + ".__init__"
             if dottedpath in localmods:
                 return (n, dottedpath, True)
         return False
+
     return fromlocal
 
+
 def populateextmods(localmods):
     """Populate C extension modules based on pure modules"""
     newlocalmods = set(localmods)
     for n in localmods:
-        if n.startswith('mercurial.pure.'):
-            m = n[len('mercurial.pure.'):]
-            newlocalmods.add('mercurial.cext.' + m)
-            newlocalmods.add('mercurial.cffi._' + m)
+        if n.startswith("mercurial.pure."):
+            m = n[len("mercurial.pure.") :]
+            newlocalmods.add("mercurial.cext." + m)
+            newlocalmods.add("mercurial.cffi._" + m)
     return newlocalmods
 
+
 def list_stdlib_modules():
     """List the modules present in the stdlib.
 
@@ -227,18 +234,18 @@
         yield m
     # These modules only exist on windows, but we should always
     # consider them stdlib.
-    for m in ['msvcrt', '_winreg']:
+    for m in ["msvcrt", "_winreg"]:
         yield m
-    yield '__builtin__'
-    yield 'builtins' # python3 only
-    yield 'importlib.abc' # python3 only
-    yield 'importlib.machinery' # python3 only
-    yield 'importlib.util' # python3 only
-    for m in 'fcntl', 'grp', 'pwd', 'termios':  # Unix only
+    yield "__builtin__"
+    yield "builtins"  # python3 only
+    yield "importlib.abc"  # python3 only
+    yield "importlib.machinery"  # python3 only
+    yield "importlib.util"  # python3 only
+    for m in "fcntl", "grp", "pwd", "termios":  # Unix only
         yield m
-    for m in 'cPickle', 'datetime': # in Python (not C) on PyPy
+    for m in "cPickle", "datetime":  # in Python (not C) on PyPy
         yield m
-    for m in ['cffi']:
+    for m in ["cffi"]:
         yield m
     stdlib_prefixes = {sys.prefix, sys.exec_prefix}
     # We need to supplement the list of prefixes for the search to work
@@ -262,28 +269,33 @@
     for libpath in sys.path:
         # We want to walk everything in sys.path that starts with something in
         # stdlib_prefixes, but not directories from the hg sources.
-        if (os.path.abspath(libpath).startswith(sourceroot)
-            or not any(libpath.startswith(p) for p in stdlib_prefixes)):
+        if os.path.abspath(libpath).startswith(sourceroot) or not any(
+            libpath.startswith(p) for p in stdlib_prefixes
+        ):
             continue
         for top, dirs, files in os.walk(libpath):
             for i, d in reversed(list(enumerate(dirs))):
-                if (not os.path.exists(os.path.join(top, d, '__init__.py'))
-                    or top == libpath and d in ('hgdemandimport', 'hgext',
-                                                'mercurial')):
+                if (
+                    not os.path.exists(os.path.join(top, d, "__init__.py"))
+                    or top == libpath
+                    and d in ("hgdemandimport", "hgext", "mercurial")
+                ):
                     del dirs[i]
             for name in files:
-                if not name.endswith(('.py', '.so', '.pyc', '.pyo', '.pyd')):
+                if not name.endswith((".py", ".so", ".pyc", ".pyo", ".pyd")):
                     continue
-                if name.startswith('__init__.py'):
+                if name.startswith("__init__.py"):
                     full_path = top
                 else:
                     full_path = os.path.join(top, name)
-                rel_path = full_path[len(libpath) + 1:]
+                rel_path = full_path[len(libpath) + 1 :]
                 mod = dotted_name_of_path(rel_path)
                 yield mod
 
+
 stdlib_modules = set(list_stdlib_modules())
 
+
 def imported_modules(source, modulename, f, localmods, ignore_nested=False):
     """Given the source of a file as a string, yield the names
     imported by that file.
@@ -344,7 +356,7 @@
     """
     fromlocal = fromlocalfunc(modulename, localmods)
     for node in ast.walk(ast.parse(source, f)):
-        if ignore_nested and getattr(node, 'col_offset', 0) > 0:
+        if ignore_nested and getattr(node, "col_offset", 0) > 0:
             continue
         if isinstance(node, ast.Import):
             for n in node.names:
@@ -368,7 +380,7 @@
                 continue
 
             modnotfound = False
-            prefix = absname + '.'
+            prefix = absname + "."
             for n in node.names:
                 found = fromlocal(prefix + n.name)
                 if not found:
@@ -381,6 +393,7 @@
                 # lookup
                 yield dottedpath
 
+
 def verify_import_convention(module, source, localmods):
     """Verify imports match our established coding convention.
 
@@ -398,6 +411,7 @@
     else:
         return verify_stdlib_on_own_line(root)
 
+
 def verify_modern_convention(module, root, localmods, root_col_offset=0):
     """Verify a file conforms to the modern import convention rules.
 
@@ -426,8 +440,8 @@
       and readability problems. See `requirealias`.
     """
     if not isinstance(module, str):
-        module = module.decode('ascii')
-    topmodule = module.split('.')[0]
+        module = module.decode("ascii")
+    topmodule = module.split(".")[0]
     fromlocal = fromlocalfunc(module, localmods)
 
     # Whether a local/non-stdlib import has been performed.
@@ -441,19 +455,24 @@
     seenlevels = set()
 
     for node, newscope in walklocal(root):
+
         def msg(fmt, *args):
             return (fmt % args, node.lineno)
+
         if newscope:
             # Check for local imports in function
-            for r in verify_modern_convention(module, node, localmods,
-                                              node.col_offset + 4):
+            for r in verify_modern_convention(
+                module, node, localmods, node.col_offset + 4
+            ):
                 yield r
         elif isinstance(node, ast.Import):
             # Disallow "import foo, bar" and require separate imports
             # for each module.
             if len(node.names) > 1:
-                yield msg('multiple imported names: %s',
-                          ', '.join(n.name for n in node.names))
+                yield msg(
+                    "multiple imported names: %s",
+                    ", ".join(n.name for n in node.names),
+                )
 
             name = node.names[0].name
             asname = node.names[0].asname
@@ -463,88 +482,105 @@
             # Ignore sorting rules on imports inside blocks.
             if node.col_offset == root_col_offset:
                 if lastname and name < lastname and laststdlib == stdlib:
-                    yield msg('imports not lexically sorted: %s < %s',
-                              name, lastname)
+                    yield msg(
+                        "imports not lexically sorted: %s < %s", name, lastname
+                    )
 
             lastname = name
             laststdlib = stdlib
 
             # stdlib imports should be before local imports.
             if stdlib and seenlocal and node.col_offset == root_col_offset:
-                yield msg('stdlib import "%s" follows local import: %s',
-                          name, seenlocal)
+                yield msg(
+                    'stdlib import "%s" follows local import: %s',
+                    name,
+                    seenlocal,
+                )
 
             if not stdlib:
                 seenlocal = name
 
             # Import of sibling modules should use relative imports.
-            topname = name.split('.')[0]
+            topname = name.split(".")[0]
             if topname == topmodule:
-                yield msg('import should be relative: %s', name)
+                yield msg("import should be relative: %s", name)
 
             if name in requirealias and asname != requirealias[name]:
-                yield msg('%s module must be "as" aliased to %s',
-                          name, requirealias[name])
+                yield msg(
+                    '%s module must be "as" aliased to %s',
+                    name,
+                    requirealias[name],
+                )
 
         elif isinstance(node, ast.ImportFrom):
             # Resolve the full imported module name.
             if node.level > 0:
-                fullname = '.'.join(module.split('.')[:-node.level])
+                fullname = ".".join(module.split(".")[: -node.level])
                 if node.module:
-                    fullname += '.%s' % node.module
+                    fullname += ".%s" % node.module
             else:
                 assert node.module
                 fullname = node.module
 
-                topname = fullname.split('.')[0]
+                topname = fullname.split(".")[0]
                 if topname == topmodule:
-                    yield msg('import should be relative: %s', fullname)
+                    yield msg("import should be relative: %s", fullname)
 
             # __future__ is special since it needs to come first and use
             # symbol import.
-            if fullname != '__future__':
+            if fullname != "__future__":
                 if not fullname or (
                     fullname in stdlib_modules
                     and fullname not in localmods
-                    and fullname + '.__init__' not in localmods):
-                    yield msg('relative import of stdlib module')
+                    and fullname + ".__init__" not in localmods
+                ):
+                    yield msg("relative import of stdlib module")
                 else:
                     seenlocal = fullname
 
             # Direct symbol import is only allowed from certain modules and
             # must occur before non-symbol imports.
             found = fromlocal(node.module, node.level)
             if found and found[2]:  # node.module is a package
-                prefix = found[0] + '.'
-                symbols = (n.name for n in node.names
-                           if not fromlocal(prefix + n.name))
+                prefix = found[0] + "."
+                symbols = (
+                    n.name for n in node.names if not fromlocal(prefix + n.name)
+                )
             else:
                 symbols = (n.name for n in node.names)
             symbols = [sym for sym in symbols if sym not in directsymbols]
             if node.module and node.col_offset == root_col_offset:
                 if symbols and fullname not in allowsymbolimports:
-                    yield msg('direct symbol import %s from %s',
-                              ', '.join(symbols), fullname)
+                    yield msg(
+                        "direct symbol import %s from %s",
+                        ", ".join(symbols),
+                        fullname,
+                    )
 
                 if symbols and seennonsymbollocal:
-                    yield msg('symbol import follows non-symbol import: %s',
-                              fullname)
+                    yield msg(
+                        "symbol import follows non-symbol import: %s", fullname
+                    )
             if not symbols and fullname not in stdlib_modules:
                 seennonsymbollocal = True
 
             if not node.module:
                 assert node.level
 
                 # Only allow 1 group per level.
-                if (node.level in seenlevels
-                    and node.col_offset == root_col_offset):
-                    yield msg('multiple "from %s import" statements',
-                              '.' * node.level)
+                if (
+                    node.level in seenlevels
+                    and node.col_offset == root_col_offset
+                ):
+                    yield msg(
+                        'multiple "from %s import" statements', "." * node.level
+                    )
 
                 # Higher-level groups come before lower-level groups.
                 if any(node.level > l for l in seenlevels):
-                    yield msg('higher-level import should come first: %s',
-                              fullname)
+                    yield msg(
+                        "higher-level import should come first: %s", fullname
+                    )
 
                 seenlevels.add(node.level)
 
@@ -554,14 +590,23 @@
 
             for n in node.names:
                 if lastentryname and n.name < lastentryname:
-                    yield msg('imports from %s not lexically sorted: %s < %s',
-                              fullname, n.name, lastentryname)
+                    yield msg(
+                        "imports from %s not lexically sorted: %s < %s",
+                        fullname,
+                        n.name,
+                        lastentryname,
+                    )
 
                 lastentryname = n.name
 
                 if n.name in requirealias and n.asname != requirealias[n.name]:
-                    yield msg('%s from %s must be "as" aliased to %s',
-                              n.name, fullname, requirealias[n.name])
+                    yield msg(
+                        '%s from %s must be "as" aliased to %s',
+                        n.name,
+                        fullname,
+                        requirealias[n.name],
+                    )
+
 
 def verify_stdlib_on_own_line(root):
     """Given some python source, verify that stdlib imports are done
@@ -580,13 +625,20 @@
             for n in node.names:
                 from_stdlib[n.name in stdlib_modules].append(n.name)
             if from_stdlib[True] and from_stdlib[False]:
-                yield ('mixed imports\n   stdlib:    %s\n   relative:  %s' %
-                       (', '.join(sorted(from_stdlib[True])),
-                        ', '.join(sorted(from_stdlib[False]))), node.lineno)
+                yield (
+                    "mixed imports\n   stdlib:    %s\n   relative:  %s"
+                    % (
+                        ", ".join(sorted(from_stdlib[True])),
+                        ", ".join(sorted(from_stdlib[False])),
+                    ),
+                    node.lineno,
+                )
+
 
 class CircularImport(Exception):
     pass
 
+
 def checkmod(mod, imports):
     shortest = {}
     visit = [[mod]]
@@ -601,6 +653,7 @@
                     continue
                 visit.append(path + [i])
 
+
 def rotatecycle(cycle):
     """arrange a cycle so that the lexicographically first module listed first
 
@@ -611,6 +664,7 @@
     idx = cycle.index(lowest)
     return cycle[idx:] + cycle[:idx] + [lowest]
 
+
 def find_cycles(imports):
     """Find cycles in an already-loaded import graph.
 
@@ -634,9 +688,11 @@
             cycles.add(" -> ".join(rotatecycle(cycle)))
     return cycles
 
+
 def _cycle_sortkey(c):
     return len(c), c
 
+
 def embedded(f, modname, src):
     """Extract embedded python code
 
@@ -670,14 +726,15 @@
         if not name:
             # use 'doctest.py', in order to make already existing
             # doctest above pass instantly
-            name = 'doctest.py'
+            name = "doctest.py"
         # "starts" is "line number" (1-origin), but embedded() is
         # expected to return "line offset" (0-origin). Therefore, this
         # yields "starts - 1".
         if not isinstance(modname, str):
-            modname = modname.decode('utf8')
+            modname = modname.decode("utf8")
         yield code, "%s[%d]" % (modname, starts), name, starts - 1
 
+
 def sources(f, modname):
     """Yields possibly multiple sources from a filepath
 
@@ -689,20 +746,21 @@
     the input file.
     """
     py = False
-    if not f.endswith('.t'):
-        with open(f, 'rb') as src:
+    if not f.endswith(".t"):
+        with open(f, "rb") as src:
             yield src.read(), modname, f, 0
             py = True
-    if py or f.endswith('.t'):
-        with open(f, 'rb') as src:
+    if py or f.endswith(".t"):
+        with open(f, "rb") as src:
             for script, modname, t, line in embedded(f, modname, src):
-                yield script, modname.encode('utf8'), t, line
+                yield script, modname.encode("utf8"), t, line
+
 
 def main(argv):
-    if len(argv) < 2 or (argv[1] == '-' and len(argv) > 2):
-        print('Usage: %s {-|file [file] [file] ...}')
+    if len(argv) < 2 or (argv[1] == "-" and len(argv) > 2):
+        print("Usage: %s {-|file [file] [file] ...}")
         return 1
-    if argv[1] == '-':
+    if argv[1] == "-":
         argv = argv[:1]
         argv.extend(l.rstrip() for l in sys.stdin.readlines())
     localmodpaths = {}
@@ -715,19 +773,23 @@
     for localmodname, source_path in sorted(localmodpaths.items()):
         if not isinstance(localmodname, bytes):
             # This is only safe because all hg's files are ascii
-            localmodname = localmodname.encode('ascii')
+            localmodname = localmodname.encode("ascii")
         for src, modname, name, line in sources(source_path, localmodname):
             try:
                 used_imports[modname] = sorted(
-                    imported_modules(src, modname, name, localmods,
-                                     ignore_nested=True))
-                for error, lineno in verify_import_convention(modname, src,
-                                                              localmods):
+                    imported_modules(
+                        src, modname, name, localmods, ignore_nested=True
+                    )
+                )
+                for error, lineno in verify_import_convention(
+                    modname, src, localmods
+                ):
                     any_errors = True
-                    print('%s:%d: %s' % (source_path, lineno + line, error))
+                    print("%s:%d: %s" % (source_path, lineno + line, error))
             except SyntaxError as e:
-                print('%s:%d: SyntaxError: %s' %
-                      (source_path, e.lineno + line, e))
+                print(
+                    "%s:%d: SyntaxError: %s" % (source_path, e.lineno + line, e)
+                )
     cycles = find_cycles(used_imports)
     if cycles:
         firstmods = set()
@@ -738,10 +800,11 @@
             # of cycles that are effectively duplicates.
             if first in firstmods:
                 continue
-            print('Import cycle:', c)
+            print("Import cycle:", c)
             firstmods.add(first)
         any_errors = True
     return any_errors != 0
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     sys.exit(int(main(sys.argv)))



To: durin42, #hg-reviewers
Cc: martinvonz, mjpieters, mercurial-devel


More information about the Mercurial-devel mailing list