From 842edf9f7377038f0e28395177d42b696e87d913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 20 Dec 2025 12:25:03 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Update=20tests=20and=20sou?= =?UTF-8?q?rce=20docs=20to=20not=20depend=20on=20Pydantic=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tutorial002_pv1_an_py310.py | 20 -- .../tutorial002_pv1_an_py39.py | 20 -- .../tutorial002_pv1_py310.py | 18 -- .../tutorial002_pv1_py39.py | 20 -- .../tutorial002_pv1_an_py310.py | 22 --- .../tutorial002_pv1_an_py39.py | 22 --- .../tutorial002_pv1_py310.py | 20 -- .../tutorial002_pv1_py39.py | 22 --- .../tutorial007_pv1_py39.py | 2 +- .../tutorial002_pv1_an_py310.py | 21 --- .../tutorial002_pv1_an_py39.py | 21 --- .../tutorial002_pv1_py310.py | 21 --- .../tutorial002_pv1_py39.py | 21 --- .../tutorial002_pv1_an_py39.py | 5 +- .../tutorial002_pv1_py39.py | 5 +- .../tutorial001_pv1_py310.py | 2 +- .../tutorial001_pv1_py39.py | 2 +- docs_src/settings/app03_an_py39/config_pv1.py | 2 +- docs_src/settings/app03_py39/config_pv1.py | 2 +- docs_src/settings/tutorial001_pv1_py39.py | 2 +- tests/test_datetime_custom_encoder.py | 3 +- .../test_filter_pydantic_sub_model/app_pv1.py | 2 +- ...t_get_model_definitions_formfeed_escape.py | 24 --- tests/test_inherited_custom_class.py | 3 +- tests/test_jsonable_encoder.py | 9 +- tests/test_read_with_orm_mode.py | 3 +- .../test_body_updates/test_tutorial001.py | 136 +------------- .../test_tutorial002.py | 5 - .../test_dataclasses/test_tutorial003.py | 134 +------------- .../test_tutorial002.py | 6 +- .../test_tutorial004.py | 99 +--------- .../test_tutorial005.py | 99 +--------- .../test_tutorial002.py | 6 +- .../test_tutorial002_pv1.py | 84 --------- .../test_tutorial001.py | 135 +------------- .../test_tutorial001_pv1.py | 171 +++++++++--------- tests/utils.py | 4 +- 37 files changed, 124 insertions(+), 1069 deletions(-) delete mode 100644 docs_src/cookie_param_models/tutorial002_pv1_an_py310.py delete mode 100644 docs_src/cookie_param_models/tutorial002_pv1_an_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial002_pv1_py310.py delete mode 100644 docs_src/cookie_param_models/tutorial002_pv1_py39.py delete mode 100644 docs_src/header_param_models/tutorial002_pv1_an_py310.py delete mode 100644 docs_src/header_param_models/tutorial002_pv1_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial002_pv1_py310.py delete mode 100644 docs_src/header_param_models/tutorial002_pv1_py39.py delete mode 100644 docs_src/query_param_models/tutorial002_pv1_an_py310.py delete mode 100644 docs_src/query_param_models/tutorial002_pv1_an_py39.py delete mode 100644 docs_src/query_param_models/tutorial002_pv1_py310.py delete mode 100644 docs_src/query_param_models/tutorial002_pv1_py39.py diff --git a/docs_src/cookie_param_models/tutorial002_pv1_an_py310.py b/docs_src/cookie_param_models/tutorial002_pv1_an_py310.py deleted file mode 100644 index ac00360b6..000000000 --- a/docs_src/cookie_param_models/tutorial002_pv1_an_py310.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Annotated - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - class Config: - extra = "forbid" - - session_id: str - fatebook_tracker: str | None = None - googall_tracker: str | None = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_pv1_an_py39.py b/docs_src/cookie_param_models/tutorial002_pv1_an_py39.py deleted file mode 100644 index 573caea4b..000000000 --- a/docs_src/cookie_param_models/tutorial002_pv1_an_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - class Config: - extra = "forbid" - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_pv1_py310.py b/docs_src/cookie_param_models/tutorial002_pv1_py310.py deleted file mode 100644 index 2c59aad12..000000000 --- a/docs_src/cookie_param_models/tutorial002_pv1_py310.py +++ /dev/null @@ -1,18 +0,0 @@ -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - class Config: - extra = "forbid" - - session_id: str - fatebook_tracker: str | None = None - googall_tracker: str | None = None - - -@app.get("/items/") -async def read_items(cookies: Cookies = Cookie()): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_pv1_py39.py b/docs_src/cookie_param_models/tutorial002_pv1_py39.py deleted file mode 100644 index 13f78b850..000000000 --- a/docs_src/cookie_param_models/tutorial002_pv1_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - class Config: - extra = "forbid" - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Cookies = Cookie()): - return cookies diff --git a/docs_src/header_param_models/tutorial002_pv1_an_py310.py b/docs_src/header_param_models/tutorial002_pv1_an_py310.py deleted file mode 100644 index e99e24ea5..000000000 --- a/docs_src/header_param_models/tutorial002_pv1_an_py310.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Annotated - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - class Config: - extra = "forbid" - - host: str - save_data: bool - if_modified_since: str | None = None - traceparent: str | None = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial002_pv1_an_py39.py b/docs_src/header_param_models/tutorial002_pv1_an_py39.py deleted file mode 100644 index 18398b726..000000000 --- a/docs_src/header_param_models/tutorial002_pv1_an_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - class Config: - extra = "forbid" - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial002_pv1_py310.py b/docs_src/header_param_models/tutorial002_pv1_py310.py deleted file mode 100644 index 3dbff9d7b..000000000 --- a/docs_src/header_param_models/tutorial002_pv1_py310.py +++ /dev/null @@ -1,20 +0,0 @@ -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - class Config: - extra = "forbid" - - host: str - save_data: bool - if_modified_since: str | None = None - traceparent: str | None = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial002_pv1_py39.py b/docs_src/header_param_models/tutorial002_pv1_py39.py deleted file mode 100644 index 86e19be0d..000000000 --- a/docs_src/header_param_models/tutorial002_pv1_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - class Config: - extra = "forbid" - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py b/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py index 831966553..849f648e1 100644 --- a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py +++ b/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py @@ -1,6 +1,6 @@ import yaml from fastapi import FastAPI, HTTPException, Request -from pydantic import BaseModel, ValidationError +from pydantic.v1 import BaseModel, ValidationError app = FastAPI() diff --git a/docs_src/query_param_models/tutorial002_pv1_an_py310.py b/docs_src/query_param_models/tutorial002_pv1_an_py310.py deleted file mode 100644 index d635aae88..000000000 --- a/docs_src/query_param_models/tutorial002_pv1_an_py310.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - class Config: - extra = "forbid" - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_pv1_an_py39.py b/docs_src/query_param_models/tutorial002_pv1_an_py39.py deleted file mode 100644 index d635aae88..000000000 --- a/docs_src/query_param_models/tutorial002_pv1_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - class Config: - extra = "forbid" - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_pv1_py310.py b/docs_src/query_param_models/tutorial002_pv1_py310.py deleted file mode 100644 index 9ffdeefc0..000000000 --- a/docs_src/query_param_models/tutorial002_pv1_py310.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - class Config: - extra = "forbid" - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_pv1_py39.py b/docs_src/query_param_models/tutorial002_pv1_py39.py deleted file mode 100644 index 9ffdeefc0..000000000 --- a/docs_src/query_param_models/tutorial002_pv1_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - class Config: - extra = "forbid" - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/request_form_models/tutorial002_pv1_an_py39.py b/docs_src/request_form_models/tutorial002_pv1_an_py39.py index 942d5d411..392e6873c 100644 --- a/docs_src/request_form_models/tutorial002_pv1_an_py39.py +++ b/docs_src/request_form_models/tutorial002_pv1_an_py39.py @@ -1,7 +1,8 @@ from typing import Annotated -from fastapi import FastAPI, Form -from pydantic import BaseModel +from fastapi import FastAPI +from fastapi.temp_pydantic_v1_params import Form +from pydantic.v1 import BaseModel app = FastAPI() diff --git a/docs_src/request_form_models/tutorial002_pv1_py39.py b/docs_src/request_form_models/tutorial002_pv1_py39.py index d5f7db2a6..da160b3a5 100644 --- a/docs_src/request_form_models/tutorial002_pv1_py39.py +++ b/docs_src/request_form_models/tutorial002_pv1_py39.py @@ -1,5 +1,6 @@ -from fastapi import FastAPI, Form -from pydantic import BaseModel +from fastapi import FastAPI +from fastapi.temp_pydantic_v1_params import Form +from pydantic.v1 import BaseModel app = FastAPI() diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py310.py b/docs_src/schema_extra_example/tutorial001_pv1_py310.py index ec83f1112..b13b8a8c2 100644 --- a/docs_src/schema_extra_example/tutorial001_pv1_py310.py +++ b/docs_src/schema_extra_example/tutorial001_pv1_py310.py @@ -1,5 +1,5 @@ from fastapi import FastAPI -from pydantic import BaseModel +from pydantic.v1 import BaseModel app = FastAPI() diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py39.py b/docs_src/schema_extra_example/tutorial001_pv1_py39.py index 6ab96ff85..3240b35d6 100644 --- a/docs_src/schema_extra_example/tutorial001_pv1_py39.py +++ b/docs_src/schema_extra_example/tutorial001_pv1_py39.py @@ -1,7 +1,7 @@ from typing import Union from fastapi import FastAPI -from pydantic import BaseModel +from pydantic.v1 import BaseModel app = FastAPI() diff --git a/docs_src/settings/app03_an_py39/config_pv1.py b/docs_src/settings/app03_an_py39/config_pv1.py index e1c3ee300..7ae66ef77 100644 --- a/docs_src/settings/app03_an_py39/config_pv1.py +++ b/docs_src/settings/app03_an_py39/config_pv1.py @@ -1,4 +1,4 @@ -from pydantic import BaseSettings +from pydantic.v1 import BaseSettings class Settings(BaseSettings): diff --git a/docs_src/settings/app03_py39/config_pv1.py b/docs_src/settings/app03_py39/config_pv1.py index e1c3ee300..7ae66ef77 100644 --- a/docs_src/settings/app03_py39/config_pv1.py +++ b/docs_src/settings/app03_py39/config_pv1.py @@ -1,4 +1,4 @@ -from pydantic import BaseSettings +from pydantic.v1 import BaseSettings class Settings(BaseSettings): diff --git a/docs_src/settings/tutorial001_pv1_py39.py b/docs_src/settings/tutorial001_pv1_py39.py index 0cfd1b663..20ad2bbf6 100644 --- a/docs_src/settings/tutorial001_pv1_py39.py +++ b/docs_src/settings/tutorial001_pv1_py39.py @@ -1,5 +1,5 @@ from fastapi import FastAPI -from pydantic import BaseSettings +from pydantic.v1 import BaseSettings class Settings(BaseSettings): diff --git a/tests/test_datetime_custom_encoder.py b/tests/test_datetime_custom_encoder.py index 3aa77c0b1..ed6aaa315 100644 --- a/tests/test_datetime_custom_encoder.py +++ b/tests/test_datetime_custom_encoder.py @@ -34,7 +34,8 @@ def test_pydanticv2(): # TODO: remove when deprecating Pydantic v1 @needs_pydanticv1 def test_pydanticv1(): - class ModelWithDatetimeField(BaseModel): + from pydantic import v1 + class ModelWithDatetimeField(v1.BaseModel): dt_field: datetime class Config: diff --git a/tests/test_filter_pydantic_sub_model/app_pv1.py b/tests/test_filter_pydantic_sub_model/app_pv1.py index 657e8c5d1..510d18436 100644 --- a/tests/test_filter_pydantic_sub_model/app_pv1.py +++ b/tests/test_filter_pydantic_sub_model/app_pv1.py @@ -1,7 +1,7 @@ from typing import Optional from fastapi import Depends, FastAPI -from pydantic import BaseModel, validator +from pydantic.v1 import BaseModel, validator app = FastAPI() diff --git a/tests/test_get_model_definitions_formfeed_escape.py b/tests/test_get_model_definitions_formfeed_escape.py index 215d06a07..3e34b392a 100644 --- a/tests/test_get_model_definitions_formfeed_escape.py +++ b/tests/test_get_model_definitions_formfeed_escape.py @@ -155,27 +155,3 @@ class SortedTypeSet(set): reverse=self.sort_reversed, ) yield from members_sorted - - -@needs_pydanticv1 -@pytest.mark.parametrize("sort_reversed", [True, False]) -def test_model_description_escaped_with_formfeed(sort_reversed: bool): - """ - Regression test for bug fixed by https://github.com/fastapi/fastapi/pull/6039. - - Test `get_model_definitions` with models passed in different order. - """ - from fastapi._compat import v1 - - all_fields = fastapi.openapi.utils.get_fields_from_routes(app.routes) - - flat_models = v1.get_flat_models_from_fields(all_fields, known_models=set()) - model_name_map = pydantic.schema.get_model_name_map(flat_models) - - expected_address_description = "This is a public description of an Address\n" - - models = v1.get_model_definitions( - flat_models=SortedTypeSet(flat_models, sort_reversed=sort_reversed), - model_name_map=model_name_map, - ) - assert models["Address"]["description"] == expected_address_description diff --git a/tests/test_inherited_custom_class.py b/tests/test_inherited_custom_class.py index fe9350f4e..f8a25cca0 100644 --- a/tests/test_inherited_custom_class.py +++ b/tests/test_inherited_custom_class.py @@ -73,6 +73,7 @@ def test_pydanticv2(): # TODO: remove when deprecating Pydantic v1 @needs_pydanticv1 def test_pydanticv1(): + from pydantic import v1 app = FastAPI() @app.get("/fast_uuid") @@ -84,7 +85,7 @@ def test_pydanticv1(): vars(asyncpg_uuid) return {"fast_uuid": asyncpg_uuid} - class SomeCustomClass(BaseModel): + class SomeCustomClass(v1.BaseModel): class Config: arbitrary_types_allowed = True json_encoders = {uuid.UUID: str} diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index 3b6513e27..45f756467 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -153,7 +153,8 @@ def test_encode_custom_json_encoders_model_pydanticv2(): # TODO: remove when deprecating Pydantic v1 @needs_pydanticv1 def test_encode_custom_json_encoders_model_pydanticv1(): - class ModelWithCustomEncoder(BaseModel): + from pydantic import v1 + class ModelWithCustomEncoder(v1.BaseModel): dt_field: datetime class Config: @@ -208,10 +209,11 @@ def test_encode_model_with_default(): @needs_pydanticv1 def test_custom_encoders(): + from pydantic import v1 class safe_datetime(datetime): pass - class MyModel(BaseModel): + class MyModel(v1.BaseModel): dt_field: safe_datetime instance = MyModel(dt_field=safe_datetime.now()) @@ -288,7 +290,8 @@ def test_encode_model_with_pure_windows_path(): @needs_pydanticv1 def test_encode_root(): - class ModelWithRoot(BaseModel): + from pydantic import v1 + class ModelWithRoot(v1.BaseModel): __root__: str model = ModelWithRoot(__root__="Foo") diff --git a/tests/test_read_with_orm_mode.py b/tests/test_read_with_orm_mode.py index b35987443..b5d251ae1 100644 --- a/tests/test_read_with_orm_mode.py +++ b/tests/test_read_with_orm_mode.py @@ -48,7 +48,8 @@ def test_read_with_orm_mode() -> None: @needs_pydanticv1 def test_read_with_orm_mode_pv1() -> None: - class PersonBase(BaseModel): + from pydantic import v1 + class PersonBase(v1.BaseModel): name: str lastname: str diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py index 8bbc4d699..1184ef248 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py @@ -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, needs_pydanticv2 @pytest.fixture( @@ -185,137 +185,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"}, - } - }, - }, - } - }, - } diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py index 4a826a537..b2b026021 100644 --- a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py @@ -7,7 +7,6 @@ from inline_snapshot import snapshot from tests.utils import ( needs_py310, - needs_pydanticv1, needs_pydanticv2, pydantic_snapshot, ) @@ -20,10 +19,6 @@ from tests.utils import ( 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]), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py index d8cc45dd6..45aa7e7f6 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -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, needs_pydanticv2 @pytest.fixture( @@ -203,135 +203,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"}, - }, - }, - } - }, - } diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial002.py b/tests/test_tutorial/test_header_param_models/test_tutorial002.py index a7a271ba4..889c8c065 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial002.py @@ -5,7 +5,7 @@ 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, needs_pydanticv2 @pytest.fixture( @@ -15,10 +15,6 @@ from tests.utils import needs_py310, needs_pydanticv1, 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]), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index 3805536e7..d302e0e9a 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -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, needs_pydanticv2 @pytest.fixture( @@ -135,100 +135,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"}, - } - }, - }, - } - }, - } diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py index 2a7a2b78b..fb92c340e 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py @@ -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, needs_pydanticv2 @pytest.fixture( @@ -134,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": "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"}, - } - }, - }, - } - }, - } diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial002.py b/tests/test_tutorial/test_query_param_models/test_tutorial002.py index e7de73f80..e8e043490 100644 --- a/tests/test_tutorial/test_query_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_query_param_models/test_tutorial002.py @@ -5,7 +5,7 @@ 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, needs_pydanticv2 @pytest.fixture( @@ -15,10 +15,6 @@ from tests.utils import needs_py310, needs_pydanticv1, 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]), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py b/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py index 41c7833be..9ab30086b 100644 --- a/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py +++ b/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py @@ -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"}, - } - }, - }, - } - }, - } diff --git a/tests/test_tutorial/test_response_directly/test_tutorial001.py b/tests/test_tutorial/test_response_directly/test_tutorial001.py index 127f0e4c1..f9d2dbf05 100644 --- a/tests/test_tutorial/test_response_directly/test_tutorial001.py +++ b/tests/test_tutorial/test_response_directly/test_tutorial001.py @@ -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, needs_pydanticv2 @pytest.fixture( @@ -153,136 +153,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", - }, - }, - }, - } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py index 552bb6697..605996289 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py @@ -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", - } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", }, - "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"}, + "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, + } + ], }, - "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"}] + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", }, - "type": "array", - "title": "Location", + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, }, - "msg": {"type": "string", "title": "Message"}, - "type": {"type": "string", "title": "Error Type"}, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", }, - "type": "object", - "required": ["loc", "msg", "type"], - "title": "ValidationError", - }, - } - }, - } + } + }, + } + ) diff --git a/tests/utils.py b/tests/utils.py index 691e92bbf..c284f34a8 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -9,10 +9,10 @@ needs_py310 = pytest.mark.skipif( sys.version_info < (3, 10), reason="requires python3.10+" ) needs_py_lt_314 = pytest.mark.skipif( - sys.version_info > (3, 13), reason="requires python3.13-" + sys.version_info >= (3, 14), reason="requires python3.13-" ) needs_pydanticv2 = pytest.mark.skipif(not PYDANTIC_V2, reason="requires Pydantic v2") -needs_pydanticv1 = pytest.mark.skipif(PYDANTIC_V2, reason="requires Pydantic v1") +needs_pydanticv1 = needs_py_lt_314 def skip_module_if_py_gte_314():