1"""Parser for future statements
2
3"""
4
5from compiler import ast, walk
6
7def is_future(stmt):
8    """Return true if statement is a well-formed future statement"""
9    if not isinstance(stmt, ast.From):
10        return 0
11    if stmt.modname == "__future__":
12        return 1
13    else:
14        return 0
15
16class FutureParser:
17
18    features = ("nested_scopes", "generators", "division",
19                "absolute_import", "with_statement", "print_function",
20                "unicode_literals")
21
22    def __init__(self):
23        self.found = {} # set
24
25    def visitModule(self, node):
26        stmt = node.node
27        for s in stmt.nodes:
28            if not self.check_stmt(s):
29                break
30
31    def check_stmt(self, stmt):
32        if is_future(stmt):
33            for name, asname in stmt.names:
34                if name in self.features:
35                    self.found[name] = 1
36                else:
37                    raise SyntaxError, \
38                          "future feature %s is not defined" % name
39            stmt.valid_future = 1
40            return 1
41        return 0
42
43    def get_features(self):
44        """Return list of features enabled by future statements"""
45        return self.found.keys()
46
47class BadFutureParser:
48    """Check for invalid future statements"""
49
50    def visitFrom(self, node):
51        if hasattr(node, 'valid_future'):
52            return
53        if node.modname != "__future__":
54            return
55        raise SyntaxError, "invalid future statement " + repr(node)
56
57def find_futures(node):
58    p1 = FutureParser()
59    p2 = BadFutureParser()
60    walk(node, p1)
61    walk(node, p2)
62    return p1.get_features()
63
64if __name__ == "__main__":
65    import sys
66    from compiler import parseFile, walk
67
68    for file in sys.argv[1:]:
69        print file
70        tree = parseFile(file)
71        v = FutureParser()
72        walk(tree, v)
73        print v.found
74        print
75