From e6a833f6f5b54456f37ea47fa28f26bd36d71cfc Mon Sep 17 00:00:00 2001 From: Timothy Farrell Date: Thu, 7 May 2026 17:07:09 +0000 Subject: [PATCH] Sort path so Next is truely the alphabetical path next. --- main.py | 24 ++++++++++++++++++++---- tests/conftest.py | 1 + tests/test_navigation.py | 8 ++++---- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/main.py b/main.py index 9f32764..c66eb90 100644 --- a/main.py +++ b/main.py @@ -19,8 +19,9 @@ from fastapi.responses import ( ) app = FastAPI() -file_mapping = {} +file_mapping: dict[str, str] = {} indexers = [] +sorted_hashes: list[str] = [] class FileIndexer: @@ -164,7 +165,7 @@ INDEXER_MAP = {".zip": ZipFileIndexer} def initialize_server(args: argparse.Namespace): """Initialize the server with directory or glob indexing""" - global file_mapping, indexers + global file_mapping, indexers, sorted_hashes src_path = Path(args.source) @@ -191,6 +192,16 @@ def initialize_server(args: argparse.Namespace): print(f"Indexed {len(file_mapping)} files from {len(indexers)} source(s)") + # Build a sorted index for filename-ordered navigation + sorted_hashes = sorted( + file_mapping.keys(), + key=lambda h: ( + (indexer.get_filename_by_hash(h) or "").lower() + if (indexer := _find_indexer_for_hash(h)) + else "" + ), + ) + @app.get("/api/health") async def health_check(): @@ -283,7 +294,7 @@ def _get_navigation_data(file_hash: str, order: str | None = None): Returns: Dictionary with navigation hashes and filename. """ - keys = list(file_mapping.keys()) + keys = _get_sorted_hashes() idx = keys.index(file_hash) if order == "random": @@ -523,6 +534,11 @@ def _get_random_hash() -> str: return random.choice(keys) +def _get_sorted_hashes() -> list[str]: + """Return the cached filename-sorted hash list (built at index time).""" + return sorted_hashes + + def _get_random_navigate_path() -> str | None: """Get a random internal path from ZipFileIndexers only.""" zip_paths: list[str] = [] @@ -593,7 +609,7 @@ def _get_navigation_data_by_path( if file_hash is None: return None - keys = list(file_mapping.keys()) + keys = _get_sorted_hashes() idx = keys.index(file_hash) if order == "random": diff --git a/tests/conftest.py b/tests/conftest.py index 3686aa9..5d2d8b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,6 +16,7 @@ def _reset_state() -> None: """Reset all global state to defaults.""" main.file_mapping.clear() main.indexers.clear() + main.sorted_hashes.clear() @pytest.fixture(autouse=True) diff --git a/tests/test_navigation.py b/tests/test_navigation.py index f2e2372..c2e6ece 100644 --- a/tests/test_navigation.py +++ b/tests/test_navigation.py @@ -39,8 +39,8 @@ class TestGetNavigationData: assert data["file_hash"] == file_hash def test_sequential_next_and_prev(self, seeded_indexers: None) -> None: - """In sequential mode, next and prev are adjacent in the list.""" - keys = list(main.file_mapping.keys()) + """In sequential mode, next and prev are adjacent in filename order.""" + keys = main._get_sorted_hashes() if len(keys) < 2: pytest.skip("Need at least 2 files for sequential navigation") file_hash = keys[0] @@ -51,7 +51,7 @@ class TestGetNavigationData: def test_middle_item_navigation(self, seeded_indexers: None) -> None: """Middle item has correct prev and next.""" - keys = list(main.file_mapping.keys()) + keys = main._get_sorted_hashes() if len(keys) < 3: pytest.skip("Need at least 3 files for middle-item test") mid_idx = len(keys) // 2 @@ -62,7 +62,7 @@ class TestGetNavigationData: def test_last_item_wraps_next(self, seeded_indexers: None) -> None: """Last item's next wraps to the first item.""" - keys = list(main.file_mapping.keys()) + keys = main._get_sorted_hashes() if len(keys) < 2: pytest.skip("Need at least 2 files for wrap test") file_hash = keys[-1]