Advertisement
avisrivastava254084

Untitled

Sep 23rd, 2019
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.42 KB | None | 0 0
  1. import ast
  2. from collections import ChainMap
  3. from types import MappingProxyType as readonlydict
  4.  
  5.  
  6. class ModuleUseCollector(ast.NodeVisitor):
  7.     def __init__(self, modulename, package=''):
  8.         self.modulename = modulename
  9.         # used to resolve from ... import ... references
  10.         self.package = package
  11.         self.modulepackage, _, self.modulestem = modulename.rpartition('.')
  12.         # track scope namespaces, with a mapping of imported names (bound name to original)
  13.         # If a name references None it is used for a different purpose in that scope
  14.         # and so masks a name in the global namespace.
  15.         self.scopes = ChainMap()
  16.         self.used_at = []  # list of (name, alias, line) entries
  17.         print("{} is the self.modulepackage".format(self.modulepackage))
  18.  
  19.     def visit_FunctionDef(self, node):
  20.         self.scopes = self.scopes.new_child()
  21.         self.generic_visit(node)
  22.         self.scopes = self.scopes.parents
  23.  
  24.     def visit_Lambda(self, node):
  25.         # lambdas are just functions, albeit with no statements
  26.         self.visit_Function(node)
  27.  
  28.     def visit_ClassDef(self, node):
  29.         # class scope is a special local scope that is re-purposed to form
  30.         # the class attributes. By using a read-only dict proxy here this code
  31.         # we can expect an exception when a class body contains an import
  32.         # statement or uses names that'd mask an imported name.
  33.         self.scopes = self.scopes.new_child(readonlydict({}))
  34.         self.generic_visit(node)
  35.         self.scopes = self.scopes.parents
  36.  
  37.     def visit_Import(self, node):
  38.         self.scopes.update({
  39.             a.asname or a.name: a.name
  40.             for a in node.names
  41.             if a.name == self.modulename
  42.         })
  43.  
  44.     def visit_ImportFrom(self, node):
  45.         # resolve relative imports; from . import <name>, from ..<name> import <name>
  46.         source = node.module  # can be None
  47.         if node.level:
  48.             package = self.package
  49.             if node.level > 1:
  50.                 # go up levels as needed
  51.                 package = '.'.join(self.package.split('.')[:-(node.level - 1)])
  52.             source = f'{package}.{source}' if source else package
  53.         if self.modulename == source:
  54.             # names imported from our target module
  55.             self.scopes.update({
  56.                 a.asname or a.name: f'{self.modulename}.{a.name}'
  57.                 for a in node.names
  58.             })
  59.         elif self.modulepackage and self.modulepackage == source:
  60.             # from package import module import, where package.module is what we want
  61.             self.scopes.update({
  62.                 a.asname or a.name: self.modulename
  63.                 for a in node.names
  64.                 if a.name == self.modulestem
  65.             })
  66.  
  67.     def visit_Name(self, node):
  68.         if not isinstance(node.ctx, ast.Load):
  69.             # store or del operation, means the name is masked in the current scope
  70.             try:
  71.                 self.scopes[node.id] = None
  72.             except TypeError:
  73.                 # class scope, which we made read-only. These names can't mask
  74.                 # anything so just ignore these.
  75.                 pass
  76.             return
  77.         # find scope this name was defined in, starting at the current scope
  78.         imported_name = self.scopes.get(node.id)
  79.         if imported_name is None:
  80.             return
  81.         self.used_at.append((imported_name, node.id, node.lineno))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement