Coverage for tests/test_tutorial/test_fastapi/test_update/test_tutorial002_py310.py: 100%
96 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-09 00:02 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-09 00:02 +0000
1from dirty_equals import IsDict 1idefgh
2from fastapi.testclient import TestClient 1idefgh
3from sqlmodel import Session, create_engine 1idefgh
4from sqlmodel.pool import StaticPool 1idefgh
6from ....conftest import needs_py310 1idefgh
9@needs_py310 1idefgh
10def test_tutorial(clear_sqlmodel): 1defgh
11 from docs_src.tutorial.fastapi.update import tutorial002_py310 as mod 1abc
13 mod.sqlite_url = "sqlite://" 1abc
14 mod.engine = create_engine( 1abc
15 mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool
16 )
18 with TestClient(mod.app) as client: 1abc
19 hero1_data = { 1abc
20 "name": "Deadpond",
21 "secret_name": "Dive Wilson",
22 "password": "chimichanga",
23 }
24 hero2_data = { 1abc
25 "name": "Spider-Boy",
26 "secret_name": "Pedro Parqueador",
27 "id": 9000,
28 "password": "auntmay",
29 }
30 hero3_data = { 1abc
31 "name": "Rusty-Man",
32 "secret_name": "Tommy Sharp",
33 "age": 48,
34 "password": "bestpreventer",
35 }
36 response = client.post("/heroes/", json=hero1_data) 1abc
37 assert response.status_code == 200, response.text 1abc
38 hero1 = response.json() 1abc
39 assert "password" not in hero1 1abc
40 assert "hashed_password" not in hero1 1abc
41 hero1_id = hero1["id"] 1abc
42 response = client.post("/heroes/", json=hero2_data) 1abc
43 assert response.status_code == 200, response.text 1abc
44 hero2 = response.json() 1abc
45 hero2_id = hero2["id"] 1abc
46 response = client.post("/heroes/", json=hero3_data) 1abc
47 assert response.status_code == 200, response.text 1abc
48 hero3 = response.json() 1abc
49 hero3_id = hero3["id"] 1abc
50 response = client.get(f"/heroes/{hero2_id}") 1abc
51 assert response.status_code == 200, response.text 1abc
52 fetched_hero2 = response.json() 1abc
53 assert "password" not in fetched_hero2 1abc
54 assert "hashed_password" not in fetched_hero2 1abc
55 response = client.get("/heroes/9000") 1abc
56 assert response.status_code == 404, response.text 1abc
57 response = client.get("/heroes/") 1abc
58 assert response.status_code == 200, response.text 1abc
59 data = response.json() 1abc
60 assert len(data) == 3 1abc
61 for response_hero in data: 1abc
62 assert "password" not in response_hero 1abc
63 assert "hashed_password" not in response_hero 1abc
65 # Test hashed passwords
66 with Session(mod.engine) as session: 1abc
67 hero1_db = session.get(mod.Hero, hero1_id) 1abc
68 assert hero1_db 1abc
69 assert not hasattr(hero1_db, "password") 1abc
70 assert hero1_db.hashed_password == "not really hashed chimichanga hehehe" 1abc
71 hero2_db = session.get(mod.Hero, hero2_id) 1abc
72 assert hero2_db 1abc
73 assert not hasattr(hero2_db, "password") 1abc
74 assert hero2_db.hashed_password == "not really hashed auntmay hehehe" 1abc
75 hero3_db = session.get(mod.Hero, hero3_id) 1abc
76 assert hero3_db 1abc
77 assert not hasattr(hero3_db, "password") 1abc
78 assert hero3_db.hashed_password == "not really hashed bestpreventer hehehe" 1abc
80 response = client.patch( 1abc
81 f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"}
82 )
83 data = response.json() 1abc
84 assert response.status_code == 200, response.text 1abc
85 assert data["name"] == hero2_data["name"], "The name should not be set to none" 1abc
86 assert ( 1abc
87 data["secret_name"] == "Spider-Youngster"
88 ), "The secret name should be updated"
89 assert "password" not in data 1abc
90 assert "hashed_password" not in data 1abc
91 with Session(mod.engine) as session: 1abc
92 hero2b_db = session.get(mod.Hero, hero2_id) 1abc
93 assert hero2b_db 1abc
94 assert not hasattr(hero2b_db, "password") 1abc
95 assert hero2b_db.hashed_password == "not really hashed auntmay hehehe" 1abc
97 response = client.patch(f"/heroes/{hero3_id}", json={"age": None}) 1abc
98 data = response.json() 1abc
99 assert response.status_code == 200, response.text 1abc
100 assert data["name"] == hero3_data["name"] 1abc
101 assert ( 1abc
102 data["age"] is None
103 ), "A field should be updatable to None, even if that's the default"
104 assert "password" not in data 1abc
105 assert "hashed_password" not in data 1abc
106 with Session(mod.engine) as session: 1abc
107 hero3b_db = session.get(mod.Hero, hero3_id) 1abc
108 assert hero3b_db 1abc
109 assert not hasattr(hero3b_db, "password") 1abc
110 assert hero3b_db.hashed_password == "not really hashed bestpreventer hehehe" 1abc
112 # Test update dict, hashed_password
113 response = client.patch( 1abc
114 f"/heroes/{hero3_id}", json={"password": "philantroplayboy"}
115 )
116 data = response.json() 1abc
117 assert response.status_code == 200, response.text 1abc
118 assert data["name"] == hero3_data["name"] 1abc
119 assert data["age"] is None 1abc
120 assert "password" not in data 1abc
121 assert "hashed_password" not in data 1abc
122 with Session(mod.engine) as session: 1abc
123 hero3b_db = session.get(mod.Hero, hero3_id) 1abc
124 assert hero3b_db 1abc
125 assert not hasattr(hero3b_db, "password") 1abc
126 assert ( 1abc
127 hero3b_db.hashed_password == "not really hashed philantroplayboy hehehe"
128 )
130 response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"}) 1abc
131 assert response.status_code == 404, response.text 1abc
133 response = client.get("/openapi.json") 1abc
134 assert response.status_code == 200, response.text 1abc
135 assert response.json() == { 1abc
136 "openapi": "3.1.0",
137 "info": {"title": "FastAPI", "version": "0.1.0"},
138 "paths": {
139 "/heroes/": {
140 "get": {
141 "summary": "Read Heroes",
142 "operationId": "read_heroes_heroes__get",
143 "parameters": [
144 {
145 "required": False,
146 "schema": {
147 "title": "Offset",
148 "type": "integer",
149 "default": 0,
150 },
151 "name": "offset",
152 "in": "query",
153 },
154 {
155 "required": False,
156 "schema": {
157 "title": "Limit",
158 "maximum": 100,
159 "type": "integer",
160 "default": 100,
161 },
162 "name": "limit",
163 "in": "query",
164 },
165 ],
166 "responses": {
167 "200": {
168 "description": "Successful Response",
169 "content": {
170 "application/json": {
171 "schema": {
172 "title": "Response Read Heroes Heroes Get",
173 "type": "array",
174 "items": {
175 "$ref": "#/components/schemas/HeroPublic"
176 },
177 }
178 }
179 },
180 },
181 "422": {
182 "description": "Validation Error",
183 "content": {
184 "application/json": {
185 "schema": {
186 "$ref": "#/components/schemas/HTTPValidationError"
187 }
188 }
189 },
190 },
191 },
192 },
193 "post": {
194 "summary": "Create Hero",
195 "operationId": "create_hero_heroes__post",
196 "requestBody": {
197 "content": {
198 "application/json": {
199 "schema": {
200 "$ref": "#/components/schemas/HeroCreate"
201 }
202 }
203 },
204 "required": True,
205 },
206 "responses": {
207 "200": {
208 "description": "Successful Response",
209 "content": {
210 "application/json": {
211 "schema": {
212 "$ref": "#/components/schemas/HeroPublic"
213 }
214 }
215 },
216 },
217 "422": {
218 "description": "Validation Error",
219 "content": {
220 "application/json": {
221 "schema": {
222 "$ref": "#/components/schemas/HTTPValidationError"
223 }
224 }
225 },
226 },
227 },
228 },
229 },
230 "/heroes/{hero_id}": {
231 "get": {
232 "summary": "Read Hero",
233 "operationId": "read_hero_heroes__hero_id__get",
234 "parameters": [
235 {
236 "required": True,
237 "schema": {"title": "Hero Id", "type": "integer"},
238 "name": "hero_id",
239 "in": "path",
240 }
241 ],
242 "responses": {
243 "200": {
244 "description": "Successful Response",
245 "content": {
246 "application/json": {
247 "schema": {
248 "$ref": "#/components/schemas/HeroPublic"
249 }
250 }
251 },
252 },
253 "422": {
254 "description": "Validation Error",
255 "content": {
256 "application/json": {
257 "schema": {
258 "$ref": "#/components/schemas/HTTPValidationError"
259 }
260 }
261 },
262 },
263 },
264 },
265 "patch": {
266 "summary": "Update Hero",
267 "operationId": "update_hero_heroes__hero_id__patch",
268 "parameters": [
269 {
270 "required": True,
271 "schema": {"title": "Hero Id", "type": "integer"},
272 "name": "hero_id",
273 "in": "path",
274 }
275 ],
276 "requestBody": {
277 "content": {
278 "application/json": {
279 "schema": {
280 "$ref": "#/components/schemas/HeroUpdate"
281 }
282 }
283 },
284 "required": True,
285 },
286 "responses": {
287 "200": {
288 "description": "Successful Response",
289 "content": {
290 "application/json": {
291 "schema": {
292 "$ref": "#/components/schemas/HeroPublic"
293 }
294 }
295 },
296 },
297 "422": {
298 "description": "Validation Error",
299 "content": {
300 "application/json": {
301 "schema": {
302 "$ref": "#/components/schemas/HTTPValidationError"
303 }
304 }
305 },
306 },
307 },
308 },
309 },
310 },
311 "components": {
312 "schemas": {
313 "HTTPValidationError": {
314 "title": "HTTPValidationError",
315 "type": "object",
316 "properties": {
317 "detail": {
318 "title": "Detail",
319 "type": "array",
320 "items": {
321 "$ref": "#/components/schemas/ValidationError"
322 },
323 }
324 },
325 },
326 "HeroCreate": {
327 "title": "HeroCreate",
328 "required": ["name", "secret_name", "password"],
329 "type": "object",
330 "properties": {
331 "name": {"title": "Name", "type": "string"},
332 "secret_name": {"title": "Secret Name", "type": "string"},
333 "age": IsDict(
334 {
335 "anyOf": [{"type": "integer"}, {"type": "null"}],
336 "title": "Age",
337 }
338 )
339 | IsDict(
340 # TODO: Remove when deprecating Pydantic v1
341 {"title": "Age", "type": "integer"}
342 ),
343 "password": {"type": "string", "title": "Password"},
344 },
345 },
346 "HeroPublic": {
347 "title": "HeroPublic",
348 "required": ["name", "secret_name", "id"],
349 "type": "object",
350 "properties": {
351 "name": {"title": "Name", "type": "string"},
352 "secret_name": {"title": "Secret Name", "type": "string"},
353 "age": IsDict(
354 {
355 "anyOf": [{"type": "integer"}, {"type": "null"}],
356 "title": "Age",
357 }
358 )
359 | IsDict(
360 # TODO: Remove when deprecating Pydantic v1
361 {"title": "Age", "type": "integer"}
362 ),
363 "id": {"title": "Id", "type": "integer"},
364 },
365 },
366 "HeroUpdate": {
367 "title": "HeroUpdate",
368 "type": "object",
369 "properties": {
370 "name": IsDict(
371 {
372 "anyOf": [{"type": "string"}, {"type": "null"}],
373 "title": "Name",
374 }
375 )
376 | IsDict(
377 # TODO: Remove when deprecating Pydantic v1
378 {"title": "Name", "type": "string"}
379 ),
380 "secret_name": IsDict(
381 {
382 "anyOf": [{"type": "string"}, {"type": "null"}],
383 "title": "Secret Name",
384 }
385 )
386 | IsDict(
387 # TODO: Remove when deprecating Pydantic v1
388 {"title": "Secret Name", "type": "string"}
389 ),
390 "age": IsDict(
391 {
392 "anyOf": [{"type": "integer"}, {"type": "null"}],
393 "title": "Age",
394 }
395 )
396 | IsDict(
397 # TODO: Remove when deprecating Pydantic v1
398 {"title": "Age", "type": "integer"}
399 ),
400 "password": IsDict(
401 {
402 "anyOf": [{"type": "string"}, {"type": "null"}],
403 "title": "Password",
404 }
405 )
406 | IsDict(
407 # TODO: Remove when deprecating Pydantic v1
408 {"title": "Password", "type": "string"}
409 ),
410 },
411 },
412 "ValidationError": {
413 "title": "ValidationError",
414 "required": ["loc", "msg", "type"],
415 "type": "object",
416 "properties": {
417 "loc": {
418 "title": "Location",
419 "type": "array",
420 "items": {
421 "anyOf": [{"type": "string"}, {"type": "integer"}]
422 },
423 },
424 "msg": {"title": "Message", "type": "string"},
425 "type": {"title": "Error Type", "type": "string"},
426 },
427 },
428 }
429 },
430 }