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-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1from typing import Annotated, Optional 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[Optional[str], Form()] = None): 1abcd
18 return {"p": p} 1efghij
21class FormModelOptionalStr(BaseModel): 1abcd
22 p: Optional[str] = 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[Optional[str], Form(alias="p_alias")] = None,
79):
80 return {"p": p} 1klmnopqrs
83class FormModelOptionalAlias(BaseModel): 1abcd
84 p: Optional[str] = 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[Optional[str], Form(validation_alias="p_val_alias")] = None,
155):
156 return {"p": p} 1tuvwxyzAB
159class FormModelOptionalValidationAlias(BaseModel): 1abcd
160 p: Optional[str] = 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 Optional[str], Form(alias="p_alias", validation_alias="p_val_alias")
242 ] = None,
243):
244 return {"p": p} 1CDEFGHIJKLMN
247class FormModelOptionalAliasAndValidationAlias(BaseModel): 1abcd
248 p: Optional[str] = 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