diff options
author | Michael W. Hudson <mwh@python.net> | 2002-03-16 17:57:26 (GMT) |
---|---|---|
committer | Michael W. Hudson <mwh@python.net> | 2002-03-16 17:57:26 (GMT) |
commit | bf05f2aaa6ae80a9305f4e70691e53c380c0c459 (patch) | |
tree | 7492f478303259cf8392ae3ac30f9a3e0e89be4e | |
parent | 18d81afd2364a4f21ad4d5a63eb7604ff019229f (diff) | |
download | cpython-bf05f2aaa6ae80a9305f4e70691e53c380c0c459.zip cpython-bf05f2aaa6ae80a9305f4e70691e53c380c0c459.tar.gz cpython-bf05f2aaa6ae80a9305f4e70691e53c380c0c459.tar.bz2 |
backport gvanrossum's checkin of
revision 1.121 of test_descr.py
"Fix" for SF bug #520644: __slots__ are not pickled.
As promised in my response to the bug report, I'm not really fixing
it; in fact, one could argule over what the proper fix should do.
Instead, I'm adding a little magic that raises TypeError if you try to
pickle an instance of a class that has __slots__ but doesn't define or
override __getstate__. This is done by adding a bozo __getstate__
that always raises TypeError.
Bugfix candidate (also the checkin to typeobject.c, of course).
-rw-r--r-- | Lib/test/test_descr.py | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 1740134..a1bb650 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -2450,6 +2450,94 @@ def pickles(): print "a = x =", a print "b = y =", b +def pickleslots(): + if verbose: print "Testing pickling of classes with __slots__ ..." + import pickle, cPickle + # Pickling of classes with __slots__ but without __getstate__ should fail + global B, C, D, E + class B(object): + pass + for base in [object, B]: + class C(base): + __slots__ = ['a'] + class D(C): + pass + try: + pickle.dumps(C()) + except TypeError: + pass + else: + raise TestFailed, "should fail: pickle C instance - %s" % base + try: + cPickle.dumps(C()) + except TypeError: + pass + else: + raise TestFailed, "should fail: cPickle C instance - %s" % base + try: + pickle.dumps(C()) + except TypeError: + pass + else: + raise TestFailed, "should fail: pickle D instance - %s" % base + try: + cPickle.dumps(D()) + except TypeError: + pass + else: + raise TestFailed, "should fail: cPickle D instance - %s" % base + # Give C a __getstate__ and __setstate__ + class C(base): + __slots__ = ['a'] + def __getstate__(self): + try: + d = self.__dict__.copy() + except AttributeError: + d = {} + try: + d['a'] = self.a + except AttributeError: + pass + return d + def __setstate__(self, d): + for k, v in d.items(): + setattr(self, k, v) + class D(C): + pass + # Now it should work + x = C() + y = pickle.loads(pickle.dumps(x)) + vereq(hasattr(y, 'a'), 0) + y = cPickle.loads(cPickle.dumps(x)) + vereq(hasattr(y, 'a'), 0) + x.a = 42 + y = pickle.loads(pickle.dumps(x)) + vereq(y.a, 42) + y = cPickle.loads(cPickle.dumps(x)) + vereq(y.a, 42) + x = D() + x.a = 42 + x.b = 100 + y = pickle.loads(pickle.dumps(x)) + vereq(y.a + y.b, 142) + y = cPickle.loads(cPickle.dumps(x)) + vereq(y.a + y.b, 142) + # But a subclass that adds a slot should not work + class E(C): + __slots__ = ['b'] + try: + pickle.dumps(E()) + except TypeError: + pass + else: + raise TestFailed, "should fail: pickle E instance - %s" % base + try: + cPickle.dumps(E()) + except TypeError: + pass + else: + raise TestFailed, "should fail: cPickle E instance - %s" % base + def copies(): if verbose: print "Testing copy.copy() and copy.deepcopy()..." import copy @@ -2798,6 +2886,7 @@ def test_main(): strops() deepcopyrecursive() modules() + pickleslots() if verbose: print "All OK" if __name__ == "__main__": |