checks / unit (pull_request) Successful in 8m44s
Checks and prints that indexed an empty list, exhausted next(), or formatted None killed the rest of their file (FCST-06). Read them through the new named_absence.py (nth/first/field/given/present) and conjoin a presence term. - every site in the brief, plus the family the new scan and a sweep found - test_named_absence.py: scans every test_*.py for unguarded filtered-list indexing, next() without a default and numeric formats on maybe-None names; proven to bite; prints what it cannot see, counted - test_price.py 16a: the `_T17_CAPS is _T17_CAPS` tautology now grades the two assemble() calls' arguments - test_control.py: coverage table re-measured on runs graded to the end Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
100 lines
2.6 KiB
Python
100 lines
2.6 KiB
Python
"""Read a value a check prints or grades without raising (TEST-26).
|
|
|
|
Each test file is one script, so an IndexError in a print or a check name
|
|
kills every check after it (MUTATION.md, FCST-06). Read through these instead,
|
|
and conjoin `present(x)` in the check so the absence grades as a named FAIL.
|
|
|
|
`ABSENT` values never raise: they format as `<ABSENT ...>` under any spec,
|
|
index and attribute to themselves, compare unequal AND not-unequal, and are
|
|
falsy. `not x`, `"a" not in x` and `all(... for _ in x)` are therefore TRUE of
|
|
one, which is why the check needs the `present()` term. `int()`, `range()` and
|
|
use as a list index still raise: guard those with `present()`.
|
|
"""
|
|
|
|
_NAN = float("nan")
|
|
|
|
|
|
class Absent:
|
|
__slots__ = ("what",)
|
|
|
|
def __init__(self, what):
|
|
object.__setattr__(self, "what", what)
|
|
|
|
def __repr__(self):
|
|
return f"<ABSENT {self.what}>"
|
|
|
|
__str__ = __repr__
|
|
|
|
def __format__(self, spec):
|
|
return repr(self)
|
|
|
|
def __bool__(self):
|
|
return False
|
|
|
|
def __eq__(self, other):
|
|
return False
|
|
|
|
__ne__ = __lt__ = __le__ = __gt__ = __ge__ = __eq__
|
|
|
|
def __hash__(self):
|
|
return id(self)
|
|
|
|
def __getitem__(self, _):
|
|
return self
|
|
|
|
def __getattr__(self, _):
|
|
return self
|
|
|
|
def __call__(self, *_a, **_k):
|
|
return self
|
|
|
|
def __len__(self):
|
|
return 0
|
|
|
|
def __iter__(self):
|
|
return iter(())
|
|
|
|
def __contains__(self, _):
|
|
return False
|
|
|
|
def __float__(self):
|
|
return _NAN
|
|
|
|
def _same(self, *_):
|
|
return self
|
|
|
|
__add__ = __radd__ = __sub__ = __rsub__ = __mul__ = __rmul__ = _same
|
|
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = _same
|
|
__mod__ = __rmod__ = __neg__ = __pos__ = __abs__ = __round__ = _same
|
|
|
|
|
|
def present(*xs):
|
|
"""True when none of `xs` is an ABSENT stand-in."""
|
|
return not any(isinstance(x, Absent) for x in xs)
|
|
|
|
|
|
def nth(seq, i=0, what=None):
|
|
"""`seq[i]`, or an ABSENT saying how many items there were."""
|
|
n = 0 if seq is None else len(seq)
|
|
if -n <= i < n:
|
|
return seq[i]
|
|
return Absent(what or f"[{i}] of {n} item(s)")
|
|
|
|
|
|
def first(it, what="no match"):
|
|
"""`next(it)`, or ABSENT when it is exhausted."""
|
|
return next(iter(it), Absent(what))
|
|
|
|
|
|
def field(mapping, key, what=None):
|
|
"""`mapping[key]`, or ABSENT when the key (or the mapping) is missing."""
|
|
try:
|
|
return mapping[key]
|
|
except (KeyError, IndexError, TypeError):
|
|
return Absent(what or f"key {key!r}")
|
|
|
|
|
|
def given(x, what="None"):
|
|
"""`x`, or ABSENT when it is None - so `:.2f` and arithmetic cannot raise."""
|
|
return Absent(what) if x is None else x
|