##// END OF EJS Templates
tests: make check-py3-compat.py actually load the specified files correctly...
Kyle Lippincott -
r45776:4e5da64d default
parent child Browse files
Show More
@@ -1,113 +1,122 b''
1 1 #!/usr/bin/env python
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 # check_compat_py3 will import every filename we specify as long as it
101 # starts with one of a few prefixes. It does this by converting
102 # specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and
103 # importing that. When running standalone (not as part of a test), this
104 # means we actually import the installed versions, not the files we just
105 # specified. When running as test-check-py3-compat.t, we technically
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, '.')
100 109 fn = check_compat_py3
101 110
102 111 for f in sys.argv[1:]:
103 112 with warnings.catch_warnings(record=True) as warns:
104 113 fn(f)
105 114
106 115 for w in warns:
107 116 print(
108 117 warnings.formatwarning(
109 118 w.message, w.category, w.filename, w.lineno
110 119 ).rstrip()
111 120 )
112 121
113 122 sys.exit(0)
General Comments 0
You need to be logged in to leave comments. Login now