-
-
Notifications
You must be signed in to change notification settings - Fork 103
Comparing changes
Open a pull request
base repository: wolph/python-progressbar
base: develop
head repository: wolph/python-progressbar
compare: fast-progressbar
- 15 commits
- 23 files changed
- 1 contributor
Commits on Jun 23, 2026
-
Add behavior-preserving fast path: ~31 ns/iter (was ~254)
Wrapping a loop with progressbar2 dropped from ~254 ns/iter to ~31 ns (~11x faster, ~1.8x faster than tqdm, 2nd only to rich), with no change to observable behavior. How: an integer "next-update" gate. The common iteration is just an increment, a compare, and the value/previous_value liveness stores; the expensive redraw machinery (clock read + widget formatting) only runs at rate-limited crossings (~20x/sec). The gate calibrates _gate_step from a real timing measurement and self-corrects via a tqdm-style closed loop, so it can only skip iterations, never force a wrong redraw. The iterator path is a single inlined generator (the shortcut wrapper layer is collapsed); the manual update()/+= path skips its per-call clock read below the threshold. Backward compatibility: - Public API unchanged; bar.value and previous_value stay byte-identical to the pre-gate behavior on every iteration. - Same widgets, same redraw cadence, same finish/break/exception handling. - PROGRESSBAR_DISABLE_FASTPATH (and min_poll_interval=0) revert to the original per-iteration path. Also: - Reproducible benchmark suite (benchmarks/) vs tqdm/rich/alive-progress/ click, all rendered to a real pseudo-terminal; documented in README. - CI per-iteration performance budget guard (machine-independent ratio) to prevent regressions. - no_color/len_color skip the ANSI-strip regex on plain text (cuts the forced-redraw render cost). - Full suite green at 100% branch coverage; ruff and pyright clean.
Configuration menu - View commit details
-
Copy full SHA for c89cb10 - Browse repository at this point
Copy the full SHA c89cb10View commit details -
Add optional native iterator accelerator: ~5 ns/iter, ~4x faster than…
… rich `ProgressBar.__iter__` now dispatches to `speedups.progressbar.FastBarIterator` (the `progressbar2[fast]` extra) when it is importable, falling back to the pure-Python generator otherwise. The native iterator counts items in a C field and only calls back into Python at redraw crossings via a small protocol (`_fast_begin`/`_fast_tick`/`_fast_end`/`_fast_end_dirty`), reusing the existing gate/redraw/calibration machinery so the redraw cadence is identical. The only behavioural difference is that `value`/`previous_value` are synced at crossings rather than every iteration, so reads between redraws lag slightly (like tqdm.n); `PROGRESSBAR_DISABLE_FASTPATH=1` forces the pure-Python path. This makes progressbar2 the fastest progress bar measured: ~5 ns/iter vs rich 19, tqdm 55. Pure Python stays ~30 ns (no native build), still ~1.8x faster than tqdm and 2nd to rich. Also: - hoist `_gate_enabled` to a local in the pure-Python iterator (free, no behaviour change), trimming the fallback hot path a few ns. - conftest `disable_native_accelerator` autouse fixture forces the pure-Python path for the rest of the suite; native behaviour is covered explicitly in tests/test_native_accelerator.py (dispatch + hooks covered without the compiled package via a fake/direct calls, so CI stays at 100% coverage; real end-to-end equivalence + issue #212 break/exception cleanup tests run where speedups is installed). - refresh benchmark artifacts + README performance section.
Configuration menu - View commit details
-
Copy full SHA for c2308c2 - Browse repository at this point
Copy the full SHA c2308c2View commit details
Commits on Jun 24, 2026
-
Lighten import (~48->24ms) and trim forced-render overhead
Import: with the companion python_utils lazy-import change, `import progressbar` no longer eagerly pulls in asyncio or typing_extensions, dropping cold import from ~48ms to ~24ms (net of interpreter startup) -- on par with tqdm/click and roughly half of rich. (Requires the python_utils release that defers those imports; progressbar itself imports python_utils lazily where it can.) Render: FormatLabel.__call__ no longer wraps every mapping entry in a contextlib.suppress on the redraw hot path -- a missing key (the only common miss) is tested directly and only the value transform is guarded. The bulk of the forced-per-update render cost (~24us) is inherent to the richer default widgets (gradient bar, time widgets), so this is a modest trim, not a headline. Benchmark artifacts + README refreshed: import ~24ms, iteration ~5ns (fastest), forced render ~24us.
Configuration menu - View commit details
-
Copy full SHA for f93843a - Browse repository at this point
Copy the full SHA f93843aView commit details -
Configuration menu - View commit details
-
Copy full SHA for 42390a3 - Browse repository at this point
Copy the full SHA 42390a3View commit details -
Configuration menu - View commit details
-
Copy full SHA for 21e908b - Browse repository at this point
Copy the full SHA 21e908bView commit details -
Configuration menu - View commit details
-
Copy full SHA for d17db1e - Browse repository at this point
Copy the full SHA d17db1eView commit details -
Configuration menu - View commit details
-
Copy full SHA for 53fdb1e - Browse repository at this point
Copy the full SHA 53fdb1eView commit details -
Configuration menu - View commit details
-
Copy full SHA for f956d3c - Browse repository at this point
Copy the full SHA f956d3cView commit details -
Configuration menu - View commit details
-
Copy full SHA for 058eb74 - Browse repository at this point
Copy the full SHA 058eb74View commit details -
Configuration menu - View commit details
-
Copy full SHA for c011529 - Browse repository at this point
Copy the full SHA c011529View commit details -
Configuration menu - View commit details
-
Copy full SHA for 17961bd - Browse repository at this point
Copy the full SHA 17961bdView commit details -
docs: document fast default path; refresh benchmark artifacts
The default progressbar() now auto-uses the lean FastProgressBar: ~5 ns/iter, ~5 us/render (~2x faster than tqdm), ~1.5 ms import (lazy). Full widget/gradient bar remains via widgets=/fast=False/ProgressBar(...). Benchmark adds a fast-render scenario; README Performance section rewritten for all three axes.
Configuration menu - View commit details
-
Copy full SHA for 253c6a0 - Browse repository at this point
Copy the full SHA 253c6a0View commit details -
Configuration menu - View commit details
-
Copy full SHA for c9fc9b2 - Browse repository at this point
Copy the full SHA c9fc9b2View commit details -
fix: clear CodeQL cyclic-import + mixed-import findings
- bar.py loads widgets via importlib helper (_load_widgets) instead of static `from . import widgets`, removing the static bar->widgets cycle edges CodeQL flagged while keeping the deferred (fast-path-safe) load. Widget annotations typed loosely to drop the last TYPE_CHECKING bar->widgets edge; the public progressbar() shortcut keeps precise WidgetBase typing. - tests/test_fast_default.py uses a single import style (alias, no `from`).
Configuration menu - View commit details
-
Copy full SHA for 27df953 - Browse repository at this point
Copy the full SHA 27df953View commit details
Commits on Jun 25, 2026
-
fix: pre-warm widgets in multi.py to avoid render-thread import race
After deferring the widgets import out of bar.py (fast-path import slim-down), a MultiBar child bar's first start() would import the widgets module lazily -- and MultiBar runs start()/render from background threads, so that cold import could race MultiBar._label_bar's `assert bar.widgets` (intermittent CI flake on test_multibar). multi.py now imports widgets eagerly at module load (single- threaded; this module is itself lazy-loaded only when MultiBar is used), so the fast path and bare `import progressbar` stay widgets-free.
Configuration menu - View commit details
-
Copy full SHA for 94918a8 - Browse repository at this point
Copy the full SHA 94918a8View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff develop...fast-progressbar