##// END OF EJS Templates
status: Add some more tests...
status: Add some more tests Trying to improve coverage for various non-ovbious scenarios Differential Revision: https://phab.mercurial-scm.org/D10704

File last commit:

r46434:c102b704 default
r47954:df2bf38a default
Show More
check-py3-compat.py
122 lines | 4.1 KiB | text/x-python | PythonLexer
/ contrib / check-py3-compat.py
Gregory Szorc
global: use python3 in shebangs...
r46434 #!/usr/bin/env python3
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 #
# check-py3-compat - check Python 3 compatibility of Mercurial files
#
# Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import, print_function
import ast
Gregory Szorc
py3: remove delayed import of importlib...
r32280 import importlib
Gregory Szorc
tests: try to import modules with Python 3...
r28584 import os
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 import sys
Gregory Szorc
tests: try to import modules with Python 3...
r28584 import traceback
Gregory Szorc
check-py3-compat: manually format and print warnings...
r41696 import warnings
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
tests: perform an ast parse with Python 3...
r28583 def check_compat_py2(f):
"""Check Python 3 compatibility for a file with Python 2"""
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 with open(f, 'rb') as fh:
content = fh.read()
Yuya Nishihara
test: make check-py3-compat.py ignore empty code more reliably...
r28475 root = ast.parse(content)
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279
Gregory Szorc
contrib: ignore empty files in check-py3-compat.py
r27331 # Ignore empty files.
Yuya Nishihara
test: make check-py3-compat.py ignore empty code more reliably...
r28475 if not root.body:
Gregory Szorc
contrib: ignore empty files in check-py3-compat.py
r27331 return
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 futures = set()
haveprint = False
for node in ast.walk(root):
if isinstance(node, ast.ImportFrom):
if node.module == '__future__':
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 futures |= {n.name for n in node.names}
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 elif isinstance(node, ast.Print):
haveprint = True
if 'absolute_import' not in futures:
print('%s not using absolute_import' % f)
if haveprint and 'print_function' not in futures:
print('%s requires print_function' % f)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
tests: perform an ast parse with Python 3...
r28583 def check_compat_py3(f):
"""Check Python 3 compatibility of a file with Python 3."""
with open(f, 'rb') as fh:
content = fh.read()
try:
Gregory Szorc
check-py3-compat: provide filename to ast.parse()...
r41695 ast.parse(content, filename=f)
Gregory Szorc
tests: perform an ast parse with Python 3...
r28583 except SyntaxError as e:
print('%s: invalid syntax: %s' % (f, e))
return
Gregory Szorc
tests: try to import modules with Python 3...
r28584 # Try to import the module.
Siddharth Agarwal
check: check modules in hgdemandimport...
r32421 # For now we only support modules in packages because figuring out module
# paths for things not in a package can be confusing.
Augie Fackler
formatting: blacken the codebase...
r43346 if f.startswith(
('hgdemandimport/', 'hgext/', 'mercurial/')
) and not f.endswith('__init__.py'):
Gregory Szorc
tests: try to import modules with Python 3...
r28584 assert f.endswith('.py')
Yuya Nishihara
policy: eliminate ".pure." from module name only if marked as dual...
r32207 name = f.replace('/', '.')[:-3]
Yuya Nishihara
py3: remove superfluous indent from check-py3-compat.py
r30095 try:
importlib.import_module(name)
except Exception as e:
exc_type, exc_value, tb = sys.exc_info()
# We walk the stack and ignore frames from our custom importer,
# import mechanisms, and stdlib modules. This kinda/sorta
# emulates CPython behavior in import.c while also attempting
# to pin blame on a Mercurial file.
for frame in reversed(traceback.extract_tb(tb)):
if frame.name == '_call_with_frames_removed':
continue
if 'importlib' in frame.filename:
continue
if 'mercurial/__init__.py' in frame.filename:
continue
if frame.filename.startswith(sys.prefix):
continue
break
Gregory Szorc
tests: try to import modules with Python 3...
r28584
Yuya Nishihara
py3: remove superfluous indent from check-py3-compat.py
r30095 if frame.filename:
filename = os.path.basename(frame.filename)
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'%s: error importing: <%s> %s (error at %s:%d)'
% (f, type(e).__name__, e, filename, frame.lineno)
)
Yuya Nishihara
py3: remove superfluous indent from check-py3-compat.py
r30095 else:
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'%s: error importing module: <%s> %s (line %d)'
% (f, type(e).__name__, e, frame.lineno)
)
Gregory Szorc
tests: try to import modules with Python 3...
r28584
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 if __name__ == '__main__':
Gregory Szorc
tests: perform an ast parse with Python 3...
r28583 if sys.version_info[0] == 2:
fn = check_compat_py2
else:
Kyle Lippincott
tests: make check-py3-compat.py actually load the specified files correctly...
r45776 # check_compat_py3 will import every filename we specify as long as it
# starts with one of a few prefixes. It does this by converting
# specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and
# importing that. When running standalone (not as part of a test), this
# means we actually import the installed versions, not the files we just
# specified. When running as test-check-py3-compat.t, we technically
# would import the correct paths, but it's cleaner to have both cases
# use the same import logic.
sys.path.insert(0, '.')
Gregory Szorc
tests: perform an ast parse with Python 3...
r28583 fn = check_compat_py3
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279 for f in sys.argv[1:]:
Gregory Szorc
check-py3-compat: manually format and print warnings...
r41696 with warnings.catch_warnings(record=True) as warns:
fn(f)
for w in warns:
Augie Fackler
formatting: blacken the codebase...
r43346 print(
warnings.formatwarning(
w.message, w.category, w.filename, w.lineno
).rstrip()
)
Gregory Szorc
tests: add test for Python 3 compatibility...
r27279
sys.exit(0)