PyInsider
See what your Python program actually did.
PyInsider records the real execution of a Python program — every function call, how long each took, how calls nested, what arguments went in, what came back, and the exact path that led to an exception — and lets you explore it afterward in an interactive local viewer.
It is not a profiler that gives you aggregate numbers, and it is not a debugger that stops the world. It is an execution recorder: run once, then look at what happened.
$ pyinsider run examples/nested_calls.py
recorded 22 calls · max depth 5 · 3.14 ms
trace written to traces/run-2026-08-29-001.tl
$ pyinsider open traces/run-2026-08-29-001.tl
serving viewer at http://127.0.0.1:8721 (Ctrl-C to stop)
- Deterministic, not sampled. Every call is recorded via CPython's
sys.setprofilehook — no statistical guessing. - No AI, no telemetry, no cloud. Everything runs and stays on your machine.
The viewer binds only to
127.0.0.1. Nothing is uploaded, ever. - Local-first trace files. A run produces a single versioned
.tlfile you can save, diff, and share. - Four clean layers. The tracing and analysis engines have no dependency on the UI, so you can use PyInsider entirely from Python if you prefer.
Installation
Requires Python 3.10+. PyInsider has no runtime dependencies.
pip install pyinsider
Or from a clone, for development:
git clone https://github.com/Yashjindal11/pyinsider.git
cd pyinsider
pip install -e ".[dev]"
Quickstart
Record a script and open the result:
pyinsider run examples/simple.py
pyinsider open traces/ # opens the most recent trace in your browser
Capture arguments and return values too:
pyinsider run examples/complex_values.py --detail
Forward arguments to your program (everything after -- goes to the script):
pyinsider run app.py -- --verbose input.csv
Prefer to stay in the terminal? Skip the browser:
pyinsider open traces/run-2026-08-29-001.tl --summary # top-level summary
pyinsider open traces/run-2026-08-29-001.tl --tree # printed call tree
Using it from Python
The recorder is a plain context manager. The UI is optional.
import pyinsider
with pyinsider.trace() as run:
result = do_some_work()
trace = run.result
run.save("work.tl")
# Analyse without any UI:
for stat in pyinsider.hot_paths(trace):
print(stat.key, stat.inclusive_ms)
pyinsider.checkpoint("loaded config") drops a labelled marker into the active
trace so you can find a moment on the timeline later.
The CLI
pyinsider run <script.py | -m module> [--detail] [-o FILE] [-- args...]
pyinsider open <file.tl | dir> [--summary | --tree | --no-browser]
pyinsider compare <before.tl> <after.tl>
pyinsider --version
runpreserves your program's exit code and forwards its arguments, so it is safe to drop in front of an existing command.openaccepts either a file or a directory (it picks the newest.tl).comparediffs two runs and highlights functions that got slower, faster, appeared, or disappeared.
Colour output honours NO_COLOR, TERM=dumb, and non-TTY pipes.
Trace files (.tl)
A .tl file is gzip-compressed JSON with an explicit schema version. It
contains the full call tree, timings (nanoseconds relative to run start),
captured values, exception information, and run metadata (Python version,
platform, detail level). There is no pickle and no code in a trace file —
it is safe to open and inspect by hand.
Trace files are forward-compatible within a major schema version and are rejected if the major version is newer than the reader understands.
The viewer
pyinsider open starts a tiny local web app (stdlib only, 127.0.0.1) that
shows:
- an interactive, zoomable timeline of the run,
- a virtualised call tree with inclusive/self timings,
- a source view pointing at where each call was defined,
- a details panel with arguments and return values,
- an exceptions view with the call path that led to each failure,
- hot paths and an aggregated flame graph,
- filtering by module, name, duration, and project-vs-library code.
Architecture
PyInsider is built in four layers, each depending only on the ones below it:
cli / api / viewer <- presentation (never imported by the engine)
|
trace model + analysis <- Trace, function_stats, hot_paths, compare
|
trace events <- typed, serialisable ExecutionEvent records
|
tracer / collector <- sys.setprofile instrumentation
The tracer and analysis code never import the CLI or viewer, so the engine is usable as a library and the UI can be replaced without touching the core.
Limitations
PyInsider is deliberately honest about what it can and cannot see. Highlights:
- Caught exceptions are attributed by walking the exception's traceback, so
only exceptions that propagate are marked; an exception swallowed by a
try/exceptis not attributed to the function that raised it. - C-level functions (built-ins, C extensions) are not recorded as calls.
- Timings include tracing overhead; treat them as relative, not absolute.
- Async and multi-threaded code is recorded per-thread/per-task but concurrency interleaving is simplified.
- Subprocesses are invisible to the tracer.
See docs/limitations.md for the full, detailed list —
it is required reading before you trust a number.
Development
pip install -e ".[dev]"
pytest # run the test suite
ruff check pyinsider # lint
mypy pyinsider # type-check
See CONTRIBUTING.md for the workflow and project layout.
License
MIT. PyInsider is free and open source.
Metadata
Release files for pyinsider 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyinsider-1.0.0.tar.gz | 64.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyinsider-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 130.6 kB
Release files / pyinsider-1.0.0.tar.gz
| Download URL | pyinsider-1.0.0.tar.gz |
|---|---|
| Size | 64.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0a77416bdedf44dce978bb75416fbf358729ffa28c5404bf350c367833915cbe
|
|
BLAKE2b-256 checksum How to use checksums |
f1274d9bc4463f236312f08260244b2f533bc1be1d7016d49d7e68f98ea0c09d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.
Transparency logRelease files / pyinsider-1.0.0-py3-none-any.whl
| Download URL | pyinsider-1.0.0-py3-none-any.whl |
|---|---|
| Size | 66.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d8a67aa12dcbb1d1275a5526cda769ae6944f9751e15828ee3e25250f80989ab
|
|
BLAKE2b-256 checksum How to use checksums |
1ae7ecd180fd84ec828141d4e1a64058b51a35f9fcb3380a0cc794b90f766b53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.
Transparency log