Skip to content

Expectations

Pyssertive's foundation is a single fluent vocabulary that speaks to any value you put under test — a domain object, a primitive, a collection. Every other assertable in this library (HTTP responses, JSON, HTML, MCP, architecture) extends this same idiom.

from pyssertive import expect

expect(42).equals(42)
expect("alice@example.com").is_instance_of(str).matches(r".+@.+")
expect([1, 2, 3]).has_count(3).contains(2).does_not_contain(99)
expect({"name": "alice", "age": 30}).has_keys("name", "age")

Domain example

def test_signup_should_create_active_user():
    user = signup_service.register(email="alice@x.com")

    expect(user).is_instance_of(User)
    expect(user.id).is_not_none()
    expect(user.email).equals("alice@x.com")
    expect(user.permissions).contains("read").does_not_contain("admin")
    expect(user.is_active).is_true()

Higher-order: each and sequence

Apply matchers to every element of an iterable, or match positionally with optional predicates:

expect([2, 4, 6]).each().is_greater_than(0).is_instance_of(int)

expect(orders).sequence(
    lambda o: o.has_attribute("status", "paid"),
    lambda o: o.has_attribute("status", "shipped"),
    lambda o: o.has_attribute("status", "delivered"),
)

Custom expectations

Subclass AssertableValue to add domain-specific matchers — fully typed, autocompleted by your IDE, checked by mypy:

from pyssertive import AssertableValue

class UserExpectation(AssertableValue):
    def is_admin(self):
        assert "admin" in self._value.permissions, "Expected user to be admin"
        return self

    def is_verified(self):
        assert self._value.verified_at is not None, "Expected user to be verified"
        return self

def expect_user(u): return UserExpectation(u)

expect_user(user).is_admin().is_verified().has_attribute("email")

Unified entry point

expect is also a dispatcher to the specialized assertables, same fluent style for any subject:

from pyssertive import expect

expect(user)                # → AssertableValue (generic)
expect.json(payload)        # → AssertableJson (dict / str / bytes)
expect.html(markup)         # → AssertableHtml (str / bytes)
expect.mcp(envelope)        # → AssertableMCP (dict / response)
expect.arch("myapp.domain") # → AssertableArch (module name)

Each factory uses lazy imports — from pyssertive import expect stays light and only loads the specialized modules on first use. The direct constructors (AssertableJson(...), AssertableHtml(...), assert_arch(...), etc.) remain available for code that prefers them.

Matchers reference

Category Matchers
Equality equals, does_not_equal, is_same_as, is_not_same_as, is_none, is_not_none
Truthiness is_truthy, is_falsy, is_true, is_false
Types is_instance_of, is_not_instance_of, is_type
Comparison is_greater_than, is_less_than, is_at_least, is_at_most, is_between
Collections has_count, is_empty, is_not_empty, contains, does_not_contain
Dict/object has_key, does_not_have_key, has_keys, has_attribute, does_not_have_attribute
Strings matches, does_not_match, starts_with, ends_with
Higher-order each, sequence

The other guides show how the same vocabulary specializes for HTTP, JSON, HTML, MCP, and architectural concerns.