Cleanup type checking

This commit is contained in:
Adam Hopkins 2021-02-21 21:29:41 +02:00
parent 209579f280
commit d402d0362e
9 changed files with 63 additions and 35 deletions

View File

@ -243,6 +243,7 @@ class Sanic(BaseSanic):
self.named_response_middleware[_rn] = deque() self.named_response_middleware[_rn] = deque()
if middleware not in self.named_response_middleware[_rn]: if middleware not in self.named_response_middleware[_rn]:
self.named_response_middleware[_rn].appendleft(middleware) self.named_response_middleware[_rn].appendleft(middleware)
return middleware
def _apply_exception_handler(self, handler: FutureException): def _apply_exception_handler(self, handler: FutureException):
"""Decorate a function to be registered as a handler for exceptions """Decorate a function to be registered as a handler for exceptions
@ -257,12 +258,12 @@ class Sanic(BaseSanic):
self.error_handler.add(e, handler.handler) self.error_handler.add(e, handler.handler)
else: else:
self.error_handler.add(exception, handler.handler) self.error_handler.add(exception, handler.handler)
return handler return handler.handler
def _apply_listener(self, listener: FutureListener): def _apply_listener(self, listener: FutureListener):
return self.register_listener(listener.listener, listener.event) return self.register_listener(listener.listener, listener.event)
def _apply_route(self, route: FutureRoute) -> Route: def _apply_route(self, route: FutureRoute) -> List[Route]:
params = route._asdict() params = route._asdict()
websocket = params.pop("websocket", False) websocket = params.pop("websocket", False)
subprotocols = params.pop("subprotocols", None) subprotocols = params.pop("subprotocols", None)
@ -277,7 +278,15 @@ class Sanic(BaseSanic):
websocket_handler.__name__ = route.handler.__name__ # type: ignore websocket_handler.__name__ = route.handler.__name__ # type: ignore
websocket_handler.is_websocket = True # type: ignore websocket_handler.is_websocket = True # type: ignore
params["handler"] = websocket_handler params["handler"] = websocket_handler
return self.router.add(**params)
routes = self.router.add(**params)
if isinstance(routes, Route):
routes = [routes]
for r in routes:
r.ctx.websocket = websocket
r.ctx.static = params.get("static", False)
return routes
def _apply_static(self, static: FutureStatic) -> Route: def _apply_static(self, static: FutureStatic) -> Route:
return self._register_static(static) return self._register_static(static)

View File

@ -1,8 +1,11 @@
from collections import defaultdict from collections import defaultdict
from typing import Optional from typing import Dict, List, Optional
from sanic_routing.route import Route # type: ignore
from sanic.base import BaseSanic from sanic.base import BaseSanic
from sanic.blueprint_group import BlueprintGroup from sanic.blueprint_group import BlueprintGroup
from sanic.handlers import ListenerType, MiddlewareType, RouteHandler
from sanic.models.futures import FutureRoute, FutureStatic from sanic.models.futures import FutureRoute, FutureStatic
@ -37,12 +40,12 @@ class Blueprint(BaseSanic):
self.url_prefix = url_prefix self.url_prefix = url_prefix
self.host = host self.host = host
self.routes = [] self.routes: List[Route] = []
self.websocket_routes = [] self.websocket_routes: List[Route] = []
self.exceptions = [] self.exceptions: List[RouteHandler] = []
self.listeners = defaultdict(list) self.listeners: Dict[str, List[ListenerType]] = {}
self.middlewares = [] self.middlewares: List[MiddlewareType] = []
self.statics = [] self.statics: List[RouteHandler] = []
self.version = version self.version = version
self.strict_slashes = strict_slashes self.strict_slashes = strict_slashes
@ -107,6 +110,9 @@ class Blueprint(BaseSanic):
url_prefix = options.get("url_prefix", self.url_prefix) url_prefix = options.get("url_prefix", self.url_prefix)
routes = [] routes = []
middleware = []
exception_handlers = []
listeners = defaultdict(list)
# Routes # Routes
for future in self._future_routes: for future in self._future_routes:
@ -159,12 +165,22 @@ class Blueprint(BaseSanic):
# Middleware # Middleware
if route_names: if route_names:
for future in self._future_middleware: for future in self._future_middleware:
app._apply_middleware(future, route_names) middleware.append(app._apply_middleware(future, route_names))
# Exceptions # Exceptions
for future in self._future_exceptions: for future in self._future_exceptions:
app._apply_exception_handler(future) exception_handlers.append(app._apply_exception_handler(future))
# Event listeners # Event listeners
for listener in self._future_listeners: for listener in self._future_listeners:
app._apply_listener(listener) listeners[listener.event].append(app._apply_listener(listener))
self.routes = [route for route in routes if isinstance(route, Route)]
# Deprecate these in 21.6
self.websocket_routes = [
route for route in self.routes if route.ctx.websocket
]
self.middlewares = middleware
self.exceptions = exception_handlers
self.listeners = dict(listeners)

View File

@ -113,8 +113,8 @@ class Config(dict):
config.update_config("${some}/py/file") config.update_config("${some}/py/file")
Yes you can put environment variable here, but they must be provided Yes you can put environment variable here, but they must be provided
in format: ``${some_env_var}``, and mark that ``$some_env_var`` is treated in format: ``${some_env_var}``, and mark that ``$some_env_var`` is
as plain string. treated as plain string.
You can upload app config by providing dict holding settings. You can upload app config by providing dict holding settings.
@ -134,7 +134,8 @@ class Config(dict):
config.update_config(C) config.update_config(C)
`See user guide <https://sanicframework.org/guide/deployment/configuration.html>`__ `See user guide
<https://sanicframework.org/guide/deployment/configuration.html>`__
""" """
if isinstance(config, (bytes, str, Path)): if isinstance(config, (bytes, str, Path)):

View File

@ -1,5 +1,6 @@
""" """
Sanic `provides a pattern <https://sanicframework.org/guide/best-practices/exceptions.html#using-sanic-exceptions>`_ Sanic `provides a pattern
<https://sanicframework.org/guide/best-practices/exceptions.html#using-sanic-exceptions>`_
for providing a response when an exception occurs. However, if you do no handle for providing a response when an exception occurs. However, if you do no handle
an exception, it will provide a fallback. There are three fallback types: an exception, it will provide a fallback. There are three fallback types:
@ -72,9 +73,9 @@ class BaseRenderer:
status_text = STATUS_CODES.get(self.status, b"Error Occurred").decode() status_text = STATUS_CODES.get(self.status, b"Error Occurred").decode()
return f"{self.status}{status_text}" return f"{self.status}{status_text}"
def render(self) -> str: def render(self) -> HTTPResponse:
""" """
Outputs the exception as a ``str`` for response. Outputs the exception as a :class:`HTTPResponse`.
:return: The formatted exception :return: The formatted exception
:rtype: str :rtype: str
@ -86,14 +87,14 @@ class BaseRenderer:
) )
return output() return output()
def minimal(self) -> str: # noqa def minimal(self) -> HTTPResponse: # noqa
""" """
Provide a formatted message that is meant to not show any sensitive Provide a formatted message that is meant to not show any sensitive
data or details. data or details.
""" """
raise NotImplementedError raise NotImplementedError
def full(self) -> str: # noqa def full(self) -> HTTPResponse: # noqa
""" """
Provide a formatted message that has all details and is mean to be used Provide a formatted message that has all details and is mean to be used
primarily for debugging and non-production environments. primarily for debugging and non-production environments.
@ -145,7 +146,7 @@ class HTMLRenderer(BaseRenderer):
"{body}" "{body}"
) )
def full(self): def full(self) -> HTTPResponse:
return html( return html(
self.OUTPUT_HTML.format( self.OUTPUT_HTML.format(
title=self.title, title=self.title,
@ -156,7 +157,7 @@ class HTMLRenderer(BaseRenderer):
status=self.status, status=self.status,
) )
def minimal(self): def minimal(self) -> HTTPResponse:
return html( return html(
self.OUTPUT_HTML.format( self.OUTPUT_HTML.format(
title=self.title, title=self.title,
@ -217,7 +218,7 @@ class TextRenderer(BaseRenderer):
OUTPUT_TEXT = "{title}\n{bar}\n{text}\n\n{body}" OUTPUT_TEXT = "{title}\n{bar}\n{text}\n\n{body}"
SPACER = " " SPACER = " "
def full(self): def full(self) -> HTTPResponse:
return text( return text(
self.OUTPUT_TEXT.format( self.OUTPUT_TEXT.format(
title=self.title, title=self.title,
@ -228,7 +229,7 @@ class TextRenderer(BaseRenderer):
status=self.status, status=self.status,
) )
def minimal(self): def minimal(self) -> HTTPResponse:
return text( return text(
self.OUTPUT_TEXT.format( self.OUTPUT_TEXT.format(
title=self.title, title=self.title,
@ -277,11 +278,11 @@ class JSONRenderer(BaseRenderer):
Render an exception as JSON. Render an exception as JSON.
""" """
def full(self): def full(self) -> HTTPResponse:
output = self._generate_output(full=True) output = self._generate_output(full=True)
return json(output, status=self.status, dumps=dumps) return json(output, status=self.status, dumps=dumps)
def minimal(self): def minimal(self) -> HTTPResponse:
output = self._generate_output(full=False) output = self._generate_output(full=False)
return json(output, status=self.status, dumps=dumps) return json(output, status=self.status, dumps=dumps)

View File

@ -1,6 +1,6 @@
from enum import Enum, auto from enum import Enum, auto
from functools import partial from functools import partial
from typing import Any, Callable, Coroutine, List, Optional, Set, Union from typing import Any, Callable, Coroutine, List, Optional, Union
from sanic.models.futures import FutureListener from sanic.models.futures import FutureListener

View File

@ -30,7 +30,7 @@ class RouteMixin:
self._future_routes: Set[FutureRoute] = set() self._future_routes: Set[FutureRoute] = set()
self._future_statics: Set[FutureStatic] = set() self._future_statics: Set[FutureStatic] = set()
self.name = "" self.name = ""
self.strict_slashes = False self.strict_slashes: Optional[bool] = False
def _apply_route(self, route: FutureRoute) -> Route: def _apply_route(self, route: FutureRoute) -> Route:
raise NotImplementedError # noqa raise NotImplementedError # noqa
@ -41,7 +41,7 @@ class RouteMixin:
def route( def route(
self, self,
uri: str, uri: str,
methods: Iterable[str] = frozenset({"GET"}), methods: Optional[Iterable[str]] = None,
host: Optional[str] = None, host: Optional[str] = None,
strict_slashes: Optional[bool] = None, strict_slashes: Optional[bool] = None,
stream: bool = False, stream: bool = False,

View File

@ -21,7 +21,6 @@ if TYPE_CHECKING:
import email.utils import email.utils
import uuid import uuid
from asyncio.transports import Transport
from collections import defaultdict from collections import defaultdict
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
from types import SimpleNamespace from types import SimpleNamespace
@ -39,6 +38,7 @@ from sanic.headers import (
parse_xforwarded, parse_xforwarded,
) )
from sanic.log import error_logger, logger from sanic.log import error_logger, logger
from sanic.models.protocol_types import TransportProtocol
from sanic.response import BaseHTTPResponse, HTTPResponse from sanic.response import BaseHTTPResponse, HTTPResponse
@ -116,7 +116,7 @@ class Request:
headers: Header, headers: Header,
version: str, version: str,
method: str, method: str,
transport: Transport, transport: TransportProtocol,
app: Sanic, app: Sanic,
): ):
self.raw_url = url_bytes self.raw_url = url_bytes
@ -148,7 +148,7 @@ class Request:
self.uri_template: Optional[str] = None self.uri_template: Optional[str] = None
self.request_middleware_started = False self.request_middleware_started = False
self._cookies: Optional[Dict[str, str]] = None self._cookies: Optional[Dict[str, str]] = None
self._match_info = {} self._match_info: Dict[str, Any] = {}
self.stream: Optional[Http] = None self.stream: Optional[Http] = None
self.endpoint: Optional[str] = None self.endpoint: Optional[str] = None

View File

@ -33,7 +33,7 @@ class Router(BaseRouter):
@lru_cache(maxsize=ROUTER_CACHE_SIZE) @lru_cache(maxsize=ROUTER_CACHE_SIZE)
def _get( def _get(
self, path, method, host self, path, method, host
) -> Tuple[RouteHandler, Dict[str, Any], str, str, bool,]: ) -> Tuple[RouteHandler, Dict[str, Any], str, str, bool]:
try: try:
route, handler, params = self.resolve( route, handler, params = self.resolve(
path=path, path=path,

View File

@ -40,6 +40,7 @@ from sanic.config import Config
from sanic.exceptions import RequestTimeout, ServiceUnavailable from sanic.exceptions import RequestTimeout, ServiceUnavailable
from sanic.http import Http, Stage from sanic.http import Http, Stage
from sanic.log import logger from sanic.log import logger
from sanic.models.protocol_types import TransportProtocol
from sanic.request import Request from sanic.request import Request
@ -69,7 +70,7 @@ class ConnInfo:
"ssl", "ssl",
) )
def __init__(self, transport: Transport, unix=None): def __init__(self, transport: TransportProtocol, unix=None):
self.ssl: bool = bool(transport.get_extra_info("sslcontext")) self.ssl: bool = bool(transport.get_extra_info("sslcontext"))
self.server = self.client = "" self.server = self.client = ""
self.server_port = self.client_port = 0 self.server_port = self.client_port = 0