Skip to content

Entry points

The top-level functions exported by assertpy2.

assert_that is statically overloaded: the return type narrows to the assertions valid for the value's type. Each per-type overload is listed below. See Type safety for how this drives editor autocomplete.

assert_that

assert_that(
    val: str, description: str = ""
) -> _StringAssertion
assert_that(
    val: int | float | complex, description: str = ""
) -> _NumericAssertion
assert_that(
    val: dict, description: str = ""
) -> _DictAssertion
assert_that(
    val: list | tuple, description: str = ""
) -> _IterableAssertion
assert_that(
    val: set | frozenset, description: str = ""
) -> _IterableAssertion
assert_that(
    val: date, description: str = ""
) -> _DateAssertion
assert_that(
    val: Path, description: str = ""
) -> _PathAssertion
assert_that(
    val: bytes | bytearray, description: str = ""
) -> _BytesAssertion
assert_that(
    val: Callable[..., object], description: str = ""
) -> _CallableAssertion
assert_that(
    val: object, description: str = ""
) -> AssertionBuilder

Set the value to be tested, plus an optional description, and allow assertions to be called.

This is a factory method for the AssertionBuilder, and the single most important method in all of assertpy.

Parameters:

Name Type Description Default
val object

the value to be tested (aka the actual value)

required
description str

the extra error message description. Defaults to '' (aka empty string)

''

Examples:

Just import it once at the top of your test file, and away you go...

from assertpy2 import assert_that

def test_something():
    assert_that(1 + 2).is_equal_to(3)
    assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar')
    assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x')
Source code in assertpy2/assertpy.py
def assert_that(val: object, description="") -> _CoreAssertion:
    """Set the value to be tested, plus an optional description, and allow assertions to be called.

    This is a factory method for the `AssertionBuilder`, and the single most important
    method in all of assertpy.

    Args:
        val: the value to be tested (aka the actual value)
        description (str, optional): the extra error message description. Defaults to ``''``
            (aka empty string)

    Examples:
        Just import it once at the top of your test file, and away you go...

            from assertpy2 import assert_that

            def test_something():
                assert_that(1 + 2).is_equal_to(3)
                assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar')
                assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x')
    """
    if _soft_ctx.get():
        return _builder(val, description, "soft")
    return _builder(val, description)

assert_warn

assert_warn(val: object, description='', logger=None)

Set the value to be tested, and optional description and logger, and allow assertions to be called, but never fail, only log warnings.

This is a factory method for the AssertionBuilder, but unlike assert_that() an AssertionError is never raised, and execution is never halted. Instead, any assertion failures results in a warning message being logged. Uses the given logger, or defaults to a simple logger that prints warnings to stdout.

Parameters:

Name Type Description Default
val object

the value to be tested (aka the actual value)

required
description str

the extra error message description. Defaults to '' (aka empty string)

''
logger Logger

the logger for warning message on assertion failure. Defaults to None (aka use the default simple logger that prints warnings to stdout)

None

Examples:

Usage:

from assertpy2 import assert_warn

assert_warn('foo').is_length(4)
assert_warn('foo').is_empty()
assert_warn('foo').is_false()
assert_warn('foo').is_digit()
assert_warn('123').is_alpha()

Even though all of the above assertions fail, AssertionError is never raised and test execution is never halted. Instead, the failed assertions merely log the following warning messages to stdout:

2019-10-27 20:00:35 WARNING [test_foo.py:23]: Expected <foo> to be of length <4>, but was <3>.
2019-10-27 20:00:35 WARNING [test_foo.py:24]: Expected <foo> to be empty string, but was not.
2019-10-27 20:00:35 WARNING [test_foo.py:25]: Expected <False>, but was not.
2019-10-27 20:00:35 WARNING [test_foo.py:26]: Expected <foo> to contain only digits, but did not.
2019-10-27 20:00:35 WARNING [test_foo.py:27]: Expected <123> to contain only alphabetic chars, but did not.
Tip

Use assert_warn() if and only if you have a really good reason to log assertion failures instead of failing.

Source code in assertpy2/assertpy.py
def assert_warn(val: object, description="", logger=None):
    """Set the value to be tested, and optional description and logger, and allow assertions to be
    called, but never fail, only log warnings.

    This is a factory method for the `AssertionBuilder`, but unlike [`assert_that()`][assertpy2.assertpy.assert_that] an
    `AssertionError` is never raised, and execution is never halted.  Instead, any assertion failures
    results in a warning message being logged. Uses the given logger, or defaults to a simple logger
    that prints warnings to ``stdout``.


    Args:
        val: the value to be tested (aka the actual value)
        description (str, optional): the extra error message description. Defaults to ``''``
            (aka empty string)
        logger (Logger, optional): the logger for warning message on assertion failure. Defaults to ``None``
            (aka use the default simple logger that prints warnings to ``stdout``)

    Examples:
        Usage:

            from assertpy2 import assert_warn

            assert_warn('foo').is_length(4)
            assert_warn('foo').is_empty()
            assert_warn('foo').is_false()
            assert_warn('foo').is_digit()
            assert_warn('123').is_alpha()

        Even though all of the above assertions fail, ``AssertionError`` is never raised and
        test execution is never halted.  Instead, the failed assertions merely log the following
        warning messages to ``stdout``:

            2019-10-27 20:00:35 WARNING [test_foo.py:23]: Expected <foo> to be of length <4>, but was <3>.
            2019-10-27 20:00:35 WARNING [test_foo.py:24]: Expected <foo> to be empty string, but was not.
            2019-10-27 20:00:35 WARNING [test_foo.py:25]: Expected <False>, but was not.
            2019-10-27 20:00:35 WARNING [test_foo.py:26]: Expected <foo> to contain only digits, but did not.
            2019-10-27 20:00:35 WARNING [test_foo.py:27]: Expected <123> to contain only alphabetic chars, but did not.

    Tip:
        Use `assert_warn()` if and only if you have a *really* good reason to log assertion
        failures instead of failing.
    """
    return _builder(val, description, "warn", logger=logger)

soft_assertions

soft_assertions() -> Iterator[SoftAssertionCollector]

Create a soft assertion context.

Normally, any assertion failure will halt test execution immediately by raising an error. Soft assertions are way to collect assertion failures (and failure messages) together, to be raised all at once at the end, without halting your test.

Uses contextvars internally, so each thread and each asyncio task gets its own independent soft-assertion state.

Examples:

Create a soft assertion context, and some failing tests:

from assertpy2 import assert_that, soft_assertions

with soft_assertions():
    assert_that('foo').is_length(4)
    assert_that('foo').is_empty()
    assert_that('foo').is_false()
    assert_that('foo').is_digit()
    assert_that('123').is_alpha()

When the context ends, any assertion failures are collected together and a single AssertionError is raised:

AssertionError: soft assertion failures:
1. Expected <foo> to be of length <4>, but was <3>.
2. Expected <foo> to be empty string, but was not.
3. Expected <False>, but was not.
4. Expected <foo> to contain only digits, but did not.
5. Expected <123> to contain only alphabetic chars, but did not.

Group errors by section:

with soft_assertions() as sa:
    with sa.group("Headers"):
        assert_that(headers["Content-Type"]).is_equal_to("application/json")
    with sa.group("Body"):
        assert_that(body["status"]).is_equal_to("ok")
Note

The soft assertion context only collects assertion failures, other errors such as TypeError or ValueError are always raised immediately. Triggering an explicit test failure with fail() will similarly halt execution immediately. If you need more forgiving behavior, use soft_fail() to add a failure message without halting test execution.

Source code in assertpy2/assertpy.py
@contextlib.contextmanager
def soft_assertions() -> Iterator[SoftAssertionCollector]:
    """Create a soft assertion context.

    Normally, any assertion failure will halt test execution immediately by raising an error.
    Soft assertions are way to collect assertion failures (and failure messages) together, to be
    raised all at once at the end, without halting your test.

    Uses `contextvars` internally, so each thread and each ``asyncio`` task gets its own
    independent soft-assertion state.

    Examples:
        Create a soft assertion context, and some failing tests:

            from assertpy2 import assert_that, soft_assertions

            with soft_assertions():
                assert_that('foo').is_length(4)
                assert_that('foo').is_empty()
                assert_that('foo').is_false()
                assert_that('foo').is_digit()
                assert_that('123').is_alpha()

        When the context ends, any assertion failures are collected together and a single
        ``AssertionError`` is raised:

            AssertionError: soft assertion failures:
            1. Expected <foo> to be of length <4>, but was <3>.
            2. Expected <foo> to be empty string, but was not.
            3. Expected <False>, but was not.
            4. Expected <foo> to contain only digits, but did not.
            5. Expected <123> to contain only alphabetic chars, but did not.

        Group errors by section:

            with soft_assertions() as sa:
                with sa.group("Headers"):
                    assert_that(headers["Content-Type"]).is_equal_to("application/json")
                with sa.group("Body"):
                    assert_that(body["status"]).is_equal_to("ok")

    Note:
        The soft assertion context only collects *assertion* failures, other errors such as
        ``TypeError`` or ``ValueError`` are always raised immediately.  Triggering an explicit test
        failure with [`fail()`][assertpy2.assertpy.fail] will similarly halt execution immediately.
        If you need more forgiving behavior, use [`soft_fail()`][assertpy2.assertpy.soft_fail] to add
        a failure message without halting test execution.
    """
    ctx = _soft_ctx.get()
    if ctx == 0:
        _soft_err.set([])
    _soft_ctx.set(ctx + 1)

    try:
        yield SoftAssertionCollector()
    finally:
        _soft_ctx.set(_soft_ctx.get() - 1)

    errs = _soft_err.get([])
    if errs and _soft_ctx.get() == 0:
        out = _format_soft_errors(errs)
        _soft_err.set([])
        raise AssertionError(out)

assert_all

assert_all(*callables: Callable[[], object]) -> None

Run all callables inside a soft assertion context.

A convenience wrapper around soft_assertions() for inline use.

Examples:

Usage:

from assertpy2 import assert_all, assert_that

assert_all(
    lambda: assert_that(x).is_positive(),
    lambda: assert_that(y).is_not_none(),
)

Raises:

Type Description
AssertionError

if any of the callables produce assertion failures

Source code in assertpy2/assertpy.py
def assert_all(*callables: Callable[[], object]) -> None:
    """Run all callables inside a soft assertion context.

    A convenience wrapper around [`soft_assertions()`][assertpy2.assertpy.soft_assertions] for inline use.

    Examples:
        Usage:

            from assertpy2 import assert_all, assert_that

            assert_all(
                lambda: assert_that(x).is_positive(),
                lambda: assert_that(y).is_not_none(),
            )

    Raises:
        AssertionError: if any of the callables produce assertion failures
    """
    with soft_assertions():
        for fn in callables:
            fn()

fail

fail(msg='')

Force immediate test failure with the given message.

Parameters:

Name Type Description Default
msg str

the failure message. Defaults to ''

''

Examples:

Fail a test:

from assertpy2 import assert_that, fail

def test_fail():
    fail('forced fail!')

If you wanted to test for a known failure, here is a useful pattern:

import operator

def test_adder_bad_arg():
    try:
        operator.add(1, 'bad arg')
        fail('should have raised error')
    except TypeError as e:
        assert_that(str(e)).contains('unsupported operand')
Source code in assertpy2/assertpy.py
def fail(msg=""):
    """Force immediate test failure with the given message.

    Args:
        msg (str, optional): the failure message.  Defaults to ``''``

    Examples:
        Fail a test:

            from assertpy2 import assert_that, fail

            def test_fail():
                fail('forced fail!')

        If you wanted to test for a known failure, here is a useful pattern:

            import operator

            def test_adder_bad_arg():
                try:
                    operator.add(1, 'bad arg')
                    fail('should have raised error')
                except TypeError as e:
                    assert_that(str(e)).contains('unsupported operand')
    """
    raise AssertionError(f"Fail: {msg}!" if msg else "Fail!")

soft_fail

soft_fail(msg='')

Within a soft_assertions() context, append the failure message to the soft error list, but do not halt test execution.

Otherwise, outside the context, acts identical to fail() and forces immediate test failure with the given message.

Parameters:

Name Type Description Default
msg str

the failure message. Defaults to ''

''

Examples:

Failing soft assertions:

from assertpy2 import assert_that, soft_assertions, soft_fail

with soft_assertions():
    assert_that(1).is_equal_to(2)
    soft_fail('my message')
    assert_that('foo').is_equal_to('bar')

Fails, and outputs the following soft error list:

AssertionError: soft assertion failures:
1. Expected <1> to be equal to <2>, but was not.
2. Fail: my message!
3. Expected <foo> to be equal to <bar>, but was not.
Source code in assertpy2/assertpy.py
def soft_fail(msg=""):
    """Within a [`soft_assertions()`][assertpy2.assertpy.soft_assertions] context, append the failure
    message to the soft error list, but do not halt test execution.

    Otherwise, outside the context, acts identical to [`fail()`][assertpy2.assertpy.fail] and forces immediate test
    failure with the given message.

    Args:
        msg (str, optional): the failure message.  Defaults to ``''``

    Examples:
        Failing soft assertions:

            from assertpy2 import assert_that, soft_assertions, soft_fail

            with soft_assertions():
                assert_that(1).is_equal_to(2)
                soft_fail('my message')
                assert_that('foo').is_equal_to('bar')

        Fails, and outputs the following soft error list:

            AssertionError: soft assertion failures:
            1. Expected <1> to be equal to <2>, but was not.
            2. Fail: my message!
            3. Expected <foo> to be equal to <bar>, but was not.

    """
    if _soft_ctx.get():
        _soft_err.get().append((_soft_group.get(), f"Fail: {msg}!" if msg else "Fail!"))
        return
    fail(msg)

add_extension

add_extension(func)

Add a new user-defined custom assertion to assertpy.

Once the assertion is registered with assertpy, use it like any other assertion. Pass val to assert_that(), and then call it.

Parameters:

Name Type Description Default
func Callable

the assertion function (to be added)

required

Examples:

Usage:

from assertpy2 import add_extension

def is_5(self):
    if self.val != 5:
        return self.error(f'{self.val} is NOT 5!')
    return self

add_extension(is_5)

def test_5():
    assert_that(5).is_5()

def test_6():
    assert_that(6).is_5()  # fails
    # 6 is NOT 5!
Source code in assertpy2/assertpy.py
def add_extension(func):
    """Add a new user-defined custom assertion to assertpy.

    Once the assertion is registered with assertpy, use it like any other assertion.  Pass val to
    [`assert_that()`][assertpy2.assertpy.assert_that], and then call it.

    Args:
        func (Callable): the assertion function (to be added)

    Examples:
        Usage:

            from assertpy2 import add_extension

            def is_5(self):
                if self.val != 5:
                    return self.error(f'{self.val} is NOT 5!')
                return self

            add_extension(is_5)

            def test_5():
                assert_that(5).is_5()

            def test_6():
                assert_that(6).is_5()  # fails
                # 6 is NOT 5!
    """
    if not callable(func):
        raise TypeError("func must be callable")
    _extensions[func.__name__] = func

remove_extension

remove_extension(func)

Remove a user-defined custom assertion.

Parameters:

Name Type Description Default
func Callable

the assertion function (to be removed)

required

Examples:

Usage:

from assertpy2 import remove_extension

remove_extension(is_5)
Source code in assertpy2/assertpy.py
def remove_extension(func):
    """Remove a user-defined custom assertion.

    Args:
        func (Callable): the assertion function (to be removed)

    Examples:
        Usage:

            from assertpy2 import remove_extension

            remove_extension(is_5)
    """
    if not callable(func):
        raise TypeError("func must be callable")
    if func.__name__ in _extensions:
        del _extensions[func.__name__]