v0.3.0: Discovery ⚖️
⚖️ Discovery
v0.1.0 put Probatio on the record, v0.2.0 handed you the tools to cross-examine your test data. v0.3.0 is discovery: Probatio now takes in more kinds of evidence, and is sharper about what it does with them.
The temporal family grew up. AsDatetime, AsDate, and AsTime are the object-returning siblings of Datetime/Date/Time: they parse ISO 8601 out of the box (or a strptime format you pass) and hand you a real datetime/date/time, not the string back. Epoch reads a Unix timestamp into a timezone-aware UTC datetime. And Duration now accepts a plain numeric string as seconds, so "90" and 90 finally mean the same thing.
from probatio import Schema, AsDatetime, Epoch
Schema(AsDatetime())("2026-06-25T10:30:00+02:00")
# datetime.datetime(2026, 6, 25, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200)))
Schema(Epoch())(1719571800)
# datetime.datetime(2024, 6, 28, 10, 50, tzinfo=datetime.timezone.utc)New cross-field rules cover the last gap Home Assistant filled by hand: AtLeastOne, AtMostOne, and ExactlyOne say how many of a set of keys may or must appear, the dict-level form of Inclusive/Exclusive.
from probatio import Schema, All, ExactlyOne
Schema(All(dict, ExactlyOne("token", "password")))({"token": "t"}) # unchangedThe typed string validators gained control over their output. MacAddress, E164, HexColor, CreditCard, and IBAN take normalize=False to validate without rewriting, plus upper/separator where they fit. And two compatibility sharpenings: Coerce of an enum lists the valid values again (expected Color or one of 'red', 'green', 'blue'), and the OpenAPI codec emits format: date for Date() instead of date-time.
⚠️ Breaking change
E164, HexColor, CreditCard, and IBAN now normalize by default, so their output changes: grouping is stripped, IBAN is upper-cased, hex color is lower-cased, and E164 also starts accepting formatted numbers like +1 (415) 555-2671. Pass normalize=False to keep the old pass-through behavior. MacAddress is unaffected; it already normalized.
from probatio import Schema, IBAN
Schema(IBAN())("de89 3704 0044 0532 0130 00") # 'DE89370400440532013000'
Schema(IBAN(normalize=False))("de89 3704 0044 0532 0130 00") # unchangedThis is still a 0.x release: a faithful drop-in for voluptuous, validated against its behavior, with some internals still free to move before 1.0.
pip install probatio📚 Docs: https://probatio.frenck.dev
Put your data to the proof. ⚖️
../Frenck
Blogging my personal ramblings at frenck.dev
What's changed
🚨 Breaking changes
✨ New features
- Add AsDatetime/AsDate/AsTime object-returning parsers @frenck (#19)
- Add Epoch validator for Unix timestamps @frenck (#20)
- Add configurable normalization to typed string validators @frenck (#21)
- Add AtLeastOne/AtMostOne/ExactlyOne key-group validators @frenck (#27)
🐛 Bug fixes
- Fix OpenAPI encoder emitting date-time for Date() @frenck (#13)
- List an enum's values in the Coerce error message @frenck (#28)
🚀 Enhancements
🧰 Maintenance
- ⬆️ Update gcr.io/oss-fuzz-base/base-builder-python:latest Docker digest to 66c3a78 @renovate[bot] (#14)
- Upload test results to Codecov for test analytics @frenck (#23)
- Use markdown.processor for the rehype plugin @frenck (#25)
📚 Documentation
- Add a Codecov coverage badge to the README @frenck (#22)
- Split the codec guide into JSON Schema, OpenAPI, and Field lists @frenck (#24)
- Give TypedDict schemas their own guide page @frenck (#26)
⬆️ Dependency updates
12 changes
- ⬆️ Update actions/attest action to v4.1.1 @renovate[bot] (#6)
- ⬆️ Pin CodSpeedHQ/action action to v3.8.1 @renovate[bot] (#5)
- ⬆️ Update dependency ruff to v0.15.20 @renovate[bot] (#8)
- ⬆️ Update release-drafter/release-drafter action to v7.5.1 @renovate[bot] (#12)
- ⬆️ Update actions/attest-build-provenance action to v3.2.0 @renovate[bot] (#11)
- ⬆️ Update dependency syrupy to v5.3.4 @renovate[bot] (#9)
- ⬆️ Update dependency ty to v0.0.55 @renovate[bot] (#10)
- ⬆️ Update actions/setup-node action to v6 @renovate[bot] (#16)
- ⬆️ Update actions/attest-build-provenance action to v4 @renovate[bot] (#15)
- ⬆️ Update gcr.io/oss-fuzz-base/base-builder-python:latest Docker digest to 66c3a78 @renovate[bot] (#14)
- ⬆️ Lock file maintenance @renovate[bot] (#18)
- ⬆️ Update CodSpeedHQ/action action to v4 @renovate[bot] (#17)