Skip to content

LITE-33583: Migrate to pydantic v2#128

Merged
pcaro merged 2 commits into
masterfrom
cr/LITE-33583-migrate-pydantic-v2
Jul 6, 2026
Merged

LITE-33583: Migrate to pydantic v2#128
pcaro merged 2 commits into
masterfrom
cr/LITE-33583-migrate-pydantic-v2

Conversation

@pcaro

@pcaro pcaro commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates connect-eaas-core from pydantic v1 to v2 (^2.9), resolving the v1 deprecation warnings that Python 3.13/3.14 emit — the follow-up flagged in #125.

Note: this re-lands the work from #127. That PR was merged into the #125 branch rather than master, and #125 reached master with only the Python 3.13/3.14 support, so the pydantic v2 changes never made it to master. This PR is the same three commits, rebased directly onto master.

Along the way it also widens the fastapi range and fixes a packaging gap that only surfaces once we run on pydantic v2.

Changes

pydantic v1 → v2

Models (proto.py, inject/models.py, validation/models.py)

  • Every Optional field gets an explicit = None default — in v2 Optional no longer implies a default, so these would otherwise become required and break deserialization.
  • Message.data (discriminated union incl. None) now defaults to None, so omitting it keeps working (e.g. shutdown messages).
  • BaseModel.__repr_args__ drops the removed pydantic.utils.DUNDER_ATTRIBUTES import and reads field metadata via type(self).model_fields. Sensitive-field obfuscation is unchanged.
  • self.dict()self.model_dump() (serialize); context.dict()context.model_dump().

Tests

  • v2 tightened BaseModel.__eq__ (a model no longer equals a plain dict), so schedulable/transformation assertions compare model_dump() output.
  • .dict().model_dump().

fastapi range: ^0.115.0>=0.115,<0.137

fastapi began requiring pydantic v2 at 0.128 (its pydantic floor jumped from >=1.7.4,<3 to >=2.7), so this wider range is only reachable now that we run on pydantic v2.

Capped below 0.137: that release replaced eager route flattening in include_router with a lazy _IncludedRouter placeholder in router.routes, which breaks WebApplicationBase.get_routers() (it assumes every entry is an APIRoute with .endpoint). Lifting the cap requires adapting that code to the new routing model and is tracked separately.

Declare typing-inspect

fastapi-utils 0.8.0's cbv module imports typing_inspect in its pydantic-2 code path but only declares it under its all extra. Migrating to pydantic 2 therefore makes importing connect-eaas-core crash with ModuleNotFoundError: typing_inspect for any consumer that doesn't already pull it in (e.g. connect-cli). Declared directly (matching fastapi-utils' own >=0.9,<0.10 range) rather than via fastapi-utils[all], which would also drag in pydantic-settings and sqlalchemy.

Verification

  • 368 passed, flake8 clean, on pydantic 2.13.4.
  • Validated at both ends of the fastapi range (0.115.x and 0.136.0).
  • Reproduced the typing_inspect crash from declared deps only, then confirmed the added dependency resolves it.
  • No pydantic deprecation warnings remain.

LITE-33583

@pcaro
pcaro marked this pull request as draft July 6, 2026 09:30
pcaro added 2 commits July 6, 2026 11:42
Move the codebase off pydantic v1 to v2, resolving the v1 deprecation
warnings emitted on Python 3.13/3.14 that were flagged as follow-up in
the 3.13/3.14 support work.

Model changes (proto.py, inject/models.py, validation/models.py):
- Give every Optional field an explicit '= None' default. In v2 an
  Optional annotation no longer implies a default, so these fields would
  otherwise become required and break deserialization.
- Message.data (a discriminated union including None) now defaults to
  None so omitting it keeps working (e.g. shutdown messages).
- BaseModel.__repr_args__ no longer imports the removed
  pydantic.utils.DUNDER_ATTRIBUTES and reads field metadata via
  type(self).model_fields; sensitive-field obfuscation is unchanged.
- self.dict() -> self.model_dump() in serialize(); context.dict() ->
  context.model_dump() in inject/common.py.

Tests: v2 tightened BaseModel.__eq__ (a model no longer compares equal
to a plain dict), so schedulable/transformation assertions now compare
model_dump() output; .dict() calls switched to .model_dump().

Dependencies:
- Require pydantic ^2.12 -- the first release whose pydantic-core
  (2.41.1+) ships cp314 wheels, so Python 3.14 installs a prebuilt wheel
  instead of failing to build pydantic-core from source.
- Declare typing-inspect directly: fastapi-utils 0.8.0's cbv module
  imports typing_inspect in its pydantic-2 code path but only declares
  it under its 'all' extra, so importing connect-eaas-core would crash
  with ModuleNotFoundError under pydantic 2.
- Regenerate poetry.lock (pydantic 2.13.4, pydantic-core 2.46.4,
  typing-inspect 0.9.0).
Allow fastapi 0.116-0.136 alongside pydantic v2. fastapi began requiring
pydantic v2 at 0.128 (its pydantic floor jumped from >=1.7.4,<3 to
>=2.7), so this range is only reachable now that we run on pydantic v2.

Capped below 0.137: that release replaced eager route flattening in
include_router with a lazy _IncludedRouter placeholder in router.routes,
which breaks WebApplicationBase.get_routers() (it assumes every entry is
an APIRoute with .endpoint). Lifting the cap requires adapting that code
to the new routing model and is tracked separately.
@pcaro
pcaro force-pushed the cr/LITE-33583-migrate-pydantic-v2 branch from 9fee745 to 4fc81cc Compare July 6, 2026 09:42
@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

@pcaro
pcaro marked this pull request as ready for review July 6, 2026 09:50
@qarlosh

qarlosh commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

to not lose track, #127 (comment): The Pydantic v2 migration should be released as a major version bump (38.0) rather than a minor one (37.x) to prevent breaking current extensions.

@pcaro
pcaro merged commit 324fb89 into master Jul 6, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants