[pypy-svn] r49677 - in pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Wed Dec 12 17:00:16 CET 2007


Author: cfbolz
Date: Wed Dec 12 17:00:15 2007
New Revision: 49677

Modified:
   pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py
   pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py
Log:
binary operations


Modified: pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py	(original)
+++ pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py	Wed Dec 12 17:00:15 2007
@@ -198,13 +198,52 @@
     return unaryop
 
 def make_binary_returning_notimplemented_instance_method(name):
-    def richcmp(self, space, w_other):
+    def binaryop(self, space, w_other):
         w_meth = self.getattr(space, space.wrap(name), False)
         if w_meth is None:
             return space.w_NotImplemented
         return space.call_function(w_meth, w_other)
-    return richcmp
+    return binaryop
 
+def make_binary_instance_method(name):
+    specialname = "__%s__" % (name, )
+    rspecialname = "__r%s__" % (name, )
+    objspacename = name
+    if name in ['and', 'or']:
+        objspacename = name + '_'
+
+    def binaryop(self, space, w_other):
+        w_a, w_b = _coerce_helper(space, self, w_other)
+        if w_a is None:
+            w_a = self
+            w_b = w_other
+        if w_a is self:
+            w_meth = self.getattr(space, space.wrap(specialname), False)
+            if w_meth is None:
+                return space.w_NotImplemented
+            return space.call_function(w_meth, w_b)
+        else:
+            return getattr(space, objspacename)(w_a, w_b)
+
+    def rbinaryop(self, space, w_other):
+        w_a, w_b = _coerce_helper(space, self, w_other)
+        if w_a is None or w_a is self:
+            w_meth = self.getattr(space, space.wrap(rspecialname), False)
+            if w_meth is None:
+                return space.w_NotImplemented
+            return space.call_function(w_meth, w_other)
+        else:
+            return getattr(space, objspacename)(w_b, w_a)
+    return binaryop, rbinaryop
+
+def _coerce_helper(space, w_self, w_other):
+    try:
+        w_tup = space.coerce(w_self, w_other)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        return (None, None)
+    return space.unpacktuple(w_tup, 2)
 
 class W_InstanceObject(Wrappable):
     def __init__(self, space, w_class, w_dict=None):
@@ -406,6 +445,20 @@
         meth,
         unwrap_spec=["self", ObjSpace, W_Root])
 
+for op in "or and xor lshift rshift add sub mul div mod divmod floordiv truediv".split():
+    specialname = "__%s__" % (op, )
+    rspecialname = "__r%s__" % (op, )
+    func, rfunc = make_binary_instance_method(op)
+    # fool the gateway logic by giving it a real unbound method
+    meth = new.instancemethod(func, None, W_InstanceObject)
+    rawdict[specialname] = interp2app(
+        meth,
+        unwrap_spec=["self", ObjSpace, W_Root])
+    rmeth = new.instancemethod(rfunc, None, W_InstanceObject)
+    rawdict[rspecialname] = interp2app(
+        rmeth,
+        unwrap_spec=["self", ObjSpace, W_Root])
+
 W_InstanceObject.typedef = TypeDef("instance",
     __new__ = interp2app(W_InstanceObject.descr_new),
     __getattribute__ = interp2app(W_InstanceObject.descr_getattribute,

Modified: pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py
==============================================================================
--- pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py	(original)
+++ pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py	Wed Dec 12 17:00:15 2007
@@ -400,3 +400,38 @@
         class B:
             __metaclass__ = nclassobj
         raises(TypeError, coerce, B(), [])
+
+    def test_binaryop(self):
+        class A:
+            __metaclass__ = nclassobj
+            def __add__(self, other):
+                return 1 + other
+        a = A()
+        assert a + 1 == 2
+        assert a + 1.1 == 2.1
+
+    def test_binaryop_coerces(self):
+        class A:
+            __metaclass__ = nclassobj
+            def __add__(self, other):
+                return 1 + other
+            def __coerce__(self, other):
+                 return self, int(other)
+
+        a = A()
+        assert a + 1 == 2
+        assert a + 1.1 == 2
+
+
+    def test_binaryop_calls_coerce_always(self):
+        l = []
+        class A:
+            __metaclass__ = nclassobj
+            def __coerce__(self, other):
+                 l.append(other)
+
+        a = A()
+        raises(TypeError, "a + 1")
+        raises(TypeError, "a + 1.1")
+        assert l == [1, 1.1]
+



More information about the Pypy-commit mailing list