Browse Source

Enable Pydantic's serialization mode for responses, add support for Pydantic's `computed_field`, better OpenAPI for response models, proper required attributes, better generated clients (#10011)

*  Enable Pydantic's serialization mode for responses

*  Update tests with new Pydantic v2 serialization mode

*  Add a test for Pydantic v2's computed_field
pull/10012/head
Sebastián Ramírez 2 years ago
committed by GitHub
parent
commit
19a2c3bb54
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      fastapi/routing.py
  2. 77
      tests/test_computed_fields.py
  3. 8
      tests/test_filter_pydantic_sub_model_pv2.py
  4. 210
      tests/test_tutorial/test_body_updates/test_tutorial001.py
  5. 211
      tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
  6. 211
      tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
  7. 12
      tests/test_tutorial/test_dataclasses/test_tutorial002.py
  8. 185
      tests/test_tutorial/test_dataclasses/test_tutorial003.py
  9. 13
      tests/test_tutorial/test_extra_models/test_tutorial003.py
  10. 13
      tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
  11. 155
      tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
  12. 155
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
  13. 156
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
  14. 156
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
  15. 8
      tests/test_tutorial/test_response_model/test_tutorial003.py
  16. 8
      tests/test_tutorial/test_response_model/test_tutorial003_01.py
  17. 8
      tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py
  18. 8
      tests/test_tutorial/test_response_model/test_tutorial003_py310.py
  19. 8
      tests/test_tutorial/test_response_model/test_tutorial004.py
  20. 8
      tests/test_tutorial/test_response_model/test_tutorial004_py310.py
  21. 8
      tests/test_tutorial/test_response_model/test_tutorial004_py39.py
  22. 8
      tests/test_tutorial/test_response_model/test_tutorial005.py
  23. 8
      tests/test_tutorial/test_response_model/test_tutorial005_py310.py
  24. 8
      tests/test_tutorial/test_response_model/test_tutorial006.py
  25. 8
      tests/test_tutorial/test_response_model/test_tutorial006_py310.py
  26. 8
      tests/test_tutorial/test_security/test_tutorial005.py
  27. 8
      tests/test_tutorial/test_security/test_tutorial005_an.py
  28. 8
      tests/test_tutorial/test_security/test_tutorial005_an_py310.py
  29. 8
      tests/test_tutorial/test_security/test_tutorial005_an_py39.py
  30. 8
      tests/test_tutorial/test_security/test_tutorial005_py310.py
  31. 8
      tests/test_tutorial/test_security/test_tutorial005_py39.py

4
fastapi/routing.py

@ -448,9 +448,7 @@ class APIRoute(routing.Route):
self.response_field = create_response_field( self.response_field = create_response_field(
name=response_name, name=response_name,
type_=self.response_model, type_=self.response_model,
# TODO: This should actually set mode='serialization', just, that changes the schemas mode="serialization",
# mode="serialization",
mode="validation",
) )
# Create a clone of the field, so that a Pydantic submodel is not returned # Create a clone of the field, so that a Pydantic submodel is not returned
# as is just because it's an instance of a subclass of a more limited class # as is just because it's an instance of a subclass of a more limited class

77
tests/test_computed_fields.py

@ -0,0 +1,77 @@
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from .utils import needs_pydanticv2
@pytest.fixture(name="client")
def get_client():
app = FastAPI()
from pydantic import BaseModel, computed_field
class Rectangle(BaseModel):
width: int
length: int
@computed_field
@property
def area(self) -> int:
return self.width * self.length
@app.get("/")
def read_root() -> Rectangle:
return Rectangle(width=3, length=4)
client = TestClient(app)
return client
@needs_pydanticv2
def test_get(client: TestClient):
response = client.get("/")
assert response.status_code == 200, response.text
assert response.json() == {"width": 3, "length": 4, "area": 12}
@needs_pydanticv2
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": {
"/": {
"get": {
"summary": "Read Root",
"operationId": "read_root__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Rectangle"}
}
},
}
},
}
}
},
"components": {
"schemas": {
"Rectangle": {
"properties": {
"width": {"type": "integer", "title": "Width"},
"length": {"type": "integer", "title": "Length"},
"area": {"type": "integer", "title": "Area", "readOnly": True},
},
"type": "object",
"required": ["width", "length", "area"],
"title": "Rectangle",
}
}
},
}

8
tests/test_filter_pydantic_sub_model_pv2.py

@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
import pytest import pytest
from dirty_equals import HasRepr, IsDict from dirty_equals import HasRepr, IsDict, IsOneOf
from fastapi import Depends, FastAPI from fastapi import Depends, FastAPI
from fastapi.exceptions import ResponseValidationError from fastapi.exceptions import ResponseValidationError
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
@ -139,7 +139,11 @@ def test_openapi_schema(client: TestClient):
}, },
"ModelA": { "ModelA": {
"title": "ModelA", "title": "ModelA",
"required": ["name", "foo"], "required": IsOneOf(
["name", "description", "foo"],
# TODO remove when deprecating Pydantic v1
["name", "foo"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

210
tests/test_tutorial/test_body_updates/test_tutorial001.py

@ -1,7 +1,8 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
def get_client(): def get_client():
@ -36,7 +37,181 @@ def test_put(client: TestClient):
} }
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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": {
"/items/{item_id}": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ItemOutput"
}
}
},
},
"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/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
},
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"type": "object",
"properties": {
"name": {
"title": "Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"type": "object",
"required": ["name", "description", "price", "tax", "tags"],
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Name",
},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {
"anyOf": [{"type": "number"}, {"type": "null"}],
"title": "Price",
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -124,36 +299,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item", "title": "Item",
"type": "object", "type": "object",
"properties": { "properties": {
"name": IsDict( "name": {"title": "Name", "type": "string"},
{ "description": {"title": "Description", "type": "string"},
"title": "Name", "price": {"title": "Price", "type": "number"},
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Name", "type": "string"}
),
"description": IsDict(
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": IsDict(
{
"title": "Price",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Price", "type": "number"}
),
"tax": {"title": "Tax", "type": "number", "default": 10.5}, "tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": { "tags": {
"title": "Tags", "title": "Tags",

211
tests/test_tutorial/test_body_updates/test_tutorial001_py310.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -41,7 +40,182 @@ def test_put(client: TestClient):
@needs_py310 @needs_py310
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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": {
"/items/{item_id}": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ItemOutput"
}
}
},
},
"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/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
},
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"type": "object",
"properties": {
"name": {
"title": "Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"type": "object",
"required": ["name", "description", "price", "tax", "tags"],
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Name",
},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {
"anyOf": [{"type": "number"}, {"type": "null"}],
"title": "Price",
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_py310
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item", "title": "Item",
"type": "object", "type": "object",
"properties": { "properties": {
"name": IsDict( "name": {"title": "Name", "type": "string"},
{ "description": {"title": "Description", "type": "string"},
"title": "Name", "price": {"title": "Price", "type": "number"},
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Name", "type": "string"}
),
"description": IsDict(
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": IsDict(
{
"title": "Price",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Price", "type": "number"}
),
"tax": {"title": "Tax", "type": "number", "default": 10.5}, "tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": { "tags": {
"title": "Tags", "title": "Tags",

211
tests/test_tutorial/test_body_updates/test_tutorial001_py39.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -41,7 +40,182 @@ def test_put(client: TestClient):
@needs_py39 @needs_py39
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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": {
"/items/{item_id}": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ItemOutput"
}
}
},
},
"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/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
},
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"type": "object",
"properties": {
"name": {
"title": "Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"type": "object",
"required": ["name", "description", "price", "tax", "tags"],
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Name",
},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {
"anyOf": [{"type": "number"}, {"type": "null"}],
"title": "Price",
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_py39
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item", "title": "Item",
"type": "object", "type": "object",
"properties": { "properties": {
"name": IsDict( "name": {"title": "Name", "type": "string"},
{ "description": {"title": "Description", "type": "string"},
"title": "Name", "price": {"title": "Price", "type": "number"},
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Name", "type": "string"}
),
"description": IsDict(
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": IsDict(
{
"title": "Price",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Price", "type": "number"}
),
"tax": {"title": "Tax", "type": "number", "default": 10.5}, "tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": { "tags": {
"title": "Tags", "title": "Tags",

12
tests/test_tutorial/test_dataclasses/test_tutorial002.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial002 import app from docs_src.dataclasses.tutorial002 import app
@ -21,8 +21,7 @@ def test_get_item():
def test_openapi_schema(): def test_openapi_schema():
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200 assert response.status_code == 200
data = response.json() assert response.json() == {
assert data == {
"openapi": "3.1.0", "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"}, "info": {"title": "FastAPI", "version": "0.1.0"},
"paths": { "paths": {
@ -47,7 +46,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "price", "tags", "description", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
@ -57,7 +60,6 @@ def test_openapi_schema():
"title": "Tags", "title": "Tags",
"type": "array", "type": "array",
"items": {"type": "string"}, "items": {"type": "string"},
"default": [],
} }
) )
| IsDict( | IsDict(

185
tests/test_tutorial/test_dataclasses/test_tutorial003.py

@ -1,8 +1,9 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial003 import app from docs_src.dataclasses.tutorial003 import app
from ...utils import needs_pydanticv1, needs_pydanticv2
client = TestClient(app) client = TestClient(app)
@ -52,6 +53,7 @@ def test_get_authors():
] ]
@needs_pydanticv2
def test_openapi_schema(): def test_openapi_schema():
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200 assert response.status_code == 200
@ -77,7 +79,7 @@ def test_openapi_schema():
"schema": { "schema": {
"title": "Items", "title": "Items",
"type": "array", "type": "array",
"items": {"$ref": "#/components/schemas/Item"}, "items": {"$ref": "#/components/schemas/ItemInput"},
} }
} }
}, },
@ -132,26 +134,164 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Author": { "Author": {
"title": "Author", "title": "Author",
"required": ["name", "items"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"items": {
"title": "Items",
"type": "array",
"items": {"$ref": "#/components/schemas/ItemOutput"},
},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
"ItemInput": {
"title": "Item",
"required": ["name"], "required": ["name"],
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"items": IsDict( "description": {
{ "title": "Description",
"title": "Items", "anyOf": [{"type": "string"}, {"type": "null"}],
"type": "array", },
"items": {"$ref": "#/components/schemas/Item"}, },
"default": [], },
} "ItemOutput": {
) "title": "Item",
| IsDict( "required": ["name", "description"],
# TODO: remove when deprecating Pydantic v1 "type": "object",
{ "properties": {
"title": "Items", "name": {"title": "Name", "type": "string"},
"type": "array", "description": {
"items": {"$ref": "#/components/schemas/Item"}, "title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
},
"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"},
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1():
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": { "HTTPValidationError": {
@ -171,16 +311,7 @@ def test_openapi_schema():
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
}, },
}, },
"ValidationError": { "ValidationError": {

13
tests/test_tutorial/test_extra_models/test_tutorial003.py

@ -1,3 +1,4 @@
from dirty_equals import IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.extra_models.tutorial003 import app from docs_src.extra_models.tutorial003 import app
@ -76,7 +77,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"PlaneItem": { "PlaneItem": {
"title": "PlaneItem", "title": "PlaneItem",
"required": ["description", "size"], "required": IsOneOf(
["description", "type", "size"],
# TODO: remove when deprecating Pydantic v1
["description", "size"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},
@ -86,7 +91,11 @@ def test_openapi_schema():
}, },
"CarItem": { "CarItem": {
"title": "CarItem", "title": "CarItem",
"required": ["description"], "required": IsOneOf(
["description", "type"],
# TODO: remove when deprecating Pydantic v1
["description"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},

13
tests/test_tutorial/test_extra_models/test_tutorial003_py310.py

@ -1,4 +1,5 @@
import pytest import pytest
from dirty_equals import IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -86,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"PlaneItem": { "PlaneItem": {
"title": "PlaneItem", "title": "PlaneItem",
"required": ["description", "size"], "required": IsOneOf(
["description", "type", "size"],
# TODO: remove when deprecating Pydantic v1
["description", "size"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},
@ -96,7 +101,11 @@ def test_openapi_schema(client: TestClient):
}, },
"CarItem": { "CarItem": {
"title": "CarItem", "title": "CarItem",
"required": ["description"], "required": IsOneOf(
["description", "type"],
# TODO: remove when deprecating Pydantic v1
["description"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},

155
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py

@ -1,8 +1,9 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.path_operation_advanced_configuration.tutorial004 import app from docs_src.path_operation_advanced_configuration.tutorial004 import app
from ...utils import needs_pydanticv1, needs_pydanticv2
client = TestClient(app) client = TestClient(app)
@ -18,7 +19,137 @@ def test_query_params_str_validations():
} }
@needs_pydanticv2
def test_openapi_schema(): def test_openapi_schema():
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/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"uniqueItems": True,
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"required": ["name", "description", "price", "tax", "tags"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1():
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -69,27 +200,9 @@ def test_openapi_schema():
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

155
tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py

@ -1,8 +1,9 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.path_operation_configuration.tutorial005 import app from docs_src.path_operation_configuration.tutorial005 import app
from ...utils import needs_pydanticv1, needs_pydanticv2
client = TestClient(app) client = TestClient(app)
@ -18,7 +19,137 @@ def test_query_params_str_validations():
} }
@needs_pydanticv2
def test_openapi_schema(): def test_openapi_schema():
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/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"uniqueItems": True,
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"required": ["name", "description", "price", "tax", "tags"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_openapi_schema_pv1():
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -69,27 +200,9 @@ def test_openapi_schema():
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

156
tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
@needs_py310 @needs_py310
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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": {
"/items/": {
"post": {
"responses": {
"200": {
"description": "The created item",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"uniqueItems": True,
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"required": ["name", "description", "price", "tax", "tags"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_py310
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

156
tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
@needs_py39 @needs_py39
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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": {
"/items/": {
"post": {
"responses": {
"200": {
"description": "The created item",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ItemOutput"
}
}
},
},
"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/ItemInput"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"ItemInput": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"uniqueItems": True,
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ItemOutput": {
"title": "Item",
"required": ["name", "description", "price", "tax", "tags"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"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"},
}
},
},
}
},
}
# TODO: remove when deprecating Pydantic v1
@needs_py39
@needs_pydanticv1
def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

8
tests/test_tutorial/test_response_model/test_tutorial003.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.response_model.tutorial003 import app from docs_src.response_model.tutorial003 import app
@ -70,7 +70,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"UserOut": { "UserOut": {
"title": "UserOut", "title": "UserOut",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial003_01.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.response_model.tutorial003_01 import app from docs_src.response_model.tutorial003_01 import app
@ -70,7 +70,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"BaseUser": { "BaseUser": {
"title": "BaseUser", "title": "BaseUser",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"BaseUser": { "BaseUser": {
"title": "BaseUser", "title": "BaseUser",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial003_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"UserOut": { "UserOut": {
"title": "UserOut", "title": "UserOut",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial004.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.response_model.tutorial004 import app from docs_src.response_model.tutorial004 import app
@ -79,7 +79,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax", "tags"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial004_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax", "tags"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial004_py39.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39
@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax", "tags"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial005.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.response_model.tutorial005 import app from docs_src.response_model.tutorial005 import app
@ -102,7 +102,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial005_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial006.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.response_model.tutorial006 import app from docs_src.response_model.tutorial006 import app
@ -102,7 +102,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial006_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.security.tutorial005 import ( from docs_src.security.tutorial005 import (
@ -267,7 +267,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_an.py

@ -1,4 +1,4 @@
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.security.tutorial005_an import ( from docs_src.security.tutorial005_an import (
@ -267,7 +267,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_an_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_an_py39.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_py39.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

Loading…
Cancel
Save