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:
86
sanic/app.py
86
sanic/app.py
@@ -3,7 +3,13 @@ import logging.config
|
||||
import os
|
||||
import re
|
||||
|
||||
from asyncio import CancelledError, Protocol, ensure_future, get_event_loop
|
||||
from asyncio import (
|
||||
CancelledError,
|
||||
Protocol,
|
||||
ensure_future,
|
||||
get_event_loop,
|
||||
wait_for,
|
||||
)
|
||||
from asyncio.futures import Future
|
||||
from collections import defaultdict, deque
|
||||
from functools import partial
|
||||
@@ -13,7 +19,9 @@ from ssl import Purpose, SSLContext, create_default_context
|
||||
from traceback import format_exc
|
||||
from typing import (
|
||||
Any,
|
||||
Awaitable,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Deque,
|
||||
Dict,
|
||||
Iterable,
|
||||
@@ -26,6 +34,7 @@ from typing import (
|
||||
from urllib.parse import urlencode, urlunparse
|
||||
|
||||
from sanic_routing.exceptions import FinalizationError # type: ignore
|
||||
from sanic_routing.exceptions import NotFound # type: ignore
|
||||
from sanic_routing.route import Route # type: ignore
|
||||
|
||||
from sanic import reloader_helpers
|
||||
@@ -48,20 +57,17 @@ from sanic.models.futures import (
|
||||
FutureListener,
|
||||
FutureMiddleware,
|
||||
FutureRoute,
|
||||
FutureSignal,
|
||||
FutureStatic,
|
||||
)
|
||||
from sanic.models.handler_types import ListenerType, MiddlewareType
|
||||
from sanic.request import Request
|
||||
from sanic.response import BaseHTTPResponse, HTTPResponse
|
||||
from sanic.router import Router
|
||||
from sanic.server import (
|
||||
AsyncioServer,
|
||||
HttpProtocol,
|
||||
Signal,
|
||||
serve,
|
||||
serve_multiple,
|
||||
serve_single,
|
||||
)
|
||||
from sanic.server import AsyncioServer, HttpProtocol
|
||||
from sanic.server import Signal as ServerSignal
|
||||
from sanic.server import serve, serve_multiple, serve_single
|
||||
from sanic.signals import Signal, SignalRouter
|
||||
from sanic.websocket import ConnectionClosed, WebSocketProtocol
|
||||
|
||||
|
||||
@@ -76,10 +82,11 @@ class Sanic(BaseSanic):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = None,
|
||||
router: Router = None,
|
||||
error_handler: ErrorHandler = None,
|
||||
router: Optional[Router] = None,
|
||||
signal_router: Optional[SignalRouter] = None,
|
||||
error_handler: Optional[ErrorHandler] = None,
|
||||
load_env: bool = True,
|
||||
request_class: Type[Request] = None,
|
||||
request_class: Optional[Type[Request]] = None,
|
||||
strict_slashes: bool = False,
|
||||
log_config: Optional[Dict[str, Any]] = None,
|
||||
configure_logging: bool = True,
|
||||
@@ -100,6 +107,7 @@ class Sanic(BaseSanic):
|
||||
self.name = name
|
||||
self.asgi = False
|
||||
self.router = router or Router()
|
||||
self.signal_router = signal_router or SignalRouter()
|
||||
self.request_class = request_class
|
||||
self.error_handler = error_handler or ErrorHandler()
|
||||
self.config = Config(load_env=load_env)
|
||||
@@ -162,7 +170,7 @@ class Sanic(BaseSanic):
|
||||
also return a future, and the actual ensure_future call
|
||||
is delayed until before server start.
|
||||
|
||||
`See user guide
|
||||
`See user guide re: background tasks
|
||||
<https://sanicframework.org/guide/basics/tasks.html#background-tasks>`__
|
||||
|
||||
:param task: future, couroutine or awaitable
|
||||
@@ -309,6 +317,28 @@ class Sanic(BaseSanic):
|
||||
middleware.middleware, middleware.attach_to
|
||||
)
|
||||
|
||||
def _apply_signal(self, signal: FutureSignal) -> Signal:
|
||||
return self.signal_router.add(*signal)
|
||||
|
||||
def dispatch(
|
||||
self,
|
||||
event: str,
|
||||
*,
|
||||
condition: Optional[Dict[str, str]] = None,
|
||||
context: Optional[Dict[str, Any]] = None,
|
||||
) -> Coroutine[Any, Any, Awaitable[Any]]:
|
||||
return self.signal_router.dispatch(
|
||||
event,
|
||||
context=context,
|
||||
condition=condition,
|
||||
)
|
||||
|
||||
def event(self, event: str, timeout: Optional[Union[int, float]] = None):
|
||||
signal = self.signal_router.name_index.get(event)
|
||||
if not signal:
|
||||
raise NotFound("Could not find signal %s" % event)
|
||||
return wait_for(signal.ctx.event.wait(), timeout=timeout)
|
||||
|
||||
def enable_websocket(self, enable=True):
|
||||
"""Enable or disable the support for websocket.
|
||||
|
||||
@@ -382,7 +412,7 @@ class Sanic(BaseSanic):
|
||||
|
||||
app.config.SERVER_NAME = "myserver:7777"
|
||||
|
||||
`See user guide
|
||||
`See user guide re: routing
|
||||
<https://sanicframework.org/guide/basics/routing.html#generating-a-url>`__
|
||||
|
||||
:param view_name: string referencing the view name
|
||||
@@ -1031,11 +1061,9 @@ class Sanic(BaseSanic):
|
||||
):
|
||||
"""Helper function used by `run` and `create_server`."""
|
||||
|
||||
try:
|
||||
self.router.finalize()
|
||||
except FinalizationError as e:
|
||||
if not Sanic.test_mode:
|
||||
raise e
|
||||
self.listeners["before_server_start"] = [
|
||||
self.finalize
|
||||
] + self.listeners["before_server_start"]
|
||||
|
||||
if isinstance(ssl, dict):
|
||||
# try common aliaseses
|
||||
@@ -1064,7 +1092,7 @@ class Sanic(BaseSanic):
|
||||
"unix": unix,
|
||||
"ssl": ssl,
|
||||
"app": self,
|
||||
"signal": Signal(),
|
||||
"signal": ServerSignal(),
|
||||
"loop": loop,
|
||||
"register_sys_signals": register_sys_signals,
|
||||
"backlog": backlog,
|
||||
@@ -1159,7 +1187,7 @@ class Sanic(BaseSanic):
|
||||
"""
|
||||
Update app.config. Full implementation can be found in the user guide.
|
||||
|
||||
`See user guide
|
||||
`See user guide re: configuration
|
||||
<https://sanicframework.org/guide/deployment/configuration.html#basics>`__
|
||||
"""
|
||||
|
||||
@@ -1196,7 +1224,7 @@ class Sanic(BaseSanic):
|
||||
'Multiple Sanic apps found, use Sanic.get_app("app_name")'
|
||||
)
|
||||
elif len(cls._app_registry) == 0:
|
||||
raise SanicException(f"No Sanic apps have been registered.")
|
||||
raise SanicException("No Sanic apps have been registered.")
|
||||
else:
|
||||
return list(cls._app_registry.values())[0]
|
||||
try:
|
||||
@@ -1205,3 +1233,17 @@ class Sanic(BaseSanic):
|
||||
if force_create:
|
||||
return cls(name)
|
||||
raise SanicException(f'Sanic app name "{name}" not found.')
|
||||
|
||||
# -------------------------------------------------------------------- #
|
||||
# Static methods
|
||||
# -------------------------------------------------------------------- #
|
||||
|
||||
@staticmethod
|
||||
async def finalize(app, _):
|
||||
try:
|
||||
app.router.finalize()
|
||||
if app.signal_router.routes:
|
||||
app.signal_router.finalize() # noqa
|
||||
except FinalizationError as e:
|
||||
if not Sanic.test_mode:
|
||||
raise e # noqa
|
||||
|
||||
Reference in New Issue
Block a user