From: Michael Foord <fuzzyman@voidspace.org.uk>
Date: Sat, 20 Nov 2010 15:34:26 +0000 (+0000)
Subject: Issue 10326: TestCase instances can now be pickled (they store names of instance... 
X-Git-Tag: v3.2b1~310
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8ca6d9884bcbdd05fe270e75e10f51af614e22a2;p=python

Issue 10326: TestCase instances can now be pickled (they store names of instance methods instead of references to the instance methods themselves).
---

diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 5831a76e03..1df19dca59 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -191,6 +191,27 @@ class _AssertWarnsContext(_AssertRaisesBaseContext):
                 .format(exc_name))
 
 
+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, str):
+            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.
 
@@ -253,13 +274,13 @@ class TestCase(object):
         # 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 = {}
-        self.addTypeEqualityFunc(dict, self.assertDictEqual)
-        self.addTypeEqualityFunc(list, self.assertListEqual)
-        self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
-        self.addTypeEqualityFunc(set, self.assertSetEqual)
-        self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
-        self.addTypeEqualityFunc(str, self.assertMultiLineEqual)
+        self._type_equality_funcs = _TypeEqualityDict(self)
+        self.addTypeEqualityFunc(dict, 'assertDictEqual')
+        self.addTypeEqualityFunc(list, 'assertListEqual')
+        self.addTypeEqualityFunc(tuple, 'assertTupleEqual')
+        self.addTypeEqualityFunc(set, 'assertSetEqual')
+        self.addTypeEqualityFunc(frozenset, 'assertSetEqual')
+        self.addTypeEqualityFunc(str, 'assertMultiLineEqual')
 
     def addTypeEqualityFunc(self, typeobj, function):
         """Add a type specific assertEqual style function to compare a type.
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index 1bd839f27e..444b58be06 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -1,5 +1,6 @@
 import difflib
 import pprint
+import pickle
 import re
 import sys
 import warnings
@@ -1095,3 +1096,14 @@ test case
 
         # This shouldn't blow up
         deepcopy(test)
+
+    def testPickle(self):
+        # Issue 10326
+
+        # Can't use TestCase classes defined in Test class as
+        # pickle does not work with inner classes
+        test = unittest.TestCase('run')
+        for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
+
+            # blew up prior to fix
+            pickled_test = pickle.dumps(test, protocol=protocol)
diff --git a/Misc/NEWS b/Misc/NEWS
index 68769fb2a0..c0294d7e5c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,8 @@ Core and Builtins
 Library
 -------
 
+- Issue 10326: unittest.TestCase instances can be pickled.
+
 - Issue #9920: Skip tests for cmath.atan and cmath.atanh applied to
   complex zeros on systems where the log1p function fails to respect
   the sign of zero.  This fixes a test failure on AIX.