Commit bbd3cf8f authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

Fix ref cycles in TestCase.assertRaises() (#193)

bpo-23890: unittest.TestCase.assertRaises() now manually breaks a
reference cycle to not keep objects alive longer than expected.
parent 6003db7d
...@@ -153,6 +153,7 @@ class _AssertRaisesBaseContext(_BaseTestCaseContext): ...@@ -153,6 +153,7 @@ class _AssertRaisesBaseContext(_BaseTestCaseContext):
If args is not empty, call a callable passing positional and keyword If args is not empty, call a callable passing positional and keyword
arguments. arguments.
""" """
try:
if not _is_subtype(self.expected, self._base_type): if not _is_subtype(self.expected, self._base_type):
raise TypeError('%s() arg 1 must be %s' % raise TypeError('%s() arg 1 must be %s' %
(name, self._base_type_str)) (name, self._base_type_str))
...@@ -175,6 +176,9 @@ class _AssertRaisesBaseContext(_BaseTestCaseContext): ...@@ -175,6 +176,9 @@ class _AssertRaisesBaseContext(_BaseTestCaseContext):
self.obj_name = str(callable_obj) self.obj_name = str(callable_obj)
with self: with self:
callable_obj(*args, **kwargs) callable_obj(*args, **kwargs)
finally:
# bpo-23890: manually break a reference cycle
self = None
class _AssertRaisesContext(_AssertRaisesBaseContext): class _AssertRaisesContext(_AssertRaisesBaseContext):
...@@ -725,7 +729,11 @@ class TestCase(object): ...@@ -725,7 +729,11 @@ class TestCase(object):
self.assertEqual(the_exception.error_code, 3) self.assertEqual(the_exception.error_code, 3)
""" """
context = _AssertRaisesContext(expected_exception, self) context = _AssertRaisesContext(expected_exception, self)
try:
return context.handle('assertRaises', args, kwargs) return context.handle('assertRaises', args, kwargs)
finally:
# bpo-23890: manually break a reference cycle
context = None
def assertWarns(self, expected_warning, *args, **kwargs): def assertWarns(self, expected_warning, *args, **kwargs):
"""Fail unless a warning of class warnClass is triggered """Fail unless a warning of class warnClass is triggered
......
...@@ -1273,6 +1273,19 @@ test case ...@@ -1273,6 +1273,19 @@ test case
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
self.assertRaises((ValueError, object)) self.assertRaises((ValueError, object))
def testAssertRaisesRefcount(self):
# bpo-23890: assertRaises() must not keep objects alive longer
# than expected
def func() :
try:
raise ValueError
except ValueError:
raise ValueError
refcount = sys.getrefcount(func)
self.assertRaises(ValueError, func)
self.assertEqual(refcount, sys.getrefcount(func))
def testAssertRaisesRegex(self): def testAssertRaisesRegex(self):
class ExceptionMock(Exception): class ExceptionMock(Exception):
pass pass
......
...@@ -291,6 +291,9 @@ Extension Modules ...@@ -291,6 +291,9 @@ Extension Modules
Library Library
------- -------
- bpo-23890: unittest.TestCase.assertRaises() now manually breaks a reference
cycle to not keep objects alive longer than expected.
- bpo-29901: The zipapp module now supports general path-like objects, not - bpo-29901: The zipapp module now supports general path-like objects, not
just pathlib.Path. just pathlib.Path.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment