wrapture — monkey patching and observability in a single mechanism
Posted on Wed, 16 Sep 2026 in Programación
Simon Willison has published a note recommending wrapture, the new library by Graham Dumpleton (author of wrapt and autowrapt). Released on August 31st, it's in beta ahead of 1.0.0 but already very usable. Its motto: "Wrap anything, capture everything, change nothing".

What it is¶
wrapture (wrapt + capture) is a Python library for attaching bindings to arbitrary call sites, without modifying the code being observed. One mechanism, three uses:
- Monkey patching: a clean lifecycle and behaviour vocabulary over
wrapt.wrap_object(): stub, fail, transform arguments or results, and remove again, with honest reporting if something else displaced the patch. - Unit testing: observe and assert how calls actually flowed through the real call graph (nesting, ordering, arguments and return values) and optionally intervene. Unlike a
unittest.mockMock(which fabricates values and can't see calls an object makes to itself), wrapture watches the real code run and offers strictstub()andmock()stand-ins. - Ad-hoc tracing: attach bindings to a running application — even one you cannot modify — and emit a structured, nested trace.
What catches my eye¶
Configuration without touching code: with a wrapture.toml naming the methods and a sink, you just run:
python -m wrapture manage.py runserver
And with autowrapt installed, not even the launcher is needed:
AUTOWRAPT_BOOTSTRAP=wrapture python manage.py runserver
OpenTelemetry export: the same recorded events can be sent to any OTLP backend as traces, metrics and correlated logs, enabled by one [otel] table in the config, with trace identity propagated via W3C traceparent headers between services.
Packaged instrumentation: the wrapture-instrumentation package covers flask, django, fastapi, starlette, aiohttp, httpx, requests, sqlalchemy, sqlite3, grpc, jinja2, uvicorn and more.
Minimal example¶
place = wrapture.binding(OrderService, "place")
charge = wrapture.binding(Gateway, "charge")
record = wrapture.binding(Ledger, "record")
with wrapture.timeline(place, charge, record) as tape:
OrderService().place(500)
print(tape.tree())
None of those classes know they are being observed.
Graham publishes tutorials almost daily and there are interactive workshops as JupyterLab notebooks. The idea that a test monkey patch can grow into production observability without rewriting code feels like a Swiss Army knife that will keep paying off for years.