⬆️ Increase lower bound to `pydantic >=2.9.0.` and fix the test suite (#15139)

Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com>
This commit is contained in:
Sofie Van Landeghem 2026-03-23 13:36:49 +01:00 committed by GitHub
parent 64feaec802
commit aeb9f4bb85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 102 additions and 39 deletions

View File

@ -102,6 +102,9 @@ jobs:
uv.lock
- name: Install Dependencies
run: uv sync --no-dev --group tests --extra all
- name: Ensure that we have the lowest supported Pydantic version
if: matrix.uv-resolution == 'lowest-direct'
run: uv pip install "pydantic==2.9.0"
- name: Install Starlette from source
if: matrix.starlette-src == 'starlette-git'
run: uv pip install "git+https://github.com/Kludex/starlette@main"

View File

@ -43,7 +43,7 @@ classifiers = [
]
dependencies = [
"starlette>=0.46.0",
"pydantic>=2.7.0",
"pydantic>=2.9.0",
"typing-extensions>=4.8.0",
"typing-inspection>=0.4.2",
"annotated-doc>=0.0.2",
@ -156,7 +156,7 @@ docs-tests = [
]
github-actions = [
"httpx >=0.27.0,<1.0.0",
"pydantic >=2.5.3,<3.0.0",
"pydantic >=2.9.0,<3.0.0",
"pydantic-settings >=2.1.0,<3.0.0",
"pygithub >=2.3.0,<3.0.0",
"pyyaml >=5.3.1,<7.0.0",

View File

@ -1,4 +1,5 @@
import pytest
from dirty_equals import IsOneOf
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@ -63,28 +64,58 @@ def test_openapi_schema(client: TestClient):
}
},
"components": {
"schemas": {
"PlatformRole": {
"type": "string",
"enum": ["admin", "user"],
"title": "PlatformRole",
},
"User": {
"properties": {
"username": {"type": "string", "title": "Username"},
"role": {
"anyOf": [
{"$ref": "#/components/schemas/PlatformRole"},
{"enum": [], "title": "OtherRole"},
],
"title": "Role",
},
"schemas": IsOneOf(
# Pydantic >= 2.11: no top-level OtherRole
{
"PlatformRole": {
"type": "string",
"enum": ["admin", "user"],
"title": "PlatformRole",
},
"User": {
"properties": {
"username": {"type": "string", "title": "Username"},
"role": {
"anyOf": [
{"$ref": "#/components/schemas/PlatformRole"},
{"enum": [], "title": "OtherRole"},
],
"title": "Role",
},
},
"type": "object",
"required": ["username", "role"],
"title": "User",
},
"type": "object",
"required": ["username", "role"],
"title": "User",
},
}
# Pydantic < 2.11: adds a top-level OtherRole schema
{
"OtherRole": {
"enum": [],
"title": "OtherRole",
},
"PlatformRole": {
"type": "string",
"enum": ["admin", "user"],
"title": "PlatformRole",
},
"User": {
"properties": {
"username": {"type": "string", "title": "Username"},
"role": {
"anyOf": [
{"$ref": "#/components/schemas/PlatformRole"},
{"enum": [], "title": "OtherRole"},
],
"title": "Role",
},
},
"type": "object",
"required": ["username", "role"],
"title": "User",
},
},
)
},
}
)

View File

@ -1,5 +1,6 @@
from typing import Annotated, Any, Literal
from dirty_equals import IsOneOf
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@ -88,11 +89,19 @@ def test_discriminator_pydantic_v2() -> None:
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": True,
"title": "Response Save Union Body Discriminator Items Post",
}
"schema": IsOneOf(
# Pydantic < 2.11: no additionalProperties
{
"type": "object",
"title": "Response Save Union Body Discriminator Items Post",
},
# Pydantic >= 2.11: has additionalProperties
{
"type": "object",
"additionalProperties": True,
"title": "Response Save Union Body Discriminator Items Post",
},
)
}
},
},
@ -114,11 +123,21 @@ def test_discriminator_pydantic_v2() -> None:
"schemas": {
"FirstItem": {
"properties": {
"value": {
"type": "string",
"const": "first",
"title": "Value",
},
"value": IsOneOf(
# Pydantic >= 2.10: const only
{
"type": "string",
"const": "first",
"title": "Value",
},
# Pydantic 2.9: const + enum
{
"type": "string",
"const": "first",
"enum": ["first"],
"title": "Value",
},
),
"price": {"type": "integer", "title": "Price"},
},
"type": "object",
@ -140,11 +159,21 @@ def test_discriminator_pydantic_v2() -> None:
},
"OtherItem": {
"properties": {
"value": {
"type": "string",
"const": "other",
"title": "Value",
},
"value": IsOneOf(
# Pydantic >= 2.10.0: const only
{
"type": "string",
"const": "other",
"title": "Value",
},
# Pydantic 2.9.x: const + enum
{
"type": "string",
"const": "other",
"enum": ["other"],
"title": "Value",
},
),
"price": {"type": "number", "title": "Price"},
},
"type": "object",

View File

@ -1252,7 +1252,7 @@ requires-dist = [
{ name = "jinja2", marker = "extra == 'all'", specifier = ">=3.1.5" },
{ name = "jinja2", marker = "extra == 'standard'", specifier = ">=3.1.5" },
{ name = "jinja2", marker = "extra == 'standard-no-fastapi-cloud-cli'", specifier = ">=3.1.5" },
{ name = "pydantic", specifier = ">=2.7.0" },
{ name = "pydantic", specifier = ">=2.9.0" },
{ name = "pydantic-extra-types", marker = "extra == 'all'", specifier = ">=2.0.0" },
{ name = "pydantic-extra-types", marker = "extra == 'standard'", specifier = ">=2.0.0" },
{ name = "pydantic-extra-types", marker = "extra == 'standard-no-fastapi-cloud-cli'", specifier = ">=2.0.0" },
@ -1350,7 +1350,7 @@ docs-tests = [
]
github-actions = [
{ name = "httpx", specifier = ">=0.27.0,<1.0.0" },
{ name = "pydantic", specifier = ">=2.5.3,<3.0.0" },
{ name = "pydantic", specifier = ">=2.9.0,<3.0.0" },
{ name = "pydantic-settings", specifier = ">=2.1.0,<3.0.0" },
{ name = "pygithub", specifier = ">=2.3.0,<3.0.0" },
{ name = "pyyaml", specifier = ">=5.3.1,<7.0.0" },