|
|
|
@ -1,7 +1,7 @@ |
|
|
|
from typing import List, Optional |
|
|
|
|
|
|
|
from dirty_equals import IsDict |
|
|
|
from fastapi import FastAPI, Form |
|
|
|
from fastapi import FastAPI, File, Form |
|
|
|
from fastapi.testclient import TestClient |
|
|
|
from pydantic import BaseModel, Field |
|
|
|
from typing_extensions import Annotated |
|
|
|
@ -17,11 +17,24 @@ class FormModel(BaseModel): |
|
|
|
alias_with: str = Field(alias="with", default="nothing") |
|
|
|
|
|
|
|
|
|
|
|
class FormWithFileModel(BaseModel): |
|
|
|
comment: str |
|
|
|
file_data: bytes = File() |
|
|
|
|
|
|
|
|
|
|
|
@app.post("/form/") |
|
|
|
def post_form(user: Annotated[FormModel, Form()]): |
|
|
|
return user |
|
|
|
|
|
|
|
|
|
|
|
@app.post("/form-with-file/") |
|
|
|
def post_form_(form_data: Annotated[FormWithFileModel, Form()]): |
|
|
|
return { |
|
|
|
"comment": form_data.comment, |
|
|
|
"file_size": len(form_data.file_data), |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
client = TestClient(app) |
|
|
|
|
|
|
|
|
|
|
|
@ -131,3 +144,74 @@ def test_no_data(): |
|
|
|
] |
|
|
|
} |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
def test_form_with_file(): |
|
|
|
file_content = b"Hello, this is a test file." |
|
|
|
response = client.post( |
|
|
|
"/form-with-file/", |
|
|
|
data={"comment": "This is a comment."}, |
|
|
|
files={"file_data": ("test.txt", file_content, "text/plain")}, |
|
|
|
) |
|
|
|
assert response.status_code == 200, response.text |
|
|
|
assert response.json() == { |
|
|
|
"comment": "This is a comment.", |
|
|
|
"file_size": len(file_content), |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
def test_form_with_file_missing_file(): |
|
|
|
response = client.post( |
|
|
|
"/form-with-file/", |
|
|
|
data={"comment": "This is a comment."}, |
|
|
|
) |
|
|
|
assert response.status_code == 422, response.text |
|
|
|
assert response.json() == IsDict( |
|
|
|
{ |
|
|
|
"detail": [ |
|
|
|
{ |
|
|
|
"type": "missing", |
|
|
|
"loc": ["body", "file_data"], |
|
|
|
"msg": "Field required", |
|
|
|
"input": {"comment": "This is a comment."}, |
|
|
|
} |
|
|
|
] |
|
|
|
} |
|
|
|
) | IsDict( |
|
|
|
# TODO: remove when deprecating Pydantic v1 |
|
|
|
{ |
|
|
|
"detail": [ |
|
|
|
{ |
|
|
|
"loc": ["body", "file_data"], |
|
|
|
"msg": "field required", |
|
|
|
"type": "value_error.missing", |
|
|
|
} |
|
|
|
] |
|
|
|
} |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
def test_form_with_file_openapi(): |
|
|
|
response = client.get("/openapi.json") |
|
|
|
assert response.status_code == 200, response.text |
|
|
|
openapi_schema = response.json() |
|
|
|
assert openapi_schema["paths"]["/form-with-file/"]["post"]["requestBody"] == { |
|
|
|
"content": { |
|
|
|
"multipart/form-data": { |
|
|
|
"schema": { |
|
|
|
"$ref": "#/components/schemas/FormWithFileModel", |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
"required": True, |
|
|
|
} |
|
|
|
|
|
|
|
assert openapi_schema["components"]["schemas"]["FormWithFileModel"] == { |
|
|
|
"title": "FormWithFileModel", |
|
|
|
"type": "object", |
|
|
|
"properties": { |
|
|
|
"file_data": {"title": "File Data", "type": "string", "format": "binary"}, |
|
|
|
"comment": {"title": "Comment", "type": "string"}, |
|
|
|
}, |
|
|
|
"required": ["comment", "file_data"], |
|
|
|
} |
|
|
|
|