diff --git a/fastapi/applications.py b/fastapi/applications.py index 05c7bd2be..0266ecafb 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1469,7 +1469,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -1788,6 +1788,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP GET operation. @@ -1806,6 +1807,7 @@ class FastAPI(Starlette): """ return self.router.get( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -1828,6 +1830,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def put( @@ -1842,7 +1845,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2161,6 +2164,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PUT operation. @@ -2184,6 +2188,7 @@ class FastAPI(Starlette): """ return self.router.put( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2206,6 +2211,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def post( @@ -2220,7 +2226,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2539,6 +2545,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP POST operation. @@ -2562,6 +2569,7 @@ class FastAPI(Starlette): """ return self.router.post( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2584,6 +2592,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def delete( @@ -2598,7 +2607,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2917,6 +2926,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP DELETE operation. @@ -2935,6 +2945,7 @@ class FastAPI(Starlette): """ return self.router.delete( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2957,6 +2968,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def options( @@ -2971,7 +2983,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3290,6 +3302,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP OPTIONS operation. @@ -3308,6 +3321,7 @@ class FastAPI(Starlette): """ return self.router.options( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3330,6 +3344,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def head( @@ -3344,7 +3359,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3663,6 +3678,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP HEAD operation. @@ -3681,6 +3697,7 @@ class FastAPI(Starlette): """ return self.router.head( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3703,6 +3720,7 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def patch( @@ -3717,7 +3735,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4036,6 +4054,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PATCH operation. @@ -4081,6 +4100,8 @@ class FastAPI(Starlette): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + # *args, + **kwargs, ) def trace( @@ -4095,7 +4116,7 @@ class FastAPI(Starlette): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4414,6 +4435,7 @@ class FastAPI(Starlette): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP TRACE operation. @@ -4432,6 +4454,7 @@ class FastAPI(Starlette): """ return self.router.trace( path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -4454,6 +4477,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 54c75a027..a68f06833 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -431,7 +431,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, @@ -460,6 +460,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 @@ -622,7 +623,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]]], @@ -834,6 +835,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> None: super().__init__( routes=routes, @@ -883,7 +885,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, @@ -912,6 +914,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 {} @@ -933,7 +936,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, @@ -958,13 +962,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, @@ -990,11 +995,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, @@ -1018,6 +1025,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) return func @@ -1123,7 +1131,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]]], @@ -1231,6 +1239,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> None: """ Include another `APIRouter` in the same current `APIRouter`. @@ -1303,6 +1312,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, @@ -1329,6 +1339,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 []) @@ -1376,7 +1387,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -1695,6 +1706,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP GET operation. @@ -1715,7 +1727,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -1739,6 +1752,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def put( @@ -1753,7 +1767,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2072,6 +2086,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PUT operation. @@ -2097,7 +2112,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2121,6 +2137,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def post( @@ -2135,7 +2152,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2454,6 +2471,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP POST operation. @@ -2479,7 +2497,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2503,6 +2522,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def delete( @@ -2517,7 +2537,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -2836,6 +2856,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP DELETE operation. @@ -2856,7 +2877,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -2880,6 +2902,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def options( @@ -2894,7 +2917,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3213,6 +3236,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP OPTIONS operation. @@ -3233,7 +3257,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3257,6 +3282,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def head( @@ -3271,7 +3297,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3590,6 +3616,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP HEAD operation. @@ -3615,7 +3642,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -3639,6 +3667,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def patch( @@ -3653,7 +3682,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -3972,6 +4001,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP PATCH operation. @@ -3997,7 +4027,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -4021,6 +4052,7 @@ class APIRouter(routing.Router): callbacks=callbacks, openapi_extra=openapi_extra, generate_unique_id_function=generate_unique_id_function, + **kwargs, ) def trace( @@ -4035,7 +4067,7 @@ class APIRouter(routing.Router): """ ), ], - *, + *args: Any, response_model: Annotated[ Any, Doc( @@ -4354,6 +4386,7 @@ class APIRouter(routing.Router): """ ), ] = Default(generate_unique_id), + **kwargs: Any, ) -> Callable[[DecoratedCallable], DecoratedCallable]: """ Add a *path operation* using an HTTP TRACE operation. @@ -4379,7 +4412,8 @@ class APIRouter(routing.Router): ``` """ return self.api_route( - path=path, + path, + *args, response_model=response_model, status_code=status_code, tags=tags, @@ -4403,6 +4437,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