Coverage for tests / test_request_params / test_form / test_optional_str.py: 100%
131 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-21 17:29 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-21 17:29 +0000
1from typing import Annotated 1abcd
3import pytest 1abcd
4from fastapi import FastAPI, Form 1abcd
5from fastapi.testclient import TestClient 1abcd
6from pydantic import BaseModel, Field 1abcd
8from .utils import get_body_model_name 1abcd
10app = FastAPI() 1abcd
12# =====================================================================================
13# Without aliases
16@app.post("/optional-str", operation_id="optional_str") 1abcd
17async def read_optional_str(p: Annotated[str | None, Form()] = None): 1abcd
18 return {"p": p} 1efghij
21class FormModelOptionalStr(BaseModel): 1abcd
22 p: str | None = None 1abcd
25@app.post("/model-optional-str", operation_id="model_optional_str") 1abcd
26async def read_model_optional_str(p: Annotated[FormModelOptionalStr, Form()]): 1abcd
27 return {"p": p.p} 1efghij
30@pytest.mark.parametrize( 1abcd
31 "path",
32 ["/optional-str", "/model-optional-str"],
33)
34def test_optional_str_schema(path: str): 1abcd
35 openapi = app.openapi() 1OPQ
36 body_model_name = get_body_model_name(openapi, path) 1OPQ
38 assert app.openapi()["components"]["schemas"][body_model_name] == { 1OPQ
39 "properties": {
40 "p": {
41 "anyOf": [{"type": "string"}, {"type": "null"}],
42 "title": "P",
43 },
44 },
45 "title": body_model_name,
46 "type": "object",
47 }
50@pytest.mark.parametrize( 1abcd
51 "path",
52 ["/optional-str", "/model-optional-str"],
53)
54def test_optional_str_missing(path: str): 1abcd
55 client = TestClient(app) 1fhj
56 response = client.post(path) 1fhj
57 assert response.status_code == 200 1fhj
58 assert response.json() == {"p": None} 1fhj
61@pytest.mark.parametrize( 1abcd
62 "path",
63 ["/optional-str", "/model-optional-str"],
64)
65def test_optional_str(path: str): 1abcd
66 client = TestClient(app) 1egi
67 response = client.post(path, data={"p": "hello"}) 1egi
68 assert response.status_code == 200 1egi
69 assert response.json() == {"p": "hello"} 1egi
72# =====================================================================================
73# Alias
76@app.post("/optional-alias", operation_id="optional_alias") 1abcd
77async def read_optional_alias( 1abcd
78 p: Annotated[str | None, Form(alias="p_alias")] = None,
79):
80 return {"p": p} 1klmnopqrs
83class FormModelOptionalAlias(BaseModel): 1abcd
84 p: str | None = Field(None, alias="p_alias") 1abcd
87@app.post("/model-optional-alias", operation_id="model_optional_alias") 1abcd
88async def read_model_optional_alias(p: Annotated[FormModelOptionalAlias, Form()]): 1abcd
89 return {"p": p.p} 1klmnopqrs
92@pytest.mark.parametrize( 1abcd
93 "path",
94 [
95 "/optional-alias",
96 "/model-optional-alias",
97 ],
98)
99def test_optional_str_alias_schema(path: str): 1abcd
100 openapi = app.openapi() 1RST
101 body_model_name = get_body_model_name(openapi, path) 1RST
103 assert app.openapi()["components"]["schemas"][body_model_name] == { 1RST
104 "properties": {
105 "p_alias": {
106 "anyOf": [{"type": "string"}, {"type": "null"}],
107 "title": "P Alias",
108 },
109 },
110 "title": body_model_name,
111 "type": "object",
112 }
115@pytest.mark.parametrize( 1abcd
116 "path",
117 ["/optional-alias", "/model-optional-alias"],
118)
119def test_optional_alias_missing(path: str): 1abcd
120 client = TestClient(app) 1mps
121 response = client.post(path) 1mps
122 assert response.status_code == 200 1mps
123 assert response.json() == {"p": None} 1mps
126@pytest.mark.parametrize( 1abcd
127 "path",
128 ["/optional-alias", "/model-optional-alias"],
129)
130def test_optional_alias_by_name(path: str): 1abcd
131 client = TestClient(app) 1lor
132 response = client.post(path, data={"p": "hello"}) 1lor
133 assert response.status_code == 200 1lor
134 assert response.json() == {"p": None} 1lor
137@pytest.mark.parametrize( 1abcd
138 "path",
139 ["/optional-alias", "/model-optional-alias"],
140)
141def test_optional_alias_by_alias(path: str): 1abcd
142 client = TestClient(app) 1knq
143 response = client.post(path, data={"p_alias": "hello"}) 1knq
144 assert response.status_code == 200 1knq
145 assert response.json() == {"p": "hello"} 1knq
148# =====================================================================================
149# Validation alias
152@app.post("/optional-validation-alias", operation_id="optional_validation_alias") 1abcd
153def read_optional_validation_alias( 1abcd
154 p: Annotated[str | None, Form(validation_alias="p_val_alias")] = None,
155):
156 return {"p": p} 1tuvwxyzAB
159class FormModelOptionalValidationAlias(BaseModel): 1abcd
160 p: str | None = Field(None, validation_alias="p_val_alias") 1abcd
163@app.post( 1abcd
164 "/model-optional-validation-alias", operation_id="model_optional_validation_alias"
165)
166def read_model_optional_validation_alias( 1abcd
167 p: Annotated[FormModelOptionalValidationAlias, Form()],
168):
169 return {"p": p.p} 1tuvwxyzAB
172@pytest.mark.parametrize( 1abcd
173 "path",
174 ["/optional-validation-alias", "/model-optional-validation-alias"],
175)
176def test_optional_validation_alias_schema(path: str): 1abcd
177 openapi = app.openapi() 1UVW
178 body_model_name = get_body_model_name(openapi, path) 1UVW
180 assert app.openapi()["components"]["schemas"][body_model_name] == { 1UVW
181 "properties": {
182 "p_val_alias": {
183 "anyOf": [{"type": "string"}, {"type": "null"}],
184 "title": "P Val Alias",
185 },
186 },
187 "title": body_model_name,
188 "type": "object",
189 }
192@pytest.mark.parametrize( 1abcd
193 "path",
194 ["/optional-validation-alias", "/model-optional-validation-alias"],
195)
196def test_optional_validation_alias_missing(path: str): 1abcd
197 client = TestClient(app) 1vyB
198 response = client.post(path) 1vyB
199 assert response.status_code == 200 1vyB
200 assert response.json() == {"p": None} 1vyB
203@pytest.mark.parametrize( 1abcd
204 "path",
205 [
206 "/optional-validation-alias",
207 "/model-optional-validation-alias",
208 ],
209)
210def test_optional_validation_alias_by_name(path: str): 1abcd
211 client = TestClient(app) 1twz
212 response = client.post(path, data={"p": "hello"}) 1twz
213 assert response.status_code == 200 1twz
214 assert response.json() == {"p": None} 1twz
217@pytest.mark.parametrize( 1abcd
218 "path",
219 [
220 "/optional-validation-alias",
221 "/model-optional-validation-alias",
222 ],
223)
224def test_optional_validation_alias_by_validation_alias(path: str): 1abcd
225 client = TestClient(app) 1uxA
226 response = client.post(path, data={"p_val_alias": "hello"}) 1uxA
227 assert response.status_code == 200 1uxA
228 assert response.json() == {"p": "hello"} 1uxA
231# =====================================================================================
232# Alias and validation alias
235@app.post( 1abcd
236 "/optional-alias-and-validation-alias",
237 operation_id="optional_alias_and_validation_alias",
238)
239def read_optional_alias_and_validation_alias( 1abcd
240 p: Annotated[
241 str | None, Form(alias="p_alias", validation_alias="p_val_alias")
242 ] = None,
243):
244 return {"p": p} 1CDEFGHIJKLMN
247class FormModelOptionalAliasAndValidationAlias(BaseModel): 1abcd
248 p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias") 1abcd
251@app.post( 1abcd
252 "/model-optional-alias-and-validation-alias",
253 operation_id="model_optional_alias_and_validation_alias",
254)
255def read_model_optional_alias_and_validation_alias( 1abcd
256 p: Annotated[FormModelOptionalAliasAndValidationAlias, Form()],
257):
258 return {"p": p.p} 1CDEFGHIJKLMN
261@pytest.mark.parametrize( 1abcd
262 "path",
263 [
264 "/optional-alias-and-validation-alias",
265 "/model-optional-alias-and-validation-alias",
266 ],
267)
268def test_optional_alias_and_validation_alias_schema(path: str): 1abcd
269 openapi = app.openapi() 1XYZ
270 body_model_name = get_body_model_name(openapi, path) 1XYZ
272 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ
273 "properties": {
274 "p_val_alias": {
275 "anyOf": [{"type": "string"}, {"type": "null"}],
276 "title": "P Val Alias",
277 },
278 },
279 "title": body_model_name,
280 "type": "object",
281 }
284@pytest.mark.parametrize( 1abcd
285 "path",
286 [
287 "/optional-alias-and-validation-alias",
288 "/model-optional-alias-and-validation-alias",
289 ],
290)
291def test_optional_alias_and_validation_alias_missing(path: str): 1abcd
292 client = TestClient(app) 1FJN
293 response = client.post(path) 1FJN
294 assert response.status_code == 200 1FJN
295 assert response.json() == {"p": None} 1FJN
298@pytest.mark.parametrize( 1abcd
299 "path",
300 [
301 "/optional-alias-and-validation-alias",
302 "/model-optional-alias-and-validation-alias",
303 ],
304)
305def test_optional_alias_and_validation_alias_by_name(path: str): 1abcd
306 client = TestClient(app) 1DHL
307 response = client.post(path, data={"p": "hello"}) 1DHL
308 assert response.status_code == 200 1DHL
309 assert response.json() == {"p": None} 1DHL
312@pytest.mark.parametrize( 1abcd
313 "path",
314 [
315 "/optional-alias-and-validation-alias",
316 "/model-optional-alias-and-validation-alias",
317 ],
318)
319def test_optional_alias_and_validation_alias_by_alias(path: str): 1abcd
320 client = TestClient(app) 1CGK
321 response = client.post(path, data={"p_alias": "hello"}) 1CGK
322 assert response.status_code == 200 1CGK
323 assert response.json() == {"p": None} 1CGK
326@pytest.mark.parametrize( 1abcd
327 "path",
328 [
329 "/optional-alias-and-validation-alias",
330 "/model-optional-alias-and-validation-alias",
331 ],
332)
333def test_optional_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
334 client = TestClient(app) 1EIM
335 response = client.post(path, data={"p_val_alias": "hello"}) 1EIM
336 assert response.status_code == 200 1EIM
337 assert response.json() == {"p": "hello"} 1EIM