我们从Python开源项目中,提取了以下50个代码示例,用于说明如何使用ast.iter_fields()。
def generic_visit(self, node, phase=None): """Drive the visitor.""" phase = phase or constants.PRIMARY for _, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if not isinstance(item, ast.AST): continue if not self.pre_visit(item): continue self.visit(item, phase=phase) self.generic_visit(item, phase=phase) self.post_visit(item) elif isinstance(value, ast.AST): if not self.pre_visit(value): continue self.visit(value, phase=phase) self.generic_visit(value, phase=phase) self.post_visit(value)
def generic_visit(self, node: ast.AST) -> None: """Called if no explicit visitor function exists for a node.""" for _field, value in ast.iter_fields(node): if self.should_type_check: break if isinstance(value, list): for item in value: if self.should_type_check: break if isinstance(item, ast.AST): self.visit(item) elif isinstance(value, ast.AST): self.visit(value) # Generic mypy error
def is_before(node1, node2): """ checks if definately appears before node2 """ current = node2 while current is not None: try: if current.parent == node1.parent: for field, value in ast.iter_fields(node1.parent): if value == current or value == node1: return False elif isinstance(value, list) and current in value and node1 in value: list_index1 = value.index(node1) list_index2 = value.index(current) if list_index2 > list_index1: return True except: pass current = current.parent return False
def insert_before_parent_list_fixed(node_list, s): """ insert a string before a certain ast node if the node's parent has a field which is a list that contains the node """ for i in range(len(node_list)): parent = node_list[i].parent for field, value in ast.iter_fields(parent): if isinstance(value, list): try: index = value.index(node_list[i]) value[index:index] = ast.parse(s).body except: continue return
def visit_For(self, node): for field, value in ast.iter_fields(node): flag_cache = self.flag if field == 'target': self.flag = 'lhs' if isinstance(value, list): for item in value: if isinstance(item, ast.AST): self.visit(item) elif isinstance(value, ast.AST): self.visit(value) self.flag = flag_cache
def visit_Assign(self, node): for field, value in ast.iter_fields(node): if field == 'targets': self.flag = 'lhs' elif field == 'value': self.flag = 'rhs' if isinstance(value, list): for item in value: if isinstance(item, ast.AST): self.visit(item) elif isinstance(value, ast.AST): self.visit(value) self.flag = None
def add_after_node(ast_root, after_node, node_to_add): """Same idea as add_before_node, but in this case add it after after_node """ node, parent = find_node_recursive(ast_root, after_node) if node is None: raise ValueError("Node %s not found in ast: %s" % ( str(after_node), dump_ast(after_node))) for field, value in ast.iter_fields(parent): if isinstance(value, list): for i in range(len(value)): if isinstance(value[i], ast.AST) and \ nodes_are_equal(value[i], node): value.insert(i + 1, node_to_add) return
def get_all_nodes_in_bfs_order(ast_root): q = [ast_root] result = [] while len(q) > 0: top = q.pop(0) result.append(top) for field, value in ast.iter_fields(top): if isinstance(value, list): for item in value: if isinstance(item, ast.AST): q.append(item) elif isinstance(value, ast.AST): result.append(value) return result
def _walk_ast(self, node, top=False): if not hasattr(node, 'parent'): node.parent = None node.parents = [] for field, value in ast.iter_fields(node): if isinstance(value, list): for index, item in enumerate(value): if isinstance(item, ast.AST): self._walk_ast(item) self._set_parnt_fields(item, node, field, index) elif isinstance(value, ast.AST): self._walk_ast(value) self._set_parnt_fields(value, node, field) if top: return ast.walk(node)
def run_in_context(code, context, defs={}): ast_ = ast.parse(code, '<code>', 'exec') last_expr = None last_def_name = None for field_ in ast.iter_fields(ast_): if 'body' != field_[0]: continue if len(field_[1]) > 0: le = field_[1][-1] if isinstance(le, ast.Expr): last_expr = ast.Expression() last_expr.body = field_[1].pop().value elif isinstance(le, (ast.FunctionDef, ast.ClassDef)): last_def_name = le.name exec(compile(ast_, '<hbi-code>', 'exec'), context, defs) if last_expr is not None: return eval(compile(last_expr, '<hbi-code>', 'eval'), context, defs) elif last_def_name is not None: return defs[last_def_name] return None
def extract_option_from_arg_list(options, optname, default_value): if not options: return default_value, options try: args = list(ast.iter_fields(ast.parse(f"f({options})", mode='eval')))[0][1].keywords for idx,field in enumerate(args): if field.arg == optname: try: value = eval(compile(ast.Expression(body=field.value), filename="<ast>", mode="eval")) new_options = ','.join([x for x in options.split(',') if not x.strip().startswith(optname)]) return value, new_options.strip() except: raise ValueError(f"A constant value is expected for option {optname}: {options} provided.") return default_value, options except SyntaxError as e: raise ValueError(f"Expect a list of keyword arguments: {options} provided")
def _walk_fields(self, state, node, ctx): """ Traverses all fields of an AST node. """ if self._transform: transformed = False new_fields = {} new_state = state for field, value in ast.iter_fields(node): block_context = field in _BLOCK_FIELDS and type(value) == list new_state, new_value = self._walk_field( new_state, value, ctx, block_context=block_context) if self._transform: new_fields[field] = new_value if new_value is not value: transformed = True if self._transform and transformed: return new_state, type(node)(**new_fields) else: return new_state, node
def ast2tree(node, include_attrs=True): def _transform(node): if isinstance(node, ast.AST): fields = ((a, _transform(b)) for a, b in ast.iter_fields(node)) if include_attrs: attrs = ((a, _transform(getattr(node, a))) for a in node._attributes if hasattr(node, a)) return (node.__class__.__name__, dict(fields), dict(attrs)) return (node.__class__.__name__, dict(fields)) elif isinstance(node, list): return [_transform(x) for x in node] elif isinstance(node, str): return repr(node) return node if not isinstance(node, ast.AST): raise TypeError('expected AST, got %r' % node.__class__.__name__) return _transform(node)
def findListId(a, id): # We want to go one level up to get the list this belongs to if type(a) == list and len(a) > 0 and hasattr(a[0], "global_id") and a[0].global_id == id: return a if type(a) == list: for item in a: tmp = findListId(item, id) if tmp != None: return tmp elif isinstance(a, ast.AST): for (field, val) in ast.iter_fields(a): tmp = findListId(val, id) if tmp != None: return tmp return None
def dump(node, annotate_fields=True, include_attributes=False): """ Return a formatted dump of the tree in *node*. This is mainly useful for debugging purposes. The returned string will show the names and the values for fields. This makes the code impossible to evaluate, so if evaluation is wanted *annotate_fields* must be set to False. Attributes such as line numbers and column offsets are not dumped by default. If this is wanted, *include_attributes* can be set to True. """ def _format(node): if isinstance(node, AST): fields = [(a, _format(b)) for a, b in iter_fields(node)] rv = '%s(%s' % (node.__class__.__name__, ', '.join( ('%s=%s' % field for field in fields) if annotate_fields else (b for a, b in fields) )) if include_attributes and node._attributes: rv += fields and ', ' or ' ' rv += ', '.join('%s=%s' % (a, _format(getattr(node, a))) for a in node._attributes) return rv + ')' elif isinstance(node, list): return '[%s]' % ', '.join(_format(x) for x in node) return repr(node) if not isinstance(node, AST): raise TypeError('expected AST, got %r' % node.__class__.__name__) return _format(node)
def test_comprehensions(self): # See https://bitbucket.org/plas/thonny/issues/8/range-marker-doesnt-work-correctly-with for source in ( "[(key, val) for key, val in ast.iter_fields(node)]", "((key, val) for key, val in ast.iter_fields(node))", "{(key, val) for key, val in ast.iter_fields(node)}", "{key: val for key, val in ast.iter_fields(node)}", "[[c for c in key] for key, val in ast.iter_fields(node)]"): m = self.create_mark_checker(source) m.verify_all_nodes(self)
def test_iter_fields(self): node = ast.parse('foo()', mode='eval') d = dict(ast.iter_fields(node.body)) self.assertEqual(d.pop('func').id, 'foo') self.assertEqual(d, {'keywords': [], 'kwargs': None, 'args': [], 'starargs': None})
def str_ast_node(node): if isinstance(node, ast.AST): fields = [(name, str_ast_node(val)) for name, val in ast.iter_fields(node) if name not in ('left', 'right')] rv = '%s(%s' % (node.__class__.__name__, ', '.join('%s=%s' % field for field in fields)) return rv + ')' else: return repr(node)
def ast_pretty_dump(node, annotate_fields=True, include_attributes=False, indent=' '): """ Originally copied from ast_demo.dump() source code https://github.com/st3fan/pythoncodeanalysis/blob/master/utils/astpp.py Return a formatted dump of the tree in *node*. This is mainly useful for debugging purposes. The returned string will show the names and the values for fields. This makes the code impossible to evaluate, so if evaluation is wanted *annotate_fields* must be set to False. Attributes such as line numbers and column offsets are not dumped by default. If this is wanted, *include_attributes* can be set to True. """ def _format(node, level=0): if isinstance(node, ast.AST): fields = [(a, _format(b, level)) for a, b in ast.iter_fields(node)] if include_attributes and node._attributes: fields.extend([(a, _format(getattr(node, a), level)) for a in node._attributes]) return ''.join([ node.__class__.__name__, '(', ', '.join(('%s=%s' % field for field in fields) if annotate_fields else (b for a, b in fields)), ')']) elif isinstance(node, list): lines = ['['] lines.extend((indent * (level + 2) + _format(x, level + 2) + ',' for x in node)) if len(lines) > 1: lines.append(indent * (level + 1) + ']') else: lines[-1] += ']' return '\n'.join(lines) return repr(node) if not isinstance(node, ast.AST): raise TypeError('expected AST, got %r' % node.__class__.__name__) return _format(node)
def preprocess_nodes(self, node): """Run preprocessors on nodes for the visitor.""" for _, value in ast.iter_fields(node): if isinstance(value, list): max_idx = len(value) - 1 for idx, item in enumerate(value): if not isinstance(item, ast.AST): continue if idx < max_idx: setattr(item, 'sibling', value[idx + 1]) else: setattr(item, 'sibling', None) setattr(item, 'parent', node) setattr(item, 'storage', {}) if not self.pre_visit(item, preprocess=True): continue self.preprocess_nodes(item) self.post_visit(item) elif isinstance(value, ast.AST): setattr(value, 'sibling', None) setattr(value, 'parent', node) setattr(value, 'storage', {}) if not self.pre_visit(value, preprocess=True): continue self.preprocess_nodes(value) self.post_visit(value)
def generic_visit(self, node, container=None): for field, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, ast.AST): yield from self.visit(item, container) elif isinstance(value, ast.AST): yield from self.visit(value, container)
def generic_visit(self, node): """Called if no explicit visitor function exists for a node.""" for _, value in ast.iter_fields(node): if isinstance(value, list): self._handle_ast_list(value) for item in value: if isinstance(item, ast.AST): self.visit(item) elif isinstance(value, ast.AST): self.visit(value)
def _iter_all_ast(node): yield node for field, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, ast.AST): for child in _iter_all_ast(item): yield child elif isinstance(value, ast.AST): for child in _iter_all_ast(value): yield child
def copy_node(node): new_node = type(node)() for field, value in ast.iter_fields(node): setattr(new_node, field, value) for attr in node._attributes: try: value = getattr(node, attr) except AttributeError: pass else: setattr(new_node, attr, value) return new_node
def generic_visit(self, node): for field, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, ast.AST): res = self.visit(item) if not res: return False elif isinstance(value, ast.AST): res = self.visit(value) if not res: return False return True
def find_parent_field(parent, node): """ assume parent is the ancestor of node, return the field that derives to node in parent """ current = node while current.parent != parent: current = current.parent for field, value in ast.iter_fields(parent): if isinstance(value, list): if current in value: return field elif current == value: return field return None
def visit_Subscript(self, node): """ tag variables that are followed by index as array """ try: if node.value.id not in self.array_name: self.array_name.append(node.value.id) except: pass for field, value in ast.iter_fields(node): flag_cache = self.flag #index_cache = self.index_name #self.index_name = node.value if field == 'slice': self.flag = None elif field == 'ctx': self.flag = None if isinstance(value, list): for item in value: if isinstance(item, ast.AST): self.visit(item) elif isinstance(value, ast.AST): self.visit(value) self.flag = flag_cache #self.index_name = index_cache
def visit_Subscript(self, node): ind_node = node.slice for field, value in ast.iter_fields(ind_node): if field == 'value': if isinstance(value, ast.Tuple): try: for i in range(len(value.elts)): ind_value = py_ast.dump_ast(value.elts[i]) self.value.append(ind_value) self.write.append([]) self.visit(value.elts[i]) except: pass else: try: ind_value = py_ast.dump_ast(value) self.value.append(ind_value) self.write.append([]) self.visit(value) except: pass elif field == 'dims': try: for i in range(len(value)): ind_value = py_ast.dump_ast(value[i]) self.value.append(ind_value) self.write.append([]) self.visit(value[i]) except: pass
def replace_node(ast_root, node_to_replace, replacement_node): """Replaces node_to_replace with replacement_node in the ast. """ # first, search for the node #node, parent = find_node_recursive(ast_root, node_to_replace) if not hasattr(node_to_replace, 'parent'): add_parent_info(ast_root) # if you can't find the node you want to replace, raise an error if not hasattr(node_to_replace, 'parent'): raise ValueError("Node %s not found in ast: %s" % ( str(node_to_replace), dump_ast(node_to_replace))) parent = node_to_replace.parent # otherwise, find the node, within its parent, and replace it for field, value in ast.iter_fields(parent): if isinstance(value, list): for i in range(len(value)): if isinstance(value[i], ast.AST) and \ nodes_are_equal(value[i], node_to_replace): value[i] = replacement_node return elif isinstance(value, ast.AST) and nodes_are_equal(value, node_to_replace): setattr(parent, field, replacement_node) setattr(replacement_node, 'parent', parent) return
def add_before_node(ast_root, before_node, node_to_add): """Attempts to add node_to_add before before_node For example, if you had the code: def foo(j): for i in range(j): print(i) and before_node was "for i in range(j):" and node_to_add was "print(2)", the result would be: def foo(i): print(2) for i in range(j): print(i) """ node, parent = find_node_recursive(ast_root, before_node) if node is None: raise ValueError("Node %s not found in ast: %s" % ( str(before_node), dump_ast(before_node))) for field, value in ast.iter_fields(parent): if isinstance(value, list): for i in range(len(value)): if isinstance(value[i], ast.AST) and \ nodes_are_equal(value[i], node): value.insert(i, node_to_add) return
def _LiteralEval(value): """Parse value as a Python literal, or container of containers and literals. First the AST of the value is updated so that bare-words are turned into strings. Then the resulting AST is evaluated as a literal or container of only containers and literals. This allows for the YAML-like syntax {a: b} to represent the dict {'a': 'b'} Args: value: A string to be parsed as a literal or container of containers and literals. Returns: The Python value representing the value arg. Raises: ValueError: If the value is not an expression with only containers and literals. SyntaxError: If the value string has a syntax error. """ root = ast.parse(value, mode='eval') if isinstance(root.body, ast.BinOp): raise ValueError(value) for node in ast.walk(root): for field, child in ast.iter_fields(node): if isinstance(child, list): for index, subchild in enumerate(child): if isinstance(subchild, ast.Name): child[index] = _Replacement(subchild) elif isinstance(child, ast.Name): replacement = _Replacement(child) node.__setattr__(field, replacement) # ast.literal_eval supports the following types: # strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None # (bytes and set literals only starting with Python 3.2) return ast.literal_eval(root)
def generic_visit(self, node): for field, old_value in ast.iter_fields(node): old_value = getattr(node, field, None) if isinstance(old_value, list): old_value[:] = self.visit_list(old_value) elif isinstance(old_value, ast.AST): new_node = self.visit(old_value) if new_node is None: delattr(node, field) else: setattr(node, field, new_node) return node
def generic_visit(self, node): """Called if no explicit visitor function exists for a node.""" for field, value in ast.iter_fields(node): if isinstance(value, list): self.visit_list(value) elif isinstance(value, ast.AST): self.visit(value)
def generic_visit(self, node): """Called if no explicit visitor function exists for a node.""" res = [] for field, value in ast.iter_fields(node): if isinstance(value, list): for item in value: vv = self.visit(item) res.append(vv) elif isinstance(value, dict): for k, v in value: res.append(self.visit(v)) res.append(self.visit(value)) if not res: print("visiting", node) return list(filter(None, res))
def visit_Compare(self, node): if len(node.ops) not in (1, 2,): raise SyntaxError("ast.Compare with more than 2 ops: %s is not supported" % node) (_, left), (_, ops), (_, comps) = ast.iter_fields(node) self.visit(left) left = self.data.pop() comparators = list() for comparator in comps: self.visit(comparator) comparators.append(self.data.pop()) if len(ops) == 1: right = comparators[0] cls = criteria_class.lookup(ast_op_to_criteria.lookup(type(ops[0]))) criteria = cls(left, *right) if type(right) in (list, tuple,) else cls(left, right) self.data.append(criteria) else: lower = left lower_op = ast_op_to_operator.lookup(type(ops[0])) one = comparators[0] upper_op = ast_op_to_operator.lookup(type(ops[1])) upper = comparators[1] criteria = criteria_class.instance(Const.Between, lower, one, upper, lower_op, upper_op) self.data.append(criteria)
def visit_Call(self, node): fields = {k: v for k, v in ast.iter_fields(node) if v} self.visit(fields[Const.func]) name, args, kwargs = self.data.pop(), list(), collections.OrderedDict() func = SyntaxAstCallExtender.find_deserializer(name) if not func: raise SyntaxError("%s is not supported" % name) if Const.args in fields: for arg in fields[Const.args]: self.visit(arg) args.append(self.data.pop()) if Const.keywords in fields: for keyword in fields[Const.keywords]: (_, key), (_, value) = ast.iter_fields(keyword) self.visit(value) kwargs[key] = self.data.pop() if Const.kwargs in fields: (_, knodes), (_, vnodes) = ast.iter_fields(fields[Const.kwargs]) for knode, vnode in zip(knodes, vnodes): self.visit(knode) key = self.data.pop() self.visit(vnode) value = self.data.pop() kwargs[key] = value obj = func(*args, **kwargs) self.data.append(obj)
def generic_visit(self, node, inner=False): for _, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, ast.AST): self.visit(item, inner) elif isinstance(value, ast.AST): self.visit(value, inner)
def generic_visit(self, node): for field, old_value in ast.iter_fields(node): if isinstance(old_value, list): generator = self.generic_visit_list(old_value) elif isinstance(old_value, ast.AST): generator = self.generic_visit_real_node(node, field, old_value) else: generator = [] for _ in generator: yield node
def str_node(node): if isinstance(node, ast.AST): fields = [(name, str_node(val)) for name, val in ast.iter_fields(node) if name not in ('left', 'right')] rv = '%s(%s' % (node.__class__.__name__, ', '.join('%s=%s' % field for field in fields)) return rv + ')' else: return repr(node)
def ast_visit(node, level=0): print(' ' * level + str_node(node)) for field, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, ast.AST): ast_visit(item, level=level+1) elif isinstance(value, ast.AST): ast_visit(value, level=level+1)
def filter_arguments(arguments, bound_argnames): """ Filters a node containing function arguments (an ``ast.arguments`` object) to exclude all arguments with the names present in ``bound_arguments``. Returns the new ``ast.arguments`` node. """ assert type(arguments) == ast.arguments new_params = dict(ast.iter_fields(arguments)) new_params['args'], new_params['defaults'] = filter_arglist( arguments.args, arguments.defaults, bound_argnames) new_params['kwonlyargs'], new_params['kw_defaults'] = filter_arglist( arguments.kwonlyargs, arguments.kw_defaults, bound_argnames) vararg_name = arguments.vararg.arg if arguments.vararg is not None else None kwarg_name = arguments.kwarg.arg if arguments.kwarg is not None else None if vararg_name is not None and vararg_name in bound_argnames: new_params['vararg'] = None if kwarg_name is not None and kwarg_name in bound_argnames: new_params['kwarg'] = None return ast.arguments(**new_params)