bpo-23890: Fix ref cycle in TestCase.assertRaises (#858)
unittest.TestCase.assertRaises() now manually breaks a
reference cycle to not keep objects alive longer than expected.
(cherry picked from commit bbd3cf8f1ef1e91a8d6dac6411e18b4b9084abf5)
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index b523f73..f4dbc52 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -153,28 +153,32 @@
If args is not empty, call a callable passing positional and keyword
arguments.
"""
- if not _is_subtype(self.expected, self._base_type):
- raise TypeError('%s() arg 1 must be %s' %
- (name, self._base_type_str))
- if args and args[0] is None:
- warnings.warn("callable is None",
- DeprecationWarning, 3)
- args = ()
- if not args:
- self.msg = kwargs.pop('msg', None)
- if kwargs:
- warnings.warn('%r is an invalid keyword argument for '
- 'this function' % next(iter(kwargs)),
- DeprecationWarning, 3)
- return self
-
- callable_obj, *args = args
try:
- self.obj_name = callable_obj.__name__
- except AttributeError:
- self.obj_name = str(callable_obj)
- with self:
- callable_obj(*args, **kwargs)
+ if not _is_subtype(self.expected, self._base_type):
+ raise TypeError('%s() arg 1 must be %s' %
+ (name, self._base_type_str))
+ if args and args[0] is None:
+ warnings.warn("callable is None",
+ DeprecationWarning, 3)
+ args = ()
+ if not args:
+ self.msg = kwargs.pop('msg', None)
+ if kwargs:
+ warnings.warn('%r is an invalid keyword argument for '
+ 'this function' % next(iter(kwargs)),
+ DeprecationWarning, 3)
+ return self
+
+ callable_obj, *args = args
+ try:
+ self.obj_name = callable_obj.__name__
+ except AttributeError:
+ self.obj_name = str(callable_obj)
+ with self:
+ callable_obj(*args, **kwargs)
+ finally:
+ # bpo-23890: manually break a reference cycle
+ self = None
class _AssertRaisesContext(_AssertRaisesBaseContext):
@@ -725,7 +729,11 @@
self.assertEqual(the_exception.error_code, 3)
"""
context = _AssertRaisesContext(expected_exception, self)
- return context.handle('assertRaises', args, kwargs)
+ try:
+ return context.handle('assertRaises', args, kwargs)
+ finally:
+ # bpo-23890: manually break a reference cycle
+ context = None
def assertWarns(self, expected_warning, *args, **kwargs):
"""Fail unless a warning of class warnClass is triggered