DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (5f2e62175414)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 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)