From 90729cb814dbf2ddf4e49e3aff50be8763ebfda6 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Tue, 19 May 2026 13:15:29 +0530 Subject: [PATCH] remove asyncio policy system --- Doc/deprecations/pending-removal-in-3.16.rst | 24 --- Doc/library/asyncio-eventloop.rst | 17 +- Doc/library/asyncio-llapi-index.rst | 24 --- Doc/library/asyncio-policy.rst | 173 ------------------ Doc/library/asyncio-runner.rst | 10 +- Doc/library/asyncio.rst | 1 - Doc/whatsnew/3.14.rst | 12 +- Doc/whatsnew/3.16.rst | 11 ++ Lib/asyncio/__init__.py | 25 --- Lib/asyncio/events.py | 152 ++++----------- Lib/asyncio/unix_events.py | 6 - Lib/asyncio/windows_events.py | 13 +- Lib/test/libregrtest/save_env.py | 10 +- Lib/test/support/__init__.py | 6 +- Lib/test/test_asyncgen.py | 2 +- Lib/test/test_asyncio/test_base_events.py | 2 +- Lib/test/test_asyncio/test_buffered_proto.py | 2 +- Lib/test/test_asyncio/test_context.py | 2 +- .../test_asyncio/test_eager_task_factory.py | 2 +- Lib/test/test_asyncio/test_events.py | 160 ++++++---------- Lib/test/test_asyncio/test_free_threading.py | 2 +- Lib/test/test_asyncio/test_futures.py | 2 +- Lib/test/test_asyncio/test_futures2.py | 2 +- Lib/test/test_asyncio/test_graph.py | 2 +- Lib/test/test_asyncio/test_locks.py | 2 +- Lib/test/test_asyncio/test_pep492.py | 2 +- Lib/test/test_asyncio/test_proactor_events.py | 2 +- Lib/test/test_asyncio/test_protocols.py | 2 +- Lib/test/test_asyncio/test_queues.py | 2 +- Lib/test/test_asyncio/test_runners.py | 101 +++++----- Lib/test/test_asyncio/test_selector_events.py | 2 +- Lib/test/test_asyncio/test_sendfile.py | 2 +- Lib/test/test_asyncio/test_server.py | 2 +- Lib/test/test_asyncio/test_server_context.py | 2 +- Lib/test/test_asyncio/test_sock_lowlevel.py | 2 +- Lib/test/test_asyncio/test_ssl.py | 5 +- Lib/test/test_asyncio/test_sslproto.py | 2 +- Lib/test/test_asyncio/test_staggered.py | 2 +- Lib/test/test_asyncio/test_streams.py | 2 +- Lib/test/test_asyncio/test_subprocess.py | 2 +- Lib/test/test_asyncio/test_taskgroups.py | 2 +- Lib/test/test_asyncio/test_tasks.py | 2 +- Lib/test/test_asyncio/test_threads.py | 2 +- Lib/test/test_asyncio/test_timeouts.py | 2 +- Lib/test/test_asyncio/test_transports.py | 2 +- Lib/test/test_asyncio/test_unix_events.py | 2 +- Lib/test/test_asyncio/test_waitfor.py | 2 +- Lib/test/test_asyncio/test_windows_events.py | 37 +--- Lib/test/test_asyncio/test_windows_utils.py | 2 +- Lib/test/test_asyncio/utils.py | 6 - .../test_interpreter_pool.py | 14 +- Lib/test/test_coroutines.py | 2 +- Lib/test/test_inspect/test_inspect.py | 2 +- Lib/test/test_logging.py | 6 +- Lib/test/test_os/test_os.py | 2 +- Lib/test/test_pdb.py | 4 +- Lib/test/test_unittest/test_async_case.py | 8 +- Lib/test/test_unittest/testmock/testasync.py | 2 +- Lib/unittest/async_case.py | 10 +- ...-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst | 6 + Modules/_asynciomodule.c | 23 +-- Modules/clinic/_asynciomodule.c.h | 5 +- 62 files changed, 245 insertions(+), 694 deletions(-) delete mode 100644 Doc/library/asyncio-policy.rst create mode 100644 Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst index 7606daba16dcf8..be841699d4879f 100644 --- a/Doc/deprecations/pending-removal-in-3.16.rst +++ b/Doc/deprecations/pending-removal-in-3.16.rst @@ -23,30 +23,6 @@ Pending removal in Python 3.16 use :func:`inspect.iscoroutinefunction` instead. (Contributed by Jiahao Li and Kumar Aditya in :gh:`122875`.) - * :mod:`asyncio` policy system is deprecated and will be removed in Python 3.16. - In particular, the following classes and functions are deprecated: - - * :class:`asyncio.AbstractEventLoopPolicy` - * :class:`asyncio.DefaultEventLoopPolicy` - * :class:`asyncio.WindowsSelectorEventLoopPolicy` - * :class:`asyncio.WindowsProactorEventLoopPolicy` - * :func:`asyncio.get_event_loop_policy` - * :func:`asyncio.set_event_loop_policy` - - Users should use :func:`asyncio.run` or :class:`asyncio.Runner` with - *loop_factory* to use the desired event loop implementation. - - For example, to use :class:`asyncio.SelectorEventLoop` on Windows:: - - import asyncio - - async def main(): - ... - - asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop) - - (Contributed by Kumar Aditya in :gh:`127949`.) - * :mod:`builtins`: * Bitwise inversion on boolean types, ``~True`` or ``~False`` diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 79c9516cda2d60..65bc349e2a727d 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -48,10 +48,10 @@ an event loop: 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. + the loop set by :func:`set_event_loop`, or raise a :exc:`RuntimeError` + if no loop has been set. - Because this function has rather complex behavior (especially - when custom event loop policies are in use), using the + Because this function has rather complex behavior, using the :func:`get_running_loop` function is preferred to :func:`get_event_loop` in coroutines and callbacks. @@ -62,13 +62,6 @@ an event loop: .. versionchanged:: 3.14 Raises a :exc:`RuntimeError` if there is no current event loop. - .. note:: - - The :mod:`!asyncio` policy system is deprecated and will be removed - in Python 3.16; from there on, this function will return the current - running event loop if present else it will return the - loop set by :func:`set_event_loop`. - .. function:: set_event_loop(loop) Set *loop* as the current event loop for the current OS thread. @@ -77,10 +70,6 @@ an event loop: Create and return a new event loop object. -Note that the behaviour of :func:`get_event_loop`, :func:`set_event_loop`, -and :func:`new_event_loop` functions can be altered by -:ref:`setting a custom event loop policy `. - .. rubric:: Contents diff --git a/Doc/library/asyncio-llapi-index.rst b/Doc/library/asyncio-llapi-index.rst index f5af888f31f186..48849c78b82e8e 100644 --- a/Doc/library/asyncio-llapi-index.rst +++ b/Doc/library/asyncio-llapi-index.rst @@ -497,27 +497,3 @@ Protocol classes can implement the following **callback methods**: - Called when the child process has exited. It can be called before :meth:`~SubprocessProtocol.pipe_data_received` and :meth:`~SubprocessProtocol.pipe_connection_lost` methods. - - -Event Loop Policies -=================== - -Policies is a low-level mechanism to alter the behavior of -functions like :func:`asyncio.get_event_loop`. See also -the main :ref:`policies section ` for more -details. - - -.. rubric:: Accessing Policies -.. list-table:: - :widths: 50 50 - :class: full-width-table - - * - :meth:`asyncio.get_event_loop_policy` - - Return the current process-wide policy. - - * - :meth:`asyncio.set_event_loop_policy` - - Set a new process-wide policy. - - * - :class:`AbstractEventLoopPolicy` - - Base class for policy objects. diff --git a/Doc/library/asyncio-policy.rst b/Doc/library/asyncio-policy.rst deleted file mode 100644 index 57f964912dd6ea..00000000000000 --- a/Doc/library/asyncio-policy.rst +++ /dev/null @@ -1,173 +0,0 @@ -.. currentmodule:: asyncio - - -.. _asyncio-policies: - -======== -Policies -======== - -.. warning:: - - Policies are deprecated and will be removed in Python 3.16. - Users are encouraged to use the :func:`asyncio.run` function - or the :class:`asyncio.Runner` with *loop_factory* to use - the desired loop implementation. - - -An event loop policy is a global object -used to get and set the current :ref:`event loop `, -as well as create new event loops. -The default policy can be :ref:`replaced ` with -:ref:`built-in alternatives ` -to use different event loop implementations, -or substituted by a :ref:`custom policy ` -that can override these behaviors. - -The :ref:`policy object ` -gets and sets a separate event loop per *context*. -This is per-thread by default, -though custom policies could define *context* differently. - -Custom event loop policies can control the behavior of -:func:`get_event_loop`, :func:`set_event_loop`, and :func:`new_event_loop`. - -Policy objects should implement the APIs defined -in the :class:`AbstractEventLoopPolicy` abstract base class. - - -.. _asyncio-policy-get-set: - -Getting and Setting the Policy -============================== - -The following functions can be used to get and set the policy -for the current process: - -.. function:: get_event_loop_policy() - - Return the current process-wide policy. - - .. deprecated:: 3.14 - 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*. - - If *policy* is set to ``None``, the default policy is restored. - - .. deprecated:: 3.14 - The :func:`set_event_loop_policy` function is deprecated and - will be removed in Python 3.16. - - -.. _asyncio-policy-objects: - -Policy Objects -============== - -The abstract event loop policy base class is defined as follows: - -.. class:: AbstractEventLoopPolicy - - An abstract base class for asyncio policies. - - .. method:: get_event_loop() - - Get the event loop for the current context. - - Return an event loop object implementing the - :class:`AbstractEventLoop` interface. - - This method should never return ``None``. - - .. versionchanged:: 3.6 - - .. method:: set_event_loop(loop) - - Set the event loop for the current context to *loop*. - - .. method:: new_event_loop() - - Create and return a new event loop object. - - This method should never return ``None``. - - .. deprecated:: 3.14 - The :class:`AbstractEventLoopPolicy` class is deprecated and - will be removed in Python 3.16. - - -.. _asyncio-policy-builtin: - -asyncio ships with the following built-in policies: - - -.. class:: DefaultEventLoopPolicy - - The default asyncio policy. Uses :class:`SelectorEventLoop` - on Unix and :class:`ProactorEventLoop` on Windows. - - There is no need to install the default policy manually. asyncio - is configured to use the default policy automatically. - - .. versionchanged:: 3.8 - - On Windows, :class:`ProactorEventLoop` is now used by default. - - .. versionchanged:: 3.14 - The :meth:`get_event_loop` method of the default asyncio policy now - raises a :exc:`RuntimeError` if there is no set event loop. - - .. deprecated:: 3.14 - The :class:`DefaultEventLoopPolicy` class is deprecated and - will be removed in Python 3.16. - - -.. class:: WindowsSelectorEventLoopPolicy - - An alternative event loop policy that uses the - :class:`SelectorEventLoop` event loop implementation. - - .. availability:: Windows. - - .. deprecated:: 3.14 - The :class:`WindowsSelectorEventLoopPolicy` class is deprecated and - will be removed in Python 3.16. - - -.. class:: WindowsProactorEventLoopPolicy - - An alternative event loop policy that uses the - :class:`ProactorEventLoop` event loop implementation. - - .. availability:: Windows. - - .. deprecated:: 3.14 - The :class:`WindowsProactorEventLoopPolicy` class is deprecated and - will be removed in Python 3.16. - - -.. _asyncio-custom-policies: - -Custom Policies -=============== - -To implement a new event loop policy, it is recommended to subclass -:class:`DefaultEventLoopPolicy` and override the methods for which -custom behavior is wanted, e.g.:: - - class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy): - - def get_event_loop(self): - """Get the event loop. - - This may be None or an instance of EventLoop. - """ - loop = super().get_event_loop() - # Do something with loop ... - return loop - - asyncio.set_event_loop_policy(MyEventLoopPolicy()) diff --git a/Doc/library/asyncio-runner.rst b/Doc/library/asyncio-runner.rst index 48d78099fd3ce7..cd125b30703c79 100644 --- a/Doc/library/asyncio-runner.rst +++ b/Doc/library/asyncio-runner.rst @@ -43,9 +43,7 @@ Running an asyncio Program otherwise :func:`asyncio.new_event_loop` is used. The loop is closed at the end. This function should be used as a main entry point for asyncio programs, and should ideally only be called once. It is recommended to use - *loop_factory* to configure the event loop instead of policies. - Passing :class:`asyncio.EventLoop` allows running asyncio without the - policy system. + *loop_factory* to configure the event loop. The executor is given a timeout duration of 5 minutes to shutdown. If the executor hasn't finished within that duration, a warning is @@ -76,12 +74,6 @@ Running an asyncio Program *coro* can be any awaitable object. - .. note:: - - The :mod:`!asyncio` policy system is deprecated and will be removed - in Python 3.16; from there on, an explicit *loop_factory* is needed - to configure the event loop. - Runner context manager ====================== diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index 0f72e31dee5f1d..deb97a20234b55 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -117,7 +117,6 @@ for full functionality and the latest features. asyncio-eventloop.rst asyncio-future.rst asyncio-protocol.rst - asyncio-policy.rst asyncio-platforms.rst asyncio-extending.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 39d1d8da5367e5..f71fa0a14afa3c 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -2628,12 +2628,12 @@ New deprecations and will be removed in Python 3.16. In particular, the following classes and functions are deprecated: - * :class:`asyncio.AbstractEventLoopPolicy` - * :class:`asyncio.DefaultEventLoopPolicy` - * :class:`asyncio.WindowsSelectorEventLoopPolicy` - * :class:`asyncio.WindowsProactorEventLoopPolicy` - * :func:`asyncio.get_event_loop_policy` - * :func:`asyncio.set_event_loop_policy` + * :class:`!asyncio.AbstractEventLoopPolicy` + * :class:`!asyncio.DefaultEventLoopPolicy` + * :class:`!asyncio.WindowsSelectorEventLoopPolicy` + * :class:`!asyncio.WindowsProactorEventLoopPolicy` + * :func:`!asyncio.get_event_loop_policy` + * :func:`!asyncio.set_event_loop_policy` Users should use :func:`asyncio.run` or :class:`asyncio.Runner` with the *loop_factory* argument to use the desired event loop implementation. diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index cff0b8bbe32f0b..07db6bb9f2b134 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -121,6 +121,17 @@ asyncio which has been deprecated since Python 3.14. Use :func:`inspect.iscoroutinefunction` instead. +* The event loop policy system, including the + :class:`!asyncio.AbstractEventLoopPolicy`, + :class:`!asyncio.DefaultEventLoopPolicy`, + :class:`!asyncio.WindowsSelectorEventLoopPolicy` and + :class:`!asyncio.WindowsProactorEventLoopPolicy` classes and the + :func:`!asyncio.get_event_loop_policy` and + :func:`!asyncio.set_event_loop_policy` functions, + which have been deprecated since Python 3.14. + Use :func:`asyncio.run` or :class:`asyncio.Runner` with a custom + *loop_factory* instead. + functools --------- diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py index 32a5dbae03af21..2432e2dad74c23 100644 --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -47,28 +47,3 @@ else: from .unix_events import * # pragma: no cover __all__ += unix_events.__all__ - -def __getattr__(name: str): - import warnings - - match name: - case "AbstractEventLoopPolicy": - warnings._deprecated(f"asyncio.{name}", remove=(3, 16)) - return events._AbstractEventLoopPolicy - case "DefaultEventLoopPolicy": - warnings._deprecated(f"asyncio.{name}", remove=(3, 16)) - if sys.platform == 'win32': - return windows_events._DefaultEventLoopPolicy - return unix_events._DefaultEventLoopPolicy - case "WindowsSelectorEventLoopPolicy": - if sys.platform == 'win32': - warnings._deprecated(f"asyncio.{name}", remove=(3, 16)) - return windows_events._WindowsSelectorEventLoopPolicy - # Else fall through to the AttributeError below. - case "WindowsProactorEventLoopPolicy": - if sys.platform == 'win32': - warnings._deprecated(f"asyncio.{name}", remove=(3, 16)) - return windows_events._WindowsProactorEventLoopPolicy - # Else fall through to the AttributeError below. - - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index a7fb55982abe9c..c6655532ba2ccf 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -9,8 +9,6 @@ "AbstractServer", "Handle", "TimerHandle", - "get_event_loop_policy", - "set_event_loop_policy", "get_event_loop", "set_event_loop", "new_event_loop", @@ -26,7 +24,6 @@ import subprocess import sys import threading -import warnings from . import format_helpers @@ -662,84 +659,13 @@ def set_debug(self, enabled): raise NotImplementedError -class _AbstractEventLoopPolicy: - """Abstract policy for accessing the event loop.""" +# Each thread has its own event loop, set explicitly via set_event_loop(). +# A thread has no event loop by default. +class _Local(threading.local): + _loop = None - def get_event_loop(self): - """Get the event loop for the current context. - Returns an event loop object implementing the AbstractEventLoop interface, - or raises an exception in case no event loop has been set for the - current context and the current policy does not specify to create one. - - It should never return None.""" - raise NotImplementedError - - def set_event_loop(self, loop): - """Set the event loop for the current context to loop.""" - raise NotImplementedError - - def new_event_loop(self): - """Create and return a new event loop object according to this - policy's rules. If there's need to set this loop as the event loop for - the current context, set_event_loop must be called explicitly.""" - raise NotImplementedError - -class _BaseDefaultEventLoopPolicy(_AbstractEventLoopPolicy): - """Default policy implementation for accessing the event loop. - - In this policy, each thread has its own event loop. However, we - only automatically create an event loop by default for the main - thread; other threads by default have no event loop. - - Other policies may have different rules (e.g. a single global - event loop, or automatically creating an event loop per thread, or - using some other notion of context to which an event loop is - associated). - """ - - _loop_factory = None - - class _Local(threading.local): - _loop = None - - def __init__(self): - self._local = self._Local() - - def get_event_loop(self): - """Get the event loop for the current context. - - Returns an instance of EventLoop or raises an exception. - """ - if self._local._loop is None: - raise RuntimeError('There is no current event loop in thread %r.' - % threading.current_thread().name) - - return self._local._loop - - def set_event_loop(self, loop): - """Set the event loop.""" - if loop is not None and not isinstance(loop, AbstractEventLoop): - raise TypeError(f"loop must be an instance of AbstractEventLoop or None, not '{type(loop).__name__}'") - self._local._loop = loop - - def new_event_loop(self): - """Create a new event loop. - - You must call set_event_loop() to make this the current event - loop. - """ - return self._loop_factory() - - -# Event loop policy. The policy itself is always global, even if the -# policy's rules say that there is an event loop per thread (or other -# notion of context). The default policy is installed by the first -# call to get_event_loop_policy(). -_event_loop_policy = None - -# Lock for protecting the on-the-fly creation of the event loop policy. -_lock = threading.Lock() +_local = _Local() # A TLS for the running event loop, used by _get_running_loop. @@ -784,39 +710,19 @@ def _set_running_loop(loop): _running_loop.loop_pid = (loop, os.getpid()) -def _init_event_loop_policy(): - global _event_loop_policy - with _lock: - if _event_loop_policy is None: # pragma: no branch - if sys.platform == 'win32': - from .windows_events import _DefaultEventLoopPolicy - else: - from .unix_events import _DefaultEventLoopPolicy - _event_loop_policy = _DefaultEventLoopPolicy() - +def _get_event_loop(): + """Return the event loop set for the current thread. -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. - - If policy is None, the default policy is restored.""" - global _event_loop_policy - if policy is not None and not isinstance(policy, _AbstractEventLoopPolicy): - raise TypeError(f"policy must be an instance of AbstractEventLoopPolicy or None, not '{type(policy).__name__}'") - _event_loop_policy = policy + Raise a RuntimeError if no event loop has been set for the current + thread. This is the slow path of get_event_loop(); the running loop + is checked by the caller. + """ + loop = _local._loop + if loop is None: + raise RuntimeError('There is no current event loop in thread %r.' + % threading.current_thread().name) + return loop -def set_event_loop_policy(policy): - warnings._deprecated('asyncio.set_event_loop_policy', remove=(3,16)) - _set_event_loop_policy(policy) def get_event_loop(): """Return an asyncio event loop. @@ -825,23 +731,33 @@ def get_event_loop(): 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 `get_event_loop_policy().get_event_loop()` call. + the loop set by ``set_event_loop()``, or raise a RuntimeError if + no loop has been set. """ # NOTE: this function is implemented in C (see _asynciomodule.c) 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() def set_event_loop(loop): - """Equivalent to calling get_event_loop_policy().set_event_loop(loop).""" - _get_event_loop_policy().set_event_loop(loop) + """Set the event loop for the current thread to loop. + + If loop is None, the current event loop is unset. + """ + if loop is not None and not isinstance(loop, AbstractEventLoop): + raise TypeError(f"loop must be an instance of AbstractEventLoop or None, not '{type(loop).__name__}'") + _local._loop = loop def new_event_loop(): - """Equivalent to calling get_event_loop_policy().new_event_loop().""" - return _get_event_loop_policy().new_event_loop() + """Create and return a new event loop object.""" + if sys.platform == 'win32': + from .windows_events import EventLoop + else: + from .unix_events import EventLoop + return EventLoop() # Alias pure-Python implementations for testing purposes. @@ -870,8 +786,8 @@ def new_event_loop(): if hasattr(os, 'fork'): def on_fork(): # Reset the loop and wakeupfd in the forked child process. - if _event_loop_policy is not None: - _event_loop_policy._local = _BaseDefaultEventLoopPolicy._Local() + global _local + _local = _Local() _set_running_loop(None) signal.set_wakeup_fd(-1) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 915ff845249151..c6580c22dd69cd 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -963,11 +963,5 @@ def can_use_pidfd(): return True -class _UnixDefaultEventLoopPolicy(events._BaseDefaultEventLoopPolicy): - """UNIX event loop policy""" - _loop_factory = _UnixSelectorEventLoop - - SelectorEventLoop = _UnixSelectorEventLoop -_DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy EventLoop = SelectorEventLoop diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index 5f75b17d8ca649..0fc20346fa718b 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -29,8 +29,7 @@ __all__ = ( 'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor', - '_DefaultEventLoopPolicy', '_WindowsSelectorEventLoopPolicy', - '_WindowsProactorEventLoopPolicy', 'EventLoop', + 'EventLoop', ) @@ -890,14 +889,4 @@ def callback(f): SelectorEventLoop = _WindowsSelectorEventLoop - -class _WindowsSelectorEventLoopPolicy(events._BaseDefaultEventLoopPolicy): - _loop_factory = SelectorEventLoop - - -class _WindowsProactorEventLoopPolicy(events._BaseDefaultEventLoopPolicy): - _loop_factory = ProactorEventLoop - - -_DefaultEventLoopPolicy = _WindowsProactorEventLoopPolicy EventLoop = ProactorEventLoop diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index 138465012a252c..6393036118010e 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -70,7 +70,7 @@ def __init__(self, test_name, verbose, quiet, *, pgo): 'sysconfig._CONFIG_VARS', 'sysconfig._INSTALL_SCHEMES', 'files', 'locale', 'warnings.showwarning', 'shutil_archive_formats', 'shutil_unpack_formats', - 'asyncio.events._event_loop_policy', + 'asyncio.events._local._loop', 'urllib.requests._url_tempfiles', 'urllib.requests._opener', 'stty_echo', ) @@ -100,12 +100,12 @@ def restore_urllib_requests__opener(self, opener): urllib_request = self.get_module('urllib.request') urllib_request._opener = opener - def get_asyncio_events__event_loop_policy(self): + def get_asyncio_events__local__loop(self): self.try_get_module('asyncio') - return support.maybe_get_event_loop_policy() - def restore_asyncio_events__event_loop_policy(self, policy): + return support.maybe_get_event_loop() + def restore_asyncio_events__local__loop(self, loop): asyncio = self.get_module('asyncio') - asyncio.events._set_event_loop_policy(policy) + asyncio.events._local._loop = loop def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 2cac70f4ab2afb..a35c5fdb9e4a86 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2282,10 +2282,10 @@ def __gt__(self, other): SMALLEST = _SMALLEST() -def maybe_get_event_loop_policy(): - """Return the global event loop policy if one is set, else return None.""" +def maybe_get_event_loop(): + """Return the event loop set for the current thread, else return None.""" import asyncio.events - return asyncio.events._event_loop_policy + return asyncio.events._local._loop # Helpers for testing hashing. NHASHBITS = sys.hash_info.width # number of bits in hash() result diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index cd33878d6c74ba..e9eecbc8341551 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -629,7 +629,7 @@ def setUp(self): def tearDown(self): self.loop.close() self.loop = None - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def check_async_iterator_anext(self, ait_class): with self.subTest(anext="pure-Python"): diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index e59bc25668b4cb..fa3821e0783858 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -29,7 +29,7 @@ class CustomError(Exception): def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def mock_socket_module(): diff --git a/Lib/test/test_asyncio/test_buffered_proto.py b/Lib/test/test_asyncio/test_buffered_proto.py index 6d3edcc36f5c79..8300620bc59840 100644 --- a/Lib/test/test_asyncio/test_buffered_proto.py +++ b/Lib/test/test_asyncio/test_buffered_proto.py @@ -5,7 +5,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class ReceiveStuffProto(asyncio.BufferedProtocol): diff --git a/Lib/test/test_asyncio/test_context.py b/Lib/test/test_asyncio/test_context.py index f85f39839cbd79..cd3981c7959a47 100644 --- a/Lib/test/test_asyncio/test_context.py +++ b/Lib/test/test_asyncio/test_context.py @@ -4,7 +4,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) @unittest.skipUnless(decimal.HAVE_CONTEXTVAR, "decimal is built with a thread-local context") diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index 0561b54a3f19c6..594a48baa32e52 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -13,7 +13,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class EagerTaskFactoryLoopTests: diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 919d543b0329e9..fed9bf67217762 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -38,7 +38,7 @@ from test.support import ALWAYS_EQ, LARGEST, SMALLEST def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def broken_unix_getsockname(): @@ -2830,107 +2830,74 @@ async def inner(): class PolicyTests(unittest.TestCase): - def test_abstract_event_loop_policy_deprecation(self): - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.AbstractEventLoopPolicy' is deprecated"): - policy = asyncio.AbstractEventLoopPolicy() - self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy) - - def test_default_event_loop_policy_deprecation(self): - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.DefaultEventLoopPolicy' is deprecated"): - policy = asyncio.DefaultEventLoopPolicy() - self.assertIsInstance(policy, asyncio.DefaultEventLoopPolicy) - - def test_event_loop_policy(self): - policy = asyncio.events._AbstractEventLoopPolicy() - self.assertRaises(NotImplementedError, policy.get_event_loop) - self.assertRaises(NotImplementedError, policy.set_event_loop, object()) - self.assertRaises(NotImplementedError, policy.new_event_loop) - def test_get_event_loop(self): - policy = test_utils.DefaultEventLoopPolicy() - self.assertIsNone(policy._local._loop) + old_loop = asyncio.events._local._loop + try: + asyncio.set_event_loop(None) + self.assertIsNone(asyncio.events._local._loop) - with self.assertRaises(RuntimeError): - loop = policy.get_event_loop() - self.assertIsNone(policy._local._loop) + with self.assertRaises(RuntimeError): + asyncio.get_event_loop() + self.assertIsNone(asyncio.events._local._loop) + finally: + asyncio.events._local._loop = old_loop def test_get_event_loop_does_not_call_set_event_loop(self): - policy = test_utils.DefaultEventLoopPolicy() + old_loop = asyncio.events._local._loop + try: + asyncio.set_event_loop(None) - with mock.patch.object( - policy, "set_event_loop", - wraps=policy.set_event_loop) as m_set_event_loop: + with mock.patch( + 'asyncio.events.set_event_loop', + wraps=asyncio.events.set_event_loop) as m_set_event_loop: - with self.assertRaises(RuntimeError): - loop = policy.get_event_loop() + with self.assertRaises(RuntimeError): + asyncio.get_event_loop() + + m_set_event_loop.assert_not_called() - m_set_event_loop.assert_not_called() + self.assertIsNone(asyncio.events._local._loop) + finally: + asyncio.events._local._loop = old_loop def test_get_event_loop_after_set_none(self): - policy = test_utils.DefaultEventLoopPolicy() - policy.set_event_loop(None) - self.assertRaises(RuntimeError, policy.get_event_loop) + old_loop = asyncio.events._local._loop + try: + asyncio.set_event_loop(None) + self.assertRaises(RuntimeError, asyncio.get_event_loop) + finally: + asyncio.events._local._loop = old_loop - @mock.patch('asyncio.events.threading.current_thread') - def test_get_event_loop_thread(self, m_current_thread): + def test_get_event_loop_thread(self): def f(): - policy = test_utils.DefaultEventLoopPolicy() - self.assertRaises(RuntimeError, policy.get_event_loop) + self.assertRaises(RuntimeError, asyncio.get_event_loop) th = threading.Thread(target=f) th.start() th.join() def test_new_event_loop(self): - policy = test_utils.DefaultEventLoopPolicy() - - loop = policy.new_event_loop() + loop = asyncio.new_event_loop() self.assertIsInstance(loop, asyncio.AbstractEventLoop) loop.close() def test_set_event_loop(self): - policy = test_utils.DefaultEventLoopPolicy() - old_loop = policy.new_event_loop() - policy.set_event_loop(old_loop) - - self.assertRaises(TypeError, policy.set_event_loop, object()) - - loop = policy.new_event_loop() - policy.set_event_loop(loop) - self.assertIs(loop, policy.get_event_loop()) - self.assertIsNot(old_loop, policy.get_event_loop()) - loop.close() - old_loop.close() - - def test_get_event_loop_policy(self): - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): - policy = asyncio.get_event_loop_policy() - self.assertIsInstance(policy, asyncio.events._AbstractEventLoopPolicy) - self.assertIs(policy, asyncio.get_event_loop_policy()) - - def test_set_event_loop_policy(self): - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"): - self.assertRaises( - TypeError, asyncio.set_event_loop_policy, object()) - - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): - old_policy = asyncio.get_event_loop_policy() + old_loop = asyncio.events._local._loop + loop = None + try: + self.assertRaises(TypeError, asyncio.set_event_loop, object()) - policy = test_utils.DefaultEventLoopPolicy() - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"): - asyncio.set_event_loop_policy(policy) + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + self.assertIs(loop, asyncio.get_event_loop()) - with self.assertWarnsRegex( - DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): - self.assertIs(policy, asyncio.get_event_loop_policy()) - self.assertIsNot(policy, old_policy) + asyncio.set_event_loop(None) + self.assertRaises(RuntimeError, asyncio.get_event_loop) + finally: + asyncio.events._local._loop = old_loop + if loop is not None: + loop.close() class GetEventLoopTestsMixin: @@ -3031,28 +2998,24 @@ async def main(): def test_get_event_loop_returns_running_loop(self): - class TestError(Exception): - pass - - class Policy(test_utils.DefaultEventLoopPolicy): - def get_event_loop(self): - raise TestError - - old_policy = asyncio.events._get_event_loop_policy() + old_loop = asyncio.events._local._loop + loop = None try: - asyncio.events._set_event_loop_policy(Policy()) + asyncio.set_event_loop(None) loop = asyncio.new_event_loop() - with self.assertRaises(TestError): - asyncio.get_event_loop() - asyncio.set_event_loop(None) - with self.assertRaises(TestError): + # No running loop and no loop set for the thread: the running + # loop is checked first, then get_event_loop() falls back to + # the per-thread loop and raises RuntimeError. + with self.assertRaisesRegex(RuntimeError, 'no current'): asyncio.get_event_loop() with self.assertRaisesRegex(RuntimeError, 'no running'): asyncio.get_running_loop() self.assertIs(asyncio._get_running_loop(), None) + # While a loop is running, get_event_loop() returns it + # without consulting the per-thread loop. async def func(): self.assertIs(asyncio.get_event_loop(), loop) self.assertIs(asyncio.get_running_loop(), loop) @@ -3060,15 +3023,13 @@ async def func(): loop.run_until_complete(func()) - asyncio.set_event_loop(loop) - with self.assertRaises(TestError): - asyncio.get_event_loop() + # Back outside the running loop with no loop set: raises again. asyncio.set_event_loop(None) - with self.assertRaises(TestError): + with self.assertRaisesRegex(RuntimeError, 'no current'): asyncio.get_event_loop() finally: - asyncio.events._set_event_loop_policy(old_policy) + asyncio.events._local._loop = old_loop if loop is not None: loop.close() @@ -3078,9 +3039,10 @@ async def func(): self.assertIs(asyncio._get_running_loop(), None) def test_get_event_loop_returns_running_loop2(self): - old_policy = asyncio.events._get_event_loop_policy() + old_loop = asyncio.events._local._loop + loop = None try: - asyncio.events._set_event_loop_policy(test_utils.DefaultEventLoopPolicy()) + asyncio.set_event_loop(None) loop = asyncio.new_event_loop() self.addCleanup(loop.close) @@ -3106,7 +3068,7 @@ async def func(): asyncio.get_event_loop() finally: - asyncio.events._set_event_loop_policy(old_policy) + asyncio.events._local._loop = old_loop if loop is not None: loop.close() diff --git a/Lib/test/test_asyncio/test_free_threading.py b/Lib/test/test_asyncio/test_free_threading.py index d874ed00bd7e7a..93a43bcfd0b373 100644 --- a/Lib/test/test_asyncio/test_free_threading.py +++ b/Lib/test/test_asyncio/test_free_threading.py @@ -15,7 +15,7 @@ class MyException(Exception): def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TestFreeThreading: diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 9385a65e52813e..320de2180e7db7 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -17,7 +17,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def _fakefunc(f): diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py index c7c0ebdac1b676..cf90835ce87cc3 100644 --- a/Lib/test/test_asyncio/test_futures2.py +++ b/Lib/test/test_asyncio/test_futures2.py @@ -7,7 +7,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class FutureTests: diff --git a/Lib/test/test_asyncio/test_graph.py b/Lib/test/test_asyncio/test_graph.py index cffb2b30ad9cff..3dde7535284b25 100644 --- a/Lib/test/test_asyncio/test_graph.py +++ b/Lib/test/test_asyncio/test_graph.py @@ -6,7 +6,7 @@ # To prevent a warning "test altered the execution environment" def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def capture_test_stack(*, fut=None, depth=1): diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py index e025d2990a3f8a..320a933e144813 100644 --- a/Lib/test/test_asyncio/test_locks.py +++ b/Lib/test/test_asyncio/test_locks.py @@ -20,7 +20,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class LockTests(unittest.IsolatedAsyncioTestCase): diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py index 95a9f3a9a7cf71..3d4a5d8375f8a2 100644 --- a/Lib/test/test_asyncio/test_pep492.py +++ b/Lib/test/test_asyncio/test_pep492.py @@ -11,7 +11,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) # Test that asyncio.iscoroutine() uses collections.abc.Coroutine diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index edfad5e11db35e..2f229887ad62cc 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -18,7 +18,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def close_transport(transport): diff --git a/Lib/test/test_asyncio/test_protocols.py b/Lib/test/test_asyncio/test_protocols.py index 29d3bd22705c6a..643199962b8af0 100644 --- a/Lib/test/test_asyncio/test_protocols.py +++ b/Lib/test/test_asyncio/test_protocols.py @@ -7,7 +7,7 @@ def tearDownModule(): # not needed for the test file but added for uniformness with all other # asyncio test files for the sake of unified cleanup - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class ProtocolsAbsTests(unittest.TestCase): diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py index 54bbe79f81ff69..7c1548f1948f77 100644 --- a/Lib/test/test_asyncio/test_queues.py +++ b/Lib/test/test_asyncio/test_queues.py @@ -6,7 +6,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class QueueBasicTests(unittest.IsolatedAsyncioTestCase): diff --git a/Lib/test/test_asyncio/test_runners.py b/Lib/test/test_asyncio/test_runners.py index 8a4d7f5c796661..b9d94833a2cccd 100644 --- a/Lib/test/test_asyncio/test_runners.py +++ b/Lib/test/test_asyncio/test_runners.py @@ -12,33 +12,13 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def interrupt_self(): _thread.interrupt_main() -class TestPolicy(asyncio.events._AbstractEventLoopPolicy): - - def __init__(self, loop_factory): - self.loop_factory = loop_factory - self.loop = None - - def get_event_loop(self): - # shouldn't ever be called by asyncio.run() - raise RuntimeError - - def new_event_loop(self): - return self.loop_factory() - - def set_event_loop(self, loop): - if loop is not None: - # we want to check if the loop is closed - # in BaseTest.tearDown - self.loop = loop - - class BaseTest(unittest.TestCase): def new_loop(self): @@ -55,21 +35,26 @@ async def shutdown_asyncgens(): loop.shutdown_ag_run = True loop.shutdown_asyncgens = shutdown_asyncgens + # Track created loops so tearDown can assert they were closed and + # had their async generators shut down. + self._loops.append(loop) return loop def setUp(self): super().setUp() - policy = TestPolicy(self.new_loop) - asyncio.events._set_event_loop_policy(policy) + # Isolate the current thread's event loop and use ``new_loop`` as + # an explicit ``loop_factory`` in the tests. + self._loops = [] + asyncio.set_event_loop(None) def tearDown(self): - policy = asyncio.events._get_event_loop_policy() - if policy.loop is not None: - self.assertTrue(policy.loop.is_closed()) - self.assertTrue(policy.loop.shutdown_ag_run) + if self._loops: + loop = self._loops[-1] + self.assertTrue(loop.is_closed()) + self.assertTrue(loop.shutdown_ag_run) - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) super().tearDown() @@ -80,7 +65,7 @@ async def main(): await asyncio.sleep(0) return 42 - self.assertEqual(asyncio.run(main()), 42) + self.assertEqual(asyncio.run(main(), loop_factory=self.new_loop), 42) def test_asyncio_run_raises(self): async def main(): @@ -88,7 +73,7 @@ async def main(): raise ValueError('spam') with self.assertRaisesRegex(ValueError, 'spam'): - asyncio.run(main()) + asyncio.run(main(), loop_factory=self.new_loop) def test_asyncio_run_only_coro(self): for o in {1, lambda: None}: @@ -102,26 +87,26 @@ async def main(expected): loop = asyncio.get_event_loop() self.assertIs(loop.get_debug(), expected) - asyncio.run(main(False), debug=False) - asyncio.run(main(True), debug=True) + asyncio.run(main(False), debug=False, loop_factory=self.new_loop) + asyncio.run(main(True), debug=True, loop_factory=self.new_loop) with mock.patch('asyncio.coroutines._is_debug_mode', lambda: True): - asyncio.run(main(True)) - asyncio.run(main(False), debug=False) + asyncio.run(main(True), loop_factory=self.new_loop) + asyncio.run(main(False), debug=False, loop_factory=self.new_loop) with mock.patch('asyncio.coroutines._is_debug_mode', lambda: False): - asyncio.run(main(True), debug=True) - asyncio.run(main(False)) + asyncio.run(main(True), debug=True, loop_factory=self.new_loop) + asyncio.run(main(False), loop_factory=self.new_loop) def test_asyncio_run_from_running_loop(self): async def main(): coro = main() try: - asyncio.run(coro) + asyncio.run(coro, loop_factory=self.new_loop) finally: coro.close() # Suppress ResourceWarning with self.assertRaisesRegex(RuntimeError, 'cannot be called from a running'): - asyncio.run(main()) + asyncio.run(main(), loop_factory=self.new_loop) def test_asyncio_run_cancels_hanging_tasks(self): lo_task = None @@ -134,7 +119,7 @@ async def main(): lo_task = asyncio.create_task(leftover()) return 123 - self.assertEqual(asyncio.run(main()), 123) + self.assertEqual(asyncio.run(main(), loop_factory=self.new_loop), 123) self.assertTrue(lo_task.done()) def test_asyncio_run_reports_hanging_tasks_errors(self): @@ -155,7 +140,7 @@ async def main(): lo_task = asyncio.create_task(leftover()) return 123 - self.assertEqual(asyncio.run(main()), 123) + self.assertEqual(asyncio.run(main(), loop_factory=self.new_loop), 123) self.assertTrue(lo_task.done()) call_exc_handler_mock.assert_called_with({ @@ -194,7 +179,7 @@ async def main(): raise FancyExit with self.assertRaises(FancyExit): - asyncio.run(main()) + asyncio.run(main(), loop_factory=self.new_loop) self.assertTrue(lazyboy.done()) @@ -208,10 +193,14 @@ async def main(): await asyncio.sleep(0) return 42 - policy = asyncio.events._get_event_loop_policy() - policy.set_event_loop = mock.Mock() - asyncio.run(main()) - self.assertTrue(policy.set_event_loop.called) + # asyncio.run() must set the event loop for the running thread. + # This only happens when no explicit loop_factory is passed, so + # patch the default loop creation to use a mock loop and verify + # set_event_loop() is called. + with mock.patch('asyncio.events.new_event_loop', self.new_loop), \ + mock.patch('asyncio.runners.events.set_event_loop') as set_event_loop: + asyncio.run(main()) + self.assertTrue(set_event_loop.called) def test_asyncio_run_without_uncancel(self): # See https://github.com/python/cpython/issues/95097 @@ -259,9 +248,8 @@ def new_event_loop(): loop.set_task_factory(Task) return loop - asyncio.events._set_event_loop_policy(TestPolicy(new_event_loop)) with self.assertRaises(asyncio.CancelledError): - asyncio.run(main()) + asyncio.run(main(), loop_factory=new_event_loop) def test_asyncio_run_loop_factory(self): factory = mock.Mock() @@ -495,14 +483,17 @@ def test_set_event_loop_called_once(self): async def coro(): pass - policy = asyncio.events._get_event_loop_policy() - policy.set_event_loop = mock.Mock() - runner = asyncio.Runner() - runner.run(coro()) - runner.run(coro()) - - self.assertEqual(1, policy.set_event_loop.call_count) - runner.close() + # The runner must call set_event_loop() exactly once even when + # run() is called multiple times. This only happens on the + # implicit loop_factory path, so patch the default loop creation. + with mock.patch('asyncio.events.new_event_loop', self.new_loop), \ + mock.patch('asyncio.runners.events.set_event_loop') as set_event_loop: + runner = asyncio.Runner() + runner.run(coro()) + runner.run(coro()) + + self.assertEqual(1, set_event_loop.call_count) + runner.close() def test_no_repr_is_call_on_the_task_result(self): # See https://github.com/python/cpython/issues/112559. diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 4bb5d4fb816a9a..76ba39019e3663 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -24,7 +24,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TestBaseSelectorEventLoop(BaseSelectorEventLoop): diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index dcd963b3355ef8..391701283b6b1f 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -22,7 +22,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class MySendfileProto(asyncio.Protocol): diff --git a/Lib/test/test_asyncio/test_server.py b/Lib/test/test_asyncio/test_server.py index 581ea47d2dec97..67a46085be31ce 100644 --- a/Lib/test/test_asyncio/test_server.py +++ b/Lib/test/test_asyncio/test_server.py @@ -11,7 +11,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class BaseStartServer(func_tests.FunctionalTestCaseMixin): diff --git a/Lib/test/test_asyncio/test_server_context.py b/Lib/test/test_asyncio/test_server_context.py index 3f15654a1af467..9ee5eb436e0b8d 100644 --- a/Lib/test/test_asyncio/test_server_context.py +++ b/Lib/test/test_asyncio/test_server_context.py @@ -13,7 +13,7 @@ from test.test_asyncio import utils as test_utils def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class ServerContextvarsTestCase: loop_factory = None # To be defined in subclasses diff --git a/Lib/test/test_asyncio/test_sock_lowlevel.py b/Lib/test/test_asyncio/test_sock_lowlevel.py index f32dcd589e2de2..5d825440e41ca7 100644 --- a/Lib/test/test_asyncio/test_sock_lowlevel.py +++ b/Lib/test/test_asyncio/test_sock_lowlevel.py @@ -15,7 +15,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class MyProto(asyncio.Protocol): diff --git a/Lib/test/test_asyncio/test_ssl.py b/Lib/test/test_asyncio/test_ssl.py index ca15fc3bdd42dd..567d9ce5d24422 100644 --- a/Lib/test/test_asyncio/test_ssl.py +++ b/Lib/test/test_asyncio/test_ssl.py @@ -31,7 +31,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class MyBaseProto(asyncio.Protocol): @@ -185,9 +185,6 @@ def _abort_socket_test(self, ex): def new_loop(self): return asyncio.new_event_loop() - def new_policy(self): - return asyncio.DefaultEventLoopPolicy() - async def wait_closed(self, obj): if not isinstance(obj, asyncio.StreamWriter): return diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py index 3e304c166425b0..1b1437b51bab0a 100644 --- a/Lib/test/test_asyncio/test_sslproto.py +++ b/Lib/test/test_asyncio/test_sslproto.py @@ -21,7 +21,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) @unittest.skipIf(ssl is None, 'No ssl module') diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py index 32e4817b70d717..693bf02001a2c3 100644 --- a/Lib/test/test_asyncio/test_staggered.py +++ b/Lib/test/test_asyncio/test_staggered.py @@ -8,7 +8,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class StaggeredTests(unittest.IsolatedAsyncioTestCase): diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index cae8c7c6f7c94c..fb774895a7e52a 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -18,7 +18,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class StreamTests(test_utils.TestCase): diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index c08eb7cf261568..fdffab691a3285 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -37,7 +37,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TestSubprocessTransport(base_subprocess.BaseSubprocessTransport): diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 8925884b9dcf73..e1eaa60e4df85d 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -15,7 +15,7 @@ # To prevent a warning "test altered the execution environment" def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class MyExc(Exception): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 56b1494c8363ca..7a217f886b87de 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -24,7 +24,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) async def coroutine_function(): diff --git a/Lib/test/test_asyncio/test_threads.py b/Lib/test/test_asyncio/test_threads.py index 8ad5f9b2c9e750..4300df90ff2b18 100644 --- a/Lib/test/test_asyncio/test_threads.py +++ b/Lib/test/test_asyncio/test_threads.py @@ -8,7 +8,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class ToThreadTests(unittest.IsolatedAsyncioTestCase): diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py index f60722c48b7617..69936aae5cc81d 100644 --- a/Lib/test/test_asyncio/test_timeouts.py +++ b/Lib/test/test_asyncio/test_timeouts.py @@ -9,7 +9,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TimeoutTests(unittest.IsolatedAsyncioTestCase): diff --git a/Lib/test/test_asyncio/test_transports.py b/Lib/test/test_asyncio/test_transports.py index dbb572e2e1536b..a5b4c98ebf64f3 100644 --- a/Lib/test/test_asyncio/test_transports.py +++ b/Lib/test/test_asyncio/test_transports.py @@ -10,7 +10,7 @@ def tearDownModule(): # not needed for the test file but added for uniformness with all other # asyncio test files for the sake of unified cleanup - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TransportTests(unittest.TestCase): diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index d2b3de3b9a4cb6..2bf4fc2e51a980 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -30,7 +30,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) MOCK_ANY = mock.ANY diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py index dedc6bf69d770e..56dbafd88e45ef 100644 --- a/Lib/test/test_asyncio/test_waitfor.py +++ b/Lib/test/test_asyncio/test_waitfor.py @@ -5,7 +5,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) # The following value can be used as a very small timeout: diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index 0af3368627afca..c40391b237d57e 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -19,7 +19,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class UpperProto(asyncio.Protocol): @@ -324,40 +324,5 @@ def threadMain(): thr.join() -class WinPolicyTests(WindowsEventsTestCase): - - def test_selector_win_policy(self): - async def main(): - self.assertIsInstance(asyncio.get_running_loop(), asyncio.SelectorEventLoop) - - old_policy = asyncio.events._get_event_loop_policy() - try: - with self.assertWarnsRegex( - DeprecationWarning, - "'asyncio.WindowsSelectorEventLoopPolicy' is deprecated", - ): - asyncio.events._set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) - asyncio.run(main()) - finally: - asyncio.events._set_event_loop_policy(old_policy) - - def test_proactor_win_policy(self): - async def main(): - self.assertIsInstance( - asyncio.get_running_loop(), - asyncio.ProactorEventLoop) - - old_policy = asyncio.events._get_event_loop_policy() - try: - with self.assertWarnsRegex( - DeprecationWarning, - "'asyncio.WindowsProactorEventLoopPolicy' is deprecated", - ): - asyncio.events._set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) - asyncio.run(main()) - finally: - asyncio.events._set_event_loop_policy(old_policy) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_asyncio/test_windows_utils.py b/Lib/test/test_asyncio/test_windows_utils.py index 50969761347595..1ac77262d1420d 100644 --- a/Lib/test/test_asyncio/test_windows_utils.py +++ b/Lib/test/test_asyncio/test_windows_utils.py @@ -16,7 +16,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class PipeTests(unittest.TestCase): diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 62cfcf8ceb5f2a..e86c221d7f7025 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -601,9 +601,3 @@ def func(): await asyncio.sleep(0) if exc is not None: raise exc - - -if sys.platform == 'win32': - DefaultEventLoopPolicy = asyncio.windows_events._DefaultEventLoopPolicy -else: - DefaultEventLoopPolicy = asyncio.unix_events._DefaultEventLoopPolicy diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 7241fcc4b1e74d..db5b89bb76ada9 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -518,16 +518,16 @@ class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase): @classmethod def setUpClass(cls): - # Most uses of asyncio will implicitly call set_event_loop_policy() - # with the default policy if a policy hasn't been set already. + # Most uses of asyncio will implicitly set a thread event loop + # if one hasn't been set already. # If that happens in a test, like here, we'll end up with a failure # when --fail-env-changed is used. That's why the other tests that - # use asyncio are careful to set the policy back to None and why + # use asyncio are careful to set the loop back to None and why # we're careful to do so here. We also validate that no other - # tests left a policy in place, just in case. - policy = support.maybe_get_event_loop_policy() - assert policy is None, policy - cls.addClassCleanup(lambda: asyncio.events._set_event_loop_policy(None)) + # tests left a loop in place, just in case. + loop = support.maybe_get_event_loop() + assert loop is None, loop + cls.addClassCleanup(lambda: asyncio.set_event_loop(None)) def setUp(self): super().setUp() diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 93e9e7a8393cb1..9d415238876c8f 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -2321,7 +2321,7 @@ async def f(): pass finally: loop.close() - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) self.assertEqual(buffer, [1, 2, 'MyException']) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 7351f97fd9a4b5..495702badc3a7f 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -2988,7 +2988,7 @@ async def asyncTearDown(self): @classmethod def tearDownClass(cls): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) def _asyncgenstate(self): return inspect.getasyncgenstate(self.asyncgen) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index f2cbc2514fce53..57fa76864b1316 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -5449,7 +5449,7 @@ def test_taskName_with_asyncio_imported(self): logging.logAsyncioTasks = False runner.run(make_record(self.assertIsNone)) finally: - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) @support.requires_working_socket() def test_taskName_without_asyncio_imported(self): @@ -5461,7 +5461,7 @@ def test_taskName_without_asyncio_imported(self): logging.logAsyncioTasks = False runner.run(make_record(self.assertIsNone)) finally: - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class BasicConfigTest(unittest.TestCase): @@ -5786,7 +5786,7 @@ async def log_record(): data = f.read().strip() self.assertRegex(data, r'Task-\d+ - hello world') finally: - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) if handler: handler.close() diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index e71c28424e095f..41078a5b1aa9f1 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -92,7 +92,7 @@ def requires_os_func(name): def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class MiscTests(unittest.TestCase): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 410f1436ed4d20..0cf5dd2e4c1004 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -17,7 +17,7 @@ import zipapp import zipfile -from asyncio.events import _set_event_loop_policy +from asyncio import set_event_loop from contextlib import ExitStack, redirect_stdout from io import StringIO from test import support @@ -5312,7 +5312,7 @@ def tearDown(test): # Ensure that asyncio state has been cleared at the end of the test. # This prevents a "test altered the execution environment" warning if # asyncio features are used. - _set_event_loop_policy(None) + set_event_loop(None) # A doctest of pdb could have residues. For example, pdb could still # be running, or breakpoints might be left uncleared. These residues diff --git a/Lib/test/test_unittest/test_async_case.py b/Lib/test/test_unittest/test_async_case.py index 91d45283eb3b1b..fae8f0e325353c 100644 --- a/Lib/test/test_unittest/test_async_case.py +++ b/Lib/test/test_unittest/test_async_case.py @@ -12,7 +12,7 @@ class MyException(Exception): def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TestCM: @@ -480,7 +480,7 @@ def test_setup_get_event_loop(self): class TestCase1(unittest.IsolatedAsyncioTestCase): def setUp(self): - asyncio.events._get_event_loop_policy().get_event_loop() + asyncio.get_event_loop() async def test_demo1(self): pass @@ -490,7 +490,7 @@ async def test_demo1(self): self.assertTrue(result.wasSuccessful()) def test_loop_factory(self): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class TestCase1(unittest.IsolatedAsyncioTestCase): loop_factory = asyncio.EventLoop @@ -501,7 +501,7 @@ async def test_demo1(self): test = TestCase1('test_demo1') result = test.run() self.assertTrue(result.wasSuccessful()) - self.assertIsNone(support.maybe_get_event_loop_policy()) + self.assertIsNone(support.maybe_get_event_loop()) if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_unittest/testmock/testasync.py b/Lib/test/test_unittest/testmock/testasync.py index dc36ceeb6502e8..f96aef7325ff4c 100644 --- a/Lib/test/test_unittest/testmock/testasync.py +++ b/Lib/test/test_unittest/testmock/testasync.py @@ -15,7 +15,7 @@ def tearDownModule(): - asyncio.events._set_event_loop_policy(None) + asyncio.set_event_loop(None) class AsyncClass: diff --git a/Lib/unittest/async_case.py b/Lib/unittest/async_case.py index a1c0d6c368ce8a..36128c5fb953c5 100644 --- a/Lib/unittest/async_case.py +++ b/Lib/unittest/async_case.py @@ -25,13 +25,11 @@ class IsolatedAsyncioTestCase(TestCase): # To share contextvars between setUp(), test and tearDown() we need to execute # them inside the same task. - # Note: the test case modifies event loop policy if the policy was not instantiated - # yet, unless loop_factory=asyncio.EventLoop is set. - # asyncio.get_event_loop_policy() creates a default policy on demand but never - # returns None + # Note: the test case sets the per-thread event loop unless + # loop_factory=asyncio.EventLoop is set. # I believe this is not an issue in user level tests but python itself for testing - # should reset a policy in every test module - # by calling asyncio.set_event_loop_policy(None) in tearDownModule() + # should reset the event loop in every test module + # by calling asyncio.set_event_loop(None) in tearDownModule() # or set loop_factory=asyncio.EventLoop loop_factory = None diff --git a/Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst b/Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst new file mode 100644 index 00000000000000..5004f0e14082a2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst @@ -0,0 +1,6 @@ +Remove the deprecated :mod:`asyncio` event loop policy system, including +:func:`!asyncio.get_event_loop_policy`, :func:`!asyncio.set_event_loop_policy`, +and the :class:`!asyncio.AbstractEventLoopPolicy`, +:class:`!asyncio.DefaultEventLoopPolicy`, +:class:`!asyncio.WindowsSelectorEventLoopPolicy` and +:class:`!asyncio.WindowsProactorEventLoopPolicy` classes. Patch by Kumar Aditya. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 9679a7dde31b0d..3357a1a7180e3a 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -163,7 +163,7 @@ typedef struct { PyObject *iscoroutine_typecache; /* Imports from asyncio.events. */ - PyObject *asyncio_get_event_loop_policy; + PyObject *asyncio_get_event_loop; /* Imports from asyncio.base_futures. */ PyObject *asyncio_future_repr_func; @@ -343,7 +343,6 @@ static PyObject * get_event_loop(asyncio_state *state) { PyObject *loop; - PyObject *policy; _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); loop = Py_XNewRef(ts->asyncio_running_loop); @@ -352,14 +351,7 @@ get_event_loop(asyncio_state *state) return loop; } - policy = PyObject_CallNoArgs(state->asyncio_get_event_loop_policy); - if (policy == NULL) { - return NULL; - } - - loop = PyObject_CallMethodNoArgs(policy, &_Py_ID(get_event_loop)); - Py_DECREF(policy); - return loop; + return PyObject_CallNoArgs(state->asyncio_get_event_loop); } @@ -3635,12 +3627,13 @@ 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 `get_event_loop_policy().get_event_loop()` call. +the loop set by `set_event_loop()`, or raise a RuntimeError if +no loop has been set. [clinic start generated code]*/ static PyObject * _asyncio_get_event_loop_impl(PyObject *module) -/*[clinic end generated code: output=2a2d8b2f824c648b input=9364bf2916c8655d]*/ +/*[clinic end generated code: output=2a2d8b2f824c648b input=fa104f00dc7995dc]*/ { asyncio_state *state = get_asyncio_state(module); return get_event_loop(state); @@ -4188,7 +4181,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->asyncio_mod); Py_VISIT(state->traceback_extract_stack); Py_VISIT(state->asyncio_future_repr_func); - Py_VISIT(state->asyncio_get_event_loop_policy); + Py_VISIT(state->asyncio_get_event_loop); Py_VISIT(state->asyncio_iscoroutine_func); Py_VISIT(state->asyncio_task_get_stack_func); Py_VISIT(state->asyncio_task_print_stack_func); @@ -4218,7 +4211,7 @@ module_clear(PyObject *mod) Py_CLEAR(state->asyncio_mod); Py_CLEAR(state->traceback_extract_stack); Py_CLEAR(state->asyncio_future_repr_func); - Py_CLEAR(state->asyncio_get_event_loop_policy); + Py_CLEAR(state->asyncio_get_event_loop); Py_CLEAR(state->asyncio_iscoroutine_func); Py_CLEAR(state->asyncio_task_get_stack_func); Py_CLEAR(state->asyncio_task_print_stack_func); @@ -4281,7 +4274,7 @@ module_init(asyncio_state *state) } WITH_MOD("asyncio.events") - GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "_get_event_loop_policy") + GET_MOD_ATTR(state->asyncio_get_event_loop, "_get_event_loop") WITH_MOD("asyncio.base_futures") GET_MOD_ATTR(state->asyncio_future_repr_func, "_future_repr") diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h index 66953d74213b66..6efa91b7691f55 100644 --- a/Modules/clinic/_asynciomodule.c.h +++ b/Modules/clinic/_asynciomodule.c.h @@ -1581,7 +1581,8 @@ PyDoc_STRVAR(_asyncio_get_event_loop__doc__, "running event loop.\n" "\n" "If there is no running event loop set, the function will return\n" -"the result of `get_event_loop_policy().get_event_loop()` call."); +"the loop set by `set_event_loop()`, or raise a RuntimeError if\n" +"no loop has been set."); #define _ASYNCIO_GET_EVENT_LOOP_METHODDEF \ {"get_event_loop", (PyCFunction)_asyncio_get_event_loop, METH_NOARGS, _asyncio_get_event_loop__doc__}, @@ -2232,4 +2233,4 @@ _asyncio_future_discard_from_awaited_by(PyObject *module, PyObject *const *args, exit: return return_value; } -/*[clinic end generated code: output=b69948ed810591d9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=60e0d4f74b52d47a input=a9049054013a1b77]*/