diff --git a/litestar/app.py b/litestar/app.py index 3dbdbf676f..6acc4cb9f2 100644 --- a/litestar/app.py +++ b/litestar/app.py @@ -198,6 +198,7 @@ def __init__( openapi_config: OpenAPIConfig | None = DEFAULT_OPENAPI_CONFIG, opt: Mapping[str, Any] | None = None, parameters: ParametersMap | None = None, + path: str | None = None, plugins: Sequence[PluginProtocol] | None = None, request_class: type[Request] | None = None, response_cache_config: ResponseCacheConfig | None = None, @@ -277,6 +278,10 @@ def __init__( :class:`ASGI Scope <.types.Scope>`. parameters: A mapping of :class:`Parameter <.params.Parameter>` definitions available to all application paths. + path: A path fragment that is prefixed to all route handlers, controllers and routers associated + with the application instance. + + .. versionadded:: 2.8.0 pdb_on_exception: Drop into the PDB when an exception occurs. plugins: Sequence of plugins. request_class: An optional subclass of :class:`Request <.connection.Request>` to use for http connections. @@ -350,6 +355,7 @@ def __init__( on_startup=list(on_startup or []), openapi_config=openapi_config, opt=dict(opt or {}), + path=path or "", parameters=parameters or {}, pdb_on_exception=pdb_on_exception, plugins=self._get_default_plugins(list(plugins or [])), @@ -455,7 +461,7 @@ def __init__( middleware=config.middleware, opt=config.opt, parameters=config.parameters, - path="", + path=config.path, request_class=self.request_class, response_class=config.response_class, response_cookies=config.response_cookies, diff --git a/litestar/config/app.py b/litestar/config/app.py index 0acefb1ae9..aef812ecca 100644 --- a/litestar/config/app.py +++ b/litestar/config/app.py @@ -151,6 +151,12 @@ class AppConfig: """ parameters: ParametersMap = field(default_factory=dict) """A mapping of :class:`Parameter <.params.Parameter>` definitions available to all application paths.""" + path: str = field(default="") + """A base path that prefixed to all route handlers, controllers and routers associated with the + application instance. + + .. versionadded:: 2.8.0 + """ pdb_on_exception: bool = field(default=False) """Drop into the PDB on an exception""" plugins: list[PluginProtocol] = field(default_factory=list) diff --git a/litestar/testing/helpers.py b/litestar/testing/helpers.py index 5ac59af7c8..ab15609ffe 100644 --- a/litestar/testing/helpers.py +++ b/litestar/testing/helpers.py @@ -86,6 +86,7 @@ def create_test_client( openapi_config: OpenAPIConfig | None = DEFAULT_OPENAPI_CONFIG, opt: Mapping[str, Any] | None = None, parameters: ParametersMap | None = None, + path: str | None = None, plugins: Sequence[PluginProtocol] | None = None, lifespan: list[Callable[[Litestar], AbstractAsyncContextManager] | AbstractAsyncContextManager] | None = None, raise_server_exceptions: bool = True, @@ -201,6 +202,10 @@ def test_my_handler() -> None: :class:`ASGI Scope <.types.Scope>`. parameters: A mapping of :class:`Parameter <.params.Parameter>` definitions available to all application paths. + path: A path fragment that is prefixed to all route handlers, controllers and routers associated + with the application instance. + + .. versionadded:: 2.8.0 pdb_on_exception: Drop into the PDB when an exception occurs. plugins: Sequence of plugins. request_class: An optional subclass of :class:`Request <.connection.Request>` to use for http connections. @@ -273,6 +278,7 @@ def test_my_handler() -> None: openapi_config=openapi_config, opt=opt, parameters=parameters, + path=path, pdb_on_exception=pdb_on_exception, plugins=plugins, request_class=request_class, @@ -343,6 +349,7 @@ def create_async_test_client( opt: Mapping[str, Any] | None = None, parameters: ParametersMap | None = None, pdb_on_exception: bool | None = None, + path: str | None = None, plugins: Sequence[PluginProtocol] | None = None, raise_server_exceptions: bool = True, request_class: type[Request] | None = None, @@ -456,6 +463,10 @@ async def test_my_handler() -> None: :class:`ASGI Scope <.types.Scope>`. parameters: A mapping of :class:`Parameter <.params.Parameter>` definitions available to all application paths. + path: A path fragment that is prefixed to all route handlers, controllers and routers associated + with the application instance. + + .. versionadded:: 2.8.0 pdb_on_exception: Drop into the PDB when an exception occurs. plugins: Sequence of plugins. request_class: An optional subclass of :class:`Request <.connection.Request>` to use for http connections. @@ -527,6 +538,7 @@ async def test_my_handler() -> None: openapi_config=openapi_config, opt=opt, parameters=parameters, + path=path, pdb_on_exception=pdb_on_exception, plugins=plugins, request_class=request_class, diff --git a/tests/unit/test_app.py b/tests/unit/test_app.py index 809b8abe1e..8eff0ef534 100644 --- a/tests/unit/test_app.py +++ b/tests/unit/test_app.py @@ -450,3 +450,12 @@ async def hook_b(app: Litestar) -> None: def test_use_dto_codegen_feature_flag_warns() -> None: with pytest.warns(LitestarWarning, match="Use of redundant experimental feature flag DTO_CODEGEN"): Litestar(experimental_features=[ExperimentalFeatures.DTO_CODEGEN]) + + +def test_using_custom_path_parameter() -> None: + @get() + def my_route_handler() -> None: ... + + with create_test_client(my_route_handler, path="/abc") as client: + response = client.get("/abc") + assert response.status_code == HTTP_200_OK