This note documents how we determined the lowest Pydantic 2.x version that
works across our supported Python versions (3.10–3.14) using uv and pytest.
It also records the final requirement change made to pyproject.toml.
- Identify the minimum Pydantic version that passes our test suite across Python 3.10, 3.11, 3.12, 3.13, and 3.14.
- Update our dependency constraint accordingly.
uvfor isolated environments, dependency resolution, and Python switchingpytestfor running the test suite
Rather than sweeping all versions linearly, we:
- Verified a recent upper bound (2.12.3), which we expected to pass.
- Probed an early lower bound (2.0.3), which failed on newer Pythons due to
pydantic-corebuild issues. - Bisected across representative releases (2.6.x, 2.9.x, 2.10.x, 2.11.x, 2.12.x) to locate the first version that passes on all supported Python versions.
uv can select a Python interpreter per run via --python:
uv run --isolated --python=3.12 --extra dev pytest -qThis aligns with our Makefile pattern for matrix testing.
Validate a recent upper bound:
# Pydantic 2.12.3 across all supported Pythons
for py in 3.10 3.11 3.12 3.13 3.14; do
echo "===> Python $py, pydantic 2.12.3"
uv run --isolated --python="$py" --extra dev --with 'pydantic==2.12.3' pytest -q
doneProbe an early lower bound:
# Pydantic 2.0.3 across all supported Pythons
for py in 3.10 3.11 3.12 3.13 3.14; do
echo "===> Python $py, pydantic 2.0.3"
uv run --isolated --python="$py" --extra dev --with 'pydantic==2.0.3' pytest -q
doneBinary cut over representative versions:
PY_VERSIONS=(3.10 3.11 3.12 3.13 3.14)
CANDIDATES=(2.6.4 2.9.2 2.10.6 2.11.10 2.12.0 2.12.3)
for v in "${CANDIDATES[@]}"; do
echo -e "\n=== pydantic $v across Pythons ==="
for py in "${PY_VERSIONS[@]}"; do
echo -n "Py ${py} pydantic ${v}: "
if uv run --isolated --python="$py" --extra dev --with "pydantic==${v}" pytest -q >/dev/null; then
echo PASS
else
echo FAIL
fi
done
doneSanity probe to print versions:
import sys, pydantic
print(sys.version.split()[0], 'pydantic', pydantic.__version__)
try:
import pydantic_core
print('pydantic_core', pydantic_core.__version__)
except Exception as e:
print('pydantic_core import failed:', e)- 2.12.3: PASS on 3.10, 3.11, 3.12, 3.13, 3.14
- 2.12.0: PASS on 3.10, 3.11, 3.12, 3.13, 3.14
- 2.11.10: PASS on 3.10–3.13, FAIL on 3.14 (pydantic-core via PyO3 blocks 3.14)
- 2.10.6: PASS on 3.10–3.13, FAIL on 3.14
- 2.9.2: PASS on 3.10–3.13, FAIL on 3.14
- 2.6.4: PASS on 3.10–3.12, FAIL on 3.13–3.14
- 2.0.3: PASS on 3.10–3.12, FAIL on 3.13–3.14
Root cause for pre-2.12 failures on Python 3.14:
- Older
pydantic-corereleases lack cp314 wheels and fall back to native builds with PyO3 versions that reject Python 3.14 at build time. - Pydantic 2.12.x provides compatibility/wheels for 3.14.
- Minimum supported pydantic version: 2.12.0 (covers Python 3.10–3.14)
pyproject.tomlupdated to:
[project]
dependencies = [
"pydantic>=2.12.0",
]If we ever restrict our Python range to ≤3.13, the minimum could be relaxed to
>=2.9.2; however, with 3.14 in scope, >=2.12.0 is required.