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

hpk at codespeak.net hpk at codespeak.net
Wed Mar 21 20:02:35 CET 2007


Author: hpk
Date: Wed Mar 21 20:02:34 2007
New Revision: 40966

Modified:
   pypy/dist/demo/tp-persistence.py
   pypy/dist/pypy/lib/test2/test_tputil.py
   pypy/dist/pypy/lib/tputil.py
Log:
settling the tputil API to handle both virtual
and concrete proxies (the latter are instantiated
through providing an instance 'obj' and there is
convenient help to delegate operations to it, 
see the tests and docstring for details) 


Modified: pypy/dist/demo/tp-persistence.py
==============================================================================
--- pypy/dist/demo/tp-persistence.py	(original)
+++ pypy/dist/demo/tp-persistence.py	Wed Mar 21 20:02:34 2007
@@ -5,7 +5,7 @@
 
 """
 from pypymagic import tproxy, get_tproxy_controller
-from tputil import make_instance_proxy 
+from tputil import make_proxy 
 
 list_changeops = set('__iadd__ __imul__ __delitem__ __setitem__ '
                      '__delslice__ __setslice__ '
@@ -13,11 +13,11 @@
 
 def make_plist(instance, storage): 
     def perform(invocation): 
-        res = invocation.perform()
+        res = invocation.delegate()
         if invocation.opname in list_changeops: 
             storage.dump(instance) 
         return res
-    return make_instance_proxy(instance, perform, typ=list) 
+    return make_proxy(perform, type=list, obj=instance) 
 
 def get_plist(storage):
     obj = storage.load()

Modified: pypy/dist/pypy/lib/test2/test_tputil.py
==============================================================================
--- pypy/dist/pypy/lib/test2/test_tputil.py	(original)
+++ pypy/dist/pypy/lib/test2/test_tputil.py	Wed Mar 21 20:02:34 2007
@@ -1,35 +1,59 @@
 from pypy.conftest import gettestobjspace
 
-class AppTestTPListproxy:
+class AppTest_make_proxy:
     def setup_class(cls):
         cls.space = gettestobjspace(**{"objspace.std.withtproxy": True})
+
+    def test_errors(self):
+        from tputil import make_proxy 
+        raises(TypeError, "make_proxy(None)")
+        raises(TypeError, "make_proxy(None, None)")
+        def f(): pass 
+        raises(TypeError, "make_proxy(f)")
+        raises(TypeError, "make_proxy(f, None, None)")
+
+    def test_virtual_proxy(self):
+        from tputil import make_proxy 
+        l = []
+        tp = make_proxy(l.append, type=list)
+        x = len(tp)
+        assert len(l) == 1
+        assert l[0].opname == '__len__'
        
-    def test_listproxy_basic(self):
-        from tputil import make_instance_proxy 
+    def test_simple(self):
+        from tputil import make_proxy 
         record = []
-        def func(invocation):
-            record.append(invocation)
-            return invocation.perform()
-        l = make_instance_proxy([], func) 
+        def func(operation):
+            record.append(operation)
+            return operation.delegate()
+        l = make_proxy(func, obj=[])
         l.append(1)
         assert len(record) == 2
         i1, i2 = record 
         assert i1.opname == '__getattribute__'
         assert i2.opname == 'append' 
 
+    def test_missing_attr(self):
+        from tputil import make_proxy
+        def func(operation):
+            return operation.delegate()
+        l = make_proxy(func, obj=[]) 
+        excinfo = raises(AttributeError, "l.asdasd")
+        assert str(excinfo).find("asdasd") != -1
+
     def test_proxy_double(self): 
-        from tputil import make_instance_proxy 
+        from tputil import make_proxy
         r1 = []
         r2 = []
-        def func1(invocation):
-            r1.append(invocation)
-            return invocation.perform()
-        def func2(invocation):
-            r2.append(invocation)
-            return invocation.perform()
+        def func1(operation):
+            r1.append(operation)
+            return operation.delegate()
+        def func2(operation):
+            r2.append(operation)
+            return operation.delegate()
             
-        l = make_instance_proxy([], func1) 
-        l2 = make_instance_proxy(l, func2) 
+        l = make_proxy(func1, obj=[])
+        l2 = make_proxy(func2, obj=l)
         assert not r1 and not r2
         l2.append
         assert len(r2) == 1
@@ -42,12 +66,12 @@
 
     def test_proxy_inplace_add(self):
         r = []
-        from tputil import make_instance_proxy 
-        def func1(invocation):
-            r.append(invocation)
-            return invocation.perform()
+        from tputil import make_proxy 
+        def func1(operation):
+            r.append(operation)
+            return operation.delegate()
 
-        l2 = make_instance_proxy([], func1)
+        l2 = make_proxy(func1, obj=[])
         l = l2
         l += [3]
         assert l is l2

Modified: pypy/dist/pypy/lib/tputil.py
==============================================================================
--- pypy/dist/pypy/lib/tputil.py	(original)
+++ pypy/dist/pypy/lib/tputil.py	Wed Mar 21 20:02:34 2007
@@ -10,34 +10,59 @@
 from pypymagic import tproxy 
 from types import MethodType
 
-def make_instance_proxy(instance, invokefunc=None, typ=None): 
-    if typ is None:
-        typ = type(instance) 
+_dummy = object()
+origtype = type
+
+def make_proxy(controller, type=_dummy, obj=_dummy): 
+    """ return a tranparent proxy controlled by the given 
+        'controller' callable.  The proxy will appear 
+        as a completely regular instance of the given 
+        type but all operations on it are send to the 
+        specified controller - which receices on 
+        ProxyOperation instance on each such call.  A non-specified 
+        type will default to type(obj) if obj is specified. 
+    """
+    if type is _dummy: 
+        if obj is _dummy: 
+            raise TypeError("you must specify a type or an instance obj") 
+        type = origtype(obj) 
     def perform(opname, *args, **kwargs):
-        invocation = Invocation(tp, instance, opname, args, kwargs)
-        return invokefunc(invocation) 
-    tp = tproxy(typ, perform) 
+        operation = ProxyOperation(tp, type, obj, opname, args, kwargs)
+        return controller(operation) 
+    tp = tproxy(type, perform) 
     return tp 
 
-class Invocation(object):
-    def __init__(self, proxyobj, realobj, opname, args, kwargs):
+class ProxyOperation(object):
+    def __init__(self, proxyobj, type, obj, opname, args, kwargs):
         self.proxyobj = proxyobj
-        self.realobj = realobj 
         self.opname = opname 
         self.args = args
         self.kwargs = kwargs
-        self.realmethod = getattr(realobj, opname) 
+        self.type = type 
+        if obj is not _dummy: 
+            self.obj = obj 
 
-    def perform(self):
-        res = self.realmethod(*self.args, **self.kwargs)
+    def delegate(self):
+        """ return result from delegating this operation to the 
+            underyling self.obj - which must exist and is usually 
+            provided through the initial make_proxy(..., obj=...) 
+            creation. 
+        """ 
+        try:
+            obj = getattr(self, 'obj')
+        except AttributeError: 
+            raise TypeError("proxy does not have an underlying 'obj', "
+                            "cannot delegate")
+        objattr = getattr(obj, self.opname) 
+        res = objattr(*self.args, **self.kwargs) 
         if self.opname == "__getattribute__": 
             if (isinstance(res, MethodType) and
-                res.im_self is self.realobj):
+                res.im_self is self.instance):
                 res = MethodType(res.im_func, self.proxyobj, res.im_class)
-        if res is self.realobj:
-            return self.proxyobj
+        if res is self.obj: 
+            res = self.proxyobj
         return res 
 
     def __repr__(self):
-        return "<Invocation %s(*%r, **%r)" %(self.realmethod, 
-                                             self.args, self.kwargs)
+        return "<ProxyOperation %s(*%r, **%r) %x>" %(
+                    self.opname, self.args, self.kwargs, id(self))



More information about the Pypy-commit mailing list