Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions robyn/router.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -72,6 +75,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 _PATH_PARAM_ACCESS_TYPES:
return True

return bool((_REQUEST_PARAM_NAMES | _PATH_PARAMS_PARAM_NAMES) & set(handler_params))

def _format_tuple_response(self, res: tuple) -> Response:
if len(res) != 3:
raise ValueError("Tuple should have 3 elements")
Expand Down Expand Up @@ -151,7 +161,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",
Expand Down
102 changes: 102 additions & 0 deletions unit_tests/test_router_path_param_warnings.py
Original file line number Diff line number Diff line change
@@ -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]