Skip to content

Assertions

Voci vendors pytest's assertion rewriter, so a plain assert statements are explained in case of a failure.

Utilities for capturing exceptions and approximate comparisons are available:

Capturing exceptions

voci.raises

raises(
    expected: type[E] | tuple[type[E], ...],
    *,
    match: str | Pattern[str] | None = None,
) -> RaisesContext[E]
raises(
    expected: type[E] | tuple[type[E], ...],
    func: Callable[..., object],
    *args: Any,
    match: str | Pattern[str] | None = None,
    **kwargs: Any,
) -> ExceptionInfo[E]
raises(expected, func=None, *args, match=None, **kwargs)

Assert that expected is raised, optionally with a message matching match.

Used as a context manager, raises returns a RaisesContext whose __enter__ hands back an ExceptionInfo, populated once the block exits. Given a second positional argument, it instead calls func(*args, **kwargs) under the same machinery and returns the ExceptionInfo directly; a non-callable func raises TypeError.

match always matches against the raised exception, in both forms — it is never one of func's **kwargs, so a call means the same thing regardless of which form invoked it. It is an re.search rather than a full match, so regex metacharacters in an otherwise literal message need escaping.

An expected that would catch asyncio.CancelledError raises TypeError: voci enforces test timeouts by cancellation, and a block that swallowed it would make that test un-timeout-able.

voci.ExceptionInfo

ExceptionInfo()

Handle on the exception a raises block caught. Populated on block exit.

traceback property

traceback: TracebackType | None

The caught exception's traceback.

type property

type: type[E]

The caught exception's class.

value property

value: E

The caught exception. Reading it before the block exits raises RuntimeError.

match

match(pattern: str | Pattern[str]) -> bool

re.search pattern against the string form of the exception.

Returns True, or raises AssertionError if the pattern does not match.

Approximate comparisons

voci.approx

approx(
    expected: ApproxExpected,
    *,
    rel: float | None = None,
    abs: float | None = None,
    nan_ok: bool = False,
) -> Approx

A tolerant stand-in for expected in an ==: assert value == voci.approx(0.3).

expected is a number, or a list, tuple, or dict of numbers compared elementwise under the same tolerances. A set raises TypeError, as does a container nested inside a list, tuple, or dict.

The default tolerances are rel=1e-6 and abs=1e-12, whichever is looser. Naming abs alone applies the absolute tolerance only; naming rel alone keeps the default absolute tolerance underneath it, which is what makes a comparison against zero work. Two NaNs compare equal only under nan_ok=True.

voci.Approx

Approx(
    expected: ApproxExpected,
    *,
    rel: float | None,
    abs: float | None,
    nan_ok: bool,
)

Tolerant numeric comparison. Compare with == in either direction.

A list or tuple compares elementwise by position and a dict compares elementwise by key, both under the same rel/abs/nan_ok tolerances applied to every element. A list, tuple, dict, or set nested inside a list, tuple, or dict raises TypeError, since approx only walks one level, and so does a set at the top level: there is no position to compare it by.