Browse Source

♻️ Update tests and source docs to not depend on Pydantic v1

pull/14575/head
Sebastián Ramírez 7 months ago
parent
commit
842edf9f73
  1. 20
      docs_src/cookie_param_models/tutorial002_pv1_an_py310.py
  2. 20
      docs_src/cookie_param_models/tutorial002_pv1_an_py39.py
  3. 18
      docs_src/cookie_param_models/tutorial002_pv1_py310.py
  4. 20
      docs_src/cookie_param_models/tutorial002_pv1_py39.py
  5. 22
      docs_src/header_param_models/tutorial002_pv1_an_py310.py
  6. 22
      docs_src/header_param_models/tutorial002_pv1_an_py39.py
  7. 20
      docs_src/header_param_models/tutorial002_pv1_py310.py
  8. 22
      docs_src/header_param_models/tutorial002_pv1_py39.py
  9. 2
      docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py
  10. 21
      docs_src/query_param_models/tutorial002_pv1_an_py310.py
  11. 21
      docs_src/query_param_models/tutorial002_pv1_an_py39.py
  12. 21
      docs_src/query_param_models/tutorial002_pv1_py310.py
  13. 21
      docs_src/query_param_models/tutorial002_pv1_py39.py
  14. 5
      docs_src/request_form_models/tutorial002_pv1_an_py39.py
  15. 5
      docs_src/request_form_models/tutorial002_pv1_py39.py
  16. 2
      docs_src/schema_extra_example/tutorial001_pv1_py310.py
  17. 2
      docs_src/schema_extra_example/tutorial001_pv1_py39.py
  18. 2
      docs_src/settings/app03_an_py39/config_pv1.py
  19. 2
      docs_src/settings/app03_py39/config_pv1.py
  20. 2
      docs_src/settings/tutorial001_pv1_py39.py
  21. 3
      tests/test_datetime_custom_encoder.py
  22. 2
      tests/test_filter_pydantic_sub_model/app_pv1.py
  23. 24
      tests/test_get_model_definitions_formfeed_escape.py
  24. 3
      tests/test_inherited_custom_class.py
  25. 9
      tests/test_jsonable_encoder.py
  26. 3
      tests/test_read_with_orm_mode.py
  27. 136
      tests/test_tutorial/test_body_updates/test_tutorial001.py
  28. 5
      tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
  29. 134
      tests/test_tutorial/test_dataclasses/test_tutorial003.py
  30. 6
      tests/test_tutorial/test_header_param_models/test_tutorial002.py
  31. 99
      tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
  32. 99
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
  33. 6
      tests/test_tutorial/test_query_param_models/test_tutorial002.py
  34. 84
      tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py
  35. 135
      tests/test_tutorial/test_response_directly/test_tutorial001.py
  36. 171
      tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py
  37. 4
      tests/utils.py

20
docs_src/cookie_param_models/tutorial002_pv1_an_py310.py

@ -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

20
docs_src/cookie_param_models/tutorial002_pv1_an_py39.py

@ -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

18
docs_src/cookie_param_models/tutorial002_pv1_py310.py

@ -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

20
docs_src/cookie_param_models/tutorial002_pv1_py39.py

@ -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

22
docs_src/header_param_models/tutorial002_pv1_an_py310.py

@ -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

22
docs_src/header_param_models/tutorial002_pv1_an_py39.py

@ -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

20
docs_src/header_param_models/tutorial002_pv1_py310.py

@ -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

22
docs_src/header_param_models/tutorial002_pv1_py39.py

@ -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

2
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()

21
docs_src/query_param_models/tutorial002_pv1_an_py310.py

@ -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

21
docs_src/query_param_models/tutorial002_pv1_an_py39.py

@ -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

21
docs_src/query_param_models/tutorial002_pv1_py310.py

@ -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

21
docs_src/query_param_models/tutorial002_pv1_py39.py

@ -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

5
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()

5
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()

2
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()

2
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()

2
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):

2
docs_src/settings/app03_py39/config_pv1.py

@ -1,4 +1,4 @@
from pydantic import BaseSettings
from pydantic.v1 import BaseSettings
class Settings(BaseSettings):

2
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):

3
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:

2
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()

24
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

3
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}

9
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")

3
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

136
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"},
}
},
},
}
},
}

5
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):

134
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"},
},
},
}
},
}

6
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):

99
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"},
}
},
},
}
},
}

99
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"},
}
},
},
}
},
}

6
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):

84
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"},
}
},
},
}
},
}

135
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",
},
},
},
}

171
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",
},
}
},
}
}
},
}
)

4
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():

Loading…
Cancel
Save