25 changed files with 9 additions and 6527 deletions
File diff suppressed because it is too large
@ -1,45 +0,0 @@ |
|||
import warnings |
|||
from typing import Optional |
|||
|
|||
from fastapi import Depends, FastAPI |
|||
from pydantic.v1 import BaseModel, validator |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class ModelB(BaseModel): |
|||
username: str |
|||
|
|||
|
|||
class ModelC(ModelB): |
|||
password: str |
|||
|
|||
|
|||
class ModelA(BaseModel): |
|||
name: str |
|||
description: Optional[str] = None |
|||
model_b: ModelB |
|||
tags: dict[str, str] = {} |
|||
|
|||
@validator("name") |
|||
def lower_username(cls, name: str, values): |
|||
if not name.endswith("A"): |
|||
raise ValueError("name must end in A") |
|||
return name |
|||
|
|||
|
|||
async def get_model_c() -> ModelC: |
|||
return ModelC(username="test-user", password="test-password") |
|||
|
|||
|
|||
with warnings.catch_warnings(record=True): |
|||
warnings.simplefilter("always") |
|||
|
|||
@app.get("/model/{name}", response_model=ModelA) |
|||
async def get_model_a(name: str, model_c=Depends(get_model_c)): |
|||
return { |
|||
"name": name, |
|||
"description": "model-a-desc", |
|||
"model_b": model_c, |
|||
"tags": {"key1": "value1", "key2": "value2"}, |
|||
} |
|||
@ -1,146 +0,0 @@ |
|||
import pytest |
|||
from fastapi.exceptions import ResponseValidationError |
|||
from fastapi.testclient import TestClient |
|||
from inline_snapshot import snapshot |
|||
|
|||
from ..utils import needs_pydanticv1 |
|||
|
|||
|
|||
@pytest.fixture(name="client") |
|||
def get_client(): |
|||
from .app_pv1 import app |
|||
|
|||
client = TestClient(app) |
|||
return client |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_filter_sub_model(client: TestClient): |
|||
response = client.get("/model/modelA") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"name": "modelA", |
|||
"description": "model-a-desc", |
|||
"model_b": {"username": "test-user"}, |
|||
"tags": {"key1": "value1", "key2": "value2"}, |
|||
} |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_validator_is_cloned(client: TestClient): |
|||
with pytest.raises(ResponseValidationError) as err: |
|||
client.get("/model/modelX") |
|||
assert err.value.errors() == [ |
|||
{ |
|||
"loc": ("response", "name"), |
|||
"msg": "name must end in A", |
|||
"type": "value_error", |
|||
} |
|||
] |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_openapi_schema(client: TestClient): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/model/{name}": { |
|||
"get": { |
|||
"summary": "Get Model A", |
|||
"operationId": "get_model_a_model__name__get", |
|||
"parameters": [ |
|||
{ |
|||
"required": True, |
|||
"schema": {"title": "Name", "type": "string"}, |
|||
"name": "name", |
|||
"in": "path", |
|||
} |
|||
], |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/ModelA" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
} |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"title": "HTTPValidationError", |
|||
"type": "object", |
|||
"properties": { |
|||
"detail": { |
|||
"title": "Detail", |
|||
"type": "array", |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
"ModelA": { |
|||
"title": "ModelA", |
|||
"required": ["name", "model_b"], |
|||
"type": "object", |
|||
"properties": { |
|||
"name": {"title": "Name", "type": "string"}, |
|||
"description": {"title": "Description", "type": "string"}, |
|||
"model_b": {"$ref": "#/components/schemas/ModelB"}, |
|||
"tags": { |
|||
"additionalProperties": {"type": "string"}, |
|||
"type": "object", |
|||
"title": "Tags", |
|||
"default": {}, |
|||
}, |
|||
}, |
|||
}, |
|||
"ModelB": { |
|||
"title": "ModelB", |
|||
"required": ["username"], |
|||
"type": "object", |
|||
"properties": { |
|||
"username": {"title": "Username", "type": "string"} |
|||
}, |
|||
}, |
|||
"ValidationError": { |
|||
"title": "ValidationError", |
|||
"required": ["loc", "msg", "type"], |
|||
"type": "object", |
|||
"properties": { |
|||
"loc": { |
|||
"title": "Location", |
|||
"type": "array", |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
}, |
|||
"msg": {"title": "Message", "type": "string"}, |
|||
"type": {"title": "Error Type", "type": "string"}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
@ -1,439 +0,0 @@ |
|||
import sys |
|||
import warnings |
|||
from typing import Any, Union |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
from fastapi import FastAPI |
|||
from fastapi._compat.v1 import BaseModel |
|||
from fastapi.testclient import TestClient |
|||
from inline_snapshot import snapshot |
|||
|
|||
|
|||
class SubItem(BaseModel): |
|||
name: str |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
title: str |
|||
size: int |
|||
description: Union[str, None] = None |
|||
sub: SubItem |
|||
multi: list[SubItem] = [] |
|||
|
|||
|
|||
app = FastAPI() |
|||
|
|||
with warnings.catch_warnings(record=True): |
|||
warnings.simplefilter("always") |
|||
|
|||
@app.post("/simple-model") |
|||
def handle_simple_model(data: SubItem) -> SubItem: |
|||
return data |
|||
|
|||
@app.post("/simple-model-filter", response_model=SubItem) |
|||
def handle_simple_model_filter(data: SubItem) -> Any: |
|||
extended_data = data.dict() |
|||
extended_data.update({"secret_price": 42}) |
|||
return extended_data |
|||
|
|||
@app.post("/item") |
|||
def handle_item(data: Item) -> Item: |
|||
return data |
|||
|
|||
@app.post("/item-filter", response_model=Item) |
|||
def handle_item_filter(data: Item) -> Any: |
|||
extended_data = data.dict() |
|||
extended_data.update({"secret_data": "classified", "internal_id": 12345}) |
|||
extended_data["sub"].update({"internal_id": 67890}) |
|||
return extended_data |
|||
|
|||
|
|||
client = TestClient(app) |
|||
|
|||
|
|||
def test_old_simple_model(): |
|||
response = client.post( |
|||
"/simple-model", |
|||
json={"name": "Foo"}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == {"name": "Foo"} |
|||
|
|||
|
|||
def test_old_simple_model_validation_error(): |
|||
response = client.post( |
|||
"/simple-model", |
|||
json={"wrong_name": "Foo"}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body", "name"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_old_simple_model_filter(): |
|||
response = client.post( |
|||
"/simple-model-filter", |
|||
json={"name": "Foo"}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == {"name": "Foo"} |
|||
|
|||
|
|||
def test_item_model(): |
|||
response = client.post( |
|||
"/item", |
|||
json={ |
|||
"title": "Test Item", |
|||
"size": 100, |
|||
"description": "This is a test item", |
|||
"sub": {"name": "SubItem1"}, |
|||
"multi": [{"name": "Multi1"}, {"name": "Multi2"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "Test Item", |
|||
"size": 100, |
|||
"description": "This is a test item", |
|||
"sub": {"name": "SubItem1"}, |
|||
"multi": [{"name": "Multi1"}, {"name": "Multi2"}], |
|||
} |
|||
|
|||
|
|||
def test_item_model_minimal(): |
|||
response = client.post( |
|||
"/item", |
|||
json={"title": "Minimal Item", "size": 50, "sub": {"name": "SubMin"}}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "Minimal Item", |
|||
"size": 50, |
|||
"description": None, |
|||
"sub": {"name": "SubMin"}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_item_model_validation_errors(): |
|||
response = client.post( |
|||
"/item", |
|||
json={"title": "Missing fields"}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
error_detail = response.json()["detail"] |
|||
assert len(error_detail) == 2 |
|||
assert { |
|||
"loc": ["body", "size"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} in error_detail |
|||
assert { |
|||
"loc": ["body", "sub"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} in error_detail |
|||
|
|||
|
|||
def test_item_model_nested_validation_error(): |
|||
response = client.post( |
|||
"/item", |
|||
json={"title": "Test Item", "size": 100, "sub": {"wrong_field": "test"}}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body", "sub", "name"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_item_model_invalid_type(): |
|||
response = client.post( |
|||
"/item", |
|||
json={"title": "Test Item", "size": "not_a_number", "sub": {"name": "SubItem"}}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body", "size"], |
|||
"msg": "value is not a valid integer", |
|||
"type": "type_error.integer", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_item_filter(): |
|||
response = client.post( |
|||
"/item-filter", |
|||
json={ |
|||
"title": "Filtered Item", |
|||
"size": 200, |
|||
"description": "Test filtering", |
|||
"sub": {"name": "SubFiltered"}, |
|||
"multi": [], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert result == { |
|||
"title": "Filtered Item", |
|||
"size": 200, |
|||
"description": "Test filtering", |
|||
"sub": {"name": "SubFiltered"}, |
|||
"multi": [], |
|||
} |
|||
assert "secret_data" not in result |
|||
assert "internal_id" not in result |
|||
|
|||
|
|||
def test_openapi_schema(): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/simple-model": { |
|||
"post": { |
|||
"summary": "Handle Simple Model", |
|||
"operationId": "handle_simple_model_simple_model_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/SubItem"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/SubItem" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/simple-model-filter": { |
|||
"post": { |
|||
"summary": "Handle Simple Model Filter", |
|||
"operationId": "handle_simple_model_filter_simple_model_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/SubItem"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/SubItem" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item": { |
|||
"post": { |
|||
"summary": "Handle Item", |
|||
"operationId": "handle_item_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item-filter": { |
|||
"post": { |
|||
"summary": "Handle Item Filter", |
|||
"operationId": "handle_item_filter_item_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"title": {"type": "string", "title": "Title"}, |
|||
"size": {"type": "integer", "title": "Size"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"sub": {"$ref": "#/components/schemas/SubItem"}, |
|||
"multi": { |
|||
"items": {"$ref": "#/components/schemas/SubItem"}, |
|||
"type": "array", |
|||
"title": "Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["title", "size", "sub"], |
|||
"title": "Item", |
|||
}, |
|||
"SubItem": { |
|||
"properties": {"name": {"type": "string", "title": "Name"}}, |
|||
"type": "object", |
|||
"required": ["name"], |
|||
"title": "SubItem", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
@ -1,682 +0,0 @@ |
|||
import sys |
|||
import warnings |
|||
from typing import Any, Union |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
from fastapi import FastAPI |
|||
from fastapi._compat.v1 import BaseModel |
|||
from fastapi.testclient import TestClient |
|||
from inline_snapshot import snapshot |
|||
|
|||
|
|||
class SubItem(BaseModel): |
|||
name: str |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
title: str |
|||
size: int |
|||
description: Union[str, None] = None |
|||
sub: SubItem |
|||
multi: list[SubItem] = [] |
|||
|
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
with warnings.catch_warnings(record=True): |
|||
warnings.simplefilter("always") |
|||
|
|||
@app.post("/item") |
|||
def handle_item(data: Item) -> list[Item]: |
|||
return [data, data] |
|||
|
|||
@app.post("/item-filter", response_model=list[Item]) |
|||
def handle_item_filter(data: Item) -> Any: |
|||
extended_data = data.dict() |
|||
extended_data.update({"secret_data": "classified", "internal_id": 12345}) |
|||
extended_data["sub"].update({"internal_id": 67890}) |
|||
return [extended_data, extended_data] |
|||
|
|||
@app.post("/item-list") |
|||
def handle_item_list(data: list[Item]) -> Item: |
|||
if data: |
|||
return data[0] |
|||
return Item(title="", size=0, sub=SubItem(name="")) |
|||
|
|||
@app.post("/item-list-filter", response_model=Item) |
|||
def handle_item_list_filter(data: list[Item]) -> Any: |
|||
if data: |
|||
extended_data = data[0].dict() |
|||
extended_data.update({"secret_data": "classified", "internal_id": 12345}) |
|||
extended_data["sub"].update({"internal_id": 67890}) |
|||
return extended_data |
|||
return Item(title="", size=0, sub=SubItem(name="")) |
|||
|
|||
@app.post("/item-list-to-list") |
|||
def handle_item_list_to_list(data: list[Item]) -> list[Item]: |
|||
return data |
|||
|
|||
@app.post("/item-list-to-list-filter", response_model=list[Item]) |
|||
def handle_item_list_to_list_filter(data: list[Item]) -> Any: |
|||
if data: |
|||
extended_data = data[0].dict() |
|||
extended_data.update({"secret_data": "classified", "internal_id": 12345}) |
|||
extended_data["sub"].update({"internal_id": 67890}) |
|||
return [extended_data, extended_data] |
|||
return [] |
|||
|
|||
|
|||
client = TestClient(app) |
|||
|
|||
|
|||
def test_item_to_list(): |
|||
response = client.post( |
|||
"/item", |
|||
json={ |
|||
"title": "Test Item", |
|||
"size": 100, |
|||
"description": "This is a test item", |
|||
"sub": {"name": "SubItem1"}, |
|||
"multi": [{"name": "Multi1"}, {"name": "Multi2"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert isinstance(result, list) |
|||
assert len(result) == 2 |
|||
for item in result: |
|||
assert item == { |
|||
"title": "Test Item", |
|||
"size": 100, |
|||
"description": "This is a test item", |
|||
"sub": {"name": "SubItem1"}, |
|||
"multi": [{"name": "Multi1"}, {"name": "Multi2"}], |
|||
} |
|||
|
|||
|
|||
def test_item_to_list_filter(): |
|||
response = client.post( |
|||
"/item-filter", |
|||
json={ |
|||
"title": "Filtered Item", |
|||
"size": 200, |
|||
"description": "Test filtering", |
|||
"sub": {"name": "SubFiltered"}, |
|||
"multi": [], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert isinstance(result, list) |
|||
assert len(result) == 2 |
|||
for item in result: |
|||
assert item == { |
|||
"title": "Filtered Item", |
|||
"size": 200, |
|||
"description": "Test filtering", |
|||
"sub": {"name": "SubFiltered"}, |
|||
"multi": [], |
|||
} |
|||
# Verify secret fields are filtered out |
|||
assert "secret_data" not in item |
|||
assert "internal_id" not in item |
|||
assert "internal_id" not in item["sub"] |
|||
|
|||
|
|||
def test_list_to_item(): |
|||
response = client.post( |
|||
"/item-list", |
|||
json=[ |
|||
{"title": "First Item", "size": 50, "sub": {"name": "First Sub"}}, |
|||
{"title": "Second Item", "size": 75, "sub": {"name": "Second Sub"}}, |
|||
], |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "First Item", |
|||
"size": 50, |
|||
"description": None, |
|||
"sub": {"name": "First Sub"}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_list_to_item_empty(): |
|||
response = client.post( |
|||
"/item-list", |
|||
json=[], |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "", |
|||
"size": 0, |
|||
"description": None, |
|||
"sub": {"name": ""}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_list_to_item_filter(): |
|||
response = client.post( |
|||
"/item-list-filter", |
|||
json=[ |
|||
{ |
|||
"title": "First Item", |
|||
"size": 100, |
|||
"sub": {"name": "First Sub"}, |
|||
"multi": [{"name": "Multi1"}], |
|||
}, |
|||
{"title": "Second Item", "size": 200, "sub": {"name": "Second Sub"}}, |
|||
], |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert result == { |
|||
"title": "First Item", |
|||
"size": 100, |
|||
"description": None, |
|||
"sub": {"name": "First Sub"}, |
|||
"multi": [{"name": "Multi1"}], |
|||
} |
|||
# Verify secret fields are filtered out |
|||
assert "secret_data" not in result |
|||
assert "internal_id" not in result |
|||
|
|||
|
|||
def test_list_to_item_filter_no_data(): |
|||
response = client.post("/item-list-filter", json=[]) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "", |
|||
"size": 0, |
|||
"description": None, |
|||
"sub": {"name": ""}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_list_to_list(): |
|||
input_items = [ |
|||
{"title": "Item 1", "size": 10, "sub": {"name": "Sub1"}}, |
|||
{ |
|||
"title": "Item 2", |
|||
"size": 20, |
|||
"description": "Second item", |
|||
"sub": {"name": "Sub2"}, |
|||
"multi": [{"name": "M1"}, {"name": "M2"}], |
|||
}, |
|||
{"title": "Item 3", "size": 30, "sub": {"name": "Sub3"}}, |
|||
] |
|||
response = client.post( |
|||
"/item-list-to-list", |
|||
json=input_items, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert isinstance(result, list) |
|||
assert len(result) == 3 |
|||
assert result[0] == { |
|||
"title": "Item 1", |
|||
"size": 10, |
|||
"description": None, |
|||
"sub": {"name": "Sub1"}, |
|||
"multi": [], |
|||
} |
|||
assert result[1] == { |
|||
"title": "Item 2", |
|||
"size": 20, |
|||
"description": "Second item", |
|||
"sub": {"name": "Sub2"}, |
|||
"multi": [{"name": "M1"}, {"name": "M2"}], |
|||
} |
|||
assert result[2] == { |
|||
"title": "Item 3", |
|||
"size": 30, |
|||
"description": None, |
|||
"sub": {"name": "Sub3"}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_list_to_list_filter(): |
|||
response = client.post( |
|||
"/item-list-to-list-filter", |
|||
json=[{"title": "Item 1", "size": 100, "sub": {"name": "Sub1"}}], |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert isinstance(result, list) |
|||
assert len(result) == 2 |
|||
for item in result: |
|||
assert item == { |
|||
"title": "Item 1", |
|||
"size": 100, |
|||
"description": None, |
|||
"sub": {"name": "Sub1"}, |
|||
"multi": [], |
|||
} |
|||
# Verify secret fields are filtered out |
|||
assert "secret_data" not in item |
|||
assert "internal_id" not in item |
|||
|
|||
|
|||
def test_list_to_list_filter_no_data(): |
|||
response = client.post( |
|||
"/item-list-to-list-filter", |
|||
json=[], |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == [] |
|||
|
|||
|
|||
def test_list_validation_error(): |
|||
response = client.post( |
|||
"/item-list", |
|||
json=[ |
|||
{"title": "Valid Item", "size": 100, "sub": {"name": "Sub1"}}, |
|||
{ |
|||
"title": "Invalid Item" |
|||
# Missing required fields: size and sub |
|||
}, |
|||
], |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
error_detail = response.json()["detail"] |
|||
assert len(error_detail) == 2 |
|||
assert { |
|||
"loc": ["body", 1, "size"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} in error_detail |
|||
assert { |
|||
"loc": ["body", 1, "sub"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} in error_detail |
|||
|
|||
|
|||
def test_list_nested_validation_error(): |
|||
response = client.post( |
|||
"/item-list", |
|||
json=[ |
|||
{"title": "Item with bad sub", "size": 100, "sub": {"wrong_field": "value"}} |
|||
], |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body", 0, "sub", "name"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_list_type_validation_error(): |
|||
response = client.post( |
|||
"/item-list", |
|||
json=[{"title": "Item", "size": "not_a_number", "sub": {"name": "Sub"}}], |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body", 0, "size"], |
|||
"msg": "value is not a valid integer", |
|||
"type": "type_error.integer", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_invalid_list_structure(): |
|||
response = client.post( |
|||
"/item-list", |
|||
json={"title": "Not a list", "size": 100, "sub": {"name": "Sub"}}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body"], |
|||
"msg": "value is not a valid list", |
|||
"type": "type_error.list", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_openapi_schema(): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/item": { |
|||
"post": { |
|||
"summary": "Handle Item", |
|||
"operationId": "handle_item_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle Item Item Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item-filter": { |
|||
"post": { |
|||
"summary": "Handle Item Filter", |
|||
"operationId": "handle_item_filter_item_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle Item Filter Item Filter Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item-list": { |
|||
"post": { |
|||
"summary": "Handle Item List", |
|||
"operationId": "handle_item_list_item_list_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": {"$ref": "#/components/schemas/Item"}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item-list-filter": { |
|||
"post": { |
|||
"summary": "Handle Item List Filter", |
|||
"operationId": "handle_item_list_filter_item_list_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": {"$ref": "#/components/schemas/Item"}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item-list-to-list": { |
|||
"post": { |
|||
"summary": "Handle Item List To List", |
|||
"operationId": "handle_item_list_to_list_item_list_to_list_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": {"$ref": "#/components/schemas/Item"}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle Item List To List Item List To List Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/item-list-to-list-filter": { |
|||
"post": { |
|||
"summary": "Handle Item List To List Filter", |
|||
"operationId": "handle_item_list_to_list_filter_item_list_to_list_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": {"$ref": "#/components/schemas/Item"}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle Item List To List Filter Item List To List Filter Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"title": {"type": "string", "title": "Title"}, |
|||
"size": {"type": "integer", "title": "Size"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"sub": {"$ref": "#/components/schemas/SubItem"}, |
|||
"multi": { |
|||
"items": {"$ref": "#/components/schemas/SubItem"}, |
|||
"type": "array", |
|||
"title": "Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["title", "size", "sub"], |
|||
"title": "Item", |
|||
}, |
|||
"SubItem": { |
|||
"properties": {"name": {"type": "string", "title": "Name"}}, |
|||
"type": "object", |
|||
"required": ["name"], |
|||
"title": "SubItem", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
File diff suppressed because it is too large
@ -1,137 +0,0 @@ |
|||
import warnings |
|||
|
|||
from fastapi import FastAPI |
|||
|
|||
from . import modelsv1, modelsv2, modelsv2b |
|||
|
|||
app = FastAPI() |
|||
|
|||
with warnings.catch_warnings(record=True): |
|||
warnings.simplefilter("always") |
|||
|
|||
@app.post("/v1-to-v2/item") |
|||
def handle_v1_item_to_v2(data: modelsv1.Item) -> modelsv2.Item: |
|||
return modelsv2.Item( |
|||
new_title=data.title, |
|||
new_size=data.size, |
|||
new_description=data.description, |
|||
new_sub=modelsv2.SubItem(new_sub_name=data.sub.name), |
|||
new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in data.multi], |
|||
) |
|||
|
|||
@app.post("/v2-to-v1/item") |
|||
def handle_v2_item_to_v1(data: modelsv2.Item) -> modelsv1.Item: |
|||
return modelsv1.Item( |
|||
title=data.new_title, |
|||
size=data.new_size, |
|||
description=data.new_description, |
|||
sub=modelsv1.SubItem(name=data.new_sub.new_sub_name), |
|||
multi=[modelsv1.SubItem(name=s.new_sub_name) for s in data.new_multi], |
|||
) |
|||
|
|||
@app.post("/v1-to-v2/item-to-list") |
|||
def handle_v1_item_to_v2_list(data: modelsv1.Item) -> list[modelsv2.Item]: |
|||
converted = modelsv2.Item( |
|||
new_title=data.title, |
|||
new_size=data.size, |
|||
new_description=data.description, |
|||
new_sub=modelsv2.SubItem(new_sub_name=data.sub.name), |
|||
new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in data.multi], |
|||
) |
|||
return [converted, converted] |
|||
|
|||
@app.post("/v1-to-v2/list-to-list") |
|||
def handle_v1_list_to_v2_list(data: list[modelsv1.Item]) -> list[modelsv2.Item]: |
|||
result = [] |
|||
for item in data: |
|||
result.append( |
|||
modelsv2.Item( |
|||
new_title=item.title, |
|||
new_size=item.size, |
|||
new_description=item.description, |
|||
new_sub=modelsv2.SubItem(new_sub_name=item.sub.name), |
|||
new_multi=[ |
|||
modelsv2.SubItem(new_sub_name=s.name) for s in item.multi |
|||
], |
|||
) |
|||
) |
|||
return result |
|||
|
|||
@app.post("/v1-to-v2/list-to-item") |
|||
def handle_v1_list_to_v2_item(data: list[modelsv1.Item]) -> modelsv2.Item: |
|||
if data: |
|||
item = data[0] |
|||
return modelsv2.Item( |
|||
new_title=item.title, |
|||
new_size=item.size, |
|||
new_description=item.description, |
|||
new_sub=modelsv2.SubItem(new_sub_name=item.sub.name), |
|||
new_multi=[modelsv2.SubItem(new_sub_name=s.name) for s in item.multi], |
|||
) |
|||
return modelsv2.Item( |
|||
new_title="", new_size=0, new_sub=modelsv2.SubItem(new_sub_name="") |
|||
) |
|||
|
|||
@app.post("/v2-to-v1/item-to-list") |
|||
def handle_v2_item_to_v1_list(data: modelsv2.Item) -> list[modelsv1.Item]: |
|||
converted = modelsv1.Item( |
|||
title=data.new_title, |
|||
size=data.new_size, |
|||
description=data.new_description, |
|||
sub=modelsv1.SubItem(name=data.new_sub.new_sub_name), |
|||
multi=[modelsv1.SubItem(name=s.new_sub_name) for s in data.new_multi], |
|||
) |
|||
return [converted, converted] |
|||
|
|||
@app.post("/v2-to-v1/list-to-list") |
|||
def handle_v2_list_to_v1_list(data: list[modelsv2.Item]) -> list[modelsv1.Item]: |
|||
result = [] |
|||
for item in data: |
|||
result.append( |
|||
modelsv1.Item( |
|||
title=item.new_title, |
|||
size=item.new_size, |
|||
description=item.new_description, |
|||
sub=modelsv1.SubItem(name=item.new_sub.new_sub_name), |
|||
multi=[ |
|||
modelsv1.SubItem(name=s.new_sub_name) for s in item.new_multi |
|||
], |
|||
) |
|||
) |
|||
return result |
|||
|
|||
@app.post("/v2-to-v1/list-to-item") |
|||
def handle_v2_list_to_v1_item(data: list[modelsv2.Item]) -> modelsv1.Item: |
|||
if data: |
|||
item = data[0] |
|||
return modelsv1.Item( |
|||
title=item.new_title, |
|||
size=item.new_size, |
|||
description=item.new_description, |
|||
sub=modelsv1.SubItem(name=item.new_sub.new_sub_name), |
|||
multi=[modelsv1.SubItem(name=s.new_sub_name) for s in item.new_multi], |
|||
) |
|||
return modelsv1.Item(title="", size=0, sub=modelsv1.SubItem(name="")) |
|||
|
|||
@app.post("/v2-to-v1/same-name") |
|||
def handle_v2_same_name_to_v1( |
|||
item1: modelsv2.Item, item2: modelsv2b.Item |
|||
) -> modelsv1.Item: |
|||
return modelsv1.Item( |
|||
title=item1.new_title, |
|||
size=item2.dup_size, |
|||
description=item1.new_description, |
|||
sub=modelsv1.SubItem(name=item1.new_sub.new_sub_name), |
|||
multi=[modelsv1.SubItem(name=s.dup_sub_name) for s in item2.dup_multi], |
|||
) |
|||
|
|||
@app.post("/v2-to-v1/list-of-items-to-list-of-items") |
|||
def handle_v2_items_in_list_to_v1_item_in_list( |
|||
data1: list[modelsv2.ItemInList], data2: list[modelsv2b.ItemInList] |
|||
) -> list[modelsv1.ItemInList]: |
|||
item1 = data1[0] |
|||
item2 = data2[0] |
|||
return [ |
|||
modelsv1.ItemInList(name1=item1.name2), |
|||
modelsv1.ItemInList(name1=item2.dup_name2), |
|||
] |
|||
@ -1,19 +0,0 @@ |
|||
from typing import Union |
|||
|
|||
from fastapi._compat.v1 import BaseModel |
|||
|
|||
|
|||
class SubItem(BaseModel): |
|||
name: str |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
title: str |
|||
size: int |
|||
description: Union[str, None] = None |
|||
sub: SubItem |
|||
multi: list[SubItem] = [] |
|||
|
|||
|
|||
class ItemInList(BaseModel): |
|||
name1: str |
|||
@ -1,19 +0,0 @@ |
|||
from typing import Union |
|||
|
|||
from pydantic import BaseModel |
|||
|
|||
|
|||
class SubItem(BaseModel): |
|||
new_sub_name: str |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
new_title: str |
|||
new_size: int |
|||
new_description: Union[str, None] = None |
|||
new_sub: SubItem |
|||
new_multi: list[SubItem] = [] |
|||
|
|||
|
|||
class ItemInList(BaseModel): |
|||
name2: str |
|||
@ -1,19 +0,0 @@ |
|||
from typing import Union |
|||
|
|||
from pydantic import BaseModel |
|||
|
|||
|
|||
class SubItem(BaseModel): |
|||
dup_sub_name: str |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
dup_title: str |
|||
dup_size: int |
|||
dup_description: Union[str, None] = None |
|||
dup_sub: SubItem |
|||
dup_multi: list[SubItem] = [] |
|||
|
|||
|
|||
class ItemInList(BaseModel): |
|||
dup_name2: str |
|||
@ -1,951 +0,0 @@ |
|||
import sys |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
from fastapi.testclient import TestClient |
|||
from inline_snapshot import snapshot |
|||
|
|||
from .main import app |
|||
|
|||
client = TestClient(app) |
|||
|
|||
|
|||
def test_v1_to_v2_item(): |
|||
response = client.post( |
|||
"/v1-to-v2/item", |
|||
json={"title": "Test", "size": 10, "sub": {"name": "SubTest"}}, |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"new_title": "Test", |
|||
"new_size": 10, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "SubTest"}, |
|||
"new_multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v2_to_v1_item(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "NewTest", |
|||
"new_size": 20, |
|||
"new_sub": {"new_sub_name": "NewSubTest"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"title": "NewTest", |
|||
"size": 20, |
|||
"description": None, |
|||
"sub": {"name": "NewSubTest"}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v1_to_v2_item_to_list(): |
|||
response = client.post( |
|||
"/v1-to-v2/item-to-list", |
|||
json={"title": "ListTest", "size": 30, "sub": {"name": "SubListTest"}}, |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == [ |
|||
{ |
|||
"new_title": "ListTest", |
|||
"new_size": 30, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "SubListTest"}, |
|||
"new_multi": [], |
|||
}, |
|||
{ |
|||
"new_title": "ListTest", |
|||
"new_size": 30, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "SubListTest"}, |
|||
"new_multi": [], |
|||
}, |
|||
] |
|||
|
|||
|
|||
def test_v1_to_v2_list_to_list(): |
|||
response = client.post( |
|||
"/v1-to-v2/list-to-list", |
|||
json=[ |
|||
{"title": "Item1", "size": 40, "sub": {"name": "Sub1"}}, |
|||
{"title": "Item2", "size": 50, "sub": {"name": "Sub2"}}, |
|||
], |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == [ |
|||
{ |
|||
"new_title": "Item1", |
|||
"new_size": 40, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "Sub1"}, |
|||
"new_multi": [], |
|||
}, |
|||
{ |
|||
"new_title": "Item2", |
|||
"new_size": 50, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "Sub2"}, |
|||
"new_multi": [], |
|||
}, |
|||
] |
|||
|
|||
|
|||
def test_v1_to_v2_list_to_item(): |
|||
response = client.post( |
|||
"/v1-to-v2/list-to-item", |
|||
json=[ |
|||
{"title": "FirstItem", "size": 60, "sub": {"name": "FirstSub"}}, |
|||
{"title": "SecondItem", "size": 70, "sub": {"name": "SecondSub"}}, |
|||
], |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"new_title": "FirstItem", |
|||
"new_size": 60, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "FirstSub"}, |
|||
"new_multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v2_to_v1_item_to_list(): |
|||
response = client.post( |
|||
"/v2-to-v1/item-to-list", |
|||
json={ |
|||
"new_title": "ListNew", |
|||
"new_size": 80, |
|||
"new_sub": {"new_sub_name": "SubListNew"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == [ |
|||
{ |
|||
"title": "ListNew", |
|||
"size": 80, |
|||
"description": None, |
|||
"sub": {"name": "SubListNew"}, |
|||
"multi": [], |
|||
}, |
|||
{ |
|||
"title": "ListNew", |
|||
"size": 80, |
|||
"description": None, |
|||
"sub": {"name": "SubListNew"}, |
|||
"multi": [], |
|||
}, |
|||
] |
|||
|
|||
|
|||
def test_v2_to_v1_list_to_list(): |
|||
response = client.post( |
|||
"/v2-to-v1/list-to-list", |
|||
json=[ |
|||
{ |
|||
"new_title": "New1", |
|||
"new_size": 90, |
|||
"new_sub": {"new_sub_name": "NewSub1"}, |
|||
}, |
|||
{ |
|||
"new_title": "New2", |
|||
"new_size": 100, |
|||
"new_sub": {"new_sub_name": "NewSub2"}, |
|||
}, |
|||
], |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == [ |
|||
{ |
|||
"title": "New1", |
|||
"size": 90, |
|||
"description": None, |
|||
"sub": {"name": "NewSub1"}, |
|||
"multi": [], |
|||
}, |
|||
{ |
|||
"title": "New2", |
|||
"size": 100, |
|||
"description": None, |
|||
"sub": {"name": "NewSub2"}, |
|||
"multi": [], |
|||
}, |
|||
] |
|||
|
|||
|
|||
def test_v2_to_v1_list_to_item(): |
|||
response = client.post( |
|||
"/v2-to-v1/list-to-item", |
|||
json=[ |
|||
{ |
|||
"new_title": "FirstNew", |
|||
"new_size": 110, |
|||
"new_sub": {"new_sub_name": "FirstNewSub"}, |
|||
}, |
|||
{ |
|||
"new_title": "SecondNew", |
|||
"new_size": 120, |
|||
"new_sub": {"new_sub_name": "SecondNewSub"}, |
|||
}, |
|||
], |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"title": "FirstNew", |
|||
"size": 110, |
|||
"description": None, |
|||
"sub": {"name": "FirstNewSub"}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v1_to_v2_list_to_item_empty(): |
|||
response = client.post("/v1-to-v2/list-to-item", json=[]) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"new_title": "", |
|||
"new_size": 0, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": ""}, |
|||
"new_multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v2_to_v1_list_to_item_empty(): |
|||
response = client.post("/v2-to-v1/list-to-item", json=[]) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"title": "", |
|||
"size": 0, |
|||
"description": None, |
|||
"sub": {"name": ""}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v2_same_name_to_v1(): |
|||
response = client.post( |
|||
"/v2-to-v1/same-name", |
|||
json={ |
|||
"item1": { |
|||
"new_title": "Title1", |
|||
"new_size": 100, |
|||
"new_description": "Description1", |
|||
"new_sub": {"new_sub_name": "Sub1"}, |
|||
"new_multi": [{"new_sub_name": "Multi1"}], |
|||
}, |
|||
"item2": { |
|||
"dup_title": "Title2", |
|||
"dup_size": 200, |
|||
"dup_description": "Description2", |
|||
"dup_sub": {"dup_sub_name": "Sub2"}, |
|||
"dup_multi": [ |
|||
{"dup_sub_name": "Multi2a"}, |
|||
{"dup_sub_name": "Multi2b"}, |
|||
], |
|||
}, |
|||
}, |
|||
) |
|||
assert response.status_code == 200 |
|||
assert response.json() == { |
|||
"title": "Title1", |
|||
"size": 200, |
|||
"description": "Description1", |
|||
"sub": {"name": "Sub1"}, |
|||
"multi": [{"name": "Multi2a"}, {"name": "Multi2b"}], |
|||
} |
|||
|
|||
|
|||
def test_v2_items_in_list_to_v1_item_in_list(): |
|||
response = client.post( |
|||
"/v2-to-v1/list-of-items-to-list-of-items", |
|||
json={ |
|||
"data1": [{"name2": "Item1"}, {"name2": "Item2"}], |
|||
"data2": [{"dup_name2": "Item3"}, {"dup_name2": "Item4"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == [ |
|||
{"name1": "Item1"}, |
|||
{"name1": "Item3"}, |
|||
] |
|||
|
|||
|
|||
def test_openapi_schema(): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200 |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/v1-to-v2/item": { |
|||
"post": { |
|||
"summary": "Handle V1 Item To V2", |
|||
"operationId": "handle_v1_item_to_v2_v1_to_v2_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{ |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/item": { |
|||
"post": { |
|||
"summary": "Handle V2 Item To V1", |
|||
"operationId": "handle_v2_item_to_v1_v2_to_v1_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item-Input" |
|||
}, |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v1-to-v2/item-to-list": { |
|||
"post": { |
|||
"summary": "Handle V1 Item To V2 List", |
|||
"operationId": "handle_v1_item_to_v2_list_v1_to_v2_item_to_list_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{ |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle V1 Item To V2 List V1 To V2 Item To List Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v1-to-v2/list-to-list": { |
|||
"post": { |
|||
"summary": "Handle V1 List To V2 List", |
|||
"operationId": "handle_v1_list_to_v2_list_v1_to_v2_list_to_list_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle V1 List To V2 List V1 To V2 List To List Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v1-to-v2/list-to-item": { |
|||
"post": { |
|||
"summary": "Handle V1 List To V2 Item", |
|||
"operationId": "handle_v1_list_to_v2_item_v1_to_v2_list_to_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/item-to-list": { |
|||
"post": { |
|||
"summary": "Handle V2 Item To V1 List", |
|||
"operationId": "handle_v2_item_to_v1_list_v2_to_v1_item_to_list_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item-Input" |
|||
}, |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle V2 Item To V1 List V2 To V1 Item To List Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/list-to-list": { |
|||
"post": { |
|||
"summary": "Handle V2 List To V1 List", |
|||
"operationId": "handle_v2_list_to_v1_list_v2_to_v1_list_to_list_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item-Input" |
|||
}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle V2 List To V1 List V2 To V1 List To List Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/list-to-item": { |
|||
"post": { |
|||
"summary": "Handle V2 List To V1 Item", |
|||
"operationId": "handle_v2_list_to_v1_item_v2_to_v1_list_to_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item-Input" |
|||
}, |
|||
"type": "array", |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/same-name": { |
|||
"post": { |
|||
"summary": "Handle V2 Same Name To V1", |
|||
"operationId": "handle_v2_same_name_to_v1_v2_to_v1_same_name_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/Body_handle_v2_same_name_to_v1_v2_to_v1_same_name_post" |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__Item" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/list-of-items-to-list-of-items": { |
|||
"post": { |
|||
"summary": "Handle V2 Items In List To V1 Item In List", |
|||
"operationId": "handle_v2_items_in_list_to_v1_item_in_list_v2_to_v1_list_of_items_to_list_of_items_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/Body_handle_v2_items_in_list_to_v1_item_in_list_v2_to_v1_list_of_items_to_list_of_items_post" |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__ItemInList" |
|||
}, |
|||
"type": "array", |
|||
"title": "Response Handle V2 Items In List To V1 Item In List V2 To V1 List Of Items To List Of Items Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"Body_handle_v2_items_in_list_to_v1_item_in_list_v2_to_v1_list_of_items_to_list_of_items_post": { |
|||
"properties": { |
|||
"data1": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__ItemInList" |
|||
}, |
|||
"type": "array", |
|||
"title": "Data1", |
|||
}, |
|||
"data2": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2b__ItemInList" |
|||
}, |
|||
"type": "array", |
|||
"title": "Data2", |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["data1", "data2"], |
|||
"title": "Body_handle_v2_items_in_list_to_v1_item_in_list_v2_to_v1_list_of_items_to_list_of_items_post", |
|||
}, |
|||
"Body_handle_v2_same_name_to_v1_v2_to_v1_same_name_post": { |
|||
"properties": { |
|||
"item1": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__Item-Input" |
|||
}, |
|||
"item2": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2b__Item" |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["item1", "item2"], |
|||
"title": "Body_handle_v2_same_name_to_v1_v2_to_v1_same_name_post", |
|||
}, |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [ |
|||
{"type": "string"}, |
|||
{"type": "integer"}, |
|||
] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv1__Item": { |
|||
"properties": { |
|||
"title": {"type": "string", "title": "Title"}, |
|||
"size": {"type": "integer", "title": "Size"}, |
|||
"description": { |
|||
"type": "string", |
|||
"title": "Description", |
|||
}, |
|||
"sub": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__SubItem" |
|||
}, |
|||
"multi": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv1__SubItem" |
|||
}, |
|||
"type": "array", |
|||
"title": "Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["title", "size", "sub"], |
|||
"title": "Item", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv1__ItemInList": { |
|||
"properties": {"name1": {"type": "string", "title": "Name1"}}, |
|||
"type": "object", |
|||
"required": ["name1"], |
|||
"title": "ItemInList", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv1__SubItem": { |
|||
"properties": {"name": {"type": "string", "title": "Name"}}, |
|||
"type": "object", |
|||
"required": ["name"], |
|||
"title": "SubItem", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2__Item": { |
|||
"properties": { |
|||
"new_title": { |
|||
"type": "string", |
|||
"title": "New Title", |
|||
}, |
|||
"new_size": { |
|||
"type": "integer", |
|||
"title": "New Size", |
|||
}, |
|||
"new_description": { |
|||
"anyOf": [{"type": "string"}, {"type": "null"}], |
|||
"title": "New Description", |
|||
}, |
|||
"new_sub": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem" |
|||
}, |
|||
"new_multi": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem" |
|||
}, |
|||
"type": "array", |
|||
"title": "New Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["new_title", "new_size", "new_sub"], |
|||
"title": "Item", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2__Item-Input": { |
|||
"properties": { |
|||
"new_title": { |
|||
"type": "string", |
|||
"title": "New Title", |
|||
}, |
|||
"new_size": { |
|||
"type": "integer", |
|||
"title": "New Size", |
|||
}, |
|||
"new_description": { |
|||
"anyOf": [{"type": "string"}, {"type": "null"}], |
|||
"title": "New Description", |
|||
}, |
|||
"new_sub": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem" |
|||
}, |
|||
"new_multi": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem" |
|||
}, |
|||
"type": "array", |
|||
"title": "New Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["new_title", "new_size", "new_sub"], |
|||
"title": "Item", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2__ItemInList": { |
|||
"properties": {"name2": {"type": "string", "title": "Name2"}}, |
|||
"type": "object", |
|||
"required": ["name2"], |
|||
"title": "ItemInList", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem": { |
|||
"properties": { |
|||
"new_sub_name": { |
|||
"type": "string", |
|||
"title": "New Sub Name", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"required": ["new_sub_name"], |
|||
"title": "SubItem", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2b__Item": { |
|||
"properties": { |
|||
"dup_title": { |
|||
"type": "string", |
|||
"title": "Dup Title", |
|||
}, |
|||
"dup_size": { |
|||
"type": "integer", |
|||
"title": "Dup Size", |
|||
}, |
|||
"dup_description": { |
|||
"anyOf": [{"type": "string"}, {"type": "null"}], |
|||
"title": "Dup Description", |
|||
}, |
|||
"dup_sub": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2b__SubItem" |
|||
}, |
|||
"dup_multi": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2b__SubItem" |
|||
}, |
|||
"type": "array", |
|||
"title": "Dup Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["dup_title", "dup_size", "dup_sub"], |
|||
"title": "Item", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2b__ItemInList": { |
|||
"properties": { |
|||
"dup_name2": { |
|||
"type": "string", |
|||
"title": "Dup Name2", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"required": ["dup_name2"], |
|||
"title": "ItemInList", |
|||
}, |
|||
"tests__test_pydantic_v1_v2_multifile__modelsv2b__SubItem": { |
|||
"properties": { |
|||
"dup_sub_name": { |
|||
"type": "string", |
|||
"title": "Dup Sub Name", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"required": ["dup_sub_name"], |
|||
"title": "SubItem", |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
) |
|||
@ -1,692 +0,0 @@ |
|||
import sys |
|||
import warnings |
|||
from typing import Any, Union |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
from fastapi import FastAPI |
|||
from fastapi._compat.v1 import BaseModel |
|||
from fastapi.testclient import TestClient |
|||
from inline_snapshot import snapshot |
|||
from pydantic import BaseModel as NewBaseModel |
|||
|
|||
|
|||
class SubItem(BaseModel): |
|||
name: str |
|||
|
|||
|
|||
class Item(BaseModel): |
|||
title: str |
|||
size: int |
|||
description: Union[str, None] = None |
|||
sub: SubItem |
|||
multi: list[SubItem] = [] |
|||
|
|||
|
|||
class NewSubItem(NewBaseModel): |
|||
new_sub_name: str |
|||
|
|||
|
|||
class NewItem(NewBaseModel): |
|||
new_title: str |
|||
new_size: int |
|||
new_description: Union[str, None] = None |
|||
new_sub: NewSubItem |
|||
new_multi: list[NewSubItem] = [] |
|||
|
|||
|
|||
app = FastAPI() |
|||
|
|||
with warnings.catch_warnings(record=True): |
|||
warnings.simplefilter("always") |
|||
|
|||
@app.post("/v1-to-v2/") |
|||
def handle_v1_item_to_v2(data: Item) -> Union[NewItem, None]: |
|||
if data.size < 0: |
|||
return None |
|||
return NewItem( |
|||
new_title=data.title, |
|||
new_size=data.size, |
|||
new_description=data.description, |
|||
new_sub=NewSubItem(new_sub_name=data.sub.name), |
|||
new_multi=[NewSubItem(new_sub_name=s.name) for s in data.multi], |
|||
) |
|||
|
|||
@app.post("/v1-to-v2/item-filter", response_model=Union[NewItem, None]) |
|||
def handle_v1_item_to_v2_filter(data: Item) -> Any: |
|||
if data.size < 0: |
|||
return None |
|||
result = { |
|||
"new_title": data.title, |
|||
"new_size": data.size, |
|||
"new_description": data.description, |
|||
"new_sub": { |
|||
"new_sub_name": data.sub.name, |
|||
"new_sub_secret": "sub_hidden", |
|||
}, |
|||
"new_multi": [ |
|||
{"new_sub_name": s.name, "new_sub_secret": "sub_hidden"} |
|||
for s in data.multi |
|||
], |
|||
"secret": "hidden_v1_to_v2", |
|||
} |
|||
return result |
|||
|
|||
@app.post("/v2-to-v1/item") |
|||
def handle_v2_item_to_v1(data: NewItem) -> Union[Item, None]: |
|||
if data.new_size < 0: |
|||
return None |
|||
return Item( |
|||
title=data.new_title, |
|||
size=data.new_size, |
|||
description=data.new_description, |
|||
sub=SubItem(name=data.new_sub.new_sub_name), |
|||
multi=[SubItem(name=s.new_sub_name) for s in data.new_multi], |
|||
) |
|||
|
|||
@app.post("/v2-to-v1/item-filter", response_model=Union[Item, None]) |
|||
def handle_v2_item_to_v1_filter(data: NewItem) -> Any: |
|||
if data.new_size < 0: |
|||
return None |
|||
result = { |
|||
"title": data.new_title, |
|||
"size": data.new_size, |
|||
"description": data.new_description, |
|||
"sub": {"name": data.new_sub.new_sub_name, "sub_secret": "sub_hidden"}, |
|||
"multi": [ |
|||
{"name": s.new_sub_name, "sub_secret": "sub_hidden"} |
|||
for s in data.new_multi |
|||
], |
|||
"secret": "hidden_v2_to_v1", |
|||
} |
|||
return result |
|||
|
|||
|
|||
client = TestClient(app) |
|||
|
|||
|
|||
def test_v1_to_v2_item_success(): |
|||
response = client.post( |
|||
"/v1-to-v2/", |
|||
json={ |
|||
"title": "Old Item", |
|||
"size": 100, |
|||
"description": "V1 description", |
|||
"sub": {"name": "V1 Sub"}, |
|||
"multi": [{"name": "M1"}, {"name": "M2"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"new_title": "Old Item", |
|||
"new_size": 100, |
|||
"new_description": "V1 description", |
|||
"new_sub": {"new_sub_name": "V1 Sub"}, |
|||
"new_multi": [{"new_sub_name": "M1"}, {"new_sub_name": "M2"}], |
|||
} |
|||
|
|||
|
|||
def test_v1_to_v2_item_returns_none(): |
|||
response = client.post( |
|||
"/v1-to-v2/", |
|||
json={"title": "Invalid Item", "size": -10, "sub": {"name": "Sub"}}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() is None |
|||
|
|||
|
|||
def test_v1_to_v2_item_minimal(): |
|||
response = client.post( |
|||
"/v1-to-v2/", json={"title": "Minimal", "size": 50, "sub": {"name": "MinSub"}} |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"new_title": "Minimal", |
|||
"new_size": 50, |
|||
"new_description": None, |
|||
"new_sub": {"new_sub_name": "MinSub"}, |
|||
"new_multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v1_to_v2_item_filter_success(): |
|||
response = client.post( |
|||
"/v1-to-v2/item-filter", |
|||
json={ |
|||
"title": "Filtered Item", |
|||
"size": 50, |
|||
"sub": {"name": "Sub"}, |
|||
"multi": [{"name": "Multi1"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert result["new_title"] == "Filtered Item" |
|||
assert result["new_size"] == 50 |
|||
assert result["new_sub"]["new_sub_name"] == "Sub" |
|||
assert result["new_multi"][0]["new_sub_name"] == "Multi1" |
|||
# Verify secret fields are filtered out |
|||
assert "secret" not in result |
|||
assert "new_sub_secret" not in result["new_sub"] |
|||
assert "new_sub_secret" not in result["new_multi"][0] |
|||
|
|||
|
|||
def test_v1_to_v2_item_filter_returns_none(): |
|||
response = client.post( |
|||
"/v1-to-v2/item-filter", |
|||
json={"title": "Invalid", "size": -1, "sub": {"name": "Sub"}}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() is None |
|||
|
|||
|
|||
def test_v2_to_v1_item_success(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "New Item", |
|||
"new_size": 200, |
|||
"new_description": "V2 description", |
|||
"new_sub": {"new_sub_name": "V2 Sub"}, |
|||
"new_multi": [{"new_sub_name": "N1"}, {"new_sub_name": "N2"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "New Item", |
|||
"size": 200, |
|||
"description": "V2 description", |
|||
"sub": {"name": "V2 Sub"}, |
|||
"multi": [{"name": "N1"}, {"name": "N2"}], |
|||
} |
|||
|
|||
|
|||
def test_v2_to_v1_item_returns_none(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "Invalid New", |
|||
"new_size": -5, |
|||
"new_sub": {"new_sub_name": "NewSub"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() is None |
|||
|
|||
|
|||
def test_v2_to_v1_item_minimal(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "MinimalNew", |
|||
"new_size": 75, |
|||
"new_sub": {"new_sub_name": "MinNewSub"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"title": "MinimalNew", |
|||
"size": 75, |
|||
"description": None, |
|||
"sub": {"name": "MinNewSub"}, |
|||
"multi": [], |
|||
} |
|||
|
|||
|
|||
def test_v2_to_v1_item_filter_success(): |
|||
response = client.post( |
|||
"/v2-to-v1/item-filter", |
|||
json={ |
|||
"new_title": "Filtered New", |
|||
"new_size": 75, |
|||
"new_sub": {"new_sub_name": "NewSub"}, |
|||
"new_multi": [], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
result = response.json() |
|||
assert result["title"] == "Filtered New" |
|||
assert result["size"] == 75 |
|||
assert result["sub"]["name"] == "NewSub" |
|||
# Verify secret fields are filtered out |
|||
assert "secret" not in result |
|||
assert "sub_secret" not in result["sub"] |
|||
|
|||
|
|||
def test_v2_to_v1_item_filter_returns_none(): |
|||
response = client.post( |
|||
"/v2-to-v1/item-filter", |
|||
json={ |
|||
"new_title": "Invalid Filtered", |
|||
"new_size": -100, |
|||
"new_sub": {"new_sub_name": "Sub"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() is None |
|||
|
|||
|
|||
def test_v1_to_v2_validation_error(): |
|||
response = client.post("/v1-to-v2/", json={"title": "Missing fields"}) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"loc": ["body", "size"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
}, |
|||
{ |
|||
"loc": ["body", "sub"], |
|||
"msg": "field required", |
|||
"type": "value_error.missing", |
|||
}, |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_v1_to_v2_nested_validation_error(): |
|||
response = client.post( |
|||
"/v1-to-v2/", |
|||
json={"title": "Bad sub", "size": 100, "sub": {"wrong_field": "value"}}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
error_detail = response.json()["detail"] |
|||
assert len(error_detail) == 1 |
|||
assert error_detail[0]["loc"] == ["body", "sub", "name"] |
|||
|
|||
|
|||
def test_v1_to_v2_type_validation_error(): |
|||
response = client.post( |
|||
"/v1-to-v2/", |
|||
json={"title": "Bad type", "size": "not_a_number", "sub": {"name": "Sub"}}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
error_detail = response.json()["detail"] |
|||
assert len(error_detail) == 1 |
|||
assert error_detail[0]["loc"] == ["body", "size"] |
|||
|
|||
|
|||
def test_v2_to_v1_validation_error(): |
|||
response = client.post("/v2-to-v1/item", json={"new_title": "Missing fields"}) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"type": "missing", |
|||
"loc": ["body", "new_size"], |
|||
"msg": "Field required", |
|||
"input": {"new_title": "Missing fields"}, |
|||
}, |
|||
{ |
|||
"type": "missing", |
|||
"loc": ["body", "new_sub"], |
|||
"msg": "Field required", |
|||
"input": {"new_title": "Missing fields"}, |
|||
}, |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_v2_to_v1_nested_validation_error(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "Bad sub", |
|||
"new_size": 200, |
|||
"new_sub": {"wrong_field": "value"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"type": "missing", |
|||
"loc": ["body", "new_sub", "new_sub_name"], |
|||
"msg": "Field required", |
|||
"input": {"wrong_field": "value"}, |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_v2_to_v1_type_validation_error(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "Bad type", |
|||
"new_size": "not_a_number", |
|||
"new_sub": {"new_sub_name": "Sub"}, |
|||
}, |
|||
) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"detail": [ |
|||
{ |
|||
"type": "int_parsing", |
|||
"loc": ["body", "new_size"], |
|||
"msg": "Input should be a valid integer, unable to parse string as an integer", |
|||
"input": "not_a_number", |
|||
} |
|||
] |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_v1_to_v2_with_multi_items(): |
|||
response = client.post( |
|||
"/v1-to-v2/", |
|||
json={ |
|||
"title": "Complex Item", |
|||
"size": 300, |
|||
"description": "Item with multiple sub-items", |
|||
"sub": {"name": "Main Sub"}, |
|||
"multi": [{"name": "Sub1"}, {"name": "Sub2"}, {"name": "Sub3"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"new_title": "Complex Item", |
|||
"new_size": 300, |
|||
"new_description": "Item with multiple sub-items", |
|||
"new_sub": {"new_sub_name": "Main Sub"}, |
|||
"new_multi": [ |
|||
{"new_sub_name": "Sub1"}, |
|||
{"new_sub_name": "Sub2"}, |
|||
{"new_sub_name": "Sub3"}, |
|||
], |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_v2_to_v1_with_multi_items(): |
|||
response = client.post( |
|||
"/v2-to-v1/item", |
|||
json={ |
|||
"new_title": "Complex New Item", |
|||
"new_size": 400, |
|||
"new_description": "New item with multiple sub-items", |
|||
"new_sub": {"new_sub_name": "Main New Sub"}, |
|||
"new_multi": [{"new_sub_name": "NewSub1"}, {"new_sub_name": "NewSub2"}], |
|||
}, |
|||
) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"title": "Complex New Item", |
|||
"size": 400, |
|||
"description": "New item with multiple sub-items", |
|||
"sub": {"name": "Main New Sub"}, |
|||
"multi": [{"name": "NewSub1"}, {"name": "NewSub2"}], |
|||
} |
|||
) |
|||
|
|||
|
|||
def test_openapi_schema(): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/v1-to-v2/": { |
|||
"post": { |
|||
"summary": "Handle V1 Item To V2", |
|||
"operationId": "handle_v1_item_to_v2_v1_to_v2__post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"anyOf": [ |
|||
{ |
|||
"$ref": "#/components/schemas/NewItem" |
|||
}, |
|||
{"type": "null"}, |
|||
], |
|||
"title": "Response Handle V1 Item To V2 V1 To V2 Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v1-to-v2/item-filter": { |
|||
"post": { |
|||
"summary": "Handle V1 Item To V2 Filter", |
|||
"operationId": "handle_v1_item_to_v2_filter_v1_to_v2_item_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Data", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"anyOf": [ |
|||
{ |
|||
"$ref": "#/components/schemas/NewItem" |
|||
}, |
|||
{"type": "null"}, |
|||
], |
|||
"title": "Response Handle V1 Item To V2 Filter V1 To V2 Item Filter Post", |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/item": { |
|||
"post": { |
|||
"summary": "Handle V2 Item To V1", |
|||
"operationId": "handle_v2_item_to_v1_v2_to_v1_item_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/NewItem"} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
"/v2-to-v1/item-filter": { |
|||
"post": { |
|||
"summary": "Handle V2 Item To V1 Filter", |
|||
"operationId": "handle_v2_item_to_v1_filter_v2_to_v1_item_filter_post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/NewItem"} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"title": {"type": "string", "title": "Title"}, |
|||
"size": {"type": "integer", "title": "Size"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"sub": {"$ref": "#/components/schemas/SubItem"}, |
|||
"multi": { |
|||
"items": {"$ref": "#/components/schemas/SubItem"}, |
|||
"type": "array", |
|||
"title": "Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["title", "size", "sub"], |
|||
"title": "Item", |
|||
}, |
|||
"NewItem": { |
|||
"properties": { |
|||
"new_title": {"type": "string", "title": "New Title"}, |
|||
"new_size": {"type": "integer", "title": "New Size"}, |
|||
"new_description": { |
|||
"anyOf": [{"type": "string"}, {"type": "null"}], |
|||
"title": "New Description", |
|||
}, |
|||
"new_sub": {"$ref": "#/components/schemas/NewSubItem"}, |
|||
"new_multi": { |
|||
"items": {"$ref": "#/components/schemas/NewSubItem"}, |
|||
"type": "array", |
|||
"title": "New Multi", |
|||
"default": [], |
|||
}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["new_title", "new_size", "new_sub"], |
|||
"title": "NewItem", |
|||
}, |
|||
"NewSubItem": { |
|||
"properties": { |
|||
"new_sub_name": {"type": "string", "title": "New Sub Name"} |
|||
}, |
|||
"type": "object", |
|||
"required": ["new_sub_name"], |
|||
"title": "NewSubItem", |
|||
}, |
|||
"SubItem": { |
|||
"properties": {"name": {"type": "string", "title": "Name"}}, |
|||
"type": "object", |
|||
"required": ["name"], |
|||
"title": "SubItem", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
@ -1,31 +0,0 @@ |
|||
import sys |
|||
from typing import Any |
|||
|
|||
import pytest |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
|
|||
import importlib |
|||
|
|||
from ...utils import needs_py310 |
|||
|
|||
|
|||
@pytest.fixture( |
|||
name="mod", |
|||
params=[ |
|||
"tutorial001_an_py39", |
|||
pytest.param("tutorial001_an_py310", marks=needs_py310), |
|||
], |
|||
) |
|||
def get_mod(request: pytest.FixtureRequest): |
|||
mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}") |
|||
return mod |
|||
|
|||
|
|||
def test_model(mod: Any): |
|||
item = mod.Item(name="Foo", size=3.4) |
|||
assert item.dict() == {"name": "Foo", "description": None, "size": 3.4} |
|||
@ -1,142 +0,0 @@ |
|||
import sys |
|||
import warnings |
|||
|
|||
import pytest |
|||
from inline_snapshot import snapshot |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
|
|||
import importlib |
|||
|
|||
from fastapi.testclient import TestClient |
|||
|
|||
from ...utils import needs_py310 |
|||
|
|||
|
|||
@pytest.fixture( |
|||
name="client", |
|||
params=[ |
|||
"tutorial002_an_py39", |
|||
pytest.param("tutorial002_an_py310", marks=needs_py310), |
|||
], |
|||
) |
|||
def get_client(request: pytest.FixtureRequest): |
|||
with warnings.catch_warnings(record=True): |
|||
warnings.filterwarnings( |
|||
"ignore", |
|||
message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*", |
|||
category=DeprecationWarning, |
|||
) |
|||
mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}") |
|||
|
|||
c = TestClient(mod.app) |
|||
return c |
|||
|
|||
|
|||
def test_call(client: TestClient): |
|||
response = client.post("/items/", json={"name": "Foo", "size": 3.4}) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"name": "Foo", |
|||
"description": None, |
|||
"size": 3.4, |
|||
} |
|||
|
|||
|
|||
def test_openapi_schema(client: TestClient): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/items/": { |
|||
"post": { |
|||
"summary": "Create Item", |
|||
"operationId": "create_item_items__post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Item", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
} |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"name": {"type": "string", "title": "Name"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"size": {"type": "number", "title": "Size"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["name", "size"], |
|||
"title": "Item", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
@ -1,157 +0,0 @@ |
|||
import sys |
|||
import warnings |
|||
|
|||
import pytest |
|||
from inline_snapshot import snapshot |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
|
|||
import importlib |
|||
|
|||
from fastapi.testclient import TestClient |
|||
|
|||
from ...utils import needs_py310 |
|||
|
|||
|
|||
@pytest.fixture( |
|||
name="client", |
|||
params=[ |
|||
"tutorial003_an_py39", |
|||
pytest.param("tutorial003_an_py310", marks=needs_py310), |
|||
], |
|||
) |
|||
def get_client(request: pytest.FixtureRequest): |
|||
with warnings.catch_warnings(record=True): |
|||
warnings.filterwarnings( |
|||
"ignore", |
|||
message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*", |
|||
category=DeprecationWarning, |
|||
) |
|||
mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}") |
|||
|
|||
c = TestClient(mod.app) |
|||
return c |
|||
|
|||
|
|||
def test_call(client: TestClient): |
|||
response = client.post("/items/", json={"name": "Foo", "size": 3.4}) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"name": "Foo", |
|||
"description": None, |
|||
"size": 3.4, |
|||
} |
|||
|
|||
|
|||
def test_openapi_schema(client: TestClient): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/items/": { |
|||
"post": { |
|||
"summary": "Create Item", |
|||
"operationId": "create_item_items__post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
"title": "Item", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/ItemV2" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
} |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"name": {"type": "string", "title": "Name"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"size": {"type": "number", "title": "Size"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["name", "size"], |
|||
"title": "Item", |
|||
}, |
|||
"ItemV2": { |
|||
"properties": { |
|||
"name": {"type": "string", "title": "Name"}, |
|||
"description": { |
|||
"anyOf": [{"type": "string"}, {"type": "null"}], |
|||
"title": "Description", |
|||
}, |
|||
"size": {"type": "number", "title": "Size"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["name", "size"], |
|||
"title": "ItemV2", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
@ -1,155 +0,0 @@ |
|||
import sys |
|||
import warnings |
|||
|
|||
import pytest |
|||
from inline_snapshot import snapshot |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
|
|||
import importlib |
|||
|
|||
from fastapi.testclient import TestClient |
|||
|
|||
from ...utils import needs_py310 |
|||
|
|||
|
|||
@pytest.fixture( |
|||
name="client", |
|||
params=[ |
|||
pytest.param("tutorial004_an_py39"), |
|||
pytest.param("tutorial004_an_py310", marks=needs_py310), |
|||
], |
|||
) |
|||
def get_client(request: pytest.FixtureRequest): |
|||
with warnings.catch_warnings(record=True): |
|||
warnings.filterwarnings( |
|||
"ignore", |
|||
message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*", |
|||
category=DeprecationWarning, |
|||
) |
|||
mod = importlib.import_module(f"docs_src.pydantic_v1_in_v2.{request.param}") |
|||
|
|||
c = TestClient(mod.app) |
|||
return c |
|||
|
|||
|
|||
def test_call(client: TestClient): |
|||
response = client.post("/items/", json={"item": {"name": "Foo", "size": 3.4}}) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"name": "Foo", |
|||
"description": None, |
|||
"size": 3.4, |
|||
} |
|||
|
|||
|
|||
def test_openapi_schema(client: TestClient): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/items/": { |
|||
"post": { |
|||
"summary": "Create Item", |
|||
"operationId": "create_item_items__post", |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"allOf": [ |
|||
{ |
|||
"$ref": "#/components/schemas/Body_create_item_items__post" |
|||
} |
|||
], |
|||
"title": "Body", |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": {"$ref": "#/components/schemas/Item"} |
|||
} |
|||
}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
} |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"Body_create_item_items__post": { |
|||
"properties": { |
|||
"item": { |
|||
"allOf": [{"$ref": "#/components/schemas/Item"}], |
|||
"title": "Item", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"required": ["item"], |
|||
"title": "Body_create_item_items__post", |
|||
}, |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"name": {"type": "string", "title": "Name"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"size": {"type": "number", "title": "Size"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["name", "size"], |
|||
"title": "Item", |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
@ -1,127 +0,0 @@ |
|||
import importlib |
|||
import warnings |
|||
|
|||
import pytest |
|||
from fastapi.testclient import TestClient |
|||
|
|||
from ...utils import needs_pydanticv1 |
|||
|
|||
|
|||
@pytest.fixture( |
|||
name="client", |
|||
params=[ |
|||
"tutorial002_pv1_py39", |
|||
"tutorial002_pv1_an_py39", |
|||
], |
|||
) |
|||
def get_client(request: pytest.FixtureRequest): |
|||
with warnings.catch_warnings(record=True): |
|||
warnings.filterwarnings( |
|||
"ignore", |
|||
message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*", |
|||
category=DeprecationWarning, |
|||
) |
|||
mod = importlib.import_module(f"docs_src.request_form_models.{request.param}") |
|||
|
|||
client = TestClient(mod.app) |
|||
return client |
|||
|
|||
|
|||
# TODO: remove when deprecating Pydantic v1 |
|||
@needs_pydanticv1 |
|||
def test_post_body_form(client: TestClient): |
|||
response = client.post("/login/", data={"username": "Foo", "password": "secret"}) |
|||
assert response.status_code == 200 |
|||
assert response.json() == {"username": "Foo", "password": "secret"} |
|||
|
|||
|
|||
# TODO: remove when deprecating Pydantic v1 |
|||
@needs_pydanticv1 |
|||
def test_post_body_extra_form(client: TestClient): |
|||
response = client.post( |
|||
"/login/", data={"username": "Foo", "password": "secret", "extra": "extra"} |
|||
) |
|||
assert response.status_code == 422 |
|||
assert response.json() == { |
|||
"detail": [ |
|||
{ |
|||
"type": "value_error.extra", |
|||
"loc": ["body", "extra"], |
|||
"msg": "extra fields not permitted", |
|||
} |
|||
] |
|||
} |
|||
|
|||
|
|||
# TODO: remove when deprecating Pydantic v1 |
|||
@needs_pydanticv1 |
|||
def test_post_body_form_no_password(client: TestClient): |
|||
response = client.post("/login/", data={"username": "Foo"}) |
|||
assert response.status_code == 422 |
|||
assert response.json() == { |
|||
"detail": [ |
|||
{ |
|||
"type": "value_error.missing", |
|||
"loc": ["body", "password"], |
|||
"msg": "field required", |
|||
} |
|||
] |
|||
} |
|||
|
|||
|
|||
# TODO: remove when deprecating Pydantic v1 |
|||
@needs_pydanticv1 |
|||
def test_post_body_form_no_username(client: TestClient): |
|||
response = client.post("/login/", data={"password": "secret"}) |
|||
assert response.status_code == 422 |
|||
assert response.json() == { |
|||
"detail": [ |
|||
{ |
|||
"type": "value_error.missing", |
|||
"loc": ["body", "username"], |
|||
"msg": "field required", |
|||
} |
|||
] |
|||
} |
|||
|
|||
|
|||
# TODO: remove when deprecating Pydantic v1 |
|||
@needs_pydanticv1 |
|||
def test_post_body_form_no_data(client: TestClient): |
|||
response = client.post("/login/") |
|||
assert response.status_code == 422 |
|||
assert response.json() == { |
|||
"detail": [ |
|||
{ |
|||
"type": "value_error.missing", |
|||
"loc": ["body", "username"], |
|||
"msg": "field required", |
|||
}, |
|||
{ |
|||
"type": "value_error.missing", |
|||
"loc": ["body", "password"], |
|||
"msg": "field required", |
|||
}, |
|||
] |
|||
} |
|||
|
|||
|
|||
# TODO: remove when deprecating Pydantic v1 |
|||
@needs_pydanticv1 |
|||
def test_post_body_json(client: TestClient): |
|||
response = client.post("/login/", json={"username": "Foo", "password": "secret"}) |
|||
assert response.status_code == 422, response.text |
|||
assert response.json() == { |
|||
"detail": [ |
|||
{ |
|||
"type": "value_error.missing", |
|||
"loc": ["body", "username"], |
|||
"msg": "field required", |
|||
}, |
|||
{ |
|||
"type": "value_error.missing", |
|||
"loc": ["body", "password"], |
|||
"msg": "field required", |
|||
}, |
|||
] |
|||
} |
|||
@ -1,151 +0,0 @@ |
|||
import importlib |
|||
import warnings |
|||
|
|||
import pytest |
|||
from fastapi.testclient import TestClient |
|||
from inline_snapshot import snapshot |
|||
|
|||
from ...utils import needs_py310, needs_pydanticv1 |
|||
|
|||
|
|||
@pytest.fixture( |
|||
name="client", |
|||
params=[ |
|||
pytest.param("tutorial001_pv1_py39"), |
|||
pytest.param("tutorial001_pv1_py310", marks=needs_py310), |
|||
], |
|||
) |
|||
def get_client(request: pytest.FixtureRequest): |
|||
with warnings.catch_warnings(record=True): |
|||
warnings.filterwarnings( |
|||
"ignore", |
|||
message=r"pydantic\.v1 is deprecated and will soon stop being supported by FastAPI\..*", |
|||
category=DeprecationWarning, |
|||
) |
|||
mod = importlib.import_module(f"docs_src.schema_extra_example.{request.param}") |
|||
|
|||
client = TestClient(mod.app) |
|||
return client |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_post_body_example(client: TestClient): |
|||
response = client.put( |
|||
"/items/5", |
|||
json={ |
|||
"name": "Foo", |
|||
"description": "A very nice Item", |
|||
"price": 35.4, |
|||
"tax": 3.2, |
|||
}, |
|||
) |
|||
assert response.status_code == 200 |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_openapi_schema(client: TestClient): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == snapshot( |
|||
{ |
|||
"openapi": "3.1.0", |
|||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|||
"paths": { |
|||
"/items/{item_id}": { |
|||
"put": { |
|||
"summary": "Update Item", |
|||
"operationId": "update_item_items__item_id__put", |
|||
"parameters": [ |
|||
{ |
|||
"required": True, |
|||
"schema": {"type": "integer", "title": "Item Id"}, |
|||
"name": "item_id", |
|||
"in": "path", |
|||
} |
|||
], |
|||
"requestBody": { |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"title": "Item", |
|||
"allOf": [ |
|||
{"$ref": "#/components/schemas/Item"} |
|||
], |
|||
} |
|||
} |
|||
}, |
|||
"required": True, |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful Response", |
|||
"content": {"application/json": {"schema": {}}}, |
|||
}, |
|||
"422": { |
|||
"description": "Validation Error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/HTTPValidationError" |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
} |
|||
} |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"HTTPValidationError": { |
|||
"properties": { |
|||
"detail": { |
|||
"items": { |
|||
"$ref": "#/components/schemas/ValidationError" |
|||
}, |
|||
"type": "array", |
|||
"title": "Detail", |
|||
} |
|||
}, |
|||
"type": "object", |
|||
"title": "HTTPValidationError", |
|||
}, |
|||
"Item": { |
|||
"properties": { |
|||
"name": {"type": "string", "title": "Name"}, |
|||
"description": {"type": "string", "title": "Description"}, |
|||
"price": {"type": "number", "title": "Price"}, |
|||
"tax": {"type": "number", "title": "Tax"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["name", "price"], |
|||
"title": "Item", |
|||
"examples": [ |
|||
{ |
|||
"name": "Foo", |
|||
"description": "A very nice Item", |
|||
"price": 35.4, |
|||
"tax": 3.2, |
|||
} |
|||
], |
|||
}, |
|||
"ValidationError": { |
|||
"properties": { |
|||
"loc": { |
|||
"items": { |
|||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|||
}, |
|||
"type": "array", |
|||
"title": "Location", |
|||
}, |
|||
"msg": {"type": "string", "title": "Message"}, |
|||
"type": {"type": "string", "title": "Error Type"}, |
|||
}, |
|||
"type": "object", |
|||
"required": ["loc", "msg", "type"], |
|||
"title": "ValidationError", |
|||
}, |
|||
} |
|||
}, |
|||
} |
|||
) |
|||
Loading…
Reference in new issue