durin42 updated this revision to Diff 16867. REPOSITORY rHG Mercurial
CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D6342?vs=16829&id=16867 CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D6342/new/ REVISION DETAIL https://phab.mercurial-scm.org/D6342 AFFECTED FILES contrib/examples/fix.hgrc 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 CHANGE DETAILS diff --git a/mercurial/stack.py b/mercurial/stack.py --- a/mercurial/stack.py +++ b/mercurial/stack.py @@ -7,6 +7,7 @@ from __future__ import absolute_import + 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. diff --git a/mercurial/scmwindows.py b/mercurial/scmwindows.py --- a/mercurial/scmwindows.py +++ b/mercurial/scmwindows.py @@ -11,6 +11,7 @@ try: import _winreg as winreg + winreg.CloseKey except ImportError: import winreg @@ -18,6 +19,7 @@ # MS-DOS 'more' is the only pager available by default on Windows. fallbackpager = 'more' + def systemrcpath(): '''return default os-specific hgrc search path''' rcpath = [] @@ -32,8 +34,9 @@ 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) @@ -46,16 +49,17 @@ 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')] + 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')) 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 @@ -18,17 +18,23 @@ # 'less' as the default seems reasonable. fallbackpager = 'less' + def _rcfiles(path): 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': @@ -43,6 +49,7 @@ path.extend(_rcfiles('/' + root)) return path + def userrcpath(): if pycompat.sysplatform == 'plan9': return [encoding.environ['home'] + '/lib/hgrc'] @@ -53,12 +60,16 @@ if confighome is None or not os.path.isabs(confighome): 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 diff --git a/mercurial/rewriteutil.py b/mercurial/rewriteutil.py --- a/mercurial/rewriteutil.py +++ b/mercurial/rewriteutil.py @@ -16,6 +16,7 @@ revset, ) + def precheck(repo, revs, action='rewrite'): """check if revs can be rewritten action is used to control the error message. @@ -23,7 +24,7 @@ Make sure this function is called after taking the lock. """ if node.nullrev in revs: - msg = _("cannot %s null changeset") % (action) + msg = _("cannot %s null changeset") % action hint = _("no changeset checked out") raise error.Abort(msg, hint=hint) @@ -32,7 +33,7 @@ publicrevs = repo.revs('%ld and public()', revs) if publicrevs: - msg = _("cannot %s public changesets") % (action) + msg = _("cannot %s public changesets") % action hint = _("see 'hg help phases' for details") raise error.Abort(msg, hint=hint) @@ -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,15 +24,18 @@ systemrcpath = scmplatform.systemrcpath userrcpath = scmplatform.userrcpath + def _expandrcpath(path): '''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. @@ -55,6 +58,7 @@ result.append((section, configname, env[envname], '$%s' % envname)) return result + def defaultrcpath(): '''return rc paths in default.d''' path = [] @@ -63,6 +67,7 @@ path = _expandrcpath(defaultpath) return path + def rccomponents(): '''return an ordered [(type, obj)] about where to load configs. @@ -92,6 +97,7 @@ _rccomponents.extend(normpaths(userrcpath())) return _rccomponents + def defaultpagerenv(): '''return a dict of default environment variables and their values, intended to be set before starting a pager. diff --git a/mercurial/pushkey.py b/mercurial/pushkey.py --- a/mercurial/pushkey.py +++ b/mercurial/pushkey.py @@ -14,6 +14,7 @@ phases, ) + def _nslist(repo): n = {} for k in _namespaces: @@ -22,36 +23,45 @@ 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''' pk = _get(namespace)[0] return pk(repo, key, old, new) + def list(repo, namespace): '''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]) + def decodekeys(data): """decode the content of a pushkey namespace from exchange over the wire""" result = {} diff --git a/mercurial/policy.py b/mercurial/policy.py --- a/mercurial/policy.py +++ b/mercurial/policy.py @@ -39,6 +39,7 @@ try: from . import __modulepolicy__ + policy = __modulepolicy__.modulepolicy except ImportError: pass @@ -57,6 +58,7 @@ else: policy = os.environ.get(r'HGMODULEPOLICY', policy) + def _importfrom(pkgname, modname): # from .<pkgname> import <modname> (where . is looked through this module) fakelocals = {} @@ -69,6 +71,7 @@ getattr(mod, r'__doc__', None) return fakelocals[modname] + # keep in sync with "version" in C modules _cextversions = { (r'cext', r'base85'): 1, @@ -86,13 +89,17 @@ (r'cffi', r'parsers'): (r'pure', r'parsers'), } + def _checkmod(pkgname, modname, mod): expected = _cextversions.get((pkgname, modname)) 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""" @@ -114,10 +121,12 @@ pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname)) return _importfrom(pn, mn) + def _isrustpermissive(): """Assuming the policy is a Rust one, tell if it's permissive.""" return policy.endswith(b'-allow') + def importrust(modname, member=None, default=None): """Import Rust module according to policy and availability. diff --git a/mercurial/node.py b/mercurial/node.py --- a/mercurial/node.py +++ b/mercurial/node.py @@ -20,6 +20,7 @@ except binascii.Error as e: raise TypeError(e) + nullrev = -1 # In hex, this is '0000000000000000000000000000000000000000' nullid = b"\0" * 20 @@ -38,10 +39,11 @@ # 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,11 +15,13 @@ 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")) @@ -28,20 +30,23 @@ 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" + 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) 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:"')) + 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) @@ -63,15 +68,18 @@ 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.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,6 +62,7 @@ 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) @@ -109,10 +111,18 @@ 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): + 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') diff --git a/mercurial/dirstateguard.py b/mercurial/dirstateguard.py --- a/mercurial/dirstateguard.py +++ b/mercurial/dirstateguard.py @@ -15,6 +15,7 @@ util, ) + class dirstateguard(util.transactional): '''Restore dirstate at unexpected failure. @@ -34,14 +35,16 @@ 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._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 @@ -49,27 +52,33 @@ 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 @@ -47,6 +48,7 @@ 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] @@ -62,6 +64,7 @@ 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,6 +8,7 @@ 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 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: @@ -47,9 +47,7 @@ ) # 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. @@ -57,6 +55,7 @@ 'ui': 'uimod', } + def usingabsolute(root): """Whether absolute imports are being used.""" if sys.version_info[0] >= 3: @@ -71,6 +70,7 @@ return False + def walklocal(root): """Recursively yield all descendant nodes but not in a different scope""" todo = collections.deque(ast.iter_child_nodes(root)) @@ -82,6 +82,7 @@ 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. @@ -91,11 +92,12 @@ 'zlib' """ parts = path.replace(os.sep, '/').split('/') - parts[-1] = parts[-1].split('.', 1)[0] # remove .py and .so and .ARCH.so + 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) + def fromlocalfunc(modulename, localmods): """Get a function to examine which locally defined module the target source imports via a specified name. @@ -164,6 +166,7 @@ prefix = '.'.join(modulename.split('.')[:-1]) if prefix: prefix += '.' + def fromlocal(name, level=0): # name is false value when relative imports are used. if not name: @@ -175,8 +178,9 @@ # 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: @@ -185,18 +189,21 @@ 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.'):] + 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. @@ -232,13 +239,13 @@ 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 + 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']: yield m @@ -264,14 +271,17 @@ 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')): @@ -280,12 +290,14 @@ 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. @@ -383,6 +395,7 @@ # lookup yield dottedpath + def verify_import_convention(module, source, localmods): """Verify imports match our established coding convention. @@ -400,6 +413,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. @@ -443,19 +457,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 @@ -465,16 +484,20 @@ # 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 @@ -485,13 +508,16 @@ 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 else: @@ -508,7 +534,8 @@ if not fullname or ( fullname in stdlib_modules and fullname not in localmods - and fullname + '.__init__' not in localmods): + and fullname + '.__init__' not in localmods + ): yield msg('relative import of stdlib module') else: seenlocal = fullname @@ -518,19 +545,24 @@ 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)) + 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 @@ -538,15 +570,19 @@ 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) @@ -556,14 +592,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 @@ -582,13 +627,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]] @@ -603,6 +655,7 @@ continue visit.append(path + [i]) + def rotatecycle(cycle): """arrange a cycle so that the lexicographically first module listed first @@ -613,6 +666,7 @@ idx = cycle.index(lowest) return cycle[idx:] + cycle[:idx] + [lowest] + def find_cycles(imports): """Find cycles in an already-loaded import graph. @@ -636,9 +690,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 @@ -680,6 +736,7 @@ modname = modname.decode('utf8') yield code, "%s[%d]" % (modname, starts), name, starts - 1 + def sources(f, modname): """Yields possibly multiple sources from a filepath @@ -700,6 +757,7 @@ for script, modname, t, line in embedded(f, modname, src): 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] ...}') @@ -721,15 +779,19 @@ 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)) 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() @@ -745,5 +807,6 @@ any_errors = True return any_errors != 0 + if __name__ == '__main__': sys.exit(int(main(sys.argv))) diff --git a/contrib/examples/fix.hgrc b/contrib/examples/fix.hgrc --- a/contrib/examples/fix.hgrc +++ b/contrib/examples/fix.hgrc @@ -7,4 +7,4 @@ # We use black, but currently with https://github.com/psf/black/pull/826 applied. # black:command = black --skip-string-normalization -# black:pattern = set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" +# black:pattern = set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/** To: durin42, #hg-reviewers, indygreg Cc: martinvonz, mjpieters, mercurial-devel _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel