Mercurial > hg
annotate contrib/import-checker.py @ 50400:95acba2c29f6
encoding: avoid quadratic time complexity when json-encoding non-UTF8 strings
Apparently the code uses "+=" with a bytes object, which is linear-time, so the
whole encoding is quadratic-time. This patch makes us use a bytearray object,
instead, which has a(n amortized-)constant-time append operation.
The encoding is still not particularly fast, but at least a 10MB file
takes tens of seconds, not many hours to encode.
author | Arseniy Alekseyev <aalekseyev@janestreet.com> |
---|---|
date | Mon, 06 Mar 2023 11:27:57 +0000 |
parents | 1572f790ee5e |
children | ada9a0245fd7 |
rev | line source |
---|---|
45830
c102b704edb5
global: use python3 in shebangs
Gregory Szorc <gregory.szorc@gmail.com>
parents:
44413
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:
42813
diff
changeset
|
13 if True: # disable lexical sorting checks |
33876
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
diff
changeset
|
14 try: |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
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:
32595
diff
changeset
|
16 except ImportError: |
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
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 |
40095
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
diff
changeset
|
20 import testparseutil |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
diff
changeset
|
21 |
48961
8dec9abf2669
import-checker: allow symbol imports from typing module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48879
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__', |
47377
26127236b229
convert-bazaar: use breezy package instead of old bzr one
Raphaël Gomès <rgomes@octobus.net>
parents:
45830
diff
changeset
|
25 'breezy', |
48834
029b76d645dc
imports: allow importing futures from concurrent
Augie Fackler <augie@google.com>
parents:
47801
diff
changeset
|
26 'concurrent', |
33915
2d64b2f1787b
contrib: allow symbol imports from hgclient for tests
Augie Fackler <raf@durin42.com>
parents:
33897
diff
changeset
|
27 'hgclient', |
33893
c9cf69d0c3b9
contrib: allow importing "symbols" from mercurial
Augie Fackler <raf@durin42.com>
parents:
33890
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', |
42813
268662aac075
interfaces: create a new folder for interfaces and move repository.py in it
Pulkit Goyal <pulkit@yandex-team.ru>
parents:
42728
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', |
39329
729082bb9938
revlog: split constants into a new `revlogutils.constants` module
Boris Feld <boris.feld@octobus.net>
parents:
38797
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:
38797
diff
changeset
|
36 'mercurial.revlogutils.constants', |
42728
ca5ca3badd3c
flagutil: create a `mercurial.revlogutils.flagutil` module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
42388
diff
changeset
|
37 'mercurial.revlogutils.flagutil', |
32507
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32420
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:
32420
diff
changeset
|
39 'mercurial.pure.base85', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32420
diff
changeset
|
40 'mercurial.pure.bdiff', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32420
diff
changeset
|
41 'mercurial.pure.mpatch', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32420
diff
changeset
|
42 'mercurial.pure.osutil', |
95085d747db8
import-checker: allow importing symbols from pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32420
diff
changeset
|
43 'mercurial.pure.parsers', |
34395
41401f502c83
tests: disable lints on mercurial/thirdparty
Siddharth Agarwal <sid0@fb.com>
parents:
34038
diff
changeset
|
44 # third-party imports should be directly imported |
41401f502c83
tests: disable lints on mercurial/thirdparty
Siddharth Agarwal <sid0@fb.com>
parents:
34038
diff
changeset
|
45 'mercurial.thirdparty', |
38797
8751d1e2a7ff
util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
37711
diff
changeset
|
46 'mercurial.thirdparty.attr', |
37180
922b3fae9c7d
setup: register zope.interface packages and compile C extension
Gregory Szorc <gregory.szorc@gmail.com>
parents:
34395
diff
changeset
|
47 'mercurial.thirdparty.zope', |
922b3fae9c7d
setup: register zope.interface packages and compile C extension
Gregory Szorc <gregory.szorc@gmail.com>
parents:
34395
diff
changeset
|
48 'mercurial.thirdparty.zope.interface', |
48961
8dec9abf2669
import-checker: allow symbol imports from typing module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48879
diff
changeset
|
49 'typing', |
49370
1572f790ee5e
convert: remove old ElementTree import cruft from darcs
Ian Moody <moz-ian@perix.co.uk>
parents:
48961
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 |
48961
8dec9abf2669
import-checker: allow symbol imports from typing module
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48879
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:
42813
diff
changeset
|
54 directsymbols = ('demandimport',) |
32419
d02888308235
import-checker: add a way to directly import certain symbols
Siddharth Agarwal <sid0@fb.com>
parents:
32374
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:
42813
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:
42813
diff
changeset
|
74 |
32374
194b0f781132
import-checker: drop workaround for pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32372
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:
42813
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:
42813
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 |
32508
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32507
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:
32507
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 |
32508
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32507
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:
32507
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:
32507
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 """ |
33890
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33877
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:
33877
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:
42813
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:
42813
diff
changeset
|
170 candidates = [ |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
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:
42813
diff
changeset
|
184 |
32509
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
185 def populateextmods(localmods): |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
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:
32508
diff
changeset
|
187 newlocalmods = set(localmods) |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
188 for n in localmods: |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
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:
42813
diff
changeset
|
190 m = n[len('mercurial.pure.') :] |
32509
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
191 newlocalmods.add('mercurial.cext.' + m) |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
192 newlocalmods.add('mercurial.cffi._' + m) |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
193 return newlocalmods |
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
194 |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
195 |
20036 | 196 def list_stdlib_modules(): |
197 """List the modules present in the stdlib. | |
198 | |
33876
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
diff
changeset
|
199 >>> py3 = sys.version_info[0] >= 3 |
20036 | 200 >>> mods = set(list_stdlib_modules()) |
33876
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
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 | |
33876
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
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 | |
33894
c856cb1c29be
contrib: inform import checker that __builtin__ is a thing
Augie Fackler <raf@durin42.com>
parents:
33893
diff
changeset
|
230 yield '__builtin__' |
43075
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
231 yield 'builtins' # python3 only |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
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:
42813
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 |
32291
bd872f64a8ba
cleanup: use set literals
Martin von Zweigbergk <martinvonz@google.com>
parents:
32212
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. |
33876
998fad4b3072
contrib: work around some modules not existing on Py3 in import checker
Augie Fackler <raf@durin42.com>
parents:
32595
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:
32595
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:
32595
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) |
40687
dd028bca9221
tests: make test-check-module-imports more robust
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents:
40481
diff
changeset
|
259 sourceroot = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) |
20036 | 260 for libpath in sys.path: |
40687
dd028bca9221
tests: make test-check-module-imports more robust
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents:
40481
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:
40481
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:
42813
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:
42813
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:
42813
diff
changeset
|
265 ): |
20036 | 266 continue |
267 for top, dirs, files in os.walk(libpath): | |
47801
42e2cdb50db0
check-module-imports: ignore non-stdlib module installed by distribution
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
47377
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:
47377
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:
42813
diff
changeset
|
271 if ( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
273 or top == libpath |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
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:
42813
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:
42813
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__`) |
32508
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32507
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] |
44413
4cabeea6d214
hgext: start building a library for simple hooks
Joerg Sonnenberger <joerg@bec.de>
parents:
43954
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 |
44413
4cabeea6d214
hgext: start building a library for simple hooks
Joerg Sonnenberger <joerg@bec.de>
parents:
43954
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:
42813
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): |
48868
a52f5bfc9358
import-checker: assume absolute and use modern import checker
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48834
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:
48834
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 |
48868
a52f5bfc9358
import-checker: assume absolute and use modern import checker
Gregory Szorc <gregory.szorc@gmail.com>
parents:
48834
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:
42813
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. |
34038
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33920
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:
33920
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 """ |
33890
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33877
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:
33877
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 |
30590
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:
42813
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:
42813
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:
42813
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:
42813
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:
42813
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:
42813
diff
changeset
|
455 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
456 'multiple imported names: %s', |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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 |
30590
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: |
30590
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:
42813
diff
changeset
|
468 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
470 ) |
25703
1a6a117d0b95
import-checker: establish modern import convention
Gregory Szorc <gregory.szorc@gmail.com>
parents:
25702
diff
changeset
|
471 |
30590
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:
42813
diff
changeset
|
477 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
479 name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
480 seenlocal, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
492 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
494 name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
495 requirealias[name], |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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__': |
34038
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33920
diff
changeset
|
515 if not fullname or ( |
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33920
diff
changeset
|
516 fullname in stdlib_modules |
43596
0ad5d6c4bfad
import-checker: allow 'from typing import ...'
Yuya Nishihara <yuya@tcha.org>
parents:
43415
diff
changeset
|
517 # allow standard 'from typing import ...' style |
43954
303576116ac1
import-checker: allow all absolute imports of stdlib modules
Martin von Zweigbergk <martinvonz@google.com>
parents:
43596
diff
changeset
|
518 and fullname.startswith('.') |
34038
bc2535238de2
import-checker: allow relative import a module being checked
Jun Wu <quark@fb.com>
parents:
33920
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:
42813
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:
42813
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:
42813
diff
changeset
|
531 symbols = ( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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: |
32419
d02888308235
import-checker: add a way to directly import certain symbols
Siddharth Agarwal <sid0@fb.com>
parents:
32374
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:
32374
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:
42813
diff
changeset
|
539 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
541 ', '.join(symbols), |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
542 fullname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
546 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
diff
changeset
|
556 if ( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
557 node.level in seenlevels |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
559 ): |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
560 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
diff
changeset
|
566 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
diff
changeset
|
578 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
580 fullname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
581 n.name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
582 lastentryname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
588 yield msg( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
590 n.name, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
591 fullname, |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
592 requirealias[n.name], |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
593 ) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
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:
42813
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:
42813
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:
42813
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 |
33877
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33876
diff
changeset
|
656 >>> def _forcestr(thing): |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33876
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:
33876
diff
changeset
|
658 ... return thing.decode('ascii') |
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33876
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): |
33877
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33876
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:
33876
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:
33876
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 = [ |
42388
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 ... ] |
33877
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33876
diff
changeset
|
675 >>> test(b"example.t", lines) |
40095
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
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:
39329
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:
39329
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 """ |
40095
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
diff
changeset
|
681 errors = [] |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
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:
39329
diff
changeset
|
683 if not name: |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
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:
39329
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:
39329
diff
changeset
|
686 name = 'doctest.py' |
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
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:
39329
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:
39329
diff
changeset
|
689 # yields "starts - 1". |
40480
99d5424eedc8
contrib: fix import-checker to not b'' module names on Python 3
Augie Fackler <augie@google.com>
parents:
40095
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:
40095
diff
changeset
|
691 modname = modname.decode('utf8') |
40095
7288838bec1f
import-checker: use testparseutil.embedded() to centralize detection logic
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
39329
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:
42813
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'): |
33877
bcf53149ebce
contrib: make import checker always think in terms of bytes
Augie Fackler <raf@durin42.com>
parents:
33876
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): |
40481
90517fad4293
contrib: tweak import-checker to always use bytes for module names
Augie Fackler <augie@google.com>
parents:
40480
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:
42813
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()) |
32508
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32507
diff
changeset
|
727 localmodpaths = {} |
20036 | 728 used_imports = {} |
729 any_errors = False | |
730 for source_path in argv[1:]: | |
32374
194b0f781132
import-checker: drop workaround for pure modules
Yuya Nishihara <yuya@tcha.org>
parents:
32372
diff
changeset
|
731 modname = dotted_name_of_path(source_path) |
32508
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32507
diff
changeset
|
732 localmodpaths[modname] = source_path |
32509
a025ec43856c
import-checker: guess names of C extension modules
Yuya Nishihara <yuya@tcha.org>
parents:
32508
diff
changeset
|
733 localmods = populateextmods(localmodpaths) |
32508
4c712b90c60a
import-checker: convert localmods to a set of module names
Yuya Nishihara <yuya@tcha.org>
parents:
32507
diff
changeset
|
734 for localmodname, source_path in sorted(localmodpaths.items()): |
33890
3de9a2df6411
contrib: have import-checker work mostly with native strings for mod names
Augie Fackler <raf@durin42.com>
parents:
33877
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:
33877
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:
33877
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:
42813
diff
changeset
|
741 imported_modules( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
743 ) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
diff
changeset
|
744 ) |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
746 modname, src, localmods |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
diff
changeset
|
751 print( |
57875cf423c9
style: run a patched black on a subset of mercurial
Augie Fackler <augie@google.com>
parents:
42813
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:
42813
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:
42813
diff
changeset
|
769 |
20036 | 770 if __name__ == '__main__': |
771 sys.exit(int(main(sys.argv))) |