https://github.com/python/cpython/commit/e5967403993f4d491950aac01525c9d9a9b8eb1a
commit: e5967403993f4d491950aac01525c9d9a9b8eb1a
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: willingc <[email protected]>
date: 2024-10-23T12:35:56-07:00
summary:

[3.13] gh-124858: fix happy eyeballs refcyles (GH-124859) (#124912)

gh-124858: fix happy eyeballs refcyles (GH-124859)
(cherry picked from commit c066bf553577d1000e208eb078d9e758c3e41186)

Co-authored-by: Thomas Grainger <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst
M Lib/asyncio/base_events.py
M Lib/asyncio/staggered.py
M Lib/test/test_asyncio/test_streams.py

diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index e4a39f4d345c79..91434042685239 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -17,7 +17,6 @@
 import collections.abc
 import concurrent.futures
 import errno
-import functools
 import heapq
 import itertools
 import os
@@ -1140,11 +1139,18 @@ async def create_connection(
                     except OSError:
                         continue
             else:  # using happy eyeballs
-                sock, _, _ = await staggered.staggered_race(
-                    (functools.partial(self._connect_sock,
-                                       exceptions, addrinfo, laddr_infos)
-                     for addrinfo in infos),
-                    happy_eyeballs_delay, loop=self)
+                sock = (await staggered.staggered_race(
+                    (
+                        # can't use functools.partial as it keeps a reference
+                        # to exceptions
+                        lambda addrinfo=addrinfo: self._connect_sock(
+                            exceptions, addrinfo, laddr_infos
+                        )
+                        for addrinfo in infos
+                    ),
+                    happy_eyeballs_delay,
+                    loop=self,
+                ))[0]  # can't use sock, _, _ as it keeks a reference to 
exceptions
 
             if sock is None:
                 exceptions = [exc for sub in exceptions for exc in sub]
diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py
index 7aafcea4d885eb..0f4df8855a80b9 100644
--- a/Lib/asyncio/staggered.py
+++ b/Lib/asyncio/staggered.py
@@ -144,6 +144,7 @@ async def run_one_coro(ok_to_start, previous_failed) -> 
None:
                         raise d.exception()
         return winner_result, winner_index, exceptions
     finally:
+        del exceptions
         # Make sure no tasks are left running if we leave this function
         for t in running_tasks:
             t.cancel()
diff --git a/Lib/test/test_asyncio/test_streams.py 
b/Lib/test/test_asyncio/test_streams.py
index ae943f39869815..3040ca55fae0e9 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -1246,6 +1246,24 @@ async def handle_echo(reader, writer):
         messages = self._basetest_unhandled_exceptions(handle_echo)
         self.assertEqual(messages, [])
 
+    def test_open_connection_happy_eyeball_refcycles(self):
+        port = socket_helper.find_unused_port()
+        async def main():
+            exc = None
+            try:
+                await asyncio.open_connection(
+                    host="localhost",
+                    port=port,
+                    happy_eyeballs_delay=0.25,
+                )
+            except* OSError as excs:
+                # can't use assertRaises because that clears frames
+                exc = excs.exceptions[0]
+            self.assertIsNotNone(exc)
+            self.assertListEqual(gc.get_referrers(exc), [])
+
+        asyncio.run(main())
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst 
b/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst
new file mode 100644
index 00000000000000..c05d24a7c5aacb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst
@@ -0,0 +1 @@
+Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` 
when used with ``happy_eyeballs_delay``

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to