[Python-checkins] cpython (3.4): Closes #22429, asyncio: Fix EventLoop.run_until_complete(), don't stop the

victor.stinner python-checkins at python.org
Fri Dec 5 01:45:37 CET 2014


https://hg.python.org/cpython/rev/83bddbfbd3a4
changeset:   93727:83bddbfbd3a4
branch:      3.4
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Fri Dec 05 01:44:10 2014 +0100
summary:
  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.

files:
  Lib/asyncio/base_events.py                |  14 +++++-
  Lib/test/test_asyncio/test_base_events.py |  25 +++++++++++
  2 files changed, 37 insertions(+), 2 deletions(-)


diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -102,6 +102,16 @@
     raise _StopError
 
 
+def _run_until_complete_cb(fut):
+    exc = fut._exception
+    if (isinstance(exc, BaseException)
+    and not isinstance(exc, Exception)):
+        # Issue #22429: run_forever() already finished, no need to
+        # stop it.
+        return
+    _raise_stop_error()
+
+
 class Server(events.AbstractServer):
 
     def __init__(self, loop, sockets):
@@ -268,7 +278,7 @@
             # is no need to log the "destroy pending task" message
             future._log_destroy_pending = False
 
-        future.add_done_callback(_raise_stop_error)
+        future.add_done_callback(_run_until_complete_cb)
         try:
             self.run_forever()
         except:
@@ -278,7 +288,7 @@
                 # local task.
                 future.exception()
             raise
-        future.remove_done_callback(_raise_stop_error)
+        future.remove_done_callback(_run_until_complete_cb)
         if not future.done():
             raise RuntimeError('Event loop stopped before Future completed.')
 
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -638,6 +638,31 @@
 
         self.assertFalse(self.loop.call_exception_handler.called)
 
+    def test_run_until_complete_baseexception(self):
+        # Python issue #22429: run_until_complete() must not schedule a pending
+        # call to stop() if the future raised a BaseException
+        @asyncio.coroutine
+        def raise_keyboard_interrupt():
+            raise KeyboardInterrupt
+
+        self.loop._process_events = mock.Mock()
+
+        try:
+            self.loop.run_until_complete(raise_keyboard_interrupt())
+        except KeyboardInterrupt:
+            pass
+
+        def func():
+            self.loop.stop()
+            func.called = True
+        func.called = False
+        try:
+            self.loop.call_soon(func)
+            self.loop.run_forever()
+        except KeyboardInterrupt:
+            pass
+        self.assertTrue(func.called)
+
 
 class MyProto(asyncio.Protocol):
     done = None

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list