Mercurial > hg-stable
annotate contrib/import-checker.py @ 50113:cf8b9c80d67c
dirstate: issue a developer warning on implicit write on wlock release
Our goal is to get rid of all these to clarify the writing pattern, so it is
time to warn about this (and later, forbid it).
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Tue, 13 Dec 2022 09:59:22 +0100 |
parents | 1572f790ee5e |
children | ada9a0245fd7 |
rev | line source |
---|---|
45849
c102b704edb5
global: use python3 in shebangs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
44440
diff
changeset
|
1 #!/usr/bin/env python3 |
26954
f804bf27439b
import-checker: make it executable for convenience
Yuya Nishihara <yuya@tcha.org>
parents:
26781
diff
changeset
|
2 |
28702
e44f671018e3
py3: use absolute_import in import-checker
timeless <timeless@mozdev.org>
parents:
28700
diff
changeset
|
3 |
20036 | 4 import ast |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
5 import collections |
43415
a8454e846736
import-checker: open all source files as utf-8
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43084
diff
changeset
|
6 import io |
20036 | 7 import os |
8 import sys | |
9 | |
20198
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
10 # Import a minimal set of stdlib modules needed for list_stdlib_modules() |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
11 # to work when run from a virtualenv. The modules were chosen empirically |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
12 # so that the return value matches the return value without virtualenv. |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
13 if True: # disable lexical sorting checks |
33895
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
14 try: |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
15 import BaseHTTPServer as basehttpserver |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
16 except ImportError: |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
17 basehttpserver = None |
29211
b42c2a66a698
py3: make contrib/import-checker.py get along with itself
Yuya Nishihara <yuya@tcha.org>
parents:
29208
diff
changeset
|
18 import zlib |
20198
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
19 |
40096
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
20 import testparseutil |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
21 |
49052
8dec9abf2669
import-checker: allow symbol imports from typing module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48970
diff
changeset
|
22 # Allow list of modules that symbols can be directly imported from. |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
23 allowsymbolimports = ( |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
24 '__future__', |
47383
26127236b229
convert-bazaar: use breezy package instead of old bzr one
Raphaël Gomès <rgomes@octobus.net>
parents:
45849
diff
changeset
|
25 'breezy', |
48925
029b76d645dc
imports: allow importing futures from concurrent
Augie Fackler <augie@google.com>
parents:
47797
diff
changeset
|
26 'concurrent', |
33933
2d64b2f1787b
contrib: allow symbol imports from hgclient for tests
Augie Fackler <raf@durin42.com>
parents:
33915
diff
changeset
|
27 'hgclient', |
33911
c9cf69d0c3b9
contrib: allow importing "symbols" from mercurial
Augie Fackler <raf@durin42.com>
parents:
33908
diff
changeset
|
28 'mercurial', |
27018
e5be48dd8215
import-checker: allow symbol imports from hgweb.common and .request
Yuya Nishihara <yuya@tcha.org>
parents:
26965
diff
changeset
|
29 'mercurial.hgweb.common', |
e5be48dd8215
import-checker: allow symbol imports from hgweb.common and .request
Yuya Nishihara <yuya@tcha.org>
parents:
26965
diff
changeset
|
30 'mercurial.hgweb.request', |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
31 'mercurial.i18n', |
42823
268662aac075
interfaces: create a new folder for interfaces and move repository.py in it
Pulkit Goyal <pulkit@yandex-team.ru>
parents:
42745
diff
changeset
|
32 'mercurial.interfaces', |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
33 'mercurial.node', |
43084
c2e284cee333
import-checker: allow symbol imports from mercurial.pycompat
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43075
diff
changeset
|
34 'mercurial.pycompat', |
39356
729082bb9938
revlog: split constants into a new `revlogutils.constants` module
Boris Feld <boris.feld@octobus.net>
parents:
38837
diff
changeset
|
35 # for revlog to re-export constant to extensions |
729082bb9938
revlog: split constants into a new `revlogutils.constants` module
Boris Feld <boris.feld@octobus.net>
parents:
38837
diff
changeset
|
36 'mercurial.revlogutils.constants', |
42745
ca5ca3badd3c
flagutil: create a `mercurial.revlogutils.flagutil` module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
42407
diff
changeset
|
37 'mercurial.revlogutils.flagutil', |
32540
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32458
diff
changeset
|
38 # for cffi modules to re-export pure functions |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32458
diff
changeset
|
39 'mercurial.pure.base85', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32458
diff
changeset
|
40 'mercurial.pure.bdiff', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32458
diff
changeset
|
41 'mercurial.pure.mpatch', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32458
diff
changeset
|
42 'mercurial.pure.osutil', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32458
diff
changeset
|
43 'mercurial.pure.parsers', |
34396
41401f502c83
tests: disable lints on mercurial/thirdparty
Siddharth Agarwal <sid0@fb.com>
parents:
34055
diff
changeset
|
44 # third-party imports should be directly imported |
41401f502c83
tests: disable lints on mercurial/thirdparty
Siddharth Agarwal <sid0@fb.com>
parents:
34055
diff
changeset
|
45 'mercurial.thirdparty', |
38837
8751d1e2a7ff
util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
37711
diff
changeset
|
46 'mercurial.thirdparty.attr', |
37182
922b3fae9c7d
setup: register zope.interface packages and compile C extension
Gregory Szorc <gregory.szorc@gmail.com>
parents:
34396
diff
changeset
|
47 'mercurial.thirdparty.zope', |
922b3fae9c7d
setup: register zope.interface packages and compile C extension
Gregory Szorc <gregory.szorc@gmail.com>
parents:
34396
diff
changeset
|
48 'mercurial.thirdparty.zope.interface', |
49052
8dec9abf2669
import-checker: allow symbol imports from typing module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48970
diff
changeset
|
49 'typing', |
49369
1572f790ee5e
convert: remove old ElementTree import cruft from darcs
Ian Moody <moz-ian@perix.co.uk>
parents:
49052
diff
changeset
|
50 'xml.etree.ElementTree', |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
51 ) |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
52 |
49052
8dec9abf2669
import-checker: allow symbol imports from typing module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48970
diff
changeset
|
53 # Allow list of symbols that can be directly imported. |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
54 directsymbols = ('demandimport',) |
32457
d02888308235
import-checker: add a way to directly import certain symbols
Siddharth Agarwal <sid0@fb.com>
parents:
32413
diff
changeset
|
55 |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
56 # Modules that must be aliased because they are commonly confused with |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
57 # common variables and can create aliasing and readability issues. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
58 requirealias = { |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
59 'ui': 'uimod', |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
60 } |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
61 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
62 |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
63 def walklocal(root): |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
64 """Recursively yield all descendant nodes but not in a different scope""" |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
65 todo = collections.deque(ast.iter_child_nodes(root)) |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
66 yield root, False |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
67 while todo: |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
68 node = todo.popleft() |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
69 newscope = isinstance(node, ast.FunctionDef) |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
70 if not newscope: |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
71 todo.extend(ast.iter_child_nodes(node)) |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
72 yield node, newscope |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
73 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
74 |
32413
194b0f781132
import-checker: drop workaround for pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32411
diff
changeset
|
75 def dotted_name_of_path(path): |
20036 | 76 """Given a relative path to a source file, return its dotted module name. |
77 | |
78 >>> dotted_name_of_path('mercurial/error.py') | |
79 'mercurial.error' | |
20383
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
80 >>> dotted_name_of_path('zlibmodule.so') |
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
81 'zlib' |
20036 | 82 """ |
27620
0c60843b55b5
import-checker: normalize directory separator to get module name on Windows
Yuya Nishihara <yuya@tcha.org>
parents:
27520
diff
changeset
|
83 parts = path.replace(os.sep, '/').split('/') |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
84 parts[-1] = parts[-1].split('.', 1)[0] # remove .py and .so and .ARCH.so |
20383
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
85 if parts[-1].endswith('module'): |
4990abb4729d
import-checker: fix names of dynamically loaded modules
Mads Kiilerich <madski@unity3d.com>
parents:
20238
diff
changeset
|
86 parts[-1] = parts[-1][:-6] |
20036 | 87 return '.'.join(parts) |
88 | |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
89 |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
90 def fromlocalfunc(modulename, localmods): |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
91 """Get a function to examine which locally defined module the |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
92 target source imports via a specified name. |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
93 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
94 `modulename` is an `dotted_name_of_path()`-ed source file path, |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
95 which may have `.__init__` at the end of it, of the target source. |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
96 |
32541
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
97 `localmods` is a set of absolute `dotted_name_of_path()`-ed source file |
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
98 paths of locally defined (= Mercurial specific) modules. |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
99 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
100 This function assumes that module names not existing in |
26781
1aee2ab0f902
spelling: trivial spell checking
Mads Kiilerich <madski@unity3d.com>
parents:
26221
diff
changeset
|
101 `localmods` are from the Python standard library. |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
102 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
103 This function returns the function, which takes `name` argument, |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
104 and returns `(absname, dottedpath, hassubmod)` tuple if `name` |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
105 matches against locally defined module. Otherwise, it returns |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
106 False. |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
107 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
108 It is assumed that `name` doesn't have `.__init__`. |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
109 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
110 `absname` is an absolute module name of specified `name` |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
111 (e.g. "hgext.convert"). This can be used to compose prefix for sub |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
112 modules or so. |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
113 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
114 `dottedpath` is a `dotted_name_of_path()`-ed source file path |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
115 (e.g. "hgext.convert.__init__") of `name`. This is used to look |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
116 module up in `localmods` again. |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
117 |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
118 `hassubmod` is whether it may have sub modules under it (for |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
119 convenient, even though this is also equivalent to "absname != |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
120 dottednpath") |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
121 |
32541
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
122 >>> localmods = {'foo.__init__', 'foo.foo1', |
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
123 ... 'foo.bar.__init__', 'foo.bar.bar1', |
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
124 ... 'baz.__init__', 'baz.baz1'} |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
125 >>> fromlocal = fromlocalfunc('foo.xxx', localmods) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
126 >>> # relative |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
127 >>> fromlocal('foo1') |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
128 ('foo.foo1', 'foo.foo1', False) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
129 >>> fromlocal('bar') |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
130 ('foo.bar', 'foo.bar.__init__', True) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
131 >>> fromlocal('bar.bar1') |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
132 ('foo.bar.bar1', 'foo.bar.bar1', False) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
133 >>> # absolute |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
134 >>> fromlocal('baz') |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
135 ('baz', 'baz.__init__', True) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
136 >>> fromlocal('baz.baz1') |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
137 ('baz.baz1', 'baz.baz1', False) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
138 >>> # unknown = maybe standard library |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
139 >>> fromlocal('os') |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
140 False |
25701
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
141 >>> fromlocal(None, 1) |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
142 ('foo', 'foo.__init__', True) |
29122
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
143 >>> fromlocal('foo1', 1) |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
144 ('foo.foo1', 'foo.foo1', False) |
25701
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
145 >>> fromlocal2 = fromlocalfunc('foo.xxx.yyy', localmods) |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
146 >>> fromlocal2(None, 2) |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
147 ('foo', 'foo.__init__', True) |
29122
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
148 >>> fromlocal2('bar2', 1) |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
149 False |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
150 >>> fromlocal2('bar', 2) |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
151 ('foo.bar', 'foo.bar.__init__', True) |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
152 """ |
33908
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
153 if not isinstance(modulename, str): |
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
154 modulename = modulename.decode('ascii') |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
155 prefix = '.'.join(modulename.split('.')[:-1]) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
156 if prefix: |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
157 prefix += '.' |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
158 |
25701
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
159 def fromlocal(name, level=0): |
29374
7712fcde2d56
import-checker: increase portability for python 2.6.x
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
29234
diff
changeset
|
160 # name is false value when relative imports are used. |
7712fcde2d56
import-checker: increase portability for python 2.6.x
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
29234
diff
changeset
|
161 if not name: |
25701
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
162 # If relative imports are used, level must not be absolute. |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
163 assert level > 0 |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
164 candidates = ['.'.join(modulename.split('.')[:-level])] |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
165 else: |
29122
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
166 if not level: |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
167 # Check relative name first. |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
168 candidates = [prefix + name, name] |
660d8d4ec7aa
import-checker: recognize relative imports from parents of current package
liscju <piotr.listkiewicz@gmail.com>
parents:
28922
diff
changeset
|
169 else: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
170 candidates = [ |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
171 '.'.join(modulename.split('.')[:-level]) + '.' + name |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
172 ] |
25701
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
173 |
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
174 for n in candidates: |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
175 if n in localmods: |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
176 return (n, n, False) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
177 dottedpath = n + '.__init__' |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
178 if dottedpath in localmods: |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
179 return (n, dottedpath, True) |
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
180 return False |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
181 |
25173
7358b5d9991e
import-checker: add utility to examine what module is imported easily
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25064
diff
changeset
|
182 return fromlocal |
20036 | 183 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
184 |
32542
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
185 def populateextmods(localmods): |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
186 """Populate C extension modules based on pure modules""" |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
187 newlocalmods = set(localmods) |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
188 for n in localmods: |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
189 if n.startswith('mercurial.pure.'): |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
190 m = n[len('mercurial.pure.') :] |
32542
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
191 newlocalmods.add('mercurial.cext.' + m) |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
192 newlocalmods.add('mercurial.cffi._' + m) |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
193 return newlocalmods |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
194 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
195 |
20036 | 196 def list_stdlib_modules(): |
197 """List the modules present in the stdlib. | |
198 | |
33895
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
199 >>> py3 = sys.version_info[0] >= 3 |
20036 | 200 >>> mods = set(list_stdlib_modules()) |
33895
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
201 >>> 'BaseHTTPServer' in mods or py3 |
20036 | 202 True |
203 | |
204 os.path isn't really a module, so it's missing: | |
205 | |
206 >>> 'os.path' in mods | |
207 False | |
208 | |
209 sys requires special treatment, because it's baked into the | |
210 interpreter, but it should still appear: | |
211 | |
212 >>> 'sys' in mods | |
213 True | |
214 | |
215 >>> 'collections' in mods | |
216 True | |
217 | |
33895
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
218 >>> 'cStringIO' in mods or py3 |
20036 | 219 True |
29395
4c8026babe8c
import-checker: ensure cffi is always a system module
Augie Fackler <raf@durin42.com>
parents:
29374
diff
changeset
|
220 |
4c8026babe8c
import-checker: ensure cffi is always a system module
Augie Fackler <raf@durin42.com>
parents:
29374
diff
changeset
|
221 >>> 'cffi' in mods |
4c8026babe8c
import-checker: ensure cffi is always a system module
Augie Fackler <raf@durin42.com>
parents:
29374
diff
changeset
|
222 True |
20036 | 223 """ |
224 for m in sys.builtin_module_names: | |
225 yield m | |
226 # These modules only exist on windows, but we should always | |
227 # consider them stdlib. | |
228 for m in ['msvcrt', '_winreg']: | |
229 yield m | |
33912
c856cb1c29be
contrib: inform import checker that __builtin__ is a thing
Augie Fackler <raf@durin42.com>
parents:
33911
diff
changeset
|
230 yield '__builtin__' |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
231 yield 'builtins' # python3 only |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
232 yield 'importlib.abc' # python3 only |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
233 yield 'importlib.machinery' # python3 only |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
234 yield 'importlib.util' # python3 only |
24669
fbdbff1b486a
import-checker: force 'fcntl', 'grp', 'pwd', and 'termios' to stdlib modules
Matt Harbison <matt_harbison@yahoo.com>
parents:
24668
diff
changeset
|
235 for m in 'fcntl', 'grp', 'pwd', 'termios': # Unix only |
fbdbff1b486a
import-checker: force 'fcntl', 'grp', 'pwd', and 'termios' to stdlib modules
Matt Harbison <matt_harbison@yahoo.com>
parents:
24668
diff
changeset
|
236 yield m |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
237 for m in 'cPickle', 'datetime': # in Python (not C) on PyPy |
28713
806d260c6f3b
tests: fix builtin module test on pypy
Maciej Fijalkowski <fijall@gmail.com>
parents:
28704
diff
changeset
|
238 yield m |
29395
4c8026babe8c
import-checker: ensure cffi is always a system module
Augie Fackler <raf@durin42.com>
parents:
29374
diff
changeset
|
239 for m in ['cffi']: |
4c8026babe8c
import-checker: ensure cffi is always a system module
Augie Fackler <raf@durin42.com>
parents:
29374
diff
changeset
|
240 yield m |
32331
bd872f64a8ba
cleanup: use set literals
Martin von Zweigbergk <martinvonz@google.com>
parents:
32252
diff
changeset
|
241 stdlib_prefixes = {sys.prefix, sys.exec_prefix} |
20198
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
242 # We need to supplement the list of prefixes for the search to work |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
243 # when run from within a virtualenv. |
33895
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
244 for mod in (basehttpserver, zlib): |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
245 if mod is None: |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32621
diff
changeset
|
246 continue |
20198
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
247 try: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
248 # Not all module objects have a __file__ attribute. |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
249 filename = mod.__file__ |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
250 except AttributeError: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
251 continue |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
252 dirname = os.path.dirname(filename) |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
253 for prefix in stdlib_prefixes: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
254 if dirname.startswith(prefix): |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
255 # Then this directory is redundant. |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
256 break |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
257 else: |
f5393a9dc4e5
import-checker: make test-module-imports.t work using virtualenv (issue4129)
Chris Jerdonek <chris.jerdonek@gmail.com>
parents:
20197
diff
changeset
|
258 stdlib_prefixes.add(dirname) |
40726
dd028bca9221
tests: make test-check-module-imports more robust
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents:
40531
diff
changeset
|
259 sourceroot = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) |
20036 | 260 for libpath in sys.path: |
40726
dd028bca9221
tests: make test-check-module-imports more robust
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents:
40531
diff
changeset
|
261 # We want to walk everything in sys.path that starts with something in |
dd028bca9221
tests: make test-check-module-imports more robust
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents:
40531
diff
changeset
|
262 # stdlib_prefixes, but not directories from the hg sources. |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
263 if os.path.abspath(libpath).startswith(sourceroot) or not any( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
264 libpath.startswith(p) for p in stdlib_prefixes |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
265 ): |
20036 | 266 continue |
267 for top, dirs, files in os.walk(libpath): | |
47797
42e2cdb50db0
check-module-imports: ignore non-stdlib module installed by distribution
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
47383
diff
changeset
|
268 if 'dist-packages' in top.split(os.path.sep): |
42e2cdb50db0
check-module-imports: ignore non-stdlib module installed by distribution
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
47383
diff
changeset
|
269 continue |
25733
f99c066f5f9a
import-checker: recurse into subtree of sys.path only if __init__.py exists
Yuya Nishihara <yuya@tcha.org>
parents:
25731
diff
changeset
|
270 for i, d in reversed(list(enumerate(dirs))): |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
271 if ( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
272 not os.path.exists(os.path.join(top, d, '__init__.py')) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
273 or top == libpath |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
274 and d in ('hgdemandimport', 'hgext', 'mercurial') |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
275 ): |
25733
f99c066f5f9a
import-checker: recurse into subtree of sys.path only if __init__.py exists
Yuya Nishihara <yuya@tcha.org>
parents:
25731
diff
changeset
|
276 del dirs[i] |
20036 | 277 for name in files: |
26221
ae65b1b4cb46
import-checker: use modern .endswith for multiple suffixes
Augie Fackler <augie@google.com>
parents:
26166
diff
changeset
|
278 if not name.endswith(('.py', '.so', '.pyc', '.pyo', '.pyd')): |
20036 | 279 continue |
27621
39845b064041
import-checker: list package directory as stdlib module
Yuya Nishihara <yuya@tcha.org>
parents:
27620
diff
changeset
|
280 if name.startswith('__init__.py'): |
39845b064041
import-checker: list package directory as stdlib module
Yuya Nishihara <yuya@tcha.org>
parents:
27620
diff
changeset
|
281 full_path = top |
39845b064041
import-checker: list package directory as stdlib module
Yuya Nishihara <yuya@tcha.org>
parents:
27620
diff
changeset
|
282 else: |
39845b064041
import-checker: list package directory as stdlib module
Yuya Nishihara <yuya@tcha.org>
parents:
27620
diff
changeset
|
283 full_path = os.path.join(top, name) |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
284 rel_path = full_path[len(libpath) + 1 :] |
20036 | 285 mod = dotted_name_of_path(rel_path) |
286 yield mod | |
287 | |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
288 |
20036 | 289 stdlib_modules = set(list_stdlib_modules()) |
290 | |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
291 |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
292 def imported_modules(source, modulename, f, localmods, ignore_nested=False): |
20036 | 293 """Given the source of a file as a string, yield the names |
294 imported by that file. | |
295 | |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
296 Args: |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
297 source: The python source to examine as a string. |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
298 modulename: of specified python source (may have `__init__`) |
32541
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
299 localmods: set of locally defined module names (may have `__init__`) |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
300 ignore_nested: If true, import statements that do not start in |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
301 column zero will be ignored. |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
302 |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
303 Returns: |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
304 A list of absolute module names imported by the given source. |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
305 |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
306 >>> f = 'foo/xxx.py' |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
307 >>> modulename = 'foo.xxx' |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
308 >>> localmods = {'foo.__init__': True, |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
309 ... 'foo.foo1': True, 'foo.foo2': True, |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
310 ... 'foo.bar.__init__': True, 'foo.bar.bar1': True, |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
311 ... 'baz.__init__': True, 'baz.baz1': True } |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
312 >>> # standard library (= not locally defined ones) |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
313 >>> sorted(imported_modules( |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
314 ... 'from stdlib1 import foo, bar; import stdlib2', |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
315 ... modulename, f, localmods)) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
316 [] |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
317 >>> # relative importing |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
318 >>> sorted(imported_modules( |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
319 ... 'import foo1; from bar import bar1', |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
320 ... modulename, f, localmods)) |
26964
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
321 ['foo.bar.bar1', 'foo.foo1'] |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
322 >>> sorted(imported_modules( |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
323 ... 'from bar.bar1 import name1, name2, name3', |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
324 ... modulename, f, localmods)) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
325 ['foo.bar.bar1'] |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
326 >>> # absolute importing |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
327 >>> sorted(imported_modules( |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
328 ... 'from baz import baz1, name1', |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
329 ... modulename, f, localmods)) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
330 ['baz.__init__', 'baz.baz1'] |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
331 >>> # mixed importing, even though it shouldn't be recommended |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
332 >>> sorted(imported_modules( |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
333 ... 'import stdlib, foo1, baz', |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
334 ... modulename, f, localmods)) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
335 ['baz.__init__', 'foo.foo1'] |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
336 >>> # ignore_nested |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
337 >>> sorted(imported_modules( |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
338 ... '''import foo |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
339 ... def wat(): |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
340 ... import bar |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
341 ... ''', modulename, f, localmods)) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
342 ['foo.__init__', 'foo.bar.__init__'] |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
343 >>> sorted(imported_modules( |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
344 ... '''import foo |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
345 ... def wat(): |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
346 ... import bar |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
347 ... ''', modulename, f, localmods, ignore_nested=True)) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
348 ['foo.__init__'] |
20036 | 349 """ |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
350 fromlocal = fromlocalfunc(modulename, localmods) |
28921
02ee31a50002
import-checker: track filenames for SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28920
diff
changeset
|
351 for node in ast.walk(ast.parse(source, f)): |
20037
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
352 if ignore_nested and getattr(node, 'col_offset', 0) > 0: |
957b43371928
import-checker: ignore nested imports
Augie Fackler <raf@durin42.com>
parents:
20036
diff
changeset
|
353 continue |
20036 | 354 if isinstance(node, ast.Import): |
355 for n in node.names: | |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
356 found = fromlocal(n.name) |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
357 if not found: |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
358 # this should import standard library |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
359 continue |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
360 yield found[1] |
20036 | 361 elif isinstance(node, ast.ImportFrom): |
25701
1f88c0f6ff5a
import-checker: resolve relative imports
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25660
diff
changeset
|
362 found = fromlocal(node.module, node.level) |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
363 if not found: |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
364 # this should import standard library |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
365 continue |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
366 |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
367 absname, dottedpath, hassubmod = found |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
368 if not hassubmod: |
26964
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
369 # "dottedpath" is not a package; must be imported |
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
370 yield dottedpath |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
371 # examination of "node.names" should be redundant |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
372 # e.g.: from mercurial.node import nullid, nullrev |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
373 continue |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
374 |
26964
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
375 modnotfound = False |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
376 prefix = absname + '.' |
20036 | 377 for n in node.names: |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
378 found = fromlocal(prefix + n.name) |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
379 if not found: |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
380 # this should be a function or a property of "node.module" |
26964
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
381 modnotfound = True |
25174
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
382 continue |
86298718b01c
import-checker: make imported_modules yield absolute dotted_name_of_path
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25173
diff
changeset
|
383 yield found[1] |
44440
4cabeea6d214
hgext: start building a library for simple hooks
Joerg Sonnenberger <joerg@bec.de>
parents:
43959
diff
changeset
|
384 if modnotfound and dottedpath != modulename: |
26964
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
385 # "dottedpath" is a package, but imported because of non-module |
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
386 # lookup |
44440
4cabeea6d214
hgext: start building a library for simple hooks
Joerg Sonnenberger <joerg@bec.de>
parents:
43959
diff
changeset
|
387 # specifically allow "from . import foo" from __init__.py |
26964
5abba2c92da3
import-checker: allow import of child modules from package root
Yuya Nishihara <yuya@tcha.org>
parents:
26956
diff
changeset
|
388 yield dottedpath |
20036 | 389 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
390 |
27272
69308357ecd1
import-checker: allow absolute imports of sub modules from local packages
Yuya Nishihara <yuya@tcha.org>
parents:
27018
diff
changeset
|
391 def verify_import_convention(module, source, localmods): |
48959
a52f5bfc9358
import-checker: assume absolute and use modern import checker
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48925
diff
changeset
|
392 """Verify imports match our established coding convention.""" |
a52f5bfc9358
import-checker: assume absolute and use modern import checker
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48925
diff
changeset
|
393 root = ast.parse(source) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
394 |
48959
a52f5bfc9358
import-checker: assume absolute and use modern import checker
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48925
diff
changeset
|
395 return verify_modern_convention(module, root, localmods) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
396 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
397 |
27272
69308357ecd1
import-checker: allow absolute imports of sub modules from local packages
Yuya Nishihara <yuya@tcha.org>
parents:
27018
diff
changeset
|
398 def verify_modern_convention(module, root, localmods, root_col_offset=0): |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
399 """Verify a file conforms to the modern import convention rules. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
400 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
401 The rules of the modern convention are: |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
402 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
403 * Ordering is stdlib followed by local imports. Each group is lexically |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
404 sorted. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
405 * Importing multiple modules via "import X, Y" is not allowed: use |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
406 separate import statements. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
407 * Importing multiple modules via "from X import ..." is allowed if using |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
408 parenthesis and one entry per line. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
409 * Only 1 relative import statement per import level ("from .", "from ..") |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
410 is allowed. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
411 * Relative imports from higher levels must occur before lower levels. e.g. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
412 "from .." must be before "from .". |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
413 * Imports from peer packages should use relative import (e.g. do not |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
414 "import mercurial.foo" from a "mercurial.*" module). |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
415 * Symbols can only be imported from specific modules (see |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
416 `allowsymbolimports`). For other modules, first import the module then |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
417 assign the symbol to a module-level variable. In addition, these imports |
29208
cba8bc11ed10
import-checker: extend check of symbol-import order to all local modules
Yuya Nishihara <yuya@tcha.org>
parents:
29207
diff
changeset
|
418 must be performed before other local imports. This rule only |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
419 applies to import statements outside of any blocks. |
34055
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33938
diff
changeset
|
420 * Relative imports from the standard library are not allowed, unless that |
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33938
diff
changeset
|
421 library is also a local module. |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
422 * Certain modules must be aliased to alternate names to avoid aliasing |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
423 and readability problems. See `requirealias`. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
424 """ |
33908
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
425 if not isinstance(module, str): |
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
426 module = module.decode('ascii') |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
427 topmodule = module.split('.')[0] |
27272
69308357ecd1
import-checker: allow absolute imports of sub modules from local packages
Yuya Nishihara <yuya@tcha.org>
parents:
27018
diff
changeset
|
428 fromlocal = fromlocalfunc(module, localmods) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
429 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
430 # Whether a local/non-stdlib import has been performed. |
28330
f3fb24e36d61
import-checker: report local with stdlib late warning
timeless <timeless@mozdev.org>
parents:
27621
diff
changeset
|
431 seenlocal = None |
29208
cba8bc11ed10
import-checker: extend check of symbol-import order to all local modules
Yuya Nishihara <yuya@tcha.org>
parents:
29207
diff
changeset
|
432 # Whether a local/non-stdlib, non-symbol import has been seen. |
cba8bc11ed10
import-checker: extend check of symbol-import order to all local modules
Yuya Nishihara <yuya@tcha.org>
parents:
29207
diff
changeset
|
433 seennonsymbollocal = False |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
434 # The last name to be imported (for sorting). |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
435 lastname = None |
30595
74eecb93c617
import-checker: do not enforce lexical sort accross stdlib/local boundary
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
29395
diff
changeset
|
436 laststdlib = None |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
437 # Relative import levels encountered so far. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
438 seenlevels = set() |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
439 |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
440 for node, newscope in walklocal(root): |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
441 |
26955
c4114e335b49
import-checker: extract function to generate a formatted warning
Yuya Nishihara <yuya@tcha.org>
parents:
26954
diff
changeset
|
442 def msg(fmt, *args): |
26956
4b56214ebb7a
import-checker: include lineno in warning message
Yuya Nishihara <yuya@tcha.org>
parents:
26955
diff
changeset
|
443 return (fmt % args, node.lineno) |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
444 |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
445 if newscope: |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
446 # Check for local imports in function |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
447 for r in verify_modern_convention( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
448 module, node, localmods, node.col_offset + 4 |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
449 ): |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
450 yield r |
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
451 elif isinstance(node, ast.Import): |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
452 # Disallow "import foo, bar" and require separate imports |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
453 # for each module. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
454 if len(node.names) > 1: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
455 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
456 'multiple imported names: %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
457 ', '.join(n.name for n in node.names), |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
458 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
459 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
460 name = node.names[0].name |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
461 asname = node.names[0].asname |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
462 |
30595
74eecb93c617
import-checker: do not enforce lexical sort accross stdlib/local boundary
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
29395
diff
changeset
|
463 stdlib = name in stdlib_modules |
74eecb93c617
import-checker: do not enforce lexical sort accross stdlib/local boundary
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
29395
diff
changeset
|
464 |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
465 # Ignore sorting rules on imports inside blocks. |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
466 if node.col_offset == root_col_offset: |
30595
74eecb93c617
import-checker: do not enforce lexical sort accross stdlib/local boundary
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
29395
diff
changeset
|
467 if lastname and name < lastname and laststdlib == stdlib: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
468 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
469 'imports not lexically sorted: %s < %s', name, lastname |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
470 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
471 |
30595
74eecb93c617
import-checker: do not enforce lexical sort accross stdlib/local boundary
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
29395
diff
changeset
|
472 lastname = name |
74eecb93c617
import-checker: do not enforce lexical sort accross stdlib/local boundary
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
29395
diff
changeset
|
473 laststdlib = stdlib |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
474 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
475 # stdlib imports should be before local imports. |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
476 if stdlib and seenlocal and node.col_offset == root_col_offset: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
477 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
478 'stdlib import "%s" follows local import: %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
479 name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
480 seenlocal, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
481 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
482 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
483 if not stdlib: |
28330
f3fb24e36d61
import-checker: report local with stdlib late warning
timeless <timeless@mozdev.org>
parents:
27621
diff
changeset
|
484 seenlocal = name |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
485 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
486 # Import of sibling modules should use relative imports. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
487 topname = name.split('.')[0] |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
488 if topname == topmodule: |
26955
c4114e335b49
import-checker: extract function to generate a formatted warning
Yuya Nishihara <yuya@tcha.org>
parents:
26954
diff
changeset
|
489 yield msg('import should be relative: %s', name) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
490 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
491 if name in requirealias and asname != requirealias[name]: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
492 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
493 '%s module must be "as" aliased to %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
494 name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
495 requirealias[name], |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
496 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
497 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
498 elif isinstance(node, ast.ImportFrom): |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
499 # Resolve the full imported module name. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
500 if node.level > 0: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
501 fullname = '.'.join(module.split('.')[: -node.level]) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
502 if node.module: |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
503 fullname += '.%s' % node.module |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
504 else: |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
505 assert node.module |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
506 fullname = node.module |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
507 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
508 topname = fullname.split('.')[0] |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
509 if topname == topmodule: |
26955
c4114e335b49
import-checker: extract function to generate a formatted warning
Yuya Nishihara <yuya@tcha.org>
parents:
26954
diff
changeset
|
510 yield msg('import should be relative: %s', fullname) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
511 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
512 # __future__ is special since it needs to come first and use |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
513 # symbol import. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
514 if fullname != '__future__': |
34055
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33938
diff
changeset
|
515 if not fullname or ( |
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33938
diff
changeset
|
516 fullname in stdlib_modules |
43641
0ad5d6c4bfad
import-checker: allow 'from typing import ...'
Yuya Nishihara <yuya@tcha.org>
parents:
43415
diff
changeset
|
517 # allow standard 'from typing import ...' style |
43959
303576116ac1
import-checker: allow all absolute imports of stdlib modules
Martin von Zweigbergk <martinvonz@google.com>
parents:
43641
diff
changeset
|
518 and fullname.startswith('.') |
34055
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33938
diff
changeset
|
519 and fullname not in localmods |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
520 and fullname + '.__init__' not in localmods |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
521 ): |
26955
c4114e335b49
import-checker: extract function to generate a formatted warning
Yuya Nishihara <yuya@tcha.org>
parents:
26954
diff
changeset
|
522 yield msg('relative import of stdlib module') |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
523 else: |
28330
f3fb24e36d61
import-checker: report local with stdlib late warning
timeless <timeless@mozdev.org>
parents:
27621
diff
changeset
|
524 seenlocal = fullname |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
525 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
526 # Direct symbol import is only allowed from certain modules and |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
527 # must occur before non-symbol imports. |
29207
a09098c61fea
import-checker: always build a list of imported symbols
Yuya Nishihara <yuya@tcha.org>
parents:
29122
diff
changeset
|
528 found = fromlocal(node.module, node.level) |
a09098c61fea
import-checker: always build a list of imported symbols
Yuya Nishihara <yuya@tcha.org>
parents:
29122
diff
changeset
|
529 if found and found[2]: # node.module is a package |
a09098c61fea
import-checker: always build a list of imported symbols
Yuya Nishihara <yuya@tcha.org>
parents:
29122
diff
changeset
|
530 prefix = found[0] + '.' |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
531 symbols = ( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
532 n.name for n in node.names if not fromlocal(prefix + n.name) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
533 ) |
29207
a09098c61fea
import-checker: always build a list of imported symbols
Yuya Nishihara <yuya@tcha.org>
parents:
29122
diff
changeset
|
534 else: |
32457
d02888308235
import-checker: add a way to directly import certain symbols
Siddharth Agarwal <sid0@fb.com>
parents:
32413
diff
changeset
|
535 symbols = (n.name for n in node.names) |
d02888308235
import-checker: add a way to directly import certain symbols
Siddharth Agarwal <sid0@fb.com>
parents:
32413
diff
changeset
|
536 symbols = [sym for sym in symbols if sym not in directsymbols] |
26965
1fa66d3ad28d
import-checker: reset context to verify convention in function scope
Yuya Nishihara <yuya@tcha.org>
parents:
26964
diff
changeset
|
537 if node.module and node.col_offset == root_col_offset: |
27272
69308357ecd1
import-checker: allow absolute imports of sub modules from local packages
Yuya Nishihara <yuya@tcha.org>
parents:
27018
diff
changeset
|
538 if symbols and fullname not in allowsymbolimports: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
539 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
540 'direct symbol import %s from %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
541 ', '.join(symbols), |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
542 fullname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
543 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
544 |
29208
cba8bc11ed10
import-checker: extend check of symbol-import order to all local modules
Yuya Nishihara <yuya@tcha.org>
parents:
29207
diff
changeset
|
545 if symbols and seennonsymbollocal: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
546 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
547 'symbol import follows non-symbol import: %s', fullname |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
548 ) |
29208
cba8bc11ed10
import-checker: extend check of symbol-import order to all local modules
Yuya Nishihara <yuya@tcha.org>
parents:
29207
diff
changeset
|
549 if not symbols and fullname not in stdlib_modules: |
cba8bc11ed10
import-checker: extend check of symbol-import order to all local modules
Yuya Nishihara <yuya@tcha.org>
parents:
29207
diff
changeset
|
550 seennonsymbollocal = True |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
551 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
552 if not node.module: |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
553 assert node.level |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
554 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
555 # Only allow 1 group per level. |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
556 if ( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
557 node.level in seenlevels |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
558 and node.col_offset == root_col_offset |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
559 ): |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
560 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
561 'multiple "from %s import" statements', '.' * node.level |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
562 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
563 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
564 # Higher-level groups come before lower-level groups. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
565 if any(node.level > l for l in seenlevels): |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
566 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
567 'higher-level import should come first: %s', fullname |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
568 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
569 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
570 seenlevels.add(node.level) |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
571 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
572 # Entries in "from .X import ( ... )" lists must be lexically |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
573 # sorted. |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
574 lastentryname = None |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
575 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
576 for n in node.names: |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
577 if lastentryname and n.name < lastentryname: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
578 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
579 'imports from %s not lexically sorted: %s < %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
580 fullname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
581 n.name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
582 lastentryname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
583 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
584 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
585 lastentryname = n.name |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
586 |
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
587 if n.name in requirealias and n.asname != requirealias[n.name]: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
588 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
589 '%s from %s must be "as" aliased to %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
590 n.name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
591 fullname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
592 requirealias[n.name], |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
593 ) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
594 |
25702
ab2c5163900e
import-checker: establish new function for verifying import conventions
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25701
diff
changeset
|
595 |
20036 | 596 class CircularImport(Exception): |
597 pass | |
598 | |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
599 |
24490
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
600 def checkmod(mod, imports): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
601 shortest = {} |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
602 visit = [[mod]] |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
603 while visit: |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
604 path = visit.pop(0) |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
605 for i in sorted(imports.get(path[-1], [])): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
606 if len(path) < shortest.get(i, 1000): |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
607 shortest[i] = len(path) |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
608 if i in path: |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
609 if i == path[0]: |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
610 raise CircularImport(path) |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
611 continue |
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
612 visit.append(path + [i]) |
20036 | 613 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
614 |
20038
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
615 def rotatecycle(cycle): |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
616 """arrange a cycle so that the lexicographically first module listed first |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
617 |
24488
4b3fc46097f7
import-checker: drop duplicate element from cycle
Matt Mackall <mpm@selenic.com>
parents:
24487
diff
changeset
|
618 >>> rotatecycle(['foo', 'bar']) |
20038
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
619 ['bar', 'foo', 'bar'] |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
620 """ |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
621 lowest = min(cycle) |
c65a6937b828
import-checker: try a little harder to show fewer cycles
Augie Fackler <raf@durin42.com>
parents:
20037
diff
changeset
|
622 idx = cycle.index(lowest) |
24488
4b3fc46097f7
import-checker: drop duplicate element from cycle
Matt Mackall <mpm@selenic.com>
parents:
24487
diff
changeset
|
623 return cycle[idx:] + cycle[:idx] + [lowest] |
20036 | 624 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
625 |
20036 | 626 def find_cycles(imports): |
627 """Find cycles in an already-loaded import graph. | |
628 | |
25175
10e6c4b7121b
import-checker: don't treat modules as relative one if not found
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25174
diff
changeset
|
629 All module names recorded in `imports` should be absolute one. |
10e6c4b7121b
import-checker: don't treat modules as relative one if not found
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25174
diff
changeset
|
630 |
10e6c4b7121b
import-checker: don't treat modules as relative one if not found
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25174
diff
changeset
|
631 >>> imports = {'top.foo': ['top.bar', 'os.path', 'top.qux'], |
10e6c4b7121b
import-checker: don't treat modules as relative one if not found
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25174
diff
changeset
|
632 ... 'top.bar': ['top.baz', 'sys'], |
10e6c4b7121b
import-checker: don't treat modules as relative one if not found
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25174
diff
changeset
|
633 ... 'top.baz': ['top.foo'], |
10e6c4b7121b
import-checker: don't treat modules as relative one if not found
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25174
diff
changeset
|
634 ... 'top.qux': ['top.foo']} |
28703
a274c4f9087a
py3: use print_function in import-checker
timeless <timeless@mozdev.org>
parents:
28702
diff
changeset
|
635 >>> print('\\n'.join(sorted(find_cycles(imports)))) |
24487
642d245ff537
import-checker: fix rotatecycle
Matt Mackall <mpm@selenic.com>
parents:
22975
diff
changeset
|
636 top.bar -> top.baz -> top.foo -> top.bar |
642d245ff537
import-checker: fix rotatecycle
Matt Mackall <mpm@selenic.com>
parents:
22975
diff
changeset
|
637 top.foo -> top.qux -> top.foo |
20036 | 638 """ |
24491
784b278b349c
import-checker: rotatecycle is actually the canonical cycle key
Matt Mackall <mpm@selenic.com>
parents:
24490
diff
changeset
|
639 cycles = set() |
28704
1fa6fdb72275
py3: handle iter/iterkeys+iteritems python3 divergence in import-checker
timeless <timeless@mozdev.org>
parents:
28703
diff
changeset
|
640 for mod in sorted(imports.keys()): |
20036 | 641 try: |
24490
fb4639d5268e
import-checker: make search algorithm non-recursive breadth-first
Matt Mackall <mpm@selenic.com>
parents:
24489
diff
changeset
|
642 checkmod(mod, imports) |
25660
328739ea70c3
global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25175
diff
changeset
|
643 except CircularImport as e: |
20036 | 644 cycle = e.args[0] |
24491
784b278b349c
import-checker: rotatecycle is actually the canonical cycle key
Matt Mackall <mpm@selenic.com>
parents:
24490
diff
changeset
|
645 cycles.add(" -> ".join(rotatecycle(cycle))) |
784b278b349c
import-checker: rotatecycle is actually the canonical cycle key
Matt Mackall <mpm@selenic.com>
parents:
24490
diff
changeset
|
646 return cycles |
20036 | 647 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
648 |
20036 | 649 def _cycle_sortkey(c): |
650 return len(c), c | |
651 | |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
652 |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
653 def embedded(f, modname, src): |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
654 """Extract embedded python code |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
655 |
33896
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
656 >>> def _forcestr(thing): |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
657 ... if not isinstance(thing, str): |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
658 ... return thing.decode('ascii') |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
659 ... return thing |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
660 >>> def test(fn, lines): |
33896
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
661 ... for s, m, f, l in embedded(fn, b"example", lines): |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
662 ... print("%s %s %d" % (_forcestr(m), _forcestr(f), l)) |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
663 ... print(repr(_forcestr(s))) |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
664 >>> lines = [ |
42407
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
665 ... 'comment', |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
666 ... ' >>> from __future__ import print_function', |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
667 ... " >>> ' multiline", |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
668 ... " ... string'", |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
669 ... ' ', |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
670 ... 'comment', |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
671 ... ' $ cat > foo.py <<EOF', |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
672 ... ' > from __future__ import print_function', |
04eb3c5607af
contrib: fix import-checker to operate on str instead of bytes
Augie Fackler <augie@google.com>
parents:
41161
diff
changeset
|
673 ... ' > EOF', |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
674 ... ] |
33896
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
675 >>> test(b"example.t", lines) |
40096
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
676 example[2] doctest.py 1 |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
677 "from __future__ import print_function\\n' multiline\\nstring'\\n\\n" |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
678 example[8] foo.py 7 |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
679 'from __future__ import print_function\\n' |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
680 """ |
40096
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
681 errors = [] |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
682 for name, starts, ends, code in testparseutil.pyembedded(f, src, errors): |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
683 if not name: |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
684 # use 'doctest.py', in order to make already existing |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
685 # doctest above pass instantly |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
686 name = 'doctest.py' |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
687 # "starts" is "line number" (1-origin), but embedded() is |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
688 # expected to return "line offset" (0-origin). Therefore, this |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
689 # yields "starts - 1". |
40530
99d5424eedc8
contrib: fix import-checker to not b'' module names on Python 3
Augie Fackler <augie@google.com>
parents:
40096
diff
changeset
|
690 if not isinstance(modname, str): |
99d5424eedc8
contrib: fix import-checker to not b'' module names on Python 3
Augie Fackler <augie@google.com>
parents:
40096
diff
changeset
|
691 modname = modname.decode('utf8') |
40096
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39356
diff
changeset
|
692 yield code, "%s[%d]" % (modname, starts), name, starts - 1 |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
693 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
694 |
28919
a94f34306bb9
import-checker: refactor source reading
timeless <timeless@mozdev.org>
parents:
28713
diff
changeset
|
695 def sources(f, modname): |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
696 """Yields possibly multiple sources from a filepath |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
697 |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
698 input: filepath, modulename |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
699 yields: script(string), modulename, filepath, linenumber |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
700 |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
701 For embedded scripts, the modulename and filepath will be different |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
702 from the function arguments. linenumber is an offset relative to |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
703 the input file. |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
704 """ |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
705 py = False |
29234
393aef802535
tests: enable import checker for all python files (including no .py files)
Yuya Nishihara <yuya@tcha.org>
parents:
29211
diff
changeset
|
706 if not f.endswith('.t'): |
33896
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33895
diff
changeset
|
707 with open(f, 'rb') as src: |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
708 yield src.read(), modname, f, 0 |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
709 py = True |
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
710 if py or f.endswith('.t'): |
43415
a8454e846736
import-checker: open all source files as utf-8
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43084
diff
changeset
|
711 # Strictly speaking we should sniff for the magic header that denotes |
a8454e846736
import-checker: open all source files as utf-8
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43084
diff
changeset
|
712 # Python source file encoding. But in reality we don't use anything |
a8454e846736
import-checker: open all source files as utf-8
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43084
diff
changeset
|
713 # other than ASCII (mainly) and UTF-8 (in a few exceptions), so |
a8454e846736
import-checker: open all source files as utf-8
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43084
diff
changeset
|
714 # simplicity is fine. |
a8454e846736
import-checker: open all source files as utf-8
Gregory Szorc <gregory.szorc@gmail.com>
parents:
43084
diff
changeset
|
715 with io.open(f, 'r', encoding='utf-8') as src: |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
716 for script, modname, t, line in embedded(f, modname, src): |
40531
90517fad4293
contrib: tweak import-checker to always use bytes for module names
Augie Fackler <augie@google.com>
parents:
40530
diff
changeset
|
717 yield script, modname.encode('utf8'), t, line |
28919
a94f34306bb9
import-checker: refactor source reading
timeless <timeless@mozdev.org>
parents:
28713
diff
changeset
|
718 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
719 |
20036 | 720 def main(argv): |
25063
723e364488f4
import-checker: add xargs like mode
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
24669
diff
changeset
|
721 if len(argv) < 2 or (argv[1] == '-' and len(argv) > 2): |
28703
a274c4f9087a
py3: use print_function in import-checker
timeless <timeless@mozdev.org>
parents:
28702
diff
changeset
|
722 print('Usage: %s {-|file [file] [file] ...}') |
20036 | 723 return 1 |
25063
723e364488f4
import-checker: add xargs like mode
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
24669
diff
changeset
|
724 if argv[1] == '-': |
723e364488f4
import-checker: add xargs like mode
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
24669
diff
changeset
|
725 argv = argv[:1] |
723e364488f4
import-checker: add xargs like mode
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
24669
diff
changeset
|
726 argv.extend(l.rstrip() for l in sys.stdin.readlines()) |
32541
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
727 localmodpaths = {} |
20036 | 728 used_imports = {} |
729 any_errors = False | |
730 for source_path in argv[1:]: | |
32413
194b0f781132
import-checker: drop workaround for pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32411
diff
changeset
|
731 modname = dotted_name_of_path(source_path) |
32541
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
732 localmodpaths[modname] = source_path |
32542
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32541
diff
changeset
|
733 localmods = populateextmods(localmodpaths) |
32541
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32540
diff
changeset
|
734 for localmodname, source_path in sorted(localmodpaths.items()): |
33908
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
735 if not isinstance(localmodname, bytes): |
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
736 # This is only safe because all hg's files are ascii |
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33896
diff
changeset
|
737 localmodname = localmodname.encode('ascii') |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
738 for src, modname, name, line in sources(source_path, localmodname): |
28920
cdf331b54eb8
import-checker: track SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28919
diff
changeset
|
739 try: |
cdf331b54eb8
import-checker: track SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28919
diff
changeset
|
740 used_imports[modname] = sorted( |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
741 imported_modules( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
742 src, modname, name, localmods, ignore_nested=True |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
743 ) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
744 ) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
745 for error, lineno in verify_import_convention( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
746 modname, src, localmods |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
747 ): |
28920
cdf331b54eb8
import-checker: track SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28919
diff
changeset
|
748 any_errors = True |
28922
4ec62a084e5c
import-checker: parse python code from .t files
timeless <timeless@mozdev.org>
parents:
28921
diff
changeset
|
749 print('%s:%d: %s' % (source_path, lineno + line, error)) |
28920
cdf331b54eb8
import-checker: track SyntaxErrors
timeless <timeless@mozdev.org>
parents:
28919
diff
changeset
|
750 except SyntaxError as e: |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
751 print( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
752 '%s:%d: SyntaxError: %s' % (source_path, e.lineno + line, e) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
753 ) |
20036 | 754 cycles = find_cycles(used_imports) |
755 if cycles: | |
756 firstmods = set() | |
757 for c in sorted(cycles, key=_cycle_sortkey): | |
758 first = c.split()[0] | |
759 # As a rough cut, ignore any cycle that starts with the | |
760 # same module as some other cycle. Otherwise we see lots | |
761 # of cycles that are effectively duplicates. | |
762 if first in firstmods: | |
763 continue | |
28703
a274c4f9087a
py3: use print_function in import-checker
timeless <timeless@mozdev.org>
parents:
28702
diff
changeset
|
764 print('Import cycle:', c) |
20036 | 765 firstmods.add(first) |
766 any_errors = True | |
25731
cd1daab5d036
import-checker.py: exit with code 0 if no error is detected
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
25703
diff
changeset
|
767 return any_errors != 0 |
20036 | 768 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42823
diff
changeset
|
769 |
20036 | 770 if __name__ == '__main__': |
771 sys.exit(int(main(sys.argv))) |