Drop support for Pydantic v1, keeping short temporary support for Pydantic v2's pydantic.v1 (#14575)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Sebastián Ramírez
2025-12-20 07:55:38 -08:00
committed by GitHub
parent 5c7dceb80f
commit e2cd8a4201
138 changed files with 1272 additions and 3658 deletions

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -45,7 +45,6 @@ def test_put(client: TestClient):
}
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
@@ -185,137 +184,3 @@ def test_openapi_schema(client: TestClient):
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Item",
"operationId": "read_item_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
}
],
},
"put": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
},
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -2,8 +2,6 @@ import importlib
from fastapi.testclient import TestClient
from ...utils import needs_pydanticv2
def get_client() -> TestClient:
from docs_src.conditional_openapi import tutorial001_py39
@@ -14,7 +12,6 @@ def get_client() -> TestClient:
return client
@needs_pydanticv2
def test_disable_openapi(monkeypatch):
monkeypatch.setenv("OPENAPI_URL", "")
# Load the client after setting the env var
@@ -27,7 +24,6 @@ def test_disable_openapi(monkeypatch):
assert response.status_code == 404, response.text
@needs_pydanticv2
def test_root():
client = get_client()
response = client.get("/")
@@ -35,7 +31,6 @@ def test_root():
assert response.json() == {"message": "Hello World"}
@needs_pydanticv2
def test_default_openapi():
client = get_client()
response = client.get("/docs")

View File

@@ -5,25 +5,16 @@ from dirty_equals import IsDict
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from tests.utils import (
needs_py310,
needs_pydanticv1,
needs_pydanticv2,
pydantic_snapshot,
)
from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39", marks=needs_pydanticv2),
pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]),
pytest.param("tutorial002_an_py39", marks=needs_pydanticv2),
pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]),
pytest.param("tutorial002_pv1_py39", marks=needs_pydanticv1),
pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]),
pytest.param("tutorial002_pv1_an_py39", marks=needs_pydanticv1),
pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]),
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=[needs_py310]),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=[needs_py310]),
],
)
def get_client(request: pytest.FixtureRequest):
@@ -62,31 +53,16 @@ def test_cookie_param_model_defaults(client: TestClient):
def test_cookie_param_model_invalid(client: TestClient):
response = client.get("/items/")
assert response.status_code == 422
assert response.json() == pydantic_snapshot(
v2=snapshot(
assert response.json() == {
"detail": [
{
"detail": [
{
"type": "missing",
"loc": ["cookie", "session_id"],
"msg": "Field required",
"input": {},
}
]
"type": "missing",
"loc": ["cookie", "session_id"],
"msg": "Field required",
"input": {},
}
),
v1=snapshot(
{
"detail": [
{
"type": "value_error.missing",
"loc": ["cookie", "session_id"],
"msg": "field required",
}
]
}
),
)
]
}
def test_cookie_param_model_extra(client: TestClient):
@@ -146,24 +122,13 @@ def test_openapi_schema(client: TestClient):
"name": "fatebook_tracker",
"in": "cookie",
"required": False,
"schema": pydantic_snapshot(
v2=snapshot(
{
"anyOf": [
{"type": "string"},
{"type": "null"},
],
"title": "Fatebook Tracker",
}
),
v1=snapshot(
# TODO: remove when deprecating Pydantic v1
{
"type": "string",
"title": "Fatebook Tracker",
}
),
),
"schema": {
"anyOf": [
{"type": "string"},
{"type": "null"},
],
"title": "Fatebook Tracker",
},
},
{
"name": "googall_tracker",

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -67,7 +67,6 @@ def test_get_authors(client: TestClient):
]
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
@@ -201,137 +200,3 @@ def test_openapi_schema(client: TestClient):
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/authors/{author_id}/items/": {
"post": {
"summary": "Create Author Items",
"operationId": "create_author_items_authors__author_id__items__post",
"parameters": [
{
"required": True,
"schema": {"title": "Author Id", "type": "string"},
"name": "author_id",
"in": "path",
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"title": "Items",
"type": "array",
"items": {"$ref": "#/components/schemas/Item"},
}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Author"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
},
"/authors/": {
"get": {
"summary": "Get Authors",
"operationId": "get_authors_authors__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"title": "Response Get Authors Authors Get",
"type": "array",
"items": {
"$ref": "#/components/schemas/Author"
},
}
}
},
}
},
}
},
},
"components": {
"schemas": {
"Author": {
"title": "Author",
"required": ["name"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"items": {
"title": "Items",
"type": "array",
"items": {"$ref": "#/components/schemas/Item"},
},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
"Item": {
"title": "Item",
"required": ["name"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {"title": "Description", "type": "string"},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
}
},
}

View File

@@ -5,20 +5,16 @@ from dirty_equals import IsDict
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from tests.utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39", marks=needs_pydanticv2),
pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]),
pytest.param("tutorial002_an_py39", marks=needs_pydanticv2),
pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]),
pytest.param("tutorial002_pv1_py39", marks=needs_pydanticv1),
pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]),
pytest.param("tutorial002_pv1_an_py39", marks=needs_pydanticv1),
pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]),
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=[needs_py310]),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=[needs_py310]),
],
)
def get_client(request: pytest.FixtureRequest):

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -35,7 +35,6 @@ def test_query_params_str_validations(client: TestClient):
}
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
@@ -135,100 +134,3 @@ def test_openapi_schema(client: TestClient):
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create an item",
"description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
"tax": {"title": "Tax", "type": "number"},
"tags": {
"title": "Tags",
"uniqueItems": True,
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -3,8 +3,6 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_pydanticv2
@pytest.fixture(
name="client",
@@ -21,7 +19,6 @@ def get_client(request: pytest.FixtureRequest):
return client
@needs_pydanticv2
def test_post(client: TestClient):
yaml_data = """
name: Deadpoolio
@@ -38,7 +35,6 @@ def test_post(client: TestClient):
}
@needs_pydanticv2
def test_post_broken_yaml(client: TestClient):
yaml_data = """
name: Deadpoolio
@@ -52,7 +48,6 @@ def test_post_broken_yaml(client: TestClient):
assert response.json() == {"detail": "Invalid YAML"}
@needs_pydanticv2
def test_post_invalid(client: TestClient):
yaml_data = """
name: Deadpoolio
@@ -77,7 +72,6 @@ def test_post_invalid(client: TestClient):
}
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -34,7 +34,6 @@ def test_query_params_str_validations(client: TestClient):
}
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
@@ -134,100 +133,3 @@ def test_openapi_schema(client: TestClient):
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"post": {
"responses": {
"200": {
"description": "The created item",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create an item",
"description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
"tax": {"title": "Tax", "type": "number"},
"tags": {
"title": "Tags",
"uniqueItems": True,
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -2,7 +2,6 @@ import sys
from typing import Any
import pytest
from fastapi._compat import PYDANTIC_V2
from tests.utils import skip_module_if_py_gte_314
@@ -10,13 +9,8 @@ if sys.version_info >= (3, 14):
skip_module_if_py_gte_314()
if not PYDANTIC_V2:
pytest.skip("This test is only for Pydantic v2", allow_module_level=True)
import importlib
import pytest
from ...utils import needs_py310

View File

@@ -1,7 +1,6 @@
import sys
import pytest
from fastapi._compat import PYDANTIC_V2
from inline_snapshot import snapshot
from tests.utils import skip_module_if_py_gte_314
@@ -10,12 +9,8 @@ if sys.version_info >= (3, 14):
skip_module_if_py_gte_314()
if not PYDANTIC_V2:
pytest.skip("This test is only for Pydantic v2", allow_module_level=True)
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310

View File

@@ -1,7 +1,6 @@
import sys
import pytest
from fastapi._compat import PYDANTIC_V2
from inline_snapshot import snapshot
from tests.utils import skip_module_if_py_gte_314
@@ -9,9 +8,6 @@ from tests.utils import skip_module_if_py_gte_314
if sys.version_info >= (3, 14):
skip_module_if_py_gte_314()
if not PYDANTIC_V2:
pytest.skip("This test is only for Pydantic v2", allow_module_level=True)
import importlib

View File

@@ -1,7 +1,6 @@
import sys
import pytest
from fastapi._compat import PYDANTIC_V2
from inline_snapshot import snapshot
from tests.utils import skip_module_if_py_gte_314
@@ -9,9 +8,6 @@ from tests.utils import skip_module_if_py_gte_314
if sys.version_info >= (3, 14):
skip_module_if_py_gte_314()
if not PYDANTIC_V2:
pytest.skip("This test is only for Pydantic v2", allow_module_level=True)
import importlib

View File

@@ -5,20 +5,16 @@ from dirty_equals import IsDict
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from tests.utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39", marks=needs_pydanticv2),
pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]),
pytest.param("tutorial002_an_py39", marks=needs_pydanticv2),
pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]),
pytest.param("tutorial002_pv1_py39", marks=needs_pydanticv1),
pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]),
pytest.param("tutorial002_pv1_an_py39", marks=needs_pydanticv1),
pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]),
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=[needs_py310]),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=[needs_py310]),
],
)
def get_client(request: pytest.FixtureRequest):

View File

@@ -5,14 +5,14 @@ from dirty_equals import IsStr
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from ...utils import needs_py310, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial015_an_py39", marks=needs_pydanticv2),
pytest.param("tutorial015_an_py310", marks=(needs_py310, needs_pydanticv2)),
pytest.param("tutorial015_an_py39"),
pytest.param("tutorial015_an_py310", marks=[needs_py310]),
],
)
def get_client(request: pytest.FixtureRequest):

View File

@@ -3,8 +3,6 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_pydanticv2
@pytest.fixture(
name="client",
@@ -20,14 +18,12 @@ def get_client(request: pytest.FixtureRequest):
return client
@needs_pydanticv2
def test_post_body_form(client: TestClient):
response = client.post("/login/", data={"username": "Foo", "password": "secret"})
assert response.status_code == 200
assert response.json() == {"username": "Foo", "password": "secret"}
@needs_pydanticv2
def test_post_body_extra_form(client: TestClient):
response = client.post(
"/login/", data={"username": "Foo", "password": "secret", "extra": "extra"}
@@ -45,7 +41,6 @@ def test_post_body_extra_form(client: TestClient):
}
@needs_pydanticv2
def test_post_body_form_no_password(client: TestClient):
response = client.post("/login/", data={"username": "Foo"})
assert response.status_code == 422
@@ -61,7 +56,6 @@ def test_post_body_form_no_password(client: TestClient):
}
@needs_pydanticv2
def test_post_body_form_no_username(client: TestClient):
response = client.post("/login/", data={"password": "secret"})
assert response.status_code == 422
@@ -77,7 +71,6 @@ def test_post_body_form_no_username(client: TestClient):
}
@needs_pydanticv2
def test_post_body_form_no_data(client: TestClient):
response = client.post("/login/")
assert response.status_code == 422
@@ -99,7 +92,6 @@ def test_post_body_form_no_data(client: TestClient):
}
@needs_pydanticv2
def test_post_body_json(client: TestClient):
response = client.post("/login/", json={"username": "Foo", "password": "secret"})
assert response.status_code == 422, response.text
@@ -121,7 +113,6 @@ def test_post_body_json(client: TestClient):
}
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -118,87 +118,3 @@ def test_post_body_json(client: TestClient):
},
]
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/login/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Login",
"operationId": "login_login__post",
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {"$ref": "#/components/schemas/FormData"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"FormData": {
"properties": {
"username": {"type": "string", "title": "Username"},
"password": {"type": "string", "title": "Password"},
},
"additionalProperties": False,
"type": "object",
"required": ["username", "password"],
"title": "FormData",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -37,7 +37,6 @@ def test_path_operation(client: TestClient):
}
@needs_pydanticv2
def test_openapi_schema_pv2(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
@@ -151,138 +150,3 @@ def test_openapi_schema_pv2(client: TestClient):
},
},
}
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"info": {
"title": "FastAPI",
"version": "0.1.0",
},
"openapi": "3.1.0",
"paths": {
"/items/{id}": {
"put": {
"operationId": "update_item_items__id__put",
"parameters": [
{
"in": "path",
"name": "id",
"required": True,
"schema": {
"title": "Id",
"type": "string",
},
},
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
},
},
},
"required": True,
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Update Item",
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"description": {
"title": "Description",
"type": "string",
},
"timestamp": {
"format": "date-time",
"title": "Timestamp",
"type": "string",
},
"title": {
"title": "Title",
"type": "string",
},
},
"required": [
"title",
"timestamp",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -20,7 +20,6 @@ def get_client(request: pytest.FixtureRequest):
return client
@needs_pydanticv2
def test_post_body_example(client: TestClient):
response = client.put(
"/items/5",
@@ -34,7 +33,6 @@ def test_post_body_example(client: TestClient):
assert response.status_code == 200
@needs_pydanticv2
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -2,6 +2,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from ...utils import needs_py310, needs_pydanticv1
@@ -38,98 +39,106 @@ def test_post_body_example(client: TestClient):
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
# insert_assert(response.json())
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"required": True,
"schema": {"type": "integer", "title": "Item Id"},
"name": "item_id",
"in": "path",
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
assert response.json() == snapshot(
{
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"required": True,
"schema": {"type": "integer", "title": "Item Id"},
"name": "item_id",
"in": "path",
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
"title": "Item",
"allOf": [
{"$ref": "#/components/schemas/Item"}
],
}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail",
}
},
"type": "object",
"title": "HTTPValidationError",
},
"Item": {
"properties": {
"name": {"type": "string", "title": "Name"},
"description": {"type": "string", "title": "Description"},
"price": {"type": "number", "title": "Price"},
"tax": {"type": "number", "title": "Tax"},
},
"type": "object",
"required": ["name", "price"],
"title": "Item",
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
"type": "array",
"title": "Location",
},
"msg": {"type": "string", "title": "Message"},
"type": {"type": "string", "title": "Error Type"},
},
"type": "object",
"required": ["loc", "msg", "type"],
"title": "ValidationError",
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {"$ref": "#/components/schemas/ValidationError"},
"type": "array",
"title": "Detail",
}
},
"type": "object",
"title": "HTTPValidationError",
},
"Item": {
"properties": {
"name": {"type": "string", "title": "Name"},
"description": {"type": "string", "title": "Description"},
"price": {"type": "number", "title": "Price"},
"tax": {"type": "number", "title": "Tax"},
},
"type": "object",
"required": ["name", "price"],
"title": "Item",
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
"type": "array",
"title": "Location",
},
"msg": {"type": "string", "title": "Message"},
"type": {"type": "string", "title": "Error Type"},
},
"type": "object",
"required": ["loc", "msg", "type"],
"title": "ValidationError",
},
}
},
}
},
}
)

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -38,7 +38,6 @@ def test_read_items(client: TestClient) -> None:
]
@needs_pydanticv2
def test_openapi_schema(client: TestClient) -> None:
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -3,7 +3,7 @@ import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310, needs_pydanticv2
from ...utils import needs_py310
@pytest.fixture(
@@ -38,7 +38,6 @@ def test_read_items(client: TestClient) -> None:
]
@needs_pydanticv2
def test_openapi_schema(client: TestClient) -> None:
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -4,8 +4,6 @@ from types import ModuleType
import pytest
from pytest import MonkeyPatch
from ...utils import needs_pydanticv2
@pytest.fixture(
name="mod_path",
@@ -31,7 +29,6 @@ def get_test_main_mod(mod_path: str) -> ModuleType:
return test_main_mod
@needs_pydanticv2
def test_settings(main_mod: ModuleType, monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
settings = main_mod.get_settings()
@@ -39,6 +36,5 @@ def test_settings(main_mod: ModuleType, monkeypatch: MonkeyPatch):
assert settings.items_per_user == 50
@needs_pydanticv2
def test_override_settings(test_main_mod: ModuleType):
test_main_mod.test_app()

View File

@@ -5,7 +5,7 @@ import pytest
from fastapi.testclient import TestClient
from pytest import MonkeyPatch
from ...utils import needs_pydanticv1, needs_pydanticv2
from ...utils import needs_pydanticv1
@pytest.fixture(
@@ -26,7 +26,6 @@ def get_main_mod(mod_path: str) -> ModuleType:
return main_mod
@needs_pydanticv2
def test_settings(main_mod: ModuleType, monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
settings = main_mod.get_settings()
@@ -45,7 +44,6 @@ def test_settings_pv1(mod_path: str, monkeypatch: MonkeyPatch):
assert settings.items_per_user == 50
@needs_pydanticv2
def test_endpoint(main_mod: ModuleType, monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
client = TestClient(main_mod.app)

View File

@@ -4,13 +4,13 @@ import pytest
from fastapi.testclient import TestClient
from pytest import MonkeyPatch
from ...utils import needs_pydanticv1, needs_pydanticv2
from ...utils import needs_pydanticv1
@pytest.fixture(
name="app",
params=[
pytest.param("tutorial001_py39", marks=needs_pydanticv2),
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_pv1_py39", marks=needs_pydanticv1),
],
)