Skip to content

Getting started

Install

redef is not yet on PyPI. It is a single stdlib-only module; until release, vendor it:

curl -O https://raw.githubusercontent.com/.../redef.py   # or copy lib/redef.py

Python 3.10 through 3.14 are supported and tested, including under -O and -OO.

Your first rewrite

A transform is an ast.NodeTransformer (or any callable from ast.Module to ast.Module). Here is one that doubles every integer constant, applied to a function:

import ast
from redef import rewrite

class Double(ast.NodeTransformer):
    def visit_Constant(self, node):
        if isinstance(node.value, int) and not isinstance(node.value, bool):
            return ast.copy_location(ast.Constant(node.value * 2), node)
        return node

@rewrite(Double())
def answer(x):
    return x + 20

print(answer(1))    # 41: the constant 20 became 40 at definition time

Three things happened when Python executed the def:

  1. redef recovered the function's source, applied the repairs (dedent, decorator stripping, line-number offsets), and checked that the recovered text really defines answer, including recompiling it and comparing code objects (see Verification).
  2. Your transform received the parsed tree and returned it modified.
  3. The result was compiled under the module's own compiler flags and answer was re-defined from it, keeping its original defaults, __qualname__, and attributes.

Seeing what you did

A rewrite you cannot display is a rewrite you cannot review:

print(rewrite.expansion(answer))
# def answer(x):
#     return x + 40

When it refuses

redef fails loudly wherever the naive pipeline misbehaves silently. All errors derive from RedefError:

from redef import rewrite, RedefError

def outer():
    secret = 7
    def uses(x):
        return x + secret
    return rewrite(Double())(uses)

outer()
# ClosureUnsupported: closes over ('secret',); recompiling would turn
# these into global lookups (E5 F5)

Lambdas, functions carrying __wrapped__, sourceless contexts, and stale sources each raise their own error with the reason named. The catalogue is in Support matrix; the API in Reference.

The innermost rule

@rewrite(...) must be the decorator closest to def. Decorators apply bottom-up, so anything applied below the rewrite would be discarded by recompiling from source. redef refuses functions that advertise a wrapper (__wrapped__) and documents the rest of the contract; see Design.

Next