From a200971337d4f4be949832c219d640599bd4bd8d Mon Sep 17 00:00:00 2001 From: Ahmad M Date: Thu, 28 May 2026 17:18:54 -0700 Subject: [PATCH 1/2] fix path param warning for request handlers --- robyn/router.py | 11 +- unit_tests/test_router_path_param_warnings.py | 102 ++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 unit_tests/test_router_path_param_warnings.py diff --git a/robyn/router.py b/robyn/router.py index b666792c8..d368d0c18 100644 --- a/robyn/router.py +++ b/robyn/router.py @@ -1,7 +1,7 @@ import inspect import logging from abc import ABC, abstractmethod -from collections.abc import Callable +from collections.abc import Callable, Mapping from functools import wraps from types import CoroutineType from typing import NamedTuple, is_typeddict @@ -72,6 +72,13 @@ def __init__(self) -> None: super().__init__() self.routes: list[Route] = [] + def _handler_can_access_path_params(self, handler_params: Mapping[str, inspect.Parameter]) -> bool: + for param in handler_params.values(): + if param.annotation in (Request, PathParams): + return True + + return bool({"r", "req", "request", "path_params"} & set(handler_params)) + def _format_tuple_response(self, res: tuple) -> Response: if len(res) != 3: raise ValueError("Tuple should have 3 elements") @@ -151,7 +158,7 @@ def add_route( # type: ignore handler_params = inspect.signature(handler).parameters handler_param_names = set(handler_params.keys()) - unused_route_params = route_param_names - handler_param_names + unused_route_params = set() if self._handler_can_access_path_params(handler_params) else route_param_names - handler_param_names if unused_route_params: _logger.warning( "Route '%s' declares path params %s but handler '%s' doesn't use them", diff --git a/unit_tests/test_router_path_param_warnings.py b/unit_tests/test_router_path_param_warnings.py new file mode 100644 index 000000000..e553d049f --- /dev/null +++ b/unit_tests/test_router_path_param_warnings.py @@ -0,0 +1,102 @@ +import logging + +import pytest + +from robyn.robyn import HttpMethod, Request +from robyn.router import Router +from robyn.types import PathParams + + +def add_get_route(router, endpoint, handler): + router.add_route( + route_type=HttpMethod.GET, + endpoint=endpoint, + handler=handler, + is_const=False, + auth_required=False, + openapi_name="", + openapi_tags=[], + exception_handler=None, + injected_dependencies={"router_dependencies": {}, "global_dependencies": {}}, + ) + + +def path_param_warning_messages(caplog): + return [record.getMessage() for record in caplog.records if record.name == "robyn.router" and "declares path params" in record.getMessage()] + + +def handler_with_request_name(request): + return request + + +def handler_with_req_name(req): + return req + + +def handler_with_r_name(r): + return r + + +def handler_with_path_params_name(path_params): + return path_params + + +def handler_with_path_param_name(key_id): + return key_id + + +def handler_with_typed_request(request_data: Request): + return request_data + + +def handler_with_typed_path_params(path_data: PathParams): + return path_data + + +def handler_with_typed_request_and_named_param(request_data: Request, user_id): + return request_data, user_id + + +@pytest.mark.parametrize( + "handler", + [ + handler_with_request_name, + handler_with_req_name, + handler_with_r_name, + handler_with_path_params_name, + handler_with_path_param_name, + handler_with_typed_request, + handler_with_typed_path_params, + ], +) +def test_path_param_warning_skipped_for_request_or_path_params_access(caplog, handler): + caplog.set_level(logging.WARNING, logger="robyn.router") + + add_get_route(Router(), "/v1/keys/:key_id", handler) + + assert path_param_warning_messages(caplog) == [] + + +def test_path_param_warning_skipped_when_request_can_access_remaining_params(caplog): + caplog.set_level(logging.WARNING, logger="robyn.router") + + add_get_route(Router(), "/users/:user_id/posts/:post_id", handler_with_typed_request_and_named_param) + + assert path_param_warning_messages(caplog) == [] + + +def test_path_param_warning_logged_when_param_is_not_accessible(caplog): + def handler(): + return "ok" + + caplog.set_level(logging.WARNING, logger="robyn.router") + + add_get_route(Router(), "/users/:user_id/posts/:post_id", handler) + + warning_messages = path_param_warning_messages(caplog) + + assert len(warning_messages) == 1 + assert "Route '/users/:user_id/posts/:post_id' declares path params" in warning_messages[0] + assert "user_id" in warning_messages[0] + assert "post_id" in warning_messages[0] + assert "handler 'handler' doesn't use them" in warning_messages[0] From b09adbfb636264ae5d58c352f0e40da9ee656adb Mon Sep 17 00:00:00 2001 From: Ahmad M Date: Thu, 28 May 2026 18:00:04 -0700 Subject: [PATCH 2/2] clarify path param access names --- robyn/router.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/robyn/router.py b/robyn/router.py index d368d0c18..f363df7a4 100644 --- a/robyn/router.py +++ b/robyn/router.py @@ -34,6 +34,9 @@ # never receive the Response and can't mutate it either. _JSON_HEADERS = Headers({"Content-Type": "application/json"}) _TEXT_HEADERS = Headers({"Content-Type": "text/plain"}) +_REQUEST_PARAM_NAMES = {"r", "req", "request"} +_PATH_PARAMS_PARAM_NAMES = {"path_params"} +_PATH_PARAM_ACCESS_TYPES = (Request, PathParams) def lower_http_method(method: HttpMethod): @@ -74,10 +77,10 @@ def __init__(self) -> None: def _handler_can_access_path_params(self, handler_params: Mapping[str, inspect.Parameter]) -> bool: for param in handler_params.values(): - if param.annotation in (Request, PathParams): + if param.annotation in _PATH_PARAM_ACCESS_TYPES: return True - return bool({"r", "req", "request", "path_params"} & set(handler_params)) + return bool((_REQUEST_PARAM_NAMES | _PATH_PARAMS_PARAM_NAMES) & set(handler_params)) def _format_tuple_response(self, res: tuple) -> Response: if len(res) != 3: