Skip to content

Commit 4d3efd1

Browse files
committed
test(schema): name the field when _splitters can't reach it in FULL
A pattern constraint on a field FULL omits made _splitters raise a bare KeyError out of _get, since it read the path unguarded. test_the_fixture_reaches_every_pattern_in_the_schema already catches the same reachability gap cleanly and by field name via _reachable; this was the other place reading an arbitrary schema path out of FULL, and it failed worse when it hit the same gap. _splitters now checks reachability first and raises LookupError naming the field, and test_every_pattern_is_mirrored_or_split_or_declared catches that and reports it alongside every other unaccounted pattern instead of aborting the run. test_a_missing_path_fails_with_the_field_name_not_a_keyerror covers it directly. Signed-off-by: chernistry <sanderchernitsky@gmail.com>
1 parent e5f6cdb commit 4d3efd1

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

tests/test_the_schema_and_the_models_agree.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,18 @@ def _probes(pattern: str, valid: str) -> list[str]:
341341

342342

343343
def _splitters(path: tuple[str, ...], pattern: str) -> list[tuple[str, bool, bool]]:
344-
"""Probes at *path* the two validators disagree about."""
344+
"""Probes at *path* the two validators disagree about.
345+
346+
Raises ``LookupError`` naming *path* when ``FULL`` does not reach it, rather than
347+
letting the plain ``KeyError`` out of ``_get`` propagate. This is the same gap
348+
``test_the_fixture_reaches_every_pattern_in_the_schema`` already reports by field
349+
name via ``_reachable``; this read the path unguarded.
350+
"""
351+
if not _reachable(FULL, path):
352+
raise LookupError(
353+
f"{'.'.join(path)}: pattern {pattern!r} constrains a path FULL does not "
354+
"reach, so nothing here can probe it"
355+
)
345356
valid = _get(FULL, path)
346357
split: list[tuple[str, bool, bool]] = []
347358
for probe in _probes(pattern, valid):
@@ -534,7 +545,11 @@ def _unaccounted_patterns(
534545
dotted = ".".join(path)
535546
if model_field_patterns.get(path) == pattern:
536547
continue
537-
split = _splitters(path, pattern)
548+
try:
549+
split = _splitters(path, pattern)
550+
except LookupError as exc:
551+
unaccounted.append(str(exc))
552+
continue
538553
declared = [s for s in split if (dotted, repr(s[0])[:26]) in DECLARED_DIVERGENCES]
539554
if split and len(declared) == len(split):
540555
continue
@@ -642,3 +657,26 @@ def test_the_mirror_check_is_by_field_not_flat_membership() -> None:
642657
"must be flagged, even though the pattern string itself is genuinely in use "
643658
"elsewhere in the model:\n" + "\n".join(unaccounted)
644659
)
660+
661+
662+
def test_a_missing_path_fails_with_the_field_name_not_a_keyerror() -> None:
663+
"""Review counterfactual: a pattern on a field ``FULL`` omits must fail naming
664+
that field, not with a raw ``KeyError`` out of ``_get``.
665+
666+
``test_the_fixture_reaches_every_pattern_in_the_schema`` already catches the same
667+
reachability gap cleanly, by field name, via ``_reachable``. ``_splitters`` is the
668+
other place that reads an arbitrary schema path out of ``FULL``, and it read the
669+
path unguarded, so the same gap surfaced there as a bare ``KeyError`` instead.
670+
"""
671+
bogus_path = ("build_provenance", "does_not_exist_in_full")
672+
assert not _reachable(FULL, bogus_path), "setup: the path must genuinely be absent from FULL"
673+
674+
with pytest.raises(Exception) as excinfo:
675+
_splitters(bogus_path, "^irrelevant$")
676+
677+
assert not isinstance(excinfo.value, KeyError), (
678+
f"a missing path must not surface as a raw KeyError: {excinfo.value!r}"
679+
)
680+
assert "build_provenance.does_not_exist_in_full" in str(excinfo.value), (
681+
f"the failure must name the missing field; got {excinfo.value!r}"
682+
)

0 commit comments

Comments
 (0)