English 中文(简体)
以查询取代 AST 节点
原标题:Inline replace of AST node by query
Given input like: query = ("class_name", "function_name", "arg_name") How do I replace what is found with some other provided node? Parsed example of the before stage: class Foo(object): def f(self, g: str = "foo"): pass Parsed example of the after stage: class Foo(object): def f(self, g: int = 5): pass Given the following call to a hypothetical function: replace_ast_node( query=("Foo", "f", "g"), node=ast.parse("class Foo(object): def f(self, g: str = foo ): pass"), # Use `AnnAssign` over `arg`; as `defaults` is higher in the `FunctionDef` replace_with=AnnAssign( annotation=Name(ctx=Load(), id="int"), simple=1, target=Name(ctx=Store(), id="g"), value=Constant(kind=None, value=5), ), ) I ve hacked together a simple solution for finding a node with the query list, which has the added benefit of working for anything ("Foo", "f", "g") could refer to def Foo(): def f(): def g():, as well as a parser/emitter from arg to AnnAssign. But I can t figure this stage out; does ast.NodeTransformer traverse in-order, and sequentially? - So should I be constantly traversing, appending current name, and checking if current location is the full query string? - I feel like there s some clean solution I m missing…
最佳回答
I decided to split it into two problems. The first, give every node awareness of its place in the universe: def annotate_ancestry(node): """ Look to your roots. Find the child; find the parent. Sets _location attribute to every child node. :param node: AST node. Will be annotated in-place. :type node: ```ast.AST``` """ node._location = [node.name] if hasattr(node, name ) else [] parent_location = [] for _node in ast.walk(node): name = [_node.name] if hasattr(_node, name ) else [] for child in ast.iter_child_nodes(_node): if hasattr(child, name ): child._location = name + [child.name] parent_location = child._location elif isinstance(child, ast.arg): child._location = parent_location + [child.arg] Then implement one method of the aforementioned ast.NodeTransformer: class RewriteAtQuery(ast.NodeTransformer): """ Replace the node at query with given node :ivar search: Search query, e.g., [ class_name , method_name , arg_name ] :ivar replacement_node: Node to replace this search """ def __init__(self, search, replacement_node): """ :param search: Search query :type search: ```List[str]``` :param replacement_node: Node to replace this search :type replacement_node: ```ast.AST``` """ self.search = search self.replacement_node = replacement_node self.replaced = False def generic_visit(self, node): """ Visit every node, replace once, and only if found :param node: AST node :type node: ```ast.AST``` :returns: AST node, potentially edited :rtype: ```ast.AST``` """ if not self.replaced and hasattr(node, _location ) and node._location == self.search: node = self.replacement_node self.replaced = True return ast.NodeTransformer.generic_visit(self, node) And you re done =) Usage/test: parsed_ast = ast.parse(class_with_method_and_body_types_str) annotate_ancestry(parsed_ast) rewrite_at_query = RewriteAtQuery( search="C.method_name.dataset_name".split("."), replacement_node=arg( annotation=Name(ctx=Load(), id="int"), arg="dataset_name", type_comment=None, ), ).visit(parsed_ast) self.assertTrue(rewrite_at_query.replaced, True) # Additional test to compare AST produced with desired AST [see repo]
问题回答

暂无回答




相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签