def replaceHazards(a):
if not isinstance(a, ast.AST):
return
for field in ast.walk(a):
if type(a) == ast.Import:
for i in range(len(a.names)):
if a.names[i].name not in supportedLibraries:
if not (a.names[i].name[0] == "r" and a.names[i].name[1] in "0123456789") and not ("NotAllowed" in a.names[i].name):
a.names[i].name = a.names[i].name + "NotAllowed"
elif type(a) == ast.ImportFrom:
if a.module not in supportedLibraries:
if not (a.module[0] == "r" and a.module[1] in "0123456789") and not ("NotAllowed" in a.module):
a.module = a.module + "NotAllowed"
elif type(a) == ast.Call:
if type(a.func) == ast.Name and a.func.id in ["compile", "eval", "execfile", "file", "open", "__import__", "apply"]:
a.func.id = a.func.id + "NotAllowed"
python类Import()的实例源码
def getAllImports(a):
"""Gather all imported module names"""
if not isinstance(a, ast.AST):
return []
imports = []
for child in ast.walk(a):
if type(child) == ast.Import:
for alias in child.names:
if alias.name in supportedLibraries:
imports.append(alias.asname if alias.asname != None else alias.name)
else:
log("astTools\tgetAllImports\tUnknown library: " + alias.name, "bug")
elif type(child) == ast.ImportFrom:
if child.module in supportedLibraries:
for alias in child.names: # these are all functions
if alias.name in libraryMap[child.module]:
imports.append(alias.asname if alias.asname != None else alias.name)
else:
log("astTools\tgetAllImports\tUnknown import from name: " + \
child.module + "," + alias.name, "bug")
else:
log("astTools\tgetAllImports\tUnknown library: " + child.module, "bug")
return imports
def match_type(self, typ, node):
if typ == 'class':
return isinstance(node, ast.ClassDef)
if typ == 'def':
return isinstance(node, ast.FunctionDef)
if typ == 'import':
return isinstance(node, (ast.Import, ast.ImportFrom))
if typ == 'assign':
return isinstance(node, ast.Assign)
if typ == 'attr':
return isinstance(node, ast.Attribute)
if typ == 'call':
if isinstance(node, ast.Call):
return True
# Python 2.x compatibility
return hasattr(ast, 'Print') and isinstance(node, ast.Print)
def _add_aliases(self, node):
"""
We delegate to this method instead of using visit_alias() to have
access to line numbers and to filter imports from __future__.
"""
assert isinstance(node, (ast.Import, ast.ImportFrom))
for name_and_alias in node.names:
# Store only top-level module name ("os.path" -> "os").
# We can't easily detect when "os.path" is used.
name = name_and_alias.name.partition('.')[0]
alias = name_and_alias.asname
self._define(
self.defined_imports, alias or name, node,
confidence=90, ignore=_ignore_import)
if alias is not None:
self.used_names.add(name_and_alias.name)
def add_import(tree, name, asname):
# import fat as __fat__
import_node = ast.Import(names=[ast.alias(name=name, asname=asname)],
lineno=1, col_offset=1)
for index, node in enumerate(tree.body):
if (index == 0 and isinstance(node, ast.Expr)
and isinstance(node.value, ast.Constant)
and isinstance(node.value.value, str)):
# docstring
continue
if (isinstance(node, ast.ImportFrom) and node.module == '__future__'):
# from __future__ import ...
continue
tree.body.insert(index, import_node)
break
else:
# body is empty or only contains __future__ imports
tree.body.append(import_node)
def walk(self, prog_ast):
result = list(ast.walk(prog_ast))
import_nodes = [node for node in result if isinstance(node, ast.Import)]
import_from_nodes = [node for node in result if isinstance(node, ast.ImportFrom)]
for node in import_nodes:
for name in node.names:
if ImportHandler.is_builtin(name.name):
new_ast = ImportHandler.get_builtin_ast(name.name)
else:
new_ast = ImportHandler.get_module_ast(name.name, self.base_folder)
result += self.walk(new_ast)
for node in import_from_nodes:
if node.module == "typing":
# FIXME ignore typing for now, not to break type vars
continue
if ImportHandler.is_builtin(node.module):
new_ast = ImportHandler.get_builtin_ast(node.module)
else:
new_ast = ImportHandler.get_module_ast(node.module, self.base_folder)
result += self.walk(new_ast)
return result
def _infer_import_from(node, context, solver):
"""Infer the imported module in an `import from` statement"""
if node.module == "typing":
# FIXME ignore typing module for now, so as not to break type variables
# Remove after implementing stub for typing and built-in importing
return solver.z3_types.none
import_context = ImportHandler.infer_import(node.module, solver.config.base_folder, infer, solver)
if len(node.names) == 1 and node.names[0].name == "*":
# import all module elements
for v in import_context.types_map:
context.set_type(v, import_context.get_type(v))
else:
# Import only stated names
for name in node.names:
elt_name = name.name
if name.asname:
elt_name = name.asname
if name.name not in import_context.types_map:
raise ImportError("Cannot import name {}".format(name.name))
context.set_type(elt_name, import_context.get_type(name.name))
return solver.z3_types.none
def get_all_filters():
"""Return all the available filters"""
return (
# TODO: Add ast.Module to the docstring search.
DocString('d', 'doc', (ast.FunctionDef, ast.ClassDef, ast.Module),
help="Match class and function docstrings."),
NameFilter('c', 'class', (ast.ClassDef, ),
help="Match class names."),
DefFilter('f', 'def', (ast.FunctionDef, ), (ast.AST, ),
help="Match all defs."),
DefFilter('F', 'function', (ast.FunctionDef, ), (ast.Module, ),
help="Match function names at the module level."),
DefFilter('m', 'method', (ast.FunctionDef, ), (ast.ClassDef, ),
help="Match class method names."),
DefFilter('j', 'closure', (ast.FunctionDef, ), (ast.FunctionDef, ),
help="Match closure def names."),
ImportFilter('i', 'import', (ast.Import, ast.ImportFrom, ),
help="Match imported package names."),
CallFilter('C', 'call', (ast.Call, ),
help="Match call statements."),
AttrFilter('a', 'attr', (ast.Attribute, ),
help="Match attributes on objects"),
)
def get_coverable_nodes(cls):
return {
ast.Assert,
ast.Assign,
ast.AugAssign,
ast.Break,
ast.Continue,
ast.Delete,
ast.Expr,
ast.Global,
ast.Import,
ast.ImportFrom,
ast.Nonlocal,
ast.Pass,
ast.Raise,
ast.Return,
ast.FunctionDef,
ast.ClassDef,
ast.TryExcept,
ast.TryFinally,
ast.ExceptHandler,
ast.If,
ast.For,
ast.While,
}
def get_coverable_nodes(cls):
return {
ast.Assert,
ast.Assign,
ast.AugAssign,
ast.Break,
ast.Continue,
ast.Delete,
ast.Expr,
ast.Global,
ast.Import,
ast.ImportFrom,
ast.Nonlocal,
ast.Pass,
ast.Raise,
ast.Return,
ast.ClassDef,
ast.FunctionDef,
ast.Try,
ast.ExceptHandler,
ast.If,
ast.For,
ast.While,
}
def _is_relative_import(module_name, path):
"""Checks if import is relative. Returns True if relative, False if
absolute, and None if import could not be found."""
try:
# Check within the restricted path of a (sub-)package
imp.find_module(module_name, [path])
except ImportError:
pass
else:
return True
try:
# Check across all of sys.path
imp.find_module(module_name)
except ImportError:
pass
else:
return False
# Module could not be found on system due to:
# 1. Import that doesn't exist. "Bad import".
# 2. Since we're only scanning the AST, there's a good chance the
# import's inclusion is conditional, and would never be triggered.
# For example, an import specific to an OS.
return None
def _find_imports(self, node):
"""Recurses through AST collecting the targets of all import
statements."""
if isinstance(node, ast.Import):
return {self._extract_root_module(alias.name) for alias in node.names}
elif isinstance(node, ast.ImportFrom):
# We ignore all imports with levels other than 0. That's because if
# if level > 0, we know that it's a relative import, and we only
# care about root modules.
if node.level == 0:
return {self._extract_root_module(node.module)}
else:
return set()
elif hasattr(node, 'body') and hasattr(node.body, '__iter__'):
# Not all bodies are lists (for ex. exec)
imps = set()
for child_node in node.body:
imps.update(self._find_imports(child_node))
return imps
else:
return set()
def visit_Import(self, node: ast.Import) -> ast.Import:
const = self.__class__._constants
for module in node.names:
if module.name in const and not module.asname:
for name in const[module.name]:
self._add_value(module.name, name, '{}.{}'.format(module.name, name))
return self.generic_visit(node)
def importedName(id, importList):
for imp in importList:
if type(imp) == ast.Import:
for name in imp.names:
if hasattr(name, "asname") and name.asname != None:
if id == name.asname:
return True
else:
if id == name.name:
return True
elif type(imp) == ast.ImportFrom:
if hasattr(imp, "module"):
if imp.module in supportedLibraries:
libMap = libraryMap[imp.module]
for name in imp.names:
if hasattr(name, "asname") and name.asname != None:
if id == name.asname:
return True
else:
if id == name.name:
return True
else:
log("astTools\timportedName\tUnsupported library: " + printFunction(imp), "bug")
else:
log("astTools\timportedName\tWhy no module? " + printFunction(imp), "bug")
return False
def isStatement(a):
"""Determine whether the given node is a statement (vs an expression)"""
return type(a) in [ ast.Module, ast.Interactive, ast.Expression, ast.Suite,
ast.FunctionDef, ast.ClassDef, ast.Return, ast.Delete,
ast.Assign, ast.AugAssign, ast.For, ast.While,
ast.If, ast.With, ast.Raise, ast.Try,
ast.Assert, ast.Import, ast.ImportFrom, ast.Global,
ast.Expr, ast.Pass, ast.Break, ast.Continue ]
def getAllImportStatements(a):
if not isinstance(a, ast.AST):
return []
imports = []
for child in ast.walk(a):
if type(child) == ast.Import:
imports.append(child)
elif type(child) == ast.ImportFrom:
imports.append(child)
return imports
def rule_I200(self, node):
if isinstance(node, ast.Import):
for alias in node.names:
if '.' not in alias.name:
from_name = None
imported_name = alias.name
else:
from_name, imported_name = alias.name.rsplit('.', 1)
if imported_name == alias.asname:
if from_name:
rewritten = 'from {} import {}'.format(
from_name, imported_name
)
else:
rewritten = 'import {}'.format(imported_name)
yield (
node.lineno,
node.col_offset,
self.message_I200.format(rewritten),
type(self)
)
elif isinstance(node, ast.ImportFrom):
for alias in node.names:
if alias.name == alias.asname:
rewritten = 'from {} import {}'.format(node.module, alias.name)
yield (
node.lineno,
node.col_offset,
self.message_I200.format(rewritten),
type(self)
)
def rule_I201(self, node):
if isinstance(node, ast.Import):
module_names = [alias.name for alias in node.names]
elif isinstance(node, ast.ImportFrom):
node_module = node.module or ''
module_names = [node_module]
for alias in node.names:
module_names.append('{}.{}'.format(node_module, alias.name))
else:
return
# Sort from most to least specific paths.
module_names.sort(key=len, reverse=True)
warned = set()
for module_name in module_names:
if module_name in self.banned_modules:
message = self.message_I201.format(
name=module_name,
msg=self.banned_modules[module_name]
)
if any(mod.startswith(module_name) for mod in warned):
# Do not show an error for this line if we already showed
# a more specific error.
continue
else:
warned.add(module_name)
yield (
node.lineno,
node.col_offset,
message,
type(self)
)
def test_import(self):
matches = list(self.m.match('import', self.filepath('imports.py')))
self.assertEqual(len(matches), 6)
# check instances
self.assertIsInstance(matches[0][0], ast.ImportFrom)
self.assertIsInstance(matches[1][0], ast.ImportFrom)
self.assertIsInstance(matches[2][0], ast.ImportFrom)
self.assertIsInstance(matches[3][0], ast.ImportFrom)
self.assertIsInstance(matches[4][0], ast.Import)
self.assertIsInstance(matches[5][0], ast.Import)
def test_import_not_from(self):
matches = list(self.m.match('import:not([from^=foo])',
self.filepath('imports.py')))
self.assertEqual(len(matches), 3)
# check instances
self.assertIsInstance(matches[0][0], ast.ImportFrom)
self.assertIsInstance(matches[1][0], ast.Import)
self.assertIsInstance(matches[2][0], ast.Import)
def visit_Import(self, node):
# type: (ast.Import) -> None
for child in node.names:
if isinstance(child, ast.alias):
import_name = child.name
if import_name == self._SDK_PACKAGE:
self._set_inferred_type_for_name(
import_name, Boto3ModuleType())
self.generic_visit(node)
def iter_imported_modules(node):
"""
Yield the imported module names from *node* where *node* is either an
ast.Import or ast.ImportFrom instance.
"""
if isinstance(node, ast.Import):
for alias in node.names:
yield alias.name
elif isinstance(node, ast.ImportFrom):
for alias in node.names:
yield node.module + '.' + alias.name
else:
raise ValueError('node must be an instance of either ast.Import or ast.ImportFrom')
def iter_method_classes(parent, call_node, context, child=None):
import_aliases = context._context['import_aliases']
if not isinstance(call_node, ast.Call):
raise ValueError('call_node must be of type ast.Call')
if not isinstance(call_node.func, ast.Attribute):
raise ValueError('call_node must be an attribute')
for init_node in iter_expr_values(parent, call_node.func.value, call_node):
# the init_node is the one in which the class is initialized
# all expr nodes should be either call (Name or Attribute) or Name
if not isinstance(init_node, ast.Call):
continue
if isinstance(init_node.func, ast.Attribute):
klass_name = get_attribute_name(init_node.func)
if klass_name is None:
continue
module_name, klass_name = klass_name.rsplit('.', 1)
for def_node in get_definition_nodes(parent, init_node.func.value, child=init_node):
if isinstance(def_node, (ast.Import, ast.ImportFrom)):
yield import_aliases.get(module_name, module_name) + '.' + klass_name
elif isinstance(init_node.func, ast.Name):
if init_node.func.id in import_aliases:
yield import_aliases[init_node.func.id]
continue
for klass_node in iter_expr_values(parent, init_node.func):
if isinstance(klass_node, ast.Attribute):
yield get_attribute_name(klass_node, import_aliases)
def test_import(self):
self.stmt(ast.Import([]), "empty names on Import")
def visit_Import(self, node: ast.Import) -> None:
for name in node.names:
if (
isinstance(name, ast.alias) and
name.name == 'typing' or
name.name.startswith('typing.')
):
self.should_type_check = True
break
def __init__(self, name, source):
# A dot should only appear in the name when it is a submodule import
assert '.' in name and (not source or isinstance(source, ast.Import))
package_name = name.split('.')[0]
super(SubmoduleImportation, self).__init__(package_name, source)
self.fullName = name
def test_import(self):
self.stmt(ast.Import([]), "empty names on Import")
def infer(node, context, solver):
if isinstance(node, ast.Assign):
return _infer_assign(node, context, solver)
elif isinstance(node, ast.AugAssign):
return _infer_augmented_assign(node, context, solver)
elif isinstance(node, ast.Return):
if not node.value:
return solver.z3_types.none
return expr.infer(node.value, context, solver)
elif isinstance(node, ast.Delete):
return _infer_delete(node, context, solver)
elif isinstance(node, (ast.If, ast.While)):
return _infer_control_flow(node, context, solver)
elif isinstance(node, ast.For):
return _infer_for(node, context, solver)
elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.AsyncFor):
# AsyncFor is introduced in Python 3.5
return _infer_for(node, context, solver)
elif isinstance(node, ast.With):
return _infer_with(node, context, solver)
elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.AsyncWith):
# AsyncWith is introduced in Python 3.5
return _infer_with(node, context, solver)
elif isinstance(node, ast.Try):
return _infer_try(node, context, solver)
elif isinstance(node, ast.FunctionDef):
return _infer_func_def(node, context, solver)
elif isinstance(node, ast.ClassDef):
return _infer_class_def(node, context, solver)
elif isinstance(node, ast.Expr):
expr.infer(node.value, context, solver)
elif isinstance(node, ast.Import):
return _infer_import(node, context, solver)
elif isinstance(node, ast.ImportFrom):
return _infer_import_from(node, context, solver)
return solver.z3_types.none
def make_node(name, pkg, allowed, glbnames):
"""Makes a node by parsing a file and traversing its AST."""
raw = SOURCES[pkg, name]
tree = parse(raw, filename=name)
# we only want to deal with global import statements
pkgdeps = set()
extdeps = set()
futures = set()
glbnames.module = name
for a in tree.body:
glbnames.add(a, istopnode=True)
if isinstance(a, Import):
for n in a.names:
p, dot, m = n.name.rpartition('.')
if p == pkg and m in allowed:
pkgdeps.add(m)
else:
extdeps.add(n.name)
elif isinstance(a, ImportFrom):
if module_is_package(a.module, pkg, a.level):
pkgdeps.update(n.name for n in a.names if n.name in allowed)
elif module_from_package(a.module, pkg, a.level):
p, m = resolve_package_module(a.module, pkg, a.level,
default=a.names[0].name)
if p == pkg and m in allowed:
pkgdeps.add(m)
else:
extdeps.add(a.module)
elif a.module == '__future__':
futures.update(n.name for n in a.names)
return ModNode(name, frozenset(pkgdeps), frozenset(extdeps),
frozenset(futures))
def test_import(all_filters, ast_test_code):
f = all_filters['import']
patterns = [pattern.compile('mything'), ]
count = 0
for node in ast_test_code:
if f.match(node, patterns):
count += 1
assert isinstance(node, (ast.Import, ast.ImportFrom))
assert count == 2