"""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 `` 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"" __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