diff --git a/sanic/__init__.py b/sanic/__init__.py index 2b7e779267..cf050fc615 100644 --- a/sanic/__init__.py +++ b/sanic/__init__.py @@ -4,6 +4,7 @@ from sanic.constants import HTTPMethod from sanic.request import Request from sanic.response import HTTPResponse, html, json, text +from sanic.server.websockets.impl import WebsocketImplProtocol as Websocket __all__ = ( @@ -13,6 +14,7 @@ "HTTPMethod", "HTTPResponse", "Request", + "Websocket", "html", "json", "text", diff --git a/sanic/__version__.py b/sanic/__version__.py index 847ff8e612..667ec2f017 100644 --- a/sanic/__version__.py +++ b/sanic/__version__.py @@ -1 +1 @@ -__version__ = "22.3.0" +__version__ = "22.3.1" diff --git a/sanic/app.py b/sanic/app.py index a67b437dcc..4dbb1b2e5d 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -252,7 +252,13 @@ def loop(self): "Loop can only be retrieved after the app has started " "running. Not supported with `create_server` function" ) - return get_running_loop() + try: + return get_running_loop() + except RuntimeError: + if sys.version_info > (3, 10): + return asyncio.get_event_loop_policy().get_event_loop() + else: + return asyncio.get_event_loop() # -------------------------------------------------------------------- # # Registration diff --git a/sanic/compat.py b/sanic/compat.py index e28e64a15d..d8e0bea11f 100644 --- a/sanic/compat.py +++ b/sanic/compat.py @@ -72,7 +72,7 @@ async def stay_active(app): """Asyncio wakeups to allow receiving SIGINT in Python""" while not die: # If someone else stopped the app, just exit - if app.is_stopping: + if app.state.is_stopping: return # Windows Python blocks signal handlers while the event loop is # waiting for I/O. Frequent wakeups keep interrupts flowing. diff --git a/tests/test_signal_handlers.py b/tests/test_signal_handlers.py index c6838b5e3a..ee28f5488a 100644 --- a/tests/test_signal_handlers.py +++ b/tests/test_signal_handlers.py @@ -3,6 +3,7 @@ import signal from queue import Queue +from types import SimpleNamespace from unittest.mock import MagicMock import pytest @@ -74,11 +75,12 @@ def test_windows_workaround(): # Windows... class MockApp: def __init__(self): - self.is_stopping = False + self.state = SimpleNamespace() + self.state.is_stopping = False def stop(self): - assert not self.is_stopping - self.is_stopping = True + assert not self.state.is_stopping + self.state.is_stopping = True def add_task(self, func): loop = asyncio.get_event_loop() @@ -91,11 +93,11 @@ async def atest(stop_first): if stop_first: app.stop() await asyncio.sleep(0.2) - assert app.is_stopping == stop_first + assert app.state.is_stopping == stop_first # First Ctrl+C: should call app.stop() within 0.1 seconds os.kill(os.getpid(), signal.SIGINT) await asyncio.sleep(0.2) - assert app.is_stopping + assert app.state.is_stopping assert app.stay_active_task.result() is None # Second Ctrl+C should raise with pytest.raises(KeyboardInterrupt):