RFC/1630 Signals (#2042)
* Temp working version of initial signal api * fix signals router finalizing * Additional tests * Add event test * finalize test * remove old comment * Add some missing annotations * multiple apps per BP support * deepsource? * rtemove deepsource * nominal change * fix blueprints test * trivial change to trigger build * signal docstring * squash * squash * Add a couple new tests * Add some suggestions from review * Remove inaccessible code * Change where to condition
This commit is contained in:
@@ -43,8 +43,8 @@ class ListenerMixin:
|
||||
async def before_server_start(app, loop):
|
||||
...
|
||||
|
||||
`See user guide
|
||||
<https://sanicframework.org/guide/basics/listeners.html#listeners>`_
|
||||
`See user guide re: listeners
|
||||
<https://sanicframework.org/guide/basics/listeners.html#listeners>`__
|
||||
|
||||
:param event: event to listen to
|
||||
"""
|
||||
|
||||
@@ -19,8 +19,8 @@ class MiddlewareMixin:
|
||||
Can either be called as *@app.middleware* or
|
||||
*@app.middleware('request')*
|
||||
|
||||
`See user guide
|
||||
<https://sanicframework.org/guide/basics/middleware.html>`_
|
||||
`See user guide re: middleware
|
||||
<https://sanicframework.org/guide/basics/middleware.html>`__
|
||||
|
||||
:param: middleware_or_request: Optional parameter to use for
|
||||
identifying which type of middleware is being registered.
|
||||
|
||||
@@ -32,7 +32,7 @@ class RouteMixin:
|
||||
self.name = ""
|
||||
self.strict_slashes: Optional[bool] = False
|
||||
|
||||
def _apply_route(self, route: FutureRoute) -> Route:
|
||||
def _apply_route(self, route: FutureRoute) -> List[Route]:
|
||||
raise NotImplementedError # noqa
|
||||
|
||||
def _apply_static(self, static: FutureStatic) -> Route:
|
||||
|
||||
62
sanic/mixins/signals.py
Normal file
62
sanic/mixins/signals.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from typing import Any, Callable, Dict, Set
|
||||
|
||||
from sanic.models.futures import FutureSignal
|
||||
from sanic.models.handler_types import SignalHandler
|
||||
from sanic.signals import Signal
|
||||
|
||||
|
||||
class HashableDict(dict):
|
||||
def __hash__(self):
|
||||
return hash(tuple(sorted(self.items())))
|
||||
|
||||
|
||||
class SignalMixin:
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self._future_signals: Set[FutureSignal] = set()
|
||||
|
||||
def _apply_signal(self, signal: FutureSignal) -> Signal:
|
||||
raise NotImplementedError # noqa
|
||||
|
||||
def signal(
|
||||
self,
|
||||
event: str,
|
||||
*,
|
||||
apply: bool = True,
|
||||
condition: Dict[str, Any] = None,
|
||||
) -> Callable[[SignalHandler], FutureSignal]:
|
||||
"""
|
||||
For creating a signal handler, used similar to a route handler:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.signal("foo.bar.<thing>")
|
||||
async def signal_handler(thing, **kwargs):
|
||||
print(f"[signal_handler] {thing=}", kwargs)
|
||||
|
||||
:param event: Representation of the event in ``one.two.three`` form
|
||||
:type event: str
|
||||
:param apply: For lazy evaluation, defaults to True
|
||||
:type apply: bool, optional
|
||||
:param condition: For use with the ``condition`` argument in dispatch
|
||||
filtering, defaults to None
|
||||
:type condition: Dict[str, Any], optional
|
||||
"""
|
||||
|
||||
def decorator(handler: SignalHandler):
|
||||
nonlocal event
|
||||
nonlocal apply
|
||||
|
||||
future_signal = FutureSignal(
|
||||
handler, event, HashableDict(condition or {})
|
||||
)
|
||||
self._future_signals.add(future_signal)
|
||||
|
||||
if apply:
|
||||
self._apply_signal(future_signal)
|
||||
|
||||
return future_signal
|
||||
|
||||
return decorator
|
||||
|
||||
def event(self, event: str):
|
||||
raise NotImplementedError
|
||||
Reference in New Issue
Block a user