[Python-checkins] bpo-36916: asyncio: Swallow unhandled write() exception (GH-13313)

Victor Stinner webhook-mailer at python.org
Tue May 14 12:09:55 EDT 2019


https://github.com/python/cpython/commit/f12ba7cd0a7370631214ac0b337ab5455ce717b2
commit: f12ba7cd0a7370631214ac0b337ab5455ce717b2
branch: master
author: Andrew Svetlov <andrew.svetlov at gmail.com>
committer: Victor Stinner <vstinner at redhat.com>
date: 2019-05-14T18:09:44+02:00
summary:

bpo-36916: asyncio: Swallow unhandled write() exception (GH-13313)

files:
A Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst
M Lib/asyncio/streams.py
M Lib/test/test_asyncio/test_streams.py

diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py
index d9a9f5e72d3b..146a33818d95 100644
--- a/Lib/asyncio/streams.py
+++ b/Lib/asyncio/streams.py
@@ -329,6 +329,13 @@ def __del__(self):
             closed.exception()
 
 
+def _swallow_unhandled_exception(task):
+    # Do a trick to suppress unhandled exception
+    # if stream.write() was used without await and
+    # stream.drain() was paused and resumed with an exception
+    task.exception()
+
+
 class StreamWriter:
     """Wraps a Transport.
 
@@ -393,7 +400,9 @@ def _fast_drain(self):
                 # fast path, the stream is not paused
                 # no need to wait for resume signal
                 return self._complete_fut
-        return self._loop.create_task(self.drain())
+        ret = self._loop.create_task(self.drain())
+        ret.add_done_callback(_swallow_unhandled_exception)
+        return ret
 
     def write_eof(self):
         return self._transport.write_eof()
diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
index bf93f30e1aaf..8d6a1d26ac19 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -851,6 +851,8 @@ def test_drain_raises(self):
         # where it never gives up the event loop but the socket is
         # closed on the  server side.
 
+        messages = []
+        self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
         q = queue.Queue()
 
         def server():
@@ -883,6 +885,7 @@ def server():
         # Clean up the thread.  (Only on success; on failure, it may
         # be stuck in accept().)
         thread.join()
+        self.assertEqual([], messages)
 
     def test___repr__(self):
         stream = asyncio.StreamReader(loop=self.loop,
diff --git a/Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst b/Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst
new file mode 100644
index 000000000000..8726bb241f23
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-14-15-39-34.bpo-36916._GPsTt.rst
@@ -0,0 +1,2 @@
+Remove a message about an unhandled exception in a task when writer.write()
+is used without await and writer.drain() fails with an exception.



More information about the Python-checkins mailing list