diff --git a/litestar/app.py b/litestar/app.py index 71d373a23f..efcd446743 100644 --- a/litestar/app.py +++ b/litestar/app.py @@ -15,6 +15,7 @@ from itertools import chain from pathlib import Path from typing import TYPE_CHECKING, Any, AsyncGenerator, Callable, Iterable, Mapping, Sequence, TypedDict, cast +from uuid import UUID from litestar._asgi import ASGIRouter from litestar._asgi.utils import get_route_handlers, wrap_in_exception_handler @@ -768,7 +769,9 @@ def get_membership_details(group_id: int, user_id: int) -> None: Args: name: A route handler unique name. - **path_parameters: Actual values for path parameters in the route. + **path_parameters: Actual values for path parameters in the route. Parameters of type + `datetime`, `date`, `time`, `timedelta`, `float`, `Path`, `UUID` + may be passed in their string representations. Raises: NoRouteMatchFoundException: If route with 'name' does not exist, path parameters are missing in @@ -781,7 +784,7 @@ def get_membership_details(group_id: int, user_id: int) -> None: if handler_index is None: raise NoRouteMatchFoundException(f"Route {name} can not be found") - allow_str_instead = {datetime, date, time, timedelta, float, Path} + allow_str_instead = {datetime, date, time, timedelta, float, Path, UUID} routes = sorted( self.asgi_router.route_mapping[handler_index["identifier"]], key=lambda r: len(r.path_parameters), diff --git a/tests/e2e/test_routing/test_route_reverse.py b/tests/e2e/test_routing/test_route_reverse.py index 0a8d914883..0d2351108b 100644 --- a/tests/e2e/test_routing/test_route_reverse.py +++ b/tests/e2e/test_routing/test_route_reverse.py @@ -1,5 +1,7 @@ -from datetime import time +from datetime import date, datetime, time, timedelta +from pathlib import Path from typing import Type +from uuid import UUID import pytest @@ -102,3 +104,41 @@ def handler_two() -> None: with pytest.raises(NoRouteMatchFoundException): app.route_reverse("another-handler-name", param=1) + + +def test_route_reverse_allow_string_params() -> None: + @get( + "/strings-everywhere/{datetime_param:datetime}/{date_param:date}/" + "{time_param:time}/{timedelta_param:timedelta}/" + "{float_param:float}/{uuid_param:uuid}/{path_param:path}", + name="strings-everywhere-handler", + ) + def strings_everywhere_handler( + datetime_param: datetime, + date_param: date, + time_param: time, + timedelta_param: timedelta, + float_param: float, + uuid_param: UUID, + path_param: Path, + ) -> None: + return None + + app = Litestar(route_handlers=[strings_everywhere_handler]) + + reversed_url_path = app.route_reverse( + "strings-everywhere-handler", + datetime_param="0001-01-01T01:01:01.000001Z", # datetime(1, 1, 1, 1, 1, 1, 1, tzinfo=UTC) + date_param="0001-01-01", # date(1,1,1) + time_param="01:01:01.000001Z", # time(1, 1, 1, 1, tzinfo=UTC) + timedelta_param="P8DT3661.001001S", # timedelta(1, 1, 1, 1, 1, 1, 1) + float_param="0.1", + uuid_param="00000000-0000-0000-0000-000000000000", # UUID(int=0) + path_param="/home/user", # Path("/home/user/"), + ) + + assert ( + reversed_url_path == "/strings-everywhere/0001-01-01T01:01:01.000001Z/" + "0001-01-01/01:01:01.000001Z/P8DT3661.001001S/0.1/" + "00000000-0000-0000-0000-000000000000/home/user" + )