Skip to main content

Terminal progress bars via decorators

Project description

⏱ timeo

Terminal progress bars for Python functions — just add a decorator.

PyPI Python License: MIT CI

✓ process_files   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  100%  12.4s
  download_data   ━━━━━━━━━━━━━━━━━━━━━━━          72%   0:00:04
  compress_output ━━━━━━                           20%   0:00:31

Why timeo?

Most progress bar libraries ask you to wrap your loops manually and manage the display yourself. timeo gets out of the way — decorate a function, iterate normally, done.

# before
for item in items:
    process(item)

# after
@timeo.track
def run(items):
    for item in timeo.iter(items):
        process(item)

Installation

pip install timeo

Usage

Basic progress bar

@timeo.track wraps any function with a live progress bar. The total is inferred automatically from the first argument with a len(). Use timeo.iter() to advance the bar on each iteration — no manual bookkeeping needed.

import timeo

@timeo.track
def process_files(files):
    for f in timeo.iter(files):
        do_work(f)

process_files(my_files)

Prefer manual control? Use timeo.advance() instead:

@timeo.track
def process_files(files):
    for f in files:
        do_work(f)
        timeo.advance()

Multiple concurrent functions

Every decorated function gets its own bar. They render together in a single live display. Finished bars collapse to a compact summary line so the output stays clean.

@timeo.track
def process_files(files):
    for f in timeo.iter(files):
        do_work(f)

@timeo.track
def download_data(urls):
    for url in timeo.iter(urls):
        fetch(url)

process_files(my_files)
download_data(my_urls)
✓ process_files   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  100%  12.4s
  download_data   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━   72%  0:00:04

Concurrent execution (threads) is fully supported — each bar tracks its own function independently.


Learn mode

Add learn=True and timeo will remember how long your function takes across runs, building an EMA (exponential moving average) of its runtime. Instead of counting steps, the bar fills over the expected duration.

@timeo.track(learn=True)
def run_pipeline(data):
    heavy_computation(data)
    more_work(data)
Run Behaviour
First Indeterminate spinner with run_pipeline (learning...) label
Subsequent Determinate bar filling over the expected duration
After code change Cache invalidates automatically — learning restarts

Timing data lives at ~/.cache/timeo/timings.json. The cache key is a hash of the function's bytecode — not its name — so renaming a function preserves its history, and changing its implementation resets it.


Explicit display control

The live display starts and stops automatically in most cases. For complex scripts with branching logic or long-running setup, use timeo.live() to pin the display lifetime explicitly:

with timeo.live():
    process_files(my_files)
    download_data(my_urls)
    # display stays open until the with-block exits

How it works

Piece Role
@timeo.track Wraps the function, infers total from Sized args, manages the task lifecycle
ProgressManager Singleton owning the rich live display; reference-counted so it tears down only when all tasks finish
TrackedTask Dataclass holding per-function progress state
timeo.iter() Thin generator wrapper that calls advance() on each item
ContextVar Ensures timeo.advance() always updates the right bar, even across threads

The display is built on rich.progress and rich.live.


Contributing

# Enter the nix development shell
nix develop

# Install dependencies
uv sync

# Install pre-commit hooks (one-time)
pre-commit install

# Run tests
pytest

# Run linting and formatting
pre-commit run --all-files

All commits must follow Conventional Commits. See CONVENTIONS.md for full guidelines.


Built with rich · MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

timeo-0.2.0.tar.gz (31.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

timeo-0.2.0-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

File details

Details for the file timeo-0.2.0.tar.gz.

File metadata

  • Download URL: timeo-0.2.0.tar.gz
  • Upload date:
  • Size: 31.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for timeo-0.2.0.tar.gz
Algorithm Hash digest
SHA256 5d61a5d52f7fcc5cac63710a98e67de3f3e869492c993e97cc3f15f2e0cb1a51
MD5 055f9b66587a961989064c41f53ec5a3
BLAKE2b-256 249945b20ed0377cdf6ae9999aa54093aa5378ef27408a7f38ff1db13c36864c

See more details on using hashes here.

Provenance

The following attestation bundles were made for timeo-0.2.0.tar.gz:

Publisher: publish.yml on wtewalt/timeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file timeo-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: timeo-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 10.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for timeo-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f8386d50b7251ce19b9611f579abfbcf3b3e4da29d3fdcec72af1a038bb50b40
MD5 cc4c6e756f6ed73b4b69a87b95c38dde
BLAKE2b-256 5e14e5bf8a466360ca5c7419b1e643e06ff42c20f1216681842bdf36adf82e71

See more details on using hashes here.

Provenance

The following attestation bundles were made for timeo-0.2.0-py3-none-any.whl:

Publisher: publish.yml on wtewalt/timeo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page