From fb3076d40f0e1df2007e63a76436f2688e22576f Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Fri, 21 Apr 2023 00:17:06 +0300 Subject: [PATCH] Fix compatibility with Python 3.8-3.9 (#1162) * Try to fix compatibility with Python 3.8-3.9 * Added changelog --- CHANGES/1162.bugfix.rst | 1 + aiogram/dispatcher/dispatcher.py | 13 ++++++++-- pyproject.toml | 7 +++++ tests/test_dispatcher/test_dispatcher.py | 33 +++++++++++++++++++++--- 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 CHANGES/1162.bugfix.rst diff --git a/CHANGES/1162.bugfix.rst b/CHANGES/1162.bugfix.rst new file mode 100644 index 00000000..16d5be16 --- /dev/null +++ b/CHANGES/1162.bugfix.rst @@ -0,0 +1 @@ +Fixed compatibility with Python 3.8-3.9 diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index 8485d83c..9c61a447 100644 --- a/aiogram/dispatcher/dispatcher.py +++ b/aiogram/dispatcher/dispatcher.py @@ -92,8 +92,8 @@ class Dispatcher(Router): self.workflow_data: Dict[str, Any] = kwargs self._running_lock = Lock() - self._stop_signal = Event() - self._stopped_signal = Event() + self._stop_signal: Optional[Event] = None + self._stopped_signal: Optional[Event] = None def __getitem__(self, item: str) -> Any: return self.workflow_data[item] @@ -430,6 +430,8 @@ class Dispatcher(Router): """ if not self._running_lock.locked(): raise RuntimeError("Polling is not started") + if not self._stop_signal or not self._stopped_signal: + return self._stop_signal.set() await self._stopped_signal.wait() @@ -438,6 +440,8 @@ class Dispatcher(Router): return loggers.dispatcher.warning("Received %s signal", sig.name) + if not self._stop_signal: + return self._stop_signal.set() async def start_polling( @@ -473,6 +477,11 @@ class Dispatcher(Router): ) async with self._running_lock: # Prevent to run this method twice at a once + if self._stop_signal is None: + self._stop_signal = Event() + if self._stopped_signal is None: + self._stopped_signal = Event() + self._stop_signal.clear() self._stopped_signal.clear() diff --git a/pyproject.toml b/pyproject.toml index 5bf6abab..cf0f81ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -151,6 +151,13 @@ extra-dependencies = [ "butcher @ git+https://github.com/aiogram/butcher.git@v0.1.14" ] +[tool.hatch.envs.dev.scripts] +update = [ + "butcher parse", + "butcher refresh", + "butcher apply all", +] + [tool.hatch.envs.test] features = [ "fast", diff --git a/tests/test_dispatcher/test_dispatcher.py b/tests/test_dispatcher/test_dispatcher.py index 4fb2b113..bcebfaa2 100644 --- a/tests/test_dispatcher/test_dispatcher.py +++ b/tests/test_dispatcher/test_dispatcher.py @@ -708,10 +708,15 @@ class TestDispatcher: with pytest.raises(RuntimeError): await dispatcher.stop_polling() - assert not dispatcher._stop_signal.is_set() - assert not dispatcher._stopped_signal.is_set() + assert not dispatcher._stop_signal + assert not dispatcher._stopped_signal with patch("asyncio.locks.Event.wait", new_callable=AsyncMock) as mocked_wait: async with dispatcher._running_lock: + await dispatcher.stop_polling() + assert not dispatcher._stop_signal + + dispatcher._stop_signal = Event() + dispatcher._stopped_signal = Event() await dispatcher.stop_polling() assert dispatcher._stop_signal.is_set() mocked_wait.assert_awaited() @@ -723,6 +728,11 @@ class TestDispatcher: mocked_set.assert_not_called() async with dispatcher._running_lock: + dispatcher._signal_stop_polling(signal.SIGINT) + mocked_set.assert_not_called() + + dispatcher._stop_signal = Event() + dispatcher._stopped_signal = Event() dispatcher._signal_stop_polling(signal.SIGINT) mocked_set.assert_called() @@ -764,12 +774,29 @@ class TestDispatcher: def test_run_polling(self, bot: MockedBot): dispatcher = Dispatcher() + + async def stop(): + await asyncio.sleep(0.5) + await dispatcher.stop_polling() + + start_called = False + + @dispatcher.startup() + async def startup(): + nonlocal start_called + start_called = True + asyncio.create_task(stop()) + + original_start_polling = dispatcher.start_polling with patch( - "aiogram.dispatcher.dispatcher.Dispatcher.start_polling" + "aiogram.dispatcher.dispatcher.Dispatcher.start_polling", + side_effect=original_start_polling, ) as patched_start_polling: dispatcher.run_polling(bot) patched_start_polling.assert_awaited_once() + assert start_called + async def test_feed_webhook_update_fast_process(self, bot: MockedBot): dispatcher = Dispatcher() dispatcher.message.register(simple_message_handler)