Skip to content

API reference

One module, four callables, seven exception types. Everything is stdlib-only.

rewrite(transform, verify=True)

Decorator factory. Returns a decorator that re-defines the function from its transformed AST.

  • transform: an ast.NodeTransformer instance (its visit is called on the Module) or a callable from ast.Module to ast.Module. Returning anything except the Module raises RedefError.
  • verify: run verify-by-recompile during acquisition. Default True.
  • Contract: must be the innermost decorator. Functions carrying __wrapped__ are refused with InnermostViolation.
  • Preserved from the original: __defaults__, __kwdefaults__, __qualname__, __dict__ entries. The module's __future__ compiler flags are inherited into the recompile.
  • Raises: any RedefError subclass below; ClosureUnsupported if the function has free variables.
@rewrite(MyTransformer())
def f(x): ...

rewrite.expansion(f)

The unparsed source of the transformed function, as compiled. Raises RedefError if f was not produced by rewrite. Stored on the function as __redef_source__.

recover(fn, verify=True)

Acquisition without transformation: returns (tree, meta).

  • tree: an ast.Module whose single statement is the FunctionDef (or AsyncFunctionDef), decorator list stripped, line numbers offset to true file positions.
  • meta: a dict with:
    • filename: the code object's co_filename
    • first_lineno: where the recovered snippet started in its file
    • repairs: which repairs ran, from "dedent", "strip-decorators", "increment-lineno", "verify-recompile", "verify-recompile-structural"
    • freevars: the function's co_freevars
  • Closures are accepted here; only recompilation refuses them. Verification compiles closures inside a synthetic enclosing scope.
  • Also available as rewrite.recover.

Use recover when your tool analyzes or relocates the body rather than re-defining it in place: transpilers, remote executors, DSL projectors.

gensym(base="tmp", avoid=None)

A fresh identifier of the form _{base}_{n}, guaranteed absent from every Name and argument in avoid (any AST node) when given. Process-global counter; successive calls never repeat.

Exceptions

All derive from RedefError.

Exception Raised when Attributes
SourceUnavailable no source exists in this context reason ("frozen-or-sourceless", "stdin", "repl", "bare-exec", "unknown: ..."), remedy (str or None)
SourceMismatch recovered text defines a different function, or a same-named body fails verification
SourceUnparseable recovered text does not parse
NotAFunction not a plain def (lambdas, non-functions)
ClosureUnsupported recompiling a function with free variables
InnermostViolation the function carries __wrapped__

Catching RedefError at your tool's boundary and re-raising in your own vocabulary is the intended pattern:

try:
    tree, meta = recover(fn)
except RedefError as exc:
    raise MyToolError(f"cannot read {fn.__name__}: {exc}") from exc

Versioning and stability

Unreleased. The shapes above are stable in intent; names (including the package name) are not. Supported interpreters: CPython 3.10 through 3.14, tested at -O and -OO.