Implement 0.6 routing and some cleanup (#2117)
* Implement 0.6 routing and some cleanup * Additional tests and annotation cleanup * Resolve sorting * cleanup test with encoding
This commit is contained in:
@@ -164,10 +164,12 @@ class ASGIApp:
|
||||
Read and stream the body in chunks from an incoming ASGI message.
|
||||
"""
|
||||
message = await self.transport.receive()
|
||||
body = message.get("body", b"")
|
||||
if not message.get("more_body", False):
|
||||
self.request_body = False
|
||||
return None
|
||||
return message.get("body", b"")
|
||||
if not body:
|
||||
return None
|
||||
return body
|
||||
|
||||
async def __aiter__(self):
|
||||
while self.request_body:
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
from collections.abc import MutableSequence
|
||||
from typing import List, Optional, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Union
|
||||
|
||||
import sanic
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sanic.blueprints import Blueprint
|
||||
|
||||
|
||||
class BlueprintGroup(MutableSequence):
|
||||
"""
|
||||
This class provides a mechanism to implement a Blueprint Group
|
||||
@@ -56,7 +60,12 @@ class BlueprintGroup(MutableSequence):
|
||||
|
||||
__slots__ = ("_blueprints", "_url_prefix", "_version", "_strict_slashes")
|
||||
|
||||
def __init__(self, url_prefix=None, version=None, strict_slashes=None):
|
||||
def __init__(
|
||||
self,
|
||||
url_prefix: Optional[str] = None,
|
||||
version: Optional[Union[int, str, float]] = None,
|
||||
strict_slashes: Optional[bool] = None,
|
||||
):
|
||||
"""
|
||||
Create a new Blueprint Group
|
||||
|
||||
@@ -65,13 +74,13 @@ class BlueprintGroup(MutableSequence):
|
||||
inherited by each of the Blueprint
|
||||
:param strict_slashes: URL Strict slash behavior indicator
|
||||
"""
|
||||
self._blueprints = []
|
||||
self._blueprints: List[Blueprint] = []
|
||||
self._url_prefix = url_prefix
|
||||
self._version = version
|
||||
self._strict_slashes = strict_slashes
|
||||
|
||||
@property
|
||||
def url_prefix(self) -> str:
|
||||
def url_prefix(self) -> Optional[Union[int, str, float]]:
|
||||
"""
|
||||
Retrieve the URL prefix being used for the Current Blueprint Group
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class Blueprint(BaseSanic):
|
||||
name: str,
|
||||
url_prefix: Optional[str] = None,
|
||||
host: Optional[str] = None,
|
||||
version: Optional[int] = None,
|
||||
version: Optional[Union[int, str, float]] = None,
|
||||
strict_slashes: Optional[bool] = None,
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
@@ -82,6 +82,7 @@ class Http:
|
||||
"request_max_size",
|
||||
"response",
|
||||
"response_func",
|
||||
"response_size",
|
||||
"response_bytes_left",
|
||||
"upgrade_websocket",
|
||||
]
|
||||
@@ -272,6 +273,7 @@ class Http:
|
||||
size = len(data)
|
||||
headers = res.headers
|
||||
status = res.status
|
||||
self.response_size = size
|
||||
|
||||
if not isinstance(status, int) or status < 200:
|
||||
raise RuntimeError(f"Invalid response status {status!r}")
|
||||
@@ -426,7 +428,9 @@ class Http:
|
||||
req, res = self.request, self.response
|
||||
extra = {
|
||||
"status": getattr(res, "status", 0),
|
||||
"byte": getattr(self, "response_bytes_left", -1),
|
||||
"byte": getattr(
|
||||
self, "response_bytes_left", getattr(self, "response_size", -1)
|
||||
),
|
||||
"host": "UNKNOWN",
|
||||
"request": "nil",
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class RouteMixin:
|
||||
host: Optional[str] = None,
|
||||
strict_slashes: Optional[bool] = None,
|
||||
stream: bool = False,
|
||||
version: Optional[int] = None,
|
||||
version: Optional[Union[int, str, float]] = None,
|
||||
name: Optional[str] = None,
|
||||
ignore_body: bool = False,
|
||||
apply: bool = True,
|
||||
|
||||
@@ -33,7 +33,7 @@ class Router(BaseRouter):
|
||||
return self.resolve(
|
||||
path=path,
|
||||
method=method,
|
||||
extra={"host": host},
|
||||
extra={"host": host} if host else None,
|
||||
)
|
||||
except RoutingNotFound as e:
|
||||
raise NotFound("Requested URL {} not found".format(e.path))
|
||||
@@ -161,7 +161,7 @@ class Router(BaseRouter):
|
||||
|
||||
@property
|
||||
def routes_all(self):
|
||||
return self.routes
|
||||
return {route.parts: route for route in self.routes}
|
||||
|
||||
@property
|
||||
def routes_static(self):
|
||||
|
||||
@@ -5,7 +5,7 @@ import asyncio
|
||||
from inspect import isawaitable
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from sanic_routing import BaseRouter, Route # type: ignore
|
||||
from sanic_routing import BaseRouter, Route, RouteGroup # type: ignore
|
||||
from sanic_routing.exceptions import NotFound # type: ignore
|
||||
from sanic_routing.utils import path_to_parts # type: ignore
|
||||
|
||||
@@ -20,17 +20,11 @@ RESERVED_NAMESPACES = (
|
||||
|
||||
|
||||
class Signal(Route):
|
||||
def get_handler(self, raw_path, method, _):
|
||||
method = method or self.router.DEFAULT_METHOD
|
||||
raw_path = raw_path.lstrip(self.router.delimiter)
|
||||
try:
|
||||
return self.handlers[raw_path][method]
|
||||
except (IndexError, KeyError):
|
||||
raise self.router.method_handler_exception(
|
||||
f"Method '{method}' not found on {self}",
|
||||
method=method,
|
||||
allowed_methods=set(self.methods[raw_path]),
|
||||
)
|
||||
...
|
||||
|
||||
|
||||
class SignalGroup(RouteGroup):
|
||||
...
|
||||
|
||||
|
||||
class SignalRouter(BaseRouter):
|
||||
@@ -38,6 +32,7 @@ class SignalRouter(BaseRouter):
|
||||
super().__init__(
|
||||
delimiter=".",
|
||||
route_class=Signal,
|
||||
group_class=SignalGroup,
|
||||
stacking=True,
|
||||
)
|
||||
self.ctx.loop = None
|
||||
@@ -49,7 +44,13 @@ class SignalRouter(BaseRouter):
|
||||
):
|
||||
extra = condition or {}
|
||||
try:
|
||||
return self.resolve(f".{event}", extra=extra)
|
||||
group, param_basket = self.find_route(
|
||||
f".{event}",
|
||||
self.DEFAULT_METHOD,
|
||||
self,
|
||||
{"__params__": {}},
|
||||
extra=extra,
|
||||
)
|
||||
except NotFound:
|
||||
message = "Could not find signal %s"
|
||||
terms: List[Union[str, Optional[Dict[str, str]]]] = [event]
|
||||
@@ -58,16 +59,20 @@ class SignalRouter(BaseRouter):
|
||||
terms.append(extra)
|
||||
raise NotFound(message % tuple(terms))
|
||||
|
||||
params = param_basket.pop("__params__")
|
||||
return group, [route.handler for route in group], params
|
||||
|
||||
async def _dispatch(
|
||||
self,
|
||||
event: str,
|
||||
context: Optional[Dict[str, Any]] = None,
|
||||
condition: Optional[Dict[str, str]] = None,
|
||||
) -> None:
|
||||
signal, handlers, params = self.get(event, condition=condition)
|
||||
group, handlers, params = self.get(event, condition=condition)
|
||||
|
||||
signal_event = signal.ctx.event
|
||||
signal_event.set()
|
||||
events = [signal.ctx.event for signal in group]
|
||||
for signal_event in events:
|
||||
signal_event.set()
|
||||
if context:
|
||||
params.update(context)
|
||||
|
||||
@@ -78,7 +83,8 @@ class SignalRouter(BaseRouter):
|
||||
if isawaitable(maybe_coroutine):
|
||||
await maybe_coroutine
|
||||
finally:
|
||||
signal_event.clear()
|
||||
for signal_event in events:
|
||||
signal_event.clear()
|
||||
|
||||
async def dispatch(
|
||||
self,
|
||||
@@ -116,7 +122,7 @@ class SignalRouter(BaseRouter):
|
||||
handler,
|
||||
requirements=condition,
|
||||
name=name,
|
||||
overwrite=True,
|
||||
append=True,
|
||||
) # type: ignore
|
||||
|
||||
def finalize(self, do_compile: bool = True):
|
||||
@@ -125,7 +131,7 @@ class SignalRouter(BaseRouter):
|
||||
except RuntimeError:
|
||||
raise RuntimeError("Cannot finalize signals outside of event loop")
|
||||
|
||||
for signal in self.routes.values():
|
||||
for signal in self.routes:
|
||||
signal.ctx.event = asyncio.Event()
|
||||
|
||||
return super().finalize(do_compile=do_compile)
|
||||
|
||||
Reference in New Issue
Block a user