v0.2.0

Changelog

All notable changes to this project are documented here.

5 min readgenerated by git-cliffEdit this page

The format follows Keep a Changelog, and this project adheres to Semantic Versioning.

This file is generated from the commit log by git-cliff. Don't edit it -- write the commit message, which a CI gate already requires to be a Conventional Commit.

0.2.0 (2026-09-01)

⚠ BREAKING CHANGES

  • license: the Mozilla Public License 2.0, from 0.2.0 on (#30)

Features

  • license: the Mozilla Public License 2.0, from 0.2.0 on (#30) (93b5462)

Performance

  • imports: load a subject the first time a value needs one, not at import (#21) (2523965)

Documentation

  • concepts: correct what the design pages claim about the library (#34) (d0cd564)
  • contributing: state the terms a contribution arrives under (#29) (a5b9687)
  • getting-started: correct the entry path, and give two pages an opening (#33) (682ccd0)
  • give each repeated lesson one owner, and define the words the tree relies on (#38) (adff86e)
  • guides: correct the last seven guides, and state the halves that fail silently (#37) (802546d)
  • guides: correct the translation tables, and the Jest claim the source made too (#36) (24e297d)
  • internal: the guidance describes the tree it is guidance for (#28) (5e0e265)
  • readme: keep the logo out of the documentation corpus, and restore the H1 (#32) (a174a60)
  • readme: the logo, five fewer paragraphs, and badges that report something (#31) (8d2af02)

Refactoring

  • callable: three families, split by what each one is asked (#20) (0d6b90b)
  • collection: one file per seam, over a shared root (#16) (4b282e3)
  • core: assemble the subject from one mixin per seam (#14) (194bbea)
  • datetime: the seams are the classes, made into files (#19) (77cafdc)
  • diff: one file per kind of thing being compared (#10) (443efb5)
  • enum: three families of question, and the helpers behind them (#25) (668292d)
  • equivalence: one file per question the engine has to answer (#22) (92dbf2e)
  • formatting: separate the registries, the limits and the scope (#12) (0976a68)
  • matching: one file per placeholder, and the naming halves apart (#13) (605bc90)
  • occurrence: the protocol, the constraints, and the words for them (#26) (d7c009b)
  • ordered: the protocol, the words, and three families of comparison (#27) (479f573)
  • path: two subjects, split by whether the disk is asked (#18) (4641808)
  • reflection: split the leaves by the question they answer (#11) (decf57f)
  • sequence: split the two subjects that inherit a catalogue (#17) (ddcebb3)
  • string: one file per seam of the widest catalogue (#15) (5624f33)
  • type: four families of question, and the helpers behind them (#23) (e68a4c4)

Tests

  • guards: walk the package once, so a subpackage cannot blind a rule (#8) (024fcd4)

0.1.0 (2026-08-30)

Features

  • fluent, strictly-typed assertions for Python tests (c7b0448)

Documentation

  • correct what the pages got wrong, and run the README (#2) (42d3fc5)

CI

  • codeql: analyse with security-extended, not security-and-quality (#1) (b3d5d6a)
  • release: derive the version from the commit log with release-please (#4) (3c18126)
  • release: tag as v0.1.0, and pin what nothing else connects (#6) (729149c)
  • sonar: harden the release gate, and scope what Sonar grades (#3) (30a64c4)

[0.1.0] - 2026-08-29

Added

  • Fluent, strictly-typed assertions for Python tests

    expect(value).is_equal_to(...). The competition is not assertpy or PyHamcrest — it is pytest's own assert rewriting, which already introspects assert a == b and prints a decent diff. So this library claims three things instead, and breaking any one of them would leave it with no reason to exist.

    Typed discoverability. expect(x). offers only the assertions valid for the type of x. A str subject has no is_positive. Dispatch is one table written twice — an @overload chain a checker walks, and a runtime branch order that walks the same one — so what you are offered and what you get cannot disagree.

    Real narrowing. expect(raw).is_not_none().subject is a str to both pyright and mypy, not an object. The limitation is stated rather than hidden: the caller's own variable stays str | None, because TypeIs can only narrow a function's first positional argument and expect() captures its subject inside a wrapper. Narrowing flows through the returned subject — rebind it, and the type is statically guaranteed.

    Failure messages that explain. A sentence naming the subject, what was expected, and what was actually there:

    Expected server_config to contain key 'hostname' (did you mean 'host'?),
    but the keys were ['host'].

    A missing key and a key holding the wrong value are different bugs and get different sentences. Difference blocks are bounded, so comparing two very large lists costs a few hundred characters rather than the lists themselves.

    Subjects for strings, numbers, collections, sequences, mappings, dates and times, paths, exceptions, warnings, mocks, types and enums; soft assertions, asymmetric matchers, structural equivalence, occurrence counting, output control, and an extension API that hands a subclass the whole inherited catalogue.

    Zero runtime dependencies, permanently — this package is installed into test suites that already carry their own trees, and adding to theirs is a cost they did not choose. Python 3.13+, py.typed, full type completeness, pyright and mypy both strict and both green on 3.13 and 3.14.

    A passing assertion costs a comparison and a return self: no allocation, no frame inspection, no message built. The failure path may do whatever it needs to explain itself.

    Every Python block in the documentation is executed by the test suite and every failure message it quotes is compared against what the library actually prints, so a page cannot drift from the code without failing the build.

esc

Nothing matches that. The reference is generated, so try an assertion name.

No results. The reference is generated, so try an assertion name.

↑↓ navigate↵ open30 pages, every example executed in CI