Skip to content
Open
19 changes: 13 additions & 6 deletions falcon/routing/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from falcon._typing import MethodDict


class SuffixedMethodNotFoundError(Exception):
class MethodNotFoundError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)
self.message = message
Expand Down Expand Up @@ -69,11 +69,18 @@ def map_http_methods(resource: object, suffix: str | None = None) -> MethodDict:
if callable(responder):
method_map[method] = responder

# If suffix is specified and doesn't map to any methods, raise an error
if suffix and not method_map:
raise SuffixedMethodNotFoundError(
'No responders found for the specified suffix'
)
# If doesn't map to any methods, raise an error
if not method_map:
resource_name = resource.__class__.__name__
if suffix:
raise MethodNotFoundError(
f'No responders found for the specified resource: '
f'{resource_name} and suffix: {suffix}'
)
else:
raise MethodNotFoundError(
f'No responders found for the specified resource: {resource_name}'
)

return method_map

Expand Down
3 changes: 2 additions & 1 deletion tests/asgi/test_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,8 @@ async def on_websocket(self, req, ws):

async def test_ws_simulator_collect_edge_cases(conductor):
class Resource:
pass
async def on_websocket(self, req, ws):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe adding an unrelated method (such as on_delete or whatever) would match the original intent of this test case better? (I.e., not having any on_websocket() responder.)

pass

conductor.app.add_route('/', Resource())

Expand Down
17 changes: 0 additions & 17 deletions tests/test_http_method_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@
]


@pytest.fixture
def stonewall():
return Stonewall()


@pytest.fixture
def resource_things():
return ThingsResource()
Expand All @@ -64,8 +59,6 @@ def resource_get_with_faulty_put():
def client(asgi, util):
app = util.create_app(asgi)

app.add_route('/stonewall', Stonewall())

resource_things = ThingsResource()
app.add_route('/things', resource_things)
app.add_route('/things/{id}/stuff/{sid}', resource_things)
Expand Down Expand Up @@ -115,10 +108,6 @@ def on_websocket(self, req, resp, id, sid):
self.called = True


class Stonewall:
pass


def capture(func):
@wraps(func)
def with_capture(*args, **kwargs):
Expand Down Expand Up @@ -238,12 +227,6 @@ def test_misc(self, client, resource_misc, catch_wsgiref_query_warning):
assert resource_misc.called
assert resource_misc.req.method == method

def test_methods_not_allowed_simple(self, client, stonewall):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave this stonewall test intact (until Falcon 5.0, that is), just assert with pytest.warns(...) that a deprecation warning was emitted by add_route below.

client.app.add_route('/stonewall', stonewall)
for method in ['GET', 'HEAD', 'PUT', 'PATCH']:
response = client.simulate_request(path='/stonewall', method=method)
assert response.status == falcon.HTTP_405

def test_methods_not_allowed_complex(
self, client, resource_things, catch_wsgiref_query_warning
):
Expand Down
12 changes: 10 additions & 2 deletions tests/test_uri_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import falcon
from falcon import testing
from falcon.routing.util import SuffixedMethodNotFoundError
from falcon.routing.util import MethodNotFoundError

_TEST_UUID = uuid.uuid4()
_TEST_UUID_2 = uuid.uuid4()
Expand Down Expand Up @@ -596,9 +596,17 @@ def test_with_and_without_trailing_slash(client, reverse):

def test_custom_error_on_suffix_route_not_found(client):
resource_with_suffix_routes = ResourceWithSuffixRoutes()
with pytest.raises(SuffixedMethodNotFoundError):
with pytest.raises(MethodNotFoundError):
client.app.add_route(
'/collections/{collection_id}/items',
resource_with_suffix_routes,
suffix='bad-alt',
)


def test_custom_error_route_not_found(client):
class EmptyResource:
pass

with pytest.raises(MethodNotFoundError):
client.app.add_route('/empty', EmptyResource())