Pyccolo

Pyccolo (pronounced like the instrument “piccolo”) lets you change what Python does — observe it, rewrite values as they flow, or teach the language brand-new syntax — without touching bytecode, patching the interpreter, or hand-writing an ast.NodeTransformer. You write a small class, decorate a method with the moment you care about, and Pyccolo rewrites the program’s source so that moment calls your code.

That single idea scales a long way. The same twenty-line building block underlies statement-level code coverage, a reactive Jupyter kernel, a pipe operator, lazy imports, optional chaining, and reverse-mode autodiff over ordinary NumPy — all listed under examples.

A tracer in fifteen seconds

Here is a tracer that makes every float literal exact by promoting it to a Decimal — a real behavioral change in one handler:

from decimal import Decimal
import pyccolo as pyc


class ExactFloats(pyc.BaseTracer):
    @pyc.after_float
    def to_decimal(self, ret, *_, **__):
        return Decimal(str(ret))


with ExactFloats:
    print(pyc.exec("x = 0.1 + 0.2")["x"])
0.3

@pyc.after_float subscribes to_decimal to the “a float literal was just evaluated” event; whatever the handler returns replaces that value. No float in the pyc.exec block escaped the substitution, and nothing outside the with block was affected. That is the whole model — events and handlers — and everything else is built on it.

Why Pyccolo

  • Ergonomic — subscribe to an event by decorating a method. There is no bytecode to patch and no AST visitor to write by hand.

  • Composable — independently-written tracers layer just by nesting their with blocks; their return values thread through in order. See Compose multiple tracers.

  • Portable — instrumentation lives at the level of source code, so the same tracer runs on CPython 3.6 through 3.14 (a few features need 3.8+).

  • Pay-as-you-go — Pyccolo only rewrites a construct when some active tracer actually listens for it, so a hundred available events cost nothing until you use one.

Try it in your browser

You don’t have to install anything to get a feel for it: the live JupyterLite demo runs Pyccolo entirely in your browser.

How this documentation is organized

  • Start here installs Pyccolo and walks through your first tracer line by line.

  • Guides are task-oriented and example-dense: overriding values, composing tracers, guards and performance, running under imports/functions/the CLI, source-to-source rewriting, adding syntax, and the IPython integration.

  • Tutorials build complete tools end to end — a coverage tracer, optional chaining, a pipe operator, quick lambdas, lazy imports, a concolic-execution engine, and a variable watchpoint debugger.

  • How it works is the mental model: the rewrite pipeline, why tracers compose, and how pyc.exec and scoping fit together.

  • Reference is the precise, code-derived catalog of every event, method, and option.

Indices and tables