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