diff --git a/fastapi/applications.py b/fastapi/applications.py index 02193312b..039a44a7d 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1554,7 +1554,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -1873,6 +1873,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP GET operation. @@ -1891,6 +1892,7 @@ class FastAPI(Starlette): """ return self.router.get( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -1913,6 +1915,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def put( @@ -1927,7 +1930,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2246,6 +2249,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PUT operation. @@ -2269,6 +2273,7 @@ class FastAPI(Starlette): """ return self.router.put( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2291,6 +2296,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def post( @@ -2305,7 +2311,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2624,6 +2630,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP POST operation. @@ -2647,6 +2654,7 @@ class FastAPI(Starlette): """ return self.router.post( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2669,6 +2677,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def delete( @@ -2683,7 +2692,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3002,6 +3011,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP DELETE operation. @@ -3020,6 +3030,7 @@ class FastAPI(Starlette): """ return self.router.delete( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3042,6 +3053,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def options( @@ -3056,7 +3068,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3375,6 +3387,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP OPTIONS operation. @@ -3393,6 +3406,7 @@ class FastAPI(Starlette): """ return self.router.options( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3415,6 +3429,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def head( @@ -3429,7 +3444,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3748,6 +3763,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP HEAD operation. @@ -3766,6 +3782,7 @@ class FastAPI(Starlette): """ return self.router.head( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3788,6 +3805,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def patch( @@ -3802,7 +3820,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4121,6 +4139,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PATCH operation. @@ -4166,6 +4185,8 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + # *args, + **kwargs, ) def trace( @@ -4180,7 +4201,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4499,6 +4520,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP TRACE operation. @@ -4517,6 +4539,7 @@ class FastAPI(Starlette): """ return self.router.trace( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -4539,6 +4562,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def websocket_route( diff --git a/fastapi/routing.py b/fastapi/routing.py index 9be2b44bc..359d0fe48 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -562,7 +562,7 @@ class APIRoute(routing.Route): self, path: str, endpoint: Callable[..., Any], - *, + *args: Any, response_model: Any = Default(None), status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, @@ -591,6 +591,7 @@ class APIRoute(routing.Route): generate_unique_id_function: Union[ Callable[["APIRoute"], str], DefaultPlaceholder ] = Default(generate_unique_id), + **kwargs: Any, ) -> None: self.path = path self.endpoint = endpoint @@ -755,7 +756,7 @@ class APIRouter(routing.Router): def __init__( self, - *, + *args: Any, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ Optional[List[Union[str, Enum]]], @@ -967,6 +968,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> None: super().__init__( routes=routes, @@ -1016,7 +1018,7 @@ class APIRouter(routing.Router): self, path: str, endpoint: Callable[..., Any], - *, + *args: Any, response_model: Any = Default(None), status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, @@ -1045,6 +1047,7 @@ class APIRouter(routing.Router): generate_unique_id_function: Union[ Callable[[APIRoute], str], DefaultPlaceholder ] = Default(generate_unique_id), + **kwargs: Any, ) -> None: route_class = route_class_override or self.route_class responses = responses or {} @@ -1066,7 +1069,8 @@ class APIRouter(routing.Router): ) route = route_class( self.prefix + path, - endpoint=endpoint, + endpoint, + *args, response_model=response_model, status_code=status_code, tags=current_tags, @@ -1091,13 +1095,14 @@ class APIRouter(routing.Router): callbacks=current_callbacks, openapi_extra=openapi_extra, generate_unique_id_function=current_generate_unique_id, + **kwargs, ) self.routes.append(route) def api_route( self, path: str, - *, + *args: Any, response_model: Any = Default(None), status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, @@ -1123,11 +1128,13 @@ class APIRouter(routing.Router): generate_unique_id_function: Callable[[APIRoute], str] = Default( generate_unique_id ), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_api_route( path, func, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -1151,6 +1158,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) return func @@ -1256,7 +1264,7 @@ class APIRouter(routing.Router): def include_router( self, router: Annotated["APIRouter", Doc("The `APIRouter` to include.")], - *, + *args: Any, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ Optional[List[Union[str, Enum]]], @@ -1364,6 +1372,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> None: """ Include another `APIRouter` in the same current `APIRouter`. @@ -1436,6 +1445,7 @@ class APIRouter(routing.Router): self.add_api_route( prefix + route.path, route.endpoint, + *args, response_model=route.response_model, status_code=route.status_code, tags=current_tags, @@ -1462,6 +1472,7 @@ class APIRouter(routing.Router): callbacks=current_callbacks, openapi_extra=route.openapi_extra, generate_unique_id_function=current_generate_unique_id, + **kwargs, ) elif isinstance(route, routing.Route): methods = list(route.methods or []) @@ -1509,7 +1520,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -1828,6 +1839,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP GET operation. @@ -1848,7 +1860,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -1872,6 +1885,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def put( @@ -1886,7 +1900,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2205,6 +2219,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PUT operation. @@ -2230,7 +2245,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2254,6 +2270,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def post( @@ -2268,7 +2285,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2587,6 +2604,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP POST operation. @@ -2612,7 +2630,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2636,6 +2655,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def delete( @@ -2650,7 +2670,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2969,6 +2989,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP DELETE operation. @@ -2989,7 +3010,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3013,6 +3035,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def options( @@ -3027,7 +3050,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3346,6 +3369,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP OPTIONS operation. @@ -3366,7 +3390,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3390,6 +3415,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def head( @@ -3404,7 +3430,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3723,6 +3749,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP HEAD operation. @@ -3748,7 +3775,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3772,6 +3800,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def patch( @@ -3786,7 +3815,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4105,6 +4134,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PATCH operation. @@ -4130,7 +4160,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -4154,6 +4185,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def trace( @@ -4168,7 +4200,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4487,6 +4519,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP TRACE operation. @@ -4512,7 +4545,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -4536,6 +4570,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) @deprecated( diff --git a/tests/test_operations_signatures.py b/tests/test_operations_signatures.py index 1a749651d..832f9a0c9 100644 --- a/tests/test_operations_signatures.py +++ b/tests/test_operations_signatures.py @@ -1,22 +1,25 @@ import inspect +import pytest from fastapi import APIRouter, FastAPI -method_names = ["get", "put", "post", "delete", "options", "head", "patch", "trace"] - -def test_signatures_consistency(): - base_sig = inspect.signature(APIRouter.get) - for method_name in method_names: - router_method = getattr(APIRouter, method_name) - app_method = getattr(FastAPI, method_name) - router_sig = inspect.signature(router_method) - app_sig = inspect.signature(app_method) - param: inspect.Parameter - for key, param in base_sig.parameters.items(): - router_param: inspect.Parameter = router_sig.parameters[key] - app_param: inspect.Parameter = app_sig.parameters[key] - assert param.annotation == router_param.annotation - assert param.annotation == app_param.annotation - assert param.default == router_param.default - assert param.default == app_param.default +@pytest.mark.parametrize( + "method_name", ["get", "put", "post", "delete", "options", "head", "patch", "trace"] +) +@pytest.mark.parametrize( + "sig_param", inspect.signature(APIRouter.get).parameters.items() +) +def test_signatures_consistency(method_name, sig_param): + router_method = getattr(APIRouter, method_name) + app_method = getattr(FastAPI, method_name) + router_sig = inspect.signature(router_method) + app_sig = inspect.signature(app_method) + param: inspect.Parameter + key, param = sig_param + router_param: inspect.Parameter = router_sig.parameters[key] + app_param: inspect.Parameter = app_sig.parameters[key] + assert param.annotation == router_param.annotation + assert param.annotation == app_param.annotation + assert param.default == router_param.default + assert param.default == app_param.default