feat: catalog-level validate_catalog + index_by_id (unique ids)

Per sub-project-2 plan Task 2 / spec §3. Purely additive to hef.catalog;
no existing symbol changes. validate_catalog runs per-record validate() then
asserts id uniqueness; index_by_id gives by-id lookup the player also wants.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-06-04 06:23:01 -07:00
parent db4f036729
commit b6fb635ef4
2 changed files with 65 additions and 0 deletions
+17
View File
@@ -126,3 +126,20 @@ def append_record(record, path) -> None:
path = Path(path)
with path.open("a", encoding="utf-8") as fh:
fh.write(json.dumps(record_to_dict(record), ensure_ascii=False) + "\n")
def index_by_id(records) -> dict:
"""Map id -> Record, raising CatalogError on a duplicate id."""
idx: dict = {}
for r in records:
if r.id in idx:
raise CatalogError(f"duplicate record id: {r.id!r}")
idx[r.id] = r
return idx
def validate_catalog(records) -> None:
"""Validate every record AND cross-record invariants (currently: unique ids)."""
for r in records:
validate(r)
index_by_id(records) # raises on duplicate id
+48
View File
@@ -0,0 +1,48 @@
import pytest
from hef.catalog import Record, validate_catalog, index_by_id, CatalogError
def make_record(**o):
base = dict(
id="a",
title="t",
source_url="u",
source_archive="nasa",
license="public_domain",
mode="video",
left=0,
right=0,
dark=0,
light=0,
duration_s=1,
file_path="p",
)
base.update(o)
return Record(**base)
def test_validate_catalog_accepts_unique_ids():
validate_catalog([make_record(id="a"), make_record(id="b")]) # no raise
def test_validate_catalog_rejects_duplicate_id():
with pytest.raises(CatalogError) as e:
validate_catalog([make_record(id="dup"), make_record(id="dup")])
assert "dup" in str(e.value)
def test_validate_catalog_validates_each_record():
with pytest.raises(CatalogError):
validate_catalog([make_record(left=9)])
def test_index_by_id_round_trips():
recs = [make_record(id="a"), make_record(id="b")]
idx = index_by_id(recs)
assert idx["a"].id == "a" and idx["b"].id == "b"
def test_index_by_id_rejects_duplicates():
with pytest.raises(CatalogError):
index_by_id([make_record(id="x"), make_record(id="x")])