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:
@@ -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
|
||||
|
||||
@@ -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")])
|
||||
Reference in New Issue
Block a user