Configure and apply isort & black
A => .flake8 +2 -0
@@ 0,0 1,2 @@ 
+[flake8]
+max-line-length = 88

          
M hgext3rd/confman/__init__.py +17 -15
@@ 6,23 6,24 @@ or in the REAMDE.md file.
 testedwith = '5.8 5.9 6.0 6.1 6.2 6.3'
 
 import os.path as osp
+
 from mercurial import extensions
 
+from .commands import *
 from .meta import colortable
 
-from .commands import *
-
-
 configtable = {}
 configitem = registrar.configitem(configtable)
 
-configitem(b'confman', b'hggit',
-           default=True,
+configitem(
+    b'confman',
+    b'hggit',
+    default=True,
 )
 
 
 def extsetup(ui):
-    """ add confman support to hgview """
+    """add confman support to hgview"""
     try:
         extensions.find(b'hgview')
     except KeyError:

          
@@ 31,19 32,20 @@ def extsetup(ui):
         from hgviewlib.util import SUBREPO_GETTERS
     except ImportError:
         return
+
     def _get_confman(repo_path):
-        """ return mapping of section -> path
-        for all managed repositories """
+        """return mapping of section -> path
+        for all managed repositories"""
         confpath = osp.join(repo_path, '.hgconf')
         if not osp.exists(confpath):
             return None
         from .configuration import configurationmanager
+
         confman = configurationmanager(ui, repo_path, (), {})
-        return ((section, conf.get('layout'))
-                for section, conf, managed in confman.iterrepos()
-                if (managed is not None or
-                    conf.get('expand', None) is not None))
+        return (
+            (section, conf.get('layout'))
+            for section, conf, managed in confman.iterrepos()
+            if (managed is not None or conf.get('expand', None) is not None)
+        )
+
     SUBREPO_GETTERS.append(_get_confman)
-
-
-

          
M hgext3rd/confman/commands.py +125 -100
@@ 3,28 3,12 @@ import os
 import os.path as osp
 import sys
 
-from mercurial import (
-    error,
-    registrar
-)
+from mercurial import error, registrar
 from mercurial.i18n import _
 
-from .utils import (
-    readconf,
-    WrappedUI,
-    WrappedRepo
-)
-from .managed import (
-    gitrepo,
-    hgrepo
-)
-from .opts import (
-    DEFAULTOPTS,
-    EXCLUDEOPT,
-    INCLUDEOPT,
-    PULLURIOPT,
-    REMOTEOPTS
-)
+from .managed import gitrepo, hgrepo
+from .opts import DEFAULTOPTS, EXCLUDEOPT, INCLUDEOPT, PULLURIOPT, REMOTEOPTS
+from .utils import WrappedRepo, WrappedUI, readconf
 
 ENC = os.environ.get('ENCODING')
 

          
@@ 35,46 19,45 @@ cmdtable = {}
 def command(name, opts):
     name = name.encode('utf-8')
     newopts = [
-        tuple(item.encode('utf-8')
-              if isinstance(item, str) else item
-              for item in elt)
+        tuple(item.encode('utf-8') if isinstance(item, str) else item for item in elt)
         for elt in opts
     ]
 
     def wrap_command(func):
         def wrapped_func(ui, repo, *args, **kw):
-            newargs = tuple(
-                elt.decode('utf-8')
-                for elt in args
-            )
+            newargs = tuple(elt.decode('utf-8') for elt in args)
             newk = {}
             for k, v in kw.items():
                 if isinstance(v, bytes):
                     v = v.decode('utf-8')
                 elif isinstance(v, list):
                     v = [
-                        elt.decode('utf-8')
-                        if isinstance(elt, bytes) else elt
+                        elt.decode('utf-8') if isinstance(elt, bytes) else elt
                         for elt in v
                     ]
                 newk[k] = v
-            return func(
-                WrappedUI(ui),
-                WrappedRepo(repo),
-                *newargs,
-                **newk
-            )
+            return func(WrappedUI(ui), WrappedRepo(repo), *newargs, **newk)
+
         wrapped_func.__doc__ = func.__doc__
         return _command(name, newopts)(wrapped_func)
 
     return wrap_command
 
 
-@command('cfensureconf',
-         DEFAULTOPTS + REMOTEOPTS + [
-             ('s', 'share-path', '', 'specify share path'),
-             ('', 'keep-descendant', False,
-              'do not update managed if it is on a descendant of track')])
+@command(
+    'cfensureconf',
+    DEFAULTOPTS
+    + REMOTEOPTS
+    + [
+        ('s', 'share-path', '', 'specify share path'),
+        (
+            '',
+            'keep-descendant',
+            False,
+            'do not update managed if it is on a descendant of track',
+        ),
+    ],
+)
 def ensureconf(ui, repo, *args, **opts):
     """update managed repositories using their track value
 

          
@@ 104,7 87,7 @@ def ensureconf(ui, repo, *args, **opts):
         snapshot = snaps.get(layout)
         wctx = managed.workingctx()
         if wctx.hex == snapshot:
-            continue # already up to date
+            continue  # already up to date
         if managed.check_dirty(section):
             failedrepos.append(section)
             continue

          
@@ 122,13 105,19 @@ def ensureconf(ui, repo, *args, **opts):
     if failedrepos:
         return 1
 
+
 # baseline
 
-@command('cfbaseline',
-         DEFAULTOPTS + [
-             ('', 'force-hgconf', False, 'force the generation of an .hgconf file'),
-             ('', 'propagate', False, 'edit inner configuration also'),
-             ('Z', 'ignoremaster', True, 'ignore the <origin>/master tag')])
+
+@command(
+    'cfbaseline',
+    DEFAULTOPTS
+    + [
+        ('', 'force-hgconf', False, 'force the generation of an .hgconf file'),
+        ('', 'propagate', False, 'edit inner configuration also'),
+        ('Z', 'ignoremaster', True, 'ignore the <origin>/master tag'),
+    ],
+)
 def baseline(ui, repo, *args, **opts):
     """update the track attributes with cset hashes or matching tags
 

          
@@ 195,9 184,10 @@ def baseline(ui, repo, *args, **opts):
 
 # pull
 
+
 @command('cfpull', DEFAULTOPTS + REMOTEOPTS)
 def pull(ui, repo, *args, **opts):
-    """pull managed repositories """
+    """pull managed repositories"""
     confman, repo = readconf(ui, repo, args, opts)
 
     for section, conf, managed in confman.iterrepos():

          
@@ 214,9 204,10 @@ def pull(ui, repo, *args, **opts):
 
 # push
 
+
 @command('cfpush', DEFAULTOPTS + REMOTEOPTS)
 def push(ui, repo, *args, **opts):
-    """push managed repositories up to their tracked rev """
+    """push managed repositories up to their tracked rev"""
     confman, repo = readconf(ui, repo, args, opts)
 
     for section, conf, managed in confman.iterrepos():

          
@@ 225,8 216,10 @@ def push(ui, repo, *args, **opts):
             continue
         managed.push_repo(section, conf)
 
+
 # summary
 
+
 @command('cfsummary', DEFAULTOPTS)
 def summary(ui, repo, *args, **opts):
     """print a summary of the managed repositories

          
@@ 252,7 245,7 @@ def summary(ui, repo, *args, **opts):
 
         phase = rctx.phase
         if phase:
-           ui.write(' ')
+            ui.write(' ')
         ui.write('%s' % phase, label='confman.%s-phase' % phase)
         ui.write(') ')
 

          
@@ 271,31 264,39 @@ def summary(ui, repo, *args, **opts):
         track = conf.get('track')
         trackctx = managed.revsingle(track, skiperror=True)
         if track is None:
-            ui.write('[no baseline]',
-                     label='confman.nobaseline')
+            ui.write('[no baseline]', label='confman.nobaseline')
         elif track == branch:
-            ui.write('[baseline aligned with branch]',
-                     label='confman.branchaligned')
+            ui.write('[baseline aligned with branch]', label='confman.branchaligned')
         elif track in tags:
             ui.write_bytes(
                 '\N{CHECK MARK}'.encode(ENC or sys.stdout.encoding, 'confman'),
-                label='confman.tagaligned'
+                label='confman.tagaligned',
             )
         elif track == str(rctx.revnum) or rctx.hex.startswith(track):
-            ui.write('[baseline aligned with%s cset %s]' % (obs(trackctx), track[:12]),
-                     label='confman.csetaligned')
+            ui.write(
+                '[baseline aligned with%s cset %s]' % (obs(trackctx), track[:12]),
+                label='confman.csetaligned',
+            )
         elif trackctx == rctx:
-            ui.write('[baseline aligned with revset %r]' % track,
-                     label='confman.revsetaligned')
+            ui.write(
+                '[baseline aligned with revset %r]' % track,
+                label='confman.revsetaligned',
+            )
         elif trackctx in rctx.ancestors():
-            ui.write('[at descendant of%s %r]' % (obs(trackctx), track),
-                     label='confman.snapolder')
+            ui.write(
+                '[at descendant of%s %r]' % (obs(trackctx), track),
+                label='confman.snapolder',
+            )
         elif trackctx in rctx.descendants():
-            ui.write('[at parent of%s %r]' % (obs(trackctx), track),
-                     label='confman.snapnewer')
+            ui.write(
+                '[at parent of%s %r]' % (obs(trackctx), track),
+                label='confman.snapnewer',
+            )
         elif trackctx:
-            ui.write('[baseline%s %r in a parallel branch]' % (obs(trackctx), track),
-                     label='confman.snapparallel')
+            ui.write(
+                '[baseline%s %r in a parallel branch]' % (obs(trackctx), track),
+                label='confman.snapparallel',
+            )
         else:
             ui.write('[baseline says %r]' % track, label='confman.unaligned')
 

          
@@ 330,8 331,8 @@ def summary(ui, repo, *args, **opts):
 
 # broadcast
 
-@command('cfbroadcast', DEFAULTOPTS + [
-    ('e', 'execute', [], 'execute command')])
+
+@command('cfbroadcast', DEFAULTOPTS + [('e', 'execute', [], 'execute command')])
 def broadcast(ui, repo, *args, **opts):
     """execute a shell command in the context of managed repositories
 

          
@@ 364,24 365,36 @@ def broadcast(ui, repo, *args, **opts):
             try:
                 command = command % params
             except KeyError as err:
-                ui.write('skip %s: unknown parameter %s\n' % (section, err),
-                         label='confman.dirty')
+                ui.write(
+                    'skip %s: unknown parameter %s\n' % (section, err),
+                    label='confman.dirty',
+                )
                 continue
-            proc = subprocess.Popen(command, shell=True,
-                                    stdin=subprocess.PIPE,
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE,
-                                    cwd=confman.pathfromsection(section))
+            proc = subprocess.Popen(
+                command,
+                shell=True,
+                stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                cwd=confman.pathfromsection(section),
+            )
             out, err = proc.communicate()
             ui.write_bytes(out)
             if proc.returncode != 0:
-                ui.write('finished with return code %s\n' % proc.returncode,
-                         label='confman.dirty')
+                ui.write(
+                    'finished with return code %s\n' % proc.returncode,
+                    label='confman.dirty',
+                )
 
 
-@command('cffiles', DEFAULTOPTS + [
-    ('n', 'no-section', False, 'do not display section name'),
-    ('0', 'print0', False, 'end filenames with NUL, for use with xargs')])
+@command(
+    'cffiles',
+    DEFAULTOPTS
+    + [
+        ('n', 'no-section', False, 'do not display section name'),
+        ('0', 'print0', False, 'end filenames with NUL, for use with xargs'),
+    ],
+)
 def files(ui, repo, *args, **opts):
     """list tracked files in the managed repositories
 

          
@@ 403,9 416,15 @@ def files(ui, repo, *args, **opts):
 
 # rewrite repo conf
 
-@command('cfupdateconf', DEFAULTOPTS + [
-    ('', 'difftool', 'diff', 'diff command'),
-    ('a', 'apply', False, 'really apply the changes (irreversible)')])
+
+@command(
+    'cfupdateconf',
+    DEFAULTOPTS
+    + [
+        ('', 'difftool', 'diff', 'diff command'),
+        ('a', 'apply', False, 'really apply the changes (irreversible)'),
+    ],
+)
 def updateconf(ui, repo, *args, **opts):
     """update your managed repos `.hg/hgrc` files with values of the `.hgconf` entries
 

          
@@ 431,12 450,18 @@ def updateconf(ui, repo, *args, **opts):
 
 # requirements.txt handling
 
-@command('debugcfrequirements', [
-    INCLUDEOPT, EXCLUDEOPT, PULLURIOPT,
-    ('e', 'editable', False, 'use local project path or and develop mode')])
+
+@command(
+    'debugcfrequirements',
+    [
+        INCLUDEOPT,
+        EXCLUDEOPT,
+        PULLURIOPT,
+        ('e', 'editable', False, 'use local project path or and develop mode'),
+    ],
+)
 def requirements(ui, repo, *args, **opts):
-    """generate a requirements.txt file from the .hgconf specification
-    """
+    """generate a requirements.txt file from the .hgconf specification"""
     confman, repo = readconf(ui, repo, args, opts)
 
     with open('requirements.txt', 'wb') as req:

          
@@ 451,12 476,16 @@ def requirements(ui, repo, *args, **opts
                     prefix, suffix = 'git+', '@' + conf.get('track', 'default')
                 else:
                     prefix, suffix = '', ''
-                uri = conf.get('hgrc.paths.%s' % opts.get('use_hgrc_path')) or conf['pulluri']
+                uri = (
+                    conf.get('hgrc.paths.%s' % opts.get('use_hgrc_path'))
+                    or conf['pulluri']
+                )
                 req.write('%s%s%s\n' % (prefix, uri.format(**conf), suffix))
 
 
 # DEPRECATED
 
+
 @command('debugsnapshot', DEFAULTOPTS)
 def snapshot(ui, repo, *args, **opts):
     """record changeset ids of the managed repositories into the `.hgsnap` file

          
@@ 480,23 509,17 @@ def snapshot(ui, repo, *args, **opts):
 def showsnapshotstate(self, ui, snapshot, rctx):
     snaprctx = self.revsingle(snapshot, skiperror=True)
     if snapshot is None:
-        ui.write('[no snapshot]',
-                 label='confman.nosnap')
+        ui.write('[no snapshot]', label='confman.nosnap')
     elif self.unknown_rev(snapshot):
-        ui.write('[unknown snapshot]',
-                 label='confman.snapunknown')
+        ui.write('[unknown snapshot]', label='confman.snapunknown')
     elif rctx == snaprctx:
-        ui.write('[snapshot aligned]',
-                 label='confman.snapaligned')
+        ui.write('[snapshot aligned]', label='confman.snapaligned')
     elif snaprctx in rctx.ancestors():
-        ui.write('[at descendant of snapshot]',
-                 label='confman.snapolder')
+        ui.write('[at descendant of snapshot]', label='confman.snapolder')
     elif snaprctx in rctx.descendants():
-        ui.write('[at parent of snapshot]',
-                 label='confman.snapnewer')
+        ui.write('[at parent of snapshot]', label='confman.snapnewer')
     else:
-        ui.write('[snapshot in parallel branch]',
-                 label='confman.snapparallel')
+        ui.write('[snapshot in parallel branch]', label='confman.snapparallel')
 
 
 @command('debugwritegrfiles', DEFAULTOPTS + [PULLURIOPT])

          
@@ 512,7 535,9 @@ def writegrfiles(ui, repo, *args, **opts
                 track = secconf.get('track')
                 pulluri = secconf.get('pulluri')
                 if opts.get('use_hgrc_path'):
-                    pulluri = secconf.get('hgrc.paths.' + opts.get('use_hgrc_path'), pulluri)
+                    pulluri = secconf.get(
+                        'hgrc.paths.' + opts.get('use_hgrc_path'), pulluri
+                    )
                 try:
                     ctx = managed.revsingle(track)
                     track = ctx.tag or ctx.hex

          
M hgext3rd/confman/configuration.py +45 -38
@@ 1,11 1,12 @@ 
 """This module contains the configurationmanager object."""
 
+import itertools
 import os
-import itertools
 from collections import defaultdict
 
-from mercurial import util, error
-from .meta import MANDATORY, CONFMANENTRIES
+from mercurial import error, util
+
+from .meta import CONFMANENTRIES, MANDATORY
 from .utils import ending
 
 

          
@@ 28,18 29,18 @@ def _filtersection(section, exactmatch=(
         return False
     return True
 
+
 STATUSMAP = {
     0: '   ',
     1: '\N{BOX DRAWINGS LIGHT VERTICAL}  ',
     2: '\N{BOX DRAWINGS LIGHT UP AND RIGHT}\N{RIGHTWARDS ARROW} ',
-    3: '\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}\N{RIGHTWARDS ARROW} '
-    }
+    3: '\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}\N{RIGHTWARDS ARROW} ',
+}
 
 
 class configurationmanager(object):
     "Configuration manager"
-    __slots__ = ('ui', 'rootpath', 'args', 'opts',
-                 'confs', 'failed', 'sectionlevels')
+    __slots__ = ('ui', 'rootpath', 'args', 'opts', 'confs', 'failed', 'sectionlevels')
 
     def __init__(self, ui, rootpath, args, opts):
         self.ui = ui

          
@@ 62,6 63,7 @@ class configurationmanager(object):
     def _readconf(self):
         "Load configuration from <root>/.hgconf"
         from .utils import oconfig
+
         self.confs = oconfig(confman=self)
         self.confs.read(os.path.join(self.rootpath, '.hgconf'))
 

          
@@ 72,17 74,21 @@ class configurationmanager(object):
             ui = self.ui
             if not skipmissing:
                 ui.warn('You must complete the configuration before using it. See:\n')
-                ui.warn(''.join('error: %s.%s is missing\n' % (section, opt) for opt in err))
+                ui.warn(
+                    ''.join('error: %s.%s is missing\n' % (section, opt) for opt in err)
+                )
                 raise error.Abort(b'configuration error')
             else:
                 ui.warn('%s is a partial override without its master entry\n' % section)
                 return True
 
     def pathfromsection(self, section):
-        "Return the path of the repository managed at ``section`` "
-        rootpath = (self.opts.get('root_path') or
-                    self.ui.configpath('confman', 'rootpath') or
-                    self.rootpath)
+        "Return the path of the repository managed at ``section``"
+        rootpath = (
+            self.opts.get('root_path')
+            or self.ui.configpath('confman', 'rootpath')
+            or self.rootpath
+        )
         conf = self.confs[section]
         layout = conf['layout'].format(**conf)
         return os.path.join(rootpath, layout)

          
@@ 92,12 98,15 @@ class configurationmanager(object):
         None if the repository is missing.
         Raise RepoError if the repository cannot be built."""
         from .managed import repoclassbyconf
+
         path = self.pathfromsection(section)
         if not os.path.exists(path):
             return None
         try:
             return repoclassbyconf(
-                self.confs[section], path, self.hggit,
+                self.confs[section],
+                path,
+                self.hggit,
             )(self, path)
         except error.RepoError:
             return None

          
@@ 129,8 138,7 @@ class configurationmanager(object):
             managed = self.repofromsection(section)
             if managed is None and skipmissing:
                 path = self.pathfromsection(section)
-                self.ui.write('%s repository at "%s" not found\n' %
-                              (section, path))
+                self.ui.write('%s repository at "%s" not found\n' % (section, path))
                 continue
             yield section, conf, managed
             if conf.get('expand', None):

          
@@ 173,6 181,7 @@ class configurationmanager(object):
     def fill_missing(self):
         "Try to clone the missing managed repositories if possible"
         from .managed import repoclassbyconf
+
         ui = self.ui
         # catches simple rev ids but NOT revexprs
         for section, conf, managed in self.iterrepos(skipmissing=False):

          
@@ 186,9 195,7 @@ class configurationmanager(object):
             ui.status('cloning %s from %s to %s\n' % (section, source, dest))
             try:
                 path = self.pathfromsection(section)
-                repoclassbyconf(
-                    conf, path, self.hggit
-                ).clone(
+                repoclassbyconf(conf, path, self.hggit).clone(
                     self, source, dest, self.confs[section]
                 )
             except Exception as err:

          
@@ 210,29 217,27 @@ class configurationmanager(object):
                 # let's write down those options
                 self.handle_hgrc(section, conf)
 
-
     @util.cachefunc
     def levelstatus(self, section, level):
         sectionlevels = self.sectionlevels[section]
         sections = self.sections
         # sections under scope of the current section
-        scope = sections[sections.index(section) + 1:]
+        scope = sections[sections.index(section) + 1 :]
         # levels where scoped sessions  are
-        scopelevels = set(itertools.chain(*(
-            self.sectionlevels[s] for s in scope)))
+        scopelevels = set(itertools.chain(*(self.sectionlevels[s] for s in scope)))
 
         if level not in sectionlevels:
             if level in scopelevels:
-                return 1 # under our scope, not our business
-            return 0 # out of scope
-        nextsection = (section != sections[-1]
-                       and sections[sections.index(section)+1]
-                       or None)
+                return 1  # under our scope, not our business
+            return 0  # out of scope
+        nextsection = (
+            section != sections[-1] and sections[sections.index(section) + 1] or None
+        )
         if nextsection:
             if not self.levelstatus(nextsection, level):
-                return 2 # end of scope
-            return 3 # we *override* this
-        return 2 # end of scope
+                return 2  # end of scope
+            return 3  # we *override* this
+        return 2  # end of scope
 
     def unicodetreenode(self, section):
         "Return the unicode string to print for the given section."

          
@@ 249,8 254,9 @@ class configurationmanager(object):
         """Handler for the `hgrc` top level optional configuration entries
         Will turn any entry such as:
           hgrc.paths.foo = http://hg.bar.org
-        into a foo entry in the managed repo hgrc [paths] section """
-        from .utils import oconfig, _unflatten
+        into a foo entry in the managed repo hgrc [paths] section"""
+        from .utils import _unflatten, oconfig
+
         repopath = self.pathfromsection(section)
         hgrcpath = os.path.join(repopath, '.hg', 'hgrc')
         if not os.path.exists(hgrcpath):

          
@@ 297,7 303,7 @@ class configurationmanager(object):
                         rewritten.append((section, tagmap[section]))
                     newhgconf.write(line)
 
-        if os.name == 'nt': # atomic rename not a windows thing
+        if os.name == 'nt':  # atomic rename not a windows thing
             os.unlink(hgconfpath)
         os.rename(newhgconfpath, hgconfpath)
         return rewritten

          
@@ 309,9 315,7 @@ class configurationmanager(object):
             with open(snappath, 'r') as snapfile:
                 return {
                     layout: revision.strip()
-                    for revision, layout in (
-                            line.split() for line in snapfile
-                    )
+                    for revision, layout in (line.split() for line in snapfile)
                 }
         return {}
 

          
@@ 342,8 346,11 @@ class configurationmanager(object):
         oldsnaps = self.readsnapshot()
         if oldsnaps != snaps:
             with open(os.path.join(self.rootpath, '.hgsnap'), 'w') as hgsnapfile:
-                hgsnapfile.write(''.join('%s %s\n' % (node, path)
-                                         for path, node in sorted(snaps.items())))
+                hgsnapfile.write(
+                    ''.join(
+                        '%s %s\n' % (node, path) for path, node in sorted(snaps.items())
+                    )
+                )
             ui.status('new snapshot in .hgsnap\n')
         else:
             ui.status('nothing changed\n')

          
M hgext3rd/confman/gr.py +12 -6
@@ 2,18 2,19 @@ 
 guestrepo extension compatibility support
 """
 import os
-from mercurial import config, util, error
+
+from mercurial import config, error, util
 
+from .configuration import configurationmanager as _configurationmanager
 from .utils import ending
-from .configuration import configurationmanager as _configurationmanager
 
 
 class configurationmanager(_configurationmanager):
     "Configuration manager for guestrepo files"
 
     def readsnapshot(self):
-        """ return a dict(layout:rev) using the guestrepo
-        configuration files """
+        """return a dict(layout:rev) using the guestrepo
+        configuration files"""
         grepopath = os.path.join(self.rootpath, '.hgguestrepo')
         if os.path.exists(grepopath):
             conf = config.config()

          
@@ 52,10 53,15 @@ class configurationmanager(_configuratio
                         raise error.Abort(b'Malformed line %s %r' % (lineno + 1, line))
                     track = tagmap.get(name)
                     if track is not None and cset != track:
-                        sline = '%s = %s %s%s' % (layout, name, tagmap[name], ending(sline))
+                        sline = '%s = %s %s%s' % (
+                            layout,
+                            name,
+                            tagmap[name],
+                            ending(sline),
+                        )
                         rewritten.append((name, track))
                     newhgguest.write(sline)
-        if os.name == 'nt': # atomic rename not a windows thing
+        if os.name == 'nt':  # atomic rename not a windows thing
             os.unlink(hgguestpath)
         os.rename(newhgguestpath, hgguestpath)
         return rewritten

          
M hgext3rd/confman/hgcompat.py +9 -5
@@ 1,13 1,14 @@ 
 """This version aims to ensure compatibility between multiple version of
 mercurial.
 """
-from mercurial.util import sortdict, re as hgre
 from mercurial.configitems import coreconfigitem
+from mercurial.util import re as hgre
+from mercurial.util import sortdict
 
 compilere = hgre.compile
 
+
 class sortdict(sortdict):
-
     def preparewrite(self):
         """call this before writes, return self or a copied new object"""
         if getattr(self, '_copied', 0):

          
@@ 15,14 16,17 @@ class sortdict(sortdict):
             return self.__class__(self)
         return self
 
-coreconfigitem(b'confman', b'rootpath',
-               default=None
-)
+
+coreconfigitem(b'confman', b'rootpath', default=None)
 
 
 from mercurial import exchange
+
+
 def push(local, remote, *args, **kwargs):
     return exchange.push(local, remote, *args, **kwargs)
+
+
 def pull(local, remote, *args, **kwargs):
     return exchange.pull(local, remote, *args, **kwargs)
 

          
M hgext3rd/confman/managed.py +97 -98
@@ 1,15 1,17 @@ 
 "This module contains abtractions for managed repositories."
 import os
 import os.path as osp
+import tarfile
 import urllib.parse
-import tarfile
 import zipfile
 from subprocess import check_output as call
 
-from mercurial import hg, error, commands, archival, scmutil, util
+from mercurial import archival, commands, error, hg, scmutil, util
 from mercurial.utils.urlutil import parseurl
-from .hgcompat import pull as hgpull, push as hgpush
-from .utils import download_file, WrappedRepo
+
+from .hgcompat import pull as hgpull
+from .hgcompat import push as hgpush
+from .utils import WrappedRepo, download_file
 
 
 class rcbase(object):

          
@@ 43,7 45,6 @@ class rcbase(object):
 
 
 class revisioncontext(rcbase):
-
     def __init__(self, cset):
         self._cset = cset
         # be careful with the 'next commit'

          
@@ 66,8 67,7 @@ class revisioncontext(rcbase):
 
     @property
     def parents(self):
-        return [revisioncontext(p)
-                for p in self._cset.parents()]
+        return [revisioncontext(p) for p in self._cset.parents()]
 
     @property
     def phase(self):

          
@@ 75,33 75,25 @@ class revisioncontext(rcbase):
 
     @property
     def tags(self):
-        return [
-            t.decode('utf-8')
-            for t in self._cset.tags()
-        ]
+        return [t.decode('utf-8') for t in self._cset.tags()]
 
     @property
     def revnum(self):
         return self._cset.rev()
 
     def ancestors(self):
-        return (revisioncontext(cset)
-                for cset in self._cset.ancestors())
+        return (revisioncontext(cset) for cset in self._cset.ancestors())
 
     def descendants(self):
-        return (revisioncontext(cset)
-                for cset in self._cset.descendants())
+        return (revisioncontext(cset) for cset in self._cset.descendants())
 
     def obsolete(self):
         return self._cset.obsolete()
 
 
 class gitrevisioncontext(rcbase):
-
     def _call(self, *args):
-        return call(
-            ('git',) + args, cwd=self.path
-        ).strip().decode('utf-8')
+        return call(('git',) + args, cwd=self.path).strip().decode('utf-8')
 
     def __init__(self, path, hex=None):
         self.path = path

          
@@ 121,8 113,7 @@ class gitrevisioncontext(rcbase):
         # git revs (same as we do with hg revs). This is also coherent with the
         # "git rev-parse" call below, which gets a long rev.
         if self.hex:
-            args = ['describe', '--long', '--tags', '--always', '--abbrev=40',
-                    self.hex]
+            args = ['describe', '--long', '--tags', '--always', '--abbrev=40', self.hex]
             try:
                 out = self._call(*args)
                 tag, dist, _hex = (['', ''] + out.rsplit('-', 2))[-3:]

          
@@ 171,17 162,18 @@ def repoclassbyconf(conf, path, hggit=Fa
     pulluri = conf['pulluri']
 
     # first check the local repo (if it exists)
-    if (osp.isdir(osp.join(path, '.hg'))
-        or osp.isdir(osp.join(pulluri, '.hg'))):
+    if osp.isdir(osp.join(path, '.hg')) or osp.isdir(osp.join(pulluri, '.hg')):
         return hgrepo
 
     if osp.isdir(osp.join(path, '.git')):
         return gitrepo
 
     # then the hg-vs-git-vs-hggit
-    if (uri.scheme == 'git' or
-        uri.path.endswith('.git') or
-        osp.isdir(osp.join(pulluri, '.git'))):
+    if (
+        uri.scheme == 'git'
+        or uri.path.endswith('.git')
+        or osp.isdir(osp.join(pulluri, '.git'))
+    ):
         if hggit:
             return hgrepo
         return gitrepo

          
@@ 235,8 227,10 @@ class managedrepo(object):
         self.conf = conf
         self.ui = conf.ui
 
+
 class tgzrepo(managedrepo):
-    """ A tarball repository """
+    """A tarball repository"""
+
     __slots__ = ('conf', 'ui', 'root')
 
     @classmethod

          
@@ 247,7 241,9 @@ class tgzrepo(managedrepo):
                 os.makedirs(dest)
             # most of the time, the final folder is archivec
             # we would like it to be the final dest
-            if set(m.name.split('/', 1)[0] for m in tf.members) == {os.path.basename(dest)}:
+            if set(m.name.split('/', 1)[0] for m in tf.members) == {
+                os.path.basename(dest)
+            }:
                 dest = os.path.dirname(dest) or '.'
             tf.extractall(dest)
 

          
@@ 284,7 280,8 @@ class tgzrepo(managedrepo):
 
 
 class ziprepo(tgzrepo):
-    """ A zip repository """
+    """A zip repository"""
+
     __slots__ = ('conf', 'ui', 'root')
 
     @classmethod

          
@@ 297,7 294,8 @@ class ziprepo(tgzrepo):
 
 
 class gitrepo(managedrepo):
-    """ A git repository """
+    """A git repository"""
+
     __slots__ = ('conf', 'ui', 'root')
 
     @classmethod

          
@@ 311,9 309,7 @@ class gitrepo(managedrepo):
 
     def _call(self, *args):
         try:
-            return call(
-                ('git',) + args, cwd=self.root
-            ).strip().decode('utf-8')
+            return call(('git',) + args, cwd=self.root).strip().decode('utf-8')
         except Exception as exc:
             # stdout will show the shit
             pass

          
@@ 330,8 326,9 @@ class gitrepo(managedrepo):
     def check_dirty(self, section):
         changes = self.changestatus()
         if changes:
-            self.ui.write('%s repo is unclean, please adjust\n' % section,
-                          label='confman.dirty')
+            self.ui.write(
+                '%s repo is unclean, please adjust\n' % section, label='confman.dirty'
+            )
         return changes
 
     def revsingle(self, rev, skiperror=False):

          
@@ 352,10 349,9 @@ class gitrepo(managedrepo):
     def changestatus(self):
         out = self._call('status', '--porcelain')
         stat = ''.join(
-            sorted(set(
-                [l.strip().split()[0].replace('??', 'M')
-                 for l in out.splitlines()]
-            ))
+            sorted(
+                set([l.strip().split()[0].replace('??', 'M') for l in out.splitlines()])
+            )
         )
         return stat
 

          
@@ 367,14 363,13 @@ class gitrepo(managedrepo):
 
 
 class hgrepo(managedrepo):
-    """ A mercurial repository """
+    """A mercurial repository"""
+
     __slots__ = ('conf', 'ui', 'repo')
 
     def __init__(self, conf, path):
         super(hgrepo, self).__init__(conf, path)
-        self.repo = WrappedRepo(
-            hg.repository(self.ui, path=path.encode('utf-8'))
-        )
+        self.repo = WrappedRepo(hg.repository(self.ui, path=path.encode('utf-8')))
 
     @property
     def root(self):

          
@@ 383,7 378,7 @@ class hgrepo(managedrepo):
 
     def revsingle(self, revexpr, skiperror=False):
         """Return the highest cset of the revset matching the given revision
-        expression """
+        expression"""
         try:
             cset = scmutil.revsingle(self.repo, revexpr.encode('utf-8'))
         except:

          
@@ 394,10 389,8 @@ class hgrepo(managedrepo):
 
     def changestatus(self):
         """Check `modified, added, removed, deleted`
-        ignore `unknown, ignored, clean` """
-        return ''.join(tag
-                       for tag, state in zip('MARD', self.repo.status())
-                       if state)
+        ignore `unknown, ignored, clean`"""
+        return ''.join(tag for tag, state in zip('MARD', self.repo.status()) if state)
 
     def isshared(self):
         """Check if the repository is a shared"""

          
@@ 409,10 402,11 @@ class hgrepo(managedrepo):
         If ``allow_p2`` is False (default) and the current context has
         2 parents (a.k.a. merge in progress) the process is aborted.
         """
-        cset = self.repo[None] # grab the current context
+        cset = self.repo[None]  # grab the current context
         if len(cset.parents()) > 1:
-            self.ui.write('has two parents (uncommitted merge)\n',
-                          label='confman.dirty')
+            self.ui.write(
+                'has two parents (uncommitted merge)\n', label='confman.dirty'
+            )
             if not allow_p2:
                 raise error.Abort(b'bailing out')
         return revisioncontext(cset)

          
@@ 424,7 418,7 @@ class hgrepo(managedrepo):
     def workingctx(self):
         """Return the working/current context context of a repository
         Will abort if there is more than one parent (it may mean an
-        ongoing merge for instance) """
+        ongoing merge for instance)"""
         return self.currentctx().parents[0]
 
     @classmethod

          
@@ 441,23 435,15 @@ class hgrepo(managedrepo):
                 conf.ui.warn('clone: using %r instead of %r\n' % (newsource, source))
                 source = newsource
             return commands.clone(
-                conf.ui,
-                source=source.encode('utf-8'),
-                dest=dest.encode('utf-8')
+                conf.ui, source=source.encode('utf-8'), dest=dest.encode('utf-8')
             )
         target = osp.join(sharepath, secconf['layout'])
         if not osp.exists(target):
             os.makedirs(target)
             commands.clone(
-                conf.ui,
-                source=source.encode('utf-8'),
-                dest=target.encode('utf-8')
+                conf.ui, source=source.encode('utf-8'), dest=target.encode('utf-8')
             )
-        return hg.share(
-            conf.ui,
-            target.encode('utf-8'),
-            dest.encode('utf-8')
-        )
+        return hg.share(conf.ui, target.encode('utf-8'), dest.encode('utf-8'))
 
     def pull_repo(self, section, conf):
         """Pull a managed repo from its configuration

          
@@ 469,15 455,17 @@ class hgrepo(managedrepo):
         pathuri = util.expandpath(pathname.encode('utf-8'))
         if pathuri == pathname.encode('utf-8'):
             pathuri = conf['pulluri'].encode('utf-8')
-            ui.warn('%s repo has no `%s` path, using configuration pulluri `%s` instead\n' %
-                    (section, pathname, pathuri.decode('utf-8')))
+            ui.warn(
+                '%s repo has no `%s` path, using configuration pulluri `%s` instead\n'
+                % (section, pathname, pathuri.decode('utf-8'))
+            )
 
         source, _branches = parseurl(pathuri, None)
         newsource = self.conf.rewriteuri(source)
         if newsource != source:
-            ui.warn('pull: using %r instead of %r\n' % (
-                newsource.decode('utf-8'),
-                source.decode('utf-8'))
+            ui.warn(
+                'pull: using %r instead of %r\n'
+                % (newsource.decode('utf-8'), source.decode('utf-8'))
             )
             source = newsource
 

          
@@ 487,9 475,11 @@ class hgrepo(managedrepo):
         except error.RepoError:
             pulluri = conf['pulluri']
             if pathuri == pulluri:
-                raise # we already tried
-            ui.warn('%s repo cannot be pulled from its local path, using pulluri %s\n' %
-                    (section, pulluri))
+                raise  # we already tried
+            ui.warn(
+                '%s repo cannot be pulled from its local path, using pulluri %s\n'
+                % (section, pulluri)
+            )
             source, _branches = parseurl(pulluri.encode(), None)
             other = hg.peer(self.repo.ui, self.conf.opts, source)
             hgpull(self.repo._repo, other)

          
@@ 500,8 490,10 @@ class hgrepo(managedrepo):
         pathuri = util.expandpath(pathname.encode('utf-8')).decode('utf-8')
         if pathuri == pathname:
             pathuri = conf['pulluri']
-            self.ui.warn('%s repo has no %s path, using configuration pulluri %s instead\n' %
-                         (section, pathname, pathuri))
+            self.ui.warn(
+                '%s repo has no %s path, using configuration pulluri %s instead\n'
+                % (section, pathname, pathuri)
+            )
         track = conf.get('track')
         self.ui.write('pushing %s to %s\n' % (track, pathuri))
         source, __branches = parseurl(pathuri.encode('utf-8'), None)

          
@@ 509,7 501,7 @@ class hgrepo(managedrepo):
         hgpush(self.repo, other, track.encode('utf-8'))
 
     def unknown_rev(self, rev):
-        """Predicate to check if a revision belongs to a repository """
+        """Predicate to check if a revision belongs to a repository"""
         try:
             self.revsingle(rev)
         except (error.RepoLookupError, error.LookupError, error.Abort):

          
@@ 517,7 509,7 @@ class hgrepo(managedrepo):
         return False
 
     def update(self, rev):
-        "Update the repository to `rev` "
+        "Update the repository to `rev`"
         commands.update(self.ui, self.repo, rev=rev.encode('utf-8'))
 
     def update_or_pull_and_update(self, section, conf, rev):

          
@@ 538,20 530,20 @@ class hgrepo(managedrepo):
         targetrev = targetctx.tag or targetctx.hex
         ui.write('updating to %s\n' % rev, label='confman.public-phase')
         self.update(rev)
-        ui.write('updated to %s/%s from %s/%s\n' %
-                 (targetrev,
-                  targetctx.branch,
-                  currev,
-                  wctx.branch),
-                 label='confman.updated')
+        ui.write(
+            'updated to %s/%s from %s/%s\n'
+            % (targetrev, targetctx.branch, currev, wctx.branch),
+            label='confman.updated',
+        )
         return True
 
     def check_dirty(self, section):
-        """Check and log the dirtyness of a repository """
+        """Check and log the dirtyness of a repository"""
         changes = self.repo[None].dirty(missing=True)
         if changes:
-            self.ui.write('%s repo is unclean, please adjust\n' % section,
-                          label='confman.dirty')
+            self.ui.write(
+                '%s repo is unclean, please adjust\n' % section, label='confman.dirty'
+            )
         return changes
 
     def archive(self, zippath, prefix, rev, **opts):

          
@@ 571,14 563,16 @@ class hgrepo(managedrepo):
             b'zip',
             not opts.get('no_decode'),
             matchfn,
-            prefix.encode('utf-8')
+            prefix.encode('utf-8'),
         )
         archival.archivers.update(archivers)
 
     def rewrite_conf(self, conf):
+        from collections import defaultdict
         from difflib import unified_diff
-        from collections import defaultdict
+
         from mercurial.config import config
+
         from .utils import _unflatten
 
         # build the nested hgrc entries ([section] key value, key value, ...)

          
@@ 603,7 597,7 @@ class hgrepo(managedrepo):
                 if newvalue is not None and newvalue != value:
                     updated[usection][ukey] = newvalue
                 entry.pop(ukey, None)
-            if not entries[usection]: # now empty
+            if not entries[usection]:  # now empty
                 entries.pop(usection)
         # at this point entries contains exclusively *new* entries
 

          
@@ 619,20 613,20 @@ class hgrepo(managedrepo):
                 for line in hgrc:
                     sline = line.strip()
 
-                    if sline.startswith('#'): # comment
+                    if sline.startswith('#'):  # comment
                         newhgrc.write(line)
                         continue
 
-                    if updated.get(section): # check updates
+                    if updated.get(section):  # check updates
                         parsed = sline.split('=')
                         if len(parsed) == 2:
                             key, val = parsed[0].strip(), parsed[1].strip()
                             newval = updated[section].get(key)
-                            if newval: # update
+                            if newval:  # update
                                 newhgrc.write('%s = %s\n' % (key, newval))
                                 continue
 
-                    if sline.startswith('['): # new section
+                    if sline.startswith('['):  # new section
                         # handle new entries while in the previous section
                         if entries.get(section):
                             for key, val in list(entries[section].items()):

          
@@ 652,8 646,11 @@ class hgrepo(managedrepo):
         # show changes
         with open(hgrcpath, 'r') as hgrc:
             with open(newhgrcpath, 'r') as newhgrc:
-                diff = tuple(unified_diff(hgrc.readlines(), newhgrc.readlines(),
-                                          hgrcpath, newhgrcpath))
+                diff = tuple(
+                    unified_diff(
+                        hgrc.readlines(), newhgrc.readlines(), hgrcpath, newhgrcpath
+                    )
+                )
         for line in diff:
             self.ui.write(line)
 

          
@@ 661,7 658,7 @@ class hgrepo(managedrepo):
             os.unlink(newhgrcpath)
             return ()
 
-        if os.name == 'nt': # atomic rename not a windows thing
+        if os.name == 'nt':  # atomic rename not a windows thing
             os.unlink(hgrcpath)
         os.rename(newhgrcpath, hgrcpath)
         return diff

          
@@ 678,19 675,21 @@ class hgrepo(managedrepo):
 class zipit(archival.zipit):
     """Write archive to zip file or stream. Can write uncompressed,
     or compressed with deflate."""
+
     def __init__(self, dest, mtime, compress=True):
         if not isinstance(dest, str):
             try:
                 dest.tell()
             except (AttributeError, IOError):
                 dest = archival.tellable(dest)
-        self.z = archival.zipfile.ZipFile(dest, 'a',
-                                          compress and archival.zipfile.ZIP_DEFLATED or
-                                          archival.zipfile.ZIP_STORED
+        self.z = archival.zipfile.ZipFile(
+            dest,
+            'a',
+            compress and archival.zipfile.ZIP_DEFLATED or archival.zipfile.ZIP_STORED,
         )
         # Python's zipfile module emits deprecation warnings if we try
         # to store files with a date before 1980.
-        epoch = 315532800 # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0))
+        epoch = 315532800  # calendar.timegm((1980, 1, 1, 0, 0, 0, 1, 1, 0))
         if mtime < epoch:
             mtime = epoch
         self.mtime = mtime

          
M hgext3rd/confman/meta.py +22 -26
@@ 2,29 2,25 @@ 
 CONFMANENTRIES = ('pulluri', 'layout', 'track')
 MANDATORY = ('pulluri', 'layout')
 
-colortable = {b'confman.nobaseline': b'cyan',
-              b'confman.branchaligned': b'magenta',
-              b'confman.tagaligned': b'green bold',
-              b'confman.csetaligned': b'magenta',
-              b'confman.revsetaligned': b'magenta',
-              b'confman.unaligned': b'red',
-
-              b'confman.nosnap': b'cyan underline',
-              b'confman.snapaligned': b'green bold',
-              b'confman.snapolder': b'yellow',
-              b'confman.snapnewer': b'yellow',
-              b'confman.snapparallel': b'yellow',
-              b'confman.snapunknown': b'red',
-
-              b'confman.draft-phase': b'magenta',
-              b'confman.secret-phase': b'red',
-              b'confman.public-phase': b'white',
-
-              b'confman.clean': b'green',
-              b'confman.dirty': b'red',
-              b'confman.section': b'green',
-
-              b'confman.updated': b'cyan',
-
-              b'confman.shared': b'blue'
-              }
+colortable = {
+    b'confman.nobaseline': b'cyan',
+    b'confman.branchaligned': b'magenta',
+    b'confman.tagaligned': b'green bold',
+    b'confman.csetaligned': b'magenta',
+    b'confman.revsetaligned': b'magenta',
+    b'confman.unaligned': b'red',
+    b'confman.nosnap': b'cyan underline',
+    b'confman.snapaligned': b'green bold',
+    b'confman.snapolder': b'yellow',
+    b'confman.snapnewer': b'yellow',
+    b'confman.snapparallel': b'yellow',
+    b'confman.snapunknown': b'red',
+    b'confman.draft-phase': b'magenta',
+    b'confman.secret-phase': b'red',
+    b'confman.public-phase': b'white',
+    b'confman.clean': b'green',
+    b'confman.dirty': b'red',
+    b'confman.section': b'green',
+    b'confman.updated': b'cyan',
+    b'confman.shared': b'blue',
+}

          
M hgext3rd/confman/opts.py +12 -4
@@ 1,9 1,17 @@ 
 INCLUDEOPT = ('I', 'include-conf', [], 'include configuration(s)')
 EXCLUDEOPT = ('X', 'exclude-conf', [], 'exclude configuration(s)')
-ROOTPATHOPT = ('', 'root-path', '',
-               'root path for the layouts (default to configuration root)')
-PULLURIOPT = ('p', 'use-hgrc-path', '',
-              'distant repository path name registered into hgrc.paths.*')
+ROOTPATHOPT = (
+    '',
+    'root-path',
+    '',
+    'root path for the layouts (default to configuration root)',
+)
+PULLURIOPT = (
+    'p',
+    'use-hgrc-path',
+    '',
+    'distant repository path name registered into hgrc.paths.*',
+)
 URIMAPOPT = ('', 'uri-map-file', '', 'specify uri map file')
 HTTPSOPT = ('', 'insecure', False, 'work around self bad certificates')
 HGGITOPT = ('', 'hggit', None, 'git: operate with hg-git')

          
M hgext3rd/confman/utils.py +100 -87
@@ 1,17 1,20 @@ 
 "This module contains useful stuff to play with repository specs"
 
-import os
-import errno
 import codecs
-from collections import defaultdict
-import urllib.request, urllib.parse, urllib.error
 import contextlib
+import errno
+import os
+import urllib.error
+import urllib.parse
+import urllib.request
+from collections import defaultdict
 
-from mercurial import util, hg, error
-from mercurial.config import config, _
+from mercurial import error, hg, util
+from mercurial.config import _, config
+
 from .hgcompat import compilere
+from .meta import CONFMANENTRIES
 
-from .meta import CONFMANENTRIES
 
 def ending(line):
     "Return the newline character(s) of the line."

          
@@ 22,15 25,16 @@ def ending(line):
     else:
         return '\n'
 
+
 # configuration handling
 
+
 def _compilere(pattern):
     "Compile regexp (pattern + '$')"
     return compilere(pattern + '$')
 
 
 class WrappedRepo:
-
     def __init__(self, repo):
         if isinstance(repo, WrappedRepo):
             repo = repo._repo

          
@@ 52,7 56,6 @@ class WrappedRepo:
 
 
 class WrappedUI:
-
     def __init__(self, ui):
         if isinstance(ui, WrappedUI):
             ui = ui._ui

          
@@ 62,43 65,25 @@ class WrappedUI:
         if label:
             label = label.encode('utf-8')
         return meth(
-            *(elt.encode('utf-8')
-              if isinstance(elt, str) else elt
-              for elt in a),
+            *(elt.encode('utf-8') if isinstance(elt, str) else elt for elt in a),
             label=label,
             **k
         )
 
     def write(self, *a, label=b'', **k):
-        return self._output(
-            self._ui.write,
-            *a, label=label, **k
-        )
+        return self._output(self._ui.write, *a, label=label, **k)
 
     def status(self, *a, label=b'', **k):
-        return self._output(
-            self._ui.status,
-            *a, label=label, **k
-        )
+        return self._output(self._ui.status, *a, label=label, **k)
 
     def warn(self, *a, label=b'', **k):
-        return self._output(
-            self._ui.warn,
-            *a, label=label, **k
-        )
+        return self._output(self._ui.warn, *a, label=label, **k)
 
     def error(self, *a, label=b'', **k):
-        return self._output(
-            self._ui.error,
-            *a, label=label, **k
-        )
+        return self._output(self._ui.error, *a, label=label, **k)
 
     def configpath(self, *args, **kw):
-        args = (
-            elt.encode('utf-8')
-            if isinstance(elt, str) else elt
-            for elt in args
-        )
+        args = (elt.encode('utf-8') if isinstance(elt, str) else elt for elt in args)
         path = self._ui.configpath(*args, **kw)
         if path is not None:
             return path.decode('utf-8')

          
@@ 132,20 117,24 @@ class sectionfilter(object):
             self.whitelist = parent.whitelist
             self.blacklist = parent.blacklist
         if regexp:
-            self.rewhitelist = (self.rewhitelist +
-                                tuple(_compilere(exp) for exp in morewhite))
-            self.reblacklist = (self.reblacklist +
-                                tuple(_compilere(exp) for exp in moreblack))
+            self.rewhitelist = self.rewhitelist + tuple(
+                _compilere(exp) for exp in morewhite
+            )
+            self.reblacklist = self.reblacklist + tuple(
+                _compilere(exp) for exp in moreblack
+            )
         else:
             self.whitelist = self.whitelist + morewhite
             self.blacklist = self.blacklist + moreblack
 
     def __call__(self, section):
-        if (section in self.blacklist or
-            any(re.match(section) for re in self.reblacklist)):
+        if section in self.blacklist or any(
+            re.match(section) for re in self.reblacklist
+        ):
             return False
-        if ((self.whitelist and section not in self.whitelist) or
-            (self.rewhitelist and not any(re.match(section) for re in self.rewhitelist))):
+        if (self.whitelist and section not in self.whitelist) or (
+            self.rewhitelist and not any(re.match(section) for re in self.rewhitelist)
+        ):
             return False
         return True
 

          
@@ 202,9 191,17 @@ class oconfig(object):
                     hgrc.write('%s = %s\n' % (k, v))
                 hgrc.write('\n')
 
-    def parse(self, src, data, sections=None, remap=None, include=None,
-              # PATCH: level and filtering
-              level=0, section_filter=None):
+    def parse(
+        self,
+        src,
+        data,
+        sections=None,
+        remap=None,
+        include=None,
+        # PATCH: level and filtering
+        level=0,
+        section_filter=None,
+    ):
         sectionre = compilere(r'\[([^\[]+)\]')
         itemre = compilere(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
         # PATCH

          
@@ 250,9 247,10 @@ class oconfig(object):
                         include(inc, remap=remap, sections=sections)
                     except IOError as inst:
                         if inst.errno != errno.ENOENT:
-                            raise error.ParseError(_("cannot include %s (%s)")
-                                                   % (inc, inst.strerror),
-                                                   "%s:%s" % (src, line))
+                            raise error.ParseError(
+                                _("cannot include %s (%s)") % (inc, inst.strerror),
+                                "%s:%s" % (src, line),
+                            )
                 continue
             if emptyre.match(l):
                 continue

          
@@ 288,19 286,27 @@ class oconfig(object):
                         morewhite = tuple(m.group(4).split())
                     elif m.group(2) == '.blacklist':
                         moreblack += tuple(m.group(4).split())
-                    _section_filter = sectionfilter(regexp=bool(m.group(3)),
-                                                    parent=section_filter,
-                                                    morewhite=morewhite,
-                                                    moreblack=moreblack)
+                    _section_filter = sectionfilter(
+                        regexp=bool(m.group(3)),
+                        parent=section_filter,
+                        morewhite=morewhite,
+                        moreblack=moreblack,
+                    )
 
                     try:
-                        include(inc, remap=remap, sections=sections, level=level+1,
-                                section_filter=_section_filter)
+                        include(
+                            inc,
+                            remap=remap,
+                            sections=sections,
+                            level=level + 1,
+                            section_filter=_section_filter,
+                        )
                     except IOError as inst:
                         if inst.errno != errno.ENOENT:
-                            raise error.ParseError(_("cannot expand %s (%s)")
-                                                   % (inc, inst.strerror),
-                                                   "%s:%s" % (src, line))
+                            raise error.ParseError(
+                                _("cannot expand %s (%s)") % (inc, inst.strerror),
+                                "%s:%s" % (src, line),
+                            )
                 continue
             # /PATCH
             m = itemre.match(l)

          
@@ 322,8 328,7 @@ class oconfig(object):
                 continue
 
             raise error.ParseError(
-                l.rstrip().encode('utf-8'),
-                ("%s:%s" % (src, line)).encode('utf-8')
+                l.rstrip().encode('utf-8'), ("%s:%s" % (src, line)).encode('utf-8')
             )
 
     def parse_guestrepo(self, dirpath, level=0, section_filter=None):

          
@@ 341,7 346,7 @@ class oconfig(object):
                 self.set(
                     section.decode('utf-8'),
                     'pulluri',
-                    mappingconf[b''][section][0].decode('utf-8')
+                    mappingconf[b''][section][0].decode('utf-8'),
                 )
                 self.confman.sectionlevels[section.decode('utf-8')].add(level)
         guestpath = os.path.join(dirpath, '.hgguestrepo')

          
@@ 350,16 355,8 @@ class oconfig(object):
         for layout in guestconf[b'']:
             section, cset = guestconf[b''][layout][0].split(None, 1)
             if section_filter(section):
-                self.set(
-                    section.decode('utf-8'),
-                    'layout',
-                    layout.decode('utf-8')
-                )
-                self.set(
-                    section.decode('utf-8'),
-                    'track',
-                    cset.decode('utf-8')
-                )
+                self.set(section.decode('utf-8'), 'layout', layout.decode('utf-8'))
+                self.set(section.decode('utf-8'), 'track', cset.decode('utf-8'))
 
     def read(self, path, fp=None, sections=None, remap=None, **kwargs):
         if os.path.exists(path):

          
@@ 377,9 374,10 @@ def upwarditer(path):
     while path:
         yield path
         path = os.path.dirname(path)
-        if path in ('', '/'): # root, depending on linux/win32
+        if path in ('', '/'):  # root, depending on linux/win32
             return
 
+
 def findrootpath(ui, conffilename, startpath):
     "Find `conffilename` by changing directories upward"
     for iterations, repourl in enumerate(upwarditer(startpath)):

          
@@ 387,8 385,10 @@ def findrootpath(ui, conffilename, start
         if os.path.exists(confpath):
             if iterations:
                 if not ui.quiet:
-                    ui.write('found configuration repo at %s\n' % repourl,
-                             label='confman.updated')
+                    ui.write(
+                        'found configuration repo at %s\n' % repourl,
+                        label='confman.updated',
+                    )
             yield repourl
             raise StopIteration
         else:

          
@@ 401,8 401,11 @@ def readconf(ui, repo, args, opts):
     # prevent cyclic imports
     from . import gr
     from .configuration import configurationmanager
-    for cmrootpath, grrootpath in zip(findrootpath(ui, '.hgconf', repo.root),
-                                      findrootpath(ui, '.hgguestrepo', repo.root)):
+
+    for cmrootpath, grrootpath in zip(
+        findrootpath(ui, '.hgconf', repo.root),
+        findrootpath(ui, '.hgguestrepo', repo.root),
+    ):
         if cmrootpath:
             confman = configurationmanager(ui, cmrootpath, args, opts)
             break

          
@@ 411,16 414,15 @@ def readconf(ui, repo, args, opts):
             break
     else:
         raise error.Abort(
-            b'cannot find an .hgconf file in the path and '
-            b'parents up to the root',
-            hint=b'see hg help confman'
+            b'cannot find an .hgconf file in the path and ' b'parents up to the root',
+            hint=b'see hg help confman',
         )
-    return confman, WrappedRepo(
-        hg.repository(ui, confman.rootpath.encode('utf-8'))
-    )
+    return confman, WrappedRepo(hg.repository(ui, confman.rootpath.encode('utf-8')))
+
 
 # dictionnaries operations
 
+
 def _unflatten(flattened, skipkeys=CONFMANENTRIES, failed=None):
     """Build nested dictionaries from a flattened one, e.g
     hgrc.path.default-push -> {'hgrc': {'path': {'defaul-push': ...}}}

          
@@ 439,8 441,10 @@ def _unflatten(flattened, skipkeys=CONFM
         nested[toplevel][newsection][newkey] = value
     return nested
 
+
 # download utility
 
+
 @contextlib.contextmanager
 def download_file(source):
     """Download file at ``source``. This function manage file:// scheme"""

          
@@ 449,7 453,10 @@ def download_file(source):
         with open(os.path.join(*source[7:].split('/')), 'rb') as fp:
             yield fp
     else:
-        import requests, tempfile
+        import tempfile
+
+        import requests
+
         req = requests.get(source, stream=True)
         with tempfile.TemporaryFile() as fp:
             for chunk in req.iter_content(chunk_size=4096):

          
@@ 461,22 468,28 @@ def download_file(source):
 
 # register encoding error handlers
 
+
 def _treegraph_unicode_encode_handler(error):
     """Unicode error handler for tree graph characters. Shall be given to
     codecs.register_error."""
-    obj = error.object[error.start:error.end + 1]
-    obj = obj.replace('\N{BOX DRAWINGS LIGHT VERTICAL}', '|') # │
-    obj = obj.replace('\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}', '|') # ├
-    obj = obj.replace('\N{BOX DRAWINGS LIGHT UP AND RIGHT}', '`') # └
-    obj = obj.replace('\N{RIGHTWARDS ARROW}', '-') # →
+    obj = error.object[error.start : error.end + 1]
+    obj = obj.replace('\N{BOX DRAWINGS LIGHT VERTICAL}', '|')  # │
+    obj = obj.replace('\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}', '|')  # ├
+    obj = obj.replace('\N{BOX DRAWINGS LIGHT UP AND RIGHT}', '`')  # └
+    obj = obj.replace('\N{RIGHTWARDS ARROW}', '-')  # →
     return obj, error.end + 1
+
+
 codecs.register_error('treegraph', _treegraph_unicode_encode_handler)
 
 # a 'confman' encoding error handler
 
+
 def _confman_unicode_encode_handler(error):
-    obj = error.object[error.start:error.end + 1]
+    obj = error.object[error.start : error.end + 1]
     obj = obj.replace('\N{CHECK MARK}', 'ok')
     obj = obj.replace('\N{MARRIAGE SYMBOL}', '[shared]')
     return obj, error.end
+
+
 codecs.register_error('confman', _confman_unicode_encode_handler)

          
A => pyproject.toml +6 -0
@@ 0,0 1,6 @@ 
+[tool.isort]
+profile = "black"
+
+[tool.black]
+skip-string-normalization = true
+extend-exclude = "run-tests.py"

          
M setup.py +2 -3
@@ 7,7 7,6 @@ setup(
     url='https://hg.sr.ht/~auc/confman',
     author=u'Aurélien Campéas',
     author_email='aurelien.campeas@pythonian.fr',
-
     license='GPLv2+',
     keywords='hg mercurial',
     packages=['hgext3rd', 'hgext3rd.confman'],

          
@@ 19,6 18,6 @@ setup(
         'Operating System :: OS Independent',
         'Programming Language :: Python :: 3',
         'Topic :: Software Development :: Version Control',
-        'Topic :: Software Development :: Version Control :: Mercurial'
-    ]
+        'Topic :: Software Development :: Version Control :: Mercurial',
+    ],
 )