Skip to content

Commit

Permalink
✨ Allow to tag routes (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
perdy committed Mar 17, 2023
1 parent 693fdf7 commit cbd026f
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 52 deletions.
30 changes: 24 additions & 6 deletions flama/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def add_route(
name: t.Optional[str] = None,
include_in_schema: bool = True,
route: t.Optional["Route"] = None,
**tags: t.Any,
) -> "Route":
"""Register a new HTTP route or endpoint under given path.
Expand All @@ -168,9 +169,17 @@ def add_route(
:param name: Endpoint or route name.
:param include_in_schema: True if this route or endpoint should be declared as part of the API schema.
:param route: HTTP route.
:param tags: Tags to add to the route.
"""
return self.router.add_route(
path, endpoint, methods=methods, name=name, include_in_schema=include_in_schema, route=route, root=self
path,
endpoint,
methods=methods,
name=name,
include_in_schema=include_in_schema,
route=route,
root=self,
**tags,
)

def route(
Expand All @@ -179,60 +188,69 @@ def route(
methods: t.Optional[t.List[str]] = None,
name: t.Optional[str] = None,
include_in_schema: bool = True,
**tags: t.Any,
) -> t.Callable[[types.HTTPHandler], types.HTTPHandler]:
"""Decorator version for registering a new HTTP route in this router under given path.
:param path: URL path.
:param methods: List of valid HTTP methods (only applies for routes).
:param name: Endpoint or route name.
:param include_in_schema: True if this route or endpoint should be declared as part of the API schema.
:param tags: Tags to add to the route.
:return: Decorated route.
"""
return self.router.route(path, methods=methods, name=name, include_in_schema=include_in_schema, root=self)
return self.router.route(
path, methods=methods, name=name, include_in_schema=include_in_schema, root=self, **tags
)

def add_websocket_route(
self,
path: t.Optional[str] = None,
endpoint: t.Optional[types.WebSocketHandler] = None,
name: t.Optional[str] = None,
route: t.Optional["WebSocketRoute"] = None,
**tags: t.Any,
) -> "WebSocketRoute":
"""Register a new websocket route or endpoint under given path.
:param path: URL path.
:param endpoint: Websocket endpoint.
:param name: Endpoint or route name.
:param route: Websocket route.
:param tags: Tags to add to the websocket route.
"""
return self.router.add_websocket_route(path, endpoint, name=name, route=route, root=self)
return self.router.add_websocket_route(path, endpoint, name=name, route=route, root=self, **tags)

def websocket_route(
self, path: str, name: t.Optional[str] = None
self, path: str, name: t.Optional[str] = None, **tags: t.Any
) -> t.Callable[[types.WebSocketHandler], types.WebSocketHandler]:
"""Decorator version for registering a new websocket route in this router under given path.
:param path: URL path.
:param name: Websocket route name.
:param tags: Tags to add to the websocket route.
:return: Decorated route.
"""
return self.router.websocket_route(path, name=name, root=self)
return self.router.websocket_route(path, name=name, root=self, **tags)

def mount(
self,
path: t.Optional[str] = None,
app: t.Optional[types.App] = None,
name: t.Optional[str] = None,
mount: t.Optional["Mount"] = None,
**tags: t.Any,
) -> "Mount":
"""Register a new mount point containing an ASGI app in this router under given path.
:param path: URL path.
:param app: ASGI app to mount.
:param name: Application name.
:param mount: Mount.
:param tags: Tags to add to the mount.
:return: Mount.
"""
return self.router.mount(path, app, name=name, mount=mount, root=self)
return self.router.mount(path, app, name=name, mount=mount, root=self, **tags)

@property
def injector(self) -> injection.Injector:
Expand Down
47 changes: 39 additions & 8 deletions flama/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,22 @@ def __init__(
*,
name: t.Optional[str] = None,
include_in_schema: bool = True,
**tags: t.Any,
):
"""A route definition of a http endpoint.
:param path: URL path.
:param app: ASGI application.
:param name: Route name.
:param include_in_schema: True if this route must be listed as part of the App schema.
:param tags: Route tags.
"""
self.path = url.RegexPath(path)
self.app = app
self.endpoint = app.handler if isinstance(app, EndpointWrapper) else app
self.name = name
self.include_in_schema = include_in_schema
self.tags = tags
super().__init__()

async def __call__(self, scope: types.Scope, receive: types.Receive, send: types.Send) -> None:
Expand Down Expand Up @@ -288,6 +291,7 @@ def __init__(
methods: t.Optional[t.Union[t.Set[str], t.Sequence[str]]] = None,
name: t.Optional[str] = None,
include_in_schema: bool = True,
**tags: t.Any,
) -> None:
"""A route definition of a http endpoint.
Expand All @@ -296,6 +300,7 @@ def __init__(
:param methods: List of valid HTTP methods.
:param name: Route name.
:param include_in_schema: True if this route must be listed as part of the App schema.
:param tags: Route tags.
"""
assert self.is_endpoint(endpoint) or (
not inspect.isclass(endpoint) and callable(endpoint)
Expand All @@ -312,7 +317,11 @@ def __init__(
name = endpoint.__name__ if name is None else name

super().__init__(
path, EndpointWrapper(endpoint, EndpointWrapper.type.http), name=name, include_in_schema=include_in_schema
path,
EndpointWrapper(endpoint, EndpointWrapper.type.http),
name=name,
include_in_schema=include_in_schema,
**tags,
)

self.app: EndpointWrapper
Expand Down Expand Up @@ -369,13 +378,15 @@ def __init__(
*,
name: t.Optional[str] = None,
include_in_schema: bool = True,
**tags: t.Any,
):
"""A route definition of a websocket endpoint.
:param path: URL path.
:param endpoint: Websocket endpoint or function.
:param name: Route name.
:param include_in_schema: True if this route must be listed as part of the App schema.
:param tags: Route tags.
"""

assert self.is_endpoint(endpoint) or (
Expand All @@ -389,6 +400,7 @@ def __init__(
EndpointWrapper(endpoint, EndpointWrapper.type.websocket),
name=name,
include_in_schema=include_in_schema,
**tags,
)

self.app: EndpointWrapper
Expand Down Expand Up @@ -435,6 +447,7 @@ def __init__(
routes: t.Optional[t.Sequence[BaseRoute]] = None,
components: t.Optional[t.Sequence[Component]] = None,
name: t.Optional[str] = None,
**tags: t.Any,
):
"""A mount point for adding a nested ASGI application or a list of routes.
Expand All @@ -443,13 +456,14 @@ def __init__(
:param routes: List of routes.
:param components: Components registered under this mount point.
:param name: Mount name.
:param tags: Mount tags.
"""
assert app is not None or routes is not None, "Either 'app' or 'routes' must be specified"

if app is None:
app = Router(routes=routes, components=components)

super().__init__(url.RegexPath(path.rstrip("/") + "{path:path}"), app, name=name)
super().__init__(url.RegexPath(path.rstrip("/") + "{path:path}"), app, name=name, **tags)

def __eq__(self, other: t.Any) -> bool:
return super().__eq__(other) and isinstance(other, Mount)
Expand Down Expand Up @@ -618,6 +632,7 @@ def add_route(
include_in_schema: bool = True,
route: t.Optional[Route] = None,
root: t.Optional["Flama"] = None,
**tags: t.Any,
) -> Route:
"""Register a new HTTP route in this router under given path.
Expand All @@ -628,10 +643,13 @@ def add_route(
:param include_in_schema: True if this route or endpoint should be declared as part of the API schema.
:param route: HTTP route.
:param root: Flama application.
:param tags: Tags to add to the route or endpoint.
:return: Route.
"""
if path is not None and endpoint is not None:
route = Route(path, endpoint=endpoint, methods=methods, name=name, include_in_schema=include_in_schema)
route = Route(
path, endpoint=endpoint, methods=methods, name=name, include_in_schema=include_in_schema, **tags
)

assert route is not None, "Either 'path' and 'endpoint' or 'route' variables are needed"

Expand All @@ -648,6 +666,7 @@ def route(
name: t.Optional[str] = None,
include_in_schema: bool = True,
root: t.Optional["Flama"] = None,
**tags: t.Any,
) -> t.Callable[[types.HTTPHandler], types.HTTPHandler]:
"""Decorator version for registering a new HTTP route in this router under given path.
Expand All @@ -656,11 +675,14 @@ def route(
:param name: Endpoint or route name.
:param include_in_schema: True if this route or endpoint should be declared as part of the API schema.
:param root: Flama application.
:param tags: Tags to add to the endpoint.
:return: Decorated route.
"""

def decorator(func: types.HTTPHandler) -> types.HTTPHandler:
self.add_route(path, func, methods=methods, name=name, include_in_schema=include_in_schema, root=root)
self.add_route(
path, func, methods=methods, name=name, include_in_schema=include_in_schema, root=root, **tags
)
return func

return decorator
Expand All @@ -672,6 +694,7 @@ def add_websocket_route(
name: t.Optional[str] = None,
route: t.Optional[WebSocketRoute] = None,
root: t.Optional["Flama"] = None,
**tags: t.Any,
) -> WebSocketRoute:
"""Register a new websocket route in this router under given path.
Expand All @@ -680,10 +703,11 @@ def add_websocket_route(
:param name: Websocket route name.
:param route: Specific route class.
:param root: Flama application.
:param tags: Tags to add to the websocket route.
:return: Websocket route.
"""
if path is not None and endpoint is not None:
route = WebSocketRoute(path, endpoint=endpoint, name=name)
route = WebSocketRoute(path, endpoint=endpoint, name=name, **tags)

assert route is not None, "Either 'path' and 'endpoint' or 'route' variables are needed"

Expand All @@ -694,18 +718,23 @@ def add_websocket_route(
return route

def websocket_route(
self, path: str, name: t.Optional[str] = None, root: t.Optional["Flama"] = None
self,
path: str,
name: t.Optional[str] = None,
root: t.Optional["Flama"] = None,
**tags: t.Any,
) -> t.Callable[[types.WebSocketHandler], types.WebSocketHandler]:
"""Decorator version for registering a new websocket route in this router under given path.
:param path: URL path.
:param name: Websocket route name.
:param root: Flama application.
:param tags: Tags to add to the websocket route.
:return: Decorated websocket route.
"""

def decorator(func: types.WebSocketHandler) -> types.WebSocketHandler:
self.add_websocket_route(path, func, name=name, root=root)
self.add_websocket_route(path, func, name=name, root=root, **tags)
return func

return decorator
Expand All @@ -717,6 +746,7 @@ def mount(
name: t.Optional[str] = None,
mount: t.Optional[Mount] = None,
root: t.Optional["Flama"] = None,
**tags: t.Any,
) -> Mount:
"""Register a new mount point containing an ASGI app in this router under given path.
Expand All @@ -725,10 +755,11 @@ def mount(
:param name: Route name.
:param mount: Mount.
:param root: Flama application.
:param tags: Tags to add to the mount.
:return: Mount.
"""
if path is not None and app is not None:
mount = Mount(path, app=app, name=name)
mount = Mount(path, app=app, name=name, **tags)

assert mount is not None, "Either 'path' and 'app' or 'mount' variables are needed"

Expand Down
Loading

0 comments on commit cbd026f

Please sign in to comment.