Coverage for tests/test_annotated.py: 100%
60 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-08 03:53 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-08 03:53 +0000
1import pytest 1abcde
2from dirty_equals import IsDict 1abcde
3from fastapi import APIRouter, FastAPI, Query 1abcde
4from fastapi.testclient import TestClient 1abcde
5from typing_extensions import Annotated 1abcde
7app = FastAPI() 1abcde
10@app.get("/default") 1abcde
11async def default(foo: Annotated[str, Query()] = "foo"): 1abcde
12 return {"foo": foo} 1abcde
15@app.get("/required") 1abcde
16async def required(foo: Annotated[str, Query(min_length=1)]): 1abcde
17 return {"foo": foo} 1abcde
20@app.get("/multiple") 1abcde
21async def multiple(foo: Annotated[str, object(), Query(min_length=1)]): 1abcde
22 return {"foo": foo} 1abcde
25@app.get("/unrelated") 1abcde
26async def unrelated(foo: Annotated[str, object()]): 1abcde
27 return {"foo": foo} 1abcde
30client = TestClient(app) 1abcde
32foo_is_missing = { 1abcde
33 "detail": [
34 IsDict(
35 {
36 "loc": ["query", "foo"],
37 "msg": "Field required",
38 "type": "missing",
39 "input": None,
40 }
41 )
42 # TODO: remove when deprecating Pydantic v1
43 | IsDict(
44 {
45 "loc": ["query", "foo"],
46 "msg": "field required",
47 "type": "value_error.missing",
48 }
49 )
50 ]
51}
52foo_is_short = { 1abcde
53 "detail": [
54 IsDict(
55 {
56 "ctx": {"min_length": 1},
57 "loc": ["query", "foo"],
58 "msg": "String should have at least 1 character",
59 "type": "string_too_short",
60 "input": "",
61 }
62 )
63 # TODO: remove when deprecating Pydantic v1
64 | IsDict(
65 {
66 "ctx": {"limit_value": 1},
67 "loc": ["query", "foo"],
68 "msg": "ensure this value has at least 1 characters",
69 "type": "value_error.any_str.min_length",
70 }
71 )
72 ]
73}
76@pytest.mark.parametrize( 1abcde
77 "path,expected_status,expected_response",
78 [
79 ("/default", 200, {"foo": "foo"}),
80 ("/default?foo=bar", 200, {"foo": "bar"}),
81 ("/required?foo=bar", 200, {"foo": "bar"}),
82 ("/required", 422, foo_is_missing),
83 ("/required?foo=", 422, foo_is_short),
84 ("/multiple?foo=bar", 200, {"foo": "bar"}),
85 ("/multiple", 422, foo_is_missing),
86 ("/multiple?foo=", 422, foo_is_short),
87 ("/unrelated?foo=bar", 200, {"foo": "bar"}),
88 ("/unrelated", 422, foo_is_missing),
89 ],
90)
91def test_get(path, expected_status, expected_response): 1abcde
92 response = client.get(path) 1abcde
93 assert response.status_code == expected_status 1abcde
94 assert response.json() == expected_response 1abcde
97def test_multiple_path(): 1abcde
98 app = FastAPI() 1abcde
100 @app.get("/test1") 1abcde
101 @app.get("/test2") 1abcde
102 async def test(var: Annotated[str, Query()] = "bar"): 1abcde
103 return {"foo": var} 1abcde
105 client = TestClient(app) 1abcde
106 response = client.get("/test1") 1abcde
107 assert response.status_code == 200 1abcde
108 assert response.json() == {"foo": "bar"} 1abcde
110 response = client.get("/test1", params={"var": "baz"}) 1abcde
111 assert response.status_code == 200 1abcde
112 assert response.json() == {"foo": "baz"} 1abcde
114 response = client.get("/test2") 1abcde
115 assert response.status_code == 200 1abcde
116 assert response.json() == {"foo": "bar"} 1abcde
118 response = client.get("/test2", params={"var": "baz"}) 1abcde
119 assert response.status_code == 200 1abcde
120 assert response.json() == {"foo": "baz"} 1abcde
123def test_nested_router(): 1abcde
124 app = FastAPI() 1abcde
126 router = APIRouter(prefix="/nested") 1abcde
128 @router.get("/test") 1abcde
129 async def test(var: Annotated[str, Query()] = "bar"): 1abcde
130 return {"foo": var} 1abcde
132 app.include_router(router) 1abcde
134 client = TestClient(app) 1abcde
136 response = client.get("/nested/test") 1abcde
137 assert response.status_code == 200 1abcde
138 assert response.json() == {"foo": "bar"} 1abcde
141def test_openapi_schema(): 1abcde
142 response = client.get("/openapi.json") 1abcde
143 assert response.status_code == 200 1abcde
144 assert response.json() == { 1abcde
145 "openapi": "3.1.0",
146 "info": {"title": "FastAPI", "version": "0.1.0"},
147 "paths": {
148 "/default": {
149 "get": {
150 "summary": "Default",
151 "operationId": "default_default_get",
152 "parameters": [
153 {
154 "required": False,
155 "schema": {
156 "title": "Foo",
157 "type": "string",
158 "default": "foo",
159 },
160 "name": "foo",
161 "in": "query",
162 }
163 ],
164 "responses": {
165 "200": {
166 "description": "Successful Response",
167 "content": {"application/json": {"schema": {}}},
168 },
169 "422": {
170 "description": "Validation Error",
171 "content": {
172 "application/json": {
173 "schema": {
174 "$ref": "#/components/schemas/HTTPValidationError"
175 }
176 }
177 },
178 },
179 },
180 }
181 },
182 "/required": {
183 "get": {
184 "summary": "Required",
185 "operationId": "required_required_get",
186 "parameters": [
187 {
188 "required": True,
189 "schema": {
190 "title": "Foo",
191 "minLength": 1,
192 "type": "string",
193 },
194 "name": "foo",
195 "in": "query",
196 }
197 ],
198 "responses": {
199 "200": {
200 "description": "Successful Response",
201 "content": {"application/json": {"schema": {}}},
202 },
203 "422": {
204 "description": "Validation Error",
205 "content": {
206 "application/json": {
207 "schema": {
208 "$ref": "#/components/schemas/HTTPValidationError"
209 }
210 }
211 },
212 },
213 },
214 }
215 },
216 "/multiple": {
217 "get": {
218 "summary": "Multiple",
219 "operationId": "multiple_multiple_get",
220 "parameters": [
221 {
222 "required": True,
223 "schema": {
224 "title": "Foo",
225 "minLength": 1,
226 "type": "string",
227 },
228 "name": "foo",
229 "in": "query",
230 }
231 ],
232 "responses": {
233 "200": {
234 "description": "Successful Response",
235 "content": {"application/json": {"schema": {}}},
236 },
237 "422": {
238 "description": "Validation Error",
239 "content": {
240 "application/json": {
241 "schema": {
242 "$ref": "#/components/schemas/HTTPValidationError"
243 }
244 }
245 },
246 },
247 },
248 }
249 },
250 "/unrelated": {
251 "get": {
252 "summary": "Unrelated",
253 "operationId": "unrelated_unrelated_get",
254 "parameters": [
255 {
256 "required": True,
257 "schema": {"title": "Foo", "type": "string"},
258 "name": "foo",
259 "in": "query",
260 }
261 ],
262 "responses": {
263 "200": {
264 "description": "Successful Response",
265 "content": {"application/json": {"schema": {}}},
266 },
267 "422": {
268 "description": "Validation Error",
269 "content": {
270 "application/json": {
271 "schema": {
272 "$ref": "#/components/schemas/HTTPValidationError"
273 }
274 }
275 },
276 },
277 },
278 }
279 },
280 },
281 "components": {
282 "schemas": {
283 "HTTPValidationError": {
284 "title": "HTTPValidationError",
285 "type": "object",
286 "properties": {
287 "detail": {
288 "title": "Detail",
289 "type": "array",
290 "items": {"$ref": "#/components/schemas/ValidationError"},
291 }
292 },
293 },
294 "ValidationError": {
295 "title": "ValidationError",
296 "required": ["loc", "msg", "type"],
297 "type": "object",
298 "properties": {
299 "loc": {
300 "title": "Location",
301 "type": "array",
302 "items": {
303 "anyOf": [{"type": "string"}, {"type": "integer"}]
304 },
305 },
306 "msg": {"title": "Message", "type": "string"},
307 "type": {"title": "Error Type", "type": "string"},
308 },
309 },
310 }
311 },
312 }