diff --git a/sanic/mixins/listeners.py b/sanic/mixins/listeners.py index 71f11148..ebf9b131 100644 --- a/sanic/mixins/listeners.py +++ b/sanic/mixins/listeners.py @@ -1,8 +1,9 @@ from enum import Enum, auto from functools import partial -from typing import Any, Callable, Coroutine, List, Optional, Union +from typing import List, Optional, Union from sanic.models.futures import FutureListener +from sanic.models.handler_types import ListenerType class ListenerEvent(str, Enum): @@ -26,9 +27,7 @@ class ListenerMixin: def listener( self, - listener_or_event: Union[ - Callable[..., Coroutine[Any, Any, None]], str - ], + listener_or_event: Union[ListenerType, str], event_or_none: Optional[str] = None, apply: bool = True, ): @@ -63,20 +62,20 @@ class ListenerMixin: else: return partial(register_listener, event=listener_or_event) - def main_process_start(self, listener): + def main_process_start(self, listener: ListenerType) -> ListenerType: return self.listener(listener, "main_process_start") - def main_process_stop(self, listener): + def main_process_stop(self, listener: ListenerType) -> ListenerType: return self.listener(listener, "main_process_stop") - def before_server_start(self, listener): + def before_server_start(self, listener: ListenerType) -> ListenerType: return self.listener(listener, "before_server_start") - def after_server_start(self, listener): + def after_server_start(self, listener: ListenerType) -> ListenerType: return self.listener(listener, "after_server_start") - def before_server_stop(self, listener): + def before_server_stop(self, listener: ListenerType) -> ListenerType: return self.listener(listener, "before_server_stop") - def after_server_stop(self, listener): + def after_server_stop(self, listener: ListenerType) -> ListenerType: return self.listener(listener, "after_server_stop") diff --git a/sanic/mixins/routes.py b/sanic/mixins/routes.py index 3c2f4430..86bb7fc7 100644 --- a/sanic/mixins/routes.py +++ b/sanic/mixins/routes.py @@ -5,7 +5,7 @@ from os import path from pathlib import PurePath from re import sub from time import gmtime, strftime -from typing import Iterable, List, Optional, Set, Union +from typing import Callable, Iterable, List, Optional, Set, Tuple, Union from urllib.parse import unquote from sanic_routing.route import Route # type: ignore @@ -21,10 +21,16 @@ from sanic.exceptions import ( from sanic.handlers import ContentRangeHandler from sanic.log import error_logger from sanic.models.futures import FutureRoute, FutureStatic +from sanic.models.handler_types import RouteHandler from sanic.response import HTTPResponse, file, file_stream from sanic.views import CompositionView +RouteWrapper = Callable[ + [RouteHandler], Union[RouteHandler, Tuple[Route, RouteHandler]] +] + + class RouteMixin: name: str @@ -55,7 +61,7 @@ class RouteMixin: unquote: bool = False, static: bool = False, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Decorate a function to be registered as a route @@ -168,7 +174,7 @@ class RouteMixin: def add_route( self, - handler, + handler: RouteHandler, uri: str, methods: Iterable[str] = frozenset({"GET"}), host: Optional[str] = None, @@ -177,7 +183,7 @@ class RouteMixin: name: Optional[str] = None, stream: bool = False, version_prefix: str = "/v", - ): + ) -> RouteHandler: """A helper method to register class instance or functions as a handler to the application url routes. @@ -200,7 +206,8 @@ class RouteMixin: methods = set() for method in HTTP_METHODS: - _handler = getattr(handler.view_class, method.lower(), None) + view_class = getattr(handler, "view_class") + _handler = getattr(view_class, method.lower(), None) if _handler: methods.add(method) if hasattr(_handler, "is_stream"): @@ -239,7 +246,7 @@ class RouteMixin: name: Optional[str] = None, ignore_body: bool = True, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **GET** *HTTP* method @@ -273,7 +280,7 @@ class RouteMixin: version: Optional[int] = None, name: Optional[str] = None, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **POST** *HTTP* method @@ -307,7 +314,7 @@ class RouteMixin: version: Optional[int] = None, name: Optional[str] = None, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **PUT** *HTTP* method @@ -341,7 +348,7 @@ class RouteMixin: name: Optional[str] = None, ignore_body: bool = True, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **HEAD** *HTTP* method @@ -383,7 +390,7 @@ class RouteMixin: name: Optional[str] = None, ignore_body: bool = True, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **OPTIONS** *HTTP* method @@ -425,7 +432,7 @@ class RouteMixin: version: Optional[int] = None, name: Optional[str] = None, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **PATCH** *HTTP* method @@ -469,7 +476,7 @@ class RouteMixin: name: Optional[str] = None, ignore_body: bool = True, version_prefix: str = "/v", - ): + ) -> RouteWrapper: """ Add an API URL under the **DELETE** *HTTP* method @@ -847,7 +854,7 @@ class RouteMixin: ) ) - route, _ = self.route( + route, _ = self.route( # type: ignore uri=uri, methods=["GET", "HEAD"], name=name, diff --git a/sanic/models/handler_types.py b/sanic/models/handler_types.py index 704def7a..0144c964 100644 --- a/sanic/models/handler_types.py +++ b/sanic/models/handler_types.py @@ -21,5 +21,5 @@ MiddlewareType = Union[RequestMiddlewareType, ResponseMiddlewareType] ListenerType = Callable[ [Sanic, AbstractEventLoop], Optional[Coroutine[Any, Any, None]] ] -RouteHandler = Callable[..., Coroutine[Any, Any, HTTPResponse]] +RouteHandler = Callable[..., Coroutine[Any, Any, Optional[HTTPResponse]]] SignalHandler = Callable[..., Coroutine[Any, Any, None]] diff --git a/sanic/views.py b/sanic/views.py index 64a872a4..c983bef7 100644 --- a/sanic/views.py +++ b/sanic/views.py @@ -13,6 +13,7 @@ from warnings import warn from sanic.constants import HTTP_METHODS from sanic.exceptions import InvalidUsage +from sanic.models.handler_types import RouteHandler if TYPE_CHECKING: @@ -86,7 +87,7 @@ class HTTPMethodView: return handler(request, *args, **kwargs) @classmethod - def as_view(cls, *class_args, **class_kwargs): + def as_view(cls, *class_args: Any, **class_kwargs: Any) -> RouteHandler: """Return view function for use with the routing system, that dispatches request to appropriate handler method. """ @@ -100,7 +101,7 @@ class HTTPMethodView: for decorator in cls.decorators: view = decorator(view) - view.view_class = cls + view.view_class = cls # type: ignore view.__doc__ = cls.__doc__ view.__module__ = cls.__module__ view.__name__ = cls.__name__