Skip to content

Commit

Permalink
[3.11] [3.12] pythonGH-110894: Call loop exception handler for except…
Browse files Browse the repository at this point in the history
…ions in client_connected_cb (pythonGH-111601) (pythonGH-111632) (python#111634)

* [3.12] pythonGH-110894: Call loop exception handler for exceptions in client_connected_cb (pythonGH-111601) (pythonGH-111632)
(cherry picked from commit 9aa8829)

Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Call loop exception handler for exceptions in `client_connected_cb` of `asyncio.start_server` so that applications can handle it..
(cherry picked from commit 229f44d)

* pythongh-111644: Fix asyncio test_unhandled_exceptions() (python#111713)

Fix test_unhandled_exceptions() of test_asyncio.test_streams: break
explicitly a reference cycle.

Fix also StreamTests.tearDown(): the loop must not be closed
explicitly, but using set_event_loop() which takes care of shutting
down the executor with executor.shutdown(wait=True).
BaseEventLoop.close() calls executor.shutdown(wait=False).

(cherry picked from commit ac01e22)

---------

Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Co-authored-by: Victor Stinner <vstinner@python.org>
  • Loading branch information
3 people committed Nov 4, 2023
1 parent 89264a3 commit f7ffe4a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 2 deletions.
12 changes: 12 additions & 0 deletions Lib/asyncio/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,19 @@ def connection_made(self, transport):
res = self._client_connected_cb(reader,
self._stream_writer)
if coroutines.iscoroutine(res):
def callback(task):
exc = task.exception()
if exc is not None:
self._loop.call_exception_handler({
'message': 'Unhandled exception in client_connected_cb',
'exception': exc,
'transport': transport,
})
transport.close()

self._task = self._loop.create_task(res)
self._task.add_done_callback(callback)

self._strong_reader = None

def connection_lost(self, exc):
Expand Down
34 changes: 32 additions & 2 deletions Lib/test/test_asyncio/test_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ def tearDown(self):
# just in case if we have transport close callbacks
test_utils.run_briefly(self.loop)

self.loop.close()
gc.collect()
# set_event_loop() takes care of closing self.loop in a safe way
super().tearDown()

def _basetest_open_connection(self, open_connection_fut):
Expand Down Expand Up @@ -1068,6 +1067,37 @@ def test_eof_feed_when_closing_writer(self):

self.assertEqual(messages, [])

def test_unhandled_exceptions(self) -> None:
port = socket_helper.find_unused_port()

messages = []
self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))

async def client():
rd, wr = await asyncio.open_connection('localhost', port)
wr.write(b'test msg')
await wr.drain()
wr.close()
await wr.wait_closed()

async def main():
async def handle_echo(reader, writer):
raise Exception('test')

server = await asyncio.start_server(
handle_echo, 'localhost', port)
await server.start_serving()
await client()
server.close()
await server.wait_closed()

self.loop.run_until_complete(main())

self.assertEqual(messages[0]['message'],
'Unhandled exception in client_connected_cb')
# Break explicitly reference cycle
messages = None


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Call loop exception handler for exceptions in ``client_connected_cb`` of :func:`asyncio.start_server` so that applications can handle it. Patch by Kumar Aditya.

0 comments on commit f7ffe4a

Please sign in to comment.