mercurial/extensions.py
changeset 43076 2372284d9457
parent 42547 6a3872e34503
child 43077 687b865b95ad
--- a/mercurial/extensions.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/extensions.py	Sun Oct 06 09:45:02 2019 -0400
@@ -27,9 +27,7 @@
     util,
 )
 
-from .utils import (
-    stringutil,
-)
+from .utils import stringutil
 
 _extensions = {}
 _disabledextensions = {}
@@ -47,13 +45,16 @@
     'shelve',
 }
 
+
 def extensions(ui=None):
     if ui:
+
         def enabled(name):
             for format in ['%s', 'hgext.%s']:
                 conf = ui.config('extensions', format % name)
                 if conf is not None and not conf.startswith('!'):
                     return True
+
     else:
         enabled = lambda name: True
     for name in _order:
@@ -61,6 +62,7 @@
         if module and enabled(name):
             yield name, module
 
+
 def find(name):
     '''return module with given extension name'''
     mod = None
@@ -75,6 +77,7 @@
         raise KeyError(name)
     return mod
 
+
 def loadpath(path, module_name):
     module_name = module_name.replace('.', '_')
     path = util.normpath(util.expandpath(path))
@@ -90,9 +93,10 @@
             return imp.load_source(module_name, path)
         except IOError as exc:
             if not exc.filename:
-                exc.filename = path # python does not fill this
+                exc.filename = path  # python does not fill this
             raise
 
+
 def _importh(name):
     """import and return the <name> module"""
     mod = __import__(pycompat.sysstr(name))
@@ -101,6 +105,7 @@
         mod = getattr(mod, comp)
     return mod
 
+
 def _importext(name, path=None, reportfunc=None):
     if path:
         # the module will be loaded in sys.modules
@@ -121,14 +126,21 @@
                 mod = _importh(name)
     return mod
 
+
 def _reportimporterror(ui, err, failed, next):
     # note: this ui.log happens before --debug is processed,
     #       Use --config ui.debug=1 to see them.
-    ui.log(b'extension', b'    - could not import %s (%s): trying %s\n',
-           failed, stringutil.forcebytestr(err), next)
+    ui.log(
+        b'extension',
+        b'    - could not import %s (%s): trying %s\n',
+        failed,
+        stringutil.forcebytestr(err),
+        next,
+    )
     if ui.debugflag and ui.configbool('devel', 'debug.extensions'):
         ui.traceback()
 
+
 def _rejectunicode(name, xs):
     if isinstance(xs, (list, set, tuple)):
         for x in xs:
@@ -138,12 +150,16 @@
             _rejectunicode(name, k)
             _rejectunicode(b'%s.%s' % (name, stringutil.forcebytestr(k)), v)
     elif isinstance(xs, type(u'')):
-        raise error.ProgrammingError(b"unicode %r found in %s" % (xs, name),
-                                     hint="use b'' to make it byte string")
+        raise error.ProgrammingError(
+            b"unicode %r found in %s" % (xs, name),
+            hint="use b'' to make it byte string",
+        )
+
 
 # attributes set by registrar.command
 _cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo')
 
+
 def _validatecmdtable(ui, cmdtable):
     """Check if extension commands have required attributes"""
     for c, e in cmdtable.iteritems():
@@ -153,19 +169,28 @@
             continue
         raise error.ProgrammingError(
             'missing attributes: %s' % ', '.join(missing),
-            hint="use @command decorator to register '%s'" % c)
+            hint="use @command decorator to register '%s'" % c,
+        )
+
 
 def _validatetables(ui, mod):
     """Sanity check for loadable tables provided by extension module"""
     for t in ['cmdtable', 'colortable', 'configtable']:
         _rejectunicode(t, getattr(mod, t, {}))
-    for t in ['filesetpredicate', 'internalmerge', 'revsetpredicate',
-              'templatefilter', 'templatefunc', 'templatekeyword']:
+    for t in [
+        'filesetpredicate',
+        'internalmerge',
+        'revsetpredicate',
+        'templatefilter',
+        'templatefunc',
+        'templatekeyword',
+    ]:
         o = getattr(mod, t, None)
         if o:
             _rejectunicode(t, o._table)
     _validatecmdtable(ui, getattr(mod, 'cmdtable', {}))
 
+
 def load(ui, name, path, loadingtime=None):
     if name.startswith('hgext.') or name.startswith('hgext/'):
         shortname = name[6:]
@@ -189,8 +214,10 @@
     # of Mercurial.
     minver = getattr(mod, 'minimumhgversion', None)
     if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
-        msg = _('(third party extension %s requires version %s or newer '
-                'of Mercurial (current: %s); disabling)\n')
+        msg = _(
+            '(third party extension %s requires version %s or newer '
+            'of Mercurial (current: %s); disabling)\n'
+        )
         ui.warn(msg % (shortname, minver, util.version()))
         return
     ui.log(b'extension', b'    - validating extension tables: %s\n', shortname)
@@ -198,14 +225,16 @@
 
     _extensions[shortname] = mod
     _order.append(shortname)
-    ui.log(b'extension', b'    - invoking registered callbacks: %s\n',
-           shortname)
+    ui.log(
+        b'extension', b'    - invoking registered callbacks: %s\n', shortname
+    )
     with util.timedcm('callbacks extension %s', shortname) as stats:
         for fn in _aftercallbacks.get(shortname, []):
             fn(loaded=True)
     ui.log(b'extension', b'    > callbacks completed in %s\n', stats)
     return mod
 
+
 def _runuisetup(name, ui):
     uisetup = getattr(_extensions[name], 'uisetup', None)
     if uisetup:
@@ -218,6 +247,7 @@
             return False
     return True
 
+
 def _runextsetup(name, ui):
     extsetup = getattr(_extensions[name], 'extsetup', None)
     if extsetup:
@@ -230,22 +260,29 @@
             return False
     return True
 
+
 def loadall(ui, whitelist=None):
     loadingtime = collections.defaultdict(int)
     result = ui.configitems("extensions")
     if whitelist is not None:
         result = [(k, v) for (k, v) in result if k in whitelist]
     newindex = len(_order)
-    ui.log(b'extension', b'loading %sextensions\n',
-           'additional ' if newindex else '')
+    ui.log(
+        b'extension',
+        b'loading %sextensions\n',
+        'additional ' if newindex else '',
+    )
     ui.log(b'extension', b'- processing %d entries\n', len(result))
     with util.timedcm('load all extensions') as stats:
         for (name, path) in result:
             if path:
                 if path[0:1] == '!':
                     if name not in _disabledextensions:
-                        ui.log(b'extension',
-                               b'  - skipping disabled extension: %s\n', name)
+                        ui.log(
+                            b'extension',
+                            b'  - skipping disabled extension: %s\n',
+                            name,
+                        )
                     _disabledextensions[name] = path[1:]
                     continue
             try:
@@ -253,17 +290,25 @@
             except Exception as inst:
                 msg = stringutil.forcebytestr(inst)
                 if path:
-                    ui.warn(_("*** failed to import extension %s from %s: %s\n")
-                            % (name, path, msg))
+                    ui.warn(
+                        _("*** failed to import extension %s from %s: %s\n")
+                        % (name, path, msg)
+                    )
                 else:
-                    ui.warn(_("*** failed to import extension %s: %s\n")
-                            % (name, msg))
+                    ui.warn(
+                        _("*** failed to import extension %s: %s\n")
+                        % (name, msg)
+                    )
                 if isinstance(inst, error.Hint) and inst.hint:
                     ui.warn(_("*** (%s)\n") % inst.hint)
                 ui.traceback()
 
-    ui.log(b'extension', b'> loaded %d extensions, total time %s\n',
-           len(_order) - newindex, stats)
+    ui.log(
+        b'extension',
+        b'> loaded %d extensions, total time %s\n',
+        len(_order) - newindex,
+        stats,
+    )
     # list of (objname, loadermod, loadername) tuple:
     # - objname is the name of an object in extension module,
     #   from which extra information is loaded
@@ -286,8 +331,11 @@
             ui.log(b'extension', b'  - running uisetup for %s\n', name)
             with util.timedcm('uisetup %s', name) as stats:
                 if not _runuisetup(name, ui):
-                    ui.log(b'extension',
-                           b'    - the %s extension uisetup failed\n', name)
+                    ui.log(
+                        b'extension',
+                        b'    - the %s extension uisetup failed\n',
+                        name,
+                    )
                     broken.add(name)
             ui.log(b'extension', b'  > uisetup for %s took %s\n', name, stats)
             loadingtime[name] += stats.elapsed
@@ -301,8 +349,11 @@
             ui.log(b'extension', b'  - running extsetup for %s\n', name)
             with util.timedcm('extsetup %s', name) as stats:
                 if not _runextsetup(name, ui):
-                    ui.log(b'extension',
-                           b'    - the %s extension extsetup failed\n', name)
+                    ui.log(
+                        b'extension',
+                        b'    - the %s extension extsetup failed\n',
+                        name,
+                    )
                     broken.add(name)
             ui.log(b'extension', b'  > extsetup for %s took %s\n', name, stats)
             loadingtime[name] += stats.elapsed
@@ -320,9 +371,11 @@
                 continue
 
             for fn in _aftercallbacks[shortname]:
-                ui.log(b'extension',
-                       b'  - extension %s not loaded, notify callbacks\n',
-                       shortname)
+                ui.log(
+                    b'extension',
+                    b'  - extension %s not loaded, notify callbacks\n',
+                    shortname,
+                )
                 fn(loaded=False)
     ui.log(b'extension', b'> remaining aftercallbacks completed in %s\n', stats)
 
@@ -361,27 +414,36 @@
     ]
     with util.timedcm('load registration objects') as stats:
         _loadextra(ui, newindex, extraloaders)
-    ui.log(b'extension', b'> extension registration object loading took %s\n',
-           stats)
+    ui.log(
+        b'extension',
+        b'> extension registration object loading took %s\n',
+        stats,
+    )
 
     # Report per extension loading time (except reposetup)
     for name in sorted(loadingtime):
-        ui.log(b'extension', b'> extension %s take a total of %s to load\n',
-               name, util.timecount(loadingtime[name]))
+        ui.log(
+            b'extension',
+            b'> extension %s take a total of %s to load\n',
+            name,
+            util.timecount(loadingtime[name]),
+        )
 
     ui.log(b'extension', b'extension loading complete\n')
 
+
 def _loadextra(ui, newindex, extraloaders):
     for name in _order[newindex:]:
         module = _extensions[name]
         if not module:
-            continue # loading this module failed
+            continue  # loading this module failed
 
         for objname, loadermod, loadername in extraloaders:
             extraobj = getattr(module, objname, None)
             if extraobj is not None:
                 getattr(loadermod, loadername)(ui, name, extraobj)
 
+
 def afterloaded(extension, callback):
     '''Run the specified function after a named extension is loaded.
 
@@ -397,11 +459,12 @@
 
     if extension in _extensions:
         # Report loaded as False if the extension is disabled
-        loaded = (_extensions[extension] is not None)
+        loaded = _extensions[extension] is not None
         callback(loaded=loaded)
     else:
         _aftercallbacks.setdefault(extension, []).append(callback)
 
+
 def populateui(ui):
     """Run extension hooks on the given ui to populate additional members,
     extend the class dynamically, etc.
@@ -418,8 +481,11 @@
             hook(ui)
         except Exception as inst:
             ui.traceback(force=True)
-            ui.warn(_('*** failed to populate ui by extension %s: %s\n')
-                    % (name, stringutil.forcebytestr(inst)))
+            ui.warn(
+                _('*** failed to populate ui by extension %s: %s\n')
+                % (name, stringutil.forcebytestr(inst))
+            )
+
 
 def bind(func, *args):
     '''Partial function application
@@ -429,10 +495,13 @@
 
           f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
     assert callable(func)
+
     def closure(*a, **kw):
         return func(*(args + a), **kw)
+
     return closure
 
+
 def _updatewrapper(wrap, origfn, unboundwrapper):
     '''Copy and add some useful attributes to wrapper'''
     try:
@@ -445,6 +514,7 @@
     wrap._origfunc = origfn
     wrap._unboundwrapper = unboundwrapper
 
+
 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
     '''Wrap the command named `command' in table
 
@@ -482,8 +552,9 @@
             break
 
     origfn = entry[0]
-    wrap = functools.partial(util.checksignature(wrapper),
-                             util.checksignature(origfn))
+    wrap = functools.partial(
+        util.checksignature(wrapper), util.checksignature(origfn)
+    )
     _updatewrapper(wrap, origfn, wrapper)
     if docstring is not None:
         wrap.__doc__ += docstring
@@ -495,6 +566,7 @@
     table[key] = tuple(newentry)
     return entry
 
+
 def wrapfilecache(cls, propname, wrapper):
     """Wraps a filecache property.
 
@@ -506,14 +578,18 @@
         if propname in currcls.__dict__:
             origfn = currcls.__dict__[propname].func
             assert callable(origfn)
+
             def wrap(*args, **kwargs):
                 return wrapper(origfn, *args, **kwargs)
+
             currcls.__dict__[propname].func = wrap
             break
 
     if currcls is object:
-        raise AttributeError(r"type '%s' has no property '%s'" % (
-            cls, propname))
+        raise AttributeError(
+            r"type '%s' has no property '%s'" % (cls, propname)
+        )
+
 
 class wrappedfunction(object):
     '''context manager for temporarily wrapping a function'''
@@ -530,6 +606,7 @@
     def __exit__(self, exctype, excvalue, traceback):
         unwrapfunction(self._container, self._funcname, self._wrapper)
 
+
 def wrapfunction(container, funcname, wrapper):
     '''Wrap the function named funcname in container
 
@@ -579,6 +656,7 @@
     setattr(container, funcname, wrap)
     return origfn
 
+
 def unwrapfunction(container, funcname, wrapper=None):
     '''undo wrapfunction
 
@@ -599,6 +677,7 @@
         wrapfunction(container, funcname, w)
     return wrapper
 
+
 def getwrapperchain(container, funcname):
     '''get a chain of wrappers of a function
 
@@ -615,12 +694,15 @@
         fn = getattr(fn, '_origfunc', None)
     return result
 
+
 def _disabledpaths():
     '''find paths of disabled extensions. returns a dict of {name: path}'''
     import hgext
+
     extpath = os.path.dirname(
-        os.path.abspath(pycompat.fsencode(hgext.__file__)))
-    try: # might not be a filesystem path
+        os.path.abspath(pycompat.fsencode(hgext.__file__))
+    )
+    try:  # might not be a filesystem path
         files = os.listdir(extpath)
     except OSError:
         return {}
@@ -645,6 +727,7 @@
             exts[name] = path
     return exts
 
+
 def _moduledoc(file):
     '''return the top-level python documentation for the given file
 
@@ -669,7 +752,7 @@
                     result.append(line)
                 break
             elif not line:
-                return None # unmatched delimiter
+                return None  # unmatched delimiter
             result.append(line)
             line = file.readline()
     else:
@@ -677,6 +760,7 @@
 
     return ''.join(result)
 
+
 def _disabledhelp(path):
     '''retrieve help synopsis of a disabled extension (without importing)'''
     try:
@@ -685,18 +769,22 @@
     except IOError:
         return
 
-    if doc: # extracting localized synopsis
+    if doc:  # extracting localized synopsis
         return gettext(doc)
     else:
         return _('(no help text available)')
 
+
 def disabled():
     '''find disabled extensions from hgext. returns a dict of {name: desc}'''
     try:
         from hgext import __index__
-        return dict((name, gettext(desc))
-                    for name, desc in __index__.docs.iteritems()
-                    if name not in _order)
+
+        return dict(
+            (name, gettext(desc))
+            for name, desc in __index__.docs.iteritems()
+            if name not in _order
+        )
     except (ImportError, AttributeError):
         pass
 
@@ -712,10 +800,12 @@
 
     return exts
 
+
 def disabledext(name):
     '''find a specific disabled extension from hgext. returns desc'''
     try:
         from hgext import __index__
+
         if name in _order:  # enabled
             return
         else:
@@ -727,6 +817,7 @@
     if name in paths:
         return _disabledhelp(paths[name])
 
+
 def _walkcommand(node):
     """Scan @command() decorators in the tree starting at node"""
     todo = collections.deque([node])
@@ -744,6 +835,7 @@
                 continue
             yield d
 
+
 def _disabledcmdtable(path):
     """Construct a dummy command table without loading the extension module
 
@@ -765,6 +857,7 @@
         cmdtable[name] = (None, [], b'')
     return cmdtable
 
+
 def _finddisabledcmd(ui, cmd, name, path, strict):
     try:
         cmdtable = _disabledcmdtable(path)
@@ -783,6 +876,7 @@
     doc = _disabledhelp(path)
     return (cmd, name, doc)
 
+
 def disabledcmd(ui, cmd, strict=False):
     '''find cmd from disabled extensions without importing.
     returns (cmdname, extname, doc)'''
@@ -807,25 +901,27 @@
 
     raise error.UnknownCommand(cmd)
 
+
 def enabled(shortname=True):
     '''return a dict of {name: desc} of extensions'''
     exts = {}
     for ename, ext in extensions():
-        doc = (gettext(ext.__doc__) or _('(no help text available)'))
+        doc = gettext(ext.__doc__) or _('(no help text available)')
         if shortname:
             ename = ename.split('.')[-1]
         exts[ename] = doc.splitlines()[0].strip()
 
     return exts
 
+
 def notloaded():
     '''return short names of extensions that failed to load'''
     return [name for name, mod in _extensions.iteritems() if mod is None]
 
+
 def moduleversion(module):
     '''return version information from given module as a string'''
-    if (util.safehasattr(module, 'getversion')
-          and callable(module.getversion)):
+    if util.safehasattr(module, 'getversion') and callable(module.getversion):
         version = module.getversion()
     elif util.safehasattr(module, '__version__'):
         version = module.__version__
@@ -835,6 +931,7 @@
         version = '.'.join(pycompat.bytestr(o) for o in version)
     return version
 
+
 def ismoduleinternal(module):
     exttestedwith = getattr(module, 'testedwith', None)
     return exttestedwith == "ships-with-hg-core"