[pypy-svn] r40841 - in pypy/dist: demo pypy/lib pypy/lib/test2

hpk at codespeak.net hpk at codespeak.net
Tue Mar 20 14:59:52 CET 2007


Author: hpk
Date: Tue Mar 20 14:59:50 2007
New Revision: 40841

Added:
   pypy/dist/pypy/lib/test2/test_tputil.py   (contents, props changed)
   pypy/dist/pypy/lib/tputil.py   (contents, props changed)
Modified:
   pypy/dist/demo/tp-persistence.py
Log:
initial draft for some support for transparent
proxies, with tests. adapating the demo a bit. 



Modified: pypy/dist/demo/tp-persistence.py
==============================================================================
--- pypy/dist/demo/tp-persistence.py	(original)
+++ pypy/dist/demo/tp-persistence.py	Tue Mar 20 14:59:50 2007
@@ -5,39 +5,26 @@
 
 """
 from pypymagic import transparent_proxy, get_transparent_controller
-from types import MethodType
+from tputil import BaseDispatcher
 
-class PersistentListController(object):
+class PListDispatcher(BaseDispatcher):
     _changeops = ('__iadd__ __imul__ __delitem__ __setitem__ '
-                  '__delslice__ __setslice__ __init__ '
+                  '__delslice__ __setslice__ '
                   'append extend insert pop remove reverse sort').split()
 
-    def __init__(self, obj, storage): 
-        self._obj = obj 
+    def __init__(self, realobj, storage):
+        parent = super(PListDispatcher, self)
+        parent.__init__(realobj, list) 
         self._storage = storage 
-        self.persist()
-        self.proxy = transparent_proxy(list, self.perform)
 
-    def persist(self):
-        self._storage.dump(self._obj) 
-
-    def perform(self, operation, *args, **kwargs):
-        result = getattr(self._obj, operation)(*args, **kwargs)
-        if operation in self._changeops: 
-            # state was modified, do maximally eager checkpointing 
+    def op_default(self, realmethod, *args, **kwargs):
+        res = realmethod(*args, **kwargs) 
+        if realmethod.__name__ in self._changeops: 
             self.persist()
-        if result is self._obj:
-            # If the result is the proxied list
-            # return the proxy instead.
-            result = self.proxy
-        elif (isinstance(result, MethodType) and
-             result.im_self is self._obj):
-            # Convert methods bound to the proxied list
-            # to methods bound to the proxy.
-            # This is to have calls to the method become calls
-            # to perform.
-            result = MethodType(result.im_func, self.proxy, result.im_class)
-        return result
+        return res 
+
+    def persist(self):
+        self._storage.dump(self.realobj) 
 
     @classmethod
     def load(cls, storage):
@@ -46,6 +33,7 @@
 
 def work_with_list(mylist):
     assert isinstance(mylist, list)
+    assert mylist.__class__ is list 
     mylist.append(4) 
     mylist += [5,6,7]
 
@@ -54,7 +42,7 @@
     storage = py.path.local("/tmp/mystorage")
             
     somelist = [1,2,3]
-    newlist = PersistentListController(somelist, storage).proxy 
+    newlist = PListDispatcher(somelist, storage).proxyobj
 
     # here we may call into application code which can 
     # not detect easily that it is dealing with a persistent
@@ -62,6 +50,12 @@
     work_with_list(newlist)
     del somelist, newlist 
 
-    restoredlist = PersistentListController.load(storage).proxy
+    restoredlist = PListDispatcher.load(storage).proxyobj
     print "restored list", restoredlist
-    print restoredlist == [1,2,3,4,5,6,7]
+    assert restoredlist == [1,2,3,4,5,6,7]
+    restoredlist *= 2
+    del restoredlist 
+    restoredlist = PListDispatcher.load(storage).proxyobj
+    print "restored list 2", restoredlist
+    assert restoredlist == [1,2,3,4,5,6,7] * 2
+    

Added: pypy/dist/pypy/lib/test2/test_tputil.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lib/test2/test_tputil.py	Tue Mar 20 14:59:50 2007
@@ -0,0 +1,36 @@
+from pypy.conftest import gettestobjspace
+
+class AppTestTPListproxy:
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withtproxy": True})
+        cls.w_BaseDispatcher = cls.space.appexec([],"""
+            (): 
+                from tputil import BaseDispatcher
+                return BaseDispatcher 
+        """)
+       
+    def test_listproxy_basic(self):
+        x = []
+        wrapper = self.BaseDispatcher(x)
+        assert wrapper.realobj is x 
+        l = wrapper.proxyobj
+        assert type(l) is list
+        l.append(1)
+        l.extend([2,3])
+        assert l == [1,2,3]
+        assert x == l
+    
+    def test_listproxy_getattribute(self):
+        disp = self.BaseDispatcher([])
+        meth = disp.proxyobj.append 
+        assert meth.im_self == disp.proxyobj
+        meth = disp.proxyobj.__getattribute__
+        assert meth.im_self == disp.proxyobj
+
+    def test_listproxy_hook(self):
+        class MyBaseDispatcher(self.BaseDispatcher):
+            def op___getitem__(self, *args, **kwargs):
+                return 42 
+        l = MyBaseDispatcher([]).proxyobj
+        assert l[0] == 42
+        assert l[-1] == 42

Added: pypy/dist/pypy/lib/tputil.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lib/tputil.py	Tue Mar 20 14:59:50 2007
@@ -0,0 +1,39 @@
+"""
+
+application level support module for transparent proxies. 
+This currently contains a BaseDispatcher class
+whose subclasses may define "op_METH" where METH 
+is the original method operation name for 
+the proxied object. 
+
+"""
+from pypymagic import transparent_proxy 
+from types import MethodType
+
+class BaseDispatcher(object):
+    def __init__(self, realobj, typ=None):
+        self.realobj = realobj 
+        if typ is None:
+            typ = type(realobj) 
+        self.proxyobj = transparent_proxy(typ, self.invoke)
+
+    def invoke(self, operation, *args, **kwargs):
+        """ return result from dispatching to proxied operation. """
+        realmethod = getattr(self.realobj, operation) 
+        print "operation", operation
+        dispmethod = getattr(self, "op_" + operation, None)
+        if dispmethod is None:
+            dispmethod = self.op_default 
+        res = dispmethod(realmethod, *args, **kwargs)
+        return res
+
+    def op___getattribute__(self, realmethod, *args, **kwargs):
+        res = realmethod(*args, **kwargs)
+        if (isinstance(res, MethodType) and
+             res.im_self is self.realobj):
+            res= MethodType(res.im_func, self.proxyobj, res.im_class)
+        return res
+        
+    def op_default(self, realmethod, *args, **kwargs):
+        return realmethod(*args, **kwargs)
+



More information about the Pypy-commit mailing list