<s> import ast <EOL> from collections import defaultdict , deque <EOL> from funcy import cached_property , print_exits , any , icat , iterate , takewhile <EOL> from . asttools import nodes_str , is_write , ast_eval <EOL> import __builtin__ <EOL> BUILTINS = set ( dir ( __builtin__ ) ) <EOL> GLOBALS = BUILTINS | { '<STR_LIT>' , '<STR_LIT>' } <EOL> class Scope ( object ) : <EOL> def __init__ ( self , parent , node ) : <EOL> self . parent = parent <EOL> if parent : <EOL> parent . children . append ( self ) <EOL> self . children = [ ] <EOL> self . node = node <EOL> self . names = defaultdict ( list ) <EOL> self . unscoped_names = defaultdict ( list ) <EOL> self . global_names = set ( ) <EOL> self . wildcards = [ ] <EOL> @ cached_property <EOL> def module ( self ) : <EOL> scope = self <EOL> while not scope . is_module : <EOL> scope = scope . parent <EOL> return scope <EOL> @ property <EOL> def is_module ( self ) : <EOL> return isinstance ( self . node , ast . Module ) <EOL> @ property <EOL> def is_class ( self ) : <EOL> return isinstance ( self . node , ast . ClassDef ) <EOL> @ property <EOL> def has_wildcards ( self ) : <EOL> parents = takewhile ( bool , iterate ( lambda s : s . parent , self ) ) <EOL> return any ( s . wildcards for s in parents ) <EOL> @ cached_property <EOL> def exports ( self ) : <EOL> if not self . is_module : <EOL> return [ ] <EOL> if '<STR_LIT>' not in self . names : <EOL> return None <EOL> exports_node = self . names [ '<STR_LIT>' ] [ <NUM_LIT:0> ] <EOL> assign = exports_node . up <EOL> if not isinstance ( assign , ast . Assign ) or len ( assign . targets ) != <NUM_LIT:1> : <EOL> print "<STR_LIT>" <EOL> return None <EOL> try : <EOL> return ast_eval ( assign . value ) <EOL> except ValueError : <EOL> print "<STR_LIT>" <EOL> return None <EOL> def add ( self , name , node ) : <EOL> is_param = isinstance ( node , ast . Name ) and isinstance ( node . ctx , ast . Param ) <EOL> if is_param or name in self . names or self . is_module : <EOL> self . names [ name ] . append ( node ) <EOL> else : <EOL> self . unscoped_names [ name ] . append ( node ) <EOL> node . in_scope = self <EOL> def make_global ( self , names ) : <EOL> self . global_names . update ( names ) <EOL> def resolve ( self ) : <EOL> for name in self . global_names : <EOL> nodes = self . unscoped_names . pop ( name , [ ] ) <EOL> self . module . names [ name ] . extend ( nodes ) <EOL> for name , nodes in list ( self . unscoped_names . items ( ) ) : <EOL> if self . is_module or any ( is_write , nodes ) : <EOL> self . names [ name ] . extend ( nodes ) <EOL> self . unscoped_names . pop ( name ) <EOL> if not self . is_class : <EOL> for scope in self . walk_scopes ( ) : <EOL> self . _resolve_unscoped ( scope ) <EOL> def _resolve_unscoped ( self , from_scope ) : <EOL> for name , nodes in list ( from_scope . unscoped_names . items ( ) ) : <EOL> if name in self . names or self . is_global ( name ) : <EOL> self . names [ name ] . extend ( nodes ) <EOL> from_scope . unscoped_names . pop ( name ) <EOL> elif self . is_module : <EOL> from_scope . names [ name ] . extend ( nodes ) <EOL> from_scope . unscoped_names . pop ( name ) <EOL> def walk_scopes ( self ) : <EOL> yield self <EOL> for child in self . children : <EOL> for scope in child . walk_scopes ( ) : <EOL> yield scope <EOL> def walk ( self ) : <EOL> for name , nodes in self . names . items ( ) : <EOL> yield self , name , nodes <EOL> for child in self . children : <EOL> for scope , name , nodes in child . walk ( ) : <EOL> yield scope , name , nodes <EOL> def is_global ( self , name ) : <EOL> return self . is_module and name in GLOBALS <EOL> def dump ( self , indent = '<STR_LIT>' ) : <EOL> name = self . node . __class__ . __name__ <EOL> if hasattr ( self . node , '<STR_LIT:name>' ) : <EOL> name += '<STR_LIT:U+0020>' + self . node . name <EOL> if hasattr ( self . node , '<STR_LIT>' ) : <EOL> name += '<STR_LIT>' % self . node . lineno <EOL> title = indent + '<STR_LIT>' + name <EOL> names = '<STR_LIT:\n>' . join ( indent + '<STR_LIT>' % ( name , nodes_str ( nodes ) ) <EOL> for name , nodes in sorted ( self . names . items ( ) ) ) <EOL> unscoped = '<STR_LIT:\n>' . join ( indent + '<STR_LIT>' % ( name , nodes_str ( nodes ) ) <EOL> for name , nodes in sorted ( self . unscoped_names . items ( ) ) ) <EOL> children = '<STR_LIT>' . join ( c . dump ( indent + '<STR_LIT:U+0020>' ) for c in self . children ) <EOL> return '<STR_LIT:\n>' . join ( [ title , names , unscoped , children ] ) <EOL> def __str__ ( self ) : <EOL> return self . dump ( ) <EOL> class TreeLinker ( ast . NodeVisitor ) : <EOL> def __init__ ( self ) : <EOL> self . stack = deque ( ) <EOL> def visit ( self , node ) : <EOL> if self . stack : <EOL> node . up = self . stack [ - <NUM_LIT:1> ] <EOL> self . stack . append ( node ) <EOL> self . generic_visit ( node ) <EOL> self . stack . pop ( ) <EOL> class ScopeBuilder ( ast . NodeVisitor ) : <EOL> def __init__ ( self ) : <EOL> self . scopes = deque ( ) <EOL> def visit_all ( self , * node_lists ) : <EOL> for node in icat ( node_lists ) : <EOL> self . visit ( node ) <EOL> @ property <EOL> def scope ( self ) : <EOL> if self . scopes : <EOL> return self . scopes [ - <NUM_LIT:1> ] <EOL> else : <EOL> return None <EOL> def push_scope ( self , node ) : <EOL> node . scope = Scope ( self . scope , node ) <EOL> self . scopes . append ( node . scope ) <EOL> def pop_scope ( self ) : <EOL> self . scope . resolve ( ) <EOL> self . scopes . pop ( ) <EOL> def visit_Module ( self , node ) : <EOL> self . push_scope ( node ) <EOL> self . generic_visit ( node ) <EOL> self . pop_scope ( ) <EOL> def visit_Import ( self , node ) : <EOL> for alias in node . names : <EOL> name = alias . asname or alias . name <EOL> if name == '<STR_LIT:*>' : <EOL> if not self . scope . is_module : <EOL> print '<STR_LIT>' <EOL> self . scope . wildcards . append ( node ) <EOL> else : <EOL> name = name . split ( '<STR_LIT:.>' ) [ <NUM_LIT:0> ] <EOL> self . scope . add ( name , node ) <EOL> def visit_ImportFrom ( self , node ) : <EOL> if node . module != '<STR_LIT>' : <EOL> self . visit_Import ( node ) <EOL> def visit_ClassDef ( self , node ) : <EOL> self . scope . add ( node . name , node ) <EOL> self . visit_all ( node . decorator_list , node . bases ) <EOL> self . push_scope ( node ) <EOL> self . visit_all ( node . body ) <EOL> self . pop_scope ( ) <EOL> def visit_FunctionDef ( self , node ) : <EOL> self . scope . add ( node . name , node ) <EOL> self . visit_all ( node . decorator_list , node . args . defaults ) <EOL> self . push_scope ( node ) <EOL> self . visit_all ( node . args . args , node . body ) <EOL> node . args . lineno = node . lineno <EOL> node . args . col_offset = node . col_offset <EOL> if node . args . vararg : <EOL> self . scope . add ( node . args . vararg , node . args ) <EOL> if node . args . kwarg : <EOL> self . scope . add ( node . args . kwarg , node . args ) <EOL> self . pop_scope ( ) <EOL> def visit_Lambda ( self , node ) : <EOL> self . push_scope ( node ) <EOL> self . visit_all ( node . args . args ) <EOL> node . args . lineno = node . lineno <EOL> node . args . col_offset = node . col_offset <EOL> if node . args . vararg : <EOL> self . scope . add ( node . args . vararg , node . args ) <EOL> if node . args . kwarg : <EOL> self . scope . add ( node . args . kwarg , node . args ) <EOL> self . visit ( node . body ) <EOL> self . pop_scope ( ) <EOL> def visit_Name ( self , node ) : <EOL> self . scope . add ( node . id , node ) <EOL> def visit_Global ( self , node ) : <EOL> self . scope . make_global ( node . names ) <EOL> def fill_scopes ( tree ) : <EOL> TreeLinker ( ) . visit ( tree ) <EOL> ScopeBuilder ( ) . visit ( tree ) </s>
