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

Apply right name to Route when created from methods #1553

Merged
merged 13 commits into from Apr 8, 2022
2 changes: 1 addition & 1 deletion starlette/routing.py
Expand Up @@ -84,7 +84,7 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:


def get_name(endpoint: typing.Callable) -> str:
if inspect.isfunction(endpoint) or inspect.isclass(endpoint):
if inspect.isroutine(endpoint) or inspect.isclass(endpoint):
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

Does the behavior of lambda changes now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No:

import inspect
my_lambda = lambda: 1
assert inspect.isfunction(my_lambda) == inspect.isroutine(my_lambda)

return endpoint.__name__
return endpoint.__class__.__name__

Expand Down
62 changes: 61 additions & 1 deletion tests/test_routing.py
@@ -1,11 +1,20 @@
import functools
import uuid
import typing
Kludex marked this conversation as resolved.
Show resolved Hide resolved

import pytest

from starlette.applications import Starlette
from starlette.responses import JSONResponse, PlainTextResponse, Response
from starlette.routing import Host, Mount, NoMatchFound, Route, Router, WebSocketRoute
from starlette.routing import (
get_name,
flxdot marked this conversation as resolved.
Show resolved Hide resolved
Host,
Mount,
NoMatchFound,
Route,
Router,
WebSocketRoute,
)
from starlette.websockets import WebSocket, WebSocketDisconnect


Expand Down Expand Up @@ -710,3 +719,54 @@ def test_duplicated_param_names():
match="Duplicated param names id, name at path /{id}/{name}/{id}/{name}",
):
Route("/{id}/{name}/{id}/{name}", user)


class EndpointCollectionObject:
async def my_method(self, request):
return JSONResponse({"endpoint_type": "method"})

@classmethod
async def my_classmethod(self, request):
return JSONResponse({"endpoint_type": "classmethod"})

@staticmethod
async def my_staticmethod(self, request):
Kludex marked this conversation as resolved.
Show resolved Hide resolved
return JSONResponse({"endpoint_type": "staticmethod"})


class EndpointObject:
def __call__(self, request):
return JSONResponse({"endpoint_type": "class"})
flxdot marked this conversation as resolved.
Show resolved Hide resolved


@pytest.mark.parametrize(
"endpoint, expected_name",
[
pytest.param(func_homepage, "func_homepage", id="function"),
pytest.param(EndpointCollectionObject().my_method, "my_method", id="method"),
pytest.param(
EndpointCollectionObject.my_classmethod, "my_classmethod", id="classmethod"
),
pytest.param(
EndpointCollectionObject.my_staticmethod,
"my_staticmethod",
id="staticmethod",
),
pytest.param(EndpointObject, "EndpointObject", id="object"),
pytest.param(
lambda request: JSONResponse({"endpoint_type": "lambda"}),
"<lambda>",
id="lambda",
),
flxdot marked this conversation as resolved.
Show resolved Hide resolved
],
)
def test_route_name_automatic(endpoint: typing.Callable, expected_name: str):
flxdot marked this conversation as resolved.
Show resolved Hide resolved

Kludex marked this conversation as resolved.
Show resolved Hide resolved
# Path does not matter here, as we only care about how the route name is created.
flxdot marked this conversation as resolved.
Show resolved Hide resolved
assert Route(path="/", endpoint=endpoint).name == expected_name


def test_route_name_manual():

name = "my_custom_endpoint"
assert Route(path="/", endpoint=func_homepage, name=name).name == name
flxdot marked this conversation as resolved.
Show resolved Hide resolved