diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 14fd153f640f05..b5befa3c067d86 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -47,9 +47,6 @@ an event loop: call_soon or similar API), this function will always return the running event loop. - If there is no running event loop set, the function will return - the result of the ``get_event_loop_policy().get_event_loop()`` call. - Because this function has rather complex behavior (especially when custom event loop policies are in use), using the :func:`get_running_loop` function is preferred to :func:`get_event_loop` @@ -59,9 +56,8 @@ an event loop: instead of using these lower level functions to manually create and close an event loop. - .. deprecated:: 3.12 - Deprecation warning is emitted if there is no current event loop. - In some future Python release this will become an error. + .. versionchanged:: 3.14 + Raises a :exc:`RuntimeError` if there is no set event loop. .. function:: set_event_loop(loop) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 21bc289c2be5d8..f0f660b57a1e5b 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -576,6 +576,11 @@ asyncio (Contributed by Kumar Aditya in :gh:`120804`.) +* Removed implicit creation of event loop by :func:`asyncio.get_event_loop`. + It now raises a :exc:`RuntimeError` if there is no set event loop. + (Contributed by Kumar Aditya in :gh:`126353`.) + + collections.abc --------------- diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 5ba5be4cbbf817..1bf405e50f0592 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -2701,6 +2701,33 @@ def test_event_loop_policy(self): self.assertRaises(NotImplementedError, policy.set_event_loop, object()) self.assertRaises(NotImplementedError, policy.new_event_loop) + def test_get_event_loop(self): + policy = asyncio.DefaultEventLoopPolicy() + self.assertIsNone(policy._local._loop) + + with self.assertRaises(RuntimeError): + loop = policy.get_event_loop() + self.assertIsNone(policy._local._loop) + + loop = policy.new_event_loop() + self.assertIsNone(policy._local._loop) + policy.set_event_loop(loop) + self.assertIs(policy._local._loop, loop) + self.assertIs(loop, policy.get_event_loop()) + loop.close() + + def test_get_event_loop_does_not_call_set_event_loop(self): + policy = asyncio.DefaultEventLoopPolicy() + + with mock.patch.object( + policy, "set_event_loop", + wraps=policy.set_event_loop) as m_set_event_loop: + + with self.assertRaises(RuntimeError): + loop = policy.get_event_loop() + + m_set_event_loop.assert_not_called() + def test_get_event_loop_after_set_none(self): policy = asyncio.DefaultEventLoopPolicy() policy.set_event_loop(None) @@ -2881,6 +2908,7 @@ def test_get_event_loop_returns_running_loop2(self): loop = asyncio.new_event_loop() self.addCleanup(loop.close) + asyncio.set_event_loop(None) with self.assertRaisesRegex(RuntimeError, 'no current'): asyncio.get_event_loop()