mirror of
https://github.com/python/cpython.git
synced 2025-11-25 04:34:37 +00:00
gh-113538: Don't error in stream reader protocol callback when task is cancelled (#113690)
This commit is contained in:
parent
1600d78e2d
commit
4681a5271a
3 changed files with 21 additions and 7 deletions
|
|
@ -246,6 +246,9 @@ class StreamReaderProtocol(FlowControlMixin, protocols.Protocol):
|
||||||
self._stream_writer)
|
self._stream_writer)
|
||||||
if coroutines.iscoroutine(res):
|
if coroutines.iscoroutine(res):
|
||||||
def callback(task):
|
def callback(task):
|
||||||
|
if task.cancelled():
|
||||||
|
transport.close()
|
||||||
|
return
|
||||||
exc = task.exception()
|
exc = task.exception()
|
||||||
if exc is not None:
|
if exc is not None:
|
||||||
self._loop.call_exception_handler({
|
self._loop.call_exception_handler({
|
||||||
|
|
|
||||||
|
|
@ -1129,7 +1129,7 @@ os.close(fd)
|
||||||
|
|
||||||
self.assertEqual(messages, [])
|
self.assertEqual(messages, [])
|
||||||
|
|
||||||
def test_unhandled_exceptions(self) -> None:
|
def _basetest_unhandled_exceptions(self, handle_echo):
|
||||||
port = socket_helper.find_unused_port()
|
port = socket_helper.find_unused_port()
|
||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
|
|
@ -1143,9 +1143,6 @@ os.close(fd)
|
||||||
await wr.wait_closed()
|
await wr.wait_closed()
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
async def handle_echo(reader, writer):
|
|
||||||
raise Exception('test')
|
|
||||||
|
|
||||||
server = await asyncio.start_server(
|
server = await asyncio.start_server(
|
||||||
handle_echo, 'localhost', port)
|
handle_echo, 'localhost', port)
|
||||||
await server.start_serving()
|
await server.start_serving()
|
||||||
|
|
@ -1154,11 +1151,20 @@ os.close(fd)
|
||||||
await server.wait_closed()
|
await server.wait_closed()
|
||||||
|
|
||||||
self.loop.run_until_complete(main())
|
self.loop.run_until_complete(main())
|
||||||
|
return messages
|
||||||
|
|
||||||
|
def test_unhandled_exception(self):
|
||||||
|
async def handle_echo(reader, writer):
|
||||||
|
raise Exception('test')
|
||||||
|
messages = self._basetest_unhandled_exceptions(handle_echo)
|
||||||
self.assertEqual(messages[0]['message'],
|
self.assertEqual(messages[0]['message'],
|
||||||
'Unhandled exception in client_connected_cb')
|
'Unhandled exception in client_connected_cb')
|
||||||
# Break explicitly reference cycle
|
|
||||||
messages = None
|
def test_unhandled_cancel(self):
|
||||||
|
async def handle_echo(reader, writer):
|
||||||
|
asyncio.current_task().cancel()
|
||||||
|
messages = self._basetest_unhandled_exceptions(handle_echo)
|
||||||
|
self.assertEqual(messages, [])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
In :meth:`asyncio.StreamReaderProtocol.connection_made`, there is callback
|
||||||
|
that logs an error if the task wrapping the "connected callback" fails. This
|
||||||
|
callback would itself fail if the task was cancelled. Prevent this by
|
||||||
|
checking whether the task was cancelled first. If so, close the transport
|
||||||
|
but don't log an error.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue