Close #19880: Fix a reference leak in unittest.TestCase. Explicitly break

reference cycles between frames and the _Outcome instance.
This commit is contained in:
Victor Stinner 2013-12-09 01:52:50 +01:00
parent 28dd6deca8
commit 031bd532c4
3 changed files with 42 additions and 1 deletions

View File

@ -69,6 +69,9 @@ def testPartExecutor(self, test_case, isTest=False):
else:
self.success = False
self.errors.append((test_case, exc_info))
# explicitly break a reference cycle:
# exc_info -> frame -> exc_info
exc_info = None
else:
if self.result_supports_subtests and self.success:
self.errors.append((test_case, None))
@ -559,8 +562,8 @@ def run(self, result=None):
return
expecting_failure = getattr(testMethod,
"__unittest_expecting_failure__", False)
outcome = _Outcome(result)
try:
outcome = _Outcome(result)
self._outcome = outcome
with outcome.testPartExecutor(self):
@ -593,6 +596,15 @@ def run(self, result=None):
if stopTestRun is not None:
stopTestRun()
# explicitly break reference cycles:
# outcome.errors -> frame -> outcome -> outcome.errors
# outcome.expectedFailure -> frame -> outcome -> outcome.expectedFailure
outcome.errors.clear()
outcome.expectedFailure = None
# clear the outcome, no more needed
self._outcome = None
def doCleanups(self):
"""Execute all cleanup functions. Normally called for you after
tearDown."""

View File

@ -1533,6 +1533,32 @@ def testNoCycles(self):
del case
self.assertFalse(wr())
def test_no_exception_leak(self):
# Issue #19880: TestCase.run() should not keep a reference
# to the exception
class MyException(Exception):
ninstance = 0
def __init__(self):
MyException.ninstance += 1
Exception.__init__(self)
def __del__(self):
MyException.ninstance -= 1
class TestCase(unittest.TestCase):
def test1(self):
raise MyException()
@unittest.expectedFailure
def test2(self):
raise MyException()
for method_name in ('test1', 'test2'):
testcase = TestCase(method_name)
testcase.run()
self.assertEqual(MyException.ninstance, 0)
if __name__ == "__main__":
unittest.main()

View File

@ -21,6 +21,9 @@ Core and Builtins
Library
-------
- Issue #19880: Fix a reference leak in unittest.TestCase. Explicitly break
reference cycles between frames and the _Outcome instance.
- Issue #17429: platform.linux_distribution() now decodes files from the UTF-8
encoding with the surrogateescape error handler, instead of decoding from the
locale encoding in strict mode. It fixes the function on Fedora 19 which is