feat(ebook-search): implement async file path resolution and EPUB discovery

This commit is contained in:
2026-07-24 11:38:51 -04:00
parent 8073144e2b
commit 6a0e71a30d
2 changed files with 57 additions and 22 deletions
+34 -1
View File
@@ -27,7 +27,13 @@ from python.ebook_search.bm25_corpus import (
)
from python.ebook_search.config import EbookSearchConfig, RerankConfig, load_config
from python.ebook_search.embeddings import MODEL_DIMENSIONS, ensure_embedding_models
from python.ebook_search.ingest import chunk_text, find_existing_source
from python.ebook_search.ingest import (
chunk_text,
find_existing_source,
find_library_epubs,
resolve_ingest_path,
sha256_file,
)
from python.ebook_search.search import (
SearchResponse,
SearchResult,
@@ -106,6 +112,33 @@ async def test_find_existing_source_matches_path_or_hash() -> None:
assert await find_existing_source(session, Path("/new/book.epub"), "a" * 64) == source
async def test_async_ingest_path_resolution_and_hashing(tmp_path: Path) -> None:
"""Ingest file metadata uses AnyIO's asynchronous path operations."""
path = tmp_path / "book.epub"
path.write_bytes(b"epub content")
resolved_path = await resolve_ingest_path(path)
assert resolved_path == await resolved_path.resolve()
assert await sha256_file(resolved_path) == "4b71fc6fc452ae1ff7832bfe374ae56ab4d0649acf6af8ab4d068d858ea60448"
async def test_find_library_epubs_uses_async_path_walk(tmp_path: Path) -> None:
"""Library discovery finds EPUB files through AnyIO's async path API."""
(tmp_path / "nested").mkdir()
first_epub = tmp_path / "first.epub"
second_epub = tmp_path / "nested" / "second.epub"
first_epub.write_bytes(b"first")
second_epub.write_bytes(b"second")
(tmp_path / "not-a-book.txt").write_text("ignore", encoding="utf-8")
path, epub_paths = await find_library_epubs(str(tmp_path))
assert str(path) == str(tmp_path)
assert epub_paths is not None
assert [str(epub_path) for epub_path in epub_paths] == [str(first_epub), str(second_epub)]
async def test_bm25_corpus_uses_existing_search_text_without_duplicate_metadata() -> None:
engine = await build_async_engine()
async with AsyncSession(engine, expire_on_commit=False) as session: