Pydantic Canary
Pydantic Canary is an independent proof of concept. It runs one application contract against two Python environments, reports selected runtime behavior changes, and records which watched installations ran.
Install
pip install pydantic-canary
$ pydantic-canary check examples/regressions/instructor_partial_stream.py \
--inputs examples/inputs/instructor_stream.json \
--baseline pydantic==2.11.7 \
--candidate pydantic==2.12.0 \
--with instructor==1.9.2
BASELINE pydantic=2.11.7 @ .../site-packages/pydantic/__init__.py
CANDIDATE pydantic=2.12.0 @ .../site-packages/pydantic/__init__.py
CHANGED instructor_partial_stream: 1/2 inputs; first empty-initial-chunk: return {"value":null} -> ValidationError[missing]
The short form uses uv to create isolated, ephemeral environments. Existing
locked environments can be checked with --baseline-python and
--candidate-python instead. Requirement targets use the controller's Python
minor version by default. Pass --python-version to test another interpreter.
Canary never installs itself into either target.
This catches runtime drift that an API diff or JSON Schema comparison cannot
see. A case is a normal Python file with a JSON-compatible run() result:
from pydantic import BaseModel
class User(BaseModel):
age: int
def run():
return User.model_validate({"age": "42"}).model_dump(mode="json")
To replay real payloads, define run(value) and pass --inputs. The input file
can be a JSON array, a .jsonl or .ndjson file, or a Pydantic Evals JSON
dataset with a cases array. Evals case names and JSON Lines source line
numbers are preserved in the report. Canary hashes both the case and input
bytes and rejects a comparison if either changed between runs.
Exit code 0 means unchanged, 1 means behavior changed, and 2 means the capture was not trustworthy. A dependency-update job can therefore use the command as a direct CI gate.
Why another compatibility check?
Existing Pydantic gates solve different parts of an upgrade:
| Gate | What it proves |
|---|---|
| Griffe and API checks | Public names and signatures remain compatible |
JSON Schema snapshots and stable_pydantic |
Model contracts and stored schemas remain compatible |
bump-pydantic |
Source can be migrated from Pydantic V1 to V2 |
| Consumer test matrices | Full projects still pass their asserted tests |
| Pydantic Canary | Selected runtime behavior is unchanged across two exact environments |
Canary is a narrow gate before a dependency upgrade, not a replacement for a test suite. It is useful when the risky behavior is data-dependent, only partly asserted, or hidden behind validation and serialization internals.
Current evidence
The POC distinguishes three public regressions:
- strict mapping-key validation in Pydantic 2.10.6 versus 2.11.1
- modified
FieldInfodefaults in 2.11.7 versus 2.12.0 field_serializerwithserialize_as_any=Truein 2.11.9 versus 2.12.0
The FieldInfo case also runs through Instructor 1.9.2's public partial
streaming path. Under the same Python 3.12 interpreter and Instructor version,
one named payload returns a partial model on the baseline and raises Pydantic's
stable missing error type on the candidate. A complete-payload control remains
unchanged in the same run.
Canary also reports no change for identical and compatible patch environments, rejects missing watched packages, and stops a case that exceeds its timeout.
Limits
Canary does not run pytest or replace project tests. Input replay currently
accepts JSON and JSON Lines, not YAML. The receipt hashes the case and input files, but not
Python modules imported by the case. Run from an immutable revision when those
imports are part of the contract. --timeout covers environment setup and case
execution together.
Cases are trusted code. The subprocess boundary limits faults and enforces a timeout, but it is not a security sandbox. JSON receipts include local interpreter and module paths, so review them before sharing.
Development
The controller requires Python 3.10 or later and has no runtime dependencies. The worker is Python 3.9 compatible and does not need Canary installed in the target environments.
python -m venv .venv
.venv/bin/python -m pip install -e .
PYTHONPATH=src .venv/bin/python -m unittest discover -v
Release files for pydantic-canary 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pydantic_canary-0.1.1.tar.gz | 14.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pydantic_canary-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.0 kB
Release files / pydantic_canary-0.1.1.tar.gz
| Download URL | pydantic_canary-0.1.1.tar.gz |
|---|---|
| Size | 14.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5c6fad1be789bf2ec2d8b6f8e9ff636ae54e636236f96368037da3846e22066e
|
|
BLAKE2b-256 checksum How to use checksums |
beda2fa890421d71de901b95939c706c1504fc0efb341c6ce6c6316bd7dfb11d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency logRelease files / pydantic_canary-0.1.1-py3-none-any.whl
| Download URL | pydantic_canary-0.1.1-py3-none-any.whl |
|---|---|
| Size | 13.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85e063aef87d66565c1c70a29248a0828795731fc113a962af13b81284af5e05
|
|
BLAKE2b-256 checksum How to use checksums |
ab6a0ec2efc1e4d2dc11477d521874fbf125eceab17275d5b098f7b6efae8985
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency log