Skip to content

Commit 2e62a44

Browse files
augustjohnsonclaude
andcommitted
fix: improve error handling in compare_srd; add count test; document missing items runner
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9c23b9a commit 2e62a44

3 files changed

Lines changed: 36 additions & 5 deletions

File tree

api_v2/management/commands/compare_srd.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import annotations
33
import os
44
import time
5+
import traceback
56
import concurrent.futures
67
from dataclasses import dataclass
78
from typing import Any
@@ -222,6 +223,8 @@ def _run_magic_item_comparison(pdf_path: str, document: str) -> ComparisonResult
222223
return compare_records("magic_items", pdf_records, db_records, SKIP_FIELDS["magic_items"])
223224

224225

226+
# "items" (adventuring gear) is not in _RUNNERS because the SRD adventuring gear
227+
# items do not have a dedicated model in api_v2 that maps cleanly to PDF records.
225228
_RUNNERS = {
226229
"spells": _run_spell_comparison,
227230
"creatures": _run_creature_comparison,
@@ -239,7 +242,10 @@ def _run_magic_item_comparison(pdf_path: str, document: str) -> ComparisonResult
239242
def _render_results(results: dict[str, ComparisonResult], elapsed: float) -> None:
240243
console = Console()
241244

242-
summary = Table(title=f"SRD 5.2 PDF vs Database (completed in {elapsed:.1f}s)")
245+
def _fmt(n):
246+
return "[green]0[/green]" if n == 0 else str(n)
247+
248+
summary = Table(title=f"SRD 5.2 PDF vs Database (completed in {elapsed:.1f}s)")
243249
summary.add_column("Entity type", style="bold")
244250
summary.add_column("In PDF", justify="right")
245251
summary.add_column("In DB", justify="right")
@@ -248,8 +254,6 @@ def _render_results(results: dict[str, ComparisonResult], elapsed: float) -> Non
248254
summary.add_column("Mismatches", justify="right")
249255

250256
for name, result in results.items():
251-
def _fmt(n):
252-
return f"[green]0[/green]" if n == 0 else str(n)
253257
summary.add_row(
254258
name,
255259
str(result.pdf_count),
@@ -328,6 +332,8 @@ def handle(self, *args, **options):
328332
start = time.monotonic()
329333
results: dict[str, ComparisonResult] = {}
330334

335+
failed: list[str] = []
336+
331337
with concurrent.futures.ThreadPoolExecutor() as executor:
332338
futures = {
333339
executor.submit(_RUNNERS[etype], pdf_path, document): etype
@@ -339,6 +345,11 @@ def handle(self, *args, **options):
339345
results[etype] = future.result()
340346
except Exception as exc:
341347
self.stderr.write(f" ERROR comparing {etype}: {exc}")
348+
traceback.print_exc()
349+
failed.append(etype)
350+
351+
if failed:
352+
raise CommandError(f"Comparisons failed for: {', '.join(failed)}")
342353

343354
elapsed = time.monotonic() - start
344355
_render_results(

api_v2/tests/test_compare_srd.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,26 @@ def test_case_insensitive_string_comparison(self):
8787
result = compare_records("spells", pdf, db, skip_fields=SKIP)
8888
assert result.mismatches == []
8989

90+
def test_pdf_and_db_counts(self):
91+
pdf = [_make_spell("Fireball"), _make_spell("Acid Arrow")]
92+
db = [
93+
{"name": "Fireball", "level": 1, "school__name": "evocation",
94+
"casting_time": "Action", "range_text": "60 feet",
95+
"verbal": True, "somatic": True, "material": False,
96+
"duration": "Instantaneous", "concentration": False, "ritual": False},
97+
{"name": "Acid Arrow", "level": 2, "school__name": "evocation",
98+
"casting_time": "Action", "range_text": "90 feet",
99+
"verbal": True, "somatic": True, "material": True,
100+
"duration": "Instantaneous", "concentration": False, "ritual": False},
101+
{"name": "Extra Spell", "level": 1, "school__name": "evocation",
102+
"casting_time": "Action", "range_text": "60 feet",
103+
"verbal": True, "somatic": True, "material": False,
104+
"duration": "Instantaneous", "concentration": False, "ritual": False},
105+
]
106+
result = compare_records("spells", pdf, db, skip_fields=SKIP)
107+
assert result.pdf_count == 2
108+
assert result.db_count == 3
109+
90110
def test_float_comparison_within_tolerance(self):
91111
"""Challenge rating 0.25 vs 0.25000001 should not mismatch."""
92112
from data.raw_sources.srd_5_2.parsers.creatures import CreatureRecord

data/raw_sources/srd_5_2/parsers/items.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def extract_weapons(full_text: str) -> list[WeaponRecord]:
171171

172172
def extract_weapons_from_pdf(pdf_path: str) -> list[WeaponRecord]:
173173
"""Extract weapons from the real SRD PDF. Raises ValueError if fewer than 30 found."""
174-
from .base import extract_full_text # avoid circular at module load time
174+
from .base import extract_full_text # deferred import
175175
full_text = extract_full_text(pdf_path)
176176
records = extract_weapons(full_text)
177177
if len(records) < 30:
@@ -286,7 +286,7 @@ def extract_armor(full_text: str) -> list[ArmorRecord]:
286286

287287
def extract_armor_from_pdf(pdf_path: str) -> list[ArmorRecord]:
288288
"""Extract armor from the real SRD PDF. Raises ValueError if fewer than 10 found."""
289-
from .base import extract_full_text # avoid circular at module load time
289+
from .base import extract_full_text # deferred import
290290
full_text = extract_full_text(pdf_path)
291291
records = extract_armor(full_text)
292292
if len(records) < 10:

0 commit comments

Comments
 (0)