◐ Shell
reader mode source ↗
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
22 changes: 14 additions & 8 deletions Doc/library/asyncio-eventloop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ an event loop:

Get the current event loop.

If there is no current event loop set in the current OS thread,
the OS thread is main, and :func:`set_event_loop` has not yet
been called, asyncio will create a new event loop and set it as the
current one.

Because this function has rather complex behavior (especially
when custom event loop policies are in use), using the
Expand All @@ -58,10 +60,14 @@ an event loop:
event loop.

.. deprecated:: 3.10
Emits a deprecation warning if there is no running event loop.
In future Python releases, this function may become an alias of
:func:`get_running_loop` and will accordingly raise a
:exc:`RuntimeError` if there is no running event loop.

.. function:: set_event_loop(loop)

Expand Down
2 changes: 1 addition & 1 deletion Doc/library/asyncio-llapi-index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Obtaining the Event Loop
- The **preferred** function to get the running event loop.

* - :func:`asyncio.get_event_loop`
- Get an event loop instance (current or via the policy).

* - :func:`asyncio.set_event_loop`
- Set the event loop as current via the current policy.
Expand Down
5 changes: 5 additions & 0 deletions Doc/library/asyncio-policy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ asyncio ships with the following built-in policies:

On Windows, :class:`ProactorEventLoop` is now used by default.


.. class:: WindowsSelectorEventLoopPolicy

Expand Down
22 changes: 19 additions & 3 deletions Lib/asyncio/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,21 @@ def get_event_loop(self):
if (self._local._loop is None and
not self._local._set_called and
threading.current_thread() is threading.main_thread()):
self.set_event_loop(self.new_event_loop())

if self._local._loop is None:
Expand Down Expand Up @@ -763,12 +778,13 @@ def get_event_loop():


def _get_event_loop(stacklevel=3):
current_loop = _get_running_loop()
if current_loop is not None:
return current_loop
import warnings
warnings.warn('There is no current event loop',
DeprecationWarning, stacklevel=stacklevel)
return get_event_loop_policy().get_event_loop()


2 changes: 1 addition & 1 deletion Lib/test/test_asyncio/test_base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ async def coro():
def test_env_var_debug(self):
code = '\n'.join((
'import asyncio',
'loop = asyncio.get_event_loop()',
'print(loop.get_debug())'))

# Test with -E to not fail if the unit test was run with
Expand Down
54 changes: 22 additions & 32 deletions Lib/test/test_asyncio/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2561,8 +2561,9 @@ def test_event_loop_policy(self):
def test_get_event_loop(self):
policy = asyncio.DefaultEventLoopPolicy()
self.assertIsNone(policy._local._loop)

loop = policy.get_event_loop()
self.assertIsInstance(loop, asyncio.AbstractEventLoop)

self.assertIs(policy._local._loop, loop)
Expand All @@ -2576,7 +2577,10 @@ def test_get_event_loop_calls_set_event_loop(self):
policy, "set_event_loop",
wraps=policy.set_event_loop) as m_set_event_loop:

loop = policy.get_event_loop()

# policy._local._loop must be set through .set_event_loop()
# (the unix DefaultEventLoopPolicy needs this call to attach
Expand Down Expand Up @@ -2610,7 +2614,8 @@ def test_new_event_loop(self):

def test_set_event_loop(self):
policy = asyncio.DefaultEventLoopPolicy()
old_loop = policy.get_event_loop()

self.assertRaises(AssertionError, policy.set_event_loop, object())

Expand Down Expand Up @@ -2723,15 +2728,11 @@ def get_event_loop(self):
asyncio.set_event_loop_policy(Policy())
loop = asyncio.new_event_loop()

with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaises(TestError):
asyncio.get_event_loop()
self.assertEqual(cm.warnings[0].filename, __file__)
asyncio.set_event_loop(None)
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaises(TestError):
asyncio.get_event_loop()
self.assertEqual(cm.warnings[0].filename, __file__)

with self.assertRaisesRegex(RuntimeError, 'no running'):
asyncio.get_running_loop()
Expand All @@ -2745,16 +2746,11 @@ async def func():
loop.run_until_complete(func())

asyncio.set_event_loop(loop)
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaises(TestError):
asyncio.get_event_loop()
self.assertEqual(cm.warnings[0].filename, __file__)

asyncio.set_event_loop(None)
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaises(TestError):
asyncio.get_event_loop()
self.assertEqual(cm.warnings[0].filename, __file__)

finally:
asyncio.set_event_loop_policy(old_policy)
Expand All @@ -2778,10 +2774,8 @@ def test_get_event_loop_returns_running_loop2(self):
self.addCleanup(loop2.close)
self.assertEqual(cm.warnings[0].filename, __file__)
asyncio.set_event_loop(None)
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaisesRegex(RuntimeError, 'no current'):
asyncio.get_event_loop()
self.assertEqual(cm.warnings[0].filename, __file__)

with self.assertRaisesRegex(RuntimeError, 'no running'):
asyncio.get_running_loop()
Expand All @@ -2795,15 +2789,11 @@ async def func():
loop.run_until_complete(func())

asyncio.set_event_loop(loop)
with self.assertWarns(DeprecationWarning) as cm:
self.assertIs(asyncio.get_event_loop(), loop)
self.assertEqual(cm.warnings[0].filename, __file__)

asyncio.set_event_loop(None)
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaisesRegex(RuntimeError, 'no current'):
asyncio.get_event_loop()
self.assertEqual(cm.warnings[0].filename, __file__)

finally:
asyncio.set_event_loop_policy(old_policy)
Expand Down
24 changes: 8 additions & 16 deletions Lib/test/test_asyncio/test_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,8 @@ def test_initial_state(self):
self.assertTrue(f.cancelled())

def test_constructor_without_loop(self):
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaisesRegex(RuntimeError, 'There is no current event loop'):
self._new_future()
self.assertEqual(cm.warnings[0].filename, __file__)

def test_constructor_use_running_loop(self):
async def test():
@@ -158,12 +156,10 @@ async def test():
self.assertIs(f.get_loop(), self.loop)

def test_constructor_use_global_loop(self):
# Deprecated in 3.10
asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio.set_event_loop, None)
with self.assertWarns(DeprecationWarning) as cm:
f = self._new_future()
self.assertEqual(cm.warnings[0].filename, __file__)
self.assertIs(f._loop, self.loop)
self.assertIs(f.get_loop(), self.loop)

@@ -499,10 +495,8 @@ def run(arg):
return (arg, threading.get_ident())
ex = concurrent.futures.ThreadPoolExecutor(1)
f1 = ex.submit(run, 'oi')
with self.assertWarns(DeprecationWarning) as cm:
with self.assertRaises(RuntimeError):
asyncio.wrap_future(f1)
self.assertEqual(cm.warnings[0].filename, __file__)
ex.shutdown(wait=True)

def test_wrap_future_use_running_loop(self):
Expand All @@ -517,16 +511,14 @@ async def test():
ex.shutdown(wait=True)

def test_wrap_future_use_global_loop(self):
# Deprecated in 3.10
asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio.set_event_loop, None)
def run(arg):
return (arg, threading.get_ident())
ex = concurrent.futures.ThreadPoolExecutor(1)
f1 = ex.submit(run, 'oi')
with self.assertWarns(DeprecationWarning) as cm:
f2 = asyncio.wrap_future(f1)
self.assertEqual(cm.warnings[0].filename, __file__)
self.assertIs(self.loop, f2._loop)
ex.shutdown(wait=True)

Expand Down
Loading
Toggle all file notes Toggle all file annotations