summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_exceptions.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-08-20 12:18:25 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-08-20 12:18:25 (GMT)
commit8fd544ffa926a479c8d80e245e3daf12197aa7a2 (patch)
treec0787daaaae9b9f707ae6fe1bd45ede1fb404796 /Lib/test/test_exceptions.py
parent18bb330203bbff6a80343988efc12367b3be6686 (diff)
parenta370fcf3b2211242c888558237557eb4895391d0 (diff)
downloadcpython-8fd544ffa926a479c8d80e245e3daf12197aa7a2.zip
cpython-8fd544ffa926a479c8d80e245e3daf12197aa7a2.tar.gz
cpython-8fd544ffa926a479c8d80e245e3daf12197aa7a2.tar.bz2
Issue #12791: Break reference cycles early when a generator exits with an exception.
Diffstat (limited to 'Lib/test/test_exceptions.py')
-rw-r--r--Lib/test/test_exceptions.py62
1 files changed, 62 insertions, 0 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index f05d3c0..718d05c 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -608,6 +608,68 @@ class ExceptionTests(unittest.TestCase):
gc_collect()
self.assertEqual(sys.exc_info(), (None, None, None))
+ def _check_generator_cleanup_exc_state(self, testfunc):
+ # Issue #12791: exception state is cleaned up as soon as a generator
+ # is closed (reference cycles are broken).
+ class MyException(Exception):
+ def __init__(self, obj):
+ self.obj = obj
+ class MyObj:
+ pass
+
+ def raising_gen():
+ try:
+ raise MyException(obj)
+ except MyException:
+ yield
+
+ obj = MyObj()
+ wr = weakref.ref(obj)
+ g = raising_gen()
+ next(g)
+ testfunc(g)
+ g = obj = None
+ obj = wr()
+ self.assertIs(obj, None)
+
+ def test_generator_throw_cleanup_exc_state(self):
+ def do_throw(g):
+ try:
+ g.throw(RuntimeError())
+ except RuntimeError:
+ pass
+ self._check_generator_cleanup_exc_state(do_throw)
+
+ def test_generator_close_cleanup_exc_state(self):
+ def do_close(g):
+ g.close()
+ self._check_generator_cleanup_exc_state(do_close)
+
+ def test_generator_del_cleanup_exc_state(self):
+ def do_del(g):
+ g = None
+ self._check_generator_cleanup_exc_state(do_del)
+
+ def test_generator_next_cleanup_exc_state(self):
+ def do_next(g):
+ try:
+ next(g)
+ except StopIteration:
+ pass
+ else:
+ self.fail("should have raised StopIteration")
+ self._check_generator_cleanup_exc_state(do_next)
+
+ def test_generator_send_cleanup_exc_state(self):
+ def do_send(g):
+ try:
+ g.send(None)
+ except StopIteration:
+ pass
+ else:
+ self.fail("should have raised StopIteration")
+ self._check_generator_cleanup_exc_state(do_send)
+
def test_3114(self):
# Bug #3114: in its destructor, MyObject retrieves a pointer to
# obsolete and/or deallocated objects.