Coverage for tests / test_request_params / test_form / test_required_str.py: 100%
132 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 1abcd
3import pytest 1abcd
4from dirty_equals import IsOneOf 1abcd
5from fastapi import FastAPI, Form 1abcd
6from fastapi.testclient import TestClient 1abcd
7from pydantic import BaseModel, Field 1abcd
9from .utils import get_body_model_name 1abcd
11app = FastAPI() 1abcd
13# =====================================================================================
14# Without aliases
17@app.post("/required-str", operation_id="required_str") 1abcd
18async def read_required_str(p: Annotated[str, Form()]): 1abcd
19 return {"p": p} 1efg
22class FormModelRequiredStr(BaseModel): 1abcd
23 p: str 1abcd
26@app.post("/model-required-str", operation_id="model_required_str") 1abcd
27async def read_model_required_str(p: Annotated[FormModelRequiredStr, Form()]): 1abcd
28 return {"p": p.p} 1efg
31@pytest.mark.parametrize( 1abcd
32 "path",
33 ["/required-str", "/model-required-str"],
34)
35def test_required_str_schema(path: str): 1abcd
36 openapi = app.openapi() 1OPQ
37 body_model_name = get_body_model_name(openapi, path) 1OPQ
39 assert app.openapi()["components"]["schemas"][body_model_name] == { 1OPQ
40 "properties": {
41 "p": {"title": "P", "type": "string"},
42 },
43 "required": ["p"],
44 "title": body_model_name,
45 "type": "object",
46 }
49@pytest.mark.parametrize( 1abcd
50 "path",
51 ["/required-str", "/model-required-str"],
52)
53def test_required_str_missing(path: str): 1abcd
54 client = TestClient(app) 1qrs
55 response = client.post(path) 1qrs
56 assert response.status_code == 422 1qrs
57 assert response.json() == { 1qrs
58 "detail": [
59 {
60 "type": "missing",
61 "loc": ["body", "p"],
62 "msg": "Field required",
63 "input": IsOneOf(None, {}),
64 }
65 ]
66 }
69@pytest.mark.parametrize( 1abcd
70 "path",
71 ["/required-str", "/model-required-str"],
72)
73def test_required_str(path: str): 1abcd
74 client = TestClient(app) 1efg
75 response = client.post(path, data={"p": "hello"}) 1efg
76 assert response.status_code == 200 1efg
77 assert response.json() == {"p": "hello"} 1efg
80# =====================================================================================
81# Alias
84@app.post("/required-alias", operation_id="required_alias") 1abcd
85async def read_required_alias(p: Annotated[str, Form(alias="p_alias")]): 1abcd
86 return {"p": p} 1hij
89class FormModelRequiredAlias(BaseModel): 1abcd
90 p: str = Field(alias="p_alias") 1abcd
93@app.post("/model-required-alias", operation_id="model_required_alias") 1abcd
94async def read_model_required_alias(p: Annotated[FormModelRequiredAlias, Form()]): 1abcd
95 return {"p": p.p} 1hij
98@pytest.mark.parametrize( 1abcd
99 "path",
100 [
101 "/required-alias",
102 "/model-required-alias",
103 ],
104)
105def test_required_str_alias_schema(path: str): 1abcd
106 openapi = app.openapi() 1RST
107 body_model_name = get_body_model_name(openapi, path) 1RST
109 assert app.openapi()["components"]["schemas"][body_model_name] == { 1RST
110 "properties": {
111 "p_alias": {"title": "P Alias", "type": "string"},
112 },
113 "required": ["p_alias"],
114 "title": body_model_name,
115 "type": "object",
116 }
119@pytest.mark.parametrize( 1abcd
120 "path",
121 ["/required-alias", "/model-required-alias"],
122)
123def test_required_alias_missing(path: str): 1abcd
124 client = TestClient(app) 1tuv
125 response = client.post(path) 1tuv
126 assert response.status_code == 422 1tuv
127 assert response.json() == { 1tuv
128 "detail": [
129 {
130 "type": "missing",
131 "loc": ["body", "p_alias"],
132 "msg": "Field required",
133 "input": IsOneOf(None, {}),
134 }
135 ]
136 }
139@pytest.mark.parametrize( 1abcd
140 "path",
141 ["/required-alias", "/model-required-alias"],
142)
143def test_required_alias_by_name(path: str): 1abcd
144 client = TestClient(app) 1wxy
145 response = client.post(path, data={"p": "hello"}) 1wxy
146 assert response.status_code == 422 1wxy
147 assert response.json() == { 1wxy
148 "detail": [
149 {
150 "type": "missing",
151 "loc": ["body", "p_alias"],
152 "msg": "Field required",
153 "input": IsOneOf(None, {"p": "hello"}),
154 }
155 ]
156 }
159@pytest.mark.parametrize( 1abcd
160 "path",
161 ["/required-alias", "/model-required-alias"],
162)
163def test_required_alias_by_alias(path: str): 1abcd
164 client = TestClient(app) 1hij
165 response = client.post(path, data={"p_alias": "hello"}) 1hij
166 assert response.status_code == 200, response.text 1hij
167 assert response.json() == {"p": "hello"} 1hij
170# =====================================================================================
171# Validation alias
174@app.post("/required-validation-alias", operation_id="required_validation_alias") 1abcd
175def read_required_validation_alias( 1abcd
176 p: Annotated[str, Form(validation_alias="p_val_alias")],
177):
178 return {"p": p} 1klm
181class FormModelRequiredValidationAlias(BaseModel): 1abcd
182 p: str = Field(validation_alias="p_val_alias") 1abcd
185@app.post( 1abcd
186 "/model-required-validation-alias", operation_id="model_required_validation_alias"
187)
188def read_model_required_validation_alias( 1abcd
189 p: Annotated[FormModelRequiredValidationAlias, Form()],
190):
191 return {"p": p.p} 1klm
194@pytest.mark.parametrize( 1abcd
195 "path",
196 ["/required-validation-alias", "/model-required-validation-alias"],
197)
198def test_required_validation_alias_schema(path: str): 1abcd
199 openapi = app.openapi() 1UVW
200 body_model_name = get_body_model_name(openapi, path) 1UVW
202 assert app.openapi()["components"]["schemas"][body_model_name] == { 1UVW
203 "properties": {
204 "p_val_alias": {"title": "P Val Alias", "type": "string"},
205 },
206 "required": ["p_val_alias"],
207 "title": body_model_name,
208 "type": "object",
209 }
212@pytest.mark.parametrize( 1abcd
213 "path",
214 [
215 "/required-validation-alias",
216 "/model-required-validation-alias",
217 ],
218)
219def test_required_validation_alias_missing(path: str): 1abcd
220 client = TestClient(app) 1zAB
221 response = client.post(path) 1zAB
222 assert response.status_code == 422 1zAB
223 assert response.json() == { 1zAB
224 "detail": [
225 {
226 "type": "missing",
227 "loc": [
228 "body",
229 "p_val_alias",
230 ],
231 "msg": "Field required",
232 "input": IsOneOf(None, {}),
233 }
234 ]
235 }
238@pytest.mark.parametrize( 1abcd
239 "path",
240 [
241 "/required-validation-alias",
242 "/model-required-validation-alias",
243 ],
244)
245def test_required_validation_alias_by_name(path: str): 1abcd
246 client = TestClient(app) 1CDE
247 response = client.post(path, data={"p": "hello"}) 1CDE
248 assert response.status_code == 422, response.text 1CDE
250 assert response.json() == { 1CDE
251 "detail": [
252 {
253 "type": "missing",
254 "loc": ["body", "p_val_alias"],
255 "msg": "Field required",
256 "input": IsOneOf(None, {"p": "hello"}),
257 }
258 ]
259 }
262@pytest.mark.parametrize( 1abcd
263 "path",
264 [
265 "/required-validation-alias",
266 "/model-required-validation-alias",
267 ],
268)
269def test_required_validation_alias_by_validation_alias(path: str): 1abcd
270 client = TestClient(app) 1klm
271 response = client.post(path, data={"p_val_alias": "hello"}) 1klm
272 assert response.status_code == 200, response.text 1klm
274 assert response.json() == {"p": "hello"} 1klm
277# =====================================================================================
278# Alias and validation alias
281@app.post( 1abcd
282 "/required-alias-and-validation-alias",
283 operation_id="required_alias_and_validation_alias",
284)
285def read_required_alias_and_validation_alias( 1abcd
286 p: Annotated[str, Form(alias="p_alias", validation_alias="p_val_alias")],
287):
288 return {"p": p} 1nop
291class FormModelRequiredAliasAndValidationAlias(BaseModel): 1abcd
292 p: str = Field(alias="p_alias", validation_alias="p_val_alias") 1abcd
295@app.post( 1abcd
296 "/model-required-alias-and-validation-alias",
297 operation_id="model_required_alias_and_validation_alias",
298)
299def read_model_required_alias_and_validation_alias( 1abcd
300 p: Annotated[FormModelRequiredAliasAndValidationAlias, Form()],
301):
302 return {"p": p.p} 1nop
305@pytest.mark.parametrize( 1abcd
306 "path",
307 [
308 "/required-alias-and-validation-alias",
309 "/model-required-alias-and-validation-alias",
310 ],
311)
312def test_required_alias_and_validation_alias_schema(path: str): 1abcd
313 openapi = app.openapi() 1XYZ
314 body_model_name = get_body_model_name(openapi, path) 1XYZ
316 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ
317 "properties": {
318 "p_val_alias": {"title": "P Val Alias", "type": "string"},
319 },
320 "required": ["p_val_alias"],
321 "title": body_model_name,
322 "type": "object",
323 }
326@pytest.mark.parametrize( 1abcd
327 "path",
328 [
329 "/required-alias-and-validation-alias",
330 "/model-required-alias-and-validation-alias",
331 ],
332)
333def test_required_alias_and_validation_alias_missing(path: str): 1abcd
334 client = TestClient(app) 1FGH
335 response = client.post(path) 1FGH
336 assert response.status_code == 422 1FGH
337 assert response.json() == { 1FGH
338 "detail": [
339 {
340 "type": "missing",
341 "loc": [
342 "body",
343 "p_val_alias",
344 ],
345 "msg": "Field required",
346 "input": IsOneOf(None, {}),
347 }
348 ]
349 }
352@pytest.mark.parametrize( 1abcd
353 "path",
354 [
355 "/required-alias-and-validation-alias",
356 "/model-required-alias-and-validation-alias",
357 ],
358)
359def test_required_alias_and_validation_alias_by_name(path: str): 1abcd
360 client = TestClient(app) 1IJK
361 response = client.post(path, data={"p": "hello"}) 1IJK
362 assert response.status_code == 422 1IJK
364 assert response.json() == { 1IJK
365 "detail": [
366 {
367 "type": "missing",
368 "loc": [
369 "body",
370 "p_val_alias",
371 ],
372 "msg": "Field required",
373 "input": IsOneOf(None, {"p": "hello"}),
374 }
375 ]
376 }
379@pytest.mark.parametrize( 1abcd
380 "path",
381 [
382 "/required-alias-and-validation-alias",
383 "/model-required-alias-and-validation-alias",
384 ],
385)
386def test_required_alias_and_validation_alias_by_alias(path: str): 1abcd
387 client = TestClient(app) 1LMN
388 response = client.post(path, data={"p_alias": "hello"}) 1LMN
389 assert response.status_code == 422, response.text 1LMN
391 assert response.json() == { 1LMN
392 "detail": [
393 {
394 "type": "missing",
395 "loc": ["body", "p_val_alias"],
396 "msg": "Field required",
397 "input": IsOneOf(None, {"p_alias": "hello"}),
398 }
399 ]
400 }
403@pytest.mark.parametrize( 1abcd
404 "path",
405 [
406 "/required-alias-and-validation-alias",
407 "/model-required-alias-and-validation-alias",
408 ],
409)
410def test_required_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
411 client = TestClient(app) 1nop
412 response = client.post(path, data={"p_val_alias": "hello"}) 1nop
413 assert response.status_code == 200, response.text 1nop
415 assert response.json() == {"p": "hello"} 1nop