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

Code quality findings 31

Ensure functions have docstrings for documentation
missing-docstring
def custom_generate_unique_id(route: APIRoute):
Ensure functions have docstrings for documentation
missing-docstring
def custom_generate_unique_id2(route: APIRoute):
Ensure functions have docstrings for documentation
missing-docstring
def custom_generate_unique_id3(route: APIRoute):
Ensure functions have docstrings for documentation
missing-docstring
def test_top_level_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_router(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_router_overrides_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_router(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_router_include_overrides_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_router(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_subrouter_top_level_include_overrides_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_router(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_subrouter(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_router_path_operation_overrides_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_router(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_app_path_operation_overrides_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_router(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_callback_override_generate_unique_id():
Ensure functions have docstrings for documentation
missing-docstring
def post_callback(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_with_callback(item1: Item, item2: Item):
Ensure functions have docstrings for documentation
missing-docstring
def test_warn_duplicate_operation_id():
Ensure functions have docstrings for documentation
missing-docstring
def broken_operation_id(route: APIRoute):
Ensure functions have docstrings for documentation
missing-docstring
def post_root(item1: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_second(item1: Item):
Ensure functions have docstrings for documentation
missing-docstring
def post_third(item1: Item):

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.