https://github.com/python/cpython/commit/b3154aa4507f6d2612c128e912860be963dbff1a
commit: b3154aa4507f6d2612c128e912860be963dbff1a
branch: main
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-06-27T12:46:50+05:30
summary:
gh-127949: remove asyncio policy system (#150310)
files:
A Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst
D Doc/library/asyncio-policy.rst
M Doc/deprecations/pending-removal-in-3.16.rst
M Doc/library/asyncio-eventloop.rst
M Doc/library/asyncio-llapi-index.rst
M Doc/library/asyncio-runner.rst
M Doc/library/asyncio.rst
M Doc/tools/check-html-ids.py
M Doc/tools/removed-ids.txt
M Doc/whatsnew/3.14.rst
M Doc/whatsnew/3.16.rst
M Include/internal/pycore_global_objects_fini_generated.h
M Include/internal/pycore_global_strings.h
M Include/internal/pycore_runtime_init_generated.h
M Include/internal/pycore_unicodeobject_generated.h
M Lib/asyncio/__init__.py
M Lib/asyncio/events.py
M Lib/asyncio/unix_events.py
M Lib/asyncio/windows_events.py
M Lib/test/libregrtest/save_env.py
M Lib/test/support/__init__.py
M Lib/test/test_asyncgen.py
M Lib/test/test_asyncio/test_base_events.py
M Lib/test/test_asyncio/test_buffered_proto.py
M Lib/test/test_asyncio/test_context.py
M Lib/test/test_asyncio/test_eager_task_factory.py
M Lib/test/test_asyncio/test_events.py
M Lib/test/test_asyncio/test_free_threading.py
M Lib/test/test_asyncio/test_futures.py
M Lib/test/test_asyncio/test_futures2.py
M Lib/test/test_asyncio/test_graph.py
M Lib/test/test_asyncio/test_locks.py
M Lib/test/test_asyncio/test_pep492.py
M Lib/test/test_asyncio/test_proactor_events.py
M Lib/test/test_asyncio/test_protocols.py
M Lib/test/test_asyncio/test_queues.py
M Lib/test/test_asyncio/test_runners.py
M Lib/test/test_asyncio/test_selector_events.py
M Lib/test/test_asyncio/test_sendfile.py
M Lib/test/test_asyncio/test_server.py
M Lib/test/test_asyncio/test_server_context.py
M Lib/test/test_asyncio/test_sock_lowlevel.py
M Lib/test/test_asyncio/test_ssl.py
M Lib/test/test_asyncio/test_sslproto.py
M Lib/test/test_asyncio/test_staggered.py
M Lib/test/test_asyncio/test_streams.py
M Lib/test/test_asyncio/test_subprocess.py
M Lib/test/test_asyncio/test_taskgroups.py
M Lib/test/test_asyncio/test_tasks.py
M Lib/test/test_asyncio/test_threads.py
M Lib/test/test_asyncio/test_timeouts.py
M Lib/test/test_asyncio/test_transports.py
M Lib/test/test_asyncio/test_unix_events.py
M Lib/test/test_asyncio/test_waitfor.py
M Lib/test/test_asyncio/test_windows_events.py
M Lib/test/test_asyncio/test_windows_utils.py
M Lib/test/test_asyncio/utils.py
M Lib/test/test_concurrent_futures/test_interpreter_pool.py
M Lib/test/test_coroutines.py
M Lib/test/test_inspect/test_inspect.py
M Lib/test/test_logging.py
M Lib/test/test_os/test_os.py
M Lib/test/test_pdb.py
M Lib/test/test_unittest/test_async_case.py
M Lib/test/test_unittest/testmock/testasync.py
M Lib/unittest/async_case.py
M Modules/_asynciomodule.c
M Modules/clinic/_asynciomodule.c.h
diff --git a/Doc/deprecations/pending-removal-in-3.16.rst
b/Doc/deprecations/pending-removal-in-3.16.rst
index 5a28cc766a95961..9b19ec3236f92fb 100644
--- a/Doc/deprecations/pending-removal-in-3.16.rst
+++ b/Doc/deprecations/pending-removal-in-3.16.rst
@@ -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.
diff --git a/Doc/library/asyncio-eventloop.rst
b/Doc/library/asyncio-eventloop.rst
index 79c9516cda2d60b..65bc349e2a727d3 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 <asyncio-policies>`.
-
.. rubric:: Contents
diff --git a/Doc/library/asyncio-llapi-index.rst
b/Doc/library/asyncio-llapi-index.rst
index f5af888f31f1863..faf67209a2b0ef5 100644
--- a/Doc/library/asyncio-llapi-index.rst
+++ b/Doc/library/asyncio-llapi-index.rst
@@ -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
index 57f964912dd6ea2..000000000000000
--- 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 <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())
diff --git a/Doc/library/asyncio-runner.rst b/Doc/library/asyncio-runner.rst
index 48d78099fd3ce7e..cd125b30703c796 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 90a465f3e1d3af4..4ae6d1e43f2ac7b 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/tools/check-html-ids.py b/Doc/tools/check-html-ids.py
index 7d86c6cc3264ad5..3ea0a99d1dd4f68 100644
--- a/Doc/tools/check-html-ids.py
+++ b/Doc/tools/check-html-ids.py
@@ -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:
diff --git a/Doc/tools/removed-ids.txt b/Doc/tools/removed-ids.txt
index 271b383ba812307..0549ae735a92d63 100644
--- a/Doc/tools/removed-ids.txt
+++ b/Doc/tools/removed-ids.txt
@@ -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)
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index cd0d8b7cb006fee..2fa7267292d9940 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 e29d6e9b9e25ee9..7841fa56cc5952c 100644
--- a/Doc/whatsnew/3.16.rst
+++ b/Doc/whatsnew/3.16.rst
@@ -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
---------
diff --git a/Include/internal/pycore_global_objects_fini_generated.h
b/Include/internal/pycore_global_objects_fini_generated.h
index 87dde5e062bd724..7d952a1e52561a6 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -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));
diff --git a/Include/internal/pycore_global_strings.h
b/Include/internal/pycore_global_strings.h
index 43286fa36bbb05c..8a8bbc3b6d05bf7 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -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)
diff --git a/Include/internal/pycore_runtime_init_generated.h
b/Include/internal/pycore_runtime_init_generated.h
index 116dbf84f790124..366d2d300fb4780 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -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), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h
b/Include/internal/pycore_unicodeobject_generated.h
index f7197b39d9bd3ab..00d6297432b5fca 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -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));
diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py
index 32a5dbae03af216..2432e2dad74c23d 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 42d8408a38dfd1f..807c70bc775aa2c 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
@@ -665,84 +662,11 @@ def set_debug(self, enabled):
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 @@ 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 676e0b670faa49b..93dd8994e1bcd51 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -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
diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py
index 0bf7732136f1f8e..8241c10b32d105c 100644
--- a/Lib/asyncio/windows_events.py
+++ b/Lib/asyncio/windows_events.py
@@ -16,7 +16,6 @@
import time
import weakref
-from . import events
from . import base_subprocess
from . import futures
from . import exceptions
@@ -29,8 +28,7 @@
__all__ = (
'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor',
- '_DefaultEventLoopPolicy', '_WindowsSelectorEventLoopPolicy',
- '_WindowsProactorEventLoopPolicy', 'EventLoop',
+ 'EventLoop',
)
@@ -893,14 +891,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 138465012a252c5..6393036118010e6 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 a3f8a733a081f62..d17d9a2ecf8d9b0 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2289,10 +2289,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 cd33878d6c74ba6..e9eecbc83415518 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 e59bc25668b4cba..fa3821e0783858c 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 6d3edcc36f5c79b..8300620bc598403 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 f85f39839cbd798..cd3981c7959a479 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 0561b54a3f19c66..594a48baa32e522 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 919d543b0329e9f..fed9bf67217762d 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 0e149dadd7f1219..c60b61c7d41115f 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 9385a65e52813e6..320de2180e7db7c 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 c7c0ebdac1b6760..cf90835ce87cc30 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 cffb2b30ad9cff6..3dde7535284b255 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 e025d2990a3f8a5..320a933e144813d 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 95a9f3a9a7cf716..3d4a5d8375f8a24 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 edfad5e11db35e4..2f229887ad62cc8 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 29d3bd22705c6af..643199962b8af06 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 54bbe79f81ff69b..7c1548f1948f770 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 8a4d7f5c796661f..b9d94833a2cccdd 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 4bb5d4fb816a9a6..76ba39019e36631 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 7afd7de3bb936e6..2d5c06f82b3ddf1 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 581ea47d2dec976..67a46085be31ce0 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 3f15654a1af4678..9ee5eb436e0b8dd 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 f32dcd589e2de22..5d825440e41ca7c 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 784c784d261dc66..902dc7e04e5809a 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 3e304c166425b0b..1b1437b51bab0ab 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 32e4817b70d7173..693bf02001a2c3d 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 cae8c7c6f7c94c9..fb774895a7e52a5 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 4ac6b23b7120fcc..bb1a7d6ff22be8d 100644
--- a/Lib/test/test_asyncio/test_subprocess.py
+++ b/Lib/test/test_asyncio/test_subprocess.py
@@ -38,7 +38,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 8925884b9dcf731..e1eaa60e4df85df 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 56b1494c8363ca6..7a217f886b87de2 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 8ad5f9b2c9e7505..4300df90ff2b186 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 f60722c48b76179..69936aae5cc81d8 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 1781f1f67753f3a..5e743345028bec6 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 118cb866997c51c..e88437eb2337ff0 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 dedc6bf69d770e4..56dbafd88e45ef1 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 0af3368627afca7..c40391b237d57e4 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 509697613475953..1ac77262d1420dc 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 62cfcf8ceb5f2a8..e86c221d7f70259 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 7241fcc4b1e74d7..db5b89bb76ada96 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 93e9e7a8393cb10..9d415238876c8f1 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 7351f97fd9a4b5c..495702badc3a7f1 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 fcd3da61a078aec..a7ea128d64055a1 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -5504,7 +5504,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):
@@ -5516,7 +5516,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):
@@ -5841,7 +5841,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 b88388e091312a0..c75929fa86bedd2 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 410f1436ed4d20a..0cf5dd2e4c10042 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 91d45283eb3b1bb..fae8f0e325353c5 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 dc36ceeb6502e84..f96aef7325ff4c1 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 a1c0d6c368ce8a4..36128c5fb953c52 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 000000000000000..c295d5fffd82fcf
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-05-19-11-42-37.gh-issue-127949.Ab3kZq.rst
@@ -0,0 +1 @@
+Remove the deprecated :mod:`asyncio` event loop policy system. Patch by Kumar
Aditya.
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index 57c8d4a41a3a0df..bc0f7f3901e0eda 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);
}
@@ -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")
diff --git a/Modules/clinic/_asynciomodule.c.h
b/Modules/clinic/_asynciomodule.c.h
index f07a09df5ac7ae0..8bbef6b50231250 100644
--- a/Modules/clinic/_asynciomodule.c.h
+++ b/Modules/clinic/_asynciomodule.c.h
@@ -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]*/
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]