diff options
Diffstat (limited to '')
-rwxr-xr-x | tools/lint/python/check_compat.py | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/lint/python/check_compat.py b/tools/lint/python/check_compat.py new file mode 100755 index 0000000000..25a15fcedc --- /dev/null +++ b/tools/lint/python/check_compat.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import ast +import json +import sys + + +def parse_file(f): + with open(f, "rb") as fh: + content = fh.read() + try: + return ast.parse(content) + except SyntaxError as e: + err = { + "path": f, + "message": e.msg, + "lineno": e.lineno, + "column": e.offset, + "source": e.text, + "rule": "is-parseable", + } + print(json.dumps(err)) + + +def check_compat_py2(f): + """Check Python 2 and Python 3 compatibility for a file with Python 2""" + root = parse_file(f) + + # Ignore empty or un-parseable files. + if not root or not root.body: + return + + futures = set() + haveprint = False + future_lineno = 1 + may_have_relative_imports = False + for node in ast.walk(root): + if isinstance(node, ast.ImportFrom): + if node.module == "__future__": + future_lineno = node.lineno + futures |= set(n.name for n in node.names) + else: + may_have_relative_imports = True + elif isinstance(node, ast.Import): + may_have_relative_imports = True + elif isinstance(node, ast.Print): + haveprint = True + + err = { + "path": f, + "lineno": future_lineno, + "column": 1, + } + + if "absolute_import" not in futures and may_have_relative_imports: + err["rule"] = "require absolute_import" + err["message"] = "Missing from __future__ import absolute_import" + print(json.dumps(err)) + + if haveprint and "print_function" not in futures: + err["rule"] = "require print_function" + err["message"] = "Missing from __future__ import print_function" + print(json.dumps(err)) + + +def check_compat_py3(f): + """Check Python 3 compatibility of a file with Python 3.""" + parse_file(f) + + +if __name__ == "__main__": + if sys.version_info[0] == 2: + fn = check_compat_py2 + else: + fn = check_compat_py3 + + manifest = sys.argv[1] + with open(manifest, "r") as fh: + files = fh.read().splitlines() + + for f in files: + fn(f) + + sys.exit(0) |