Only what applies
A str subject has no is_positive. Not hidden — absent, and your checker says so before you run anything.
expect(spell).is_lower()
expect(wishes).has_length(3)v0.2.0 · python 3.13+ · zero dependencies
A zero-dependency Python assertion library for pytest and unittest. expect() offers only what applies to your value's type, narrowing survives the chain, and a failure turns up as a sentence rather than a shrug.
from lovely_assertions import expect
expect("lovely-assertions").starts_with("love").and_.contains("assertions")compared with a bare pytest assert
what you write today
assert "levitation" in spellbookassert 'levitation' in {'levitatoin': 3, 'fireball': 1}what you could write
expect(spellbook).contains_key("levitation")A missing key and a key holding the wrong value are two different bugs. The message picks one — and spots your typo on the way past.
A str subject has no is_positive. Not hidden — absent, and your checker says so before you run anything.
expect(spell).is_lower()
expect(wishes).has_length(3)The subject a chain returns is re-typed, statically — to pyright and to mypy alike. No cast anywhere.
found = expect(raw).is_not_none()
hero = found.subject
# hero: str, no cast, no shrugWhich value, what was required, what it actually held — plus a bounded difference block when the value is composite.
Expected quest_order to be sorted, but 'rescue'
at index 1 came after 'wedding':
['wedding', 'rescue', 'feast'].AI agents read these tests too
A diff of two dictionaries leaves it to guess which of them is wrong. A sentence naming the value, the requirement and what it actually held tells it which line to edit.
intent is in the call
is_sorted() says what is required. An agent reading the file knows the constraint without inferring it from a comparison and a comment.
wrong calls do not compile
A str subject has no is_positive. An invented assertion is a type error in the same pass, not a red run twenty seconds later.
failures fit in context
Difference blocks are bounded. Comparing two five-thousand-element lists does not spend an agent's context window on data it cannot use.
one scope, three failures, one report
3 assertions failed:
(1) Expected order_totals to be sorted, but 1 at index 1 came after 3: [3, 1, 2].
(2) Expected server_config to contain key 'hostname' (did you mean 'host'?), but the keys were ['host'].
(3) Expected config to contain entry 'port': 9090, but that key held 8080.With soft_assertions(), one run reports every failure in the block. Three fixes in one pass instead of three red-green cycles — which is the difference between an agent finishing the job and an agent asking you to run the tests again.
Assertions belong with your tests, so a dev dependency is where it goes — and it will never grow a runtime dependency of its own.
$ uv add --dev lovely-assertionsexpect("unicorn").contains("corn")✓ passes
return self.Then the guides, by type and by task, and a reference generated from the source.