]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-127949: remove asyncio policy system (#150310)
authorKumar Aditya <kumaraditya@python.org>
Sat, 27 Jun 2026 07:16:50 +0000 (12:46 +0530)
committerGitHub <noreply@github.com>
Sat, 27 Jun 2026 07:16:50 +0000 (12:46 +0530)
68 files changed:
Doc/deprecations/pending-removal-in-3.16.rst
Doc/library/asyncio-eventloop.rst
Doc/library/asyncio-llapi-index.rst
Doc/library/asyncio-policy.rst [deleted file]
Doc/library/asyncio-runner.rst
Doc/library/asyncio.rst
Doc/tools/check-html-ids.py
Doc/tools/removed-ids.txt
Doc/whatsnew/3.14.rst
Doc/whatsnew/3.16.rst
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Lib/asyncio/__init__.py
Lib/asyncio/events.py
Lib/asyncio/unix_events.py
Lib/asyncio/windows_events.py
Lib/test/libregrtest/save_env.py
Lib/test/support/__init__.py
Lib/test/test_asyncgen.py
Lib/test/test_asyncio/test_base_events.py
Lib/test/test_asyncio/test_buffered_proto.py
Lib/test/test_asyncio/test_context.py
Lib/test/test_asyncio/test_eager_task_factory.py
Lib/test/test_asyncio/test_events.py
Lib/test/test_asyncio/test_free_threading.py
Lib/test/test_asyncio/test_futures.py
Lib/test/test_asyncio/test_futures2.py
Lib/test/test_asyncio/test_graph.py
Lib/test/test_asyncio/test_locks.py
Lib/test/test_asyncio/test_pep492.py
Lib/test/test_asyncio/test_proactor_events.py
Lib/test/test_asyncio/test_protocols.py
Lib/test/test_asyncio/test_queues.py
Lib/test/test_asyncio/test_runners.py
Lib/test/test_asyncio/test_selector_events.py
Lib/test/test_asyncio/test_sendfile.py
Lib/test/test_asyncio/test_server.py
Lib/test/test_asyncio/test_server_context.py
Lib/test/test_asyncio/test_sock_lowlevel.py
Lib/test/test_asyncio/test_ssl.py
Lib/test/test_asyncio/test_sslproto.py
Lib/test/test_asyncio/test_staggered.py
Lib/test/test_asyncio/test_streams.py
Lib/test/test_asyncio/test_subprocess.py
Lib/test/test_asyncio/test_taskgroups.py
Lib/test/test_asyncio/test_tasks.py
Lib/test/test_asyncio/test_threads.py
Lib/test/test_asyncio/test_timeouts.py
Lib/test/test_asyncio/test_transports.py
Lib/test/test_asyncio/test_unix_events.py
Lib/test/test_asyncio/test_waitfor.py
Lib/test/test_asyncio/test_windows_events.py
Lib/test/test_asyncio/test_windows_utils.py
Lib/test/test_asyncio/utils.py
Lib/test/test_concurrent_futures/test_interpreter_pool.py
Lib/test/test_coroutines.py
Lib/test/test_inspect/test_inspect.py
Lib/test/test_logging.py
Lib/test/test_os/test_os.py
Lib/test/test_pdb.py
Lib/test/test_unittest/test_async_case.py
Lib/test/test_unittest/testmock/testasync.py
Lib/unittest/async_case.py
Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst [new file with mode: 0644]
Modules/_asynciomodule.c
Modules/clinic/_asynciomodule.c.h

index 5a28cc766a959611d8ef8062efa26452083da08b..9b19ec3236f92fb76ead62bf8e58d89f9cee9c57 100644 (file)
@@ -33,12 +33,12 @@ Pending removal in Python 3.16
   * :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`
+    * :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.
index 79c9516cda2d60b05b2946ee920159e8d5f82c76..65bc349e2a727d38a66a8f6e577acbc584be7a92 100644 (file)
@@ -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 <asyncio-policies>`.
-
 
 .. rubric:: Contents
 
index f5af888f31f18635ddf7c7c72ffcc6b8d0641c13..faf67209a2b0ef539eb5054cec70e93f50aec07a 100644 (file)
@@ -19,10 +19,10 @@ Obtaining the Event Loop
       - The **preferred** function to get the running event loop.
 
     * - :func:`asyncio.get_event_loop`
-      - Get an event loop instance (running or current via the current policy).
+      - Get the running event loop or the event loop set for the current thread.
 
     * - :func:`asyncio.set_event_loop`
-      - Set the event loop as current via the current policy.
+      - Set the event loop for the current thread.
 
     * - :func:`asyncio.new_event_loop`
       - Create a new event loop.
@@ -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 <asyncio-policies>` 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 (file)
index 57f9649..0000000
+++ /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 <asyncio-event-loop>`,
-as well as create new event loops.
-The default policy can be :ref:`replaced <asyncio-policy-get-set>` with
-:ref:`built-in alternatives <asyncio-policy-builtin>`
-to use different event loop implementations,
-or substituted by a :ref:`custom policy <asyncio-custom-policies>`
-that can override these behaviors.
-
-The :ref:`policy object <asyncio-policy-objects>`
-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())
index 48d78099fd3ce7eea925c1fe62158ad2f72a99ce..cd125b30703c79665053f3a90e62fce0223e4af7 100644 (file)
@@ -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
 ======================
index 90a465f3e1d3af46184ff4d317bed9a510e307b6..4ae6d1e43f2ac7bc9f9a4663cfcea4bd765be30f 100644 (file)
@@ -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
 
index 7d86c6cc3264ad554aad5d73ee81b1d08d0bf674..3ea0a99d1dd4f688a7b22b77e0222532fd258428 100644 (file)
@@ -78,9 +78,10 @@ def do_check(baseline, checked, excluded, *, verbose_print):
         try:
             checked_ids = checked[name]
         except KeyError:
-            successful = False
-            print(f'{name}: (page missing)')
-            print()
+            if (name, '(page missing)') not in excluded:
+                successful = False
+                print(f'{name}: (page missing)')
+                print()
         else:
             missing_ids = set(baseline_ids) - set(checked_ids)
             if missing_ids:
index 271b383ba8123071bf313b8603662a53ce9bf3d8..0549ae735a92d6335567e79445801f6ce0158986 100644 (file)
@@ -6,6 +6,7 @@ c-api/file.html: deprecated-api
 
 # Removed sections
 library/asyncio-task.html: terminating-a-task-group
+library/asyncio-llapi-index.html: event-loop-policies
 deprecations/index.html: pending-removal-in-python-3-15
 deprecations/index.html: pending-removal-in-python-3-16
 deprecations/index.html: c-api-pending-removal-in-python-3-15
@@ -35,3 +36,6 @@ reference/expressions.html: grammar-token-python-grammar-set_display
 # Moved to a different page
 c-api/typeobj.html: c.Py_tp_base
 c-api/typeobj.html: c.Py_tp_bases
+
+# Removed pages
+library/asyncio-policy.html: (page missing)
index cd0d8b7cb006fee9a9b5b3658a2f0b7a1c3cfbec..2fa7267292d994024b0abfc039a135d4354bef60 100644 (file)
@@ -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.
index e29d6e9b9e25ee9c526502f2b4765dcf61c34c56..7841fa56cc5952c6937fa284b584f139ad55adca 100644 (file)
@@ -411,6 +411,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
 ---------
 
index 87dde5e062bd7248626b5aa91020c407f8e2a548..7d952a1e52561a66b418265b3b1140bccaa11f67 100644 (file)
@@ -1794,7 +1794,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(generation));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get_debug));
-    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get_event_loop));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get_loop));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get_source));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(getattr));
index 43286fa36bbb05cb559cab31fe1943c570a4441d..8a8bbc3b6d05bf74e1d67e4f105c939ade117eaa 100644 (file)
@@ -517,7 +517,6 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(generation)
         STRUCT_FOR_ID(get)
         STRUCT_FOR_ID(get_debug)
-        STRUCT_FOR_ID(get_event_loop)
         STRUCT_FOR_ID(get_loop)
         STRUCT_FOR_ID(get_source)
         STRUCT_FOR_ID(getattr)
index 116dbf84f790124f477ce6b48797589814e5d908..366d2d300fb4780f7789e0ddb45f3c51890a6cf7 100644 (file)
@@ -1792,7 +1792,6 @@ extern "C" {
     INIT_ID(generation), \
     INIT_ID(get), \
     INIT_ID(get_debug), \
-    INIT_ID(get_event_loop), \
     INIT_ID(get_loop), \
     INIT_ID(get_source), \
     INIT_ID(getattr), \
index f7197b39d9bd3ab958347d9bfae39b91d9436cb8..00d6297432b5fcae8eb94ba576afdbfff9397b58 100644 (file)
@@ -1848,10 +1848,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
-    string = &_Py_ID(get_event_loop);
-    _PyUnicode_InternStatic(interp, &string);
-    assert(_PyUnicode_CheckConsistency(string, 1));
-    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(get_loop);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
index 32a5dbae03af2165847da1ff334b6ebb2c3521f9..2432e2dad74c23d1e89ac5ade56df3d4b669388e 100644 (file)
@@ -47,28 +47,3 @@ if sys.platform == 'win32':  # pragma: no cover
 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}")
index 42d8408a38dfd1fca80a1aa4c186d7db1250c80d..807c70bc775aa2cd3b900ca0983237e15c110d10 100644 (file)
@@ -9,8 +9,6 @@ __all__ = (
     "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 socket
 import subprocess
 import sys
 import threading
-import warnings
 
 from . import format_helpers
 
@@ -665,84 +662,11 @@ class AbstractEventLoop:
         raise NotImplementedError
 
 
-class _AbstractEventLoopPolicy:
-    """Abstract policy for accessing the event loop."""
+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.
@@ -787,39 +711,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.
@@ -828,23 +732,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.
@@ -873,8 +787,8 @@ else:
 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)
 
index 676e0b670faa49b192be4cd8168e23e8d710e5d5..93dd8994e1bcd5120c0eaae8a8be8f1ac8e0b63e 100644 (file)
@@ -965,11 +965,5 @@ def can_use_pidfd():
     return True
 
 
-class _UnixDefaultEventLoopPolicy(events._BaseDefaultEventLoopPolicy):
-    """UNIX event loop policy"""
-    _loop_factory = _UnixSelectorEventLoop
-
-
 SelectorEventLoop = _UnixSelectorEventLoop
-_DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy
 EventLoop = SelectorEventLoop
index 0bf7732136f1f8ea8ecf4da18e621acc9895be0c..8241c10b32d105c03a12872dc37a49a4ad7efb5a 100644 (file)
@@ -16,7 +16,6 @@ import struct
 import time
 import weakref
 
-from . import events
 from . import base_subprocess
 from . import futures
 from . import exceptions
@@ -29,8 +28,7 @@ from .log import logger
 
 __all__ = (
     'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor',
-    '_DefaultEventLoopPolicy', '_WindowsSelectorEventLoopPolicy',
-    '_WindowsProactorEventLoopPolicy', 'EventLoop',
+    'EventLoop',
 )
 
 
@@ -893,14 +891,4 @@ class _WindowsSubprocessTransport(base_subprocess.BaseSubprocessTransport):
 
 SelectorEventLoop = _WindowsSelectorEventLoop
 
-
-class _WindowsSelectorEventLoopPolicy(events._BaseDefaultEventLoopPolicy):
-    _loop_factory = SelectorEventLoop
-
-
-class _WindowsProactorEventLoopPolicy(events._BaseDefaultEventLoopPolicy):
-    _loop_factory = ProactorEventLoop
-
-
-_DefaultEventLoopPolicy = _WindowsProactorEventLoopPolicy
 EventLoop = ProactorEventLoop
index 138465012a252c5209bbc86efc0b2ef96f5d698f..6393036118010e63aaa209382a8d801b7ee236ec 100644 (file)
@@ -70,7 +70,7 @@ class saved_test_environment:
                  '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 @@ class saved_test_environment:
         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[:]
index a3f8a733a081f62b271a86e05353d4905755a2bf..d17d9a2ecf8d9b08cb7660864a4cca891a184da6 100644 (file)
@@ -2289,10 +2289,10 @@ class _SMALLEST:
 
 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
index cd33878d6c74ba6805e5115169da68f862e66ea6..e9eecbc834155183839b9f87060022be62d8e9b7 100644 (file)
@@ -629,7 +629,7 @@ class AsyncGenAsyncioTest(unittest.TestCase):
     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"):
index e59bc25668b4cba09d10edeae1d68c7347a36f7d..fa3821e0783858c67fe1812f12db2c4d7cc136c0 100644 (file)
@@ -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():
index 6d3edcc36f5c79baf4fd308f520accbd97f5fc9b..8300620bc598403158545fae42a545ccdb345f8a 100644 (file)
@@ -5,7 +5,7 @@ from test.test_asyncio import functional as func_tests
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class ReceiveStuffProto(asyncio.BufferedProtocol):
index f85f39839cbd7988884d7f0df88a49476523e9cb..cd3981c7959a47909bb457da68ded3dcff784e78 100644 (file)
@@ -4,7 +4,7 @@ import unittest
 
 
 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")
index 0561b54a3f19c66d0a7fe2359cb6b2b2ed9ad529..594a48baa32e522dec2596b25279aaad3cb042fe 100644 (file)
@@ -13,7 +13,7 @@ MOCK_ANY = mock.ANY
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class EagerTaskFactoryLoopTests:
index 919d543b0329e9fe2025228f34466445d0f9dc10..fed9bf67217762d623127227c0f2d723756a0ff9 100644 (file)
@@ -38,7 +38,7 @@ from test.support import threading_helper
 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 @@ class AbstractEventLoopTests(unittest.TestCase):
 
 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 @@ class GetEventLoopTestsMixin:
 
 
     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 @@ class GetEventLoopTestsMixin:
 
             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 @@ class GetEventLoopTestsMixin:
         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 @@ class GetEventLoopTestsMixin:
                 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()
 
index 0e149dadd7f1219adc1850501024f21d2c236da0..c60b61c7d41115f77285274ad2bdff02db083612 100644 (file)
@@ -15,7 +15,7 @@ class MyException(Exception):
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class TestFreeThreading:
index 9385a65e52813e6cb46c2df1b7077c55f4fe34d0..320de2180e7db7c2d4d5e869e1d940de9a109fbc 100644 (file)
@@ -17,7 +17,7 @@ from test import support
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 def _fakefunc(f):
index c7c0ebdac1b6760fdc3a29d9e43c3e303769bc7d..cf90835ce87cc306383e4b7186957342831a1ea7 100644 (file)
@@ -7,7 +7,7 @@ from asyncio import tasks
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class FutureTests:
index cffb2b30ad9cff67aa7f3464c01f90208613a5ab..3dde7535284b255c871a7a600de66515a06d3e06 100644 (file)
@@ -6,7 +6,7 @@ from unittest import mock
 
 # 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):
index e025d2990a3f8a52b29fde816d091e623010b934..320a933e144813deedacfd3b58113918886c8826 100644 (file)
@@ -20,7 +20,7 @@ RGX_REPR = re.compile(STR_RGX_REPR)
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class LockTests(unittest.IsolatedAsyncioTestCase):
index 95a9f3a9a7cf716e497258c14302c51fa66194ee..3d4a5d8375f8a244890d727ea7f0331d98116cbd 100644 (file)
@@ -11,7 +11,7 @@ from test.test_asyncio import utils as test_utils
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 # Test that asyncio.iscoroutine() uses collections.abc.Coroutine
index edfad5e11db35e41861784a21c55f7b188c5c4c7..2f229887ad62cc8ba2c3e2980c3e50c6ac39d42d 100644 (file)
@@ -18,7 +18,7 @@ from test.test_asyncio import utils as test_utils
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 def close_transport(transport):
index 29d3bd22705c6af1365b74a0398014a7d97bf924..643199962b8af066dd1ee68170012a05d1d36a31 100644 (file)
@@ -7,7 +7,7 @@ import asyncio
 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):
index 54bbe79f81ff69b136c1ab1779f275bc062ef4ce..7c1548f1948f770d433b3b42f992cae49170ec25 100644 (file)
@@ -6,7 +6,7 @@ from types import GenericAlias
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class QueueBasicTests(unittest.IsolatedAsyncioTestCase):
index 8a4d7f5c796661f10882815c2eb2d4a69059acdb..b9d94833a2cccdddae2f6fd751f807118aac2111 100644 (file)
@@ -12,33 +12,13 @@ from unittest.mock import patch
 
 
 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 @@ class BaseTest(unittest.TestCase):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunTests(BaseTest):
             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 @@ class RunnerTests(BaseTest):
         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.
index 4bb5d4fb816a9a6ec19b816081e89ee6e40f8369..76ba39019e36631c2d14a817efec596b9cc5eabd 100644 (file)
@@ -24,7 +24,7 @@ MOCK_ANY = mock.ANY
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class TestBaseSelectorEventLoop(BaseSelectorEventLoop):
index 7afd7de3bb936e698b8ccc82cb094034659f14ea..2d5c06f82b3ddf19e7b74ae11d4ca5f5655367c8 100644 (file)
@@ -22,7 +22,7 @@ except ImportError:
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class MySendfileProto(asyncio.Protocol):
index 581ea47d2dec976e3b5315578248676fef63bd96..67a46085be31ce09d789becce1da2d5159848850 100644 (file)
@@ -11,7 +11,7 @@ from test.test_asyncio import functional as func_tests
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class BaseStartServer(func_tests.FunctionalTestCaseMixin):
index 3f15654a1af4678a829aa0a1311d9c198282cd86..9ee5eb436e0b8ddb86922d73e63fa9d5cdf4ad4a 100644 (file)
@@ -13,7 +13,7 @@ except ImportError:
 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
index f32dcd589e2de22b261a29e3e77c5cf5b63ce816..5d825440e41ca7cc5a09d0ca9d811e3dcaaa2f29 100644 (file)
@@ -15,7 +15,7 @@ if socket_helper.tcp_blackhole():
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class MyProto(asyncio.Protocol):
index 784c784d261dc6628882da56485bebd85c300ae2..902dc7e04e5809a7a8f3fbd6244771bb0744456e 100644 (file)
@@ -31,7 +31,7 @@ HANDSHAKE_TIMEOUT = support.LONG_TIMEOUT
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class MyBaseProto(asyncio.Protocol):
@@ -185,9 +185,6 @@ class TestSSL(test_utils.TestCase):
     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
index 3e304c166425b0b87011102b3fb49c9aa9b16c82..1b1437b51bab0abcb28d79ac13c30a8147a361f2 100644 (file)
@@ -21,7 +21,7 @@ from test.test_asyncio import functional as func_tests
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 @unittest.skipIf(ssl is None, 'No ssl module')
index 32e4817b70d7173279d7c4fb248a2ba4f8debf06..693bf02001a2c3da460eaab9332af90912114055 100644 (file)
@@ -8,7 +8,7 @@ support.requires_working_socket(module=True)
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class StaggeredTests(unittest.IsolatedAsyncioTestCase):
index cae8c7c6f7c94c97aa8688c61dd35e68ba7d45cc..fb774895a7e52a545771f5233839dd53aada69cc 100644 (file)
@@ -18,7 +18,7 @@ from test.support import socket_helper
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class StreamTests(test_utils.TestCase):
index 4ac6b23b7120fcc8ea17770479573b3befc4ef4d..bb1a7d6ff22be8dbbc0df925384fecf06f377ca7 100644 (file)
@@ -38,7 +38,7 @@ PROGRAM_CAT = [
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class TestSubprocessTransport(base_subprocess.BaseSubprocessTransport):
index 8925884b9dcf731b79f3361650d5b09c283f6703..e1eaa60e4df85df83b53e9e663014d62cd65c973 100644 (file)
@@ -15,7 +15,7 @@ from test.test_asyncio.utils import await_without_task
 
 # 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):
index 56b1494c8363ca6592632b1d40a446b08ae28548..7a217f886b87de271667284870e502a2d1b08d75 100644 (file)
@@ -24,7 +24,7 @@ from test.support.script_helper import assert_python_ok
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 async def coroutine_function():
index 8ad5f9b2c9e75058d71ec73258fda2af54bd2bbc..4300df90ff2b186a27fb74fe9a895096122cffb1 100644 (file)
@@ -8,7 +8,7 @@ from unittest import mock
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class ToThreadTests(unittest.IsolatedAsyncioTestCase):
index f60722c48b7617940690ffe0203b45666807edc7..69936aae5cc81d883a0a826aa13172a8ffe62bb5 100644 (file)
@@ -9,7 +9,7 @@ from test.test_asyncio.utils import await_without_task
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 class TimeoutTests(unittest.IsolatedAsyncioTestCase):
 
index 1781f1f67753f3afb492d8fff21fd79317c1ace2..5e743345028bec67604634b303e4230f641c6d2d 100644 (file)
@@ -10,7 +10,7 @@ from asyncio import transports
 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):
index 118cb866997c51c6e4faaa733635cb73de5ee2de..e88437eb2337ff0617337146f91977e1e2e81325 100644 (file)
@@ -30,7 +30,7 @@ from test.test_asyncio import utils as test_utils
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 MOCK_ANY = mock.ANY
index dedc6bf69d770e4540da7e402eeee011e7b65504..56dbafd88e45ef1d74a5c745d295532b07dae985 100644 (file)
@@ -5,7 +5,7 @@ from test import support
 
 
 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:
index 0af3368627afca7d7ec750e5da8524228bf6d34a..c40391b237d57e401ad994d210b5da98f79ccfe0 100644 (file)
@@ -19,7 +19,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 UpperProto(asyncio.Protocol):
@@ -324,40 +324,5 @@ class ProactorTests(WindowsEventsTestCase):
         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()
index 50969761347595332d3597a86dcabac84b24a79a..1ac77262d1420dcc586956d8ca333547896e3654 100644 (file)
@@ -16,7 +16,7 @@ from test import support
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class PipeTests(unittest.TestCase):
index 62cfcf8ceb5f2a8bffb531aa6f89e6a1d8681b02..e86c221d7f702596ec952c573ff1ebc245d815ff 100644 (file)
@@ -601,9 +601,3 @@ async def await_without_task(coro):
     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
index 7241fcc4b1e74d73125313a6844734a75f72d112..db5b89bb76ada96494b6b2ea1fde9bde2d32ecb0 100644 (file)
@@ -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()
index 93e9e7a8393cb1068b31f7b64ad92a3b37c3638c..9d415238876c8f1b5d175e712fbda0003446d627 100644 (file)
@@ -2321,7 +2321,7 @@ class CoroAsyncIOCompatTest(unittest.TestCase):
             pass
         finally:
             loop.close()
-            asyncio.events._set_event_loop_policy(None)
+            asyncio.set_event_loop(None)
 
         self.assertEqual(buffer, [1, 2, 'MyException'])
 
index 7351f97fd9a4b5c8889c8299eab671749309ce06..495702badc3a7f1a2d301690a8e5f415734fb901 100644 (file)
@@ -2988,7 +2988,7 @@ class TestGetAsyncGenState(unittest.IsolatedAsyncioTestCase):
 
     @classmethod
     def tearDownClass(cls):
-        asyncio.events._set_event_loop_policy(None)
+        asyncio.set_event_loop(None)
 
     def _asyncgenstate(self):
         return inspect.getasyncgenstate(self.asyncgen)
index fcd3da61a078aec3e2dc5e490f6497f8a2e45349..a7ea128d64055a1d94194f5582b978ca95a92dec 100644 (file)
@@ -5504,7 +5504,7 @@ class LogRecordTest(BaseTest):
                 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):
@@ -5516,7 +5516,7 @@ class LogRecordTest(BaseTest):
                 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):
@@ -5841,7 +5841,7 @@ class BasicConfigTest(unittest.TestCase):
                 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()
 
index b88388e091312a0fa1422812c59109362d03f82b..c75929fa86bedd2c45b0dd34836a1d7f6d6c346c 100644 (file)
@@ -92,7 +92,7 @@ requires_splice_pipe = unittest.skipIf(sys.platform.startswith("aix"),
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class MiscTests(unittest.TestCase):
index 410f1436ed4d20a1d13d03429d35c871cb466be9..0cf5dd2e4c1004231c90eda997f62e1b5fdf8aec 100644 (file)
@@ -17,7 +17,7 @@ import linecache
 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 load_tests(loader, tests, pattern):
         # 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
index 91d45283eb3b1bb93086df59388080af89c3b8eb..fae8f0e325353c53101eb03d5167f291021846d5 100644 (file)
@@ -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 @@ class TestAsyncCase(unittest.TestCase):
 
         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 @@ class TestAsyncCase(unittest.TestCase):
         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 @@ class TestAsyncCase(unittest.TestCase):
         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()
index dc36ceeb6502e847a6183c06509a4efc55065d12..f96aef7325ff4c1a2220686dc6f359a7b9ab59e9 100644 (file)
@@ -15,7 +15,7 @@ from unittest.mock import (ANY, call, AsyncMock, patch, MagicMock, Mock,
 
 
 def tearDownModule():
-    asyncio.events._set_event_loop_policy(None)
+    asyncio.set_event_loop(None)
 
 
 class AsyncClass:
index a1c0d6c368ce8a48954c9bc7fc3a4f3f4e170073..36128c5fb953c524cecf5095e0bc6e7d5f6f6b80 100644 (file)
@@ -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 (file)
index 0000000..c295d5f
--- /dev/null
@@ -0,0 +1 @@
+Remove the deprecated :mod:`asyncio` event loop policy system. Patch by Kumar Aditya.
index 57c8d4a41a3a0dffdba6dda31c0e1533b29dba7d..bc0f7f3901e0edae9ae03d4e000c0824d4f7ecd8 100644 (file)
@@ -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);
 }
 
 
@@ -3638,12 +3630,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);
@@ -4192,7 +4185,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);
@@ -4222,7 +4215,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);
@@ -4285,7 +4278,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")
index f07a09df5ac7ae0a2edf23c3b8e38e44ffba5889..8bbef6b5023125066ae10abe1eb2334ea14d39f9 100644 (file)
@@ -1582,7 +1582,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__},
@@ -2233,4 +2234,4 @@ _asyncio_future_discard_from_awaited_by(PyObject *module, PyObject *const *args,
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=32996fb47c48245b input=a9049054013a1b77]*/
+/*[clinic end generated code: output=22e74568ff49f81f input=a9049054013a1b77]*/