Skip to content

Core & object assertions

Assertions available on every value: equality, identity, type, None, truthiness, satisfies, structural matching, and recursive field checks. A type checker offers matches_structure() on a mapping, a model or an object, and not on a number, a string, a collection, bytes, a path or a date.

Base mixin.

described_as

described_as(description: str) -> Self

Describes the assertion. On failure, the description is included in the error message.

This is not an assertion itself. But if the any of the following chained assertions fail, the description will be included in addition to the regular error message.

Parameters:

Name Type Description Default
description str

the error message description

required

Examples:

Usage:

assert_that(1).described_as('error msg desc').is_equal_to(2)  # fails
# [error msg desc] Expected <1> to be equal to <2>, but was not.

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Source code in assertpy2/base.py
def described_as(self, description: str) -> Self:
    """Describes the assertion.  On failure, the description is included in the error message.

    This is not an assertion itself.  But if the any of the following chained assertions fail,
    the description will be included in addition to the regular error message.

    Args:
        description: the error message description

    Examples:
        Usage:

            assert_that(1).described_as('error msg desc').is_equal_to(2)  # fails
            # [error msg desc] Expected <1> to be equal to <2>, but was not.

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion
    """
    self.description: str = str(description)
    return self

is_equal_to

is_equal_to(other: object, **kwargs: object) -> Self

Asserts that val is equal to other.

Checks actual is equal to expected using the == operator. When val is dict-like or has introspectable fields (dataclass, namedtuple, attrs, Pydantic model), optionally ignore or include keys/fields when checking equality.

Parameters:

Name Type Description Default
other object

the expected value

required
**kwargs object

see below

{}

Other Parameters:

Name Type Description
ignore Hashable | list | set | frozenset | None

the key/field (or list/set/frozenset of keys/fields) to ignore. Besides exact keys and nested-path tuples, a re.Pattern matches field names by regex and a type matches fields by value type.

include Hashable | list | set | frozenset | None

the key/field (or list/set/frozenset of keys/fields) to include. Accepts the same re.Pattern / type specs as ignore. A key the value does not have fails the assertion with or without not_.

tolerance float | None

an absolute tolerance that widens == for every pair of real-number leaves anywhere in the structure: a pair == holds equal stays equal, and any other is measured as is_close_to() measures it.

comparators dict | None

a dict mapping a type or a field name to an (actual, expected) -> bool predicate that alone decides every node it matches, the root included, even inside a container whose == holds; a field-name key wins over a type key. Mapping keys, set members and whatever a container shared by both sides holds are left to ==.

ignore_null bool

when True, skip any named field the expected side leaves None (a partial expected/template), at any depth. Only the expected side is skipped, so an unexpectedly None actual field is still reported. Defaults to False.

strict_types bool

when True, both sides of every node must be the same type, at any depth. Plain == does not require this: True == 1, Decimal("1") == 1 and [True] == [1] are all true, so a boolean read from JSON compares equal to an integer without a word. Opting in also rejects pairs some callers consider equal (IntEnum against int, a dict subclass against dict, float against int), and it wins over tolerance, which says how far apart two numbers may be and not that they may be different types. A comparators entry still decides the nodes it matches ahead of it, the root included, and a Matcher on the expected side is exempt, so composed matchers keep working. Dictionary keys and set elements are covered too, although a container matches them by hash before any type is looked at: {True: "a"} against {1: "a"} and {1} against {1.0} both fail, as [True] against [1] does. Defaults to False.

Examples:

Usage:

assert_that(1 + 2).is_equal_to(3)
assert_that('foo').is_equal_to('foo')
assert_that(123).is_equal_to(123)
assert_that(123.4).is_equal_to(123.4)
assert_that(['a', 'b']).is_equal_to(['a', 'b'])
assert_that((1, 2, 3)).is_equal_to((1, 2, 3))
assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 2})
assert_that({'a', 'b'}).is_equal_to({'a', 'b'})

When the val is dict-like, keys can optionally be ignored when checking equality:

# ignore a single key
assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, ignore='b')

# ignore multiple keys
assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['b', 'c'])

# ignore nested keys
assert_that({'a': {'b': 2, 'c': 3, 'd': 4}}).is_equal_to(
    {'a': {'d': 4}}, ignore=[('a', 'b'), ('a', 'c')]
)

When the val is dict-like, only certain keys can be included when checking equality:

# include a single key
assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, include='a')

# include multiple keys
assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, include=['a', 'b'])

Works with dataclasses, namedtuples, attrs, and Pydantic models:

@dataclass
class User:
    id: int
    name: str

assert_that(User(id=1, name="Alice")).is_equal_to(User(id=99, name="Alice"), ignore="id")

Compares lists of objects pairwise:

actual = [User(id=1, name="Alice"), User(id=2, name="Bob")]
expected = [User(id=99, name="Alice"), User(id=99, name="Bob")]
assert_that(actual).is_equal_to(expected, ignore="id")

Compare nested floats with an absolute tolerance, or supply custom comparators:

assert_that({"price": 1.0001}).is_equal_to({"price": 1.0}, tolerance=0.001)

# by type, or by field name (field name wins over type)
assert_that(actual).is_equal_to(expected, comparators={float: lambda a, e: round(a, 2) == round(e, 2)})
assert_that(actual).is_equal_to(expected, comparators={"name": lambda a, e: a.lower() == e.lower()})

Ignore fields by regex or by type:

import re

assert_that(payload).is_equal_to(expected, ignore=re.compile(r"^_"))  # ignore private-ish keys
assert_that(payload).is_equal_to(expected, ignore=float)               # ignore all float fields

Require the same type at every level, which plain == does not:

assert_that({"active": True}).is_equal_to({"active": 1})                     # passes
assert_that({"active": True}).is_equal_to({"active": 1}, strict_types=True)  # fails

Failure produces a nice error message:

assert_that(1).is_equal_to(2)  # fails
# Expected <1> to be equal to <2>, but was not.

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if actual is not equal to expected

TypeError

if ignore/include is a one-shot or otherwise unsupported iterable, or is used on a value that is neither dict-like nor has introspectable fields; if tolerance is not a real number or comparators is not a dict of callables; or if val or other is (or contains, at any nesting depth) an element-wise array/frame-like (numpy/pandas/polars) whose == has no single truth value (compare the value's own equality, e.g. actual.equals(expected), instead)

ValueError

if tolerance is NaN or negative

Tip

Using is_equal_to() with a float val is just asking for trouble. Instead, you'll always want to use fuzzy numeric assertions like is_close_to() or is_between().

See Also

is_equal_to_ignoring_case() - for case-insensitive string equality

Source code in assertpy2/base.py
def is_equal_to(self, other: object, **kwargs: object) -> Self:
    """Asserts that val is equal to other.

    Checks actual is equal to expected using the ``==`` operator. When val is *dict-like*
    or has introspectable fields (dataclass, namedtuple, attrs, Pydantic model),
    optionally ignore or include keys/fields when checking equality.

    Args:
        other: the expected value
        **kwargs: see below

    Keyword Args:
        ignore (Hashable | list | set | frozenset | None): the key/field (or list/set/frozenset of
            keys/fields) to ignore.  Besides exact keys and nested-path tuples, a ``re.Pattern`` matches
            field names by regex and a ``type`` matches fields by value type.
        include (Hashable | list | set | frozenset | None): the key/field (or list/set/frozenset of
            keys/fields) to include.  Accepts the same ``re.Pattern`` / ``type`` specs as ``ignore``.  A
            key the value does not have fails the assertion with or without ``not_``.
        tolerance (float | None): an absolute tolerance that widens ``==`` for every pair of real-number
            leaves anywhere in the structure: a pair ``==`` holds equal stays equal, and any other is
            measured as [`is_close_to()`][assertpy2.numeric.NumericMixin.is_close_to] measures it.
        comparators (dict | None): a dict mapping a ``type`` or a field name to an
            ``(actual, expected) -> bool`` predicate that alone decides every node it matches, the root
            included, even inside a container whose ``==`` holds; a field-name key wins over a type
            key.  Mapping keys, set members and whatever a container shared by both sides holds are
            left to ``==``.
        ignore_null (bool): when ``True``, skip any named field the *expected* side leaves ``None``
            (a partial expected/template), at any depth.  Only the expected side is skipped, so an
            unexpectedly ``None`` actual field is still reported.  Defaults to ``False``.
        strict_types (bool): when ``True``, both sides of every node must be the same type, at any
            depth.  Plain ``==`` does not require this: ``True == 1``, ``Decimal("1") == 1`` and
            ``[True] == [1]`` are all true, so a boolean read from JSON compares equal to an
            integer without a word.  Opting in also rejects pairs some callers consider equal
            (``IntEnum`` against ``int``, a ``dict`` subclass against ``dict``, ``float`` against
            ``int``), and it wins over ``tolerance``, which says how far apart two numbers may be
            and not that they may be different types.  A ``comparators`` entry still decides the
            nodes it matches ahead of it, the root included, and a `Matcher` on the expected side is
            exempt, so composed matchers keep working.  Dictionary keys and set elements are covered
            too, although a container matches them by hash before any type is looked at: ``{True: "a"}`` against
            ``{1: "a"}`` and ``{1}`` against ``{1.0}`` both fail, as ``[True]`` against ``[1]``
            does.  Defaults to ``False``.

    Examples:
        Usage:

            assert_that(1 + 2).is_equal_to(3)
            assert_that('foo').is_equal_to('foo')
            assert_that(123).is_equal_to(123)
            assert_that(123.4).is_equal_to(123.4)
            assert_that(['a', 'b']).is_equal_to(['a', 'b'])
            assert_that((1, 2, 3)).is_equal_to((1, 2, 3))
            assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1, 'b': 2})
            assert_that({'a', 'b'}).is_equal_to({'a', 'b'})

        When the val is *dict-like*, keys can optionally be *ignored* when checking equality:

            # ignore a single key
            assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, ignore='b')

            # ignore multiple keys
            assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1}, ignore=['b', 'c'])

            # ignore nested keys
            assert_that({'a': {'b': 2, 'c': 3, 'd': 4}}).is_equal_to(
                {'a': {'d': 4}}, ignore=[('a', 'b'), ('a', 'c')]
            )

        When the val is *dict-like*, only certain keys can be *included* when checking equality:

            # include a single key
            assert_that({'a': 1, 'b': 2}).is_equal_to({'a': 1}, include='a')

            # include multiple keys
            assert_that({'a': 1, 'b': 2, 'c': 3}).is_equal_to({'a': 1, 'b': 2}, include=['a', 'b'])

        Works with dataclasses, namedtuples, attrs, and Pydantic models:

            @dataclass
            class User:
                id: int
                name: str

            assert_that(User(id=1, name="Alice")).is_equal_to(User(id=99, name="Alice"), ignore="id")

        Compares lists of objects pairwise:

            actual = [User(id=1, name="Alice"), User(id=2, name="Bob")]
            expected = [User(id=99, name="Alice"), User(id=99, name="Bob")]
            assert_that(actual).is_equal_to(expected, ignore="id")

        Compare nested floats with an absolute tolerance, or supply custom comparators:

            assert_that({"price": 1.0001}).is_equal_to({"price": 1.0}, tolerance=0.001)

            # by type, or by field name (field name wins over type)
            assert_that(actual).is_equal_to(expected, comparators={float: lambda a, e: round(a, 2) == round(e, 2)})
            assert_that(actual).is_equal_to(expected, comparators={"name": lambda a, e: a.lower() == e.lower()})

        Ignore fields by regex or by type:

            import re

            assert_that(payload).is_equal_to(expected, ignore=re.compile(r"^_"))  # ignore private-ish keys
            assert_that(payload).is_equal_to(expected, ignore=float)               # ignore all float fields

        Require the same type at every level, which plain ``==`` does not:

            assert_that({"active": True}).is_equal_to({"active": 1})                     # passes
            assert_that({"active": True}).is_equal_to({"active": 1}, strict_types=True)  # fails

        Failure produces a nice error message:

            assert_that(1).is_equal_to(2)  # fails
            # Expected <1> to be equal to <2>, but was not.

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if actual is **not** equal to expected
        TypeError: if ``ignore``/``include`` is a one-shot or otherwise unsupported iterable, or is
            used on a value that is neither dict-like nor has introspectable fields; if ``tolerance`` is
            not a real number or ``comparators`` is not a dict of callables; or if val or other is (or
            contains, at any nesting depth) an element-wise array/frame-like (numpy/pandas/polars) whose
            ``==`` has no single truth value (compare the value's own equality, e.g.
            ``actual.equals(expected)``, instead)
        ValueError: if ``tolerance`` is ``NaN`` or negative

    Tip:
        Using [`is_equal_to()`][assertpy2.base.BaseMixin.is_equal_to] with a ``float`` val is just
        asking for trouble. Instead, you'll
        always want to use *fuzzy* numeric assertions
        like [`is_close_to()`][assertpy2.numeric.NumericMixin.is_close_to]
        or [`is_between()`][assertpy2.numeric.NumericMixin.is_between].

    See Also:
        [`is_equal_to_ignoring_case()`][assertpy2.string.StringMixin.is_equal_to_ignoring_case] -
            for case-insensitive string equality
    """
    if not kwargs:
        if type(self.val) in _EQ_ATOMIC and type(other) in _EQ_ATOMIC:
            # atomic scalars: no array or dict likeness, and `==` yields a real bool
            try:
                if self.val == other:
                    return self
            except decimal.InvalidOperation:
                pass  # only a signalling `Decimal` NaN signals between two atomic scalars, and it equals nothing
            if isinstance(self.val, str) and isinstance(other, str):
                actual_repr = _truncated(_elided_text_repr(self.val, other))
                expected_repr = _truncated(_elided_text_repr(other, self.val))
            else:
                actual_repr, expected_repr = _disambiguated(self.val, other)
            return self.error(
                f"Expected <{actual_repr}> to be equal to <{expected_repr}>, but was not.",
                actual=self.val,
                expected=other,
                diff=_build_equality_diff(self.val, other),
            )
        ignore = include = config = None
    else:
        reject_unknown_kwargs(kwargs, _IS_EQUAL_TO_OPTIONS, "is_equal_to")
        ignore = kwargs.get("ignore")
        include = kwargs.get("include")
        config = _build_compare_config(
            kwargs.get("tolerance"),
            kwargs.get("comparators"),
            kwargs.get("ignore_null", False),
            kwargs.get("strict_types", False),
        )

    operand = _ambiguous_array_operand(self.val, other)
    if operand is not None:
        raise _array_equality_error("is_equal_to", operand)

    # cleared however this leaves, since a soft block goes on using the builder after a failure it collected
    try:
        compared = self._compare_to(other, ignore=ignore, include=include, config=config)
    finally:
        self._equality_comparison = False
    if self._compared_nothing:
        self._compared_nothing = False
        _warn_nothing_compared()
    return compared

is_not_equal_to

is_not_equal_to(other: object) -> Self

Asserts that val is not equal to other.

Checks actual is not equal to expected using the == operator, the question is_equal_to asks. != is never asked: a type's __ne__ need not be the negation of its __eq__.

Parameters:

Name Type Description Default
other object

the expected value

required

Examples:

Usage:

assert_that(1 + 2).is_not_equal_to(4)
assert_that('foo').is_not_equal_to('bar')
assert_that(123).is_not_equal_to(456)
assert_that(123.4).is_not_equal_to(567.8)
assert_that(['a', 'b']).is_not_equal_to(['c', 'd'])
assert_that((1, 2, 3)).is_not_equal_to((1, 2, 4))
assert_that({'a': 1, 'b': 2}).is_not_equal_to({'a': 1, 'b': 3})
assert_that({'a', 'b'}).is_not_equal_to({'a', 'x'})

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if actual is equal to expected

TypeError

if val or other is (or contains, at any nesting depth) an element-wise array/frame-like (numpy/pandas/polars) whose == has no single truth value; compare the value's own equality instead

Source code in assertpy2/base.py
def is_not_equal_to(self, other: object) -> Self:
    """Asserts that val is not equal to other.

    Checks actual is not equal to expected using the ``==`` operator, the question `is_equal_to`
    asks.  ``!=`` is never asked: a type's ``__ne__`` need not be the negation of its ``__eq__``.

    Args:
        other: the expected value

    Examples:
        Usage:

            assert_that(1 + 2).is_not_equal_to(4)
            assert_that('foo').is_not_equal_to('bar')
            assert_that(123).is_not_equal_to(456)
            assert_that(123.4).is_not_equal_to(567.8)
            assert_that(['a', 'b']).is_not_equal_to(['c', 'd'])
            assert_that((1, 2, 3)).is_not_equal_to((1, 2, 4))
            assert_that({'a': 1, 'b': 2}).is_not_equal_to({'a': 1, 'b': 3})
            assert_that({'a', 'b'}).is_not_equal_to({'a', 'x'})

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if actual **is** equal to expected
        TypeError: if val or other is (or contains, at any nesting depth) an element-wise
            array/frame-like (numpy/pandas/polars) whose ``==`` has no single truth value; compare
            the value's own equality instead
    """
    operand = _ambiguous_array_operand(self.val, other)
    if operand is not None:
        raise _array_equality_error("is_not_equal_to", operand)

    if _guarded_equal(self.val, other, method="is_not_equal_to"):
        return self.error(
            f"Expected <{_truncated(str(self.val))}> to be not equal to <{_truncated(str(other))}>, but was."
        )
    return self

is_same_as

is_same_as(other: object) -> Self

Asserts that val is identical to other.

Checks actual is identical to expected using the is operator.

Parameters:

Name Type Description Default
other object

the expected value

required

Examples:

Basic types are identical:

assert_that(1).is_same_as(1)
assert_that('foo').is_same_as('foo')
assert_that(123.4).is_same_as(123.4)

As are immutables like tuple:

assert_that((1, 2, 3)).is_same_as((1, 2, 3))

But mutable collections like list, dict, and set are not:

# these all fail...
assert_that(['a', 'b']).is_same_as(['a', 'b'])  # fails
assert_that({'a': 1, 'b': 2}).is_same_as({'a': 1, 'b': 2})  # fails
assert_that({'a', 'b'}).is_same_as({'a', 'b'})  # fails

Unless they are the same object:

x = {'a': 1, 'b': 2}
y = x
assert_that(x).is_same_as(y)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if actual is not identical to expected

Source code in assertpy2/base.py
def is_same_as(self, other: object) -> Self:
    """Asserts that val is identical to other.

    Checks actual is identical to expected using the ``is`` operator.

    Args:
        other: the expected value

    Examples:
        Basic types are identical:

            assert_that(1).is_same_as(1)
            assert_that('foo').is_same_as('foo')
            assert_that(123.4).is_same_as(123.4)

        As are immutables like ``tuple``:

            assert_that((1, 2, 3)).is_same_as((1, 2, 3))

        But mutable collections like ``list``, ``dict``, and ``set`` are not:

            # these all fail...
            assert_that(['a', 'b']).is_same_as(['a', 'b'])  # fails
            assert_that({'a': 1, 'b': 2}).is_same_as({'a': 1, 'b': 2})  # fails
            assert_that({'a', 'b'}).is_same_as({'a', 'b'})  # fails

        Unless they are the same object:

            x = {'a': 1, 'b': 2}
            y = x
            assert_that(x).is_same_as(y)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if actual is **not** identical to expected
    """
    if self.val is not other:
        return self.error(
            f"Expected <{_safe_str(self.val)}> to be identical to <{other}>, but was not.", expected=other
        )
    return self

is_not_same_as

is_not_same_as(other: object) -> Self

Asserts that val is not identical to other.

Checks actual is not identical to expected using the is operator.

Parameters:

Name Type Description Default
other object

the expected value

required

Examples:

Usage:

assert_that(1).is_not_same_as(2)
assert_that('foo').is_not_same_as('bar')
assert_that(123.4).is_not_same_as(567.8)
assert_that((1, 2, 3)).is_not_same_as((1, 2, 4))

# mutable collections, even if equal, are not identical...
assert_that(['a', 'b']).is_not_same_as(['a', 'b'])
assert_that({'a': 1, 'b': 2}).is_not_same_as({'a': 1, 'b': 2})
assert_that({'a', 'b'}).is_not_same_as({'a', 'b'})

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if actual is identical to expected

Source code in assertpy2/base.py
def is_not_same_as(self, other: object) -> Self:
    """Asserts that val is not identical to other.

    Checks actual is not identical to expected using the ``is`` operator.

    Args:
        other: the expected value

    Examples:
        Usage:

            assert_that(1).is_not_same_as(2)
            assert_that('foo').is_not_same_as('bar')
            assert_that(123.4).is_not_same_as(567.8)
            assert_that((1, 2, 3)).is_not_same_as((1, 2, 4))

            # mutable collections, even if equal, are not identical...
            assert_that(['a', 'b']).is_not_same_as(['a', 'b'])
            assert_that({'a': 1, 'b': 2}).is_not_same_as({'a': 1, 'b': 2})
            assert_that({'a', 'b'}).is_not_same_as({'a', 'b'})

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if actual **is** identical to expected
    """
    if self.val is other:
        return self.error(f"Expected <{_safe_str(self.val)}> to be not identical to <{other}>, but was.")
    return self

is_true

is_true() -> Self

Asserts that val is true.

Examples:

Usage:

assert_that(True).is_true()
assert_that(1).is_true()
assert_that('foo').is_true()
assert_that(1.0).is_true()
assert_that(['a', 'b']).is_true()
assert_that((1, 2, 3)).is_true()
assert_that({'a': 1, 'b': 2}).is_true()
assert_that({'a', 'b'}).is_true()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is false

TypeError

if val is a coroutine, since every coroutine is truthy and this would hold whatever awaiting it would have answered

Source code in assertpy2/base.py
def is_true(self) -> Self:
    """Asserts that val is true.

    Examples:
        Usage:

            assert_that(True).is_true()
            assert_that(1).is_true()
            assert_that('foo').is_true()
            assert_that(1.0).is_true()
            assert_that(['a', 'b']).is_true()
            assert_that((1, 2, 3)).is_true()
            assert_that({'a': 1, 'b': 2}).is_true()
            assert_that({'a', 'b'}).is_true()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val **is** false
        TypeError: if val is a coroutine, since every coroutine is truthy and this would hold
            whatever awaiting it would have answered
    """
    if not verdict(self.val, subject="the call under test"):
        return self.error(f"Expected <{_safe_str(self.val)}> to be <True>, but was not.", expected=True)
    return self

is_false

is_false() -> Self

Asserts that val is false.

Examples:

Usage:

assert_that(False).is_false()
assert_that(0).is_false()
assert_that('').is_false()
assert_that(0.0).is_false()
assert_that([]).is_false()
assert_that(()).is_false()
assert_that({}).is_false()
assert_that(set()).is_false()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is true

TypeError

if val is a coroutine, since every coroutine is truthy and this would refuse whatever awaiting it would have answered

Source code in assertpy2/base.py
def is_false(self) -> Self:
    """Asserts that val is false.

    Examples:
        Usage:

            assert_that(False).is_false()
            assert_that(0).is_false()
            assert_that('').is_false()
            assert_that(0.0).is_false()
            assert_that([]).is_false()
            assert_that(()).is_false()
            assert_that({}).is_false()
            assert_that(set()).is_false()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val **is** true
        TypeError: if val is a coroutine, since every coroutine is truthy and this would refuse
            whatever awaiting it would have answered
    """
    if verdict(self.val, subject="the call under test"):
        return self.error(f"Expected <{_safe_str(self.val)}> to be <False>, but was not.", expected=False)
    return self

is_none

is_none() -> Self

Asserts that val is none.

Examples:

Usage:

assert_that(None).is_none()
assert_that(print('hello world')).is_none()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not none

Source code in assertpy2/base.py
def is_none(self) -> Self:
    """Asserts that val is none.

    Examples:
        Usage:

            assert_that(None).is_none()
            assert_that(print('hello world')).is_none()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** none
    """
    if self.val is not None:
        return self.error(f"Expected <{_safe_str(self.val)}> to be <None>, but was not.", expected=None)
    return self

is_not_none

is_not_none() -> Self

Asserts that val is not none.

Examples:

Usage:

assert_that(0).is_not_none()
assert_that('foo').is_not_none()
assert_that(False).is_not_none()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is none

Source code in assertpy2/base.py
def is_not_none(self) -> Self:
    """Asserts that val is not none.

    Examples:
        Usage:

            assert_that(0).is_not_none()
            assert_that('foo').is_not_none()
            assert_that(False).is_not_none()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val **is** none
    """
    if self.val is None:
        return self.error("Expected not <None>, but was.")
    return self

is_type_of

is_type_of(some_type: type) -> Self

Asserts that val is of the given type.

Parameters:

Name Type Description Default
some_type type

the expected type

required

Examples:

Usage:

assert_that(1).is_type_of(int)
assert_that('foo').is_type_of(str)
assert_that(123.4).is_type_of(float)
assert_that(['a', 'b']).is_type_of(list)
assert_that((1, 2, 3)).is_type_of(tuple)
assert_that({'a': 1, 'b': 2}).is_type_of(dict)
assert_that({'a', 'b'}).is_type_of(set)
assert_that(True).is_type_of(bool)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not of the given type

Source code in assertpy2/base.py
def is_type_of(self, some_type: type) -> Self:
    """Asserts that val is of the given type.

    Args:
        some_type (type): the expected type

    Examples:
        Usage:

            assert_that(1).is_type_of(int)
            assert_that('foo').is_type_of(str)
            assert_that(123.4).is_type_of(float)
            assert_that(['a', 'b']).is_type_of(list)
            assert_that((1, 2, 3)).is_type_of(tuple)
            assert_that({'a': 1, 'b': 2}).is_type_of(dict)
            assert_that({'a', 'b'}).is_type_of(set)
            assert_that(True).is_type_of(bool)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** of the given type
    """
    if type(some_type) is not type and not issubclass(type(some_type), type):
        refuse(some_type, "a type", subject=argument("type"))
    if type(self.val) is not some_type:
        type_name = self._type(self.val)
        return self.error(
            f"Expected <{_safe_str(self.val)}:{type_name}> to be of type <{some_type.__name__}>, but was not.",
            expected=some_type,
        )
    return self

is_instance_of

is_instance_of(some_class: ClassInfo) -> Self

Asserts that val is an instance of the given class.

Parameters:

Name Type Description Default
some_class ClassInfo

the expected class, a union of them, or a tuple nested to any depth

required

Examples:

Usage:

assert_that(1).is_instance_of(int)
assert_that('foo').is_instance_of(str)
assert_that(123.4).is_instance_of(float)
assert_that(['a', 'b']).is_instance_of(list)
assert_that((1, 2, 3)).is_instance_of(tuple)
assert_that({'a': 1, 'b': 2}).is_instance_of(dict)
assert_that({'a', 'b'}).is_instance_of(set)
assert_that(True).is_instance_of(bool)

With a user-defined class:

class Foo: pass
f = Foo()
assert_that(f).is_instance_of(Foo)
assert_that(f).is_instance_of(object)

With alternatives, anything isinstance takes, nested to any depth:

assert_that(1).is_instance_of(int | str)
assert_that(1).is_instance_of((int, str))
assert_that(1).is_instance_of((int, (str, bytes)))

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not an instance of the given class

TypeError

if the given arg, or any member of a union or tuple, is not a class

Source code in assertpy2/base.py
def is_instance_of(self, some_class: ClassInfo) -> Self:
    """Asserts that val is an instance of the given class.

    Args:
        some_class: the expected class, a union of them, or a tuple nested to any depth

    Examples:
        Usage:

            assert_that(1).is_instance_of(int)
            assert_that('foo').is_instance_of(str)
            assert_that(123.4).is_instance_of(float)
            assert_that(['a', 'b']).is_instance_of(list)
            assert_that((1, 2, 3)).is_instance_of(tuple)
            assert_that({'a': 1, 'b': 2}).is_instance_of(dict)
            assert_that({'a', 'b'}).is_instance_of(set)
            assert_that(True).is_instance_of(bool)

        With a user-defined class:

            class Foo: pass
            f = Foo()
            assert_that(f).is_instance_of(Foo)
            assert_that(f).is_instance_of(object)

        With alternatives, anything `isinstance` takes, nested to any depth:

            assert_that(1).is_instance_of(int | str)
            assert_that(1).is_instance_of((int, str))
            assert_that(1).is_instance_of((int, (str, bytes)))

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** an instance of the given class
        TypeError: if the given arg, or any member of a union or tuple, is not a class
    """
    # a class answers `isinstance` itself, raising what it raises, though a generic alias passes for one on 3.10
    if not isinstance(some_class, type) or isinstance(some_class, GenericAlias):
        _require_class_info(some_class, name="class", probe=self.val)
    if not isinstance(self.val, some_class):
        type_name = self._type(self.val)
        some_class_name = _type_expression_name(some_class)
        return self.error(
            f"Expected <{_safe_str(self.val)}:{type_name}> to be instance of class "
            f"<{some_class_name}>, but was not.",
            expected=some_class,
        )
    return self

is_instance_of_any

is_instance_of_any(*some_classes: ClassInfo) -> Self

Asserts that val is an instance of at least one of the given classes.

Parameters:

Name Type Description Default
*some_classes ClassInfo

the candidate classes, each a class, a union of them, or a nested tuple

()

Examples:

Usage:

assert_that(1).is_instance_of_any(int, float)
assert_that('foo').is_instance_of_any(str, bytes)
assert_that(TimeoutError()).is_instance_of_any(OSError, ValueError)
assert_that(1).is_instance_of_any(int | str, (bytes, bytearray))

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not an instance of any of the given classes

TypeError

if a given arg is not a class

ValueError

if no classes are given

Source code in assertpy2/base.py
def is_instance_of_any(self, *some_classes: ClassInfo) -> Self:
    """Asserts that val is an instance of at least one of the given classes.

    Args:
        *some_classes: the candidate classes, each a class, a union of them, or a nested tuple

    Examples:
        Usage:

            assert_that(1).is_instance_of_any(int, float)
            assert_that('foo').is_instance_of_any(str, bytes)
            assert_that(TimeoutError()).is_instance_of_any(OSError, ValueError)
            assert_that(1).is_instance_of_any(int | str, (bytes, bytearray))

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** an instance of any of the given classes
        TypeError: if a given arg is not a class
        ValueError: if no classes are given
    """
    if len(some_classes) == 0:
        raise ValueError("one or more args must be given")
    _require_class_info(some_classes, name="class", expectation="classes", probe=self.val)
    if not isinstance(self.val, some_classes):
        type_name = self._type(self.val)
        class_names = ", ".join(_type_expression_name(some_class) for some_class in some_classes)
        return self.error(
            f"Expected <{_safe_str(self.val)}:{type_name}> to be instance of any of <{class_names}>, but was not.",
            expected=some_classes,
        )
    return self

is_subclass_of

is_subclass_of(some_class: ClassInfo) -> Self

Asserts that val is a class and is a subclass of the given class.

Checks the class hierarchy using the issubclass() built-in, so a class counts as a subclass of itself.

Parameters:

Name Type Description Default
some_class ClassInfo

the expected ancestor class, a union of them, or a tuple nested to any depth

required

Examples:

Usage:

assert_that(bool).is_subclass_of(int)
assert_that(TimeoutError).is_subclass_of(OSError)

class Base: pass
class Derived(Base): pass

assert_that(Derived).is_subclass_of(Base)
assert_that(Derived).is_subclass_of(Derived)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not a subclass of the given class

TypeError

if val or the given arg, or any member of a union or tuple, is not a class

Source code in assertpy2/base.py
def is_subclass_of(self, some_class: ClassInfo) -> Self:
    """Asserts that val is a class and is a subclass of the given class.

    Checks the class hierarchy using the ``issubclass()`` built-in, so a class counts as a
    subclass of itself.

    Args:
        some_class: the expected ancestor class, a union of them, or a tuple nested to any depth

    Examples:
        Usage:

            assert_that(bool).is_subclass_of(int)
            assert_that(TimeoutError).is_subclass_of(OSError)

            class Base: pass
            class Derived(Base): pass

            assert_that(Derived).is_subclass_of(Base)
            assert_that(Derived).is_subclass_of(Derived)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** a subclass of the given class
        TypeError: if val or the given arg, or any member of a union or tuple, is not a class
    """
    require_type(self.val, type, "a class")
    # as in `is_instance_of`, with `issubclass` asking each member
    if not isinstance(some_class, type) or isinstance(some_class, GenericAlias):
        _require_class_info(some_class, name="class", probe=self.val, check=issubclass)
    if not issubclass(self.val, some_class):
        expected_name = _type_expression_name(some_class)
        return self.error(
            f"Expected <{self.val.__name__}> to be subclass of <{expected_name}>, but was not.",
            expected=some_class,
        )
    return self

is_length

is_length(length: SupportsIndex) -> Self

Asserts that val is the given length.

Checks val is the given length using the len() built-in.

Parameters:

Name Type Description Default
length int

the expected length

required

Examples:

Usage:

assert_that('foo').is_length(3)
assert_that(['a', 'b']).is_length(2)
assert_that((1, 2, 3)).is_length(3)
assert_that({'a': 1, 'b': 2}).is_length(2)
assert_that({'a', 'b'}).is_length(2)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not the given length

Source code in assertpy2/base.py
def is_length(self, length: SupportsIndex) -> Self:
    """Asserts that val is the given length.

    Checks val is the given length using the ``len()`` built-in.

    Args:
        length (int): the expected length

    Examples:
        Usage:

            assert_that('foo').is_length(3)
            assert_that(['a', 'b']).is_length(2)
            assert_that((1, 2, 3)).is_length(3)
            assert_that({'a': 1, 'b': 2}).is_length(2)
            assert_that({'a', 'b'}).is_length(2)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** the given length
    """
    wanted = length if type(length) is int else require_integer(length, "length")
    if wanted < 0:
        raise ValueError("given arg must be a positive int")
    if sized_len(self.val) != wanted:
        return self.error(
            f"Expected <{_safe_str(self.val)}> to be of length <{length}>, but was <{sized_len(self.val)}>.",
            expected=length,
        )
    return self

is_length_between

is_length_between(
    low: SupportsIndex, high: SupportsIndex
) -> Self

Asserts that val's length is between low and high (both inclusive).

Checks val's length using the len() built-in, like is_length(). Identical to has_size_between() apart from the error message wording.

Parameters:

Name Type Description Default
low SupportsIndex

the inclusive lower length bound

required
high SupportsIndex

the inclusive upper length bound

required

Examples:

Usage:

assert_that('foo').is_length_between(1, 5)
assert_that(['a', 'b']).is_length_between(2, 2)
assert_that((1, 2, 3)).is_length_between(0, 3)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val's length is not between low and high

TypeError

if a given arg is not an int

ValueError

if a given arg is negative, or low is greater than high

Source code in assertpy2/base.py
def is_length_between(self, low: SupportsIndex, high: SupportsIndex) -> Self:
    """Asserts that val's length is between low and high (both inclusive).

    Checks val's length using the ``len()`` built-in, like
    [`is_length()`][assertpy2.base.BaseMixin.is_length].  Identical to
    [`has_size_between()`][assertpy2.collection.CollectionMixin.has_size_between] apart from
    the error message wording.

    Args:
        low: the inclusive lower length bound
        high: the inclusive upper length bound

    Examples:
        Usage:

            assert_that('foo').is_length_between(1, 5)
            assert_that(['a', 'b']).is_length_between(2, 2)
            assert_that((1, 2, 3)).is_length_between(0, 3)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val's length is **not** between low and high
        TypeError: if a given arg is not an int
        ValueError: if a given arg is negative, or low is greater than high
    """
    least = low if type(low) is int else require_integer(low, "low")
    most = high if type(high) is int else require_integer(high, "high")
    if least < 0 or most < 0:
        raise ValueError("given args must be positive ints")
    if least > most:
        raise ValueError("given low arg must be less than given high arg")
    if not least <= sized_len(self.val) <= most:
        return self.error(
            f"Expected <{_safe_str(self.val)}> to be of length between <{low}> and <{high}>, "
            f"but was <{sized_len(self.val)}>.",
            expected=(low, high),
        )
    return self

Predicate and matcher-application assertions: satisfies / each / *_satisfy / matches_structure.

all_fields_satisfy

all_fields_satisfy(
    matcher: Matcher[Any] | Callable[..., bool],
    *,
    allow_empty: bool = False,
) -> Self

Asserts that every scalar leaf in val's object graph satisfies the given matcher.

Walks val recursively (mappings, dataclasses, namedtuples, Pydantic models, lists, tuples) and applies the matcher to each leaf value, reporting the path of every leaf that does not satisfy it. Scalars, strings, sets and opaque objects are treated as single leaves. A Pydantic model is walked through the values its fields hold, not its model_dump(): a field excluded from the dump is walked, a computed field is not, and a field serializer does not apply.

Parameters:

Name Type Description Default
matcher Matcher[Any] | Callable[..., bool]

a Matcher or callable predicate applied to every leaf

required

Examples:

Usage:

from assertpy2 import match

assert_that({"a": 1, "nested": {"b": 2}}).all_fields_satisfy(match.is_positive())
assert_that([1, [2, 3]]).all_fields_satisfy(lambda x: x > 0)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if any leaf does not satisfy the matcher

TypeError

if matcher is neither a Matcher nor callable

Source code in assertpy2/_satisfies.py
def all_fields_satisfy(self, matcher: Matcher[Any] | Callable[..., bool], *, allow_empty: bool = False) -> Self:
    """Asserts that every scalar leaf in val's object graph satisfies the given matcher.

    Walks val recursively (mappings, dataclasses, namedtuples, Pydantic models, lists, tuples) and
    applies the matcher to each leaf value, reporting the path of every leaf that does not satisfy it.
    Scalars, strings, sets and opaque objects are treated as single leaves.  A Pydantic model is
    walked through the values its fields hold, not its ``model_dump()``: a field excluded from the
    dump is walked, a computed field is not, and a field serializer does not apply.

    Args:
        matcher: a `Matcher` or callable predicate applied to every leaf

    Examples:
        Usage:

            from assertpy2 import match

            assert_that({"a": 1, "nested": {"b": 2}}).all_fields_satisfy(match.is_positive())
            assert_that([1, [2, 3]]).all_fields_satisfy(lambda x: x > 0)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if any leaf does **not** satisfy the matcher
        TypeError: if matcher is neither a Matcher nor callable
    """
    return self._every_field(matcher, allow_empty, "all_fields_satisfy")

has_no_none_fields

has_no_none_fields(*, allow_empty: bool = False) -> Self

Asserts that no scalar leaf in val's object graph is None.

Convenience wrapper over all_fields_satisfy() with a not-None matcher; reports the path of every None leaf found anywhere in the graph, reading a Pydantic model as that does.

Examples:

Usage:

assert_that({"id": 1, "profile": {"name": "Alice"}}).has_no_none_fields()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if any leaf is None

Source code in assertpy2/_satisfies.py
def has_no_none_fields(self, *, allow_empty: bool = False) -> Self:
    """Asserts that no scalar leaf in val's object graph is ``None``.

    Convenience wrapper over `all_fields_satisfy()` with a not-``None`` matcher; reports the path
    of every ``None`` leaf found anywhere in the graph, reading a Pydantic model as that does.

    Examples:
        Usage:

            assert_that({"id": 1, "profile": {"name": "Alice"}}).has_no_none_fields()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if any leaf **is** ``None``
    """
    return self._every_field(IsNotNoneMatcher(), allow_empty, "has_no_none_fields")

satisfies

satisfies(
    matcher: Matcher[Any] | Callable[..., bool],
) -> Self

Asserts that val satisfies the given matcher.

Parameters:

Name Type Description Default
matcher Matcher[Any] | Callable[..., bool]

a Matcher instance, or a callable that takes a value and returns a bool

required

Examples:

Usage with matchers:

from assertpy2 import match

assert_that(7).satisfies(match.greater_than(5) & match.less_than(10))
assert_that('hello').satisfies(match.starts_with('he'))

Usage with callables:

assert_that(42).satisfies(lambda x: x % 2 == 0)

When the callable is typed with TypeIs it also narrows the chain to the guarded type (refinement narrowing), so .value hands the value back typed - see Type Safety for checker support (advanced; not yet in PyCharm).

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val does not satisfy the matcher

Source code in assertpy2/_satisfies.py
def satisfies(self, matcher: Matcher[Any] | Callable[..., bool]) -> Self:
    """Asserts that val satisfies the given matcher.

    Args:
        matcher: a `Matcher` instance, or a callable that takes
            a value and returns a bool

    Examples:
        Usage with matchers:

            from assertpy2 import match

            assert_that(7).satisfies(match.greater_than(5) & match.less_than(10))
            assert_that('hello').satisfies(match.starts_with('he'))

        Usage with callables:

            assert_that(42).satisfies(lambda x: x % 2 == 0)

        When the callable is typed with ``TypeIs`` it also *narrows* the chain to the guarded type
        (refinement narrowing), so ``.value`` hands the value back typed - see
        [Type Safety](../concepts/type-safety.md#refinement-narrowing-with-a-typeis-predicate-advanced) for
        checker support (advanced; not yet in PyCharm).

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val does **not** satisfy the matcher
    """
    if _is_matcher(matcher):
        # asked twice about one value: on a one-shot iterator the second call made `each_item` name the wrong item
        value = materialized(self.val)
        # a matcher that walks its value is asked once, so a `key` inside it runs once
        if _has_own_evaluate(matcher):
            outcome = _evaluate_matcher(matcher, value)
            result = None if outcome.matched else outcome
        else:
            result = None if verdict(matcher.matches(value), subject="the matcher") else _refused(matcher, value)
        if result is not None:
            return self.error(
                f"Expected {result.description}, but {result.mismatch}.",
                actual=value,
                expected=result.description,
                diff=DiffResult(
                    kind="match", entries=[_ROOT.leaf_entry(actual=value, expected=result.description)]
                ),
            )
    elif callable(matcher):
        if not verdict(cast("Callable[..., object]", matcher)(self.val)):
            return self.error(
                f"Expected <{_safe_str(self.val)}> to satisfy {_describe_matcher(matcher)}, but did not.",
                expected=_describe_matcher(matcher),
            )
    else:
        refuse(matcher, "a Matcher or a callable", subject=argument("matcher"))
    return self

each

each(
    matcher: Matcher[Any] | Callable[..., bool],
    *,
    allow_empty: bool = False,
) -> Self

Asserts that every item in val satisfies the given matcher.

Parameters:

Name Type Description Default
matcher Matcher[Any] | Callable[..., bool]

a Matcher instance, or a callable that takes a value and returns a bool

required

Examples:

Usage with matchers:

from assertpy2 import match

assert_that([1, 2, 3]).each(match.is_positive())
assert_that([10, 20, 30]).each(match.between(1, 100))

Usage with extracting:

assert_that(users).extracting('age').each(match.between(18, 120))

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if any item does not satisfy the matcher

Source code in assertpy2/_satisfies.py
def each(self, matcher: Matcher[Any] | Callable[..., bool], *, allow_empty: bool = False) -> Self:
    """Asserts that every item in val satisfies the given matcher.

    Args:
        matcher: a `Matcher` instance, or a callable that takes
            a value and returns a bool

    Examples:
        Usage with matchers:

            from assertpy2 import match

            assert_that([1, 2, 3]).each(match.is_positive())
            assert_that([10, 20, 30]).each(match.between(1, 100))

        Usage with extracting:

            assert_that(users).extracting('age').each(match.between(18, 120))

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if any item does **not** satisfy the matcher
    """
    if not _is_matcher(matcher) and not callable(matcher):
        refuse(matcher, "a Matcher or a callable", subject=argument("matcher"))
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    return self._every_item(matcher, allow_empty, "each")

matches_structure

matches_structure(spec: dict[Any, Any]) -> Self

Asserts that val matches the given structure specification.

val may be any mapping (a dict, a MappingProxyType, 3.15's frozendict, or your own collections.abc.Mapping), a pydantic-style model (anything exposing model_dump()), or an attrs instance, which is normalized to its dict before matching. Each key in spec maps to either a Matcher, a raw value (checked via ==), or a nested dict for recursive matching. Extra keys in val that are absent from the spec are allowed.

Parameters:

Name Type Description Default
spec dict[Any, Any]

a dict where values can be Matcher instances, raw values, or nested dicts

required

Examples:

Usage:

from assertpy2 import assert_that, match

user = {"name": "Alice", "age": 30, "id": "550e8400-e29b-41d4-a716-446655440000"}
assert_that(user).matches_structure({
    "name": match.is_non_empty_string(),
    "age": match.between(18, 120),
    "id": match.is_uuid(),
})

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val does not match the structure spec

Source code in assertpy2/_satisfies.py
def matches_structure(self, spec: dict[Any, Any]) -> Self:
    """Asserts that val matches the given structure specification.

    ``val`` may be any mapping (a ``dict``, a ``MappingProxyType``, 3.15's ``frozendict``, or your
    own ``collections.abc.Mapping``), a pydantic-style model (anything exposing ``model_dump()``),
    or an ``attrs`` instance, which is normalized to its dict before matching.  Each key in
    ``spec`` maps to either a `Matcher`, a raw value (checked via ``==``), or a nested ``dict``
    for recursive matching.  Extra keys in val that are absent from the spec are allowed.

    Args:
        spec: a dict where values can be Matcher instances, raw values, or nested dicts

    Examples:
        Usage:

            from assertpy2 import assert_that, match

            user = {"name": "Alice", "age": 30, "id": "550e8400-e29b-41d4-a716-446655440000"}
            assert_that(user).matches_structure({
                "name": match.is_non_empty_string(),
                "age": match.between(18, 120),
                "id": match.is_uuid(),
            })

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val does **not** match the structure spec
    """
    if not is_mapping_like(self.val) and not is_model_dump_object(self.val) and not is_attrs_instance(self.val):
        refuse(self.val, "a mapping, a pydantic-style model, or an attrs instance")
    if not isinstance(spec, dict):
        refuse(spec, "a dict", subject=argument("spec"))
    matcher = StructureMatcher(spec)
    # one walk, read twice: the entries want every mismatch, the message wants the first one in words
    mismatches = matcher.walk_mismatches(self.val)
    if mismatches:
        entries = [
            mismatch.path.entry(actual=mismatch.actual, expected=mismatch.expected_desc) for mismatch in mismatches
        ]
        return self.error(
            f"Expected <{_safe_str(self.val)}> to match structure {matcher.describe()}, but"
            f" {matcher.render_mismatch(mismatches)}.",
            actual=self.val,
            expected=spec,
            diff=DiffResult(kind="match", entries=entries),
        )
    return self

is_callable

is_callable() -> Self

Asserts that val is callable.

Examples:

Usage:

assert_that(lambda: None).is_callable()
assert_that(print).is_callable()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is not callable

Source code in assertpy2/_satisfies.py
def is_callable(self) -> Self:
    """Asserts that val is callable.

    Examples:
        Usage:

            assert_that(lambda: None).is_callable()
            assert_that(print).is_callable()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val is **not** callable
    """
    if not callable(self.val):
        return self.error(f"Expected <{_safe_str(self.val)}> to be callable, but was not.")
    return self

is_not_callable

is_not_callable() -> Self

Asserts that val is not callable.

Examples:

Usage:

assert_that(42).is_not_callable()
assert_that('foo').is_not_callable()

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if val is callable

Source code in assertpy2/_satisfies.py
def is_not_callable(self) -> Self:
    """Asserts that val is not callable.

    Examples:
        Usage:

            assert_that(42).is_not_callable()
            assert_that('foo').is_not_callable()

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if val **is** callable
    """
    if callable(self.val):
        return self.error(f"Expected <{_safe_str(self.val)}> to not be callable, but was.")
    return self

any_satisfy

any_satisfy(
    matcher: Matcher[Any] | Callable[..., bool],
) -> Self

Asserts that at least one item in val satisfies the given matcher.

Parameters:

Name Type Description Default
matcher Matcher[Any] | Callable[..., bool]

a Matcher instance, or a callable that takes a value and returns a bool

required

Examples:

Usage with matchers:

from assertpy2 import match

assert_that([1, -2, 3]).any_satisfy(match.is_negative())

Usage with callables:

assert_that([1, 2, 3]).any_satisfy(lambda x: x > 2)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if no item satisfies the matcher

Source code in assertpy2/_satisfies.py
def any_satisfy(self, matcher: Matcher[Any] | Callable[..., bool]) -> Self:
    """Asserts that at least one item in val satisfies the given matcher.

    Args:
        matcher: a `Matcher` instance, or a callable that takes
            a value and returns a bool

    Examples:
        Usage with matchers:

            from assertpy2 import match

            assert_that([1, -2, 3]).any_satisfy(match.is_negative())

        Usage with callables:

            assert_that([1, 2, 3]).any_satisfy(lambda x: x > 2)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if no item satisfies the matcher
    """
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    # resolving is what refuses, so the matcher is inspected once rather than here and again there
    reading = _resolved(matcher)
    apply = reading.apply  # read once: the attribute lookup is per item otherwise
    values = materialized(self.val)
    if not any(apply(item) for item in values):
        # asked once the verdict is in, since it is wanted only for the message
        description = reading.describe()
        # "none did" alone leaves the reader to fetch the items themselves
        items = list(values)
        return self.error(
            f"Expected any item to satisfy {description}, but none of the {len(items)} did.",
            actual=values,
            expected=description,
            diff=DiffResult(
                kind="match",
                entries=[
                    _ROOT.index(index).entry(actual=item, expected=description)
                    for index, item in enumerate(items[:5])
                ],
            ),
        )
    return self

all_satisfy

all_satisfy(
    matcher: Matcher[Any] | Callable[..., bool],
    *,
    allow_empty: bool = False,
) -> Self

Asserts that all items in val satisfy the given matcher.

Semantic alias for each().

Parameters:

Name Type Description Default
matcher Matcher[Any] | Callable[..., bool]

a Matcher instance, or a callable that takes a value and returns a bool

required

Examples:

Usage with matchers:

from assertpy2 import match

assert_that([1, 2, 3]).all_satisfy(match.is_positive())

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if any item does not satisfy the matcher

Source code in assertpy2/_satisfies.py
def all_satisfy(self, matcher: Matcher[Any] | Callable[..., bool], *, allow_empty: bool = False) -> Self:
    """Asserts that all items in val satisfy the given matcher.

    Semantic alias for [`each()`][assertpy2.base.BaseMixin.each].

    Args:
        matcher: a `Matcher` instance, or a callable that takes
            a value and returns a bool

    Examples:
        Usage with matchers:

            from assertpy2 import match

            assert_that([1, 2, 3]).all_satisfy(match.is_positive())

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if any item does **not** satisfy the matcher
    """
    if not _is_matcher(matcher) and not callable(matcher):
        refuse(matcher, "a Matcher or a callable", subject=argument("matcher"))
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    return self._every_item(matcher, allow_empty, "all_satisfy")

none_satisfy

none_satisfy(
    matcher: Matcher[Any] | Callable[..., bool],
) -> Self

Asserts that no item in val satisfies the given matcher.

Parameters:

Name Type Description Default
matcher Matcher[Any] | Callable[..., bool]

a Matcher instance, or a callable that takes a value and returns a bool

required

Examples:

Usage with matchers:

from assertpy2 import match

assert_that([1, 2, 3]).none_satisfy(match.is_negative())

Usage with callables:

assert_that([1, 2, 3]).none_satisfy(lambda x: x < 0)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if any item satisfies the matcher

Source code in assertpy2/_satisfies.py
def none_satisfy(self, matcher: Matcher[Any] | Callable[..., bool]) -> Self:
    """Asserts that no item in val satisfies the given matcher.

    Args:
        matcher: a `Matcher` instance, or a callable that takes
            a value and returns a bool

    Examples:
        Usage with matchers:

            from assertpy2 import match

            assert_that([1, 2, 3]).none_satisfy(match.is_negative())

        Usage with callables:

            assert_that([1, 2, 3]).none_satisfy(lambda x: x < 0)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if any item satisfies the matcher
    """
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    if _is_matcher(matcher):
        for i, item in enumerate(self.val):
            if verdict(matcher.matches(item), subject="the matcher"):
                return self.error(
                    f"Expected no item to satisfy {matcher.describe()}, but item at index {i} <{item}> did."
                )
    elif callable(matcher):
        for i, item in enumerate(self.val):
            if verdict(cast("Callable[..., object]", matcher)(item)):
                return self.error(
                    f"Expected no item to satisfy {_describe_matcher(matcher)}, but item at index {i} <{item}> did."
                )
    else:
        refuse(matcher, "a Matcher or a callable", subject=argument("matcher"))
    return self

satisfies_exactly

satisfies_exactly(
    *matchers: Matcher[Any] | Callable[..., bool],
) -> Self

Asserts that val has exactly one item per matcher, each satisfying the matcher at its position.

Unlike each() (one matcher applied to every item), this pairs the i-th item with the i-th matcher and additionally requires the lengths to match. Every positional mismatch is reported, not just the first.

Parameters:

Name Type Description Default
*matchers Matcher[Any] | Callable[..., bool]

one Matcher or callable predicate per expected item, applied in order

()

Examples:

Usage:

from assertpy2 import match

assert_that([1, "foo", 3.0]).satisfies_exactly(
    match.is_odd(), match.is_instance_of(str), match.is_positive()
)
assert_that([2, 4]).satisfies_exactly(lambda x: x == 2, lambda x: x == 4)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if the length differs, or any item does not satisfy its matcher

TypeError

if val is not iterable, or a given arg is neither a Matcher nor callable

ValueError

if no matchers are given

Source code in assertpy2/_satisfies.py
def satisfies_exactly(self, *matchers: Matcher[Any] | Callable[..., bool]) -> Self:
    """Asserts that val has exactly one item per matcher, each satisfying the matcher at its position.

    Unlike [`each()`][assertpy2.base.BaseMixin.each] (one matcher applied to every item), this
    pairs the i-th item with the
    i-th matcher and additionally requires the lengths to match.  Every positional mismatch is
    reported, not just the first.

    Args:
        *matchers: one `Matcher` or callable predicate per expected item,
            applied in order

    Examples:
        Usage:

            from assertpy2 import match

            assert_that([1, "foo", 3.0]).satisfies_exactly(
                match.is_odd(), match.is_instance_of(str), match.is_positive()
            )
            assert_that([2, 4]).satisfies_exactly(lambda x: x == 2, lambda x: x == 4)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if the length differs, or any item does **not** satisfy its matcher
        TypeError: if val is not iterable, or a given arg is neither a Matcher nor callable
        ValueError: if no matchers are given
    """
    if len(matchers) == 0:
        raise ValueError("one or more args must be given")
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    items = list(self.val)
    if len(items) != len(matchers):
        return self.error(
            f"Expected collection length <{len(matchers)}>, but was <{len(items)}>.",
            actual=self.val,
            expected=[_describe_matcher(matcher) for matcher in matchers],
        )
    entries = [
        _ROOT.index(index).entry(actual=item, expected=_describe_matcher(matcher))
        for index, (item, matcher) in enumerate(zip(items, matchers, strict=True))
        if not _apply_matcher(matcher, item)
    ]
    if entries:
        failed = "item" if len(entries) == 1 else "items"
        return self.error(
            f"Expected items to satisfy the given matchers in order, but {len(entries)} {failed} did not.",
            actual=self.val,
            expected=[_describe_matcher(matcher) for matcher in matchers],
            diff=DiffResult(kind="match", entries=entries),
        )
    return self

satisfies_exactly_in_any_order

satisfies_exactly_in_any_order(
    *matchers: Matcher[Any] | Callable[..., bool],
) -> Self

Asserts that the items and the given matchers can be paired one-to-one, in any order.

Like satisfies_exactly() but ignoring positions: passes when some one-to-one assignment pairs every item with a distinct matcher it satisfies. The lengths must still match, and no matcher may be reused for two items.

Since every matcher is probed against every item, a probe that raises TypeError (a type-incompatible comparison on a mixed collection, like is_positive() meeting a string) counts as a non-match instead of crashing the pairing. On failure, an unpaired matcher whose probes raised is annotated with the raise count in the diff, so a buggy predicate is not mistaken for an ordinary mismatch.

Parameters:

Name Type Description Default
*matchers Matcher[Any] | Callable[..., bool]

one Matcher or callable predicate per expected item, in any order

()

Examples:

Usage:

from assertpy2 import match

assert_that(["foo", 3]).satisfies_exactly_in_any_order(
    match.is_odd(), match.is_instance_of(str)
)
assert_that([2, 1]).satisfies_exactly_in_any_order(lambda x: x == 1, lambda x: x == 2)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if the length differs, or no one-to-one pairing satisfies all matchers

TypeError

if val is not iterable, or a given arg is neither a Matcher nor callable

ValueError

if no matchers are given

Source code in assertpy2/_satisfies.py
def satisfies_exactly_in_any_order(self, *matchers: Matcher[Any] | Callable[..., bool]) -> Self:
    """Asserts that the items and the given matchers can be paired one-to-one, in any order.

    Like [`satisfies_exactly()`][assertpy2.base.BaseMixin.satisfies_exactly] but ignoring
    positions: passes when some one-to-one assignment pairs every item with a distinct matcher
    it satisfies.  The lengths must still match, and no matcher may be reused for two items.

    Since every matcher is probed against every item, a probe that raises ``TypeError`` (a
    type-incompatible comparison on a mixed collection, like ``is_positive()`` meeting a string)
    counts as a non-match instead of crashing the pairing.  On failure, an unpaired matcher whose
    probes raised is annotated with the raise count in the diff, so a buggy predicate is not
    mistaken for an ordinary mismatch.

    Args:
        *matchers: one `Matcher` or callable predicate per expected item, in any order

    Examples:
        Usage:

            from assertpy2 import match

            assert_that(["foo", 3]).satisfies_exactly_in_any_order(
                match.is_odd(), match.is_instance_of(str)
            )
            assert_that([2, 1]).satisfies_exactly_in_any_order(lambda x: x == 1, lambda x: x == 2)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if the length differs, or no one-to-one pairing satisfies all matchers
        TypeError: if val is not iterable, or a given arg is neither a Matcher nor callable
        ValueError: if no matchers are given
    """
    if len(matchers) == 0:
        raise ValueError("one or more args must be given")
    # resolved here rather than asked again per item, and the resolution is what refuses a bad one
    appliers = [reading.apply for reading in (_resolved(matcher) for matcher in matchers)]
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    items = list(self.val)
    if len(items) != len(matchers):
        return self.error(
            f"Expected collection length <{len(matchers)}>, but was <{len(items)}>.",
            actual=self.val,
            expected=[_describe_matcher(matcher) for matcher in matchers],
        )
    raised_counts = [0] * len(matchers)
    satisfied = []
    for item in items:
        row = []
        for column, apply in enumerate(appliers):
            try:
                row.append(apply(item))
            except VerdictError:  # noqa: PERF203  # never a non-match, always a mistake
                raise
            except TypeError:  # every probe may raise independently on a mixed collection
                raised_counts[column] += 1
                row.append(False)
        satisfied.append(row)
    assignment = _max_bipartite_assignment(satisfied)
    unpaired_items = [index for index, column in enumerate(assignment) if column is None]
    if unpaired_items:
        paired_columns = {column for column in assignment if column is not None}
        entries = [
            _ROOT.member(items[index], "extra").entry(actual=items[index], expected=None, absent="expected")
            for index in unpaired_items
        ]
        entries.extend(
            DiffEntry(
                path="missing",
                actual=None,
                absent="actual",
                expected=_describe_unpaired(matcher, raised_counts[column]),
            )
            for column, matcher in enumerate(matchers)
            if column not in paired_columns
        )
        failed = "item" if len(unpaired_items) == 1 else "items"
        return self.error(
            f"Expected items to satisfy the given matchers in any order,"
            f" but no pairing covers {len(unpaired_items)} {failed}.",
            actual=self.val,
            expected=[_describe_matcher(matcher) for matcher in matchers],
            diff=DiffResult(kind="contains", entries=entries),
        )
    return self

zip_satisfies

zip_satisfies(
    other: Iterable[object],
    predicate: Callable[..., bool],
    *,
    allow_empty: bool = False,
) -> Self

Asserts that each pair from zipping val with other satisfies the two-arg predicate.

Pairs the i-th item of val with the i-th item of other and checks predicate(a, b). The two iterables must have equal length. Every failing pair is reported.

Parameters:

Name Type Description Default
other Iterable[object]

the iterable to zip with val

required
predicate Callable[..., bool]

a two-arg callable returning a bool, applied to each (val_item, other_item) pair

required

Examples:

Usage:

assert_that([1, 2, 3]).zip_satisfies([2, 4, 6], lambda a, b: b == a * 2)
assert_that(["a", "bb"]).zip_satisfies([1, 2], lambda s, n: len(s) == n)

Returns:

Name Type Description
AssertionBuilder Self

returns this instance to chain to the next assertion

Raises:

Type Description
AssertionError

if the lengths differ, or any pair does not satisfy the predicate

TypeError

if val or other is not iterable, or predicate is not callable

Source code in assertpy2/_satisfies.py
def zip_satisfies(
    self, other: Iterable[object], predicate: Callable[..., bool], *, allow_empty: bool = False
) -> Self:
    """Asserts that each pair from zipping val with other satisfies the two-arg predicate.

    Pairs the i-th item of val with the i-th item of ``other`` and checks ``predicate(a, b)``.
    The two iterables must have equal length.  Every failing pair is reported.

    Args:
        other: the iterable to zip with val
        predicate: a two-arg callable returning a bool, applied to each ``(val_item, other_item)`` pair

    Examples:
        Usage:

            assert_that([1, 2, 3]).zip_satisfies([2, 4, 6], lambda a, b: b == a * 2)
            assert_that(["a", "bb"]).zip_satisfies([1, 2], lambda s, n: len(s) == n)

    Returns:
        AssertionBuilder: returns this instance to chain to the next assertion

    Raises:
        AssertionError: if the lengths differ, or any pair does **not** satisfy the predicate
        TypeError: if val or other is not iterable, or predicate is not callable
    """
    if not callable(predicate):
        refuse(predicate, "callable", subject=argument("predicate"))
    if not isinstance(self.val, collections.abc.Iterable):
        refuse(self.val, "iterable")
    if not isinstance(other, collections.abc.Iterable):
        refuse(other, "iterable", subject=argument("other"))
    val_items = list(self.val)
    other_items = list(other)
    if len(val_items) != len(other_items):
        return self.error(
            f"Expected collection length <{len(other_items)}>, but was <{len(val_items)}>.",
            actual=self.val,
            expected=other,
        )
    # warned here: a length mismatch is the verdict, and warning first said the call passed over nothing
    if not val_items:
        _warn_vacuous(self, "zip_satisfies", allow_empty)
    entries = [
        _ROOT.index(index).entry(actual=val_item, expected=other_item)
        for index, (val_item, other_item) in enumerate(zip(val_items, other_items, strict=True))
        if not verdict(predicate(val_item, other_item))
    ]
    if entries:
        failed = "pair" if len(entries) == 1 else "pairs"
        return self.error(
            f"Expected paired items to satisfy <{predicate}>, but {len(entries)} {failed} did not.",
            actual=self.val,
            expected=other,
            diff=DiffResult(kind="match", entries=entries),
        )
    return self