Skip to main content

assertpy2
The fully-typed fluent assertion library for Python
A modern, batteries-included fork of assertpy

CI Coverage PyPI version Python Downloads
public overloads type-checked by ty, mypy --strict, and pyright with zero suppressions Documentation OpenSSF Scorecard


Quick start

pip install assertpy2  # drop-in replacement for assertpy, just change the import
from assertpy2 import assert_that

def test_user():
    user = {"name": "Alice", "age": 30, "roles": ["viewer", "editor"]}

    assert_that(user).contains_key("name", "age")
    assert_that(user["age"]).is_between(18, 120)
    assert_that(user["roles"]).contains("viewer").does_not_contain("admin")
    assert_that(user).has_name("Alice")

The full documentation covers every assertion, matcher, and integration.

Why fluent assertions?

A fluent chain reads as one intent and replaces several bare asserts -
and your IDE offers only the methods that fit the value's type:

# bare - three statements, no autocomplete help
assert isinstance(items, list)
assert len(items) == 3
assert "admin" in items

# assertpy2 - one chain, type-aware autocomplete
assert_that(items).is_instance_of(list).is_length(3).contains("admin")

The real difference shows up on failure. Plain assert dumps both structures and leaves you to find the two wrong fields:

assert response == expected
E   AssertionError: assert {'id': 1, ...} == {'id': 1, ...}
E     Omitting 1 identical items, use -vv to show
E     Differing items:
E     {'user': {'name': 'Alice', 'role': 'superadmin'}} != {'user': {'name': 'Alice', 'role': 'admin'}}
E     {'status': 'active'} != {'status': 'disabled'}

assertpy2 reports the exact path to every difference, in color:

assert_that(response).is_equal_to(expected)

Structured diff in the terminal: user.role shown with its path, removal in red and addition in green

The diff recurses through nested containers, and matcher predicates get the same path-level treatment. For dynamic fields like IDs or timestamps, assert a subset with matches_structure().

Structured diffs in the terminal: dict path, list element, set extra/missing, and structural-matcher predicate diffs, side by side

Type-aware autocomplete

assert_that() uses @overload to return type-specific Protocols.
Your IDE shows only methods relevant to the value you're testing, not all 100+:

  • assert_that("hello"). → string methods: starts_with, matches, is_alpha, ...
  • assert_that(42). → numeric methods: is_positive, is_between, is_close_to, ...
  • assert_that(Path("/tmp")). → path methods: exists, is_file, is_readable, ...
  • assert_that(my_dict). → dict methods: contains_key, contains_entry, has_json_path, ...
  • assert_that(b"\x89PNG"). → bytes methods: starts_with_bytes, is_valid_utf8, decoded_as, ...

9 type-specific Protocols instead of one Any.
Works in PyCharm, VS Code, and any LSP-compatible editor.

Typed narrowing

An assertion hands the value back, statically narrowed. is_not_none() strips None, is_instance_of() narrows to the class, and .value returns it with no cast and no bare assert:

order = assert_that(repo.find(42)).is_not_none().is_instance_of(PaidOrder).value
order.refund()  # statically PaidOrder - verified by ty, mypy, and pyright

For API tests, assert_conforms() validates a raw payload against a Pydantic model and narrows the chain to it,
with exact=True catching silent contract drift:

data = assert_conforms(response.json(), OrderModel).value  # data: OrderModel

Features

Fluent API

Type safety

Built-in types

Testing

  • Soft assertions: thread-safe and async-safe via contextvars, each failure reported with its file:line. Group with sa.group() or assert_all().
  • Polling assertions: eventually() (async) / eventually_sync() (blocking) retry for eventual consistency, with a convergence trace on timeout.
  • Expected exceptions: raises().when_called_with(), walk the cause chain (caused_by(), has_root_cause()), match ExceptionGroup (contains_error()), or pivot to the object (raised()).
  • Structured errors: AssertionFailure carries .actual, .expected, .diff, and the diff renders into the message itself, so it shows off pytest too.
  • Rich pytest diffs: recursive structural diffs across containers, dataclasses, attrs, and Pydantic models, with intra-line carets for strings and circular-reference protection.
  • Snapshot testing: three modes under one typed API, all updated with --assertpy2-snapshot-update: snapshot() (external JSON file), matches_inline() (recorded into the test source), and matches_contract_snapshot() (value-tolerant structural regressions).
  • OpenAPI response contracts: conforms_to_openapi(spec, path, method) validates a JSON response body against an operation's response schema (OpenAPI 3.0/3.1), reporting every violation with its JSON path.

Extensibility

  • Custom matchers: register_matcher() for domain-specific matchers, composable with &, |, ~.
  • Regex group extraction: extracting_group() and matches_with_groups() for regex captures.
  • Extensions: add_extension() for custom assertion methods.

Integrations

  • Allure (pip install assertpy2[allure]): the pytest plugin auto-attaches structured diff and actual/expected data to Allure reports, in three configurable modes.
  • Behave (pip install assertpy2[behave]): ready-made parameter types (PositiveInt, NonEmptyString, ...) for step definitions like {age:PositiveInt}.
  • JSON (pip install assertpy2[json]): JSONPath navigation (at_json_path(), has_json_path()) and JSON Schema validation (matches_json_schema()).
  • Data frames (pip install assertpy2[pandas] / [polars] / [numpy]): fluent equality for pandas/polars frames and numpy arrays, carrying each library's own diff.

BSD 3-Clause License

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

assertpy2-2.16.0.tar.gz (583.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

assertpy2-2.16.0-py3-none-any.whl (126.9 kB view details)

Uploaded Python 3

File details

Details for the file assertpy2-2.16.0.tar.gz.

File metadata

  • Download URL: assertpy2-2.16.0.tar.gz
  • Upload date:
  • Size: 583.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for assertpy2-2.16.0.tar.gz
Algorithm Hash digest
SHA256 34ca43013e282c1f6d1a85d1f79cf4b703ff91a5d5badfe225cb0f9d20fbec46
MD5 243f8bc0bc60878fbe7d7823cb441be7
BLAKE2b-256 a46de1803055ec4c6dab4782e1541557a31102c9457d43901a59c652aa7ad8f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for assertpy2-2.16.0.tar.gz:

Publisher: publish.yml on Solganis/assertpy2

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file assertpy2-2.16.0-py3-none-any.whl.

File metadata

  • Download URL: assertpy2-2.16.0-py3-none-any.whl
  • Upload date:
  • Size: 126.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for assertpy2-2.16.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c6a89509ff0c897967a23dba3d48ab544dcf0758d892de0d9dc54599e6470bd5
MD5 a4823fd252ae9e7e975acc478ab5f638
BLAKE2b-256 7640da0723638f422a599ffd6cc1fc6efbfddbd48869374f0734272c8f64ebbf

See more details on using hashes here.

Provenance

The following attestation bundles were made for assertpy2-2.16.0-py3-none-any.whl:

Publisher: publish.yml on Solganis/assertpy2

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

2.23.0

2 files

2.22.0

2 files

2.21.0

2 files

2.20.1

2 files

2.20.0

2 files

2.19.0

2 files

2.18.0

2 files

2.17.0

2 files

This release

2.16.0 This release

2 files

2.15.0

2 files

2.14.0

2 files

2.13.0

2 files

2.12.0

2 files

2.11.0

2 files

2.10.0

2 files

2.9.1

2 files

2.9.0

2 files

2.8.1

2 files

2.8.0

2 files

2.7.0

2 files

2.6.0

2 files

2.5.1

2 files

2.5.0

2 files

2.4.0

2 files

2.3.8

2 files

2.3.7

2 files

2.3.6

2 files

2.3.5

2 files

2.3.4

2 files

2.3.3

2 files

2.3.2

2 files

2.3.1

2 files

2.3.0

2 files

2.2.0

2 files

2.1.4

2 files

2.1.3

2 files

2.1.2

2 files

2.1.1

2 files

2.1.0

2 files

2.0.1

2 files

2.0.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page