def generic_visit(self, node):
# Fallback when we don't have a special implementation.
if _is_ast_expr(node):
mod = ast.Expression(node)
co = self._compile(mod)
try:
result = self.frame.eval(co)
except Exception:
raise Failure()
explanation = self.frame.repr(result)
return explanation, result
elif _is_ast_stmt(node):
mod = ast.Module([node])
co = self._compile(mod, "exec")
try:
self.frame.exec_(co)
except Exception:
raise Failure()
return None, None
else:
raise AssertionError("can't handle %s" %(node,))
python类Module()的实例源码
def code_to_ast(code: types.CodeType, file: str = None) -> ast.Module:
"""
Return node object for code object.
"""
if code and not isinstance(code, types.CodeType):
raise TypeError('Unexpected type: {}'.format(str(type(code))))
result = None
try:
src = inspect.getsource(code)
file = file or inspect.getfile(code)
result = source_to_ast(src, file)
except IOError:
pass
return result
def module_to_ast(module: types.ModuleType, file: str = None) -> ast.Module:
"""
Return node object for python module.
"""
if module and not isinstance(module, types.ModuleType):
raise TypeError('Unexpected type: {}'.format(str(type(module))))
result = None
try:
src = inspect.getsource(module)
file = file or inspect.getfile(module)
result = source_to_ast(src, file)
except IOError:
pass
return result
def ast_to_class(node: ast.AST, old_class: type = None, file: str = None) -> type:
"""
:param node:
:param old_class:
:param file:
:return:
"""
if node and not isinstance(node, (ast.Module, ast.ClassDef)):
raise TypeError('Unexpected type for node: {}'.format(str(type(node))))
if old_class and not isinstance(old_class, type):
raise TypeError('Unexpected type for old_class: {}'.format(str(type(old_class))))
result = old_class
# @TODO:
raise NotImplementedError
return NotImplemented
def createNameMap(a, d=None):
if d == None:
d = { }
if not isinstance(a, ast.AST):
return d
if type(a) == ast.Module: # Need to go through the functions backwards to make this right
for i in range(len(a.body) - 1, -1, -1):
createNameMap(a.body[i], d)
return d
if type(a) in [ast.FunctionDef, ast.ClassDef]:
if hasattr(a, "originalId") and a.name not in d:
d[a.name] = a.originalId
elif type(a) == ast.arg:
if hasattr(a, "originalId") and a.arg not in d:
d[a.arg] = a.originalId
return d
elif type(a) == ast.Name:
if hasattr(a, "originalId") and a.id not in d:
d[a.id] = a.originalId
return d
for child in ast.iter_child_nodes(a):
createNameMap(child, d)
return d
def occursIn(sub, super):
"""Does the first AST occur as a subtree of the second?"""
superStatementTypes = [ ast.Module, ast.Interactive, ast.Suite,
ast.FunctionDef, ast.ClassDef, ast.For,
ast.While, ast.If, ast.With, ast.Try,
ast.ExceptHandler ]
if (not isinstance(super, ast.AST)):
return False
if type(sub) == type(super) and compareASTs(sub, super, checkEquality=True) == 0:
return True
# we know that a statement can never occur in an expression
# (or in a non-statement-holding statement), so cut the search off now to save time.
if isStatement(sub) and type(super) not in superStatementTypes:
return False
for child in ast.iter_child_nodes(super):
if occursIn(sub, child):
return True
return False
def getAllGlobalNames(a):
# Finds all names that can be accessed at the global level in the AST
if type(a) != ast.Module:
return []
names = []
for obj in a.body:
if type(obj) in [ast.FunctionDef, ast.ClassDef]:
names.append(obj.name)
elif type(obj) in [ast.Assign, ast.AugAssign]:
targets = obj.targets if type(obj) == ast.Assign else [obj.target]
for target in obj.targets:
if type(target) == ast.Name:
names.append(target.id)
elif type(target) in [ast.Tuple, ast.List]:
for elt in target.elts:
if type(elt) == ast.Name:
names.append(elt.id)
elif type(obj) in [ast.Import, ast.ImportFrom]:
for module in obj.names:
names.append(module.asname if module.asname != None else module.name)
return names
def isDefault(a):
"""Our programs have a default setting of return 42, so we should detect that"""
if type(a) == ast.Module and len(a.body) == 1:
a = a.body[0]
else:
return False
if type(a) != ast.FunctionDef:
return False
if len(a.body) == 0:
return True
elif len(a.body) == 1:
if type(a.body[0]) == ast.Return:
if a.body[0].value == None or \
type(a.body[0].value) == ast.Num and a.body[0].value.n == 42:
return True
return False
def _get_commands(dist # type: setuptools.dist.Distribution
):
# type: (...) -> typing.Dict[str, typing.Set[str]]
"""Find all commands belonging to the given distribution.
Args:
dist: The Distribution to search for docopt-compatible docstrings that
can be used to generate command entry points.
Returns:
A dictionary containing a mapping of primary commands to sets of
subcommands.
"""
py_files = (f for f in setuptools.findall()
if os.path.splitext(f)[1].lower() == '.py')
pkg_files = (f for f in py_files if _get_package_name(f) in dist.packages)
commands = {} # type: typing.Dict[str, typing.Set[str]]
for file_name in pkg_files:
with open(file_name) as py_file:
module = typing.cast(ast.Module, ast.parse(py_file.read()))
module_name = _get_module_name(file_name)
_append_commands(commands, module_name, _get_module_commands(module))
_append_commands(commands, module_name, _get_class_commands(module))
_append_commands(commands, module_name, _get_function_commands(module))
return commands
def _get_module_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by the python module.
Module commands consist of a docopt-style module docstring and a callable
Command class.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
cls = next((n for n in module.body
if isinstance(n, ast.ClassDef) and n.name == 'Command'), None)
if not cls:
return
methods = (n.name for n in cls.body if isinstance(n, ast.FunctionDef))
if '__call__' not in methods:
return
docstring = ast.get_docstring(module)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None), None)
def _get_class_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by python classes in the module.
Class commands are detected by inspecting all callable classes in the
module for docopt-style docstrings.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
nodes = (n for n in module.body if isinstance(n, ast.ClassDef))
for cls in nodes:
methods = (n.name for n in cls.body if isinstance(n, ast.FunctionDef))
if '__call__' in methods:
docstring = ast.get_docstring(cls)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None),
cls.name)
def _get_function_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by python functions in the module.
Function commands consist of all top-level functions that contain
docopt-style docstrings.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
nodes = (n for n in module.body if isinstance(n, ast.FunctionDef))
for func in nodes:
docstring = ast.get_docstring(func)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None),
func.name)
def to_source(node):
"""
Convert a node to source code by converting it to an astroid tree first, and using astroid's
as_string() method.
"""
if hasattr(node, 'as_string'):
return node.as_string()
builder = astroid.rebuilder.TreeRebuilder(astroid.manager.AstroidManager())
# We need to make a deep copy of node; not sure why, but node seems affected by the astroid
# TreeRebuilder.
node_copy = copy.deepcopy(node)
if isinstance(node, ast.Module):
anode = builder.visit_module(node_copy, '', '', '')
else:
# Anything besides Module needs to have astroid Module passed in as a parent.
amodule = astroid.nodes.Module('', None)
anode = builder.visit(node_copy, amodule)
return anode.as_string()
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def generic_visit(self, node):
# Fallback when we don't have a special implementation.
if _is_ast_expr(node):
mod = ast.Expression(node)
co = self._compile(mod)
try:
result = self.frame.eval(co)
except Exception:
raise Failure()
explanation = self.frame.repr(result)
return explanation, result
elif _is_ast_stmt(node):
mod = ast.Module([node])
co = self._compile(mod, "exec")
try:
self.frame.exec_(co)
except Exception:
raise Failure()
return None, None
else:
raise AssertionError("can't handle %s" %(node,))
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def generic_visit(self, node):
# Fallback when we don't have a special implementation.
if _is_ast_expr(node):
mod = ast.Expression(node)
co = self._compile(mod)
try:
result = self.frame.eval(co)
except Exception:
raise Failure()
explanation = self.frame.repr(result)
return explanation, result
elif _is_ast_stmt(node):
mod = ast.Module([node])
co = self._compile(mod, "exec")
try:
self.frame.exec_(co)
except Exception:
raise Failure()
return None, None
else:
raise AssertionError("can't handle %s" %(node,))
def generic_visit(self, node):
# Fallback when we don't have a special implementation.
if _is_ast_expr(node):
mod = ast.Expression(node)
co = self._compile(mod)
try:
result = self.frame.eval(co)
except Exception:
raise Failure()
explanation = self.frame.repr(result)
return explanation, result
elif _is_ast_stmt(node):
mod = ast.Module([node])
co = self._compile(mod, "exec")
try:
self.frame.exec_(co)
except Exception:
raise Failure()
return None, None
else:
raise AssertionError("can't handle %s" %(node,))
def check_vars(self, code, local_variables, global_variables=None,
nonlocal_variables=None,
get_node=None):
tree = compile_ast(code)
self.assertIsInstance(tree, ast.Module)
if get_node:
node = get_node(tree)
else:
node = tree.body[0]
visitor = fatoptimizer.namespace.VariableVisitor("<string>")
visitor.find_variables(node)
self.assertEqual(visitor.local_variables, local_variables)
if global_variables is not None:
self.assertEqual(visitor.global_variables, global_variables)
else:
self.assertEqual(visitor.global_variables, set())
if nonlocal_variables is not None:
self.assertEqual(visitor.nonlocal_variables, nonlocal_variables)
else:
self.assertEqual(visitor.nonlocal_variables, set())
def optimize(self, tree):
orig_tree = tree
tree = ConvertConstant(self.filename).visit(tree)
if isinstance(tree, ast.Module):
self._find_config(tree.body)
if not self.config.enabled:
self.log(tree,
"skip optimisation: disabled in __fatoptimizer__")
return orig_tree
tree = super().optimize(tree)
if self._fat_module:
add_import(tree, 'fat', self._fat_module)
return tree
def get_compound_bodies(node):
"""Returns a list of bodies of a compound statement node.
Args:
node: AST node.
Returns:
A list of bodies of the node. If the given node does not represent
a compound statement, an empty list is returned.
"""
if isinstance(node, (ast.Module, ast.FunctionDef, ast.ClassDef, ast.With)):
return [node.body]
elif isinstance(node, (ast.If, ast.While, ast.For)):
return [node.body, node.orelse]
elif PY2 and isinstance(node, ast.TryFinally):
return [node.body, node.finalbody]
elif PY2 and isinstance(node, ast.TryExcept):
return [node.body, node.orelse] + [h.body for h in node.handlers]
elif PY3 and isinstance(node, ast.Try):
return ([node.body, node.orelse, node.finalbody]
+ [h.body for h in node.handlers])
end
return []
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def valid_identifier(name):
"""Determines whether the given name could be used a Python identifier"""
try:
name = ensure_unicode(name)
except ValueError:
return False
if name in __KEYWORDS:
return False
try:
root = _ast.parse(name)
except:
return False
return (isinstance(root, _ast.Module) and
len(root.body) == 1 and
isinstance(root.body[0], _ast.Expr) and
isinstance(root.body[0].value, _ast.Name) and
root.body[0].value.id == name)
def make_plugin_module(rule_body):
return FavaCode(
Module(
body=[
FunctionDef(
name='report',
args=arguments(
args=[
Name(id='shared', ctx=Param()),
],
vararg=None,
kwarg=None,
defaults=[]),
body=[
Return(
value=rule_body.get_ast())],
decorator_list=[
Call(
func=Name(id='fava_rule', ctx=Load()),
args=[Name(id=each, ctx=Load()) for each in rule_body.get_parsers()],
keywords=[],
starargs=None, kwargs=None),
])
]),
[rule_body])
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 is_overridden(self, node, name=None):
if not isinstance(node.parent, ast.ClassDef):
raise MutationResign()
if not name:
name = node.name
parent = node.parent
parent_names = []
while parent:
if not isinstance(parent, ast.Module):
parent_names.append(parent.name)
if not isinstance(parent, ast.ClassDef) and not isinstance(parent, ast.Module):
raise MutationResign()
parent = parent.parent
getattr_rec = lambda obj, attr: functools.reduce(getattr, attr, obj)
try:
klass = getattr_rec(self.module, reversed(parent_names))
except AttributeError:
raise MutationResign()
for base_klass in type.mro(klass)[1:-1]:
if hasattr(base_klass, name):
return True
return False