timerx
timerx is a tiny, dependency-free timing utility for Python. It gives you one simple API for timing functions, code blocks, and named stopwatches, then keeps cumulative stats so you can inspect timings programmatically or print a compact summary.
Use it when you want quick timing information without setting up a profiler or
manually calling time.perf_counter() throughout your code.
Features
- Works as a decorator, context manager, or manual stopwatch
- Supports sync and async functions
- Accumulates count, total, average, min, max, and last duration
- Records timings even when decorated functions or context blocks raise
- Supports concurrent named stopwatches
- Provides isolated
TimerX()instances for libraries and tests - Uses only the Python standard library at runtime
Install
pip install timerx
For local development:
pip install -e ".[test]"
pytest
Quick Example
This example shows the three main ways to use timerx: decorate a function, measure a block, and manually start and stop a named timer.
import time
import timerx
@timerx.track
def train_model():
time.sleep(0.2)
train_model()
train_model()
with timerx.lap("preprocessing"):
time.sleep(0.05)
timerx.start("postprocess")
time.sleep(0.01)
elapsed = timerx.stop("postprocess")
print(f"postprocess took {elapsed:.4f}s")
print(timerx.summary())
Example summary:
name count total avg min max last
------------- ----- -------- -------- -------- -------- --------
train_model 2 400ms 200ms 200ms 200ms 200ms
preprocessing 1 50ms 50ms 50ms 50ms 50ms
postprocess 1 10ms 10ms 10ms 10ms 10ms
Timing Functions
Use @timerx.track when you want to measure every call to a function. It works
with or without parentheses. By default, the function name is used as the timing
label, but you can provide a custom name.
@timerx.track
def load_data():
return [1, 2, 3]
@timerx.track()
def preprocess():
return "ready"
@timerx.track(name="model.fit")
def train():
return "done"
Stats accumulate across multiple calls:
load_data()
load_data()
stats = timerx.get_stats()
print(stats["load_data"]["count"]) # 2
print(stats["load_data"]["avg"]) # average duration in seconds
Decorated functions are recorded even if they raise an exception, and the original exception is still raised normally.
Timing Async Functions
track also supports coroutine functions.
@timerx.track(name="fetch")
async def fetch_rows():
return await client.get("/rows")
Timing Code Blocks
Use timerx.lap(name) as a context manager when you want to measure part of a
function. Laps record timings even when the block raises, and nested laps work
naturally.
with timerx.lap("pipeline"):
with timerx.lap("load"):
rows = load_rows()
with timerx.lap("transform"):
rows = transform(rows)
Stopwatches
Use start(name) and stop(name) when the start and end of the work are in
different places. Named stopwatches can run concurrently. If you start the same
name more than once, timerx treats it as a stack, so stop(name) closes the most
recent start.
timerx.start("download")
timerx.start("parse")
timerx.stop("parse")
timerx.stop("download")
stop(name) returns the elapsed duration in seconds and also records it in the
same stats store used by decorators and laps.
Reading Results
Use summary() for human-readable output:
print(timerx.summary())
print(timerx.summary(unit="ms"))
print(timerx.summary(sort_by="total")) # most expensive first
Supported units are auto, s, ms, us, µs, and microseconds. Auto mode
picks seconds, milliseconds, or microseconds per value.
Pass sort_by with any stat column name (count, total, avg, min, max,
last) to sort rows descending by that column. Default is insertion order.
Use get_stats() when you need data for tests, logs, dashboards, or your own
formatting:
stats = timerx.get_stats()
{
"preprocessing": {
"count": 1,
"total": 0.00512,
"min": 0.00512,
"max": 0.00512,
"last": 0.00512,
"avg": 0.00512,
}
}
Durations in get_stats() are always stored as seconds.
Isolated Instances
The top-level timerx.track, timerx.lap, timerx.start, and timerx.stop
helpers share one global timer. For libraries, tests, or applications that need
separate timing state, create a TimerX() instance.
from timerx import TimerX
tx = TimerX()
with tx.lap("local"):
run_work()
print(tx.get_stats())
Resetting
Use reset() to clear recorded timings and running stopwatches.
timerx.reset()
Development
pip install -e ".[test]"
pytest
python examples/demo.py
Contributing
Contributions are welcome. If you find a bug, have an API idea, or want to add coverage for an edge case, please open an issue or pull request.
License
timerx is released under the MIT License. See LICENSE for details.
Metadata
Release files for timerx 0.4.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 | |
|---|---|---|---|
| timerx-0.4.0.tar.gz | 16.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| timerx-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.2 kB
Release files / timerx-0.4.0.tar.gz
| Download URL | timerx-0.4.0.tar.gz |
|---|---|
| Size | 16.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
62c3aa94e499f26c553d59afea3efaf7451887a29b749bba0ab69e32d310507a
|
|
BLAKE2b-256 checksum How to use checksums |
d76638f8fb763e2f49bfb3c7e8151aa77267809215d84183c97b8bd42cb566c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 3, 2026.
Transparency logRelease files / timerx-0.4.0-py3-none-any.whl
| Download URL | timerx-0.4.0-py3-none-any.whl |
|---|---|
| Size | 7.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bd14a07dff0d4313e32f860f270fa217dab2f4fe2952083007d03c0857c793ac
|
|
BLAKE2b-256 checksum How to use checksums |
f9682aa0e8164d8e9ebad8fbe137b75116492e00c973fe335cf6a399de168e4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 3, 2026.
Transparency log