Skip to content

Commit

Permalink
Code cleaning
Browse files Browse the repository at this point in the history
  • Loading branch information
tarsil committed Feb 8, 2025
1 parent 7e26446 commit a44842c
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 27 deletions.
10 changes: 5 additions & 5 deletions esmerald/permissions/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from functools import lru_cache
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast

from lilya.permissions.base import DefinePermission

Expand Down Expand Up @@ -45,7 +44,6 @@ def permission_denied(request: "Request", message: Optional[str] = None) -> None
raise PermissionDenied(detail=message, status_code=403)


@lru_cache
def is_esmerald_permission(permission: Union["BasePermission", Any]) -> bool:
"""
Checks if the given permission is an instance or subclass of BasePermission.
Expand All @@ -61,7 +59,9 @@ def is_esmerald_permission(permission: Union["BasePermission", Any]) -> bool:
return is_class_and_subclass(permission, BasePermission)


def wrap_permission(permission: Union["BasePermission", Any]) -> "BasePermission":
def wrap_permission(
permission: Union["BasePermission", Any],
) -> "BasePermission":
"""
Wraps the given permission into a BasePermission instance if it is not already one.
Or else it will assume its a Lilya permission and wraps it.
Expand All @@ -75,4 +75,4 @@ def wrap_permission(permission: Union["BasePermission", Any]) -> "BasePermission
if is_esmerald_permission(permission):
return permission

return DefinePermission(permission)
return cast("BasePermission", DefinePermission(cast(Any, permission)))
8 changes: 4 additions & 4 deletions esmerald/routing/gateways.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def __init__(
handler=handler, base_middleware=self.middleware
)

lilya_permissions = [
self.__lilya_permissions__ = [
wrap_permission(permission)
for permission in permissions or []
if not is_esmerald_permission(permission)
Expand All @@ -313,7 +313,7 @@ def __init__(
methods=self.methods,
middleware=self._middleware,
exception_handlers=exception_handlers,
permissions=lilya_permissions,
permissions=self.__lilya_permissions__, # type: ignore
)
"""
A "bridge" to a handler and router mapping functionality.
Expand Down Expand Up @@ -533,7 +533,7 @@ def __init__(
)
self.is_middleware: bool = False

lilya_permissions = [
self.__lilya_permissions__ = [
wrap_permission(permission)
for permission in permissions or []
if not is_esmerald_permission(permission)
Expand All @@ -544,7 +544,7 @@ def __init__(
name=name,
middleware=self._middleware,
exception_handlers=exception_handlers,
permissions=lilya_permissions,
permissions=self.__lilya_permissions__, # type: ignore
)
"""
A "bridge" to a handler and router mapping functionality.
Expand Down
31 changes: 15 additions & 16 deletions esmerald/routing/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ async def another(request: Request) -> str:
on_startup is None and on_shutdown is None
), "Use either 'lifespan' or 'on_startup'/'on_shutdown', not both."

lilya_permissions = [
self.__lilya_permissions__ = [
wrap_permission(permission)
for permission in permissions or []
if not is_esmerald_permission(permission)
Expand All @@ -529,7 +529,7 @@ async def another(request: Request) -> str:
lifespan=lifespan,
on_shutdown=on_shutdown,
on_startup=on_startup,
permissions=lilya_permissions,
permissions=self.__lilya_permissions__, # type: ignore
)
self.path = path
self.on_startup = [] if on_startup is None else list(on_startup)
Expand Down Expand Up @@ -1931,7 +1931,7 @@ def wrapper(func: Callable) -> Callable:
_body_less_methods = frozenset({"GET", "HEAD", "OPTIONS", "TRACE"})


class HTTPHandler(Dispatcher, OpenAPIFieldInfoMixin, LilyaPath):
class HTTPHandler(LilyaPath, Dispatcher, OpenAPIFieldInfoMixin):
__slots__ = (
"path",
"_interceptors",
Expand Down Expand Up @@ -1999,7 +1999,7 @@ def __init__(
if not path:
path = "/"

lilya_permissions = [
self.__lilya_permissions__ = [
wrap_permission(permission)
for permission in permissions or []
if not is_esmerald_permission(permission)
Expand All @@ -2011,7 +2011,7 @@ def __init__(
include_in_schema=include_in_schema,
exception_handlers=exception_handlers,
name=name,
permissions=lilya_permissions,
permissions=self.__lilya_permissions__, # type: ignore
)

self._permissions: Union[List[Permission], VoidType] = Void
Expand Down Expand Up @@ -2054,8 +2054,10 @@ def __init__(

self.description = description
self.permissions = [
permission for permission in permissions or [] if is_esmerald_permission(permission)
] # type: ignore
cast(Any, permission)
for permission in permissions or []
if is_esmerald_permission(permission)
]
self.interceptors: Sequence[Interceptor] = []
self.middleware = list(middleware) if middleware else []
self.description = self.description.split("\f")[0]
Expand All @@ -2081,9 +2083,6 @@ def __init__(
if self.responses:
self.validate_responses(responses=self.responses)

async def __call__(self, scope: Scope, receive: Receive, send: Send) -> Any:
await self.handle_dispatch(scope=scope, receive=receive, send=send)

def validate_responses(self, responses: Dict[int, OpenAPIResponse]) -> None:
"""
Checks if the responses are valid or raises an exception otherwise.
Expand Down Expand Up @@ -2298,7 +2297,7 @@ async def to_response(self, app: "Esmerald", data: Any) -> LilyaResponse:
return await response_handler(app=app, data=data) # type: ignore[call-arg]


class WebhookHandler(HTTPHandler, OpenAPIFieldInfoMixin, LilyaPath):
class WebhookHandler(HTTPHandler, OpenAPIFieldInfoMixin):
"""
Base for a webhook handler.
"""
Expand Down Expand Up @@ -2392,7 +2391,7 @@ def __init__(
self.path = path


class WebSocketHandler(Dispatcher, LilyaWebSocketPath):
class WebSocketHandler(LilyaWebSocketPath, Dispatcher):
"""
Websocket handler object representation.
"""
Expand Down Expand Up @@ -2429,7 +2428,7 @@ def __init__(
if not path:
path = "/"

lilya_permissions = [
self.__lilya_permissions__ = [
wrap_permission(permission)
for permission in permissions or []
if not is_esmerald_permission(permission)
Expand All @@ -2438,7 +2437,7 @@ def __init__(
path=path,
handler=handler,
exception_handlers=exception_handlers,
permissions=lilya_permissions,
permissions=self.__lilya_permissions__, # type: ignore
)
self._permissions: Union[List[Permission], VoidType] = Void
self._dependencies: Dependencies = {}
Expand Down Expand Up @@ -2925,7 +2924,7 @@ async def another(request: Request) -> str:
if routes:
routes = self.resolve_route_path_handler(routes)

lilya_permissions = [
self.__lilya_permissions__ = [
wrap_permission(permission)
for permission in permissions or []
if not is_esmerald_permission(permission)
Expand All @@ -2940,7 +2939,7 @@ async def another(request: Request) -> str:
deprecated=deprecated,
include_in_schema=include_in_schema,
redirect_slashes=redirect_slashes,
permissions=lilya_permissions,
permissions=self.__lilya_permissions__, # type: ignore
)

# Making sure Esmerald uses the Esmerald permission system and not Lilya's.
Expand Down
2 changes: 1 addition & 1 deletion esmerald/testclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def __call__(self, test_func: Any) -> Any:
"""

@wraps(test_func)
def inner(*args: P.args, **kwargs: P.kwargs) -> Any:
def inner(*args: Any, **kwargs: Any) -> Any:
with self:
return test_func(*args, **kwargs)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ testing = [
"flask>=1.1.2,<4.0.0",
"freezegun>=1.2.2,<2.0.0",
"mongoz>=0.6.0",
"mypy==1.14.1",
"mypy==1.15.0",
"pytest>=7.1.3,<9.0.0",
"pytest-cov>=4.1.0,<7.0.0",
"pytest-asyncio>=0.20.0",
Expand Down
33 changes: 33 additions & 0 deletions tests/permissions/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import pytest
from lilya.protocols.permissions import PermissionProtocol
from lilya.status import HTTP_200_OK, HTTP_403_FORBIDDEN
from lilya.types import Receive, Scope, Send
from lilya.websockets import WebSocketDisconnect

from esmerald.applications import ChildEsmerald
from esmerald.exceptions import NotAuthorized
from esmerald.permissions import AllowAny, BasePermission, DenyAll
from esmerald.permissions.utils import is_esmerald_permission
from esmerald.requests import Request
Expand Down Expand Up @@ -181,3 +183,34 @@ class DummyTrue(BasePermission): ...
)
def test_is_esmerald_permission(permission, result) -> None:
assert is_esmerald_permission(permission) == result


# Testing for lilya permissions
class LilyaDeny(PermissionProtocol):
def __init__(self, app, *args, **kwargs):
super().__init__(app, *args, **kwargs)
self.app = app

async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
raise NotAuthorized()


def xtest_permissions_with_lilya_http_handler_one() -> None:
@get(path="/secret", permissions=[LilyaDeny])
def my_http_route_handler() -> None: ...

with create_client(
routes=[Gateway(handler=my_http_route_handler)],
) as client:
response = client.get("/secret")
assert response.status_code == HTTP_403_FORBIDDEN
assert (
response.json().get("detail") == "You do not have permission to perform this action."
)
response = client.get("/secret", headers={"Authorization": "yes"})
assert response.status_code == HTTP_403_FORBIDDEN
assert (
response.json().get("detail") == "You do not have permission to perform this action."
)
response = client.get("/secret", headers={"Authorization": "yes", "allow_all": "true"})
assert response.status_code == HTTP_200_OK

0 comments on commit a44842c

Please sign in to comment.