summaryrefslogtreecommitdiffstats
path: root/tools/lint/python/check_compat.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtools/lint/python/check_compat.py87
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)