From a5a98911eba3e5b79bef2a972a746a6f9d6ce96f Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:07:38 -0700 Subject: [PATCH 1/9] initial tests --- tests/python/unit/test_pb.py | 565 +++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 tests/python/unit/test_pb.py diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py new file mode 100644 index 000000000..953389415 --- /dev/null +++ b/tests/python/unit/test_pb.py @@ -0,0 +1,565 @@ +"""Tests for `compass.pb` progress bar helpers""" + +from __future__ import annotations + +from collections.abc import Callable +from contextlib import ExitStack +from io import StringIO + +import pytest +from rich.console import Console +from rich.text import Text + +from compass import pb as pb_module +from compass.exceptions import COMPASSNotInitializedError, COMPASSValueError +from compass.pb import ( + COMPASS_PB, + _COMPASSProgressBars, + _MofNCompleteColumn, + _TimeElapsedColumn, + _TotalCostColumn, +) + + +@pytest.fixture(name="console") +def fixture_console(): + """Console directed to an in-memory buffer for deterministic tests""" + + return Console(file=StringIO(), color_system=None, force_terminal=False) + + +@pytest.fixture(name="progress_bars") +def fixture_progress_bars(console): + """Fresh progress bar manager for each test""" + + manager = _COMPASSProgressBars(console=console) + yield manager + manager._main.stop() + + +class DummyTask: + """Lightweight object exposing attributes used by rich tasks""" + + def __init__( + self, + *, + finished: bool = False, + finished_time: float | None = None, + elapsed: float | None = None, + completed: float = 0, + total: float | None = None, + fields: dict | None = None, + description: str = "", + ) -> None: + self.finished = finished + self.finished_time = finished_time + self.elapsed = elapsed + self.completed = completed + self.total = total + self.fields = fields or {} + self.description = description + + +def assert_text(text: Text, expected: str) -> None: + """Compare Text objects using their plain representation""" + + assert text.plain == expected + + +def test_time_elapsed_column_handles_missing_elapsed() -> None: + """Render placeholder when elapsed time is missing""" + + column = _TimeElapsedColumn() + task = DummyTask() + + text = column.render(task) + + assert_text(text, "[-:--:--]") + + +def test_time_elapsed_column_uses_finished_time() -> None: + """Render finished time when task completes""" + + column = _TimeElapsedColumn() + task = DummyTask(finished=True, finished_time=125.7) + + text = column.render(task) + + assert_text(text, "[0:02:05]") + + +def test_m_of_n_complete_column_with_total_known() -> None: + """Display counts when total is known""" + + column = _MofNCompleteColumn(style="green") + task = DummyTask(completed=5, total=42) + + text = column.render(task) + + assert_text(text, " 5/42") + + +def test_m_of_n_complete_column_with_unknown_total() -> None: + """Display counts when total is unknown""" + + column = _MofNCompleteColumn() + task = DummyTask(completed=7) + + text = column.render(task) + + assert_text(text, " 7/?") + + +def test_total_cost_column_with_and_without_cost() -> None: + """Show cost text only when present""" + + column = _TotalCostColumn() + + zero_text = column.render(DummyTask(fields={"total_cost": 0})) + cost_text = column.render(DummyTask(fields={"total_cost": 3.456})) + + assert_text(zero_text, "") + assert_text(cost_text, "($3.46)") + + +def test_group_property_returns_group(progress_bars) -> None: + """Expose default progress group""" + + assert progress_bars.group.renderables == [progress_bars._main] + + +def test_create_main_task_single_and_duplicate_error(console) -> None: + """Guard against duplicate main tasks""" + + bars = _COMPASSProgressBars(console=console) + bars.create_main_task(1) + + task = bars._main.tasks[bars._main_task] + assert "Searching 1 Jurisdiction" in task.description + + with pytest.raises(COMPASSValueError): + bars.create_main_task(1) + + bars._main.stop() + + +def test_create_main_task_multiple(progress_bars) -> None: + """Format description for multiple jurisdictions""" + + progress_bars.create_main_task(3) + + task = progress_bars._main.tasks[progress_bars._main_task] + assert "Searching 3 Jurisdictions" in task.description + + +def test_progress_main_task_requires_initialization(progress_bars) -> None: + """Require initialization before advancing main task""" + + with pytest.raises(COMPASSNotInitializedError): + progress_bars.progress_main_task() + + +def test_progress_main_task_advances(progress_bars) -> None: + """Advance main task increments progress""" + + progress_bars.create_main_task(2) + + progress_bars.progress_main_task() + + task = progress_bars._main.tasks[progress_bars._main_task] + assert task.completed == 1 + + +def test_update_total_cost_handles_add_and_replace(progress_bars) -> None: + """Handle cost updates for add and replace paths""" + + progress_bars.create_main_task(1) + + progress_bars.update_total_cost(1.25) + assert progress_bars._total_cost == pytest.approx(1.25) + + progress_bars.update_total_cost(0.5, replace=True) + assert progress_bars._total_cost == pytest.approx(1.25) + + progress_bars.update_total_cost(5.0, replace=True) + assert progress_bars._total_cost == pytest.approx(5.0) + + task = progress_bars._main.tasks[progress_bars._main_task] + assert task.fields["total_cost"] == pytest.approx(5.0) + + +def test_update_total_cost_without_main(progress_bars) -> None: + """Track cost updates without main task""" + + progress_bars.update_total_cost(2.0) + assert progress_bars._total_cost == pytest.approx(2.0) + + +def test_jurisdiction_prog_bar_lifecycle(progress_bars) -> None: + """Manage lifecycle for jurisdiction bars""" + + progress_bars.create_main_task(1) + + with progress_bars.jurisdiction_prog_bar("Denmark") as jd_pb: + assert "Denmark" in progress_bars._jd_pbs + progress_bars.update_jurisdiction_task("Denmark", description="Work") + + def enter_duplicate() -> None: + with ExitStack() as stack: + stack.enter_context( + progress_bars.jurisdiction_prog_bar("Denmark") + ) + + with pytest.raises(COMPASSValueError): + enter_duplicate() + + progress_bars._jd_tasks["Denmark"] = jd_pb.add_task("extra") + + task = progress_bars._main.tasks[progress_bars._main_task] + assert task.completed == 1 + assert "Denmark" not in progress_bars._jd_pbs + + +def test_jurisdiction_prog_bar_without_progress_main(progress_bars) -> None: + """Skip main progress when requested""" + + progress_bars.create_main_task(1) + + with progress_bars.jurisdiction_prog_bar("Spain", progress_main=False): + pass + + task = progress_bars._main.tasks[progress_bars._main_task] + assert task.completed == 0 + + +def test_jurisdiction_sub_prog_inserts_after_parent(progress_bars) -> None: + """Insert sub progress after parent bar""" + + progress_bars.create_main_task(1) + + with ExitStack() as stack: + stack.enter_context(progress_bars.jurisdiction_prog_bar("Sweden")) + sub_pb = stack.enter_context( + progress_bars.jurisdiction_sub_prog("Sweden") + ) + assert sub_pb in progress_bars.group.renderables + + renderables = progress_bars.group.renderables + assert not any("Sweden" in str(item) for item in renderables) + + +def test_jurisdiction_sub_prog_without_parent(progress_bars) -> None: + """Create sub progress without parent bar""" + + assert "Norway" not in progress_bars._jd_pbs + start_len = len(progress_bars.group.renderables) + + with progress_bars.jurisdiction_sub_prog("Norway") as sub_pb: + assert sub_pb in progress_bars.group.renderables + assert progress_bars.group.renderables.index(sub_pb) == start_len + + assert sub_pb not in progress_bars.group.renderables + + +def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars) -> None: + """Update jurisdiction sub progress fields""" + + progress_bars.create_main_task(1) + + with ExitStack() as stack: + stack.enter_context(progress_bars.jurisdiction_prog_bar("Iceland")) + sub_pb = stack.enter_context( + progress_bars.jurisdiction_sub_prog_bar("Iceland") + ) + task_id = sub_pb.add_task( + "downloading", + total=3, + just_parsed="none", + ) + sub_pb.advance(task_id) + sub_pb.update(task_id, just_parsed="doc.pdf") + + assert "Iceland" not in progress_bars._jd_pbs + + +@pytest.mark.asyncio() +async def test_file_download_prog_bar_async_lifecycle( + progress_bars, + monkeypatch, +) -> None: + """Drive async lifecycle for download progress bar""" + + calls: list[int] = [] + original_sleep = pb_module.asyncio.sleep + + async def fake_sleep(duration: int) -> None: + calls.append(duration) + await original_sleep(0) + + monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) + + progress_bars.create_main_task(1) + + async with progress_bars.file_download_prog_bar( + "Finland", + num_downloads=2, + ) as dl_pb: + dl_task = progress_bars._dl_tasks["Finland"] + dl_pb.advance(dl_task) + progress_bars.update_download_task("Finland", completed=1) + progress_bars._dl_tasks["Finland"] = dl_pb.add_task("extra") + + assert calls == [1] + assert "Finland" not in progress_bars._dl_pbs + + +@pytest.mark.asyncio() +async def test_file_download_prog_bar_positions_after_jurisdiction( + progress_bars, + monkeypatch, +) -> None: + """Insert download progress immediately after jurisdiction bar""" + + _patch_sleep(monkeypatch) + progress_bars.create_main_task(1) + + with progress_bars.jurisdiction_prog_bar("Poland"): + async with progress_bars.file_download_prog_bar( + "Poland", + num_downloads=1, + ) as dl_pb: + jd_index = progress_bars.group.renderables.index( + progress_bars._jd_pbs["Poland"] + ) + dl_index = progress_bars.group.renderables.index(dl_pb) + assert dl_index == jd_index + 1 + + progress_bars._dl_tasks["Poland"] = None + + progress_bars._dl_tasks.pop("Poland", None) + + +@pytest.mark.asyncio() +async def test_start_file_download_prog_bar_duplicate( + progress_bars, + monkeypatch, +) -> None: + """Prevent duplicate download progress bars""" + + original_sleep = pb_module.asyncio.sleep + + async def fake_sleep(_: int) -> None: + await original_sleep(0) + + monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) + + dl_pb, task = progress_bars.start_file_download_prog_bar("France", 1) + + with pytest.raises(COMPASSValueError): + progress_bars.start_file_download_prog_bar("France", 1) + + progress_bars._dl_tasks["France"] = dl_pb.add_task("extra") + await progress_bars.tear_down_file_download_prog_bar( + "France", + 1, + dl_pb, + task, + ) + + assert "France" not in progress_bars._dl_pbs + + +def _patch_sleep(monkeypatch) -> Callable[[], list[int]]: + """Patch asyncio.sleep and capture durations""" + + calls: list[int] = [] + original_sleep = pb_module.asyncio.sleep + + async def fake_sleep(duration: int) -> None: + calls.append(duration) + await original_sleep(0) + + monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) + return lambda: calls + + +@pytest.mark.asyncio() +async def test_website_crawl_prog_bar(progress_bars, monkeypatch) -> None: + """Drive async lifecycle for website crawl progress bar""" + + calls_getter = _patch_sleep(monkeypatch) + + progress_bars.create_main_task(1) + + async with progress_bars.website_crawl_prog_bar( + "Germany", + num_pages=3, + ) as wc_pb: + progress_bars.update_website_crawl_doc_found("Germany") + progress_bars.update_website_crawl_doc_found("Germany") + progress_bars.update_website_crawl_task("Germany", completed=1) + progress_bars._wc_tasks["Germany"] = wc_pb.add_task("extra") + + assert "Germany" not in progress_bars._wc_pbs + assert calls_getter() == [1] + + +@pytest.mark.asyncio() +async def test_website_crawl_prog_bar_positions_after_jurisdiction( + progress_bars, + monkeypatch, +) -> None: + """Insert website crawl progress immediately after jurisdiction bar""" + + calls_getter = _patch_sleep(monkeypatch) + progress_bars.create_main_task(1) + + with progress_bars.jurisdiction_prog_bar("Poland"): + async with progress_bars.website_crawl_prog_bar( + "Poland", + num_pages=1, + ) as wc_pb: + jd_index = progress_bars.group.renderables.index( + progress_bars._jd_pbs["Poland"] + ) + wc_index = progress_bars.group.renderables.index(wc_pb) + assert wc_index == jd_index + 1 + + progress_bars._wc_tasks["Poland"] = None + + assert calls_getter() == [1] + progress_bars._wc_tasks.pop("Poland", None) + + +@pytest.mark.asyncio() +async def test_file_download_prog_bar_positions_without_jurisdiction( + progress_bars, + monkeypatch, +) -> None: + """Place download progress at end when no jurisdiction bar exists""" + + calls_getter = _patch_sleep(monkeypatch) + + dl_pb, task = progress_bars.start_file_download_prog_bar("Greece", 2) + + assert progress_bars.group.renderables[-1] is dl_pb + + await progress_bars.tear_down_file_download_prog_bar( + "Greece", + 2, + dl_pb, + task, + ) + + assert calls_getter() == [1] + + +@pytest.mark.asyncio() +async def test_website_crawl_prog_bar_duplicate( + progress_bars, + monkeypatch, +) -> None: + """Prevent duplicate website crawl progress bars""" + + _patch_sleep(monkeypatch) + + async with progress_bars.website_crawl_prog_bar( + "Italy", + num_pages=1, + ) as wc_pb: + with pytest.raises(COMPASSValueError): + async with progress_bars.website_crawl_prog_bar( + "Italy", + num_pages=1, + ): + pass + + progress_bars._wc_tasks["Italy"] = wc_pb.add_task("extra") + + assert "Italy" not in progress_bars._wc_pbs + + +@pytest.mark.asyncio() +async def test_compass_website_crawl_prog_bar( + progress_bars, + monkeypatch, +) -> None: + """Drive async lifecycle for compass crawl progress bar""" + + calls_getter = _patch_sleep(monkeypatch) + + progress_bars.create_main_task(1) + + async with progress_bars.compass_website_crawl_prog_bar( + "Hungary", + num_pages=2, + ) as cwc_pb: + progress_bars.update_compass_website_crawl_doc_found("Hungary") + progress_bars.update_compass_website_crawl_doc_found("Hungary") + progress_bars.update_compass_website_crawl_task( + "Hungary", + completed=1, + ) + progress_bars._cwc_tasks["Hungary"] = cwc_pb.add_task("extra") + + assert "Hungary" not in progress_bars._cwc_pbs + assert calls_getter() == [1] + + +@pytest.mark.asyncio() +async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( + progress_bars, + monkeypatch, +) -> None: + """Insert compass crawl progress immediately after jurisdiction bar""" + + calls_getter = _patch_sleep(monkeypatch) + progress_bars.create_main_task(1) + + with progress_bars.jurisdiction_prog_bar("Poland"): + async with progress_bars.compass_website_crawl_prog_bar( + "Poland", + num_pages=1, + ) as cwc_pb: + jd_index = progress_bars.group.renderables.index( + progress_bars._jd_pbs["Poland"] + ) + cwc_index = progress_bars.group.renderables.index(cwc_pb) + assert cwc_index == jd_index + 1 + + progress_bars._cwc_tasks["Poland"] = None + + assert calls_getter() == [1] + progress_bars._cwc_tasks.pop("Poland", None) + + +@pytest.mark.asyncio() +async def test_compass_website_crawl_prog_bar_duplicate( + progress_bars, + monkeypatch, +) -> None: + """Prevent duplicate compass crawl progress bars""" + + _patch_sleep(monkeypatch) + + async with progress_bars.compass_website_crawl_prog_bar( + "Iceland", + num_pages=1, + ) as cwc_pb: + with pytest.raises(COMPASSValueError): + async with progress_bars.compass_website_crawl_prog_bar( + "Iceland", + num_pages=1, + ): + pass + + progress_bars._cwc_tasks["Iceland"] = cwc_pb.add_task("extra") + + assert "Iceland" not in progress_bars._cwc_pbs + + +def test_singleton_instance_accessible(console) -> None: + """Expose singleton progress bar instance""" + + assert isinstance(COMPASS_PB, _COMPASSProgressBars) + COMPASS_PB.console = console From c16ac9739e56eb6052ad32d6432f578d49e03a08 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:10:04 -0700 Subject: [PATCH 2/9] Add another test --- tests/python/unit/test_pb.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 953389415..5fd37e8a3 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -282,6 +282,21 @@ def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars) -> None: assert "Iceland" not in progress_bars._jd_pbs +def test_jurisdiction_sub_prog_bar_without_parent(progress_bars) -> None: + """Place sub progress bar at end when no parent exists""" + + start_len = len(progress_bars.group.renderables) + + with progress_bars.jurisdiction_sub_prog_bar("Portugal") as sub_pb: + assert progress_bars._jd_pbs.get("Portugal") is None + assert progress_bars.group.renderables.index(sub_pb) == start_len + + task_id = sub_pb.add_task("extracting", total=2) + sub_pb.advance(task_id) + + assert sub_pb not in progress_bars.group.renderables + + @pytest.mark.asyncio() async def test_file_download_prog_bar_async_lifecycle( progress_bars, From 6734904d5213a0f472039013e6b3704f7619f7fb Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:17:47 -0700 Subject: [PATCH 3/9] Style updates --- tests/python/unit/test_pb.py | 94 +++++++++++++++++------------------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 5fd37e8a3..4802ed3e7 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -1,14 +1,10 @@ """Tests for `compass.pb` progress bar helpers""" -from __future__ import annotations - -from collections.abc import Callable from contextlib import ExitStack from io import StringIO import pytest from rich.console import Console -from rich.text import Text from compass import pb as pb_module from compass.exceptions import COMPASSNotInitializedError, COMPASSValueError @@ -43,14 +39,14 @@ class DummyTask: def __init__( self, *, - finished: bool = False, - finished_time: float | None = None, - elapsed: float | None = None, - completed: float = 0, - total: float | None = None, - fields: dict | None = None, - description: str = "", - ) -> None: + finished=False, + finished_time=None, + elapsed=None, + completed=0, + total=None, + fields=None, + description="", + ): self.finished = finished self.finished_time = finished_time self.elapsed = elapsed @@ -60,13 +56,13 @@ def __init__( self.description = description -def assert_text(text: Text, expected: str) -> None: +def assert_text(text, expected): """Compare Text objects using their plain representation""" assert text.plain == expected -def test_time_elapsed_column_handles_missing_elapsed() -> None: +def test_time_elapsed_column_handles_missing_elapsed(): """Render placeholder when elapsed time is missing""" column = _TimeElapsedColumn() @@ -77,7 +73,7 @@ def test_time_elapsed_column_handles_missing_elapsed() -> None: assert_text(text, "[-:--:--]") -def test_time_elapsed_column_uses_finished_time() -> None: +def test_time_elapsed_column_uses_finished_time(): """Render finished time when task completes""" column = _TimeElapsedColumn() @@ -88,7 +84,7 @@ def test_time_elapsed_column_uses_finished_time() -> None: assert_text(text, "[0:02:05]") -def test_m_of_n_complete_column_with_total_known() -> None: +def test_m_of_n_complete_column_with_total_known(): """Display counts when total is known""" column = _MofNCompleteColumn(style="green") @@ -99,7 +95,7 @@ def test_m_of_n_complete_column_with_total_known() -> None: assert_text(text, " 5/42") -def test_m_of_n_complete_column_with_unknown_total() -> None: +def test_m_of_n_complete_column_with_unknown_total(): """Display counts when total is unknown""" column = _MofNCompleteColumn() @@ -110,7 +106,7 @@ def test_m_of_n_complete_column_with_unknown_total() -> None: assert_text(text, " 7/?") -def test_total_cost_column_with_and_without_cost() -> None: +def test_total_cost_column_with_and_without_cost(): """Show cost text only when present""" column = _TotalCostColumn() @@ -122,13 +118,13 @@ def test_total_cost_column_with_and_without_cost() -> None: assert_text(cost_text, "($3.46)") -def test_group_property_returns_group(progress_bars) -> None: +def test_group_property_returns_group(progress_bars): """Expose default progress group""" assert progress_bars.group.renderables == [progress_bars._main] -def test_create_main_task_single_and_duplicate_error(console) -> None: +def test_create_main_task_single_and_duplicate_error(console): """Guard against duplicate main tasks""" bars = _COMPASSProgressBars(console=console) @@ -143,7 +139,7 @@ def test_create_main_task_single_and_duplicate_error(console) -> None: bars._main.stop() -def test_create_main_task_multiple(progress_bars) -> None: +def test_create_main_task_multiple(progress_bars): """Format description for multiple jurisdictions""" progress_bars.create_main_task(3) @@ -152,14 +148,14 @@ def test_create_main_task_multiple(progress_bars) -> None: assert "Searching 3 Jurisdictions" in task.description -def test_progress_main_task_requires_initialization(progress_bars) -> None: +def test_progress_main_task_requires_initialization(progress_bars): """Require initialization before advancing main task""" with pytest.raises(COMPASSNotInitializedError): progress_bars.progress_main_task() -def test_progress_main_task_advances(progress_bars) -> None: +def test_progress_main_task_advances(progress_bars): """Advance main task increments progress""" progress_bars.create_main_task(2) @@ -170,7 +166,7 @@ def test_progress_main_task_advances(progress_bars) -> None: assert task.completed == 1 -def test_update_total_cost_handles_add_and_replace(progress_bars) -> None: +def test_update_total_cost_handles_add_and_replace(progress_bars): """Handle cost updates for add and replace paths""" progress_bars.create_main_task(1) @@ -188,14 +184,14 @@ def test_update_total_cost_handles_add_and_replace(progress_bars) -> None: assert task.fields["total_cost"] == pytest.approx(5.0) -def test_update_total_cost_without_main(progress_bars) -> None: +def test_update_total_cost_without_main(progress_bars): """Track cost updates without main task""" progress_bars.update_total_cost(2.0) assert progress_bars._total_cost == pytest.approx(2.0) -def test_jurisdiction_prog_bar_lifecycle(progress_bars) -> None: +def test_jurisdiction_prog_bar_lifecycle(progress_bars): """Manage lifecycle for jurisdiction bars""" progress_bars.create_main_task(1) @@ -204,7 +200,7 @@ def test_jurisdiction_prog_bar_lifecycle(progress_bars) -> None: assert "Denmark" in progress_bars._jd_pbs progress_bars.update_jurisdiction_task("Denmark", description="Work") - def enter_duplicate() -> None: + def enter_duplicate(): with ExitStack() as stack: stack.enter_context( progress_bars.jurisdiction_prog_bar("Denmark") @@ -220,7 +216,7 @@ def enter_duplicate() -> None: assert "Denmark" not in progress_bars._jd_pbs -def test_jurisdiction_prog_bar_without_progress_main(progress_bars) -> None: +def test_jurisdiction_prog_bar_without_progress_main(progress_bars): """Skip main progress when requested""" progress_bars.create_main_task(1) @@ -232,7 +228,7 @@ def test_jurisdiction_prog_bar_without_progress_main(progress_bars) -> None: assert task.completed == 0 -def test_jurisdiction_sub_prog_inserts_after_parent(progress_bars) -> None: +def test_jurisdiction_sub_prog_inserts_after_parent(progress_bars): """Insert sub progress after parent bar""" progress_bars.create_main_task(1) @@ -248,7 +244,7 @@ def test_jurisdiction_sub_prog_inserts_after_parent(progress_bars) -> None: assert not any("Sweden" in str(item) for item in renderables) -def test_jurisdiction_sub_prog_without_parent(progress_bars) -> None: +def test_jurisdiction_sub_prog_without_parent(progress_bars): """Create sub progress without parent bar""" assert "Norway" not in progress_bars._jd_pbs @@ -261,7 +257,7 @@ def test_jurisdiction_sub_prog_without_parent(progress_bars) -> None: assert sub_pb not in progress_bars.group.renderables -def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars) -> None: +def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars): """Update jurisdiction sub progress fields""" progress_bars.create_main_task(1) @@ -282,7 +278,7 @@ def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars) -> None: assert "Iceland" not in progress_bars._jd_pbs -def test_jurisdiction_sub_prog_bar_without_parent(progress_bars) -> None: +def test_jurisdiction_sub_prog_bar_without_parent(progress_bars): """Place sub progress bar at end when no parent exists""" start_len = len(progress_bars.group.renderables) @@ -301,13 +297,13 @@ def test_jurisdiction_sub_prog_bar_without_parent(progress_bars) -> None: async def test_file_download_prog_bar_async_lifecycle( progress_bars, monkeypatch, -) -> None: +): """Drive async lifecycle for download progress bar""" - calls: list[int] = [] + calls = [] original_sleep = pb_module.asyncio.sleep - async def fake_sleep(duration: int) -> None: + async def fake_sleep(duration): calls.append(duration) await original_sleep(0) @@ -332,7 +328,7 @@ async def fake_sleep(duration: int) -> None: async def test_file_download_prog_bar_positions_after_jurisdiction( progress_bars, monkeypatch, -) -> None: +): """Insert download progress immediately after jurisdiction bar""" _patch_sleep(monkeypatch) @@ -358,12 +354,12 @@ async def test_file_download_prog_bar_positions_after_jurisdiction( async def test_start_file_download_prog_bar_duplicate( progress_bars, monkeypatch, -) -> None: +): """Prevent duplicate download progress bars""" original_sleep = pb_module.asyncio.sleep - async def fake_sleep(_: int) -> None: + async def fake_sleep(_): await original_sleep(0) monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) @@ -384,13 +380,13 @@ async def fake_sleep(_: int) -> None: assert "France" not in progress_bars._dl_pbs -def _patch_sleep(monkeypatch) -> Callable[[], list[int]]: +def _patch_sleep(monkeypatch): """Patch asyncio.sleep and capture durations""" - calls: list[int] = [] + calls = [] original_sleep = pb_module.asyncio.sleep - async def fake_sleep(duration: int) -> None: + async def fake_sleep(duration): calls.append(duration) await original_sleep(0) @@ -399,7 +395,7 @@ async def fake_sleep(duration: int) -> None: @pytest.mark.asyncio() -async def test_website_crawl_prog_bar(progress_bars, monkeypatch) -> None: +async def test_website_crawl_prog_bar(progress_bars, monkeypatch): """Drive async lifecycle for website crawl progress bar""" calls_getter = _patch_sleep(monkeypatch) @@ -423,7 +419,7 @@ async def test_website_crawl_prog_bar(progress_bars, monkeypatch) -> None: async def test_website_crawl_prog_bar_positions_after_jurisdiction( progress_bars, monkeypatch, -) -> None: +): """Insert website crawl progress immediately after jurisdiction bar""" calls_getter = _patch_sleep(monkeypatch) @@ -450,7 +446,7 @@ async def test_website_crawl_prog_bar_positions_after_jurisdiction( async def test_file_download_prog_bar_positions_without_jurisdiction( progress_bars, monkeypatch, -) -> None: +): """Place download progress at end when no jurisdiction bar exists""" calls_getter = _patch_sleep(monkeypatch) @@ -473,7 +469,7 @@ async def test_file_download_prog_bar_positions_without_jurisdiction( async def test_website_crawl_prog_bar_duplicate( progress_bars, monkeypatch, -) -> None: +): """Prevent duplicate website crawl progress bars""" _patch_sleep(monkeypatch) @@ -498,7 +494,7 @@ async def test_website_crawl_prog_bar_duplicate( async def test_compass_website_crawl_prog_bar( progress_bars, monkeypatch, -) -> None: +): """Drive async lifecycle for compass crawl progress bar""" calls_getter = _patch_sleep(monkeypatch) @@ -525,7 +521,7 @@ async def test_compass_website_crawl_prog_bar( async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( progress_bars, monkeypatch, -) -> None: +): """Insert compass crawl progress immediately after jurisdiction bar""" calls_getter = _patch_sleep(monkeypatch) @@ -552,7 +548,7 @@ async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( async def test_compass_website_crawl_prog_bar_duplicate( progress_bars, monkeypatch, -) -> None: +): """Prevent duplicate compass crawl progress bars""" _patch_sleep(monkeypatch) @@ -573,7 +569,7 @@ async def test_compass_website_crawl_prog_bar_duplicate( assert "Iceland" not in progress_bars._cwc_pbs -def test_singleton_instance_accessible(console) -> None: +def test_singleton_instance_accessible(console): """Expose singleton progress bar instance""" assert isinstance(COMPASS_PB, _COMPASSProgressBars) From d234a4e6b11349c14c3aa0f28ff4c252ae1f94b6 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:26:14 -0700 Subject: [PATCH 4/9] Minor formatting --- tests/python/unit/test_pb.py | 81 ++++++++++++------------------------ 1 file changed, 26 insertions(+), 55 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 4802ed3e7..06356665f 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -33,7 +33,7 @@ def fixture_progress_bars(console): manager._main.stop() -class DummyTask: +class _DummyTask: """Lightweight object exposing attributes used by rich tasks""" def __init__( @@ -66,7 +66,7 @@ def test_time_elapsed_column_handles_missing_elapsed(): """Render placeholder when elapsed time is missing""" column = _TimeElapsedColumn() - task = DummyTask() + task = _DummyTask() text = column.render(task) @@ -77,7 +77,7 @@ def test_time_elapsed_column_uses_finished_time(): """Render finished time when task completes""" column = _TimeElapsedColumn() - task = DummyTask(finished=True, finished_time=125.7) + task = _DummyTask(finished=True, finished_time=125.7) text = column.render(task) @@ -88,7 +88,7 @@ def test_m_of_n_complete_column_with_total_known(): """Display counts when total is known""" column = _MofNCompleteColumn(style="green") - task = DummyTask(completed=5, total=42) + task = _DummyTask(completed=5, total=42) text = column.render(task) @@ -99,7 +99,7 @@ def test_m_of_n_complete_column_with_unknown_total(): """Display counts when total is unknown""" column = _MofNCompleteColumn() - task = DummyTask(completed=7) + task = _DummyTask(completed=7) text = column.render(task) @@ -111,8 +111,8 @@ def test_total_cost_column_with_and_without_cost(): column = _TotalCostColumn() - zero_text = column.render(DummyTask(fields={"total_cost": 0})) - cost_text = column.render(DummyTask(fields={"total_cost": 3.456})) + zero_text = column.render(_DummyTask(fields={"total_cost": 0})) + cost_text = column.render(_DummyTask(fields={"total_cost": 3.456})) assert_text(zero_text, "") assert_text(cost_text, "($3.46)") @@ -295,8 +295,7 @@ def test_jurisdiction_sub_prog_bar_without_parent(progress_bars): @pytest.mark.asyncio() async def test_file_download_prog_bar_async_lifecycle( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Drive async lifecycle for download progress bar""" @@ -326,8 +325,7 @@ async def fake_sleep(duration): @pytest.mark.asyncio() async def test_file_download_prog_bar_positions_after_jurisdiction( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Insert download progress immediately after jurisdiction bar""" @@ -336,8 +334,7 @@ async def test_file_download_prog_bar_positions_after_jurisdiction( with progress_bars.jurisdiction_prog_bar("Poland"): async with progress_bars.file_download_prog_bar( - "Poland", - num_downloads=1, + "Poland", num_downloads=1 ) as dl_pb: jd_index = progress_bars.group.renderables.index( progress_bars._jd_pbs["Poland"] @@ -352,8 +349,7 @@ async def test_file_download_prog_bar_positions_after_jurisdiction( @pytest.mark.asyncio() async def test_start_file_download_prog_bar_duplicate( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Prevent duplicate download progress bars""" @@ -371,10 +367,7 @@ async def fake_sleep(_): progress_bars._dl_tasks["France"] = dl_pb.add_task("extra") await progress_bars.tear_down_file_download_prog_bar( - "France", - 1, - dl_pb, - task, + "France", 1, dl_pb, task ) assert "France" not in progress_bars._dl_pbs @@ -403,8 +396,7 @@ async def test_website_crawl_prog_bar(progress_bars, monkeypatch): progress_bars.create_main_task(1) async with progress_bars.website_crawl_prog_bar( - "Germany", - num_pages=3, + "Germany", num_pages=3 ) as wc_pb: progress_bars.update_website_crawl_doc_found("Germany") progress_bars.update_website_crawl_doc_found("Germany") @@ -417,8 +409,7 @@ async def test_website_crawl_prog_bar(progress_bars, monkeypatch): @pytest.mark.asyncio() async def test_website_crawl_prog_bar_positions_after_jurisdiction( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Insert website crawl progress immediately after jurisdiction bar""" @@ -427,8 +418,7 @@ async def test_website_crawl_prog_bar_positions_after_jurisdiction( with progress_bars.jurisdiction_prog_bar("Poland"): async with progress_bars.website_crawl_prog_bar( - "Poland", - num_pages=1, + "Poland", num_pages=1 ) as wc_pb: jd_index = progress_bars.group.renderables.index( progress_bars._jd_pbs["Poland"] @@ -444,8 +434,7 @@ async def test_website_crawl_prog_bar_positions_after_jurisdiction( @pytest.mark.asyncio() async def test_file_download_prog_bar_positions_without_jurisdiction( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Place download progress at end when no jurisdiction bar exists""" @@ -456,32 +445,24 @@ async def test_file_download_prog_bar_positions_without_jurisdiction( assert progress_bars.group.renderables[-1] is dl_pb await progress_bars.tear_down_file_download_prog_bar( - "Greece", - 2, - dl_pb, - task, + "Greece", 2, dl_pb, task ) assert calls_getter() == [1] @pytest.mark.asyncio() -async def test_website_crawl_prog_bar_duplicate( - progress_bars, - monkeypatch, -): +async def test_website_crawl_prog_bar_duplicate(progress_bars, monkeypatch): """Prevent duplicate website crawl progress bars""" _patch_sleep(monkeypatch) async with progress_bars.website_crawl_prog_bar( - "Italy", - num_pages=1, + "Italy", num_pages=1 ) as wc_pb: with pytest.raises(COMPASSValueError): async with progress_bars.website_crawl_prog_bar( - "Italy", - num_pages=1, + "Italy", num_pages=1 ): pass @@ -491,10 +472,7 @@ async def test_website_crawl_prog_bar_duplicate( @pytest.mark.asyncio() -async def test_compass_website_crawl_prog_bar( - progress_bars, - monkeypatch, -): +async def test_compass_website_crawl_prog_bar(progress_bars, monkeypatch): """Drive async lifecycle for compass crawl progress bar""" calls_getter = _patch_sleep(monkeypatch) @@ -507,10 +485,7 @@ async def test_compass_website_crawl_prog_bar( ) as cwc_pb: progress_bars.update_compass_website_crawl_doc_found("Hungary") progress_bars.update_compass_website_crawl_doc_found("Hungary") - progress_bars.update_compass_website_crawl_task( - "Hungary", - completed=1, - ) + progress_bars.update_compass_website_crawl_task("Hungary", completed=1) progress_bars._cwc_tasks["Hungary"] = cwc_pb.add_task("extra") assert "Hungary" not in progress_bars._cwc_pbs @@ -519,8 +494,7 @@ async def test_compass_website_crawl_prog_bar( @pytest.mark.asyncio() async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Insert compass crawl progress immediately after jurisdiction bar""" @@ -529,8 +503,7 @@ async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( with progress_bars.jurisdiction_prog_bar("Poland"): async with progress_bars.compass_website_crawl_prog_bar( - "Poland", - num_pages=1, + "Poland", num_pages=1 ) as cwc_pb: jd_index = progress_bars.group.renderables.index( progress_bars._jd_pbs["Poland"] @@ -546,8 +519,7 @@ async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( @pytest.mark.asyncio() async def test_compass_website_crawl_prog_bar_duplicate( - progress_bars, - monkeypatch, + progress_bars, monkeypatch ): """Prevent duplicate compass crawl progress bars""" @@ -559,8 +531,7 @@ async def test_compass_website_crawl_prog_bar_duplicate( ) as cwc_pb: with pytest.raises(COMPASSValueError): async with progress_bars.compass_website_crawl_prog_bar( - "Iceland", - num_pages=1, + "Iceland", num_pages=1 ): pass From 2ae14f6aea38dd5a7cd4fb04a8a2a079ce03a49b Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:28:29 -0700 Subject: [PATCH 5/9] More formatting --- tests/python/unit/test_pb.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 06356665f..7bd9e3248 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -56,12 +56,6 @@ def __init__( self.description = description -def assert_text(text, expected): - """Compare Text objects using their plain representation""" - - assert text.plain == expected - - def test_time_elapsed_column_handles_missing_elapsed(): """Render placeholder when elapsed time is missing""" @@ -69,8 +63,7 @@ def test_time_elapsed_column_handles_missing_elapsed(): task = _DummyTask() text = column.render(task) - - assert_text(text, "[-:--:--]") + assert text.plain == "[-:--:--]" def test_time_elapsed_column_uses_finished_time(): @@ -80,8 +73,7 @@ def test_time_elapsed_column_uses_finished_time(): task = _DummyTask(finished=True, finished_time=125.7) text = column.render(task) - - assert_text(text, "[0:02:05]") + assert text.plain == "[0:02:05]" def test_m_of_n_complete_column_with_total_known(): @@ -91,8 +83,7 @@ def test_m_of_n_complete_column_with_total_known(): task = _DummyTask(completed=5, total=42) text = column.render(task) - - assert_text(text, " 5/42") + assert text.plain == " 5/42" def test_m_of_n_complete_column_with_unknown_total(): @@ -102,8 +93,7 @@ def test_m_of_n_complete_column_with_unknown_total(): task = _DummyTask(completed=7) text = column.render(task) - - assert_text(text, " 7/?") + assert text.plain == " 7/?" def test_total_cost_column_with_and_without_cost(): @@ -114,8 +104,8 @@ def test_total_cost_column_with_and_without_cost(): zero_text = column.render(_DummyTask(fields={"total_cost": 0})) cost_text = column.render(_DummyTask(fields={"total_cost": 3.456})) - assert_text(zero_text, "") - assert_text(cost_text, "($3.46)") + assert not zero_text.plain + assert cost_text.plain == "($3.46)" def test_group_property_returns_group(progress_bars): @@ -311,8 +301,7 @@ async def fake_sleep(duration): progress_bars.create_main_task(1) async with progress_bars.file_download_prog_bar( - "Finland", - num_downloads=2, + "Finland", num_downloads=2 ) as dl_pb: dl_task = progress_bars._dl_tasks["Finland"] dl_pb.advance(dl_task) From 8d912cf8973a9780d35dcddaebd1a975f85c6778 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:58:51 -0700 Subject: [PATCH 6/9] Formatting --- tests/python/unit/test_pb.py | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 7bd9e3248..8deb0ba85 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -20,17 +20,17 @@ @pytest.fixture(name="console") def fixture_console(): """Console directed to an in-memory buffer for deterministic tests""" - return Console(file=StringIO(), color_system=None, force_terminal=False) @pytest.fixture(name="progress_bars") def fixture_progress_bars(console): """Fresh progress bar manager for each test""" - manager = _COMPASSProgressBars(console=console) - yield manager - manager._main.stop() + try: + yield manager + finally: + manager._main.stop() class _DummyTask: @@ -58,7 +58,6 @@ def __init__( def test_time_elapsed_column_handles_missing_elapsed(): """Render placeholder when elapsed time is missing""" - column = _TimeElapsedColumn() task = _DummyTask() @@ -68,7 +67,6 @@ def test_time_elapsed_column_handles_missing_elapsed(): def test_time_elapsed_column_uses_finished_time(): """Render finished time when task completes""" - column = _TimeElapsedColumn() task = _DummyTask(finished=True, finished_time=125.7) @@ -78,7 +76,6 @@ def test_time_elapsed_column_uses_finished_time(): def test_m_of_n_complete_column_with_total_known(): """Display counts when total is known""" - column = _MofNCompleteColumn(style="green") task = _DummyTask(completed=5, total=42) @@ -98,7 +95,6 @@ def test_m_of_n_complete_column_with_unknown_total(): def test_total_cost_column_with_and_without_cost(): """Show cost text only when present""" - column = _TotalCostColumn() zero_text = column.render(_DummyTask(fields={"total_cost": 0})) @@ -110,13 +106,11 @@ def test_total_cost_column_with_and_without_cost(): def test_group_property_returns_group(progress_bars): """Expose default progress group""" - assert progress_bars.group.renderables == [progress_bars._main] def test_create_main_task_single_and_duplicate_error(console): """Guard against duplicate main tasks""" - bars = _COMPASSProgressBars(console=console) bars.create_main_task(1) @@ -131,7 +125,6 @@ def test_create_main_task_single_and_duplicate_error(console): def test_create_main_task_multiple(progress_bars): """Format description for multiple jurisdictions""" - progress_bars.create_main_task(3) task = progress_bars._main.tasks[progress_bars._main_task] @@ -147,9 +140,7 @@ def test_progress_main_task_requires_initialization(progress_bars): def test_progress_main_task_advances(progress_bars): """Advance main task increments progress""" - progress_bars.create_main_task(2) - progress_bars.progress_main_task() task = progress_bars._main.tasks[progress_bars._main_task] @@ -158,7 +149,6 @@ def test_progress_main_task_advances(progress_bars): def test_update_total_cost_handles_add_and_replace(progress_bars): """Handle cost updates for add and replace paths""" - progress_bars.create_main_task(1) progress_bars.update_total_cost(1.25) @@ -176,14 +166,12 @@ def test_update_total_cost_handles_add_and_replace(progress_bars): def test_update_total_cost_without_main(progress_bars): """Track cost updates without main task""" - progress_bars.update_total_cost(2.0) assert progress_bars._total_cost == pytest.approx(2.0) def test_jurisdiction_prog_bar_lifecycle(progress_bars): """Manage lifecycle for jurisdiction bars""" - progress_bars.create_main_task(1) with progress_bars.jurisdiction_prog_bar("Denmark") as jd_pb: @@ -208,7 +196,6 @@ def enter_duplicate(): def test_jurisdiction_prog_bar_without_progress_main(progress_bars): """Skip main progress when requested""" - progress_bars.create_main_task(1) with progress_bars.jurisdiction_prog_bar("Spain", progress_main=False): @@ -220,7 +207,6 @@ def test_jurisdiction_prog_bar_without_progress_main(progress_bars): def test_jurisdiction_sub_prog_inserts_after_parent(progress_bars): """Insert sub progress after parent bar""" - progress_bars.create_main_task(1) with ExitStack() as stack: @@ -249,7 +235,6 @@ def test_jurisdiction_sub_prog_without_parent(progress_bars): def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars): """Update jurisdiction sub progress fields""" - progress_bars.create_main_task(1) with ExitStack() as stack: @@ -270,7 +255,6 @@ def test_jurisdiction_sub_prog_bar_updates_fields(progress_bars): def test_jurisdiction_sub_prog_bar_without_parent(progress_bars): """Place sub progress bar at end when no parent exists""" - start_len = len(progress_bars.group.renderables) with progress_bars.jurisdiction_sub_prog_bar("Portugal") as sub_pb: @@ -288,7 +272,6 @@ async def test_file_download_prog_bar_async_lifecycle( progress_bars, monkeypatch ): """Drive async lifecycle for download progress bar""" - calls = [] original_sleep = pb_module.asyncio.sleep @@ -317,7 +300,6 @@ async def test_file_download_prog_bar_positions_after_jurisdiction( progress_bars, monkeypatch ): """Insert download progress immediately after jurisdiction bar""" - _patch_sleep(monkeypatch) progress_bars.create_main_task(1) @@ -341,7 +323,6 @@ async def test_start_file_download_prog_bar_duplicate( progress_bars, monkeypatch ): """Prevent duplicate download progress bars""" - original_sleep = pb_module.asyncio.sleep async def fake_sleep(_): @@ -364,7 +345,6 @@ async def fake_sleep(_): def _patch_sleep(monkeypatch): """Patch asyncio.sleep and capture durations""" - calls = [] original_sleep = pb_module.asyncio.sleep @@ -379,7 +359,6 @@ async def fake_sleep(duration): @pytest.mark.asyncio() async def test_website_crawl_prog_bar(progress_bars, monkeypatch): """Drive async lifecycle for website crawl progress bar""" - calls_getter = _patch_sleep(monkeypatch) progress_bars.create_main_task(1) @@ -401,7 +380,6 @@ async def test_website_crawl_prog_bar_positions_after_jurisdiction( progress_bars, monkeypatch ): """Insert website crawl progress immediately after jurisdiction bar""" - calls_getter = _patch_sleep(monkeypatch) progress_bars.create_main_task(1) @@ -426,7 +404,6 @@ async def test_file_download_prog_bar_positions_without_jurisdiction( progress_bars, monkeypatch ): """Place download progress at end when no jurisdiction bar exists""" - calls_getter = _patch_sleep(monkeypatch) dl_pb, task = progress_bars.start_file_download_prog_bar("Greece", 2) @@ -443,7 +420,6 @@ async def test_file_download_prog_bar_positions_without_jurisdiction( @pytest.mark.asyncio() async def test_website_crawl_prog_bar_duplicate(progress_bars, monkeypatch): """Prevent duplicate website crawl progress bars""" - _patch_sleep(monkeypatch) async with progress_bars.website_crawl_prog_bar( @@ -463,7 +439,6 @@ async def test_website_crawl_prog_bar_duplicate(progress_bars, monkeypatch): @pytest.mark.asyncio() async def test_compass_website_crawl_prog_bar(progress_bars, monkeypatch): """Drive async lifecycle for compass crawl progress bar""" - calls_getter = _patch_sleep(monkeypatch) progress_bars.create_main_task(1) @@ -486,7 +461,6 @@ async def test_compass_website_crawl_prog_bar_positions_after_jurisdiction( progress_bars, monkeypatch ): """Insert compass crawl progress immediately after jurisdiction bar""" - calls_getter = _patch_sleep(monkeypatch) progress_bars.create_main_task(1) @@ -511,7 +485,6 @@ async def test_compass_website_crawl_prog_bar_duplicate( progress_bars, monkeypatch ): """Prevent duplicate compass crawl progress bars""" - _patch_sleep(monkeypatch) async with progress_bars.compass_website_crawl_prog_bar( From 677a9b234016b7c1ac2272743454e241c3da741d Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 19:59:36 -0700 Subject: [PATCH 7/9] Rename fixtures --- tests/python/unit/test_pb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 8deb0ba85..32493d3f5 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -17,14 +17,14 @@ ) -@pytest.fixture(name="console") -def fixture_console(): +@pytest.fixture +def console(): """Console directed to an in-memory buffer for deterministic tests""" return Console(file=StringIO(), color_system=None, force_terminal=False) -@pytest.fixture(name="progress_bars") -def fixture_progress_bars(console): +@pytest.fixture +def progress_bars(console): """Fresh progress bar manager for each test""" manager = _COMPASSProgressBars(console=console) try: From 62b9e1daf2ca4610943b643ed3a1c24ff840409c Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 20:01:45 -0700 Subject: [PATCH 8/9] Update style --- tests/python/unit/test_pb.py | 39 ++++++++++++++---------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index 32493d3f5..a4bd0e1e9 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -6,15 +6,8 @@ import pytest from rich.console import Console -from compass import pb as pb_module +import compass.pb from compass.exceptions import COMPASSNotInitializedError, COMPASSValueError -from compass.pb import ( - COMPASS_PB, - _COMPASSProgressBars, - _MofNCompleteColumn, - _TimeElapsedColumn, - _TotalCostColumn, -) @pytest.fixture @@ -26,7 +19,7 @@ def console(): @pytest.fixture def progress_bars(console): """Fresh progress bar manager for each test""" - manager = _COMPASSProgressBars(console=console) + manager = compass.pb._COMPASSProgressBars(console=console) try: yield manager finally: @@ -58,7 +51,7 @@ def __init__( def test_time_elapsed_column_handles_missing_elapsed(): """Render placeholder when elapsed time is missing""" - column = _TimeElapsedColumn() + column = compass.pb._TimeElapsedColumn() task = _DummyTask() text = column.render(task) @@ -67,7 +60,7 @@ def test_time_elapsed_column_handles_missing_elapsed(): def test_time_elapsed_column_uses_finished_time(): """Render finished time when task completes""" - column = _TimeElapsedColumn() + column = compass.pb._TimeElapsedColumn() task = _DummyTask(finished=True, finished_time=125.7) text = column.render(task) @@ -76,7 +69,7 @@ def test_time_elapsed_column_uses_finished_time(): def test_m_of_n_complete_column_with_total_known(): """Display counts when total is known""" - column = _MofNCompleteColumn(style="green") + column = compass.pb._MofNCompleteColumn(style="green") task = _DummyTask(completed=5, total=42) text = column.render(task) @@ -86,7 +79,7 @@ def test_m_of_n_complete_column_with_total_known(): def test_m_of_n_complete_column_with_unknown_total(): """Display counts when total is unknown""" - column = _MofNCompleteColumn() + column = compass.pb._MofNCompleteColumn() task = _DummyTask(completed=7) text = column.render(task) @@ -95,7 +88,7 @@ def test_m_of_n_complete_column_with_unknown_total(): def test_total_cost_column_with_and_without_cost(): """Show cost text only when present""" - column = _TotalCostColumn() + column = compass.pb._TotalCostColumn() zero_text = column.render(_DummyTask(fields={"total_cost": 0})) cost_text = column.render(_DummyTask(fields={"total_cost": 3.456})) @@ -111,7 +104,7 @@ def test_group_property_returns_group(progress_bars): def test_create_main_task_single_and_duplicate_error(console): """Guard against duplicate main tasks""" - bars = _COMPASSProgressBars(console=console) + bars = compass.pb._COMPASSProgressBars(console=console) bars.create_main_task(1) task = bars._main.tasks[bars._main_task] @@ -273,13 +266,13 @@ async def test_file_download_prog_bar_async_lifecycle( ): """Drive async lifecycle for download progress bar""" calls = [] - original_sleep = pb_module.asyncio.sleep + original_sleep = compass.pb.asyncio.sleep async def fake_sleep(duration): calls.append(duration) await original_sleep(0) - monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) + monkeypatch.setattr(compass.pb.asyncio, "sleep", fake_sleep) progress_bars.create_main_task(1) @@ -323,12 +316,12 @@ async def test_start_file_download_prog_bar_duplicate( progress_bars, monkeypatch ): """Prevent duplicate download progress bars""" - original_sleep = pb_module.asyncio.sleep + original_sleep = compass.pb.asyncio.sleep async def fake_sleep(_): await original_sleep(0) - monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) + monkeypatch.setattr(compass.pb.asyncio, "sleep", fake_sleep) dl_pb, task = progress_bars.start_file_download_prog_bar("France", 1) @@ -346,13 +339,13 @@ async def fake_sleep(_): def _patch_sleep(monkeypatch): """Patch asyncio.sleep and capture durations""" calls = [] - original_sleep = pb_module.asyncio.sleep + original_sleep = compass.pb.asyncio.sleep async def fake_sleep(duration): calls.append(duration) await original_sleep(0) - monkeypatch.setattr(pb_module.asyncio, "sleep", fake_sleep) + monkeypatch.setattr(compass.pb.asyncio, "sleep", fake_sleep) return lambda: calls @@ -504,6 +497,4 @@ async def test_compass_website_crawl_prog_bar_duplicate( def test_singleton_instance_accessible(console): """Expose singleton progress bar instance""" - - assert isinstance(COMPASS_PB, _COMPASSProgressBars) - COMPASS_PB.console = console + assert isinstance(compass.pb.COMPASS_PB, compass.pb._COMPASSProgressBars) From d3c2d848a0132ce1eb08208b355ba9f50b2f54d5 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sat, 8 Nov 2025 20:03:10 -0700 Subject: [PATCH 9/9] Minor update --- tests/python/unit/test_pb.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/python/unit/test_pb.py b/tests/python/unit/test_pb.py index a4bd0e1e9..af0ed08a6 100644 --- a/tests/python/unit/test_pb.py +++ b/tests/python/unit/test_pb.py @@ -209,8 +209,9 @@ def test_jurisdiction_sub_prog_inserts_after_parent(progress_bars): ) assert sub_pb in progress_bars.group.renderables - renderables = progress_bars.group.renderables - assert not any("Sweden" in str(item) for item in renderables) + assert not any( + "Sweden" in str(item) for item in progress_bars.group.renderables + ) def test_jurisdiction_sub_prog_without_parent(progress_bars):