diff --git a/starlette/routing.py b/starlette/routing.py index 03db2ff3e..0388304c9 100644 --- a/starlette/routing.py +++ b/starlette/routing.py @@ -31,6 +31,10 @@ class NoMatchFound(Exception): if no matching route exists. """ + def __init__(self, name: str, path_params: typing.Dict[str, typing.Any]) -> None: + params = ", ".join(list(path_params.keys())) + super().__init__(f'No route exists for name "{name}" and params "{params}".') + class Match(Enum): NONE = 0 @@ -240,7 +244,7 @@ def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath: expected_params = set(self.param_convertors.keys()) if name != self.name or seen_params != expected_params: - raise NoMatchFound() + raise NoMatchFound(name, path_params) path, remaining_params = replace_params( self.path_format, self.param_convertors, path_params @@ -309,7 +313,7 @@ def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath: expected_params = set(self.param_convertors.keys()) if name != self.name or seen_params != expected_params: - raise NoMatchFound() + raise NoMatchFound(name, path_params) path, remaining_params = replace_params( self.path_format, self.param_convertors, path_params @@ -408,7 +412,7 @@ def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath: ) except NoMatchFound: pass - raise NoMatchFound() + raise NoMatchFound(name, path_params) async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: await self.app(scope, receive, send) @@ -472,7 +476,7 @@ def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath: return URLPath(path=str(url), protocol=url.protocol, host=host) except NoMatchFound: pass - raise NoMatchFound() + raise NoMatchFound(name, path_params) async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: await self.app(scope, receive, send) @@ -593,7 +597,7 @@ def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath: return route.url_path_for(name, **path_params) except NoMatchFound: pass - raise NoMatchFound() + raise NoMatchFound(name, path_params) async def startup(self) -> None: """ diff --git a/tests/test_routing.py b/tests/test_routing.py index acd7cdb26..7077c5616 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -243,8 +243,14 @@ def test_url_path_for(): assert app.url_path_for("homepage") == "/" assert app.url_path_for("user", username="tomchristie") == "/users/tomchristie" assert app.url_path_for("websocket_endpoint") == "/ws" - with pytest.raises(NoMatchFound): + with pytest.raises( + NoMatchFound, match='No route exists for name "broken" and params "".' + ): assert app.url_path_for("broken") + with pytest.raises( + NoMatchFound, match='No route exists for name "broken" and params "key, key2".' + ): + assert app.url_path_for("broken", key="value", key2="value2") with pytest.raises(AssertionError): app.url_path_for("user", username="tom/christie") with pytest.raises(AssertionError):