4

I am learning AST and it seems like a powerful thing but I'm confused where the code went and why it disappeared. Say I want to rewrite

example = """def fake(x):\n
    y = ['useless list']\n
    return x
"""

as

example = """def fake(x):\n
    return x
"""

I can't see any way to rewrite in this manner. I can't even find a way to get the text of the line:

In [1]: example = """def fake(x):\n
   ...:     y = ['useless list']\n
   ...:     return x
   ...: """

In [3]: import ast

In [4]: p = ast.parse(example)

In [5]: p
Out[5]: <_ast.Module at 0x7f22f7274a10>

In [6]: p.body
Out[6]: [<_ast.FunctionDef at 0x7f22f7274a50>]

In [7]: p.body
Out[7]: [<_ast.FunctionDef at 0x7f22f7274a50>]

In [8]: f = p.body[0]

In [9]: f
Out[9]: <_ast.FunctionDef at 0x7f22f7274a50>

In [10]: f.body
Out[10]: [<_ast.Assign at 0x7f22f7274b10>, <_ast.Return at 0x7f22f7274c10>]

In [11]: f.name
Out[11]: 'fake'

In [12]: newf = f.body[1:]

In [13]: newf
Out[13]: [<_ast.Return at 0x7f22f7274c10>]

In [14]: z = newf[0]

In [15]: z.value
Out[15]: <_ast.Name at 0x7f22f7274c50>

In [16]: z.value.id
Out[16]: 'x'

Even more surprising is how it gives you the lineno of the start, but not the end. So you know where a function begins, but not where it ends, which is of no use

How can I grab the code and rewrite this func without the list y? Thank you

2
  • related: stackoverflow.com/q/768634/674039 Commented Mar 15, 2016 at 22:02
  • ast may not be the right tool, in general, for rewriting code. Consider something like libcst as well. Commented Oct 26, 2024 at 22:11

3 Answers 3

6

Maybe this will help you:

import ast
import astor

example = """
def fake(x):
    y = ['useless list']
    return x
"""

tree = ast.parse(example)

# iterating through list which is represents function on ast
for ind, item in enumerate(tree.body[0].body):
    if isinstance(item, ast.Assign) and isinstance(item.value, ast.List):
        del tree.body[0].body[ind]
        break

print astor.to_source(tree)

Better using more OOP:

class RemoveList(ast.NodeTransformer):
    def visit_FunctionDef(self, node):
        self.generic_visit(node)
        for leaf in node.body:
            if isinstance(leaf, ast.Assign) and isinstance(leaf.value, ast.List):
                del node.body[node.body.index(leaf)]
        ast.fix_missing_locations(node)
        return node


tree_class = ast.parse(example)
remove_list = RemoveList().visit(tree_class)
print astor.to_source(tree_class)

Even better using RedBaron Full Syntax Tree:

from redbaron import RedBaron

example = """
def fake(x):
    y = ['useless list']
    return x
"""
red = RedBaron(example)
methods = red.find_all('DefNode').data
for data in methods:
    if len(data.value.data) > 0:
        for vals in data.value.data:
            if vals[0].type == 'assignment' and vals[0].value.type == 'list':
                index = vals[0].index_on_parent
                par = vals[0].parent
                del par[index]
                break

print red.dumps()
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for you answer. RedBaron is awesome library that preserves all code source formatting and makes easy to traverse through nodes.
2

There is now a library that can tell you the exact range of text for each node: ASTTokens. Here's your example:

import ast, asttokens
atok = asttokens.ASTTokens(example, parse=True)

for node in ast.walk(atok.tree):
  if hasattr(node, 'lineno'):
    print atok.get_text_range(node), node.__class__.__name__, atok.get_text(node)

This would produce this output (note the positions in the text):

(0, 50) FunctionDef def fake(x):
    y = ['useless list']
    return x
(17, 37) Assign y = ['useless list']
(42, 50) Return return x
(9, 10) Name x
(17, 18) Name y
(21, 37) List ['useless list']
(49, 50) Name x
(22, 36) Str 'useless list'

Comments

2

As of python version 3.9 you can use the ast module itself for unparsing expression tree:

parsed = ast.parse(text)

source = ast.unparse(parsed)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.