##// END OF EJS Templates
py3: make check-py3-compat.py load modules in standard manner...
Yuya Nishihara -
r30094:f701fffd default
parent child Browse files
Show More
@@ -1,96 +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 imp
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 mercurial.* and hgext.* modules because figuring
55 # out module paths for things not in a package can be confusing.
55 # out module 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(('hgext/', 'mercurial/')) and not f.endswith('__init__.py'):
57 assert f.endswith('.py')
57 assert f.endswith('.py')
58 name = f.replace('/', '.')[:-3].replace('.pure.', '.')
58 name = f.replace('/', '.')[:-3].replace('.pure.', '.')
59 with open(f, 'r') as fh:
59 if True:
60 try:
60 try:
61 imp.load_module(name, fh, f, ('py', 'r', imp.PY_SOURCE))
61 importlib.import_module(name)
62 except Exception as e:
62 except Exception as e:
63 exc_type, exc_value, tb = sys.exc_info()
63 exc_type, exc_value, tb = sys.exc_info()
64 # We walk the stack and ignore frames from our custom importer,
64 # We walk the stack and ignore frames from our custom importer,
65 # import mechanisms, and stdlib modules. This kinda/sorta
65 # import mechanisms, and stdlib modules. This kinda/sorta
66 # emulates CPython behavior in import.c while also attempting
66 # emulates CPython behavior in import.c while also attempting
67 # to pin blame on a Mercurial file.
67 # to pin blame on a Mercurial file.
68 for frame in reversed(traceback.extract_tb(tb)):
68 for frame in reversed(traceback.extract_tb(tb)):
69 if frame.name == '_call_with_frames_removed':
69 if frame.name == '_call_with_frames_removed':
70 continue
70 continue
71 if 'importlib' in frame.filename:
71 if 'importlib' in frame.filename:
72 continue
72 continue
73 if 'mercurial/__init__.py' in frame.filename:
73 if 'mercurial/__init__.py' in frame.filename:
74 continue
74 continue
75 if frame.filename.startswith(sys.prefix):
75 if frame.filename.startswith(sys.prefix):
76 continue
76 continue
77 break
77 break
78
78
79 if frame.filename:
79 if frame.filename:
80 filename = os.path.basename(frame.filename)
80 filename = os.path.basename(frame.filename)
81 print('%s: error importing: <%s> %s (error at %s:%d)' % (
81 print('%s: error importing: <%s> %s (error at %s:%d)' % (
82 f, type(e).__name__, e, filename, frame.lineno))
82 f, type(e).__name__, e, filename, frame.lineno))
83 else:
83 else:
84 print('%s: error importing module: <%s> %s (line %d)' % (
84 print('%s: error importing module: <%s> %s (line %d)' % (
85 f, type(e).__name__, e, frame.lineno))
85 f, type(e).__name__, e, frame.lineno))
86
86
87 if __name__ == '__main__':
87 if __name__ == '__main__':
88 if sys.version_info[0] == 2:
88 if sys.version_info[0] == 2:
89 fn = check_compat_py2
89 fn = check_compat_py2
90 else:
90 else:
91 fn = check_compat_py3
91 fn = check_compat_py3
92
92
93 for f in sys.argv[1:]:
93 for f in sys.argv[1:]:
94 fn(f)
94 fn(f)
95
95
96 sys.exit(0)
96 sys.exit(0)
@@ -1,63 +1,49 b''
1 #require test-repo
1 #require test-repo
2
2
3 $ . "$TESTDIR/helpers-testrepo.sh"
3 $ . "$TESTDIR/helpers-testrepo.sh"
4 $ cd "$TESTDIR"/..
4 $ cd "$TESTDIR"/..
5
5
6 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
6 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
7 hgext/fsmonitor/pywatchman/__init__.py not using absolute_import
7 hgext/fsmonitor/pywatchman/__init__.py not using absolute_import
8 hgext/fsmonitor/pywatchman/__init__.py requires print_function
8 hgext/fsmonitor/pywatchman/__init__.py requires print_function
9 hgext/fsmonitor/pywatchman/capabilities.py not using absolute_import
9 hgext/fsmonitor/pywatchman/capabilities.py not using absolute_import
10 hgext/fsmonitor/pywatchman/pybser.py not using absolute_import
10 hgext/fsmonitor/pywatchman/pybser.py not using absolute_import
11 i18n/check-translation.py not using absolute_import
11 i18n/check-translation.py not using absolute_import
12 setup.py not using absolute_import
12 setup.py not using absolute_import
13 tests/test-demandimport.py not using absolute_import
13 tests/test-demandimport.py not using absolute_import
14
14
15 #if py3exe
15 #if py3exe
16 $ hg files 'set:(**.py) - grep(pygments)' | sed 's|\\|/|g' \
16 $ hg files 'set:(**.py) - grep(pygments)' | sed 's|\\|/|g' \
17 > | xargs $PYTHON3 contrib/check-py3-compat.py \
17 > | xargs $PYTHON3 contrib/check-py3-compat.py \
18 > | sed 's/[0-9][0-9]*)$/*)/'
18 > | sed 's/[0-9][0-9]*)$/*)/'
19 hgext/convert/bzr.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at bzr.py:*)
19 hgext/convert/bzr.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
20 hgext/convert/convcmd.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at convcmd.py:*)
20 hgext/convert/convcmd.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
21 hgext/convert/cvs.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at cvs.py:*)
21 hgext/convert/subversion.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
22 hgext/convert/darcs.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at darcs.py:*)
22 hgext/convert/transport.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
23 hgext/convert/filemap.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at filemap.py:*)
23 hgext/fsmonitor/pywatchman/capabilities.py: error importing: <ImportError> No module named 'pybser' (error at __init__.py:*)
24 hgext/convert/git.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at git.py:*)
24 hgext/fsmonitor/pywatchman/pybser.py: error importing: <ImportError> No module named 'pybser' (error at __init__.py:*)
25 hgext/convert/gnuarch.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at gnuarch.py:*)
25 hgext/fsmonitor/watchmanclient.py: error importing: <ImportError> No module named 'pybser' (error at __init__.py:*)
26 hgext/convert/hg.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at hg.py:*)
26 hgext/journal.py: error importing: <ValueError> Type names and field names must be valid identifiers: "b'journalentry'" (error at journal.py:*)
27 hgext/convert/monotone.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at monotone.py:*)
27 hgext/largefiles/basestore.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
28 hgext/convert/p4.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at p4.py:*)
28 hgext/largefiles/lfcommands.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
29 hgext/convert/subversion.py: error importing: <SystemError> Parent module 'hgext.convert' not loaded, cannot perform relative import (error at subversion.py:*)
29 hgext/largefiles/lfutil.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
30 hgext/convert/transport.py: error importing: <ImportError> No module named 'svn.client' (error at transport.py:*)
30 hgext/largefiles/localstore.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
31 hgext/fsmonitor/watchmanclient.py: error importing: <SystemError> Parent module 'hgext.fsmonitor' not loaded, cannot perform relative import (error at watchmanclient.py:*)
31 hgext/largefiles/overrides.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
32 hgext/journal.py: error importing: <SystemError> Parent module 'hgext' not loaded, cannot perform relative import (error at journal.py:*)
32 hgext/largefiles/proto.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
33 hgext/largefiles/basestore.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at basestore.py:*)
33 hgext/largefiles/remotestore.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
34 hgext/largefiles/lfcommands.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at lfcommands.py:*)
34 hgext/largefiles/reposetup.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
35 hgext/largefiles/localstore.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at localstore.py:*)
35 hgext/largefiles/storefactory.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
36 hgext/largefiles/overrides.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at overrides.py:*)
36 hgext/largefiles/uisetup.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
37 hgext/largefiles/proto.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at proto.py:*)
37 hgext/largefiles/wirestore.py: error importing: <SyntaxError> cannot mix bytes and nonbytes literals (subversion.py, line 533) (error at convcmd.py:*)
38 hgext/largefiles/remotestore.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at remotestore.py:*)
38 hgext/mq.py: error importing: <TypeError> __import__() argument 1 must be str, not bytes (error at extensions.py:*)
39 hgext/largefiles/reposetup.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at reposetup.py:*)
40 hgext/largefiles/storefactory.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at storefactory.py:*)
41 hgext/largefiles/uisetup.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at uisetup.py:*)
42 hgext/largefiles/wirestore.py: error importing: <SystemError> Parent module 'hgext.largefiles' not loaded, cannot perform relative import (error at wirestore.py:*)
43 hgext/mq.py: error importing: <TypeError> startswith first arg must be str or a tuple of str, not bytes (error at extensions.py:*)
44 hgext/rebase.py: error importing: <TypeError> Can't convert 'bytes' object to str implicitly (error at registrar.py:*)
45 hgext/record.py: error importing: <KeyError> '^commit|ci' (error at record.py:*)
46 hgext/shelve.py: error importing: <SystemError> Parent module 'hgext' not loaded, cannot perform relative import (error at shelve.py:*)
47 hgext/transplant.py: error importing: <TypeError> Can't convert 'bytes' object to str implicitly (error at registrar.py:*)
48 mercurial/encoding.py: error importing: <TypeError> bytes expected, not str (error at encoding.py:*)
49 mercurial/fileset.py: error importing: <TypeError> Can't convert 'bytes' object to str implicitly (error at registrar.py:*)
50 mercurial/i18n.py: error importing: <TypeError> bytes expected, not str (error at i18n.py:*)
51 mercurial/revset.py: error importing: <AttributeError> 'dict' object has no attribute 'iteritems' (error at revset.py:*)
52 mercurial/scmwindows.py: error importing: <ImportError> No module named 'winreg' (error at scmwindows.py:*)
39 mercurial/scmwindows.py: error importing: <ImportError> No module named 'winreg' (error at scmwindows.py:*)
53 mercurial/store.py: error importing: <TypeError> Can't convert 'bytes' object to str implicitly (error at store.py:*)
54 mercurial/win32.py: error importing: <ImportError> No module named 'msvcrt' (error at win32.py:*)
40 mercurial/win32.py: error importing: <ImportError> No module named 'msvcrt' (error at win32.py:*)
55 mercurial/windows.py: error importing: <ImportError> No module named 'msvcrt' (error at windows.py:*)
41 mercurial/windows.py: error importing: <ImportError> No module named 'msvcrt' (error at windows.py:*)
56
42
57 #endif
43 #endif
58
44
59 #if py3exe py3pygments
45 #if py3exe py3pygments
60 $ hg files 'set:(**.py) and grep(pygments)' | sed 's|\\|/|g' \
46 $ hg files 'set:(**.py) and grep(pygments)' | sed 's|\\|/|g' \
61 > | xargs $PYTHON3 contrib/check-py3-compat.py \
47 > | xargs $PYTHON3 contrib/check-py3-compat.py \
62 > | sed 's/[0-9][0-9]*)$/*)/'
48 > | sed 's/[0-9][0-9]*)$/*)/'
63 #endif
49 #endif
General Comments 0
You need to be logged in to leave comments. Login now