Rendering (internals)#
The only place Rich lives. Documented for contributors; signatures are not a stable API.
The single Rich console the whole tool prints through.
Every human-facing message goes through this module (CLAUDE.md rule), so output
styling, quiet modes, and testability stay in one place. Core logic never
prints – the core/ report objects arrive here fully computed and this
module only renders them.
- matmelt.ui.console.note_console = <console width=80 None>#
Advisory notes that must not land on stdout, because a
--jsonrun’s stdout has to stay parseable (the M10 lesson).
- matmelt.ui.console.render_config_error(message)[source]#
One config problem report (the message already carries YAML paths).
Rendered verbatim: config errors quote user input and name lists in square brackets (
missing [structure]), which Rich would otherwise swallow as markup tags.
- matmelt.ui.console.render_legacy_config_note(legacy, preferred)[source]#
Say once that the pre-rename config filename is being used.
- matmelt.ui.console.render_error(message)[source]#
A command-level problem that is not a config error (already actionable).
- matmelt.ui.console.render_init_created(path)[source]#
Announce the scaffolded config and hand off to the doctor checks.
- matmelt.ui.console.print_json_payload(payload)[source]#
Machine-readable output for
--jsonflags: plain JSON on stdout.
- matmelt.ui.console.render_doctor(report, enumeration, model, aiida=None, *, ok)[source]#
The full
doctordiagnosis: backends, stage readiness, seeds, model, verdict.- Parameters:
report (
DoctorReport) – Backend health and per-stage readiness.enumeration (
EnumerationReport) – The seed-count report.model (
ModelStatus|None) – The screen model status, orNonewhen no screen stage is configured.aiida (
AiidaStatus|None, default:None) – The AiiDA status, orNonewhen no calculate stage is configured.ok (
bool) – The overall verdict.
- Return type:
- matmelt.ui.console.render_warning(message)[source]#
A one-line yellow warning: worth seeing, never fatal.
markup=Falsefor the same reason asrender_config_error: messages carry user data (ids, paths) that must never be eaten as Rich markup.- Return type:
- matmelt.ui.console.render_enumeration(enumeration)[source]#
The seed-enumeration report: the n-ary blast radius, before any work.
- Parameters:
enumeration (
EnumerationReport) – The report, whose oversized sizes are named explicitly so a silently-empty size is never a mystery.- Return type:
- matmelt.ui.console.render_run_header(run_name, active_stage_names)[source]#
Which run this is and which stages it will actually execute.
- matmelt.ui.console.render_unready(failures)[source]#
The preflight refusal: every unmet requirement and its exact fix.
- Parameters:
failures (
Sequence[RequirementStatus]) – The unmet requirements. Each is printed with the exact install command and the location it was probed at, so a remote gap is not mistaken for a local one.- Return type:
- matmelt.ui.console.confirm_model_download(detail)[source]#
The disclosed foundation-model consent prompt. EOF/no-TTY = declined.
- matmelt.ui.console.render_pass_summary(index, summary)[source]#
One progress line per pass with activity; silent when nothing happened.
- matmelt.ui.console.render_interrupted()[source]#
Clean Ctrl-C: everything durable, the same command resumes.
- Return type:
- matmelt.ui.console.render_run_result(counts, *, drained, only=None, selective=False, stopped_early=None)[source]#
The final per-state tally and whether the funnel fully drained.
In only-mode (
onlyset) “drained” means the one stage has no work left – other states legitimately hold non-terminal materials awaiting the rest of the funnel, so the full-run wording would mislead. The same holds for a selective run (selective): only the chosen lineage was driven, so unselected materials legitimately remain non-terminal. And for a mid-funnel stop (stopped_early= the stop_after stage name): materials rest at that stage’s output, resumable, neverDONE.- Parameters:
counts (
Mapping[MaterialState,int]) – The final per-state tally.drained (
bool) – Whether the funnel ran out of work.only (
str|None, default:None) – The single stage this run executed, if any.selective (
bool, default:False) – Whether a material selection was active.stopped_early (
str|None, default:None) – Whether a pass limit cut the run short.
- Return type:
- matmelt.ui.console.render_status(run_name, counts, failed, jobs)[source]#
The
statusview: state tally, failed materials, in-flight jobs.- Parameters:
run_name (
str) – The configured run name.counts (
Mapping[MaterialState,int]) – The per-state tally.failed (
Sequence[MaterialRecord]) – Terminally failed materials, with their stage, reason and attempts.jobs (
Sequence[InFlightJob]) – The in-flight ledger.
- Return type:
- matmelt.ui.console.render_state_materials(run_name, state, records)[source]#
The
status --stateview: the material ids sitting at one state.This is the picking list for selective runs: the ids feed
run --materials(parent ids shown so lineage selections are easy to trace back to their seeds).- Parameters:
run_name (
str) – The configured run name.state (
MaterialState) – The state being listed.records (
Sequence[MaterialRecord]) – The materials at that state, with their parents where they have one.
- Return type:
- matmelt.ui.console.render_retry_preview(run_name, records)[source]#
Summarise the FAILED materials to be retried, grouped by stage.
The “ingenious UX” the user asked for: instead of a flat wall of ids, one row per stage with its count – the headline decision info (“128 failed at structure”) – plus how many distinct reasons that stage saw and one example. (Reasons often embed the material’s own path, so clustering on the exact reason string is useless; the distinct-count still flags whether a stage failed one way or many.) Narrow with
--stageif a group is not what you meant. Stage/reason areescape-d – they carry user data (paths,<&>) that is never Rich markup.- Parameters:
run_name (
str) – The configured run name.records (
Sequence[MaterialRecord]) – The materials that would be reset.
- Return type:
- matmelt.ui.console.confirm_retry(count)[source]#
Confirm resetting
countFAILED materials. EOF/no-TTY = declined.
- matmelt.ui.console.render_retry_result(count)[source]#
Report how many materials were reset back to a claimable state.
- matmelt.ui.console.render_results(run_name, done, with_record)[source]#
The
resultsview: every DONE material and whether it has a record.
- matmelt.ui.console.render_cif_export(run_name, out_dir, written, skipped, failed)[source]#
The
cifview: what was exported, what was skipped, what failed.Skips are grouped by reason (hundreds of “did not converge” rows help nobody); failures are listed per material, because each one is something the user may want to chase. Ids and reasons are
escape-d – they are user data, never Rich markup.
Rich rendering for the monitor command: snapshot in, panels out.
The UI half of the monitor seam: core/monitor.py computes a
MonitorSnapshot; this module turns it into the five stacked panels
(run overview with the done-donut and state bar, stage pipeline, running
now with per-material CPU/GPU meters, recent completions, recent failures)
and nothing else – no queries, no business logic, no mutation. It prints
through the shared
console from ui/console.py, so the one-console rule holds; it lives
in its own module only because the monitor’s rendering is a cohesive block
that would double console.py’s size.
Everything user-data-bearing (ids, stages, failure reasons) is escape-d
before rendering – reasons carry paths and bracketed text that Rich would
otherwise swallow as markup (the render_config_error lesson).
- matmelt.ui.monitor.fmt_duration(seconds)[source]#
5085.0->"1h 24m"– coarse, human-first wall-clock spans.Sub-minute spans show seconds (
"42s"), sub-hour spans minutes and seconds ("4m 12s"), longer spans hours and minutes. Negative or zero input renders as"0s"(clock skew must never crash a dashboard).
- matmelt.ui.monitor.fmt_rate(per_min)[source]#
2.34->"2.3/min"; a zero rate is a dash, never"0.0/min".
- matmelt.ui.monitor.overview_panel(snap)[source]#
Panel 1 – headline numbers, a done-donut, and the state-distribution bar.
- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
Headline numbers, a completion donut, and the state-distribution bar.
- Return type:
rich.panel.Panel
- matmelt.ui.monitor.pipeline_panel(snap)[source]#
Panel 2 – one row per configured stage, funnel order.
- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
One row per configured stage, in funnel order.
- Return type:
rich.panel.Panel
- matmelt.ui.monitor.running_panel(snap)[source]#
Panel 3 – every material riding a live job right now.
Longest-running first (the snapshot’s order); capped at
_RUNNING_LIMITrows with an honest “+N more” line. An idle pipeline shows a dim note, not an empty table.- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
Every material riding a live job right now, longest-running first, with its stage, backend, elapsed time, try count and usage meters.
- Return type:
rich.panel.Panel
- matmelt.ui.monitor.successes_panel(snap)[source]#
Panel 4 – the newest finished (DONE) materials, the failures’ mirror.
Tookis the material’s whole ride (created -> finished), the number a screening campaign actually cares about per material.- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
The newest finished materials, with how long each ride took.
- Return type:
rich.panel.Panel
- matmelt.ui.monitor.failures_panel(snap)[source]#
Panel 3 – the newest terminal failures, or a green all-clear.
- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
The newest terminal failures, or a green all-clear when there are none.
- Return type:
rich.panel.Panel
- matmelt.ui.monitor.tracked_panel(snap)[source]#
Panel 3 (tracked mode) – one row per
--track-ed material.Rendered instead of the failures panel whenever
snap.trackedis notNone(failures stay reachable viastatus). Afound=Falserow keeps its id visible with a dim-red “not found” – a typo must be diagnosable from the dashboard itself. All user-data cells go throughText/escapeso ids and reasons never execute as Rich markup (the module-docstring lesson).- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
One row per tracked material, in the order the user named them, including honest rows for ids the store does not know.
- Return type:
rich.panel.Panel
- matmelt.ui.monitor.render_snapshot(snap)[source]#
The full dashboard, stacked: overview, pipeline, running now, recent completions, then the mode-dependent last panel – tracked materials when the snapshot carries
trackedrows (the--trackflow, even an empty tuple), recent failures otherwise.- Parameters:
snap (
MonitorSnapshot) – The snapshot to render.- Returns:
The stacked dashboard. The third panel is the tracked table when tracking was requested, and recent failures otherwise.
- Return type:
RenderableType
- matmelt.ui.monitor.print_snapshot(snap)[source]#
The
--oncepath: render the dashboard to stdout a single time.- Parameters:
snap (
MonitorSnapshot) – The snapshot to print.- Return type:
The monitor’s live loop: a Rich Live context around a build callback.
The tiny UI-layer seam between the monitor command and Rich’s Live
display – it exists so that all Rich usage stays inside ui/ (the
one-console rule) while the command layer keeps the control flow: what to
render each tick (the build callback), how often, and when to stop.
This module never queries state, never sleeps forever on its own terms, and
never decides what the dashboard contains.
Terminal safety: the loop runs inside with Live(...) so that
Live.__exit__ always restores the terminal – a Ctrl-C mid-refresh must
never leave the screen in Live’s grip. KeyboardInterrupt therefore
propagates out of this function (after the context manager has cleaned
up); the calling command catches it and turns it into a clean exit, so the
user sees a short note, never a traceback.
- matmelt.ui.monitor_live.run_live(build, *, interval_s, max_ticks=None)[source]#
Render a renderable under Rich
Live, refreshing on an interval.screen=Falseis deliberate: the stacked panels redraw in place and scroll away naturally when the loop ends, leaving the last frame visible in the terminal history instead of wiping it.- Parameters:
build (
Callable[[],ConsoleRenderable|RichCast|str]) – Called for every frame. The first call happens before the display starts, so the user sees a dashboard immediately rather than a blank frame.interval_s (
float) – Seconds to sleep between updates.max_ticks (
int|None, default:None) – Bound the number of updates after the initial render. The testing knob;Noneruns until interrupted.
- Raises:
KeyboardInterrupt – Propagated to the caller, as is any exception from
build– but only afterLive.__exit__has restored the terminal, which is the whole point of thewithblock.- Return type: