Skip to content

Commit

Permalink
Fixing typing for ListenerMixin.listener (sanic-org#2376)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
  • Loading branch information
2 people authored and ChihweiLHBird committed Jun 1, 2022
1 parent 51cd510 commit 467c6a8
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
34 changes: 31 additions & 3 deletions sanic/mixins/listeners.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from enum import Enum, auto
from functools import partial
from typing import List, Optional, Union
from typing import Callable, List, Optional, Union, overload

from sanic.base.meta import SanicMeta
from sanic.exceptions import InvalidUsage
from sanic.models.futures import FutureListener
from sanic.models.handler_types import ListenerType, Sanic

Expand All @@ -28,12 +29,33 @@ def __init__(self, *args, **kwargs) -> None:
def _apply_listener(self, listener: FutureListener):
raise NotImplementedError # noqa

@overload
def listener(
self,
listener_or_event: ListenerType[Sanic],
event_or_none: str,
apply: bool = ...,
) -> ListenerType[Sanic]:
...

@overload
def listener(
self,
listener_or_event: str,
event_or_none: None = ...,
apply: bool = ...,
) -> Callable[[ListenerType[Sanic]], ListenerType[Sanic]]:
...

def listener(
self,
listener_or_event: Union[ListenerType[Sanic], str],
event_or_none: Optional[str] = None,
apply: bool = True,
) -> ListenerType[Sanic]:
) -> Union[
ListenerType[Sanic],
Callable[[ListenerType[Sanic]], ListenerType[Sanic]],
]:
"""
Create a listener from a decorated function.
Expand All @@ -51,7 +73,9 @@ async def before_server_start(app, loop):
:param event: event to listen to
"""

def register_listener(listener, event):
def register_listener(
listener: ListenerType[Sanic], event: str
) -> ListenerType[Sanic]:
nonlocal apply

future_listener = FutureListener(listener, event)
Expand All @@ -61,6 +85,10 @@ def register_listener(listener, event):
return listener

if callable(listener_or_event):
if event_or_none is None:
raise InvalidUsage(
"Invalid event registration: Missing event name."
)
return register_listener(listener_or_event, event_or_none)
else:
return partial(register_listener, event=listener_or_event)
Expand Down
4 changes: 3 additions & 1 deletion sanic/models/handler_types.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from asyncio.events import AbstractEventLoop
from typing import Any, Callable, Coroutine, Optional, TypeVar, Union

import sanic

from sanic.request import Request
from sanic.response import BaseHTTPResponse, HTTPResponse


Sanic = TypeVar("Sanic")
Sanic = TypeVar("Sanic", bound="sanic.Sanic")

MiddlewareResponse = Union[
Optional[HTTPResponse], Coroutine[Any, Any, Optional[HTTPResponse]]
Expand Down
15 changes: 15 additions & 0 deletions tests/test_signal_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from sanic_testing.testing import HOST, PORT

from sanic.compat import ctrlc_workaround_for_windows
from sanic.exceptions import InvalidUsage
from sanic.response import HTTPResponse


Expand Down Expand Up @@ -108,3 +109,17 @@ async def atest(stop_first):
assert res == "OK"
res = loop.run_until_complete(atest(True))
assert res == "OK"


@pytest.mark.skipif(os.name == "nt", reason="May hang CI on py38/windows")
def test_signals_with_invalid_invocation(app):
"""Test if sanic register fails with invalid invocation"""

@app.route("/hello")
async def hello_route(request):
return HTTPResponse()

with pytest.raises(
InvalidUsage, match="Invalid event registration: Missing event name"
):
app.listener(stop)

0 comments on commit 467c6a8

Please sign in to comment.