mirror of https://github.com/tiangolo/fastapi.git
✨ 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
This commit is contained in:
parent
d943e02232
commit
19a2c3bb54
|
|
@ -448,9 +448,7 @@ class APIRoute(routing.Route):
|
|||
self.response_field = create_response_field(
|
||||
name=response_name,
|
||||
type_=self.response_model,
|
||||
# TODO: This should actually set mode='serialization', just, that changes the schemas
|
||||
# mode="serialization",
|
||||
mode="validation",
|
||||
mode="serialization",
|
||||
)
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from dirty_equals import HasRepr, IsDict
|
||||
from dirty_equals import HasRepr, IsDict, IsOneOf
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.exceptions import ResponseValidationError
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -139,7 +139,11 @@ def test_openapi_schema(client: TestClient):
|
|||
},
|
||||
"ModelA": {
|
||||
"title": "ModelA",
|
||||
"required": ["name", "foo"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "foo"],
|
||||
# TODO remove when deprecating Pydantic v1
|
||||
["name", "foo"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
|
|
@ -36,7 +37,181 @@ def test_put(client: TestClient):
|
|||
}
|
||||
|
||||
|
||||
@needs_pydanticv2
|
||||
def test_openapi_schema(client: TestClient):
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -124,36 +299,9 @@ def test_openapi_schema(client: TestClient):
|
|||
"title": "Item",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": IsDict(
|
||||
{
|
||||
"title": "Name",
|
||||
"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"}
|
||||
),
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
|
|
@ -41,7 +40,182 @@ def test_put(client: TestClient):
|
|||
|
||||
|
||||
@needs_py310
|
||||
@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": {
|
||||
"/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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
|
|||
"title": "Item",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": IsDict(
|
||||
{
|
||||
"title": "Name",
|
||||
"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"}
|
||||
),
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
|
|
@ -41,7 +40,182 @@ def test_put(client: TestClient):
|
|||
|
||||
|
||||
@needs_py39
|
||||
@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": {
|
||||
"/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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
|
|||
"title": "Item",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": IsDict(
|
||||
{
|
||||
"title": "Name",
|
||||
"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"}
|
||||
),
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.dataclasses.tutorial002 import app
|
||||
|
|
@ -21,8 +21,7 @@ def test_get_item():
|
|||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data == {
|
||||
assert response.json() == {
|
||||
"openapi": "3.1.0",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
|
|
@ -47,7 +46,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "price", "tags", "description", "tax"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
@ -57,7 +60,6 @@ def test_openapi_schema():
|
|||
"title": "Tags",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"default": [],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.dataclasses.tutorial003 import app
|
||||
|
||||
from ...utils import needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
|
|
@ -52,7 +53,157 @@ def test_get_authors():
|
|||
]
|
||||
|
||||
|
||||
@needs_pydanticv2
|
||||
def test_openapi_schema():
|
||||
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/ItemInput"},
|
||||
}
|
||||
}
|
||||
},
|
||||
"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", "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"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": {
|
||||
"title": "Description",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
},
|
||||
},
|
||||
},
|
||||
"ItemOutput": {
|
||||
"title": "Item",
|
||||
"required": ["name", "description"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": {
|
||||
"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() == {
|
||||
|
|
@ -136,22 +287,11 @@ def test_openapi_schema():
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"items": IsDict(
|
||||
{
|
||||
"title": "Items",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/Item"},
|
||||
"default": [],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{
|
||||
"title": "Items",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/Item"},
|
||||
}
|
||||
),
|
||||
"items": {
|
||||
"title": "Items",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/Item"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
|
|
@ -171,16 +311,7 @@ def test_openapi_schema():
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": IsDict(
|
||||
{
|
||||
"title": "Description",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Description", "type": "string"}
|
||||
),
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
},
|
||||
},
|
||||
"ValidationError": {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from dirty_equals import IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.extra_models.tutorial003 import app
|
||||
|
|
@ -76,7 +77,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"PlaneItem": {
|
||||
"title": "PlaneItem",
|
||||
"required": ["description", "size"],
|
||||
"required": IsOneOf(
|
||||
["description", "type", "size"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["description", "size"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
|
|
@ -86,7 +91,11 @@ def test_openapi_schema():
|
|||
},
|
||||
"CarItem": {
|
||||
"title": "CarItem",
|
||||
"required": ["description"],
|
||||
"required": IsOneOf(
|
||||
["description", "type"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["description"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -86,7 +87,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"PlaneItem": {
|
||||
"title": "PlaneItem",
|
||||
"required": ["description", "size"],
|
||||
"required": IsOneOf(
|
||||
["description", "type", "size"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["description", "size"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
|
|
@ -96,7 +101,11 @@ def test_openapi_schema(client: TestClient):
|
|||
},
|
||||
"CarItem": {
|
||||
"title": "CarItem",
|
||||
"required": ["description"],
|
||||
"required": IsOneOf(
|
||||
["description", "type"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["description"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.path_operation_advanced_configuration.tutorial004 import app
|
||||
|
||||
from ...utils import needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
|
|
@ -18,7 +19,137 @@ def test_query_params_str_validations():
|
|||
}
|
||||
|
||||
|
||||
@needs_pydanticv2
|
||||
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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -69,27 +200,9 @@ def test_openapi_schema():
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": IsDict(
|
||||
{
|
||||
"title": "Description",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Description", "type": "string"}
|
||||
),
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
"price": {"title": "Price", "type": "number"},
|
||||
"tax": IsDict(
|
||||
{
|
||||
"title": "Tax",
|
||||
"anyOf": [{"type": "number"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Tax", "type": "number"}
|
||||
),
|
||||
"tax": {"title": "Tax", "type": "number"},
|
||||
"tags": {
|
||||
"title": "Tags",
|
||||
"uniqueItems": True,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.path_operation_configuration.tutorial005 import app
|
||||
|
||||
from ...utils import needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
|
|
@ -18,7 +19,137 @@ def test_query_params_str_validations():
|
|||
}
|
||||
|
||||
|
||||
@needs_pydanticv2
|
||||
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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -69,27 +200,9 @@ def test_openapi_schema():
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": IsDict(
|
||||
{
|
||||
"title": "Description",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Description", "type": "string"}
|
||||
),
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
"price": {"title": "Price", "type": "number"},
|
||||
"tax": IsDict(
|
||||
{
|
||||
"title": "Tax",
|
||||
"anyOf": [{"type": "number"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Tax", "type": "number"}
|
||||
),
|
||||
"tax": {"title": "Tax", "type": "number"},
|
||||
"tags": {
|
||||
"title": "Tags",
|
||||
"uniqueItems": True,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
|
|
@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
|
|||
|
||||
|
||||
@needs_py310
|
||||
@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": {
|
||||
"/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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": IsDict(
|
||||
{
|
||||
"title": "Description",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Description", "type": "string"}
|
||||
),
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
"price": {"title": "Price", "type": "number"},
|
||||
"tax": IsDict(
|
||||
{
|
||||
"title": "Tax",
|
||||
"anyOf": [{"type": "number"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Tax", "type": "number"}
|
||||
),
|
||||
"tax": {"title": "Tax", "type": "number"},
|
||||
"tags": {
|
||||
"title": "Tags",
|
||||
"uniqueItems": True,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
|
|
@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
|
|||
|
||||
|
||||
@needs_py39
|
||||
@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": {
|
||||
"/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")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
|
|
@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
"description": IsDict(
|
||||
{
|
||||
"title": "Description",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Description", "type": "string"}
|
||||
),
|
||||
"description": {"title": "Description", "type": "string"},
|
||||
"price": {"title": "Price", "type": "number"},
|
||||
"tax": IsDict(
|
||||
{
|
||||
"title": "Tax",
|
||||
"anyOf": [{"type": "number"}, {"type": "null"}],
|
||||
}
|
||||
)
|
||||
| IsDict(
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
{"title": "Tax", "type": "number"}
|
||||
),
|
||||
"tax": {"title": "Tax", "type": "number"},
|
||||
"tags": {
|
||||
"title": "Tags",
|
||||
"uniqueItems": True,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial003 import app
|
||||
|
|
@ -70,7 +70,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"UserOut": {
|
||||
"title": "UserOut",
|
||||
"required": ["username", "email"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username", "email"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial003_01 import app
|
||||
|
|
@ -70,7 +70,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"BaseUser": {
|
||||
"title": "BaseUser",
|
||||
"required": ["username", "email"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username", "email"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"BaseUser": {
|
||||
"title": "BaseUser",
|
||||
"required": ["username", "email"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username", "email"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"UserOut": {
|
||||
"title": "UserOut",
|
||||
"required": ["username", "email"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username", "email"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial004 import app
|
||||
|
|
@ -79,7 +79,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax", "tags"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax", "tags"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
|
|
@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax", "tags"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial005 import app
|
||||
|
|
@ -102,7 +102,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial006 import app
|
||||
|
|
@ -102,7 +102,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": ["name", "price"],
|
||||
"required": IsOneOf(
|
||||
["name", "description", "price", "tax"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["name", "price"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"title": "Name", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.security.tutorial005 import (
|
||||
|
|
@ -267,7 +267,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"User": {
|
||||
"title": "User",
|
||||
"required": ["username"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name", "disabled"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.security.tutorial005_an import (
|
||||
|
|
@ -267,7 +267,11 @@ def test_openapi_schema():
|
|||
"schemas": {
|
||||
"User": {
|
||||
"title": "User",
|
||||
"required": ["username"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name", "disabled"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"User": {
|
||||
"title": "User",
|
||||
"required": ["username"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name", "disabled"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
|
|
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"User": {
|
||||
"title": "User",
|
||||
"required": ["username"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name", "disabled"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
|
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"User": {
|
||||
"title": "User",
|
||||
"required": ["username"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name", "disabled"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from dirty_equals import IsDict
|
||||
from dirty_equals import IsDict, IsOneOf
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
|
|
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
|
|||
"schemas": {
|
||||
"User": {
|
||||
"title": "User",
|
||||
"required": ["username"],
|
||||
"required": IsOneOf(
|
||||
["username", "email", "full_name", "disabled"],
|
||||
# TODO: remove when deprecating Pydantic v1
|
||||
["username"],
|
||||
),
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
|
|
|
|||
Loading…
Reference in New Issue