Skip to content

Commit

Permalink
Merge branch 'main' into clear-ts
Browse files Browse the repository at this point in the history
  • Loading branch information
kumaraditya303 authored Dec 18, 2024
2 parents 66bcb32 + dbd08fb commit 32486ae
Show file tree
Hide file tree
Showing 15 changed files with 168 additions and 44 deletions.
4 changes: 4 additions & 0 deletions Doc/library/asyncio-policy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ for the current process:

Return the current process-wide policy.

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

.. function:: set_event_loop_policy(policy)

Set the current process-wide policy to *policy*.
Expand Down
90 changes: 90 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,96 @@ asyncio
It now raises a :exc:`RuntimeError` if there is no current event loop.
(Contributed by Kumar Aditya in :gh:`126353`.)

There's a few patterns that use :func:`asyncio.get_event_loop`, most
of them can be replaced with :func:`asyncio.run`.

If you're running an async function, simply use :func:`asyncio.run`.

Before::

async def main():
...


loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
finally:
loop.close()

After::

async def main():
...

asyncio.run(main())

If you need to start something, e.g. a server listening on a socket
and then run forever, use :func:`asyncio.run` and an
:class:`asyncio.Event`.

Before::

def start_server(loop):
...

loop = asyncio.get_event_loop()
try:
start_server(loop)
loop.run_forever()
finally:
loop.close()

After::

def start_server(loop):
...

async def main():
start_server(asyncio.get_running_loop())
await asyncio.Event().wait()

asyncio.run(main())

If you need to run something in an event loop, then run some blocking
code around it, use :class:`asyncio.Runner`.

Before::

async def operation_one():
...

def blocking_code():
...

async def operation_two():
...

loop = asyncio.get_event_loop()
try:
loop.run_until_complete(operation_one())
blocking_code()
loop.run_until_complete(operation_two())
finally:
loop.close()

After::

async def operation_one():
...

def blocking_code():
...

async def operation_two():
...

with asyncio.Runner() as runner:
runner.run(operation_one())
blocking_code()
runner.run(operation_two())



collections.abc
---------------
Expand Down
14 changes: 9 additions & 5 deletions Lib/asyncio/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'AbstractEventLoopPolicy',
'AbstractEventLoop', 'AbstractServer',
'Handle', 'TimerHandle',
'_get_event_loop_policy',
'get_event_loop_policy',
'_set_event_loop_policy',
'set_event_loop_policy',
Expand Down Expand Up @@ -761,12 +762,15 @@ def _init_event_loop_policy():
_event_loop_policy = DefaultEventLoopPolicy()


def get_event_loop_policy():
def _get_event_loop_policy():
"""Get the current event loop policy."""
if _event_loop_policy is None:
_init_event_loop_policy()
return _event_loop_policy

def get_event_loop_policy():
warnings._deprecated('asyncio.get_event_loop_policy', remove=(3, 16))
return _get_event_loop_policy()

def _set_event_loop_policy(policy):
"""Set the current event loop policy.
Expand All @@ -778,7 +782,7 @@ def _set_event_loop_policy(policy):
_event_loop_policy = policy

def set_event_loop_policy(policy):
warnings._deprecated('set_event_loop_policy', remove=(3,16))
warnings._deprecated('asyncio.set_event_loop_policy', remove=(3,16))
_set_event_loop_policy(policy)

def get_event_loop():
Expand All @@ -794,17 +798,17 @@ def get_event_loop():
current_loop = _get_running_loop()
if current_loop is not None:
return current_loop
return get_event_loop_policy().get_event_loop()
return _get_event_loop_policy().get_event_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)
_get_event_loop_policy().set_event_loop(loop)


def new_event_loop():
"""Equivalent to calling get_event_loop_policy().new_event_loop()."""
return get_event_loop_policy().new_event_loop()
return _get_event_loop_policy().new_event_loop()


# Alias pure-Python implementations for testing purposes.
Expand Down
26 changes: 23 additions & 3 deletions Lib/tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,11 +437,19 @@ class _TemporaryFileCloser:
cleanup_called = False
close_called = False

def __init__(self, file, name, delete=True, delete_on_close=True):
def __init__(
self,
file,
name,
delete=True,
delete_on_close=True,
warn_message="Implicitly cleaning up unknown file",
):
self.file = file
self.name = name
self.delete = delete
self.delete_on_close = delete_on_close
self.warn_message = warn_message

def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink):
if not self.cleanup_called:
Expand Down Expand Up @@ -469,7 +477,10 @@ def close(self):
self.cleanup()

def __del__(self):
close_called = self.close_called
self.cleanup()
if not close_called:
_warnings.warn(self.warn_message, ResourceWarning)


class _TemporaryFileWrapper:
Expand All @@ -483,8 +494,17 @@ class _TemporaryFileWrapper:
def __init__(self, file, name, delete=True, delete_on_close=True):
self.file = file
self.name = name
self._closer = _TemporaryFileCloser(file, name, delete,
delete_on_close)
self._closer = _TemporaryFileCloser(
file,
name,
delete,
delete_on_close,
warn_message=f"Implicitly cleaning up {self!r}",
)

def __repr__(self):
file = self.__dict__['file']
return f"<{type(self).__name__} {file=}>"

def __getattr__(self, name):
# Attribute lookups are delegated to the underlying file
Expand Down
29 changes: 18 additions & 11 deletions Lib/test/test_asyncio/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2397,7 +2397,7 @@ def test_handle_repr_debug(self):
self.assertRegex(repr(h), regex)

def test_handle_source_traceback(self):
loop = asyncio.get_event_loop_policy().new_event_loop()
loop = asyncio.new_event_loop()
loop.set_debug(True)
self.set_event_loop(loop)

Expand Down Expand Up @@ -2759,24 +2759,31 @@ def test_set_event_loop(self):
old_loop.close()

def test_get_event_loop_policy(self):
policy = asyncio.get_event_loop_policy()
self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy)
self.assertIs(policy, asyncio.get_event_loop_policy())
with self.assertWarnsRegex(
DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"):
policy = asyncio.get_event_loop_policy()
self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy)
self.assertIs(policy, asyncio.get_event_loop_policy())

def test_set_event_loop_policy(self):
with self.assertWarnsRegex(
DeprecationWarning, "'set_event_loop_policy' is deprecated"):
DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"):
self.assertRaises(
TypeError, asyncio.set_event_loop_policy, object())

old_policy = asyncio.get_event_loop_policy()
with self.assertWarnsRegex(
DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"):
old_policy = asyncio.get_event_loop_policy()

policy = asyncio.DefaultEventLoopPolicy()
with self.assertWarnsRegex(
DeprecationWarning, "'set_event_loop_policy' is deprecated"):
DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"):
asyncio.set_event_loop_policy(policy)
self.assertIs(policy, asyncio.get_event_loop_policy())
self.assertIsNot(policy, old_policy)

with self.assertWarnsRegex(
DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"):
self.assertIs(policy, asyncio.get_event_loop_policy())
self.assertIsNot(policy, old_policy)


class GetEventLoopTestsMixin:
Expand Down Expand Up @@ -2859,7 +2866,7 @@ class Policy(asyncio.DefaultEventLoopPolicy):
def get_event_loop(self):
raise TestError

old_policy = asyncio.get_event_loop_policy()
old_policy = asyncio._get_event_loop_policy()
try:
asyncio._set_event_loop_policy(Policy())
loop = asyncio.new_event_loop()
Expand Down Expand Up @@ -2899,7 +2906,7 @@ async def func():
self.assertIs(asyncio._get_running_loop(), None)

def test_get_event_loop_returns_running_loop2(self):
old_policy = asyncio.get_event_loop_policy()
old_policy = asyncio._get_event_loop_policy()
try:
asyncio._set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
loop = asyncio.new_event_loop()
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/test_asyncio/test_runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def setUp(self):
asyncio._set_event_loop_policy(policy)

def tearDown(self):
policy = asyncio.get_event_loop_policy()
policy = asyncio._get_event_loop_policy()
if policy.loop is not None:
self.assertTrue(policy.loop.is_closed())
self.assertTrue(policy.loop.shutdown_ag_run)
Expand Down Expand Up @@ -208,7 +208,7 @@ async def main():
await asyncio.sleep(0)
return 42

policy = asyncio.get_event_loop_policy()
policy = asyncio._get_event_loop_policy()
policy.set_event_loop = mock.Mock()
asyncio.run(main())
self.assertTrue(policy.set_event_loop.called)
Expand Down Expand Up @@ -495,7 +495,7 @@ def test_set_event_loop_called_once(self):
async def coro():
pass

policy = asyncio.get_event_loop_policy()
policy = asyncio._get_event_loop_policy()
policy.set_event_loop = mock.Mock()
runner = asyncio.Runner()
runner.run(coro())
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_asyncio/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,7 @@ class SubprocessWatcherMixin(SubprocessMixin):

def setUp(self):
super().setUp()
policy = asyncio.get_event_loop_policy()
self.loop = policy.new_event_loop()
self.loop = asyncio.new_event_loop()
self.set_event_loop(self.loop)

def test_watcher_implementation(self):
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/test_windows_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ async def main():
asyncio.get_running_loop(),
asyncio.SelectorEventLoop)

old_policy = asyncio.get_event_loop_policy()
old_policy = asyncio._get_event_loop_policy()
try:
asyncio._set_event_loop_policy(
asyncio.WindowsSelectorEventLoopPolicy())
Expand All @@ -346,7 +346,7 @@ async def main():
asyncio.get_running_loop(),
asyncio.ProactorEventLoop)

old_policy = asyncio.get_event_loop_policy()
old_policy = asyncio._get_event_loop_policy()
try:
asyncio._set_event_loop_policy(
asyncio.WindowsProactorEventLoopPolicy())
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_contextlib_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ class TestAsyncExitStack(TestBaseExitStack, unittest.IsolatedAsyncioTestCase):
class SyncAsyncExitStack(AsyncExitStack):
@staticmethod
def run_coroutine(coro):
loop = asyncio.get_event_loop_policy().get_event_loop()
loop = asyncio.new_event_loop()
t = loop.create_task(coro)
t.add_done_callback(lambda f: loop.stop())
loop.run_forever()
Expand Down
17 changes: 5 additions & 12 deletions Lib/test/test_ctypes/test_dlerror.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,20 @@ def configure_locales(func):
@classmethod
def setUpClass(cls):
cls.libc_filename = find_library("c")
if cls.libc_filename is None:
raise unittest.SkipTest('cannot find libc')

@configure_locales
def test_localized_error_from_dll(self):
dll = CDLL(self.libc_filename)
with self.assertRaises(AttributeError) as cm:
with self.assertRaises(AttributeError):
dll.this_name_does_not_exist
if sys.platform.startswith('linux'):
# On macOS, the filename is not reported by dlerror().
self.assertIn(self.libc_filename, str(cm.exception))

@configure_locales
def test_localized_error_in_dll(self):
dll = CDLL(self.libc_filename)
with self.assertRaises(ValueError) as cm:
with self.assertRaises(ValueError):
c_int.in_dll(dll, 'this_name_does_not_exist')
if sys.platform.startswith('linux'):
# On macOS, the filename is not reported by dlerror().
self.assertIn(self.libc_filename, str(cm.exception))

@unittest.skipUnless(hasattr(_ctypes, 'dlopen'),
'test requires _ctypes.dlopen()')
Expand All @@ -172,11 +168,8 @@ def test_localized_error_dlopen(self):
@configure_locales
def test_localized_error_dlsym(self):
dll = _ctypes.dlopen(self.libc_filename)
with self.assertRaises(OSError) as cm:
with self.assertRaises(OSError):
_ctypes.dlsym(dll, 'this_name_does_not_exist')
if sys.platform.startswith('linux'):
# On macOS, the filename is not reported by dlerror().
self.assertIn(self.libc_filename, str(cm.exception))


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit 32486ae

Please sign in to comment.