diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -124,37 +124,16 @@ class _AssertRaisesContext(object): if isinstance(expected_regexp, basestring): expected_regexp = re.compile(expected_regexp) if not expected_regexp.search(str(exc_value)): raise self.failureException('"%s" does not match "%s"' % (expected_regexp.pattern, str(exc_value))) return True -class _TypeEqualityDict(object): - - def __init__(self, testcase): - self.testcase = testcase - self._store = {} - - def __setitem__(self, key, value): - self._store[key] = value - - def __getitem__(self, key): - value = self._store[key] - if isinstance(value, basestring): - return getattr(self.testcase, value) - return value - - def get(self, key, default=None): - if key in self._store: - return self[key] - return default - - class TestCase(object): """A class whose instances are single test cases. By default, the test code itself should be placed in a method named 'runTest'. If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase @@ -211,17 +190,17 @@ class TestCase(object): raise ValueError("no such test method in %s: %s" % (self.__class__, methodName)) self._testMethodDoc = testMethod.__doc__ self._cleanups = [] # Map types to custom assertEqual functions that will compare # instances of said type in more detail to generate a more useful # error message. - self._type_equality_funcs = _TypeEqualityDict(self) + self._type_equality_funcs = {} self.addTypeEqualityFunc(dict, 'assertDictEqual') self.addTypeEqualityFunc(list, 'assertListEqual') self.addTypeEqualityFunc(tuple, 'assertTupleEqual') self.addTypeEqualityFunc(set, 'assertSetEqual') self.addTypeEqualityFunc(frozenset, 'assertSetEqual') self.addTypeEqualityFunc(unicode, 'assertMultiLineEqual') def addTypeEqualityFunc(self, typeobj, function): @@ -505,16 +484,18 @@ class TestCase(object): # class instances using a type equality func. This means testing # subtypes won't automagically use the detailed comparison. Callers # should use their type specific assertSpamEqual method to compare # subclasses if the detailed comparison is desired and appropriate. # See the discussion in http://bugs.python.org/issue2578. # if type(first) is type(second): asserter = self._type_equality_funcs.get(type(first)) + if isinstance(asserter, str): + return getattr(self, asserter) if asserter is not None: return asserter return self._baseAssertEqual def _baseAssertEqual(self, first, second, msg=None): """The default assertEqual implementation, not type specific.""" if not first == second: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -1114,11 +1114,26 @@ test case for protocol in range(pickle.HIGHEST_PROTOCOL + 1): # blew up prior to fix pickled_test = pickle.dumps(test, protocol=protocol) unpickled_test = pickle.loads(pickled_test) self.assertEqual(test, unpickled_test) + @test_support.cpython_only + def testTestCaseNoCycles(self): + """TestCase instances should not create needless reference cycles""" + import gc, weakref + gc_enabled = gc.isenabled() + if gc_enabled: + gc.disable() + try: + case = weakref.ref(unittest.TestCase('run'))() + if case is not None: + self.fail("Refcount of %r not reduced to zero" % (case,)) + finally: + if gc_enabled: + gc.enable() + if __name__ == '__main__': unittest.main()