##// END OF EJS Templates
check-py3-compat: use an absolute path in sys.path...
av6 -
r50099:3f9125db stable
parent child Browse files
Show More
@@ -1,122 +1,122 b''
1 1 #!/usr/bin/env python3
2 2 #
3 3 # check-py3-compat - check Python 3 compatibility of Mercurial files
4 4 #
5 5 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 from __future__ import absolute_import, print_function
11 11
12 12 import ast
13 13 import importlib
14 14 import os
15 15 import sys
16 16 import traceback
17 17 import warnings
18 18
19 19
20 20 def check_compat_py2(f):
21 21 """Check Python 3 compatibility for a file with Python 2"""
22 22 with open(f, 'rb') as fh:
23 23 content = fh.read()
24 24 root = ast.parse(content)
25 25
26 26 # Ignore empty files.
27 27 if not root.body:
28 28 return
29 29
30 30 futures = set()
31 31 haveprint = False
32 32 for node in ast.walk(root):
33 33 if isinstance(node, ast.ImportFrom):
34 34 if node.module == '__future__':
35 35 futures |= {n.name for n in node.names}
36 36 elif isinstance(node, ast.Print):
37 37 haveprint = True
38 38
39 39 if 'absolute_import' not in futures:
40 40 print('%s not using absolute_import' % f)
41 41 if haveprint and 'print_function' not in futures:
42 42 print('%s requires print_function' % f)
43 43
44 44
45 45 def check_compat_py3(f):
46 46 """Check Python 3 compatibility of a file with Python 3."""
47 47 with open(f, 'rb') as fh:
48 48 content = fh.read()
49 49
50 50 try:
51 51 ast.parse(content, filename=f)
52 52 except SyntaxError as e:
53 53 print('%s: invalid syntax: %s' % (f, e))
54 54 return
55 55
56 56 # Try to import the module.
57 57 # For now we only support modules in packages because figuring out module
58 58 # paths for things not in a package can be confusing.
59 59 if f.startswith(
60 60 ('hgdemandimport/', 'hgext/', 'mercurial/')
61 61 ) and not f.endswith('__init__.py'):
62 62 assert f.endswith('.py')
63 63 name = f.replace('/', '.')[:-3]
64 64 try:
65 65 importlib.import_module(name)
66 66 except Exception as e:
67 67 exc_type, exc_value, tb = sys.exc_info()
68 68 # We walk the stack and ignore frames from our custom importer,
69 69 # import mechanisms, and stdlib modules. This kinda/sorta
70 70 # emulates CPython behavior in import.c while also attempting
71 71 # to pin blame on a Mercurial file.
72 72 for frame in reversed(traceback.extract_tb(tb)):
73 73 if frame.name == '_call_with_frames_removed':
74 74 continue
75 75 if 'importlib' in frame.filename:
76 76 continue
77 77 if 'mercurial/__init__.py' in frame.filename:
78 78 continue
79 79 if frame.filename.startswith(sys.prefix):
80 80 continue
81 81 break
82 82
83 83 if frame.filename:
84 84 filename = os.path.basename(frame.filename)
85 85 print(
86 86 '%s: error importing: <%s> %s (error at %s:%d)'
87 87 % (f, type(e).__name__, e, filename, frame.lineno)
88 88 )
89 89 else:
90 90 print(
91 91 '%s: error importing module: <%s> %s (line %d)'
92 92 % (f, type(e).__name__, e, frame.lineno)
93 93 )
94 94
95 95
96 96 if __name__ == '__main__':
97 97 if sys.version_info[0] == 2:
98 98 fn = check_compat_py2
99 99 else:
100 100 # check_compat_py3 will import every filename we specify as long as it
101 101 # starts with one of a few prefixes. It does this by converting
102 102 # specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and
103 103 # importing that. When running standalone (not as part of a test), this
104 104 # means we actually import the installed versions, not the files we just
105 105 # specified. When running as test-check-py3-compat.t, we technically
106 106 # would import the correct paths, but it's cleaner to have both cases
107 107 # use the same import logic.
108 sys.path.insert(0, '.')
108 sys.path.insert(0, os.getcwd())
109 109 fn = check_compat_py3
110 110
111 111 for f in sys.argv[1:]:
112 112 with warnings.catch_warnings(record=True) as warns:
113 113 fn(f)
114 114
115 115 for w in warns:
116 116 print(
117 117 warnings.formatwarning(
118 118 w.message, w.category, w.filename, w.lineno
119 119 ).rstrip()
120 120 )
121 121
122 122 sys.exit(0)
General Comments 0
You need to be logged in to leave comments. Login now