]> granicus.if.org Git - python/commitdiff
Issue #22601: run_forever() now consumes BaseException of the temporary task
authorVictor Stinner <victor.stinner@gmail.com>
Sat, 11 Oct 2014 12:30:18 +0000 (14:30 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Sat, 11 Oct 2014 12:30:18 +0000 (14:30 +0200)
If the coroutine raised a BaseException, consume the exception to not log a
warning. The caller doesn't have access to the local task.

Lib/asyncio/base_events.py
Lib/test/test_asyncio/test_base_events.py

index 3cff72abb5286500732a72d9af3ff354c1a56337..b6b712393bce56031686dcafe01665006f363b72 100644 (file)
@@ -268,7 +268,15 @@ class BaseEventLoop(events.AbstractEventLoop):
             future._log_destroy_pending = False
 
         future.add_done_callback(_raise_stop_error)
-        self.run_forever()
+        try:
+            self.run_forever()
+        except:
+            if new_task and future.done() and not future.cancelled():
+                # The coroutine raised a BaseException. Consume the exception
+                # to not log a warning, the caller doesn't have access to the
+                # local task.
+                future.exception()
+            raise
         future.remove_done_callback(_raise_stop_error)
         if not future.done():
             raise RuntimeError('Event loop stopped before Future completed.')
index 294872a99fbc3cc97bbb8d495cea53bb315fba28..afc448c0da8e5ccb08770aff47f9901784ccd0af 100644 (file)
@@ -9,7 +9,7 @@ import time
 import unittest
 from unittest import mock
 from test.script_helper import assert_python_ok
-from test.support import IPV6_ENABLED
+from test.support import IPV6_ENABLED, gc_collect
 
 import asyncio
 from asyncio import base_events
@@ -618,6 +618,26 @@ class BaseEventLoopTests(test_utils.TestCase):
         task._log_destroy_pending = False
         coro.close()
 
+    def test_run_forever_keyboard_interrupt(self):
+        # Python issue #22601: ensure that the temporary task created by
+        # run_forever() consumes the KeyboardInterrupt and so don't log
+        # a warning
+        @asyncio.coroutine
+        def raise_keyboard_interrupt():
+            raise KeyboardInterrupt
+
+        self.loop._process_events = mock.Mock()
+        self.loop.call_exception_handler = mock.Mock()
+
+        try:
+            self.loop.run_until_complete(raise_keyboard_interrupt())
+        except KeyboardInterrupt:
+            pass
+        self.loop.close()
+        gc_collect()
+
+        self.assertFalse(self.loop.call_exception_handler.called)
+
 
 class MyProto(asyncio.Protocol):
     done = None