astunparse

Converts a Python AST back into readable, re-parseable source code, plus a pretty-printing dump utility.

Library
PyPI
v1.6.3
230stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
37/100Needs Attention
Development Activity0
Maintenance0
Community68
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture68
Code Quality62
Innovation40
Learning Curve75

astunparse is a small, focused library that takes a Python abstract syntax tree and turns it back into source code. It is a factored-out, packaged version of the unparse.py script that ships in CPython’s own Demo/Tools directories, merging the Python 2.7 and 3.5 variants of that script into a single library with a wrapper API so both versions can share one implementation.

The core unparse(tree) function walks the AST node by node and writes out equivalent Python source, letting tools that parse, transform, and rewrite code (codegen, linters, AST-based refactoring tools, static analysis pipelines) go back from a modified tree to text without hand-rolling their own printer. A companion dump(tree) function pretty-prints the raw tree structure itself, which is useful for debugging what a parse or transformation actually produced.

Because it reuses code maintained by the Python core developers rather than reimplementing unparsing logic from scratch, its test suite round-trips large parts of the standard library to verify correctness — a bar the README notes several similar community projects (codegen, astor, astmonkey, astprint) do not consistently clear.

What You Get

  • astunparse.unparse(tree) — converts an AST (or subtree) back into Python source code as a string
  • astunparse.dump(tree) — pretty-prints an AST’s node structure for inspection and debugging
  • A test suite that round-trips against the Python standard library to validate unparsing correctness
  • Single-source compatibility across Python 2.6 through Python 3.5, useful for tooling that still spans both major versions
  • A minimal, dependency-light implementation (six at runtime) with no external parsing dependencies

Common Use Cases

  • Writing an AST-based code transformer or refactoring tool that needs to emit the modified code as text
  • Building a code generator that constructs Python source programmatically via the ast module
  • Debugging what ast.parse() produced for a given snippet by dumping the tree structure
  • Implementing linters or static-analysis tools that need to show a fixed/rewritten version of flagged code

Under The Hood

Architecture The library is intentionally small and split into two independent visitor-style traversals over ast.AST nodes: unparser.py defines an Unparser class whose dispatch() method routes each node type to a _NodeName method (following the ast.NodeVisitor naming convention but implemented by hand rather than subclassing ast.NodeVisitor), writing indented source text incrementally to a file-like buffer as it walks the tree; printer.py defines a Printer class that does subclass ast.NodeVisitor and instead recursively renders each node’s fields as a nested NodeName(field=value, ...) structure for debugging. __init__.py is a thin façade exposing unparse() and dump() as the only public entry points, each instantiating the relevant visitor against an in-memory StringIO buffer and returning the accumulated text — so the whole package has one clear extension point (add a _NodeName method) and one clear consumption path (call one of two functions).

Tech Stack Pure Python with a single runtime dependency, six, used purely for Python 2/3 string-type compatibility (six.text_type, six.moves.cStringIO) — a signal of the library’s 2014-era origin when 2/3 dual-support was standard practice. Packaging is classic setuptools/setup.py with the version read out of lib/astunparse/__init__.py via regex rather than a separate version file. Build/test automation runs through tox.ini and a Makefile, with Travis CI configured in .travis.yml.

Code Quality Tests live in tests/test_unparse.py and tests/test_dump.py, built on a shared AstunparseCommonTestCase base (in tests/common.py) using the standard-library unittest framework; the unparse tests specifically compile source to an AST, unparse it back to text, recompile that text to a second AST, and assert the two ASTs are structurally identical via ast.dump() equality — an effective round-trip correctness check rather than string-diffing output. There is no type annotation usage (predates widespread Python type hints) and no linter/formatter configuration in the repo. Error handling is minimal by design: unrecognized node types simply raise an AttributeError from the dispatch() lookup rather than a custom exception.

What Makes It Unique Unlike similar AST-to-source projects that reimplement unparsing logic independently, astunparse deliberately reuses the unparser that ships inside CPython’s own source tree (under Demo/parser for Python 2 and Tools/parser for Python 3), merging both branches into one cross-version library. That lineage is what lets its test suite round-trip large swaths of the standard library successfully, which the maintainer highlights as a correctness bar competing projects didn’t consistently meet at the time.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search