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