Mercurial > public > mercurial-scm > hg-stable
comparison contrib/check-py3-compat.py @ 48963:968b29a5a7fc
check-py3-compat: drop support for Python 2
We no longer support Python 2 so we can drop support for linting code
for Python 2 support.
This gets rid of the check for `from __future__`, enabling us to delete
those imports.
Differential Revision: https://phab.mercurial-scm.org/D12251
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sun, 20 Feb 2022 14:52:40 -0700 |
parents | c102b704edb5 |
children | 6000f5b25c9b |
comparison
equal
deleted
inserted
replaced
48962:79009cca491e | 48963:968b29a5a7fc |
---|---|
13 import importlib | 13 import importlib |
14 import os | 14 import os |
15 import sys | 15 import sys |
16 import traceback | 16 import traceback |
17 import warnings | 17 import warnings |
18 | |
19 | |
20 def check_compat_py2(f): | |
21 """Check Python 3 compatibility for a file with Python 2""" | |
22 with open(f, 'rb') as fh: | |
23 content = fh.read() | |
24 root = ast.parse(content) | |
25 | |
26 # Ignore empty files. | |
27 if not root.body: | |
28 return | |
29 | |
30 futures = set() | |
31 haveprint = False | |
32 for node in ast.walk(root): | |
33 if isinstance(node, ast.ImportFrom): | |
34 if node.module == '__future__': | |
35 futures |= {n.name for n in node.names} | |
36 elif isinstance(node, ast.Print): | |
37 haveprint = True | |
38 | |
39 if 'absolute_import' not in futures: | |
40 print('%s not using absolute_import' % f) | |
41 if haveprint and 'print_function' not in futures: | |
42 print('%s requires print_function' % f) | |
43 | 18 |
44 | 19 |
45 def check_compat_py3(f): | 20 def check_compat_py3(f): |
46 """Check Python 3 compatibility of a file with Python 3.""" | 21 """Check Python 3 compatibility of a file with Python 3.""" |
47 with open(f, 'rb') as fh: | 22 with open(f, 'rb') as fh: |
92 % (f, type(e).__name__, e, frame.lineno) | 67 % (f, type(e).__name__, e, frame.lineno) |
93 ) | 68 ) |
94 | 69 |
95 | 70 |
96 if __name__ == '__main__': | 71 if __name__ == '__main__': |
97 if sys.version_info[0] == 2: | 72 # check_compat_py3 will import every filename we specify as long as it |
98 fn = check_compat_py2 | 73 # starts with one of a few prefixes. It does this by converting |
99 else: | 74 # specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and |
100 # check_compat_py3 will import every filename we specify as long as it | 75 # importing that. When running standalone (not as part of a test), this |
101 # starts with one of a few prefixes. It does this by converting | 76 # means we actually import the installed versions, not the files we just |
102 # specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and | 77 # specified. When running as test-check-py3-compat.t, we technically |
103 # importing that. When running standalone (not as part of a test), this | 78 # would import the correct paths, but it's cleaner to have both cases |
104 # means we actually import the installed versions, not the files we just | 79 # use the same import logic. |
105 # specified. When running as test-check-py3-compat.t, we technically | 80 sys.path.insert(0, '.') |
106 # would import the correct paths, but it's cleaner to have both cases | |
107 # use the same import logic. | |
108 sys.path.insert(0, '.') | |
109 fn = check_compat_py3 | |
110 | 81 |
111 for f in sys.argv[1:]: | 82 for f in sys.argv[1:]: |
112 with warnings.catch_warnings(record=True) as warns: | 83 with warnings.catch_warnings(record=True) as warns: |
113 fn(f) | 84 check_compat_py3(f) |
114 | 85 |
115 for w in warns: | 86 for w in warns: |
116 print( | 87 print( |
117 warnings.formatwarning( | 88 warnings.formatwarning( |
118 w.message, w.category, w.filename, w.lineno | 89 w.message, w.category, w.filename, w.lineno |