library/compiler/future.py (62 lines of code) (raw):
# Portions copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
# pyre-unsafe
"""Parser for future statements
"""
from __future__ import print_function
import ast
from .visitor import ASTVisitor, walk
def is_future(stmt):
"""Return true if statement is a well-formed future statement"""
if not isinstance(stmt, ast.ImportFrom):
return 0
if stmt.module == "__future__":
return 1
else:
return 0
class FutureParser(ASTVisitor):
features = (
"nested_scopes",
"generators",
"division",
"absolute_import",
"with_statement",
"print_function",
"unicode_literals",
"generator_stop",
"barry_as_FLUFL",
"annotations",
)
def __init__(self):
super().__init__()
self.found = {} # set
def visitModule(self, node):
for s in node.body:
if isinstance(s, ast.Expr) and isinstance(s.value, ast.Str):
continue
if not self.check_stmt(s):
break
def check_stmt(self, stmt):
if is_future(stmt):
for alias in stmt.names:
name = alias.name
if name in self.features:
self.found[name] = 1
elif name == "braces":
raise SyntaxError("not a chance")
else:
raise SyntaxError("future feature %s is not defined" % name)
stmt.valid_future = 1
return 1
return 0
def get_features(self):
"""Return list of features enabled by future statements"""
return self.found.keys()
class BadFutureParser(ASTVisitor):
"""Check for invalid future statements"""
def visitImportFrom(self, node):
if hasattr(node, "valid_future"):
return
if node.module != "__future__":
return
raise SyntaxError(
"from __future__ imports must occur at the beginning of the file"
)
def find_futures(node):
p1 = FutureParser()
p2 = BadFutureParser()
walk(node, p1)
walk(node, p2)
return p1.get_features()