##// END OF EJS Templates
check: check modules in hgdemandimport...
Siddharth Agarwal -
r32421:778dc37c default
parent child Browse files
Show More
@@ -1,95 +1,96 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # check-py3-compat - check Python 3 compatibility of Mercurial files
3 # check-py3-compat - check Python 3 compatibility of Mercurial files
4 #
4 #
5 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
5 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 from __future__ import absolute_import, print_function
10 from __future__ import absolute_import, print_function
11
11
12 import ast
12 import ast
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
17
18 def check_compat_py2(f):
18 def check_compat_py2(f):
19 """Check Python 3 compatibility for a file with Python 2"""
19 """Check Python 3 compatibility for a file with Python 2"""
20 with open(f, 'rb') as fh:
20 with open(f, 'rb') as fh:
21 content = fh.read()
21 content = fh.read()
22 root = ast.parse(content)
22 root = ast.parse(content)
23
23
24 # Ignore empty files.
24 # Ignore empty files.
25 if not root.body:
25 if not root.body:
26 return
26 return
27
27
28 futures = set()
28 futures = set()
29 haveprint = False
29 haveprint = False
30 for node in ast.walk(root):
30 for node in ast.walk(root):
31 if isinstance(node, ast.ImportFrom):
31 if isinstance(node, ast.ImportFrom):
32 if node.module == '__future__':
32 if node.module == '__future__':
33 futures |= set(n.name for n in node.names)
33 futures |= set(n.name for n in node.names)
34 elif isinstance(node, ast.Print):
34 elif isinstance(node, ast.Print):
35 haveprint = True
35 haveprint = True
36
36
37 if 'absolute_import' not in futures:
37 if 'absolute_import' not in futures:
38 print('%s not using absolute_import' % f)
38 print('%s not using absolute_import' % f)
39 if haveprint and 'print_function' not in futures:
39 if haveprint and 'print_function' not in futures:
40 print('%s requires print_function' % f)
40 print('%s requires print_function' % f)
41
41
42 def check_compat_py3(f):
42 def check_compat_py3(f):
43 """Check Python 3 compatibility of a file with Python 3."""
43 """Check Python 3 compatibility of a file with Python 3."""
44 with open(f, 'rb') as fh:
44 with open(f, 'rb') as fh:
45 content = fh.read()
45 content = fh.read()
46
46
47 try:
47 try:
48 ast.parse(content)
48 ast.parse(content)
49 except SyntaxError as e:
49 except SyntaxError as e:
50 print('%s: invalid syntax: %s' % (f, e))
50 print('%s: invalid syntax: %s' % (f, e))
51 return
51 return
52
52
53 # Try to import the module.
53 # Try to import the module.
54 # For now we only support mercurial.* and hgext.* modules because figuring
54 # For now we only support modules in packages because figuring out module
55 # out module paths for things not in a package can be confusing.
55 # paths for things not in a package can be confusing.
56 if f.startswith(('hgext/', 'mercurial/')) and not f.endswith('__init__.py'):
56 if (f.startswith(('hgdemandimport/', 'hgext/', 'mercurial/'))
57 and not f.endswith('__init__.py')):
57 assert f.endswith('.py')
58 assert f.endswith('.py')
58 name = f.replace('/', '.')[:-3]
59 name = f.replace('/', '.')[:-3]
59 try:
60 try:
60 importlib.import_module(name)
61 importlib.import_module(name)
61 except Exception as e:
62 except Exception as e:
62 exc_type, exc_value, tb = sys.exc_info()
63 exc_type, exc_value, tb = sys.exc_info()
63 # We walk the stack and ignore frames from our custom importer,
64 # We walk the stack and ignore frames from our custom importer,
64 # import mechanisms, and stdlib modules. This kinda/sorta
65 # import mechanisms, and stdlib modules. This kinda/sorta
65 # emulates CPython behavior in import.c while also attempting
66 # emulates CPython behavior in import.c while also attempting
66 # to pin blame on a Mercurial file.
67 # to pin blame on a Mercurial file.
67 for frame in reversed(traceback.extract_tb(tb)):
68 for frame in reversed(traceback.extract_tb(tb)):
68 if frame.name == '_call_with_frames_removed':
69 if frame.name == '_call_with_frames_removed':
69 continue
70 continue
70 if 'importlib' in frame.filename:
71 if 'importlib' in frame.filename:
71 continue
72 continue
72 if 'mercurial/__init__.py' in frame.filename:
73 if 'mercurial/__init__.py' in frame.filename:
73 continue
74 continue
74 if frame.filename.startswith(sys.prefix):
75 if frame.filename.startswith(sys.prefix):
75 continue
76 continue
76 break
77 break
77
78
78 if frame.filename:
79 if frame.filename:
79 filename = os.path.basename(frame.filename)
80 filename = os.path.basename(frame.filename)
80 print('%s: error importing: <%s> %s (error at %s:%d)' % (
81 print('%s: error importing: <%s> %s (error at %s:%d)' % (
81 f, type(e).__name__, e, filename, frame.lineno))
82 f, type(e).__name__, e, filename, frame.lineno))
82 else:
83 else:
83 print('%s: error importing module: <%s> %s (line %d)' % (
84 print('%s: error importing module: <%s> %s (line %d)' % (
84 f, type(e).__name__, e, frame.lineno))
85 f, type(e).__name__, e, frame.lineno))
85
86
86 if __name__ == '__main__':
87 if __name__ == '__main__':
87 if sys.version_info[0] == 2:
88 if sys.version_info[0] == 2:
88 fn = check_compat_py2
89 fn = check_compat_py2
89 else:
90 else:
90 fn = check_compat_py3
91 fn = check_compat_py3
91
92
92 for f in sys.argv[1:]:
93 for f in sys.argv[1:]:
93 fn(f)
94 fn(f)
94
95
95 sys.exit(0)
96 sys.exit(0)
@@ -1,28 +1,28 b''
1 #require test-repo
1 #require test-repo
2
2
3 $ . "$TESTDIR/helpers-testrepo.sh"
3 $ . "$TESTDIR/helpers-testrepo.sh"
4
4
5 $ cat <<'EOF' > scanhelptopics.py
5 $ cat <<'EOF' > scanhelptopics.py
6 > from __future__ import absolute_import, print_function
6 > from __future__ import absolute_import, print_function
7 > import re
7 > import re
8 > import sys
8 > import sys
9 > if sys.platform == "win32":
9 > if sys.platform == "win32":
10 > import os, msvcrt
10 > import os, msvcrt
11 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
11 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
12 > topics = set()
12 > topics = set()
13 > topicre = re.compile(r':hg:`help ([a-z0-9\-.]+)`')
13 > topicre = re.compile(r':hg:`help ([a-z0-9\-.]+)`')
14 > for fname in sys.argv:
14 > for fname in sys.argv:
15 > with open(fname) as f:
15 > with open(fname) as f:
16 > topics.update(m.group(1) for m in topicre.finditer(f.read()))
16 > topics.update(m.group(1) for m in topicre.finditer(f.read()))
17 > for s in sorted(topics):
17 > for s in sorted(topics):
18 > print(s)
18 > print(s)
19 > EOF
19 > EOF
20
20
21 $ cd "$TESTDIR"/..
21 $ cd "$TESTDIR"/..
22
22
23 Check if ":hg:`help TOPIC`" is valid:
23 Check if ":hg:`help TOPIC`" is valid:
24 (use "xargs -n1 -t" to see which help commands are executed)
24 (use "xargs -n1 -t" to see which help commands are executed)
25
25
26 $ hg files 'glob:{hgext,mercurial}/**/*.py' | sed 's|\\|/|g' \
26 $ hg files 'glob:{hgdemandimport,hgext,mercurial}/**/*.py' | sed 's|\\|/|g' \
27 > | xargs python "$TESTTMP/scanhelptopics.py" \
27 > | xargs python "$TESTTMP/scanhelptopics.py" \
28 > | xargs -n1 hg help > /dev/null
28 > | xargs -n1 hg help > /dev/null
@@ -1,19 +1,19 b''
1 #require test-repo pylint hg10
1 #require test-repo pylint hg10
2
2
3 Run pylint for known rules we care about.
3 Run pylint for known rules we care about.
4 -----------------------------------------
4 -----------------------------------------
5
5
6 There should be no recorded failures; fix the codebase before introducing a
6 There should be no recorded failures; fix the codebase before introducing a
7 new check.
7 new check.
8
8
9 Current checks:
9 Current checks:
10 - W0102: no mutable default argument
10 - W0102: no mutable default argument
11
11
12 $ touch $TESTTMP/fakerc
12 $ touch $TESTTMP/fakerc
13 $ pylint --rcfile=$TESTTMP/fakerc --disable=all \
13 $ pylint --rcfile=$TESTTMP/fakerc --disable=all \
14 > --enable=W0102 --reports=no \
14 > --enable=W0102 --reports=no \
15 > mercurial hgext hgext3rd
15 > mercurial hgdemandimport hgext hgext3rd
16 (?)
16 (?)
17 ------------------------------------ (?)
17 ------------------------------------ (?)
18 Your code has been rated at 10.00/10 (?)
18 Your code has been rated at 10.00/10 (?)
19 (?)
19 (?)
General Comments 0
You need to be logged in to leave comments. Login now