Stdlib-only measurement primitives — stopwatch, rate estimation, ETA prediction.
Project description
.--:--. c o d e c h u
/ 12 \ ╔═════════╗
|9 ●---3| meter ║ 00:42.7 ║ ETA 03:18
\ 6 / ╚═════════╝
'-----' ─── tick · tock · tick · tock ───
Stopwatch, rolling-rate, and ETA — time things without lying about them.
codechu-meter
Stdlib-only measurement primitives — stopwatch, rolling-window rate estimator, ETA predictor — extracted from the Disk Cleaner toolchain. Zero dependencies. Python 3.10+.
Install
pip install codechu-meter
API
Stopwatch
from codechu_meter import Stopwatch
with Stopwatch() as sw:
do_work()
print(sw.elapsed) # → float seconds
# Manual form
sw = Stopwatch().start()
do_work()
sw.stop()
print(sw.elapsed)
Formatting is up to you. If you want pretty output, pair with
codechu-fmt:
from codechu_fmt import format_duration
print(format_duration(sw.elapsed)) # → '1m 30s'
RateEstimator
from codechu_meter import RateEstimator
re = RateEstimator(window_seconds=1.0, unit="bytes")
for chunk in stream:
re.observe(len(chunk))
print(re.rate()) # float per-second
unit is just an attribute — it never affects the numeric rate().
Use it as a label when formatting:
from codechu_fmt import format_rate
print(format_rate(re.rate(), unit=re.unit)) # → '1.2 MB/s'
ETAEstimator
from codechu_meter import ETAEstimator
eta = ETAEstimator(total=1000, mode="ema", alpha=0.3)
for current in progress:
eta.update(current)
remaining = eta.eta() # float seconds or None
mode='linear' (default) uses overall throughput since
construction. mode='ema' blends an exponential moving average
of recent throughput for smoother numbers on bursty workloads.
The alpha parameter (default 0.3) controls EMA reactivity:
higher values weight recent samples more heavily.
eta() returns None until at least two updates with measurable
elapsed time and positive progress.
Counter (v0.3.0+)
Thread-safe int counter. inc / dec / reset / .value are all
guarded by a threading.Lock.
from codechu_meter import Counter
inflight = Counter()
inflight.inc()
try:
serve(req)
finally:
inflight.dec()
print(inflight.value)
Histogram (v0.3.0+)
Bucketed distribution counter. Upper edges are inclusive; values
above the largest edge fall into a math.inf overflow bucket.
Thread-safe.
from codechu_meter import Histogram
hist = Histogram([0.01, 0.05, 0.1, 0.5, 1.0])
for r in requests:
hist.observe(r.latency_seconds)
print(hist.counts, hist.total)
PercentileEstimator (v0.3.0+)
Streaming p50 / p95 / p99 via Vitter's reservoir sampling
(max_samples capped). Pure stdlib — no numpy. Thread-safe.
from codechu_meter import PercentileEstimator
pe = PercentileEstimator(max_samples=5_000)
for r in requests:
pe.observe(r.latency_seconds)
print(pe.p50, pe.p95, pe.p99)
Stopwatch named sections (v0.3.0+)
Stopwatch.section(name) accumulates sub-timings into
Stopwatch.sections. Same name re-entered → values add. Not
thread-safe; use one Stopwatch per thread.
sw = Stopwatch().start()
with sw.section("parse"):
parse(buf)
with sw.section("emit"):
emit(result)
sw.stop()
print(sw.sections) # → {"parse": 0.012, "emit": 0.004}
Design
- Zero dependencies. Stdlib only.
- Monotonic clock. Wall-clock jumps don't break timing.
- No formatting coupling. Numeric primitives only; pair with
codechu-fmt(or roll your own) for display strings. - Defensive. Zero progress, zero elapsed, NaN, and negative rates never raise.
Migrating from 0.1.x
__str__ methods were removed in 0.2.0. Replace print(sw) /
str(re) / str(eta) with explicit calls:
# Before (0.1.x)
print(sw)
print(re)
print(eta)
# After (0.2.x)
from codechu_fmt import format_duration, format_rate
print(format_duration(sw.elapsed))
print(format_rate(re.rate(), unit=re.unit))
v = eta.eta()
print(format_duration(v) if v is not None else "?")
Tests
pip install -e ".[dev]"
pytest -q
Coverage gate: ≥90 %. Tests drive time via monkeypatching
time.monotonic for deterministic assertions.
Documentation
- API reference — every public symbol, parameter, return value, and exception.
- Migration guide — 0.1.x → 0.2.0 (breaking
__str__removal, newalphaparameter, droppedcodechu-fmtdependency). - Recipes — patterns for timing blocks, tracking
download speed, computing ETA, tuning EMA
alpha, and pairing withcodechu-fmt.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codechu_meter-0.3.0.tar.gz.
File metadata
- Download URL: codechu_meter-0.3.0.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bfca71fb3b0d45f64a75f99e53672a5cb64651935f0a69ad8fb1e224ec7bcba5
|
|
| MD5 |
324bd25ad9ed7ef2fa32a281eded9784
|
|
| BLAKE2b-256 |
42f2b87abdd8f007fa99a5215f42181f91a6e49269ad520c6974270a7759537e
|
Provenance
The following attestation bundles were made for codechu_meter-0.3.0.tar.gz:
Publisher:
release.yml on codechu/meter-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
codechu_meter-0.3.0.tar.gz -
Subject digest:
bfca71fb3b0d45f64a75f99e53672a5cb64651935f0a69ad8fb1e224ec7bcba5 - Sigstore transparency entry: 1582029806
- Sigstore integration time:
-
Permalink:
codechu/meter-py@ca339cc24e24a2793ef2064926826e5c3b8c2c78 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/codechu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ca339cc24e24a2793ef2064926826e5c3b8c2c78 -
Trigger Event:
push
-
Statement type:
File details
Details for the file codechu_meter-0.3.0-py3-none-any.whl.
File metadata
- Download URL: codechu_meter-0.3.0-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ce94451b99fcf4aa3224aa6f3810c7c6cedbd52368e2efb7228ddef449a15e9
|
|
| MD5 |
a2290fbf672737b12c1464cf102aa62b
|
|
| BLAKE2b-256 |
76509447d1c1971672676f7ec4e254dd997f01449f0ddc23e461f644a9f5a0c6
|
Provenance
The following attestation bundles were made for codechu_meter-0.3.0-py3-none-any.whl:
Publisher:
release.yml on codechu/meter-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
codechu_meter-0.3.0-py3-none-any.whl -
Subject digest:
8ce94451b99fcf4aa3224aa6f3810c7c6cedbd52368e2efb7228ddef449a15e9 - Sigstore transparency entry: 1582029983
- Sigstore integration time:
-
Permalink:
codechu/meter-py@ca339cc24e24a2793ef2064926826e5c3b8c2c78 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/codechu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ca339cc24e24a2793ef2064926826e5c3b8c2c78 -
Trigger Event:
push
-
Statement type: