Skip to content

Commit 872e4c7

Browse files
miss-islingtonOsmnvAslanasvetlov
authored
[3.14] gh-157856: Fix asyncio.as_completed() outside a running event loop (GH-157857) (#160231)
gh-157856: Fix `asyncio.as_completed()` outside a running event loop (GH-157857) (cherry picked from commit b12fcff) Co-authored-by: Aslan Osmanov <32789812+OsmnvAslan@users.noreply.github.com> Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
1 parent 33fdd01 commit 872e4c7

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎Lib/asyncio/tasks.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,13 @@ def __init__(self, aws, timeout):
567567
self._timeout_handle = None
568568

569569
loop = events.get_event_loop()
570-
self._cur_task = current_task()
570+
# The iterator may be created outside of a running event loop and
571+
# then driven with loop.run_until_complete(), in which case there
572+
# is no current task to record as the waiter.
573+
if events._get_running_loop() is loop:
574+
self._cur_task = current_task(loop)
575+
else:
576+
self._cur_task = None
571577
todo = {ensure_future(aw, loop=loop) for aw in set(aws)}
572578
for f in todo:
573579
f.add_done_callback(self._handle_completion)

‎Lib/test/test_asyncio/test_tasks.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,22 @@ async def coro():
18431843
futs = asyncio.as_completed([a])
18441844
list(futs)
18451845

1846+
def test_as_completed_outside_running_loop(self):
1847+
# gh-157856: as_completed() must not require a running event loop
1848+
# when the iterator is created, only when it is driven.
1849+
loop = self.new_test_loop()
1850+
self.addCleanup(asyncio.set_event_loop, None)
1851+
asyncio.set_event_loop(loop)
1852+
1853+
async def coro(v):
1854+
await asyncio.sleep(0)
1855+
return v
1856+
1857+
tasks = [loop.create_task(coro(v)) for v in (1, 2)]
1858+
futs = asyncio.as_completed(tasks)
1859+
results = [loop.run_until_complete(f) for f in futs]
1860+
self.assertEqual(sorted(results), [1, 2])
1861+
18461862
def test_as_completed_coroutine_use_running_loop(self):
18471863
loop = self.new_test_loop()
18481864

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :func:`asyncio.as_completed` raising :exc:`RuntimeError` ("no running
2+
event loop") when the iterator is created outside of a running event loop and
3+
driven with :meth:`loop.run_until_complete() <asyncio.loop.run_until_complete>`.

0 commit comments

Comments
 (0)