refactor(display): split output/display.py by output surface (#41)#82
refactor(display): split output/display.py by output surface (#41)#82RaghavRD wants to merge 4 commits into
Conversation
Move the 880-line output/display.py into focused per-surface modules: - output/_console.py — canonical Console() instance - output/formatting.py — byte / param / date / color helpers - output/ranking.py — display_ranking + display_hardware - output/plan.py — display_plan - output/upgrade.py — display_upgrade + summarize/verdict helpers - output/json_output.py — display_json + display_plan_json + display_upgrade_json - output/display.py — thin re-export shim (38 lines, was 880) Tests that captured output by patching display.console now patch whichllm.output._console.console instead, which is the new single source of truth that every surface module looks up at call time. Behavior-preserving: no ranking, plan, upgrade, or JSON output changes. All 220 tests pass. Refs Andyyyy64#41
Resolves a conflict in src/whichllm/output/display.py introduced by upstream b81497d (fix: apply small GPU and display fixes), which modified display_upgrade in the pre-split monolithic display.py. Since display.py is now a thin re-export shim and display_upgrade lives in output/upgrade.py, the equivalent change has been ported there: treat vram_gb == 0.0 as 0 GB rather than dash by checking 'is not None' instead of truthiness. All 228 tests pass; ruff check and ruff format clean.
|
Brought the branch up to date with All tests still pass locally |
|
I reviewed this properly today, and the split itself is in good shape. The It now conflicts with main: #68 landed changes inside
After that I'm happy to merge. The upcoming table-UX work will build on these modules, so I'd like to land this first. |
Resolves a conflict in src/whichllm/output/display.py from upstream 721ce3b (fix: correct AMD discrete GPU detection on Linux, Andyyyy64#68), which removed two heuristics inside display_hardware in the pre-split monolithic display.py. Since display.py is now a re-export shim and display_hardware lives in output/ranking.py, the equivalent changes have been ported there: simplified the non-shared GPU vram branch to a plain _format_bytes call, and removed the inverted 'extra: shared memory' tag that was incorrectly added to non-shared AMD/Intel GPUs with VRAM > 0. Also updates two new test_amd_detection.py tests added by Andyyyy64#68 to monkey-patch whichllm.output._console.console (the new single source of truth) instead of display.console. With the old pattern they would have either failed outright (one did) or passed for the wrong reason because the buf they wrote into stayed empty. All 329 tests pass; ruff check and ruff format clean.
|
@Andyyyy64 thanks for the review! Brought the branch up to date with
While porting, I also caught two new
All 329 tests pass locally; ruff check + format are clean. Ready for another look whenever you have a moment. |
Move the 880-line output/display.py into focused per-surface modules:
Tests that captured output by patching display.console now patch whichllm.output._console.console instead, which is the new single source of truth that every surface module looks up at call time.
Behavior-preserving: no ranking, plan, upgrade, or JSON output changes. All 220 tests pass.
Refs #41
What
Splits the 880-line
src/whichllm/output/display.pyinto focused per-surface modules:output/_console.pyConsole()instanceoutput/formatting.pyoutput/ranking.pydisplay_ranking+display_hardware+ ranking confidence helperoutput/plan.pydisplay_planoutput/upgrade.pydisplay_upgrade+_summarize_row+_upgrade_verdictoutput/json_output.pydisplay_json+display_plan_json+display_upgrade_jsonoutput/display.pyoutput/display.pybecomes a thin shim that re-exports everydisplay_*public function plusconsole, so every existingfrom whichllm.output.display import …import keeps working with no churn incli.pyor anywhere else.Test monkey-patch update
Three tests captured Rich output by reassigning
whichllm.output.display.console = Console(file=buf, …). After the split, that attribute is only the shim's local binding and doesn't reach the per-surface modules. The tests now target the new single source of truth,whichllm.output._console.console, which every surface looks up at call time. Same capture semantics, three-line change per site:tests/test_cli.py(2 sites, plan-JSON and ranking-JSON capture)tests/test_intel_gpu.py(Intel shared-memory hardware display)tests/test_amd_detection.py(AMD shared-memory hardware display)Why
Per #41,
display.pymixed five output surfaces (ranking, plan, upgrade, JSON, shared formatting), each with its own change cadence. Splitting them means future tweaks to the upgrade verdict, the plan VRAM table, or the JSON schema stay local to one file.Behavior
Strictly behavior-preserving:
Test plan
uv run pytest— 220 passeduv run whichllm --help— worksfrom whichllm.output.display import display_hardware, display_ranking, display_plan, display_plan_json, display_upgrade, display_upgrade_json, display_json, console— all resolveNext in series
After this lands, per the agreed plan in #41: PR 4 will split
models/fetcher.py.