10000 Closes #22429, asyncio: Fix EventLoop.run_until_complete(), don't sto… · python/cpython@f3e2e09 · GitHub
[go: up one dir, main page]

Skip to content

Commit f3e2e09

Browse files
committed
Closes #22429, asyncio: Fix EventLoop.run_until_complete(), don't stop the
event loop if a BaseException is raised, because the event loop is already stopped.
1 parent 4c85ec9 commit f3e2e09

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

Lib/asyncio/base_events.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ def _raise_stop_error(*args):
102102
raise _StopError
103103

104104

105+
def _run_until_complete_cb(fut):
106+
exc = fut._exception
107+
if (isinstance(exc, BaseException)
108+
and not isinstance(exc, Exception)):
109+
# Issue #22429: run_forever() already finished, no need to
110+
# stop it.
111+
return
112+
_raise_stop_error()
113+
114+
105115
class Server(events.AbstractServer):
106116

107117
def __init__(self, loop, sockets):
@@ -268,7 +278,7 @@ def run_until_complete(self, future):
268278
# is no need to log the "destroy pending task" message
269279
future._log_destroy_pending = False
270280

271-
future.add_done_callback(_raise_stop_error)
281+
future.add_done_callback(_run_until_complete_cb)
272282
try:
273283
self.run_forever()
274284
except:
@@ -278,7 +288,7 @@ def run_until_complete(self, future):
278288
# local task.
279289
future.exception()
280290
raise
281-
future.remove_done_callback(_raise_stop_error)
291+
future.remove_done_callback(_run_until_complete_cb)
282292
if not future.done():
283293
raise RuntimeError('Event loop stopped before Future completed.')
284294

Lib/test/test_asyncio/test_base_events.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,31 @@ def raise_keyboard_interrupt():
638638

639639
self.assertFalse(self.loop.call_exception_handler.called)
640640

641+
def test_run_until_complete_baseexception(self):
642+
# Python issue #22429: run_until_complete() must not schedule a pending
643+
# call to stop() if the future raised a BaseException
644+
@asyncio.coroutine
645+
def raise_keyboard_interrupt():
646+
raise KeyboardInterrupt
647+
648+
self.loop._process_events = mock.Mock()
649+
650+
try:
651+
self.loop.run_until_complete(raise_keyboard_interrupt())
652+
except KeyboardInterrupt:
653+
pass
654+
655+
def func():
656+
self.loop.stop()
657+
func.called = True
658+
func.called = False
659+
try:
660+
self.loop.call_soon(func)
661+
self.loop.run_forever()
662+
except KeyboardInterrupt:
663+
pass
664+
self.assertTrue(func.called)
665+
641666

642667
class MyProto(asyncio.Protocol):
643668
done = None

0 commit comments

Comments
 (0)
0