Merge branch 'main' of github.com:sanic-org/sanic into feat/optional-uvloop-use

This commit is contained in:
prryplatypus 2021-10-24 21:09:52 +02:00
commit 348c358d72
No known key found for this signature in database
GPG Key ID: 6687E128FB70819B
6 changed files with 104 additions and 22 deletions

View File

@ -68,6 +68,7 @@ from sanic.models.futures import (
FutureStatic, FutureStatic,
) )
from sanic.models.handler_types import ListenerType, MiddlewareType from sanic.models.handler_types import ListenerType, MiddlewareType
from sanic.models.handler_types import Sanic as SanicVar
from sanic.request import Request from sanic.request import Request
from sanic.response import BaseHTTPResponse, HTTPResponse from sanic.response import BaseHTTPResponse, HTTPResponse
from sanic.router import Router from sanic.router import Router
@ -184,7 +185,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
) )
self.is_running = False self.is_running = False
self.is_stopping = False self.is_stopping = False
self.listeners: Dict[str, List[ListenerType]] = defaultdict(list) self.listeners: Dict[str, List[ListenerType[Any]]] = defaultdict(list)
self.named_request_middleware: Dict[str, Deque[MiddlewareType]] = {} self.named_request_middleware: Dict[str, Deque[MiddlewareType]] = {}
self.named_response_middleware: Dict[str, Deque[MiddlewareType]] = {} self.named_response_middleware: Dict[str, Deque[MiddlewareType]] = {}
self.reload_dirs: Set[Path] = set() self.reload_dirs: Set[Path] = set()
@ -196,7 +197,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
self.sock = None self.sock = None
self.strict_slashes = strict_slashes self.strict_slashes = strict_slashes
self.websocket_enabled = False self.websocket_enabled = False
self.websocket_tasks: Set[Future] = set() self.websocket_tasks: Set[Future[Any]] = set()
# Register alternative method names # Register alternative method names
self.go_fast = self.run self.go_fast = self.run
@ -232,7 +233,10 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
# Registration # Registration
# -------------------------------------------------------------------- # # -------------------------------------------------------------------- #
def add_task(self, task) -> None: def add_task(
self,
task: Union[Future[Any], Coroutine[Any, Any, Any], Awaitable[Any]],
) -> None:
""" """
Schedule a task to run later, after the loop has started. Schedule a task to run later, after the loop has started.
Different from asyncio.ensure_future in that it does not Different from asyncio.ensure_future in that it does not
@ -255,7 +259,9 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
self.signal(task_name)(partial(self.run_delayed_task, task=task)) self.signal(task_name)(partial(self.run_delayed_task, task=task))
self._delayed_tasks.append(task_name) self._delayed_tasks.append(task_name)
def register_listener(self, listener: Callable, event: str) -> Any: def register_listener(
self, listener: ListenerType[SanicVar], event: str
) -> ListenerType[SanicVar]:
""" """
Register the listener for a given event. Register the listener for a given event.
@ -281,7 +287,9 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
return listener return listener
def register_middleware(self, middleware, attach_to: str = "request"): def register_middleware(
self, middleware: MiddlewareType, attach_to: str = "request"
) -> MiddlewareType:
""" """
Register an application level middleware that will be attached Register an application level middleware that will be attached
to all the API URLs registered under this application. to all the API URLs registered under this application.
@ -307,7 +315,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
def register_named_middleware( def register_named_middleware(
self, self,
middleware, middleware: MiddlewareType,
route_names: Iterable[str], route_names: Iterable[str],
attach_to: str = "request", attach_to: str = "request",
): ):
@ -1337,7 +1345,9 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
if unix: if unix:
logger.info(f"Goin' Fast @ {unix} {proto}://...") logger.info(f"Goin' Fast @ {unix} {proto}://...")
else: else:
logger.info(f"Goin' Fast @ {proto}://{host}:{port}") # colon(:) is legal for a host only in an ipv6 address
display_host = f"[{host}]" if ":" in host else host
logger.info(f"Goin' Fast @ {proto}://{display_host}:{port}")
debug_mode = "enabled" if self.debug else "disabled" debug_mode = "enabled" if self.debug else "disabled"
reload_mode = "enabled" if auto_reload else "disabled" reload_mode = "enabled" if auto_reload else "disabled"

View File

@ -23,7 +23,7 @@ class BaseSanic(
): ):
__fake_slots__: Tuple[str, ...] __fake_slots__: Tuple[str, ...]
def __init__(self, name: str = None, *args, **kwargs) -> None: def __init__(self, name: str = None, *args: Any, **kwargs: Any) -> None:
class_name = self.__class__.__name__ class_name = self.__class__.__name__
if name is None: if name is None:

View File

@ -208,7 +208,7 @@ class BlueprintGroup(MutableSequence):
:param args: List of Python exceptions to be caught by the handler :param args: List of Python exceptions to be caught by the handler
:param kwargs: Additional optional arguments to be passed to the :param kwargs: Additional optional arguments to be passed to the
exception handler exception handler
:return a decorated method to handle global exceptions for any :return: a decorated method to handle global exceptions for any
blueprint registered under this group. blueprint registered under this group.
""" """

View File

@ -5,7 +5,16 @@ import asyncio
from collections import defaultdict from collections import defaultdict
from copy import deepcopy from copy import deepcopy
from types import SimpleNamespace from types import SimpleNamespace
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Union from typing import (
TYPE_CHECKING,
Any,
Dict,
Iterable,
List,
Optional,
Set,
Union,
)
from sanic_routing.exceptions import NotFound # type: ignore from sanic_routing.exceptions import NotFound # type: ignore
from sanic_routing.route import Route # type: ignore from sanic_routing.route import Route # type: ignore
@ -142,7 +151,7 @@ class Blueprint(BaseSanic):
def reset(self): def reset(self):
self._apps: Set[Sanic] = set() self._apps: Set[Sanic] = set()
self.exceptions: List[RouteHandler] = [] self.exceptions: List[RouteHandler] = []
self.listeners: Dict[str, List[ListenerType]] = {} self.listeners: Dict[str, List[ListenerType[Any]]] = {}
self.middlewares: List[MiddlewareType] = [] self.middlewares: List[MiddlewareType] = []
self.routes: List[Route] = [] self.routes: List[Route] = []
self.statics: List[RouteHandler] = [] self.statics: List[RouteHandler] = []
@ -221,7 +230,7 @@ class Blueprint(BaseSanic):
version: Optional[Union[int, str, float]] = None, version: Optional[Union[int, str, float]] = None,
strict_slashes: Optional[bool] = None, strict_slashes: Optional[bool] = None,
version_prefix: str = "/v", version_prefix: str = "/v",
): ) -> BlueprintGroup:
""" """
Create a list of blueprints, optionally grouping them under a Create a list of blueprints, optionally grouping them under a
general URL prefix. general URL prefix.

View File

@ -3,7 +3,7 @@ from functools import partial
from typing import List, Optional, Union from typing import List, Optional, Union
from sanic.models.futures import FutureListener from sanic.models.futures import FutureListener
from sanic.models.handler_types import ListenerType from sanic.models.handler_types import ListenerType, Sanic
class ListenerEvent(str, Enum): class ListenerEvent(str, Enum):
@ -27,10 +27,10 @@ class ListenerMixin:
def listener( def listener(
self, self,
listener_or_event: Union[ListenerType, str], listener_or_event: Union[ListenerType[Sanic], str],
event_or_none: Optional[str] = None, event_or_none: Optional[str] = None,
apply: bool = True, apply: bool = True,
): ) -> ListenerType[Sanic]:
""" """
Create a listener from a decorated function. Create a listener from a decorated function.
@ -62,20 +62,32 @@ class ListenerMixin:
else: else:
return partial(register_listener, event=listener_or_event) return partial(register_listener, event=listener_or_event)
def main_process_start(self, listener: ListenerType) -> ListenerType: def main_process_start(
self, listener: ListenerType[Sanic]
) -> ListenerType[Sanic]:
return self.listener(listener, "main_process_start") return self.listener(listener, "main_process_start")
def main_process_stop(self, listener: ListenerType) -> ListenerType: def main_process_stop(
self, listener: ListenerType[Sanic]
) -> ListenerType[Sanic]:
return self.listener(listener, "main_process_stop") return self.listener(listener, "main_process_stop")
def before_server_start(self, listener: ListenerType) -> ListenerType: def before_server_start(
self, listener: ListenerType[Sanic]
) -> ListenerType[Sanic]:
return self.listener(listener, "before_server_start") return self.listener(listener, "before_server_start")
def after_server_start(self, listener: ListenerType) -> ListenerType: def after_server_start(
self, listener: ListenerType[Sanic]
) -> ListenerType[Sanic]:
return self.listener(listener, "after_server_start") return self.listener(listener, "after_server_start")
def before_server_stop(self, listener: ListenerType) -> ListenerType: def before_server_stop(
self, listener: ListenerType[Sanic]
) -> ListenerType[Sanic]:
return self.listener(listener, "before_server_stop") return self.listener(listener, "before_server_stop")
def after_server_stop(self, listener: ListenerType) -> ListenerType: def after_server_stop(
self, listener: ListenerType[Sanic]
) -> ListenerType[Sanic]:
return self.listener(listener, "after_server_stop") return self.listener(listener, "after_server_stop")

View File

@ -52,7 +52,7 @@ def test_server_run(appname):
("-H", "localhost", "-p", "9999"), ("-H", "localhost", "-p", "9999"),
), ),
) )
def test_host_port(cmd): def test_host_port_localhost(cmd):
command = ["sanic", "fake.server.app", *cmd] command = ["sanic", "fake.server.app", *cmd]
out, err, exitcode = capture(command) out, err, exitcode = capture(command)
lines = out.split(b"\n") lines = out.split(b"\n")
@ -62,6 +62,57 @@ def test_host_port(cmd):
assert firstline == b"Goin' Fast @ http://localhost:9999" assert firstline == b"Goin' Fast @ http://localhost:9999"
@pytest.mark.parametrize(
"cmd",
(
("--host=127.0.0.127", "--port=9999"),
("-H", "127.0.0.127", "-p", "9999"),
),
)
def test_host_port_ipv4(cmd):
command = ["sanic", "fake.server.app", *cmd]
out, err, exitcode = capture(command)
lines = out.split(b"\n")
firstline = lines[6]
assert exitcode != 1
assert firstline == b"Goin' Fast @ http://127.0.0.127:9999"
@pytest.mark.parametrize(
"cmd",
(
("--host=::", "--port=9999"),
("-H", "::", "-p", "9999"),
),
)
def test_host_port_ipv6_any(cmd):
command = ["sanic", "fake.server.app", *cmd]
out, err, exitcode = capture(command)
lines = out.split(b"\n")
firstline = lines[6]
assert exitcode != 1
assert firstline == b"Goin' Fast @ http://[::]:9999"
@pytest.mark.parametrize(
"cmd",
(
("--host=::1", "--port=9999"),
("-H", "::1", "-p", "9999"),
),
)
def test_host_port_ipv6_loopback(cmd):
command = ["sanic", "fake.server.app", *cmd]
out, err, exitcode = capture(command)
lines = out.split(b"\n")
firstline = lines[6]
assert exitcode != 1
assert firstline == b"Goin' Fast @ http://[::1]:9999"
@pytest.mark.parametrize( @pytest.mark.parametrize(
"num,cmd", "num,cmd",
( (