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
python类Try()的实例源码
def test_try(self):
p = ast.Pass()
t = ast.Try([], [], [], [p])
self.stmt(t, "empty body on Try")
t = ast.Try([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p])
self.stmt(t, "must have Load context")
t = ast.Try([p], [], [], [])
self.stmt(t, "Try has neither except handlers nor finalbody")
t = ast.Try([p], [], [p], [p])
self.stmt(t, "Try has orelse but no except handlers")
t = ast.Try([p], [ast.ExceptHandler(None, "x", [])], [], [])
self.stmt(t, "empty body on ExceptHandler")
e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])]
self.stmt(ast.Try([p], e, [], []), "must have Load context")
e = [ast.ExceptHandler(None, "x", [p])]
t = ast.Try([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p])
self.stmt(t, "must have Load context")
t = ast.Try([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))])
self.stmt(t, "must have Load context")
def CONTINUE(self, node):
# Walk the tree up until we see a loop (OK), a function or class
# definition (not OK), for 'continue', a finally block (not OK), or
# the top module scope (not OK)
n = node
while hasattr(n, 'parent'):
n, n_child = n.parent, n
if isinstance(n, LOOP_TYPES):
# Doesn't apply unless it's in the loop itself
if n_child not in n.orelse:
return
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
break
# Handle Try/TryFinally difference in Python < and >= 3.3
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
if n_child in n.finalbody:
self.report(messages.ContinueInFinally, node)
return
if isinstance(node, ast.Continue):
self.report(messages.ContinueOutsideLoop, node)
else: # ast.Break
self.report(messages.BreakOutsideLoop, node)
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_try(self):
p = ast.Pass()
t = ast.Try([], [], [], [p])
self.stmt(t, "empty body on Try")
t = ast.Try([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p])
self.stmt(t, "must have Load context")
t = ast.Try([p], [], [], [])
self.stmt(t, "Try has neither except handlers nor finalbody")
t = ast.Try([p], [], [p], [p])
self.stmt(t, "Try has orelse but no except handlers")
t = ast.Try([p], [ast.ExceptHandler(None, "x", [])], [], [])
self.stmt(t, "empty body on ExceptHandler")
e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])]
self.stmt(ast.Try([p], e, [], []), "must have Load context")
e = [ast.ExceptHandler(None, "x", [p])]
t = ast.Try([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p])
self.stmt(t, "must have Load context")
t = ast.Try([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))])
self.stmt(t, "must have Load context")
def CONTINUE(self, node):
# Walk the tree up until we see a loop (OK), a function or class
# definition (not OK), for 'continue', a finally block (not OK), or
# the top module scope (not OK)
n = node
while hasattr(n, 'parent'):
n, n_child = n.parent, n
if isinstance(n, LOOP_TYPES):
# Doesn't apply unless it's in the loop itself
if n_child not in n.orelse:
return
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
break
# Handle Try/TryFinally difference in Python < and >= 3.3
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
if n_child in n.finalbody:
self.report(messages.ContinueInFinally, node)
return
if isinstance(node, ast.Continue):
self.report(messages.ContinueOutsideLoop, node)
else: # ast.Break
self.report(messages.BreakOutsideLoop, node)
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 test_try(self):
p = ast.Pass()
t = ast.Try([], [], [], [p])
self.stmt(t, "empty body on Try")
t = ast.Try([ast.Expr(ast.Name("x", ast.Store()))], [], [], [p])
self.stmt(t, "must have Load context")
t = ast.Try([p], [], [], [])
self.stmt(t, "Try has neither except handlers nor finalbody")
t = ast.Try([p], [], [p], [p])
self.stmt(t, "Try has orelse but no except handlers")
t = ast.Try([p], [ast.ExceptHandler(None, "x", [])], [], [])
self.stmt(t, "empty body on ExceptHandler")
e = [ast.ExceptHandler(ast.Name("x", ast.Store()), "y", [p])]
self.stmt(ast.Try([p], e, [], []), "must have Load context")
e = [ast.ExceptHandler(None, "x", [p])]
t = ast.Try([p], e, [ast.Expr(ast.Name("x", ast.Store()))], [p])
self.stmt(t, "must have Load context")
t = ast.Try([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))])
self.stmt(t, "must have Load context")
def _build_node_cfg(node):
handlers = {
ast.If: _build_if_cfg,
ast.For: _build_loop_cfg,
ast.While: _build_loop_cfg,
ast.With: _build_with_cfg,
ast.Break: _build_break_cfg,
ast.Continue: _build_continue_cfg,
ast.Return: _build_return_cfg,
ast.Try: _build_try_cfg,
}
if type(node) in handlers:
handler = handlers[type(node)]
else:
handler = _build_statement_cfg
return handler(node)
def staticVars(l, vars):
"""Determines whether the given lines change the given variables"""
# First, if one of the variables can be modified, there might be a problem
mutableVars = []
for var in vars:
if (not (hasattr(var, "type") and (var.type in [int, float, str, bool]))):
mutableVars.append(var)
for i in range(len(l)):
if type(l[i]) == ast.Assign:
for var in vars:
if var.id in allVariableNamesUsed(l[i].targets[0]):
return False
elif type(l[i]) == ast.AugAssign:
for var in vars:
if var.id in allVariableNamesUsed(l[i].target):
return False
elif type(l[i]) in [ast.If, ast.While]:
if not (staticVars(l[i].body, vars) and staticVars(l[i].orelse, vars)):
return False
elif type(l[i]) == ast.For:
for var in vars:
if var.id in allVariableNamesUsed(l[i].target):
return False
if not (staticVars(l[i].body, vars) and staticVars(l[i].orelse, vars)):
return False
elif type(l[i]) in [ast.FunctionDef, ast.ClassDef, ast.Try, ast.With]:
log("transformations\tstaticVars\tMissing type: " + str(type(l[i])), "bug")
# If a mutable variable is used, we can't trust it
for var in mutableVars:
if var.id in allVariableNamesUsed(l[i]):
return False
return True
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 _try_empty_body(self, node):
if not can_remove(node.body):
return
if not can_remove(node.handlers):
return
# body block is empty, handlers can be removed
self.log_node_removal("Remove dead code (empty try block)",
node.body)
self.log_node_removal("Remove dead code (empty try block)",
node.handlers)
if not node.orelse:
# body and else blocks are empty
#
# try: pass (except: ...) finally: final_code
# => final_code
if not can_move_final(node.finalbody):
return
return self._replace_node(node, node.finalbody)
if is_empty_body(node.finalbody):
# body and finally blocks are empty, else block is non empty
#
# try: pass (except: ...) else: else_code (final: pass)
# => else_code
self.log_node_removal("Remove dead code (empty finally block)",
node.finalbody)
return self._replace_node(node, node.orelse)
# body block is empty, else and final blocks are non empty
#
# try: pass (except: ...) else: code1 finally: code2
# => try: code1 finally: code2
if not can_move_final(node.finalbody):
return
new_node = ast.Try(body=node.orelse, finalbody=node.finalbody,
handlers=[], orelse=[])
copy_lineno(node, new_node)
return new_node
def getNodeType(node_class):
return node_class.__name__.upper()
# Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
def getAlternatives(n):
if isinstance(n, ast.If):
return [n.body]
if isinstance(n, ast.Try):
return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
def _infer_try(node, context, solver):
"""Infer the types for a try/except/else block"""
result_type = solver.new_z3_const("try")
body_type = _infer_body(node.body, context, node.lineno, solver)
else_type = _infer_body(node.orelse, context, node.lineno, solver)
final_type = _infer_body(node.finalbody, context, node.lineno, solver)
solver.add(axioms.try_except(body_type, else_type, final_type, result_type, solver.z3_types),
fail_message="Try/Except block in line {}".format(node.lineno))
solver.optimize.add_soft(result_type == body_type)
solver.optimize.add_soft(result_type == else_type)
solver.optimize.add_soft(result_type == final_type)
# TODO: Infer exception handlers as classes
for handler in node.handlers:
handler_context = context
if handler.name:
handler_context = Context(node.body, solver, parent_context=context)
handler_context.set_type(handler.name,
solver.annotation_resolver.resolve(handler.type, solver))
handler_body_type = _infer_body(handler.body, handler_context, handler.lineno, solver)
solver.add(solver.z3_types.subtype(handler_body_type, result_type),
fail_message="Exception handler in line {}".format(handler.lineno))
return result_type
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 is_try(node):
return hasattr(ast, "Try") and isinstance(node, ast.Try) or \
hasattr(ast, "TryExcept") and isinstance(node, ast.TryExcept) or \
hasattr(ast, "TryFinally") and isinstance(node, ast.TryFinally)
def getNodeType(node_class):
return node_class.__name__.upper()
# Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
def getAlternatives(n):
if isinstance(n, ast.If):
return [n.body]
if isinstance(n, ast.Try):
return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
def getNodeType(node_class):
return node_class.__name__.upper()
# Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
def getAlternatives(n):
if isinstance(n, ast.If):
return [n.body]
if isinstance(n, ast.Try):
return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
def get_nontrivial_nodes(self):
# returns ids of nodes that can possibly raise an exception
nodes = []
for node_id, node_obj in self.nodes.items():
node = node_obj.ast_node
if type(node) not in (ast.Break, ast.Continue, ast.Pass, ast.Try):
nodes.append(node_id)
return nodes