Skip to content

Commit

Permalink
gh-127949: deprecate asyncio.set_event_loop (#128218)
Browse files Browse the repository at this point in the history
Deprecate `asyncio.set_event_loop` to be removed in Python 3.16.
  • Loading branch information
kumaraditya303 authored Dec 24, 2024
1 parent 3ddd70c commit 9fce906
Show file tree
Hide file tree
Showing 16 changed files with 77 additions and 55 deletions.
4 changes: 4 additions & 0 deletions Doc/library/asyncio-eventloop.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ an event loop:

Set *loop* as the current event loop for the current OS thread.

.. deprecated:: next
The :func:`set_event_loop` function is deprecated and will be removed
in Python 3.16.

.. function:: new_event_loop()

Create and return a new event loop object.
Expand Down
2 changes: 1 addition & 1 deletion Lib/asyncio/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def interrupt(self) -> None:

return_code = 0
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
asyncio._set_event_loop(loop)

repl_locals = {'asyncio': asyncio}
for key in {'__name__', '__package__',
Expand Down
32 changes: 21 additions & 11 deletions Lib/asyncio/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@
# SPDX-FileCopyrightText: Copyright (c) 2015-2021 MagicStack Inc. http://magic.io

__all__ = (
'_AbstractEventLoopPolicy',
'AbstractEventLoop', 'AbstractServer',
'Handle', 'TimerHandle',
'_get_event_loop_policy',
'get_event_loop_policy',
'_set_event_loop_policy',
'set_event_loop_policy',
'get_event_loop', 'set_event_loop', 'new_event_loop',
'_set_running_loop', 'get_running_loop',
'_get_running_loop',
"_AbstractEventLoopPolicy",
"AbstractEventLoop",
"AbstractServer",
"Handle",
"TimerHandle",
"_get_event_loop_policy",
"get_event_loop_policy",
"_set_event_loop_policy",
"set_event_loop_policy",
"get_event_loop",
"_set_event_loop",
"set_event_loop",
"new_event_loop",
"_set_running_loop",
"get_running_loop",
"_get_running_loop",
)

import contextvars
Expand Down Expand Up @@ -801,9 +807,13 @@ def get_event_loop():
return _get_event_loop_policy().get_event_loop()


def _set_event_loop(loop):
_get_event_loop_policy().set_event_loop(loop)

def set_event_loop(loop):
"""Equivalent to calling get_event_loop_policy().set_event_loop(loop)."""
_get_event_loop_policy().set_event_loop(loop)
warnings._deprecated('asyncio.set_event_loop', remove=(3,16))
_set_event_loop(loop)


def new_event_loop():
Expand Down
4 changes: 2 additions & 2 deletions Lib/asyncio/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def close(self):
loop.shutdown_default_executor(constants.THREAD_JOIN_TIMEOUT))
finally:
if self._set_event_loop:
events.set_event_loop(None)
events._set_event_loop(None)
loop.close()
self._loop = None
self._state = _State.CLOSED
Expand Down Expand Up @@ -147,7 +147,7 @@ def _lazy_init(self):
if not self._set_event_loop:
# Call set_event_loop only once to avoid calling
# attach_loop multiple times on child watchers
events.set_event_loop(self._loop)
events._set_event_loop(self._loop)
self._set_event_loop = True
else:
self._loop = self._loop_factory()
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_asyncgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ class AsyncGenAsyncioTest(unittest.TestCase):

def setUp(self):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)

def tearDown(self):
self.loop.close()
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def loop_exception_handler(self, loop, context):

def setUp(self):
self.loop = self.new_loop()
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)

self.loop.set_exception_handler(self.loop_exception_handler)
self.__unhandled_exceptions = []
Expand All @@ -39,7 +39,7 @@ def tearDown(self):
self.fail('unexpected calls to loop.call_exception_handler()')

finally:
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
self.loop = None

def tcp_server(self, server_prog, *,
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_asyncio/test_base_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ def check_in_thread(loop, event, debug, create_loop, fut):
if create_loop:
loop2 = base_events.BaseEventLoop()
try:
asyncio.set_event_loop(loop2)
asyncio._set_event_loop(loop2)
self.check_thread(loop, debug)
finally:
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
loop2.close()
else:
self.check_thread(loop, debug)
Expand Down Expand Up @@ -690,7 +690,7 @@ def default_exception_handler(self, context):

loop = Loop()
self.addCleanup(loop.close)
asyncio.set_event_loop(loop)
asyncio._set_event_loop(loop)

def run_loop():
def zero_error():
Expand Down Expand Up @@ -1983,7 +1983,7 @@ def stop_loop_cb(loop):
async def stop_loop_coro(loop):
loop.stop()

asyncio.set_event_loop(self.loop)
asyncio._set_event_loop(self.loop)
self.loop.set_debug(True)
self.loop.slow_callback_duration = 0.0

Expand Down
26 changes: 17 additions & 9 deletions Lib/test/test_asyncio/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async def doit():
return 'hello'

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
asyncio._set_event_loop(loop)
return loop.run_until_complete(doit())


Expand Down Expand Up @@ -2695,6 +2695,14 @@ async def inner():

class PolicyTests(unittest.TestCase):

def test_asyncio_set_event_loop_deprecation(self):
with self.assertWarnsRegex(
DeprecationWarning, "'asyncio.set_event_loop' is deprecated"):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
self.assertIs(loop, asyncio.get_event_loop())
loop.close()

def test_abstract_event_loop_policy_deprecation(self):
with self.assertWarnsRegex(
DeprecationWarning, "'asyncio.AbstractEventLoopPolicy' is deprecated"):
Expand Down Expand Up @@ -2824,14 +2832,14 @@ def setUp(self):
super().setUp()

self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
asyncio._set_event_loop(self.loop)

def tearDown(self):
try:
super().tearDown()
finally:
self.loop.close()
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)

events._get_running_loop = self._get_running_loop_saved
events._set_running_loop = self._set_running_loop_saved
Expand Down Expand Up @@ -2885,7 +2893,7 @@ def get_event_loop(self):

with self.assertRaises(TestError):
asyncio.get_event_loop()
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
with self.assertRaises(TestError):
asyncio.get_event_loop()

Expand All @@ -2900,10 +2908,10 @@ async def func():

loop.run_until_complete(func())

asyncio.set_event_loop(loop)
asyncio._set_event_loop(loop)
with self.assertRaises(TestError):
asyncio.get_event_loop()
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
with self.assertRaises(TestError):
asyncio.get_event_loop()

Expand All @@ -2927,7 +2935,7 @@ def test_get_event_loop_returns_running_loop2(self):
with self.assertRaisesRegex(RuntimeError, 'no current'):
asyncio.get_event_loop()

asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
with self.assertRaisesRegex(RuntimeError, 'no current'):
asyncio.get_event_loop()

Expand All @@ -2938,10 +2946,10 @@ async def func():

loop.run_until_complete(func())

asyncio.set_event_loop(loop)
asyncio._set_event_loop(loop)
self.assertIs(asyncio.get_event_loop(), loop)

asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
with self.assertRaisesRegex(RuntimeError, 'no current'):
asyncio.get_event_loop()

Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_asyncio/test_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ async def test():

def test_constructor_use_global_loop(self):
# Deprecated in 3.10, undeprecated in 3.12

This comment has been minimized.

Copy link
@graingert

graingert Dec 24, 2024

Contributor

This comment seems outdated

asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio.set_event_loop, None)
asyncio._set_event_loop(self.loop)
self.addCleanup(asyncio._set_event_loop, None)
f = self._new_future()
self.assertIs(f._loop, self.loop)
self.assertIs(f.get_loop(), self.loop)
Expand Down Expand Up @@ -566,8 +566,8 @@ async def test():

def test_wrap_future_use_global_loop(self):
# Deprecated in 3.10, undeprecated in 3.12
asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio.set_event_loop, None)
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)
Expand Down
10 changes: 5 additions & 5 deletions Lib/test/test_asyncio/test_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _basetest_open_connection_no_loop_ssl(self, open_connection_fut):
try:
reader, writer = self.loop.run_until_complete(open_connection_fut)
finally:
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)
writer.write(b'GET / HTTP/1.0\r\n\r\n')
f = reader.read()
data = self.loop.run_until_complete(f)
Expand Down Expand Up @@ -839,8 +839,8 @@ def test_streamreader_constructor_use_global_loop(self):
# asyncio issue #184: Ensure that StreamReaderProtocol constructor
# retrieves the current loop if the loop parameter is not set
# Deprecated in 3.10, undeprecated in 3.12
self.addCleanup(asyncio.set_event_loop, None)
asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio._set_event_loop, None)
asyncio._set_event_loop(self.loop)
reader = asyncio.StreamReader()
self.assertIs(reader._loop, self.loop)

Expand All @@ -863,8 +863,8 @@ def test_streamreaderprotocol_constructor_use_global_loop(self):
# asyncio issue #184: Ensure that StreamReaderProtocol constructor
# retrieves the current loop if the loop parameter is not set
# Deprecated in 3.10, undeprecated in 3.12
self.addCleanup(asyncio.set_event_loop, None)
asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio._set_event_loop, None)
asyncio._set_event_loop(self.loop)
reader = mock.Mock()
protocol = asyncio.StreamReaderProtocol(reader)
self.assertIs(protocol._loop, self.loop)
Expand Down
18 changes: 9 additions & 9 deletions Lib/test/test_asyncio/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ async def test():
self.assertEqual(t.result(), 'ok')

# Deprecated in 3.10, undeprecated in 3.12
asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio.set_event_loop, None)
asyncio._set_event_loop(self.loop)
self.addCleanup(asyncio._set_event_loop, None)
t = asyncio.ensure_future(notmuch())
self.assertIs(t._loop, self.loop)
self.loop.run_until_complete(t)
Expand Down Expand Up @@ -2202,8 +2202,8 @@ def test_shield_coroutine_use_global_loop(self):
async def coro():
return 42

asyncio.set_event_loop(self.loop)
self.addCleanup(asyncio.set_event_loop, None)
asyncio._set_event_loop(self.loop)
self.addCleanup(asyncio._set_event_loop, None)
outer = asyncio.shield(coro())
self.assertEqual(outer._loop, self.loop)
res = self.loop.run_until_complete(outer)
Expand Down Expand Up @@ -2273,7 +2273,7 @@ async def kill_me(loop):

self.assertEqual(self.all_tasks(loop=self.loop), {task})

asyncio.set_event_loop(None)
asyncio._set_event_loop(None)

# execute the task so it waits for future
self.loop._run_once()
Expand Down Expand Up @@ -3278,8 +3278,8 @@ async def gather():

def test_constructor_empty_sequence_use_global_loop(self):
# Deprecated in 3.10, undeprecated in 3.12
asyncio.set_event_loop(self.one_loop)
self.addCleanup(asyncio.set_event_loop, None)
asyncio._set_event_loop(self.one_loop)
self.addCleanup(asyncio._set_event_loop, None)
fut = asyncio.gather()
self.assertIsInstance(fut, asyncio.Future)
self.assertIs(fut._loop, self.one_loop)
Expand Down Expand Up @@ -3386,8 +3386,8 @@ def test_constructor_use_global_loop(self):
# Deprecated in 3.10, undeprecated in 3.12
async def coro():
return 'abc'
asyncio.set_event_loop(self.other_loop)
self.addCleanup(asyncio.set_event_loop, None)
asyncio._set_event_loop(self.other_loop)
self.addCleanup(asyncio._set_event_loop, None)
gen1 = coro()
gen2 = coro()
fut = asyncio.gather(gen1, gen2)
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/test_unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,11 +1116,11 @@ class TestFunctional(unittest.TestCase):

def setUp(self):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
asyncio._set_event_loop(self.loop)

def tearDown(self):
self.loop.close()
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)

def test_add_reader_invalid_argument(self):
def assert_raises():
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ def set_event_loop(self, loop, *, cleanup=True):
if loop is None:
raise AssertionError('loop is None')
# ensure that the event loop is passed explicitly in asyncio
events.set_event_loop(None)
events._set_event_loop(None)
if cleanup:
self.addCleanup(self.close_loop, loop)

Expand All @@ -554,7 +554,7 @@ def setUp(self):
self._thread_cleanup = threading_helper.threading_setup()

def tearDown(self):
events.set_event_loop(None)
events._set_event_loop(None)

# Detect CPython bug #23353: ensure that yield/yield-from is not used
# in an except block of a generator
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_coroutines.py
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,7 @@ async def f():
buffer.append('unreachable')

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
asyncio._set_event_loop(loop)
try:
loop.run_until_complete(f())
except MyException:
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@ async def coroutine[B]():

co = get_coroutine()

self.addCleanup(asyncio.set_event_loop_policy, None)
self.addCleanup(asyncio._set_event_loop_policy, None)
a, b = asyncio.run(co())

self.assertIsInstance(a, TypeVar)
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_unittest/test_async_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ async def cleanup(self, fut):
def test_setup_get_event_loop(self):
# See https://github.com/python/cpython/issues/95736
# Make sure the default event loop is not used
asyncio.set_event_loop(None)
asyncio._set_event_loop(None)

class TestCase1(unittest.IsolatedAsyncioTestCase):
def setUp(self):
Expand Down

0 comments on commit 9fce906

Please sign in to comment.