archiver-stats

Python versions PyPI - Version GitHub tag (with filter) License GitHub commits since latest release (by SemVer including pre-releases) CodeQL QA Tests Coverage Status Dependabot Documentation Status mypy uv pytest Ruff Downloads Stargazers pre-commit Prettier Follow @Tatsh Mastodon Follow

Reusable live statistics and progress display for archiver-style CLIs.

Installation

pip install archiver-stats

Usage

Declare counters and optional free-form status lines, then drive a live Rich display from the Stats instance:

import sys

from archiver_stats import Category, Stats, StatusDisplay, StatusLine

stats = Stats(
    (Category('hits', 'Hits:'), Category('misses', 'Misses:')),
    status_lines=(StatusLine('progress', 'Progress:', after='hits'),),
)
display = StatusDisplay(stats, stream=sys.stderr, initial_message='Working...')
display.start()
try:
    stats.increment('hits')
    stats['progress'] = 'https://example.com/1 (1/3)'
    display.refresh()
finally:
    display.stop()

Stats is a MutableMapping keyed by category or status-line key. Counter values are integers (update with stats[key] = value or increment()), and status-line values are str or None. Keys are fixed at construction time and the mapping does not support deletion.

StatusDisplay wraps a rich.live.Live display: call start() and stop() around your work, refresh() to re-render after updating counters, set_message() to change the spinner text, and write() to print a persistent line above the live region.

API reference

Top-level package

Reusable live statistics and progress display for archiver-style CLIs.

The following names are re-exported from the submodules below:

Statistics container

Statistics container for archiver-style CLIs.

class archiver_stats.stats.Category(key: str, label: str)

Declared counter category for a Stats instance.

Parameters:
key : str

Key used to read and update the counter on the owning Stats.

label : str

Human-readable label rendered by StatusDisplay.

key : str

Key used to read and update the counter.

label : str

Human-readable label rendered alongside the counter value.

class archiver_stats.stats.Stats(categories: Iterable[Category | tuple[str, str]] = (), *, status_lines: Iterable[StatusLine | tuple[str, str] | tuple[str, str, str | None]] = ())

Live statistics container with named counters and free-form status lines.

Instances behave as a MutableMapping keyed by the category or status-line key. Counter values are integers; status-line values are str or None. Keys are fixed at construction time: writing to an unknown key raises KeyError, and the mapping does not support deletion.

Parameters:
categories : Iterable[Category | tuple[str, str]]

Ordered counter categories exposed as integer entries.

status_lines : Iterable[StatusLine | tuple[str, str] | tuple[str, str, str | None]]

Free-form status lines whose values can be any string or None.

Raises:
  • KeyError – If a status line’s after is not a registered category key.

  • ValueError – If a category key and a status line key collide, or if any keys within categories or status_lines are duplicated.

property categories : tuple[Category, ...]

Declared counter categories in rendering order.

category_items() Iterator[tuple[Category, int]]

Yield (category, value) pairs in declaration order.

Yields:

tuple[Category, int] – Each declared category paired with its current counter value.

increment(key: str, amount: int = 1) int

Add amount to the counter named key and return the new value.

Parameters:
key : str

Name of the counter.

amount : int

Amount to add. May be negative.

Returns:

The updated counter value.

Return type:

int

Raises:

KeyError – If key is not a registered counter.

status_line_items() Iterator[tuple[StatusLine, str | None]]

Yield (status_line, value) pairs in declaration order.

Yields:

tuple[StatusLine, str | None] – Each declared status line paired with its current value.

property status_lines : tuple[StatusLine, ...]

Declared free-form status lines in declaration order.

class archiver_stats.stats.StatusLine(key: str, label: str, after: str | None = None)

Declared free-form status line for a Stats instance.

Unlike a Category (which tracks an integer counter), a status line holds an arbitrary text value that the caller sets at will, or None to render as n/a.

Parameters:
key : str

Key used to read and update the value on the owning Stats.

label : str

Human-readable label rendered by StatusDisplay.

after : str | None

Category key after which this line should render. When None, the line renders before all categories.

after : str | None

Category key after which this line should render.

key : str

Key used to read and update the value.

label : str

Human-readable label rendered alongside the value.

Live progress display

Live progress display for archiver-style CLIs.

archiver_stats.display.STATUS_REFRESH_HZ

Default refresh rate used by the live status display.

class archiver_stats.display.StatusDisplay(stats: Stats, *, stream: Any, initial_message: str = 'Starting workers...', refresh_per_second: int = 10, label_width: int = 20, value_width: int = 6, idle_text: str = 'n/a')

Rich-based live progress display with a spinner line and queue statistics.

Parameters:
stats : Stats

Statistics object whose counters and free-form status lines are rendered.

stream : Any

File-like object the underlying Console writes to.

initial_message : str

Text shown next to the spinner before set_message() is called.

refresh_per_second : int

Refresh rate passed to the underlying Live display.

label_width : int

Minimum column width for counter and status-line labels.

value_width : int

Minimum column width for counter values.

idle_text : str

Text rendered when a status line’s value is None.

refresh() None

Re-render the live display with the latest statistics.

set_message(message: str) None

Replace the status message shown next to the spinner.

Parameters:
message : str

Text rendered beside the spinner glyph.

start() None

Start the live display.

stop() None

Stop the live display and clear the rendered region.

write(message: str) None

Print a persistent status line above the live display.

Parameters:
message : str

Text to print to the attached console.

Indices and tables