我们从Python开源项目中,提取了以下50个代码示例,用于说明如何使用ast.For()。
def __init__(self, stmt, context): self.stmt = stmt self.context = context self.stmt_table = { ast.Expr: self.expr, ast.Pass: self.parse_pass, ast.AnnAssign: self.ann_assign, ast.Assign: self.assign, ast.If: self.parse_if, ast.Call: self.call, ast.Assert: self.parse_assert, ast.For: self.parse_for, ast.AugAssign: self.aug_assign, ast.Break: self.parse_break, ast.Return: self.parse_return, } stmt_type = self.stmt.__class__ if stmt_type in self.stmt_table: self.lll_node = self.stmt_table[stmt_type]() elif isinstance(stmt, ast.Name) and stmt.id == "throw": self.lll_node = LLLnode.from_list(['assert', 0], typ=None, pos=getpos(stmt)) else: raise StructureException("Unsupported statement type", stmt)
def _is_for_yield(self, node: ast.For) -> bool: if node.orelse: return False if not isinstance(node.target, ast.Name): return False body = node.body if len(body) != 1: return False expr = body[0] if not isinstance(expr, ast.Expr): return False yield_ = expr.value if not isinstance(yield_, ast.Yield): return False name = yield_.value if not isinstance(name, ast.Name): return False if name.id != node.target.id: return False return True
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 is_iterator(node1, node2): if not isinstance(node1.parent, ast.For): return False try: if not node1.parent.target == node1: return False except: return False #if node1.parent_field != 'target': # return False current = node2.parent while current is not None: if node1.parent == current: return True current = current.parent return False
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 _infer_for(node, context, solver): """Infer the type for a for loop node Limitation: - The iterable can't be a tuple. For example: the following is not allowed: for x in (1, 2.0, "string"): .... """ iter_type = expr.infer(node.iter, context, solver) # Infer the target in the loop, inside the global context # Cases: # - Var name. Ex: for i in range(5).. # - Tuple. Ex: for (a,b) in [(1,"st"), (3,"st2")].. # - List. Ex: for [a,b] in [(1, "st"), (3, "st2")].. target_type = solver.new_z3_const("for_target") solver.add(axioms.for_loop(iter_type, target_type, solver.z3_types), fail_message="For loop in line {}".format(node.lineno)) _infer_assignment_target(node.target, context, target_type, solver) return _infer_control_flow(node, context, solver)
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 _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 visit_ListComp(self, t): result_append = ast.Attribute(ast.Name('.0', load), 'append', load) body = ast.Expr(Call(result_append, [t.elt])) for loop in reversed(t.generators): for test in reversed(loop.ifs): body = ast.If(test, [body], []) body = ast.For(loop.target, loop.iter, [body], []) fn = [body, ast.Return(ast.Name('.0', load))] args = ast.arguments([ast.arg('.0', None)], None, [], None, [], []) return Call(Function('<listcomp>', args, fn), [ast.List([], load)])
def visit_ListComp(self, t): t = self.generic_visit(t) add_element = ast.Attribute(ast.Name('.elements', load), 'append', load) body = ast.Expr(Call(add_element, [t.elt])) for loop in reversed(t.generators): for test in reversed(loop.ifs): body = ast.If(test, [body], []) body = ast.For(loop.target, loop.iter, [body], []) fn = [body, ast.Return(ast.Name('.elements', load))] args = ast.arguments([ast.arg('.elements', None)], None, [], None, [], []) result = Call(Function('<listcomp>', args, fn), [ast.List([], load)]) return ast.copy_location(result, t)
def visit_For(self, node: ast.For): node = self.generic_visit(node) if self._is_for_yield(node): yield_node = ast.YieldFrom(value = node.iter) expr_node = ast.Expr(value = yield_node) node = ast.copy_location(expr_node, node) node = ast.fix_missing_locations(node) return node
def listNotEmpty(a): """Determines that the iterable is NOT empty, if we can know that""" """Used for For objects""" if not isinstance(a, ast.AST): return False if type(a) == ast.Call: if type(a.func) == ast.Name and a.func.id in ["range"]: if len(a.args) == 1: # range(x) return type(a.args[0]) == ast.Num and type(a.args[0].n) != complex and a.args[0].n > 0 elif len(a.args) == 2: # range(start, x) if type(a.args[0]) == ast.Num and type(a.args[1]) == ast.Num and \ type(a.args[0].n) != complex and type(a.args[1].n) != complex and \ a.args[0].n < a.args[1].n: return True elif type(a.args[1]) == ast.BinOp and type(a.args[1].op) == ast.Add: if type(a.args[1].right) == ast.Num and type(a.args[1].right) != complex and a.args[1].right.n > 0 and \ compareASTs(a.args[0], a.args[1].left, checkEquality=True) == 0: return True elif type(a.args[1].left) == ast.Num and type(a.args[1].left) != complex and a.args[1].left.n > 0 and \ compareASTs(a.args[0], a.args[1].right, checkEquality=True) == 0: return True elif type(a) in [ast.List, ast.Tuple]: return len(a.elts) > 0 elif type(a) == ast.Str: return len(a.s) > 0 return False
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 getAllAssignedVarIds(a): if not isinstance(a, ast.AST): return [] ids = [] for child in ast.walk(a): if type(child) == ast.Assign: ids += gatherAssignedVarIds(child.targets) elif type(child) == ast.AugAssign: ids += gatherAssignedVarIds([child.target]) elif type(child) == ast.For: ids += gatherAssignedVarIds([child.target]) return ids
def test_base_classes(self): self.assertTrue(issubclass(ast.For, ast.stmt)) self.assertTrue(issubclass(ast.Name, ast.expr)) self.assertTrue(issubclass(ast.stmt, ast.AST)) self.assertTrue(issubclass(ast.expr, ast.AST)) self.assertTrue(issubclass(ast.comprehension, ast.AST)) self.assertTrue(issubclass(ast.Gt, ast.AST))
def test_for(self): x = ast.Name("x", ast.Store()) y = ast.Name("y", ast.Load()) p = ast.Pass() self.stmt(ast.For(x, y, [], []), "empty body on For") self.stmt(ast.For(ast.Name("x", ast.Load()), y, [p], []), "must have Store context") self.stmt(ast.For(x, ast.Name("y", ast.Store()), [p], []), "must have Load context") e = ast.Expr(ast.Name("x", ast.Store())) self.stmt(ast.For(x, y, [e], []), "must have Load context") self.stmt(ast.For(x, y, [p], [e]), "must have Load context")
def test_replace_with_constant(self): # list => tuple self.check_optimize('for x in [1, 2, 3]: pass', 'for x in (1, 2, 3): pass') # set => frozenset self.check_optimize('for x in {1, 2, 3}: pass', ast.For(target=ast.Name(id='x', ctx=ast.Store()), iter=ast.Constant(frozenset((1, 2, 3))), body=[ast.Pass()], orelse=[])) # don't optimize if items are not constants self.check_dont_optimize('for x in [1, x]: pass') self.check_dont_optimize('for x in {1, x}: pass')
def __init__(self): # True if we are unable to follow the namespace, False otherwise self._unknown_state = False # mapping: variable name => value, # value can be UNSET for unknown value self._variables = {} # True if we are inside a conditional block (ast.If, ast.For body, etc.) self._inside_cond = False
def visit_For(self, node): if not self.config.simplify_iterable: return new_iter = self.optimize_iterable(node.iter) if new_iter is None: return new_node = ast.For(target=node.target, iter=new_iter, body=node.body, orelse=node.orelse) copy_lineno(node, new_node) return new_node
def find_parallel_depth(node, base_depth): """ helper function to determine whether the outermost of the inner loops are labeled parallel """ result = check_loop_parallel(node) if result: return base_depth depth = [] base_depth += 1 for child in node.body: if isinstance(child, ast.For): child_depth = find_parallel_depth(child, base_depth) depth.append(child_depth) return depth
def add_to_block(self, node): ''' We want every try statement to be in its own block. ''' if not self.current_block: return # We only want the 'top level' statements if self.current_line_num >= node.lineno: return # Special cases - test must be in its own block if isinstance(node, ast.While) or isinstance(node, ast.For): if not self.is_empty_block(self.current_block): test_block = self.new_block() self.current_block.exit_blocks.append(test_block) self.use_next_block(test_block) self.current_line_num = node.lineno for f_block_type, f_block in reversed(self.frame_blocks): if f_block_type == F_BLOCK_EXCEPT: # Statement is in a try - set exits to next statement and # excepts self.current_block.statements.append(node) for handler in f_block: self.current_block.exit_blocks.append(handler) # Special case if isinstance(node, ast.While) or isinstance(node, ast.For): break next_statement_block = self.new_block() self.current_block.exit_blocks.append(next_statement_block) self.use_next_block(next_statement_block) break else: self.current_block.statements.append(node)
def do_Loop(self, node): ''' For and While loops are treated the same. The only difference is the possibility of iterators in a For loop. The loop body always returns to test unless there is a break or return. The else body is entered when the test is false but not when there is a break or an exception. The next block of the test could in theory be the else or after. But when we access it for the breaks we want it to be the after. ''' # Put the test in its own block test_block = self.current_block test_block.tag = Block.LOOP_HEADER self.push_frame_block(F_BLOCK_LOOP, test_block) after_loop_block = self.new_block() loop_body_block = self.new_block() self.add_to_exits(test_block, loop_body_block) test_block.next = after_loop_block self.use_block(loop_body_block) for z in node.body: self.visit(z) self.check_child_exits(self.current_block, test_block) self.pop_frame_block(F_BLOCK_LOOP, test_block) if node.orelse: else_body = self.new_block() self.add_to_exits(test_block, else_body) self.use_block(else_body) else_body.next = after_loop_block for z in node.orelse: self.visit(z) self.check_child_exits(self.current_block, after_loop_block) else: self.add_to_exits(test_block, after_loop_block) self.use_next_block(after_loop_block)
def addBinding(self, node, value): """ Called when a binding is altered. - `node` is the statement responsible for the change - `value` is the new value, a Binding instance """ # assert value.source in (node, node.parent): for scope in self.scopeStack[::-1]: if value.name in scope: break existing = scope.get(value.name) if existing and not self.differentForks(node, existing.source): parent_stmt = self.getParent(value.source) if isinstance(existing, Importation) and isinstance(parent_stmt, ast.For): self.report(messages.ImportShadowedByLoopVar, node, value.name, existing.source) elif scope is self.scope: if (isinstance(parent_stmt, ast.comprehension) and not isinstance(self.getParent(existing.source), (ast.For, ast.comprehension))): self.report(messages.RedefinedInListComp, node, value.name, existing.source) elif not existing.used and value.redefines(existing): self.report(messages.RedefinedWhileUnused, node, value.name, existing.source) elif isinstance(existing, Importation) and value.redefines(existing): existing.redefined.append(node) if value.name in self.scope: # then assume the rebound name is used as a global or within a loop value.used = self.scope[value.name].used self.scope[value.name] = value
def handleNodeStore(self, node): name = getNodeName(node) if not name: return # if the name hasn't already been defined in the current scope if isinstance(self.scope, FunctionScope) and name not in self.scope: # for each function or module scope above us for scope in self.scopeStack[:-1]: if not isinstance(scope, (FunctionScope, ModuleScope)): continue # if the name was defined in that scope, and the name has # been accessed already in the current scope, and hasn't # been declared global used = name in scope and scope[name].used if used and used[0] is self.scope and name not in self.scope.globals: # then it's probably a mistake self.report(messages.UndefinedLocal, scope[name].used[1], name, scope[name].source) break parent_stmt = self.getParent(node) if isinstance(parent_stmt, (ast.For, ast.comprehension)) or ( parent_stmt != node.parent and not self.isLiteralTupleUnpacking(parent_stmt)): binding = Binding(name, node) elif name == '__all__' and isinstance(self.scope, ModuleScope): binding = ExportBinding(name, node.parent, self.scope) else: binding = Assignment(name, node) self.addBinding(node, binding)
def reverse_loop(for_node): assert isinstance(for_node, ast.For) iter_node = for_node.iter new_iter_node = NewCall(func=ast.Name(id="reversed"), args=[iter_node]) return ast.For(target=for_node.target, iter=new_iter_node, body=for_node.body)
def is_stub(node): """Check if the function is a stub definition: For the function to be a stub, it should be fully annotated and should have no body. The body should be a single `Pass` statement with optional docstring. """ if not is_annotated(node): return False if len(node.body) == 1 and isinstance(node.body[0], ast.Expr) and isinstance(node.body[0].value, ast.Ellipsis): return True return ((len(node.body) == 1 and isinstance(node.body[0], ast.Pass)) or (len(node.body) == 2 and isinstance(node.body[0], ast.Expr) and isinstance(node.body[1], ast.Pass)))
def _infer_import(node, context, solver): """Infer the imported module in normal import statement The imported modules can be used with direct module access only. Which means, re-assigning the module to a variable or passing it as a function arg is not supported. For example, the following is not possible: - import X x = X - import X f(X) The importing supports deep module access. For example, the following is supported. >> A.py x = 1 >> B.py import A >> C.py import B print(B.A.x) """ for name in node.names: import_context = ImportHandler.infer_import(name.name, solver.config.base_folder, infer, solver) if name.asname: # import X as Y module_name = name.asname else: module_name = name.name # Store the module context in the current context. context.set_type(module_name, import_context) return solver.z3_types.none
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 get_markers_from_body_node(self, node): if isinstance(node, (ast.If, ast.While)): return {node.marker} | self.get_included_markers(node.test) elif isinstance(node, ast.For): return {node.marker} | self.get_included_markers(node.target) | self.get_included_markers(node.iter) elif isinstance(node, (ast.FunctionDef, ast.ClassDef)): return self.get_included_markers(node, without=node.body) else: return {node.marker}
def checkDeadScopes(self): """ Look at scopes which have been fully examined and report names in them which were imported but unused. """ for scope in self.deadScopes: if isinstance(scope.get('__all__'), ExportBinding): all_names = set(scope['__all__'].names) if not scope.importStarred and \ os.path.basename(self.filename) != '__init__.py': # Look for possible mistakes in the export list undefined = all_names.difference(scope) for name in undefined: self.report(messages.UndefinedExport, scope['__all__'].source, name) else: all_names = [] # Look for imported names that aren't used. for value in scope.values(): if isinstance(value, Importation): used = value.used or value.name in all_names if not used: messg = messages.UnusedImport self.report(messg, value.source, value.name) for node in value.redefined: if isinstance(self.getParent(node), ast.For): messg = messages.ImportShadowedByLoopVar elif used: continue else: messg = messages.RedefinedWhileUnused self.report(messg, node, value.name, value.source)
def parse_for(self): from .parser import ( parse_body, ) # Type 0 for, eg. for i in list(): ... if self._is_list_iter(): return self.parse_for_list() if not isinstance(self.stmt.iter, ast.Call) or \ not isinstance(self.stmt.iter.func, ast.Name) or \ not isinstance(self.stmt.target, ast.Name) or \ self.stmt.iter.func.id != "range" or \ len(self.stmt.iter.args) not in (1, 2): raise StructureException("For statements must be of the form `for i in range(rounds): ..` or `for i in range(start, start + rounds): ..`", self.stmt.iter) # noqa # Type 1 for, eg. for i in range(10): ... if len(self.stmt.iter.args) == 1: if not isinstance(self.stmt.iter.args[0], ast.Num): raise StructureException("Range only accepts literal values", self.stmt.iter) start = LLLnode.from_list(0, typ='num', pos=getpos(self.stmt)) rounds = self.stmt.iter.args[0].n elif isinstance(self.stmt.iter.args[0], ast.Num) and isinstance(self.stmt.iter.args[1], ast.Num): # Type 2 for, eg. for i in range(100, 110): ... start = LLLnode.from_list(self.stmt.iter.args[0].n, typ='num', pos=getpos(self.stmt)) rounds = LLLnode.from_list(self.stmt.iter.args[1].n - self.stmt.iter.args[0].n, typ='num', pos=getpos(self.stmt)) else: # Type 3 for, eg. for i in range(x, x + 10): ... if not isinstance(self.stmt.iter.args[1], ast.BinOp) or not isinstance(self.stmt.iter.args[1].op, ast.Add): raise StructureException("Two-arg for statements must be of the form `for i in range(start, start + rounds): ...`", self.stmt.iter.args[1]) if ast.dump(self.stmt.iter.args[0]) != ast.dump(self.stmt.iter.args[1].left): raise StructureException("Two-arg for statements of the form `for i in range(x, x + y): ...` must have x identical in both places: %r %r" % (ast.dump(self.stmt.iter.args[0]), ast.dump(self.stmt.iter.args[1].left)), self.stmt.iter) if not isinstance(self.stmt.iter.args[1].right, ast.Num): raise StructureException("Range only accepts literal values", self.stmt.iter.args[1]) start = Expr.parse_value_expr(self.stmt.iter.args[0], self.context) rounds = self.stmt.iter.args[1].right.n varname = self.stmt.target.id pos = self.context.new_variable(varname, BaseType('num')) self.context.forvars[varname] = True o = LLLnode.from_list(['repeat', pos, start, rounds, parse_body(self.stmt.body, self.context)], typ=None, pos=getpos(self.stmt)) del self.context.vars[varname] del self.context.forvars[varname] return o
def iter_expr_values(parent, node, child=None): """ Yield each value for *node* which can be tracked. Literals are returned as their evaluated value where as nodes which fail to evaluate to literals are returned as is. :param node parent: The parent node used to mark the start of the search path. :param node node: The target ast.Name node to find literal values for. :param node child: An optional child node to mark the end of the search path. """ child = child or node success, value = eval_ast.literal_expr(node) if success: yield value return if not isinstance(node, ast.Name): return test_nodes = collections.deque() def_nodes = get_definition_nodes(parent, node.id, child) for def_node_idx, def_node in enumerate(def_nodes): each = False next_node = (def_nodes[def_node_idx + 1] if len(def_nodes) > def_node_idx + 1 else child) src_node = None test_nodes.clear() if isinstance(def_node, ast.Assign): test_node = get_expr_value_src_dst(def_node.value, def_node.targets[0], node) if test_node: test_nodes.append(test_node) elif isinstance(def_node, ast.For): src_node = get_expr_value_src_dst(def_node.iter, def_node.target, node) each = node_is_child_of_parent(def_node.body, next_node) elif isinstance(def_node, ast.ListComp): for generator in def_node.generators: src_node = get_expr_value_src_dst(generator.iter, generator.target, node) if src_node: break if isinstance(src_node, (ast.List, ast.Tuple, ast.Set)): test_nodes.extend(src_node.elts if each else src_node.elts[-1:]) for test_node in test_nodes: success, value = eval_ast.literal_expr(test_node) if success: yield value continue for value in iter_expr_values(parent, test_node): success = True yield value if success: continue for def_node in get_definition_nodes(parent, test_node): for value in iter_expr_values(parent, def_node): success = True yield value yield test_node
def node_defines_name(node, name): """ Check if the specified statement node defines symbol *name*. :param node: The node to check. :param name: The symbol name to check. :return: Whether or not the node defines the symbole specified. :rtype: bool """ if isinstance(name, ast.Name): name = name.id if isinstance(node, ast.Assign): if node_targets_name(node, name): return True if isinstance(node.value, (ast.DictComp, ast.ListComp, ast.SetComp)): return node_defines_name(node.value, name) elif isinstance(node, ast.ClassDef): return node.name == name # these ones all assume the iterable will be executed at least once elif isinstance(node, (ast.DictComp, ast.GeneratorExp, ast.ListComp, ast.SetComp)): for generator in node.generators: target = generator.target if isinstance(target, ast.Name): if target.id == name: return True continue for child_node in iter_child_expr_nodes(target): if isinstance(child_node, ast.Name) and child_node.id == name: return True return False elif isinstance(node, ast.ExceptHandler): if isinstance(node.name, ast.Name): return node.name.id == name elif isinstance(node.name, str): return node.name == name elif isinstance(node, ast.Expr): if isinstance(node.value, (ast.DictComp, ast.GeneratorExp, ast.ListComp, ast.SetComp)): return node_defines_name(node.value, name) elif isinstance(node, ast.For): return isinstance(node.target, ast.Name) and node.target.id == name elif isinstance(node, ast.FunctionDef): return node.name == name elif isinstance(node, (ast.Import, ast.ImportFrom)): return next((alias for alias in node.names if (alias.asname or alias.name) == name), None) is not None return False