Console / Output¶

The CLI’s terminal-output layer: the shared Rich console singletons and palette, the debug-aware status spinner, the table / diff / drift renderers, the error panel, and the logging that routes through the console (the terminal handler and excepthook). Library callers who never import patcher.cli get file-only logging and pay for none of this.

Terminal output layer for the Patcher CLI.

Owns everything the CLI puts on the terminal: the shared Rich console singletons and palette, the debug-aware status spinner, the table / diff / drift renderers, the error panel, and the logging that routes through the console (the terminal handler and excepthook). Library callers who never import patcher.cli get file-only logging and pay for none of this.

Changed in version 3.3.0: Absorbed the former terminal_logger module and the CLI’s rendering helpers so all terminal-output concerns live in one place.

class TerminalHandler(level=0)[source]¶

Logging handler that emits records as Rich-styled lines on stdout.

Maps each log level to a color so a debug run produces the same visual output the legacy in-class click.echo calls did (magenta DEBUG, blue INFO, bold-yellow WARNING, bold-red ERROR). The leading \r preserves the existing behavior of overwriting the current terminal line. Output routes through the shared console.

Initializes the instance - basically setting the formatter to None and the filter list to empty.

emit(record: LogRecord) None[source]¶

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

Parameters:

record (LogRecord)

Return type:

None

status(message: str = 'Processing', *, enabled: bool = True, spinner: str = 'dots')[source]¶

Debug-aware Rich status spinner.

Yields a live rich.status.Status when enabled is True, or a no-op stand-in with the same update / start / stop surface when disabled. Use enabled=not debug so --debug runs skip the spinner and let log lines flow uninterrupted.

Parameters:
  • message (str) – Initial message rendered next to the spinner.

  • enabled (bool) – When False, yields a _NoOpStatus instead of a live spinner.

  • spinner (str) – Name of the Rich spinner to render.

progress_bar(*, disable: bool = False) Progress[source]¶

A consistently-styled Rich progress display (spinner + description + bar).

Determinate when a task’s total is set (the bar fills); pulsing while total is None. Pass disable=debug so --debug runs skip the live display and let log lines flow uninterrupted.

Parameters:

disable (bool) – When True the display renders nothing (debug runs).

Return type:

Progress

build_table(rows: list[list], headers: list[str] | None = None, *, title: str | None = None, caption: str | None = None, justify: list[str] | None = None, no_wrap: list[bool] | None = None, footer: list | None = None, lines: bool = False) Table[source]¶

Build a Rich Table from row data.

Cells that are already Rich renderables (e.g. a styled Text) pass through untouched, so callers can color individual cells; everything else is stringified.

Parameters:
  • rows (list[list]) – Row data; each cell is a string, a value, or a Rich renderable.

  • headers (list[str] | None) – Optional column headers. When omitted the table renders headerless (used for key/value summaries).

  • title (str | None) – Optional bold title rendered above the table.

  • caption (str | None) – Optional dim line rendered below the table (run provenance).

  • justify (list[str] | None) – Optional per-column justification (e.g. "right" for numbers).

  • no_wrap (list[bool] | None) – Optional per-column wrap suppression (truncate with an ellipsis).

  • footer (list | None) – Optional per-column footer cells; presence enables the footer row.

  • lines (bool) – Draw a horizontal divider between every row (for scannable data tables).

Return type:

Table

completion_text(percent: float, threshold: float) Text[source]¶

Render a completion percentage as a health-colored cell.

Red below threshold, yellow up to 90%, green at 90% or above, so a fleet’s laggards jump out of the table at a glance.

Parameters:
  • percent (float) – Completion percentage (0-100).

  • threshold (float) – The cutoff below which a title reads as out of compliance.

Return type:

Text

build_fleet_summary(titles: list[PatchTitle], threshold: float) Panel[source]¶

Summarize fleet-wide patch compliance as a single at-a-glance panel.

Parameters:
  • titles (list[PatchTitle]) – The full set of cached patch titles (not the filtered view).

  • threshold (float) – Completion cutoff used to count titles out of compliance.

Return type:

Panel

render_diff(result: DiffResult) Group[source]¶

Render a DiffResult as Rich tables grouped by section.

Parameters:

result (DiffResult)

Return type:

Group

render_drift(result: DriftResponse) Table | Text[source]¶

Render a DriftResponse as a Rich table summary.

Parameters:

result (DriftResponse)

Return type:

Table | Text

render_drift_entry(entry: DriftEntry) Group[source]¶

Render a single DriftEntry with per-source version detail.

Parameters:

entry (DriftEntry)

Return type:

Group

format_err(exc: BaseException) None[source]¶

Render any exception in a red-bordered Rich panel on stderr.

The panel body carries the message in red, prefixed with the exception type for non-PatcherError exceptions so a bare TypeError reads clearly. If the exception exposes a recovery or remediation attribute (PatcherError lifts keyword context onto the instance), it renders as a dim paragraph below the message. A dim rule separates the log-file pointer from the error content.

Parameters:

exc (BaseException) – The exception to format.

Return type:

None

install_terminal_handler(debug: bool) None[source]¶

Attach a TerminalHandler to the Patcher logger when in debug mode.

Idempotent. Calling twice will not add duplicate handlers. No-op when debug is False, so the standard CLI run (and any library import path) sees no terminal output beyond what callers explicitly emit.

Parameters:

debug (bool) – Whether the CLI was invoked with --debug.

Return type:

None

install_terminal_excepthook() None[source]¶

Chain a terminal-styled excepthook onto custom_excepthook().

The core hook logs unhandled exceptions to file. This wrapper additionally renders the exception in the styled error panel on stderr, consistently for every exception type (the panel surfaces a recovery hint when one is present). Library callers who never import patcher.cli are unaffected; their sys.excepthook is not touched.

Return type:

None

setup_logging(debug: bool) None[source]¶

Configure Patcher logging for the CLI process.

Installs the always-on rotating file handler, then attaches the click-backed terminal handler when debug is true so debug runs surface colored, level-prefixed output to stdout.

Parameters:

debug (bool) – Whether to enable debug-level console output.

Return type:

None