Skip to content

Commit e99650b

Browse files
authored
pythongh-125472: Revert "pythongh-124958: fix asyncio.TaskGroup and _PyFuture refcycles (#12… (python#125476)
Revert "pythongh-124958: fix asyncio.TaskGroup and _PyFuture refcycles (python#124959)" This reverts commit d5dbbf4.
1 parent 187580d commit e99650b

File tree

5 files changed

+15
-147
lines changed

5 files changed

+15
-147
lines changed

Lib/asyncio/futures.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ def result(self):
190190
the future is done and has an exception set, this exception is raised.
191191
"""
192192
if self._state == _CANCELLED:
193-
raise self._make_cancelled_error()
193+
exc = self._make_cancelled_error()
194+
raise exc
194195
if self._state != _FINISHED:
195196
raise exceptions.InvalidStateError('Result is not ready.')
196197
self.__log_traceback = False
@@ -207,7 +208,8 @@ def exception(self):
207208
InvalidStateError.
208209
"""
209210
if self._state == _CANCELLED:
210-
raise self._make_cancelled_error()
211+
exc = self._make_cancelled_error()
212+
raise exc
211213
if self._state != _FINISHED:
212214
raise exceptions.InvalidStateError('Exception is not set.')
213215
self.__log_traceback = False

Lib/asyncio/taskgroups.py

+9-32
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,6 @@ async def __aenter__(self):
6666
return self
6767

6868
async def __aexit__(self, et, exc, tb):
69-
tb = None
70-
try:
71-
return await self._aexit(et, exc)
72-
finally:
73-
# Exceptions are heavy objects that can have object
74-
# cycles (bad for GC); let's not keep a reference to
75-
# a bunch of them. It would be nicer to use a try/finally
76-
# in __aexit__ directly but that introduced some diff noise
77-
self._parent_task = None
78-
self._errors = None
79-
self._base_error = None
80-
exc = None
81-
82-
async def _aexit(self, et, exc):
8369
self._exiting = True
8470

8571
if (exc is not None and
@@ -136,10 +122,7 @@ async def _aexit(self, et, exc):
136122
assert not self._tasks
137123

138124
if self._base_error is not None:
139-
try:
140-
raise self._base_error
141-
finally:
142-
exc = None
125+
raise self._base_error
143126

144127
if self._parent_cancel_requested:
145128
# If this flag is set we *must* call uncancel().
@@ -150,14 +133,8 @@ async def _aexit(self, et, exc):
150133

151134
# Propagate CancelledError if there is one, except if there
152135
# are other errors -- those have priority.
153-
try:
154-
if propagate_cancellation_error is not None and not self._errors:
155-
try:
156-
raise propagate_cancellation_error
157-
finally:
158-
exc = None
159-
finally:
160-
propagate_cancellation_error = None
136+
if propagate_cancellation_error is not None and not self._errors:
137+
raise propagate_cancellation_error
161138

162139
if et is not None and not issubclass(et, exceptions.CancelledError):
163140
self._errors.append(exc)
@@ -169,14 +146,14 @@ async def _aexit(self, et, exc):
169146
if self._parent_task.cancelling():
170147
self._parent_task.uncancel()
171148
self._parent_task.cancel()
149+
# Exceptions are heavy objects that can have object
150+
# cycles (bad for GC); let's not keep a reference to
151+
# a bunch of them.
172152
try:
173-
raise BaseExceptionGroup(
174-
'unhandled errors in a TaskGroup',
175-
self._errors,
176-
) from None
153+
me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors)
154+
raise me from None
177155
finally:
178-
exc = None
179-
156+
self._errors = None
180157

181158
def create_task(self, coro, *, name=None, context=None):
182159
"""Create a new task in this group and return it.

Lib/test/test_asyncio/test_futures.py

-22
Original file line numberDiff line numberDiff line change
@@ -659,28 +659,6 @@ def __del__(self):
659659
fut = self._new_future(loop=self.loop)
660660
fut.set_result(Evil())
661661

662-
def test_future_cancelled_result_refcycles(self):
663-
f = self._new_future(loop=self.loop)
664-
f.cancel()
665-
exc = None
666-
try:
667-
f.result()
668-
except asyncio.CancelledError as e:
669-
exc = e
670-
self.assertIsNotNone(exc)
671-
self.assertListEqual(gc.get_referrers(exc), [])
672-
673-
def test_future_cancelled_exception_refcycles(self):
674-
f = self._new_future(loop=self.loop)
675-
f.cancel()
676-
exc = None
677-
try:
678-
f.exception()
679-
except asyncio.CancelledError as e:
680-
exc = e
681-
self.assertIsNotNone(exc)
682-
self.assertListEqual(gc.get_referrers(exc), [])
683-
684662

685663
@unittest.skipUnless(hasattr(futures, '_CFuture'),
686664
'requires the C _asyncio module')

Lib/test/test_asyncio/test_taskgroups.py

+2-90
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Adapted with permission from the EdgeDB project;
22
# license: PSFL.
33

4-
import gc
4+
55
import asyncio
66
import contextvars
77
import contextlib
@@ -11,6 +11,7 @@
1111

1212
from test.test_asyncio.utils import await_without_task
1313

14+
1415
# To prevent a warning "test altered the execution environment"
1516
def tearDownModule():
1617
asyncio.set_event_loop_policy(None)
@@ -898,95 +899,6 @@ async def outer():
898899

899900
await outer()
900901

901-
async def test_exception_refcycles_direct(self):
902-
"""Test that TaskGroup doesn't keep a reference to the raised ExceptionGroup"""
903-
tg = asyncio.TaskGroup()
904-
exc = None
905-
906-
class _Done(Exception):
907-
pass
908-
909-
try:
910-
async with tg:
911-
raise _Done
912-
except ExceptionGroup as e:
913-
exc = e
914-
915-
self.assertIsNotNone(exc)
916-
self.assertListEqual(gc.get_referrers(exc), [])
917-
918-
919-
async def test_exception_refcycles_errors(self):
920-
"""Test that TaskGroup deletes self._errors, and __aexit__ args"""
921-
tg = asyncio.TaskGroup()
922-
exc = None
923-
924-
class _Done(Exception):
925-
pass
926-
927-
try:
928-
async with tg:
929-
raise _Done
930-
except* _Done as excs:
931-
exc = excs.exceptions[0]
932-
933-
self.assertIsInstance(exc, _Done)
934-
self.assertListEqual(gc.get_referrers(exc), [])
935-
936-
937-
async def test_exception_refcycles_parent_task(self):
938-
"""Test that TaskGroup deletes self._parent_task"""
939-
tg = asyncio.TaskGroup()
940-
exc = None
941-
942-
class _Done(Exception):
943-
pass
944-
945-
async def coro_fn():
946-
async with tg:
947-
raise _Done
948-
949-
try:
950-
async with asyncio.TaskGroup() as tg2:
951-
tg2.create_task(coro_fn())
952-
except* _Done as excs:
953-
exc = excs.exceptions[0].exceptions[0]
954-
955-
self.assertIsInstance(exc, _Done)
956-
self.assertListEqual(gc.get_referrers(exc), [])
957-
958-
async def test_exception_refcycles_propagate_cancellation_error(self):
959-
"""Test that TaskGroup deletes propagate_cancellation_error"""
960-
tg = asyncio.TaskGroup()
961-
exc = None
962-
963-
try:
964-
async with asyncio.timeout(-1):
965-
async with tg:
966-
await asyncio.sleep(0)
967-
except TimeoutError as e:
968-
exc = e.__cause__
969-
970-
self.assertIsInstance(exc, asyncio.CancelledError)
971-
self.assertListEqual(gc.get_referrers(exc), [])
972-
973-
async def test_exception_refcycles_base_error(self):
974-
"""Test that TaskGroup deletes self._base_error"""
975-
class MyKeyboardInterrupt(KeyboardInterrupt):
976-
pass
977-
978-
tg = asyncio.TaskGroup()
979-
exc = None
980-
981-
try:
982-
async with tg:
983-
raise MyKeyboardInterrupt
984-
except MyKeyboardInterrupt as e:
985-
exc = e
986-
987-
self.assertIsNotNone(exc)
988-
self.assertListEqual(gc.get_referrers(exc), [])
989-
990902

991903
if __name__ == "__main__":
992904
unittest.main()

Misc/NEWS.d/next/Library/2024-10-04-08-46-00.gh-issue-124958.rea9-x.rst

-1
This file was deleted.

0 commit comments

Comments
 (0)