Coverage for tests/test_generate_unique_id_function.py: 100%
125 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-13 13:38 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-13 13:38 +0000
1import warnings 1abcde
2from typing import List 1abcde
4from fastapi import APIRouter, FastAPI 1abcde
5from fastapi.routing import APIRoute 1abcde
6from fastapi.testclient import TestClient 1abcde
7from pydantic import BaseModel 1abcde
10def custom_generate_unique_id(route: APIRoute): 1abcde
11 return f"foo_{route.name}" 1puvwfOqxyzgPrABChQsDEFiRtGHIjS
14def custom_generate_unique_id2(route: APIRoute): 1abcde
15 return f"bar_{route.name}" 1JuvfKxygLABhMDEiNGHj
18def custom_generate_unique_id3(route: APIRoute): 1abcde
19 return f"baz_{route.name}" 1JpwfKqzgLrChMsFiNtIj
22class Item(BaseModel): 1abcde
23 name: str 1abcde
24 price: float 1abcde
27class Message(BaseModel): 1abcde
28 title: str 1abcde
29 description: str 1abcde
32def test_top_level_generate_unique_id(): 1abcde
33 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1OPQRS
34 router = APIRouter() 1OPQRS
36 @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) 1OPQRS
37 def post_root(item1: Item, item2: Item): 1OPQRS
38 return item1, item2 # pragma: nocover
40 @router.post( 1OPQRS
41 "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
42 )
43 def post_router(item1: Item, item2: Item): 1OPQRS
44 return item1, item2 # pragma: nocover
46 app.include_router(router) 1OPQRS
47 client = TestClient(app) 1OPQRS
48 response = client.get("/openapi.json") 1OPQRS
49 data = response.json() 1OPQRS
50 assert data == { 1OPQRS
51 "openapi": "3.1.0",
52 "info": {"title": "FastAPI", "version": "0.1.0"},
53 "paths": {
54 "/": {
55 "post": {
56 "summary": "Post Root",
57 "operationId": "foo_post_root",
58 "requestBody": {
59 "content": {
60 "application/json": {
61 "schema": {
62 "$ref": "#/components/schemas/Body_foo_post_root"
63 }
64 }
65 },
66 "required": True,
67 },
68 "responses": {
69 "200": {
70 "description": "Successful Response",
71 "content": {
72 "application/json": {
73 "schema": {
74 "title": "Response Foo Post Root",
75 "type": "array",
76 "items": {"$ref": "#/components/schemas/Item"},
77 }
78 }
79 },
80 },
81 "404": {
82 "description": "Not Found",
83 "content": {
84 "application/json": {
85 "schema": {
86 "title": "Response 404 Foo Post Root",
87 "type": "array",
88 "items": {
89 "$ref": "#/components/schemas/Message"
90 },
91 }
92 }
93 },
94 },
95 "422": {
96 "description": "Validation Error",
97 "content": {
98 "application/json": {
99 "schema": {
100 "$ref": "#/components/schemas/HTTPValidationError"
101 }
102 }
103 },
104 },
105 },
106 }
107 },
108 "/router": {
109 "post": {
110 "summary": "Post Router",
111 "operationId": "foo_post_router",
112 "requestBody": {
113 "content": {
114 "application/json": {
115 "schema": {
116 "$ref": "#/components/schemas/Body_foo_post_router"
117 }
118 }
119 },
120 "required": True,
121 },
122 "responses": {
123 "200": {
124 "description": "Successful Response",
125 "content": {
126 "application/json": {
127 "schema": {
128 "title": "Response Foo Post Router",
129 "type": "array",
130 "items": {"$ref": "#/components/schemas/Item"},
131 }
132 }
133 },
134 },
135 "404": {
136 "description": "Not Found",
137 "content": {
138 "application/json": {
139 "schema": {
140 "title": "Response 404 Foo Post Router",
141 "type": "array",
142 "items": {
143 "$ref": "#/components/schemas/Message"
144 },
145 }
146 }
147 },
148 },
149 "422": {
150 "description": "Validation Error",
151 "content": {
152 "application/json": {
153 "schema": {
154 "$ref": "#/components/schemas/HTTPValidationError"
155 }
156 }
157 },
158 },
159 },
160 }
161 },
162 },
163 "components": {
164 "schemas": {
165 "Body_foo_post_root": {
166 "title": "Body_foo_post_root",
167 "required": ["item1", "item2"],
168 "type": "object",
169 "properties": {
170 "item1": {"$ref": "#/components/schemas/Item"},
171 "item2": {"$ref": "#/components/schemas/Item"},
172 },
173 },
174 "Body_foo_post_router": {
175 "title": "Body_foo_post_router",
176 "required": ["item1", "item2"],
177 "type": "object",
178 "properties": {
179 "item1": {"$ref": "#/components/schemas/Item"},
180 "item2": {"$ref": "#/components/schemas/Item"},
181 },
182 },
183 "HTTPValidationError": {
184 "title": "HTTPValidationError",
185 "type": "object",
186 "properties": {
187 "detail": {
188 "title": "Detail",
189 "type": "array",
190 "items": {"$ref": "#/components/schemas/ValidationError"},
191 }
192 },
193 },
194 "Item": {
195 "title": "Item",
196 "required": ["name", "price"],
197 "type": "object",
198 "properties": {
199 "name": {"title": "Name", "type": "string"},
200 "price": {"title": "Price", "type": "number"},
201 },
202 },
203 "Message": {
204 "title": "Message",
205 "required": ["title", "description"],
206 "type": "object",
207 "properties": {
208 "title": {"title": "Title", "type": "string"},
209 "description": {"title": "Description", "type": "string"},
210 },
211 },
212 "ValidationError": {
213 "title": "ValidationError",
214 "required": ["loc", "msg", "type"],
215 "type": "object",
216 "properties": {
217 "loc": {
218 "title": "Location",
219 "type": "array",
220 "items": {
221 "anyOf": [{"type": "string"}, {"type": "integer"}]
222 },
223 },
224 "msg": {"title": "Message", "type": "string"},
225 "type": {"title": "Error Type", "type": "string"},
226 },
227 },
228 }
229 },
230 }
233def test_router_overrides_generate_unique_id(): 1abcde
234 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1vyBEH
235 router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) 1vyBEH
237 @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) 1vyBEH
238 def post_root(item1: Item, item2: Item): 1vyBEH
239 return item1, item2 # pragma: nocover
241 @router.post( 1vyBEH
242 "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
243 )
244 def post_router(item1: Item, item2: Item): 1vyBEH
245 return item1, item2 # pragma: nocover
247 app.include_router(router) 1vyBEH
248 client = TestClient(app) 1vyBEH
249 response = client.get("/openapi.json") 1vyBEH
250 data = response.json() 1vyBEH
251 assert data == { 1vyBEH
252 "openapi": "3.1.0",
253 "info": {"title": "FastAPI", "version": "0.1.0"},
254 "paths": {
255 "/": {
256 "post": {
257 "summary": "Post Root",
258 "operationId": "foo_post_root",
259 "requestBody": {
260 "content": {
261 "application/json": {
262 "schema": {
263 "$ref": "#/components/schemas/Body_foo_post_root"
264 }
265 }
266 },
267 "required": True,
268 },
269 "responses": {
270 "200": {
271 "description": "Successful Response",
272 "content": {
273 "application/json": {
274 "schema": {
275 "title": "Response Foo Post Root",
276 "type": "array",
277 "items": {"$ref": "#/components/schemas/Item"},
278 }
279 }
280 },
281 },
282 "404": {
283 "description": "Not Found",
284 "content": {
285 "application/json": {
286 "schema": {
287 "title": "Response 404 Foo Post Root",
288 "type": "array",
289 "items": {
290 "$ref": "#/components/schemas/Message"
291 },
292 }
293 }
294 },
295 },
296 "422": {
297 "description": "Validation Error",
298 "content": {
299 "application/json": {
300 "schema": {
301 "$ref": "#/components/schemas/HTTPValidationError"
302 }
303 }
304 },
305 },
306 },
307 }
308 },
309 "/router": {
310 "post": {
311 "summary": "Post Router",
312 "operationId": "bar_post_router",
313 "requestBody": {
314 "content": {
315 "application/json": {
316 "schema": {
317 "$ref": "#/components/schemas/Body_bar_post_router"
318 }
319 }
320 },
321 "required": True,
322 },
323 "responses": {
324 "200": {
325 "description": "Successful Response",
326 "content": {
327 "application/json": {
328 "schema": {
329 "title": "Response Bar Post Router",
330 "type": "array",
331 "items": {"$ref": "#/components/schemas/Item"},
332 }
333 }
334 },
335 },
336 "404": {
337 "description": "Not Found",
338 "content": {
339 "application/json": {
340 "schema": {
341 "title": "Response 404 Bar Post Router",
342 "type": "array",
343 "items": {
344 "$ref": "#/components/schemas/Message"
345 },
346 }
347 }
348 },
349 },
350 "422": {
351 "description": "Validation Error",
352 "content": {
353 "application/json": {
354 "schema": {
355 "$ref": "#/components/schemas/HTTPValidationError"
356 }
357 }
358 },
359 },
360 },
361 }
362 },
363 },
364 "components": {
365 "schemas": {
366 "Body_bar_post_router": {
367 "title": "Body_bar_post_router",
368 "required": ["item1", "item2"],
369 "type": "object",
370 "properties": {
371 "item1": {"$ref": "#/components/schemas/Item"},
372 "item2": {"$ref": "#/components/schemas/Item"},
373 },
374 },
375 "Body_foo_post_root": {
376 "title": "Body_foo_post_root",
377 "required": ["item1", "item2"],
378 "type": "object",
379 "properties": {
380 "item1": {"$ref": "#/components/schemas/Item"},
381 "item2": {"$ref": "#/components/schemas/Item"},
382 },
383 },
384 "HTTPValidationError": {
385 "title": "HTTPValidationError",
386 "type": "object",
387 "properties": {
388 "detail": {
389 "title": "Detail",
390 "type": "array",
391 "items": {"$ref": "#/components/schemas/ValidationError"},
392 }
393 },
394 },
395 "Item": {
396 "title": "Item",
397 "required": ["name", "price"],
398 "type": "object",
399 "properties": {
400 "name": {"title": "Name", "type": "string"},
401 "price": {"title": "Price", "type": "number"},
402 },
403 },
404 "Message": {
405 "title": "Message",
406 "required": ["title", "description"],
407 "type": "object",
408 "properties": {
409 "title": {"title": "Title", "type": "string"},
410 "description": {"title": "Description", "type": "string"},
411 },
412 },
413 "ValidationError": {
414 "title": "ValidationError",
415 "required": ["loc", "msg", "type"],
416 "type": "object",
417 "properties": {
418 "loc": {
419 "title": "Location",
420 "type": "array",
421 "items": {
422 "anyOf": [{"type": "string"}, {"type": "integer"}]
423 },
424 },
425 "msg": {"title": "Message", "type": "string"},
426 "type": {"title": "Error Type", "type": "string"},
427 },
428 },
429 }
430 },
431 }
434def test_router_include_overrides_generate_unique_id(): 1abcde
435 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1uxADG
436 router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) 1uxADG
438 @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) 1uxADG
439 def post_root(item1: Item, item2: Item): 1uxADG
440 return item1, item2 # pragma: nocover
442 @router.post( 1uxADG
443 "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
444 )
445 def post_router(item1: Item, item2: Item): 1uxADG
446 return item1, item2 # pragma: nocover
448 app.include_router(router, generate_unique_id_function=custom_generate_unique_id3) 1uxADG
449 client = TestClient(app) 1uxADG
450 response = client.get("/openapi.json") 1uxADG
451 data = response.json() 1uxADG
452 assert data == { 1uxADG
453 "openapi": "3.1.0",
454 "info": {"title": "FastAPI", "version": "0.1.0"},
455 "paths": {
456 "/": {
457 "post": {
458 "summary": "Post Root",
459 "operationId": "foo_post_root",
460 "requestBody": {
461 "content": {
462 "application/json": {
463 "schema": {
464 "$ref": "#/components/schemas/Body_foo_post_root"
465 }
466 }
467 },
468 "required": True,
469 },
470 "responses": {
471 "200": {
472 "description": "Successful Response",
473 "content": {
474 "application/json": {
475 "schema": {
476 "title": "Response Foo Post Root",
477 "type": "array",
478 "items": {"$ref": "#/components/schemas/Item"},
479 }
480 }
481 },
482 },
483 "404": {
484 "description": "Not Found",
485 "content": {
486 "application/json": {
487 "schema": {
488 "title": "Response 404 Foo Post Root",
489 "type": "array",
490 "items": {
491 "$ref": "#/components/schemas/Message"
492 },
493 }
494 }
495 },
496 },
497 "422": {
498 "description": "Validation Error",
499 "content": {
500 "application/json": {
501 "schema": {
502 "$ref": "#/components/schemas/HTTPValidationError"
503 }
504 }
505 },
506 },
507 },
508 }
509 },
510 "/router": {
511 "post": {
512 "summary": "Post Router",
513 "operationId": "bar_post_router",
514 "requestBody": {
515 "content": {
516 "application/json": {
517 "schema": {
518 "$ref": "#/components/schemas/Body_bar_post_router"
519 }
520 }
521 },
522 "required": True,
523 },
524 "responses": {
525 "200": {
526 "description": "Successful Response",
527 "content": {
528 "application/json": {
529 "schema": {
530 "title": "Response Bar Post Router",
531 "type": "array",
532 "items": {"$ref": "#/components/schemas/Item"},
533 }
534 }
535 },
536 },
537 "404": {
538 "description": "Not Found",
539 "content": {
540 "application/json": {
541 "schema": {
542 "title": "Response 404 Bar Post Router",
543 "type": "array",
544 "items": {
545 "$ref": "#/components/schemas/Message"
546 },
547 }
548 }
549 },
550 },
551 "422": {
552 "description": "Validation Error",
553 "content": {
554 "application/json": {
555 "schema": {
556 "$ref": "#/components/schemas/HTTPValidationError"
557 }
558 }
559 },
560 },
561 },
562 }
563 },
564 },
565 "components": {
566 "schemas": {
567 "Body_bar_post_router": {
568 "title": "Body_bar_post_router",
569 "required": ["item1", "item2"],
570 "type": "object",
571 "properties": {
572 "item1": {"$ref": "#/components/schemas/Item"},
573 "item2": {"$ref": "#/components/schemas/Item"},
574 },
575 },
576 "Body_foo_post_root": {
577 "title": "Body_foo_post_root",
578 "required": ["item1", "item2"],
579 "type": "object",
580 "properties": {
581 "item1": {"$ref": "#/components/schemas/Item"},
582 "item2": {"$ref": "#/components/schemas/Item"},
583 },
584 },
585 "HTTPValidationError": {
586 "title": "HTTPValidationError",
587 "type": "object",
588 "properties": {
589 "detail": {
590 "title": "Detail",
591 "type": "array",
592 "items": {"$ref": "#/components/schemas/ValidationError"},
593 }
594 },
595 },
596 "Item": {
597 "title": "Item",
598 "required": ["name", "price"],
599 "type": "object",
600 "properties": {
601 "name": {"title": "Name", "type": "string"},
602 "price": {"title": "Price", "type": "number"},
603 },
604 },
605 "Message": {
606 "title": "Message",
607 "required": ["title", "description"],
608 "type": "object",
609 "properties": {
610 "title": {"title": "Title", "type": "string"},
611 "description": {"title": "Description", "type": "string"},
612 },
613 },
614 "ValidationError": {
615 "title": "ValidationError",
616 "required": ["loc", "msg", "type"],
617 "type": "object",
618 "properties": {
619 "loc": {
620 "title": "Location",
621 "type": "array",
622 "items": {
623 "anyOf": [{"type": "string"}, {"type": "integer"}]
624 },
625 },
626 "msg": {"title": "Message", "type": "string"},
627 "type": {"title": "Error Type", "type": "string"},
628 },
629 },
630 }
631 },
632 }
635def test_subrouter_top_level_include_overrides_generate_unique_id(): 1abcde
636 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1fghij
637 router = APIRouter() 1fghij
638 sub_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) 1fghij
640 @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) 1fghij
641 def post_root(item1: Item, item2: Item): 1fghij
642 return item1, item2 # pragma: nocover
644 @router.post( 1fghij
645 "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
646 )
647 def post_router(item1: Item, item2: Item): 1fghij
648 return item1, item2 # pragma: nocover
650 @sub_router.post( 1fghij
651 "/subrouter",
652 response_model=List[Item],
653 responses={404: {"model": List[Message]}},
654 )
655 def post_subrouter(item1: Item, item2: Item): 1fghij
656 return item1, item2 # pragma: nocover
658 router.include_router(sub_router) 1fghij
659 app.include_router(router, generate_unique_id_function=custom_generate_unique_id3) 1fghij
660 client = TestClient(app) 1fghij
661 response = client.get("/openapi.json") 1fghij
662 data = response.json() 1fghij
663 assert data == { 1fghij
664 "openapi": "3.1.0",
665 "info": {"title": "FastAPI", "version": "0.1.0"},
666 "paths": {
667 "/": {
668 "post": {
669 "summary": "Post Root",
670 "operationId": "foo_post_root",
671 "requestBody": {
672 "content": {
673 "application/json": {
674 "schema": {
675 "$ref": "#/components/schemas/Body_foo_post_root"
676 }
677 }
678 },
679 "required": True,
680 },
681 "responses": {
682 "200": {
683 "description": "Successful Response",
684 "content": {
685 "application/json": {
686 "schema": {
687 "title": "Response Foo Post Root",
688 "type": "array",
689 "items": {"$ref": "#/components/schemas/Item"},
690 }
691 }
692 },
693 },
694 "404": {
695 "description": "Not Found",
696 "content": {
697 "application/json": {
698 "schema": {
699 "title": "Response 404 Foo Post Root",
700 "type": "array",
701 "items": {
702 "$ref": "#/components/schemas/Message"
703 },
704 }
705 }
706 },
707 },
708 "422": {
709 "description": "Validation Error",
710 "content": {
711 "application/json": {
712 "schema": {
713 "$ref": "#/components/schemas/HTTPValidationError"
714 }
715 }
716 },
717 },
718 },
719 }
720 },
721 "/router": {
722 "post": {
723 "summary": "Post Router",
724 "operationId": "baz_post_router",
725 "requestBody": {
726 "content": {
727 "application/json": {
728 "schema": {
729 "$ref": "#/components/schemas/Body_baz_post_router"
730 }
731 }
732 },
733 "required": True,
734 },
735 "responses": {
736 "200": {
737 "description": "Successful Response",
738 "content": {
739 "application/json": {
740 "schema": {
741 "title": "Response Baz Post Router",
742 "type": "array",
743 "items": {"$ref": "#/components/schemas/Item"},
744 }
745 }
746 },
747 },
748 "404": {
749 "description": "Not Found",
750 "content": {
751 "application/json": {
752 "schema": {
753 "title": "Response 404 Baz Post Router",
754 "type": "array",
755 "items": {
756 "$ref": "#/components/schemas/Message"
757 },
758 }
759 }
760 },
761 },
762 "422": {
763 "description": "Validation Error",
764 "content": {
765 "application/json": {
766 "schema": {
767 "$ref": "#/components/schemas/HTTPValidationError"
768 }
769 }
770 },
771 },
772 },
773 }
774 },
775 "/subrouter": {
776 "post": {
777 "summary": "Post Subrouter",
778 "operationId": "bar_post_subrouter",
779 "requestBody": {
780 "content": {
781 "application/json": {
782 "schema": {
783 "$ref": "#/components/schemas/Body_bar_post_subrouter"
784 }
785 }
786 },
787 "required": True,
788 },
789 "responses": {
790 "200": {
791 "description": "Successful Response",
792 "content": {
793 "application/json": {
794 "schema": {
795 "title": "Response Bar Post Subrouter",
796 "type": "array",
797 "items": {"$ref": "#/components/schemas/Item"},
798 }
799 }
800 },
801 },
802 "404": {
803 "description": "Not Found",
804 "content": {
805 "application/json": {
806 "schema": {
807 "title": "Response 404 Bar Post Subrouter",
808 "type": "array",
809 "items": {
810 "$ref": "#/components/schemas/Message"
811 },
812 }
813 }
814 },
815 },
816 "422": {
817 "description": "Validation Error",
818 "content": {
819 "application/json": {
820 "schema": {
821 "$ref": "#/components/schemas/HTTPValidationError"
822 }
823 }
824 },
825 },
826 },
827 }
828 },
829 },
830 "components": {
831 "schemas": {
832 "Body_bar_post_subrouter": {
833 "title": "Body_bar_post_subrouter",
834 "required": ["item1", "item2"],
835 "type": "object",
836 "properties": {
837 "item1": {"$ref": "#/components/schemas/Item"},
838 "item2": {"$ref": "#/components/schemas/Item"},
839 },
840 },
841 "Body_baz_post_router": {
842 "title": "Body_baz_post_router",
843 "required": ["item1", "item2"],
844 "type": "object",
845 "properties": {
846 "item1": {"$ref": "#/components/schemas/Item"},
847 "item2": {"$ref": "#/components/schemas/Item"},
848 },
849 },
850 "Body_foo_post_root": {
851 "title": "Body_foo_post_root",
852 "required": ["item1", "item2"],
853 "type": "object",
854 "properties": {
855 "item1": {"$ref": "#/components/schemas/Item"},
856 "item2": {"$ref": "#/components/schemas/Item"},
857 },
858 },
859 "HTTPValidationError": {
860 "title": "HTTPValidationError",
861 "type": "object",
862 "properties": {
863 "detail": {
864 "title": "Detail",
865 "type": "array",
866 "items": {"$ref": "#/components/schemas/ValidationError"},
867 }
868 },
869 },
870 "Item": {
871 "title": "Item",
872 "required": ["name", "price"],
873 "type": "object",
874 "properties": {
875 "name": {"title": "Name", "type": "string"},
876 "price": {"title": "Price", "type": "number"},
877 },
878 },
879 "Message": {
880 "title": "Message",
881 "required": ["title", "description"],
882 "type": "object",
883 "properties": {
884 "title": {"title": "Title", "type": "string"},
885 "description": {"title": "Description", "type": "string"},
886 },
887 },
888 "ValidationError": {
889 "title": "ValidationError",
890 "required": ["loc", "msg", "type"],
891 "type": "object",
892 "properties": {
893 "loc": {
894 "title": "Location",
895 "type": "array",
896 "items": {
897 "anyOf": [{"type": "string"}, {"type": "integer"}]
898 },
899 },
900 "msg": {"title": "Message", "type": "string"},
901 "type": {"title": "Error Type", "type": "string"},
902 },
903 },
904 }
905 },
906 }
909def test_router_path_operation_overrides_generate_unique_id(): 1abcde
910 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1wzCFI
911 router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) 1wzCFI
913 @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) 1wzCFI
914 def post_root(item1: Item, item2: Item): 1wzCFI
915 return item1, item2 # pragma: nocover
917 @router.post( 1wzCFI
918 "/router",
919 response_model=List[Item],
920 responses={404: {"model": List[Message]}},
921 generate_unique_id_function=custom_generate_unique_id3,
922 )
923 def post_router(item1: Item, item2: Item): 1wzCFI
924 return item1, item2 # pragma: nocover
926 app.include_router(router) 1wzCFI
927 client = TestClient(app) 1wzCFI
928 response = client.get("/openapi.json") 1wzCFI
929 data = response.json() 1wzCFI
930 assert data == { 1wzCFI
931 "openapi": "3.1.0",
932 "info": {"title": "FastAPI", "version": "0.1.0"},
933 "paths": {
934 "/": {
935 "post": {
936 "summary": "Post Root",
937 "operationId": "foo_post_root",
938 "requestBody": {
939 "content": {
940 "application/json": {
941 "schema": {
942 "$ref": "#/components/schemas/Body_foo_post_root"
943 }
944 }
945 },
946 "required": True,
947 },
948 "responses": {
949 "200": {
950 "description": "Successful Response",
951 "content": {
952 "application/json": {
953 "schema": {
954 "title": "Response Foo Post Root",
955 "type": "array",
956 "items": {"$ref": "#/components/schemas/Item"},
957 }
958 }
959 },
960 },
961 "404": {
962 "description": "Not Found",
963 "content": {
964 "application/json": {
965 "schema": {
966 "title": "Response 404 Foo Post Root",
967 "type": "array",
968 "items": {
969 "$ref": "#/components/schemas/Message"
970 },
971 }
972 }
973 },
974 },
975 "422": {
976 "description": "Validation Error",
977 "content": {
978 "application/json": {
979 "schema": {
980 "$ref": "#/components/schemas/HTTPValidationError"
981 }
982 }
983 },
984 },
985 },
986 }
987 },
988 "/router": {
989 "post": {
990 "summary": "Post Router",
991 "operationId": "baz_post_router",
992 "requestBody": {
993 "content": {
994 "application/json": {
995 "schema": {
996 "$ref": "#/components/schemas/Body_baz_post_router"
997 }
998 }
999 },
1000 "required": True,
1001 },
1002 "responses": {
1003 "200": {
1004 "description": "Successful Response",
1005 "content": {
1006 "application/json": {
1007 "schema": {
1008 "title": "Response Baz Post Router",
1009 "type": "array",
1010 "items": {"$ref": "#/components/schemas/Item"},
1011 }
1012 }
1013 },
1014 },
1015 "404": {
1016 "description": "Not Found",
1017 "content": {
1018 "application/json": {
1019 "schema": {
1020 "title": "Response 404 Baz Post Router",
1021 "type": "array",
1022 "items": {
1023 "$ref": "#/components/schemas/Message"
1024 },
1025 }
1026 }
1027 },
1028 },
1029 "422": {
1030 "description": "Validation Error",
1031 "content": {
1032 "application/json": {
1033 "schema": {
1034 "$ref": "#/components/schemas/HTTPValidationError"
1035 }
1036 }
1037 },
1038 },
1039 },
1040 }
1041 },
1042 },
1043 "components": {
1044 "schemas": {
1045 "Body_baz_post_router": {
1046 "title": "Body_baz_post_router",
1047 "required": ["item1", "item2"],
1048 "type": "object",
1049 "properties": {
1050 "item1": {"$ref": "#/components/schemas/Item"},
1051 "item2": {"$ref": "#/components/schemas/Item"},
1052 },
1053 },
1054 "Body_foo_post_root": {
1055 "title": "Body_foo_post_root",
1056 "required": ["item1", "item2"],
1057 "type": "object",
1058 "properties": {
1059 "item1": {"$ref": "#/components/schemas/Item"},
1060 "item2": {"$ref": "#/components/schemas/Item"},
1061 },
1062 },
1063 "HTTPValidationError": {
1064 "title": "HTTPValidationError",
1065 "type": "object",
1066 "properties": {
1067 "detail": {
1068 "title": "Detail",
1069 "type": "array",
1070 "items": {"$ref": "#/components/schemas/ValidationError"},
1071 }
1072 },
1073 },
1074 "Item": {
1075 "title": "Item",
1076 "required": ["name", "price"],
1077 "type": "object",
1078 "properties": {
1079 "name": {"title": "Name", "type": "string"},
1080 "price": {"title": "Price", "type": "number"},
1081 },
1082 },
1083 "Message": {
1084 "title": "Message",
1085 "required": ["title", "description"],
1086 "type": "object",
1087 "properties": {
1088 "title": {"title": "Title", "type": "string"},
1089 "description": {"title": "Description", "type": "string"},
1090 },
1091 },
1092 "ValidationError": {
1093 "title": "ValidationError",
1094 "required": ["loc", "msg", "type"],
1095 "type": "object",
1096 "properties": {
1097 "loc": {
1098 "title": "Location",
1099 "type": "array",
1100 "items": {
1101 "anyOf": [{"type": "string"}, {"type": "integer"}]
1102 },
1103 },
1104 "msg": {"title": "Message", "type": "string"},
1105 "type": {"title": "Error Type", "type": "string"},
1106 },
1107 },
1108 }
1109 },
1110 }
1113def test_app_path_operation_overrides_generate_unique_id(): 1abcde
1114 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1JKLMN
1115 router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) 1JKLMN
1117 @app.post( 1JKLMN
1118 "/",
1119 response_model=List[Item],
1120 responses={404: {"model": List[Message]}},
1121 generate_unique_id_function=custom_generate_unique_id3,
1122 )
1123 def post_root(item1: Item, item2: Item): 1JKLMN
1124 return item1, item2 # pragma: nocover
1126 @router.post( 1JKLMN
1127 "/router",
1128 response_model=List[Item],
1129 responses={404: {"model": List[Message]}},
1130 )
1131 def post_router(item1: Item, item2: Item): 1JKLMN
1132 return item1, item2 # pragma: nocover
1134 app.include_router(router) 1JKLMN
1135 client = TestClient(app) 1JKLMN
1136 response = client.get("/openapi.json") 1JKLMN
1137 data = response.json() 1JKLMN
1138 assert data == { 1JKLMN
1139 "openapi": "3.1.0",
1140 "info": {"title": "FastAPI", "version": "0.1.0"},
1141 "paths": {
1142 "/": {
1143 "post": {
1144 "summary": "Post Root",
1145 "operationId": "baz_post_root",
1146 "requestBody": {
1147 "content": {
1148 "application/json": {
1149 "schema": {
1150 "$ref": "#/components/schemas/Body_baz_post_root"
1151 }
1152 }
1153 },
1154 "required": True,
1155 },
1156 "responses": {
1157 "200": {
1158 "description": "Successful Response",
1159 "content": {
1160 "application/json": {
1161 "schema": {
1162 "title": "Response Baz Post Root",
1163 "type": "array",
1164 "items": {"$ref": "#/components/schemas/Item"},
1165 }
1166 }
1167 },
1168 },
1169 "404": {
1170 "description": "Not Found",
1171 "content": {
1172 "application/json": {
1173 "schema": {
1174 "title": "Response 404 Baz Post Root",
1175 "type": "array",
1176 "items": {
1177 "$ref": "#/components/schemas/Message"
1178 },
1179 }
1180 }
1181 },
1182 },
1183 "422": {
1184 "description": "Validation Error",
1185 "content": {
1186 "application/json": {
1187 "schema": {
1188 "$ref": "#/components/schemas/HTTPValidationError"
1189 }
1190 }
1191 },
1192 },
1193 },
1194 }
1195 },
1196 "/router": {
1197 "post": {
1198 "summary": "Post Router",
1199 "operationId": "bar_post_router",
1200 "requestBody": {
1201 "content": {
1202 "application/json": {
1203 "schema": {
1204 "$ref": "#/components/schemas/Body_bar_post_router"
1205 }
1206 }
1207 },
1208 "required": True,
1209 },
1210 "responses": {
1211 "200": {
1212 "description": "Successful Response",
1213 "content": {
1214 "application/json": {
1215 "schema": {
1216 "title": "Response Bar Post Router",
1217 "type": "array",
1218 "items": {"$ref": "#/components/schemas/Item"},
1219 }
1220 }
1221 },
1222 },
1223 "404": {
1224 "description": "Not Found",
1225 "content": {
1226 "application/json": {
1227 "schema": {
1228 "title": "Response 404 Bar Post Router",
1229 "type": "array",
1230 "items": {
1231 "$ref": "#/components/schemas/Message"
1232 },
1233 }
1234 }
1235 },
1236 },
1237 "422": {
1238 "description": "Validation Error",
1239 "content": {
1240 "application/json": {
1241 "schema": {
1242 "$ref": "#/components/schemas/HTTPValidationError"
1243 }
1244 }
1245 },
1246 },
1247 },
1248 }
1249 },
1250 },
1251 "components": {
1252 "schemas": {
1253 "Body_bar_post_router": {
1254 "title": "Body_bar_post_router",
1255 "required": ["item1", "item2"],
1256 "type": "object",
1257 "properties": {
1258 "item1": {"$ref": "#/components/schemas/Item"},
1259 "item2": {"$ref": "#/components/schemas/Item"},
1260 },
1261 },
1262 "Body_baz_post_root": {
1263 "title": "Body_baz_post_root",
1264 "required": ["item1", "item2"],
1265 "type": "object",
1266 "properties": {
1267 "item1": {"$ref": "#/components/schemas/Item"},
1268 "item2": {"$ref": "#/components/schemas/Item"},
1269 },
1270 },
1271 "HTTPValidationError": {
1272 "title": "HTTPValidationError",
1273 "type": "object",
1274 "properties": {
1275 "detail": {
1276 "title": "Detail",
1277 "type": "array",
1278 "items": {"$ref": "#/components/schemas/ValidationError"},
1279 }
1280 },
1281 },
1282 "Item": {
1283 "title": "Item",
1284 "required": ["name", "price"],
1285 "type": "object",
1286 "properties": {
1287 "name": {"title": "Name", "type": "string"},
1288 "price": {"title": "Price", "type": "number"},
1289 },
1290 },
1291 "Message": {
1292 "title": "Message",
1293 "required": ["title", "description"],
1294 "type": "object",
1295 "properties": {
1296 "title": {"title": "Title", "type": "string"},
1297 "description": {"title": "Description", "type": "string"},
1298 },
1299 },
1300 "ValidationError": {
1301 "title": "ValidationError",
1302 "required": ["loc", "msg", "type"],
1303 "type": "object",
1304 "properties": {
1305 "loc": {
1306 "title": "Location",
1307 "type": "array",
1308 "items": {
1309 "anyOf": [{"type": "string"}, {"type": "integer"}]
1310 },
1311 },
1312 "msg": {"title": "Message", "type": "string"},
1313 "type": {"title": "Error Type", "type": "string"},
1314 },
1315 },
1316 }
1317 },
1318 }
1321def test_callback_override_generate_unique_id(): 1abcde
1322 app = FastAPI(generate_unique_id_function=custom_generate_unique_id) 1pqrst
1323 callback_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) 1pqrst
1325 @callback_router.post( 1pqrst
1326 "/post-callback",
1327 response_model=List[Item],
1328 responses={404: {"model": List[Message]}},
1329 generate_unique_id_function=custom_generate_unique_id3,
1330 )
1331 def post_callback(item1: Item, item2: Item): 1pqrst
1332 return item1, item2 # pragma: nocover
1334 @app.post( 1pqrst
1335 "/",
1336 response_model=List[Item],
1337 responses={404: {"model": List[Message]}},
1338 generate_unique_id_function=custom_generate_unique_id3,
1339 callbacks=callback_router.routes,
1340 )
1341 def post_root(item1: Item, item2: Item): 1pqrst
1342 return item1, item2 # pragma: nocover
1344 @app.post( 1pqrst
1345 "/tocallback",
1346 response_model=List[Item],
1347 responses={404: {"model": List[Message]}},
1348 )
1349 def post_with_callback(item1: Item, item2: Item): 1pqrst
1350 return item1, item2 # pragma: nocover
1352 client = TestClient(app) 1pqrst
1353 response = client.get("/openapi.json") 1pqrst
1354 data = response.json() 1pqrst
1355 assert data == { 1pqrst
1356 "openapi": "3.1.0",
1357 "info": {"title": "FastAPI", "version": "0.1.0"},
1358 "paths": {
1359 "/": {
1360 "post": {
1361 "summary": "Post Root",
1362 "operationId": "baz_post_root",
1363 "requestBody": {
1364 "content": {
1365 "application/json": {
1366 "schema": {
1367 "$ref": "#/components/schemas/Body_baz_post_root"
1368 }
1369 }
1370 },
1371 "required": True,
1372 },
1373 "responses": {
1374 "200": {
1375 "description": "Successful Response",
1376 "content": {
1377 "application/json": {
1378 "schema": {
1379 "title": "Response Baz Post Root",
1380 "type": "array",
1381 "items": {"$ref": "#/components/schemas/Item"},
1382 }
1383 }
1384 },
1385 },
1386 "404": {
1387 "description": "Not Found",
1388 "content": {
1389 "application/json": {
1390 "schema": {
1391 "title": "Response 404 Baz Post Root",
1392 "type": "array",
1393 "items": {
1394 "$ref": "#/components/schemas/Message"
1395 },
1396 }
1397 }
1398 },
1399 },
1400 "422": {
1401 "description": "Validation Error",
1402 "content": {
1403 "application/json": {
1404 "schema": {
1405 "$ref": "#/components/schemas/HTTPValidationError"
1406 }
1407 }
1408 },
1409 },
1410 },
1411 "callbacks": {
1412 "post_callback": {
1413 "/post-callback": {
1414 "post": {
1415 "summary": "Post Callback",
1416 "operationId": "baz_post_callback",
1417 "requestBody": {
1418 "content": {
1419 "application/json": {
1420 "schema": {
1421 "$ref": "#/components/schemas/Body_baz_post_callback"
1422 }
1423 }
1424 },
1425 "required": True,
1426 },
1427 "responses": {
1428 "200": {
1429 "description": "Successful Response",
1430 "content": {
1431 "application/json": {
1432 "schema": {
1433 "title": "Response Baz Post Callback",
1434 "type": "array",
1435 "items": {
1436 "$ref": "#/components/schemas/Item"
1437 },
1438 }
1439 }
1440 },
1441 },
1442 "404": {
1443 "description": "Not Found",
1444 "content": {
1445 "application/json": {
1446 "schema": {
1447 "title": "Response 404 Baz Post Callback",
1448 "type": "array",
1449 "items": {
1450 "$ref": "#/components/schemas/Message"
1451 },
1452 }
1453 }
1454 },
1455 },
1456 "422": {
1457 "description": "Validation Error",
1458 "content": {
1459 "application/json": {
1460 "schema": {
1461 "$ref": "#/components/schemas/HTTPValidationError"
1462 }
1463 }
1464 },
1465 },
1466 },
1467 }
1468 }
1469 }
1470 },
1471 }
1472 },
1473 "/tocallback": {
1474 "post": {
1475 "summary": "Post With Callback",
1476 "operationId": "foo_post_with_callback",
1477 "requestBody": {
1478 "content": {
1479 "application/json": {
1480 "schema": {
1481 "$ref": "#/components/schemas/Body_foo_post_with_callback"
1482 }
1483 }
1484 },
1485 "required": True,
1486 },
1487 "responses": {
1488 "200": {
1489 "description": "Successful Response",
1490 "content": {
1491 "application/json": {
1492 "schema": {
1493 "title": "Response Foo Post With Callback",
1494 "type": "array",
1495 "items": {"$ref": "#/components/schemas/Item"},
1496 }
1497 }
1498 },
1499 },
1500 "404": {
1501 "description": "Not Found",
1502 "content": {
1503 "application/json": {
1504 "schema": {
1505 "title": "Response 404 Foo Post With Callback",
1506 "type": "array",
1507 "items": {
1508 "$ref": "#/components/schemas/Message"
1509 },
1510 }
1511 }
1512 },
1513 },
1514 "422": {
1515 "description": "Validation Error",
1516 "content": {
1517 "application/json": {
1518 "schema": {
1519 "$ref": "#/components/schemas/HTTPValidationError"
1520 }
1521 }
1522 },
1523 },
1524 },
1525 }
1526 },
1527 },
1528 "components": {
1529 "schemas": {
1530 "Body_baz_post_callback": {
1531 "title": "Body_baz_post_callback",
1532 "required": ["item1", "item2"],
1533 "type": "object",
1534 "properties": {
1535 "item1": {"$ref": "#/components/schemas/Item"},
1536 "item2": {"$ref": "#/components/schemas/Item"},
1537 },
1538 },
1539 "Body_baz_post_root": {
1540 "title": "Body_baz_post_root",
1541 "required": ["item1", "item2"],
1542 "type": "object",
1543 "properties": {
1544 "item1": {"$ref": "#/components/schemas/Item"},
1545 "item2": {"$ref": "#/components/schemas/Item"},
1546 },
1547 },
1548 "Body_foo_post_with_callback": {
1549 "title": "Body_foo_post_with_callback",
1550 "required": ["item1", "item2"],
1551 "type": "object",
1552 "properties": {
1553 "item1": {"$ref": "#/components/schemas/Item"},
1554 "item2": {"$ref": "#/components/schemas/Item"},
1555 },
1556 },
1557 "HTTPValidationError": {
1558 "title": "HTTPValidationError",
1559 "type": "object",
1560 "properties": {
1561 "detail": {
1562 "title": "Detail",
1563 "type": "array",
1564 "items": {"$ref": "#/components/schemas/ValidationError"},
1565 }
1566 },
1567 },
1568 "Item": {
1569 "title": "Item",
1570 "required": ["name", "price"],
1571 "type": "object",
1572 "properties": {
1573 "name": {"title": "Name", "type": "string"},
1574 "price": {"title": "Price", "type": "number"},
1575 },
1576 },
1577 "Message": {
1578 "title": "Message",
1579 "required": ["title", "description"],
1580 "type": "object",
1581 "properties": {
1582 "title": {"title": "Title", "type": "string"},
1583 "description": {"title": "Description", "type": "string"},
1584 },
1585 },
1586 "ValidationError": {
1587 "title": "ValidationError",
1588 "required": ["loc", "msg", "type"],
1589 "type": "object",
1590 "properties": {
1591 "loc": {
1592 "title": "Location",
1593 "type": "array",
1594 "items": {
1595 "anyOf": [{"type": "string"}, {"type": "integer"}]
1596 },
1597 },
1598 "msg": {"title": "Message", "type": "string"},
1599 "type": {"title": "Error Type", "type": "string"},
1600 },
1601 },
1602 }
1603 },
1604 }
1607def test_warn_duplicate_operation_id(): 1abcde
1608 def broken_operation_id(route: APIRoute): 1klmno
1609 return "foo" 1klmno
1611 app = FastAPI(generate_unique_id_function=broken_operation_id) 1klmno
1613 @app.post("/") 1klmno
1614 def post_root(item1: Item): 1klmno
1615 return item1 # pragma: nocover
1617 @app.post("/second") 1klmno
1618 def post_second(item1: Item): 1klmno
1619 return item1 # pragma: nocover
1621 @app.post("/third") 1klmno
1622 def post_third(item1: Item): 1klmno
1623 return item1 # pragma: nocover
1625 client = TestClient(app) 1klmno
1626 with warnings.catch_warnings(record=True) as w: 1klmno
1627 warnings.simplefilter("always") 1klmno
1628 client.get("/openapi.json") 1klmno
1629 assert len(w) >= 2 1klmno
1630 duplicate_warnings = [ 1klmno
1631 warning for warning in w if issubclass(warning.category, UserWarning)
1632 ]
1633 assert len(duplicate_warnings) > 0 1klmno
1634 assert "Duplicate Operation ID" in str(duplicate_warnings[0].message) 1klmno