Skip to content

Verification

redef checks that the source it recovered is really the source of the function it is about to rewrite. Two layers, both on by default.

The name check

The recovered definition's name must equal fn.__name__. This catches the classic stale-cache case: a linecache entry that outlived its notebook cell, handing the pipeline valid source for a different function. Without the check, the pipeline rewrites the wrong function and returns something that works, which is the worst available outcome.

Verify-by-recompile

The name check cannot catch a stale body under the same name, which is exactly what re-editing and re-running a cell produces. So redef recompiles the recovered, untransformed source, under the function's own compiler flags, and compares the resulting code object with the live one, structurally: bytecode, names, variable names, free variables, argument count, and constants, with nested code objects (comprehensions, inner defs, __annotate__) compared recursively and location tables excluded. Functions with free variables are compiled inside a synthetic enclosing scope so their names stay free.

The verdict is graded:

Verdict Meaning Result
match byte-exact agreement proceed; "verify-recompile" recorded
structural same names, varnames, consts, argcount; different instruction bytes proceed; "verify-recompile-structural" recorded
mismatch anything else SourceMismatch raised

Why structural exists

A valid .pyc can carry another compiler's output. Bytecode caches validate on source timestamp and a magic number, and two CPython builds can share the magic while selecting instructions differently; we observed a GIL 3.14.6 serving a cache compiled by a free-threaded 3.14.5. The live code was genuinely not the running compiler's output for the current text, and it was genuinely not stale either. Byte-exact comparison cannot have both cases; the graded verdict accepts identical structure and records the downgrade.

The price is stated rather than hidden: a stale edit that changes only instruction structure, while preserving every name and constant, is accepted. Real edits nearly always move a name or a constant. The rename case that motivated the whole check is caught precisely because names are compared.

Measured rather than asserted

The check's reliability is an experiment in the research programme (E6): a battery of 22 function shapes, on five CPython versions, at three optimization levels, run from real files, twice, once under a module-level from __future__ import annotations. Zero false positives in 330 cells; the stale same-named body is detected; a byte-identical re-registration stays quiet. The check's first field trial, on a 73-test suite, initially failed and forced two fixes (future flags, cross-build caches) that are now battery cells; it then ran green, and the default became on.

Turning it off

@rewrite(MyTransformer(), verify=False)
def f(...): ...

verify=False keeps the name check and drops the recompile comparison. Reasons to do it: an environment with deliberately foreign bytecode caches, or a hot path decorating thousands of functions where the extra compile per decoration measures. Reasons not to: everything on this page.