summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-09-25 16:25:58 (GMT)
committerGuido van Rossum <guido@python.org>2001-09-25 16:25:58 (GMT)
commit3926a63d0579bbeea6ab855a31dc38b9fa56b5e3 (patch)
treee8819c4a320d632f516cb269ebc28cd96793193f /Lib
parentad39aba2f67d3e7f4405f84167becab6d18ee9bc (diff)
downloadcpython-3926a63d0579bbeea6ab855a31dc38b9fa56b5e3.zip
cpython-3926a63d0579bbeea6ab855a31dc38b9fa56b5e3.tar.gz
cpython-3926a63d0579bbeea6ab855a31dc38b9fa56b5e3.tar.bz2
- Provisional support for pickling new-style objects. (*)
- Made cls.__module__ writable. - Ensure that obj.__dict__ is returned as {}, not None, even upon first reference; it simply springs into life when you ask for it. (*) The pickling support is provisional for the following reasons: - It doesn't support classes with __slots__. - It relies on additional support in copy_reg.py: the C method __reduce__, defined in the object class, really calls calling copy_reg._reduce(obj). Eventually the Python code in copy_reg.py needs to be migrated to C, but I'd like to experiment with the Python implementation first. The _reduce() code also relies on an additional helper function, _reconstructor(), defined in copy_reg.py; this should also be reimplemented in C.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/copy_reg.py29
-rw-r--r--Lib/test/test_descr.py63
-rw-r--r--Lib/test/test_descrtut.py1
3 files changed, 92 insertions, 1 deletions
diff --git a/Lib/copy_reg.py b/Lib/copy_reg.py
index e4f0b3c..e93c2a3 100644
--- a/Lib/copy_reg.py
+++ b/Lib/copy_reg.py
@@ -33,3 +33,32 @@ def pickle_complex(c):
return complex, (c.real, c.imag)
pickle(type(1j), pickle_complex, complex)
+
+# Support for picking new-style objects
+
+_dummy_classes = {}
+
+def _reconstructor(cls, base, state):
+ dummy = _dummy_classes.get(base)
+ if dummy is None:
+ class dummy(base): pass
+ _dummy_classes[base] = dummy
+ obj = dummy(state)
+ obj._foo = 1; del obj._foo # hack to create __dict__
+ obj.__class__ = cls
+ return obj
+_reconstructor.__safe_for_unpickling__ = 1
+
+_HEAPTYPE = 1<<9
+
+def _reduce(self):
+ for base in self.__class__.__mro__:
+ if not base.__flags__ & _HEAPTYPE:
+ break
+ else:
+ base = object # not really reachable
+ if base is object:
+ state = None
+ else:
+ state = base(self)
+ return _reconstructor, (self.__class__, base, state), self.__dict__
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 766c399..0357a06 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -785,7 +785,7 @@ def objects():
class Cdict(object):
pass
x = Cdict()
- verify(x.__dict__ is None)
+ verify(x.__dict__ == {})
x.foo = 1
verify(x.foo == 1)
verify(x.__dict__ == {'foo': 1})
@@ -2032,6 +2032,66 @@ def setclass():
cant(object(), list)
cant(list(), object)
+def pickles():
+ if verbose: print "Testing pickling new-style classes and objects..."
+ import pickle, cPickle
+
+ def sorteditems(d):
+ L = d.items()
+ L.sort()
+ return L
+
+ global C
+ class C(object):
+ def __init__(self, a, b):
+ super(C, self).__init__()
+ self.a = a
+ self.b = b
+ def __repr__(self):
+ return "C(%r, %r)" % (self.a, self.b)
+
+ global C1
+ class C1(list):
+ def __new__(cls, a, b):
+ return super(C1, cls).__new__(cls)
+ def __init__(self, a, b):
+ self.a = a
+ self.b = b
+ def __repr__(self):
+ return "C1(%r, %r)<%r>" % (self.a, self.b, list(self))
+
+ global C2
+ class C2(int):
+ def __new__(cls, a, b, val=0):
+ return super(C2, cls).__new__(cls, val)
+ def __init__(self, a, b, val=0):
+ self.a = a
+ self.b = b
+ def __repr__(self):
+ return "C2(%r, %r)<%r>" % (self.a, self.b, int(self))
+
+ for p in pickle, cPickle:
+ for bin in 0, 1:
+
+ for cls in C, C1, C2:
+ s = p.dumps(cls, bin)
+ cls2 = p.loads(s)
+ verify(cls2 is cls)
+
+ a = C1(1, 2); a.append(42); a.append(24)
+ b = C2("hello", "world", 42)
+ s = p.dumps((a, b), bin)
+ x, y = p.loads(s)
+ assert x.__class__ == a.__class__
+ assert sorteditems(x.__dict__) == sorteditems(a.__dict__)
+ assert y.__class__ == b.__class__
+ assert sorteditems(y.__dict__) == sorteditems(b.__dict__)
+ assert `x` == `a`
+ assert `y` == `b`
+ if verbose:
+ print "a = x =", a
+ print "b = y =", b
+
def test_main():
lists()
@@ -2075,6 +2135,7 @@ def test_main():
coercions()
descrdoc()
setclass()
+ pickles()
if verbose: print "All OK"
if __name__ == "__main__":
diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py
index a0de4cc..80e7f05 100644
--- a/Lib/test/test_descrtut.py
+++ b/Lib/test/test_descrtut.py
@@ -206,6 +206,7 @@ Instead, you can get the same information from the list type:
'__mul__',
'__ne__',
'__new__',
+ '__reduce__',
'__repr__',
'__rmul__',
'__setattr__',