Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display missing route details. #1363

Merged
14 changes: 9 additions & 5 deletions starlette/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
"""
Expand Down
8 changes: 7 additions & 1 deletion tests/test_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down