Given an AST, is there a working library for getting the source?
Asked Answered
I

4

18

Is there a way to convert a given Python abstract syntax tree (AST) to a source code?

Here is a good example of how to use Python's ast module, specifically a NodeTransformer. I was looking for a way to convert the resulting AST back to source, so the changes can be inspected visually.

Intendance answered 22/9, 2010 at 22:41 Comment(0)
H
15

The Python source tree contains an implementation of this: unparse.py in the Demo/parser directory

Editor's note: With the introduction of ast.unparse() in Python 3.9, unparse.py has been removed, so the above link has been updated to point to 3.8.

Housecarl answered 25/9, 2010 at 14:48 Comment(5)
Thanks. It looks somewhat buggy, but I can use it as a starting point.Intendance
Interesting, I didn't look closely, what sorts of bugs do you see?Housecarl
Scratch that. Looks like it is alright in Python 2.7. I was trying on 2.6 and I found problems with things like for ... else, but 2.7 is fine so far.Intendance
Who wrote this? Only reference I could find is from this README "They were all written by me[...]" with no name.Nevermore
is there something similar to 'ast.unparse()' for Python3.7 ?Whitehall
G
7

As of Python 3.9, the ast module provides an unparse function for this:

Unparse an ast.AST object and generate a string with code that would produce an equivalent ast.AST object if parsed back with ast.parse()

Grabble answered 29/4, 2020 at 7:42 Comment(1)
Thanks. Yes, I am keeping an eye on it. Seems to be the best solution.Intendance
S
5

A nice third-party library I found: astunparse which is based on the unparse.py suggested by Ned in his answer. Example:

import ast
import astunparse

code = '''
class C:
    def f(self, arg):
        return f'{arg}'

print(C().f("foo" + 'bar'))
'''

print(astunparse.unparse(ast.parse(code)))

running which yields

class C():

    def f(self, arg):
        return f'{arg}'
print(C().f(('foo' + 'bar')))

Another neat function is astunparse.dump which pretty-prints the code object:

astunparse.dump(ast.parse(code))

Output:

Module(body=[
  ClassDef(
    name='C',
    bases=[],
    keywords=[],
    body=[FunctionDef(
      name='f',
      args=arguments(
        args=[
          arg(
            arg='self',
            annotation=None),
          arg(
            arg='arg',
            annotation=None)],
        vararg=None,
        kwonlyargs=[],
        kw_defaults=[],
        kwarg=None,
        defaults=[]),
      body=[Return(value=JoinedStr(values=[FormattedValue(
        value=Name(
          id='arg',
          ctx=Load()),
        conversion=-1,
        format_spec=None)]))],
      decorator_list=[],
      returns=None)],
    decorator_list=[]),
  Expr(value=Call(
    func=Name(
      id='print',
      ctx=Load()),
    args=[Call(
      func=Attribute(
        value=Call(
          func=Name(
            id='C',
            ctx=Load()),
          args=[],
          keywords=[]),
        attr='f',
        ctx=Load()),
      args=[BinOp(
        left=Str(s='foo'),
        op=Add(),
        right=Str(s='bar'))],
      keywords=[])],
    keywords=[]))])
Secrete answered 9/4, 2019 at 10:37 Comment(0)
V
1

Have a look at http://pypi.python.org/pypi/sourcecodegen/0.6.14

Vipul answered 30/11, 2011 at 20:50 Comment(1)
I know this is ancient, but this doesn't work with the ast module --- it only works with ASTs generated by the compiler.ast module.Toil

© 2022 - 2024 — McMap. All rights reserved.