mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:07:04 +01:00
Split brother_printer page-count display into its own module
display.py 342 -> 248, under the 250-line cap. The page-count estimate, the dropped-page warning and the consumables reference move verbatim to _page_count.py, which imports the two collaborators the tests patch (check_page_delivery, estimate_consumable_life) directly. test_display_part3.py patched only those two names, so it becomes test_page_count.py with its MOD pointing at the new module. Pass count is 402 before and after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
This commit is contained in:
parent
82fe807deb
commit
386ff25296
@ -0,0 +1,44 @@
|
||||
{
|
||||
"intent": "Bring brother_printer/display.py under the 250-line cap by moving the page-count estimate and dropped-page warning into their own module, with no behaviour change.",
|
||||
"scope": [
|
||||
"python_pkg/brother_printer/_page_count.py (new)",
|
||||
"python_pkg/brother_printer/display.py",
|
||||
"python_pkg/brother_printer/tests/test_display_part3.py -> tests/test_page_count.py",
|
||||
"Non-goal: no assertion changed, no test deleted, skipped or weakened"
|
||||
],
|
||||
"changes": [
|
||||
"Moved _display_page_delivery_warning, _display_page_count_estimate and _display_consumables_reference verbatim into python_pkg/brother_printer/_page_count.py, which imports the patched collaborators check_page_delivery and estimate_consumable_life directly.",
|
||||
"display.py now imports the three functions from _page_count so display_usb_results still resolves them, and dropped the now-unused render_life_bar, TONER_RATED_PAGES and DRUM_RATED_PAGES imports; 342 -> 248 lines.",
|
||||
"Renamed tests/test_display_part3.py to tests/test_page_count.py and repointed its MOD and import block to the new module (per docs/python-split-recipes.md, the module a test patches must be the one the function actually lives in)."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "PYTHONPATH=. python3 -m pytest python_pkg/brother_printer/tests -q",
|
||||
"result": "pass",
|
||||
"evidence": "402 passed before the split and 402 passed after it - identical pass count, not merely a green run."
|
||||
},
|
||||
{
|
||||
"command": "PYTHONPATH=. python3 -c \"from python_pkg.brother_printer import display; display._display_page_count_estimate; display._display_consumables_reference; display._display_report_header; display._display_page_delivery_warning\"",
|
||||
"result": "pass",
|
||||
"evidence": "runtime probe OK - the names test_display.py patches on display are still attributes of display at import time, so ruff's TC001 rewrite trap did not fire."
|
||||
},
|
||||
{
|
||||
"command": "wc -l python_pkg/brother_printer/display.py",
|
||||
"result": "pass",
|
||||
"evidence": "248 lines, under the 250-line cap; _page_count.py is 114 lines."
|
||||
},
|
||||
{
|
||||
"command": "pre-commit run --files python_pkg/brother_printer/_page_count.py python_pkg/brother_printer/display.py python_pkg/brother_printer/tests/test_page_count.py",
|
||||
"result": "pass",
|
||||
"evidence": "ruff auto-sorted the new import block in test_page_count.py on the first run; clean on re-run."
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"mock.patch pins names to a module: a test still patching estimate_consumable_life on display would now miss. Checked - test_page_count.py is the only module that patched it, and its MOD moved with the code.",
|
||||
"display.py keeps _display_report_header, which both test_display.py and test_display_part2.py patch, so it was deliberately left in place."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert the commit; display.py returns to 342 lines and test_page_count.py back to test_display_part3.py.",
|
||||
"After rollback, re-run the package suite and confirm it still reports 402 passed."
|
||||
]
|
||||
}
|
||||
117
python_pkg/brother_printer/_page_count.py
Normal file
117
python_pkg/brother_printer/_page_count.py
Normal file
@ -0,0 +1,117 @@
|
||||
"""Page-count estimates and the dropped-page warning.
|
||||
|
||||
Split out of :mod:`python_pkg.brother_printer.display` to keep it under the
|
||||
250-line cap. ``estimate_consumable_life`` and ``check_page_delivery`` are
|
||||
patched by ``tests/test_display_part3.py``, so they are imported here rather
|
||||
than through ``display``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from python_pkg.brother_printer._supply import render_life_bar
|
||||
from python_pkg.brother_printer.constants import (
|
||||
BOLD,
|
||||
DIM,
|
||||
DRUM_RATED_PAGES,
|
||||
RED,
|
||||
RESET,
|
||||
TONER_RATED_PAGES,
|
||||
YELLOW,
|
||||
_out,
|
||||
)
|
||||
from python_pkg.brother_printer.consumables import (
|
||||
check_page_delivery,
|
||||
estimate_consumable_life,
|
||||
)
|
||||
|
||||
|
||||
def _display_page_delivery_warning(printer_total: int, *, queue_idle: bool) -> None:
|
||||
"""Warn when CUPS claims more pages than the printer actually counted.
|
||||
|
||||
Args:
|
||||
printer_total: Lifetime count from the printer's own counter.
|
||||
queue_idle: False while a job is queued or printing, when the two
|
||||
counters legitimately disagree.
|
||||
"""
|
||||
check = check_page_delivery(printer_total, queue_idle=queue_idle)
|
||||
if not check.suspected:
|
||||
return
|
||||
_out(f"{BOLD}── Dropped Pages ──{RESET}")
|
||||
_out()
|
||||
_out(
|
||||
f" {RED}{BOLD}⚠ {check.dropped} pages did not print.{RESET}"
|
||||
f" {RED}CUPS sent {check.cups_pages} pages since the last check;"
|
||||
f" the printer's own counter advanced by"
|
||||
f" {check.printer_pages}.{RESET}"
|
||||
)
|
||||
_out()
|
||||
_out(
|
||||
f" {DIM}The printer discards pages whose 600 dpi raster does not fit"
|
||||
f" its memory, stays READY, and reports no error - and CUPS still calls"
|
||||
f" the job successful. Reprint at a lower resolution:{RESET}"
|
||||
)
|
||||
_out(f" {DIM} lp -o Resolution=300dpi <file>{RESET}")
|
||||
_out()
|
||||
|
||||
|
||||
def _display_page_count_estimate(printer_total: int = 0) -> None:
|
||||
"""Show estimated consumable life based on the printer's page count.
|
||||
|
||||
Args:
|
||||
printer_total: Lifetime count from the printer's own counter, or zero
|
||||
when it could not be read and the CUPS page log has to stand in.
|
||||
"""
|
||||
estimate = estimate_consumable_life(printer_total)
|
||||
if estimate.total_pages <= 0:
|
||||
return
|
||||
_out(f"{BOLD}── Page Count Estimate ──{RESET}")
|
||||
_out()
|
||||
_out(
|
||||
f" {BOLD}Total pages printed:{RESET} {estimate.total_pages}"
|
||||
f" (toner: {estimate.toner_pages} since replacement,"
|
||||
f" drum: {estimate.drum_pages} since replacement)"
|
||||
)
|
||||
if estimate.approximate:
|
||||
_out(
|
||||
f" {YELLOW}Approximate: counted from the CUPS log, not the"
|
||||
f" printer's own counter, so it misses pages CUPS never saw"
|
||||
f" and reads high.{RESET}"
|
||||
)
|
||||
_out()
|
||||
render_life_bar(
|
||||
"Toner:",
|
||||
estimate.toner_pct_remaining,
|
||||
exhausted=estimate.toner_exhausted,
|
||||
low=estimate.toner_low,
|
||||
exhausted_note=" ← REPLACE NOW",
|
||||
low_note=" ← order soon",
|
||||
)
|
||||
render_life_bar(
|
||||
"Drum: ",
|
||||
estimate.drum_pct_remaining,
|
||||
low=estimate.drum_near_end,
|
||||
low_note=" ← nearing end",
|
||||
)
|
||||
_out(
|
||||
f" {DIM}Based on pages since last replacement"
|
||||
f" vs rated capacity (toner ~{TONER_RATED_PAGES},"
|
||||
f" drum ~{DRUM_RATED_PAGES}).{RESET}"
|
||||
)
|
||||
_out(f" {DIM}Reset after replacing: --reset-toner or --reset-drum{RESET}")
|
||||
if estimate.toner_exhausted:
|
||||
_out()
|
||||
_out(
|
||||
f" {RED}{BOLD}⚠ Toner is likely exhausted."
|
||||
f" This is probably why the orange light is flashing.{RESET}"
|
||||
)
|
||||
_out()
|
||||
|
||||
|
||||
def _display_consumables_reference() -> None:
|
||||
"""Print compatible consumables reference."""
|
||||
_out(f"{BOLD}── Compatible Consumables ──{RESET}")
|
||||
_out()
|
||||
_out(f" {BOLD}Toner:{RESET} TN-1050 / TN-1030 (or compatible third-party)")
|
||||
_out(f" {BOLD}Drum:{RESET} DR-1050 / DR-1030 (or compatible third-party)")
|
||||
_out(f" {DIM} Toner rated ~1000 pages; Drum rated ~10000 pages.{RESET}")
|
||||
_out()
|
||||
@ -9,6 +9,11 @@ from typing import TYPE_CHECKING
|
||||
# Re-exported through __all__: tests/test_display.py imports these names from
|
||||
# this module. Only the un-patched supply *maths* moved to _supply -- everything
|
||||
# the tests reach with mock.patch has to stay resolvable here.
|
||||
from python_pkg.brother_printer._page_count import (
|
||||
_display_consumables_reference,
|
||||
_display_page_count_estimate,
|
||||
_display_page_delivery_warning,
|
||||
)
|
||||
from python_pkg.brother_printer._severity import (
|
||||
_SEVERITY_COLORS,
|
||||
_SEVERITY_ICONS,
|
||||
@ -21,25 +26,18 @@ from python_pkg.brother_printer._supply import (
|
||||
_format_supply_bar,
|
||||
_parse_supply_value,
|
||||
_process_supply_item,
|
||||
render_life_bar,
|
||||
)
|
||||
from python_pkg.brother_printer.constants import (
|
||||
BOLD,
|
||||
CYAN,
|
||||
DIM,
|
||||
DRUM_RATED_PAGES,
|
||||
GREEN,
|
||||
RED,
|
||||
RESET,
|
||||
TONER_RATED_PAGES,
|
||||
YELLOW,
|
||||
_out,
|
||||
get_status_info,
|
||||
)
|
||||
from python_pkg.brother_printer.consumables import (
|
||||
check_page_delivery,
|
||||
estimate_consumable_life,
|
||||
)
|
||||
from python_pkg.brother_printer.cups_queue import (
|
||||
display_cups_queue_status,
|
||||
get_cups_queue_status,
|
||||
@ -72,98 +70,6 @@ def _display_report_header() -> None:
|
||||
_out()
|
||||
|
||||
|
||||
def _display_page_delivery_warning(printer_total: int, *, queue_idle: bool) -> None:
|
||||
"""Warn when CUPS claims more pages than the printer actually counted.
|
||||
|
||||
Args:
|
||||
printer_total: Lifetime count from the printer's own counter.
|
||||
queue_idle: False while a job is queued or printing, when the two
|
||||
counters legitimately disagree.
|
||||
"""
|
||||
check = check_page_delivery(printer_total, queue_idle=queue_idle)
|
||||
if not check.suspected:
|
||||
return
|
||||
_out(f"{BOLD}── Dropped Pages ──{RESET}")
|
||||
_out()
|
||||
_out(
|
||||
f" {RED}{BOLD}⚠ {check.dropped} pages did not print.{RESET}"
|
||||
f" {RED}CUPS sent {check.cups_pages} pages since the last check;"
|
||||
f" the printer's own counter advanced by"
|
||||
f" {check.printer_pages}.{RESET}"
|
||||
)
|
||||
_out()
|
||||
_out(
|
||||
f" {DIM}The printer discards pages whose 600 dpi raster does not fit"
|
||||
f" its memory, stays READY, and reports no error - and CUPS still calls"
|
||||
f" the job successful. Reprint at a lower resolution:{RESET}"
|
||||
)
|
||||
_out(f" {DIM} lp -o Resolution=300dpi <file>{RESET}")
|
||||
_out()
|
||||
|
||||
|
||||
def _display_page_count_estimate(printer_total: int = 0) -> None:
|
||||
"""Show estimated consumable life based on the printer's page count.
|
||||
|
||||
Args:
|
||||
printer_total: Lifetime count from the printer's own counter, or zero
|
||||
when it could not be read and the CUPS page log has to stand in.
|
||||
"""
|
||||
estimate = estimate_consumable_life(printer_total)
|
||||
if estimate.total_pages <= 0:
|
||||
return
|
||||
_out(f"{BOLD}── Page Count Estimate ──{RESET}")
|
||||
_out()
|
||||
_out(
|
||||
f" {BOLD}Total pages printed:{RESET} {estimate.total_pages}"
|
||||
f" (toner: {estimate.toner_pages} since replacement,"
|
||||
f" drum: {estimate.drum_pages} since replacement)"
|
||||
)
|
||||
if estimate.approximate:
|
||||
_out(
|
||||
f" {YELLOW}Approximate: counted from the CUPS log, not the"
|
||||
f" printer's own counter, so it misses pages CUPS never saw"
|
||||
f" and reads high.{RESET}"
|
||||
)
|
||||
_out()
|
||||
render_life_bar(
|
||||
"Toner:",
|
||||
estimate.toner_pct_remaining,
|
||||
exhausted=estimate.toner_exhausted,
|
||||
low=estimate.toner_low,
|
||||
exhausted_note=" ← REPLACE NOW",
|
||||
low_note=" ← order soon",
|
||||
)
|
||||
render_life_bar(
|
||||
"Drum: ",
|
||||
estimate.drum_pct_remaining,
|
||||
low=estimate.drum_near_end,
|
||||
low_note=" ← nearing end",
|
||||
)
|
||||
_out(
|
||||
f" {DIM}Based on pages since last replacement"
|
||||
f" vs rated capacity (toner ~{TONER_RATED_PAGES},"
|
||||
f" drum ~{DRUM_RATED_PAGES}).{RESET}"
|
||||
)
|
||||
_out(f" {DIM}Reset after replacing: --reset-toner or --reset-drum{RESET}")
|
||||
if estimate.toner_exhausted:
|
||||
_out()
|
||||
_out(
|
||||
f" {RED}{BOLD}⚠ Toner is likely exhausted."
|
||||
f" This is probably why the orange light is flashing.{RESET}"
|
||||
)
|
||||
_out()
|
||||
|
||||
|
||||
def _display_consumables_reference() -> None:
|
||||
"""Print compatible consumables reference."""
|
||||
_out(f"{BOLD}── Compatible Consumables ──{RESET}")
|
||||
_out()
|
||||
_out(f" {BOLD}Toner:{RESET} TN-1050 / TN-1030 (or compatible third-party)")
|
||||
_out(f" {BOLD}Drum:{RESET} DR-1050 / DR-1030 (or compatible third-party)")
|
||||
_out(f" {DIM} Toner rated ~1000 pages; Drum rated ~10000 pages.{RESET}")
|
||||
_out()
|
||||
|
||||
|
||||
# ── USB display helpers ──────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
"""Tests for brother_printer.display - page counts and dropped-page warning."""
|
||||
"""Tests for brother_printer._page_count - page counts and dropped pages."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from io import StringIO
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from python_pkg.brother_printer.data_classes import (
|
||||
PageCountEstimate,
|
||||
PageDeliveryCheck,
|
||||
)
|
||||
from python_pkg.brother_printer.display import (
|
||||
from python_pkg.brother_printer._page_count import (
|
||||
_display_consumables_reference,
|
||||
_display_page_count_estimate,
|
||||
_display_page_delivery_warning,
|
||||
)
|
||||
from python_pkg.brother_printer.data_classes import (
|
||||
PageCountEstimate,
|
||||
PageDeliveryCheck,
|
||||
)
|
||||
|
||||
MOD = "python_pkg.brother_printer.display"
|
||||
MOD = "python_pkg.brother_printer._page_count"
|
||||
|
||||
|
||||
class TestDisplayPageCountEstimate:
|
||||
Loading…
Reference in New Issue
Block a user