Files
fastapi/tests/test_tuples.py
Sebastián Ramírez 7dad5a820b Add support for OpenAPI 3.1.0 (#9770)
*  Update OpenAPI models for JSON Schema 2020-12 and OpenAPI 3.1.0

*  Add support for summary and webhooks

*  Update JSON Schema for UploadFiles

* ️ Revert making paths optional, to ensure always correctness

* ️ Keep UploadFile as format: binary for compatibility with the rest of Pydantic bytes fields in v1

*  Update version of OpenAPI generated to 3.1.0

*  Update the version of Swagger UI

* 📝 Update docs about extending OpenAPI

* 📝 Update docs and links to refer to OpenAPI 3.1.0

*  Update logic for handling webhooks

* ♻️ Update parameter functions and classes, deprecate example and make examples the main field

*  Update tests for OpenAPI 3.1.0

* 📝 Update examples for OpenAPI metadata

*  Add and update tests for OpenAPI metadata

* 📝 Add source example for webhooks

* 📝 Update docs for metadata

* 📝 Update docs for Schema extra

* 📝 Add docs for webhooks

* 🔧 Add webhooks docs to MkDocs

*  Update tests for extending OpenAPI

*  Add tests for webhooks

* ♻️ Refactor generation of OpenAPI and JSON Schema with params

* 📝 Update source examples for field examples

*  Update tests for examples

*  Make sure the minimum version of typing-extensions installed has deprecated() (already a dependency of Pydantic)

* ✏️ Fix typo in Webhooks example code

* 🔥 Remove commented out code of removed nullable field

* 🗑️ Add deprecation warnings for example argument

*  Update tests to check for deprecation warnings

*  Add test for webhooks with security schemes, for coverage

* 🍱 Update image for metadata, with new summary

* 🍱 Add docs image for Webhooks

* 📝 Update docs for webhooks, add docs UI image
2023-06-30 20:25:16 +02:00

266 lines
9.6 KiB
Python

from typing import List, Tuple
from fastapi import FastAPI, Form
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI()
class ItemGroup(BaseModel):
items: List[Tuple[str, str]]
class Coordinate(BaseModel):
x: float
y: float
@app.post("/model-with-tuple/")
def post_model_with_tuple(item_group: ItemGroup):
return item_group
@app.post("/tuple-of-models/")
def post_tuple_of_models(square: Tuple[Coordinate, Coordinate]):
return square
@app.post("/tuple-form/")
def hello(values: Tuple[int, int] = Form()):
return values
client = TestClient(app)
def test_model_with_tuple_valid():
data = {"items": [["foo", "bar"], ["baz", "whatelse"]]}
response = client.post("/model-with-tuple/", json=data)
assert response.status_code == 200, response.text
assert response.json() == data
def test_model_with_tuple_invalid():
data = {"items": [["foo", "bar"], ["baz", "whatelse", "too", "much"]]}
response = client.post("/model-with-tuple/", json=data)
assert response.status_code == 422, response.text
data = {"items": [["foo", "bar"], ["baz"]]}
response = client.post("/model-with-tuple/", json=data)
assert response.status_code == 422, response.text
def test_tuple_with_model_valid():
data = [{"x": 1, "y": 2}, {"x": 3, "y": 4}]
response = client.post("/tuple-of-models/", json=data)
assert response.status_code == 200, response.text
assert response.json() == data
def test_tuple_with_model_invalid():
data = [{"x": 1, "y": 2}, {"x": 3, "y": 4}, {"x": 5, "y": 6}]
response = client.post("/tuple-of-models/", json=data)
assert response.status_code == 422, response.text
data = [{"x": 1, "y": 2}]
response = client.post("/tuple-of-models/", json=data)
assert response.status_code == 422, response.text
def test_tuple_form_valid():
response = client.post("/tuple-form/", data={"values": ("1", "2")})
assert response.status_code == 200, response.text
assert response.json() == [1, 2]
def test_tuple_form_invalid():
response = client.post("/tuple-form/", data={"values": ("1", "2", "3")})
assert response.status_code == 422, response.text
response = client.post("/tuple-form/", data={"values": ("1")})
assert response.status_code == 422, response.text
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/model-with-tuple/": {
"post": {
"summary": "Post Model With Tuple",
"operationId": "post_model_with_tuple_model_with_tuple__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/ItemGroup"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
},
"/tuple-of-models/": {
"post": {
"summary": "Post Tuple Of Models",
"operationId": "post_tuple_of_models_tuple_of_models__post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"title": "Square",
"maxItems": 2,
"minItems": 2,
"type": "array",
"items": [
{"$ref": "#/components/schemas/Coordinate"},
{"$ref": "#/components/schemas/Coordinate"},
],
}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
},
"/tuple-form/": {
"post": {
"summary": "Hello",
"operationId": "hello_tuple_form__post",
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/Body_hello_tuple_form__post"
}
}
},
"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": {
"Body_hello_tuple_form__post": {
"title": "Body_hello_tuple_form__post",
"required": ["values"],
"type": "object",
"properties": {
"values": {
"title": "Values",
"maxItems": 2,
"minItems": 2,
"type": "array",
"items": [{"type": "integer"}, {"type": "integer"}],
}
},
},
"Coordinate": {
"title": "Coordinate",
"required": ["x", "y"],
"type": "object",
"properties": {
"x": {"title": "X", "type": "number"},
"y": {"title": "Y", "type": "number"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
"ItemGroup": {
"title": "ItemGroup",
"required": ["items"],
"type": "object",
"properties": {
"items": {
"title": "Items",
"type": "array",
"items": {
"maxItems": 2,
"minItems": 2,
"type": "array",
"items": [{"type": "string"}, {"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"},
},
},
}
},
}