[pypy-svn] r22897 - in pypy/dist/pypy: objspace/flow objspace/flow/test tool tool/test

cfbolz at codespeak.net cfbolz at codespeak.net
Tue Jan 31 15:36:31 CET 2006


Author: cfbolz
Date: Tue Jan 31 15:36:29 2006
New Revision: 22897

Added:
   pypy/dist/pypy/objspace/flow/test/test_picklegraph.py
   pypy/dist/pypy/tool/picklesupport.py
   pypy/dist/pypy/tool/test/test_picklesupport.py
Modified:
   pypy/dist/pypy/objspace/flow/model.py
Log:
add __getstate__ and __setstate__ to some of the classes in flow/model.py to make bare graphs (no lltypes attached) pickleable.


Modified: pypy/dist/pypy/objspace/flow/model.py
==============================================================================
--- pypy/dist/pypy/objspace/flow/model.py	(original)
+++ pypy/dist/pypy/objspace/flow/model.py	Tue Jan 31 15:36:29 2006
@@ -6,6 +6,7 @@
 from __future__ import generators
 from pypy.tool.uid import uid, Hashable
 from pypy.tool.sourcetools import PY_IDENTIFIER, nice_repr_for_func
+from pypy.tool.picklesupport import getstate_with_slots, setstate_with_slots
 
 """
     memory size before and after introduction of __slots__
@@ -151,6 +152,9 @@
     def __repr__(self):
         return "link from %s to %s" % (str(self.prevblock), str(self.target))
 
+    __getstate__ = getstate_with_slots
+    __setstate__ = setstate_with_slots
+
 
 class Block(object):
     __slots__ = """isstartblock inputargs operations exitswitch
@@ -222,6 +226,9 @@
             exit.prevblock = self
         self.exits = exits
 
+    __getstate__ = getstate_with_slots
+    __setstate__ = setstate_with_slots
+
 
 class Variable(object):
     __slots__ = ["_name", "_nr", "concretetype"]

Added: pypy/dist/pypy/objspace/flow/test/test_picklegraph.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/flow/test/test_picklegraph.py	Tue Jan 31 15:36:29 2006
@@ -0,0 +1,18 @@
+from pypy.objspace.flow.test import test_model
+from pypy.objspace.flow.model import checkgraph
+
+import pickle
+
+
+def test_pickle_block():
+    # does not raise
+    s = pickle.dumps(test_model.graph.startblock)
+    # does not raise
+    block = pickle.loads(s)
+   
+def test_pickle_graph():
+    # does not raise
+    s = pickle.dumps(test_model.graph)
+    # does not raise
+    newgraph = pickle.loads(s)
+    checkgraph(newgraph)

Added: pypy/dist/pypy/tool/picklesupport.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/tool/picklesupport.py	Tue Jan 31 15:36:29 2006
@@ -0,0 +1,50 @@
+import weakref
+
+def getstate_with_slots(self):
+    result = []
+    for cls in self.__class__.__mro__:
+        if not hasattr(cls, '__slots__'):
+            continue
+        for attr in cls.__slots__:
+            if attr in ("__weakref__", "__dict__"):
+                continue
+            if hasattr(self, attr):
+                result.append((True, attr, getattr(self, attr)))
+            else:
+                result.append((False, attr, None))
+    if hasattr(self, "__dict__"):
+        return result, self.__dict__ 
+    else:
+        return result, None
+
+def setstate_with_slots(self, (state, __dict__)):
+    for i, (is_set, attr, value) in enumerate(state):
+        if is_set:
+            # circumvent eventual __setattr__
+            desc = getattr(self.__class__, attr, None)
+            if desc is None:
+                setattr(self, attr, value)
+            else:
+                desc.__set__(self, value)
+    if __dict__ is not None:
+        self.__dict__ = __dict__
+
+
+class pickleable_weakref(object):
+    __slots__ = "ref"
+    
+    def __init__(self, obj):
+        self.ref = weakref.ref(obj)
+
+    def __call__(self):
+        return self.ref()
+
+    def __getstate__(self):
+        return self.ref()
+
+    def __setstate__(self, obj):
+        self.ref = weakref.ref(obj)
+
+    def __repr__(self):
+        return repr(self.ref)
+

Added: pypy/dist/pypy/tool/test/test_picklesupport.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/tool/test/test_picklesupport.py	Tue Jan 31 15:36:29 2006
@@ -0,0 +1,104 @@
+from pypy.tool.picklesupport import *
+
+import pickle
+import py
+
+class A(object):
+    __slots__ = ("a", "b")
+    __getstate__ = getstate_with_slots
+    __setstate__ = setstate_with_slots
+
+class B(A):
+    __slots__ = ("c", "d")
+
+class C(B):
+    pass
+
+def test_slot_getstate_setstate():
+    b = B()
+    b.a, b.c = range(2)
+    s = pickle.dumps(b)
+    new_b = pickle.loads(s)
+    assert new_b.a == b.a
+    py.test.raises(AttributeError, "new_b.b")
+    assert new_b.c == b.c
+    py.test.raises(AttributeError, "new_b.d")
+
+def test_slot_getstate_setstate_with_dict():
+    c = C()
+    assert '__dict__' in dir(c)
+    c.a, c.b, c.c, c.d, c.e = range(5)
+    s = pickle.dumps(c)
+    new_c = pickle.loads(s)
+    assert new_c.a == c.a
+    assert new_c.b == c.b
+    assert new_c.c == c.c
+    assert new_c.d == c.d
+    assert new_c.e == c.e
+
+class D(B):
+    __slots__ = '__weakref__'
+
+def test_slot_getstate_setstate_with_weakref():
+    d = D()
+    s = pickle.dumps(d)
+    new_d = pickle.loads(s)
+    assert new_d.__weakref__ is None
+
+def test_pickleable_weakref():
+    d = D()
+    ref = pickleable_weakref(d)
+    s = pickle.dumps((d, ref))
+    new_d, new_ref = pickle.loads(s)
+    assert new_ref() is new_d   
+    del new_d
+    assert new_ref() is None
+
+def test_pickleable_weakref_dieing():
+    d = D()
+    ref = pickleable_weakref(d)
+    s = pickle.dumps(ref)
+    new_ref = pickle.loads(s)
+    assert new_ref() is None
+
+class E(B):
+    __slots__ = ()
+    def __init__(self, a, b, c, d):
+        self.__class__.a.__set__(self, a)
+        self.__class__.b.__set__(self, b)
+        self.__class__.c.__set__(self, c)
+        self.__class__.d.__set__(self, d)
+    def __getattr__(self, attr):
+        raise AttributeError("not found")
+
+def test_getsetstate_getattr():
+    e = E(1, 2, 3, 4)
+    s = pickle.dumps(e)
+    new_e = pickle.loads(s)
+    assert new_e.a == 1
+    assert new_e.b == 2
+    assert new_e.c == 3
+    assert new_e.d == 4
+
+class F(B):
+    __slots__ = "__dict__"
+    def __init__(self, a, b, c, d, e):
+        self.__class__.a.__set__(self, a)
+        self.__class__.b.__set__(self, b)
+        self.__class__.c.__set__(self, c)
+        self.__class__.d.__set__(self, d)
+        self.__dict__['e'] = e
+    def __getattr__(self, attr):
+        raise AttributeError("not found")
+ 
+def test_getsetstate_getattr_withdict():
+    f = F(1, 2, 3, 4, 5)
+    assert '__dict__' in dir(f)
+    s = pickle.dumps(f)
+    new_f = pickle.loads(s)
+    assert new_f.a == 1
+    assert new_f.b == 2
+    assert new_f.c == 3
+    assert new_f.d == 4
+    assert new_f.e == 5
+



More information about the Pypy-commit mailing list