Issue #22601: run_forever() now consumes BaseException of the temporary task

If the coroutine raised a BaseException, consume the exception to not log a
warning. The caller doesn't have access to the local task.
This commit is contained in:
Victor Stinner 2014-10-11 14:30:18 +02:00
parent 682124ccc3
commit c8bd53f815
2 changed files with 30 additions and 2 deletions

View 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.')

View 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