Created
September 7, 2017 21:40
-
-
Save nascheme/7153511559f776c61340065702152128 to your computer and use it in GitHub Desktop.
Use AST analysis to find which modules can be lazy imported
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import ast | |
import importlib.util | |
def safe_assign(value): | |
safe = {ast.Num, ast.NameConstant, ast.Str} | |
return type(value) in safe | |
class Transformer(ast.NodeTransformer): | |
def __init__(self, *args, **kwargs): | |
ast.NodeTransformer.__init__(self, *args, **kwargs) | |
self.is_lazy = True | |
self.force_lazy = False | |
self.imports = [] | |
def visit_Module(self, node): | |
for stmt in node.body: | |
if isinstance(stmt, ast.ImportFrom): | |
self.imports.append(stmt.module) | |
elif isinstance(stmt, ast.Import): | |
for alias in stmt.names: | |
self.imports.append(alias.name) | |
elif isinstance(stmt, ast.Assign): | |
targets = stmt.targets | |
if len(targets) == 1 and targets[0].id == '__lazy__': | |
self.force_lazy = True | |
else: | |
if not safe_assign(stmt.value): | |
print('assign', stmt.value) | |
self.is_lazy = False | |
elif isinstance(stmt, ast.FunctionDef): | |
pass | |
elif isinstance(stmt, ast.ClassDef): | |
pass | |
else: | |
print('non-lazy %r' % stmt) | |
self.is_lazy = False | |
return self.generic_visit(node) | |
def parse(buf, filename='<string>'): | |
if isinstance(buf, bytes): | |
buf = importlib.util.decode_source(buf) | |
try: | |
node = ast.parse(buf, filename) | |
except SyntaxError as e: | |
# set the filename attribute | |
raise SyntaxError(str(e), (filename, e.lineno, e.offset, e.text)) | |
t = Transformer() | |
t.visit(node) | |
return t.is_lazy, t.force_lazy, t.imports | |
def main(): | |
for fn in sys.argv[1:]: | |
with open(fn) as fp: | |
buf = fp.read() | |
is_lazy, force, imports = parse(buf) | |
print('lazy = %s force_lazy = %s' % (is_lazy, force)) | |
for name in imports: | |
print('import', name) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment