Skip to content

Commit e5ecca2

Browse files
committed
gh-145342: Adapt guest mode to current main and fix docs CI
- test_guest: use asyncio.set_event_loop(None) in tearDownModule; the event loop policy system was removed on main. - Docs: de-duplicate the poll_events/process_events/process_ready reference entries (keep asyncio-eventloop.rst as the canonical location), fix cross-references to the loop.* targets, bump versionadded to 3.16, and add a What's New entry.
1 parent 8baa930 commit e5ecca2

6 files changed

Lines changed: 49 additions & 59 deletions

File tree

Doc/library/asyncio-eventloop.rst

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,27 +210,40 @@ Running and stopping the loop
210210
Decomposing event loop iteration
211211
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
212212

213-
The following methods decompose a single :meth:`~asyncio.BaseEventLoop._run_once`
214-
iteration into independently callable steps. They are used internally by
215-
:func:`asyncio.start_guest_run`; see :ref:`asyncio-guest` for full documentation.
213+
The following methods decompose a single iteration of the event loop
214+
into independently callable steps. They are used internally by
215+
:func:`asyncio.start_guest_run`; see :ref:`asyncio-guest` for full
216+
documentation.
216217

217218
.. method:: loop.poll_events()
218219

219-
Poll for I/O events and return the raw event list.
220+
Poll for I/O events without processing them.
220221

221-
.. versionadded:: 3.15
222+
Cleans up cancelled scheduled handles, computes an appropriate
223+
timeout from the scheduled callbacks, and calls the underlying
224+
selector. Returns the raw event list.
225+
226+
.. versionadded:: 3.16
222227

223228
.. method:: loop.process_events(event_list)
224229

225230
Process I/O events returned by :meth:`poll_events`.
226231

227-
.. versionadded:: 3.15
232+
Delegates to the selector-specific event processing that turns raw
233+
selector events into ready callbacks.
234+
235+
.. versionadded:: 3.16
228236

229237
.. method:: loop.process_ready()
230238

231239
Process expired timers and execute ready callbacks.
232240

233-
.. versionadded:: 3.15
241+
Moves scheduled callbacks whose deadline has passed into the ready
242+
queue, then runs all callbacks that were ready at call time.
243+
Callbacks enqueued *by* running callbacks are left for the next
244+
iteration.
245+
246+
.. versionadded:: 3.16
234247

235248
Scheduling callbacks
236249
^^^^^^^^^^^^^^^^^^^^

Doc/library/asyncio-guest.rst

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ replacing the host loop, asyncio piggybacks on it:
2222
When I/O events arrive it hands them back to the host thread via a
2323
thread-safe callback. The thread is not a daemon thread; it is joined
2424
when the guest run finishes.
25-
* The host thread then runs :meth:`~asyncio.BaseEventLoop.process_events`
26-
and :meth:`~asyncio.BaseEventLoop.process_ready` to advance the asyncio
27-
event loop by one step, then signals the I/O thread to poll again.
25+
* The host thread then runs
26+
:meth:`loop.process_events() <asyncio.loop.process_events>` and
27+
:meth:`loop.process_ready() <asyncio.loop.process_ready>` to advance
28+
the asyncio event loop by one step, then signals the I/O thread to
29+
poll again.
2830

2931
Exactly one of the two threads touches the event loop at any moment, so
3032
neither the host loop nor the asyncio loop starves the other.
@@ -74,7 +76,7 @@ example that embeds asyncio inside ``tkinter.mainloop()`` using
7476
This wakes the I/O thread from its selector wait so cancellation is
7577
processed promptly.
7678

77-
.. versionadded:: 3.15
79+
.. versionadded:: 3.16
7880

7981
.. _asyncio-guest-lifecycle:
8082

@@ -128,40 +130,10 @@ Host Requirements
128130

129131
.. rubric:: Low-level Event Loop Methods
130132

131-
The following three methods on :class:`BaseEventLoop` are used internally by
132-
:func:`start_guest_run`. They decompose :meth:`~BaseEventLoop._run_once`
133-
into independently callable steps and are documented here for completeness.
134-
135-
.. method:: loop.poll_events()
136-
137-
Poll for I/O events without processing them.
138-
139-
Cleans up cancelled scheduled handles, computes an appropriate timeout
140-
from the scheduled callbacks, and calls the underlying selector. Returns
141-
the raw event list.
142-
143-
Together with :meth:`~BaseEventLoop.process_events` and
144-
:meth:`~BaseEventLoop.process_ready`, this method decomposes
145-
:meth:`~BaseEventLoop._run_once` into independently callable steps so that
146-
an external event loop can drive asyncio (see :func:`start_guest_run`).
147-
148-
.. versionadded:: 3.15
149-
150-
.. method:: loop.process_events(event_list)
151-
152-
Process I/O events returned by :meth:`~BaseEventLoop.poll_events`.
153-
154-
Delegates to the selector-specific ``_process_events`` implementation
155-
which turns raw selector events into ready callbacks.
156-
157-
.. versionadded:: 3.15
158-
159-
.. method:: loop.process_ready()
160-
161-
Process expired timers and execute ready callbacks.
162-
163-
Moves scheduled callbacks whose deadline has passed into the ready queue,
164-
then runs all callbacks that were ready at call time. Callbacks enqueued
165-
*by* running callbacks are left for the next iteration.
166-
167-
.. versionadded:: 3.15
133+
:func:`start_guest_run` drives the loop through three low-level methods
134+
-- :meth:`loop.poll_events() <asyncio.loop.poll_events>`,
135+
:meth:`loop.process_events() <asyncio.loop.process_events>`, and
136+
:meth:`loop.process_ready() <asyncio.loop.process_ready>` -- which
137+
decompose a single iteration of the event loop into independently
138+
callable steps. See :ref:`asyncio-event-loop` for their reference
139+
documentation.

Doc/whatsnew/3.16.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ asyncio
109109
socket file created for *path*.
110110
(Contributed by Sam Bull in :gh:`94984`.)
111111

112+
* Add :func:`asyncio.start_guest_run` to run asyncio cooperatively inside
113+
a host event loop, such as a GUI toolkit's main loop, that owns the
114+
thread. See :ref:`asyncio-guest`.
115+
(Contributed by Cong Zhang in :gh:`145342`.)
116+
112117

113118
codecs
114119
------

Lib/asyncio/base_events.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,7 +2005,7 @@ def poll_events(self):
20052005
independently callable steps so that an external event loop can
20062006
drive asyncio (see :func:`asyncio.start_guest_run`).
20072007
2008-
.. versionadded:: 3.15
2008+
.. versionadded:: 3.16
20092009
"""
20102010
sched_count = len(self._scheduled)
20112011
if (sched_count > _MIN_SCHEDULED_TIMER_HANDLES and
@@ -2050,7 +2050,7 @@ def process_events(self, event_list):
20502050
implementation which turns raw selector events into ready
20512051
callbacks.
20522052
2053-
.. versionadded:: 3.15
2053+
.. versionadded:: 3.16
20542054
"""
20552055
self._process_events(event_list)
20562056

@@ -2062,7 +2062,7 @@ def process_ready(self):
20622062
time. Callbacks enqueued *by* running callbacks are left for
20632063
the next iteration.
20642064
2065-
.. versionadded:: 3.15
2065+
.. versionadded:: 3.16
20662066
"""
20672067
# Handle 'later' callbacks that are ready.
20682068
now = self.time()

Lib/test/test_asyncio/test_guest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
def tearDownModule():
18-
asyncio.events._set_event_loop_policy(None)
18+
asyncio.set_event_loop(None)
1919

2020

2121
class MockHost:

Misc/NEWS.d/next/Library/2026-02-28-14-00-00.gh-issue-145342.GuestMode.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ inside a host event loop (e.g. Tkinter, Qt, GTK). The host loop retains
33
control of its thread while asyncio I/O polling runs in a background
44
non-daemon thread that is joined when the run finishes. In guest mode the
55
host owns signal handling: the loop never touches
6-
:func:`signal.set_wakeup_fd` and :meth:`loop.add_signal_handler` raises
7-
:exc:`RuntimeError`. Also adds three low-level
8-
:class:`~asyncio.BaseEventLoop` methods --
9-
:meth:`~asyncio.BaseEventLoop.poll_events`,
10-
:meth:`~asyncio.BaseEventLoop.process_events`, and
11-
:meth:`~asyncio.BaseEventLoop.process_ready` -- that decompose
12-
:meth:`~asyncio.BaseEventLoop._run_once` into independently callable steps.
6+
:func:`signal.set_wakeup_fd` and :meth:`loop.add_signal_handler
7+
<asyncio.loop.add_signal_handler>` raises :exc:`RuntimeError`. Also adds
8+
three low-level event loop methods -- :meth:`loop.poll_events
9+
<asyncio.loop.poll_events>`, :meth:`loop.process_events
10+
<asyncio.loop.process_events>`, and :meth:`loop.process_ready
11+
<asyncio.loop.process_ready>` -- that decompose a single iteration of the
12+
event loop into independently callable steps.

0 commit comments

Comments
 (0)