Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2ef3676

Browse filesBrowse files
authored
[3.12] gh-109538: Catch closed loop runtime error and issue warning (GH-111983) (#112142)
* [3.12] gh-109538: Avoid RuntimeError when StreamWriter is deleted with closed loop (GH-111983) Issue a ResourceWarning instead. (cherry picked from commit e0f5127) gh-109538: Avoid RuntimeError when StreamWriter is deleted with closed loop (#111983) Issue a ResourceWarning instead. Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com> (cherry picked from commit e0f5127) * Fix missing warnings import
1 parent 3f2cdbe commit 2ef3676
Copy full SHA for 2ef3676

File tree

3 files changed

+66
-2
lines changed
Filter options

3 files changed

+66
-2
lines changed

‎Lib/asyncio/streams.py

Copy file name to clipboardExpand all lines: Lib/asyncio/streams.py
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import collections
66
import socket
77
import sys
8+
import warnings
89
import weakref
910

1011
if hasattr(socket, 'AF_UNIX'):
@@ -405,8 +406,11 @@ async def start_tls(self, sslcontext, *,
405406

406407
def __del__(self):
407408
if not self._transport.is_closing():
408-
self.close()
409-
409+
if self._loop.is_closed():
410+
warnings.warn("loop is closed", ResourceWarning)
411+
else:
412+
self.close()
413+
warnings.warn(f"unclosed {self!r}", ResourceWarning)
410414

411415
class StreamReader:
412416

‎Lib/test/test_asyncio/test_streams.py

Copy file name to clipboardExpand all lines: Lib/test/test_asyncio/test_streams.py
+59Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,65 @@ def test_eof_feed_when_closing_writer(self):
10731073

10741074
self.assertEqual(messages, [])
10751075

1076+
def test_unclosed_resource_warnings(self):
1077+
async def inner(httpd):
1078+
rd, wr = await asyncio.open_connection(*httpd.address)
1079+
1080+
wr.write(b'GET / HTTP/1.0\r\n\r\n')
1081+
data = await rd.readline()
1082+
self.assertEqual(data, b'HTTP/1.0 200 OK\r\n')
1083+
data = await rd.read()
1084+
self.assertTrue(data.endswith(b'\r\n\r\nTest message'))
1085+
with self.assertWarns(ResourceWarning) as cm:
1086+
del wr
1087+
gc.collect()
1088+
self.assertEqual(len(cm.warnings), 1)
1089+
self.assertTrue(str(cm.warnings[0].message).startswith("unclosed <StreamWriter"))
1090+
1091+
messages = []
1092+
self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
1093+
1094+
with test_utils.run_test_server() as httpd:
1095+
self.loop.run_until_complete(inner(httpd))
1096+
1097+
self.assertEqual(messages, [])
1098+
1099+
def test_loop_is_closed_resource_warnings(self):
1100+
async def inner(httpd):
1101+
rd, wr = await asyncio.open_connection(*httpd.address)
1102+
1103+
wr.write(b'GET / HTTP/1.0\r\n\r\n')
1104+
data = await rd.readline()
1105+
self.assertEqual(data, b'HTTP/1.0 200 OK\r\n')
1106+
data = await rd.read()
1107+
self.assertTrue(data.endswith(b'\r\n\r\nTest message'))
1108+
1109+
# Make "loop is closed" occur first before "del wr" for this test.
1110+
self.loop.stop()
1111+
wr.close()
1112+
while not self.loop.is_closed():
1113+
await asyncio.sleep(0.0)
1114+
1115+
with self.assertWarns(ResourceWarning) as cm:
1116+
del wr
1117+
gc.collect()
1118+
self.assertEqual(len(cm.warnings), 1)
1119+
self.assertEqual("loop is closed", str(cm.warnings[0].message))
1120+
1121+
messages = []
1122+
self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
1123+
1124+
with test_utils.run_test_server() as httpd:
1125+
try:
1126+
self.loop.run_until_complete(inner(httpd))
1127+
# This exception is caused by `self.loop.stop()` as expected.
1128+
except RuntimeError:
1129+
pass
1130+
finally:
1131+
gc.collect()
1132+
1133+
self.assertEqual(messages, [])
1134+
10761135
def test_unhandled_exceptions(self) -> None:
10771136
port = socket_helper.find_unused_port()
10781137

+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Issue warning message instead of having :class:`RuntimeError` be displayed when event loop has already been closed at :meth:`StreamWriter.__del__`.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.