[pypy-svn] r62724 - in pypy/trunk/pypy/objspace/std: . test

arigo at codespeak.net arigo at codespeak.net
Sat Mar 7 18:51:50 CET 2009


Author: arigo
Date: Sat Mar  7 18:51:49 2009
New Revision: 62724

Modified:
   pypy/trunk/pypy/objspace/std/builtinshortcut.py
   pypy/trunk/pypy/objspace/std/model.py
   pypy/trunk/pypy/objspace/std/objspace.py
   pypy/trunk/pypy/objspace/std/test/test_builtinshortcut.py
Log:
issue426 testing

Improve builtinshortcut to work also for inplace operations
that fallback to normal operations, like x += 5.


Modified: pypy/trunk/pypy/objspace/std/builtinshortcut.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/builtinshortcut.py	(original)
+++ pypy/trunk/pypy/objspace/std/builtinshortcut.py	Sat Mar  7 18:51:49 2009
@@ -50,7 +50,7 @@
             % (_name,))
 
 
-def install(space, mm):
+def install(space, mm, fallback_mm=None):
     """Install a function <name>() on the space instance which invokes
     a shortcut for built-in types.  Returns the shortcutting multimethod
     object or None.
@@ -79,6 +79,8 @@
     # (and only these ones) never match the interp-level subclasses
     # built in pypy.interpreter.typedef.get_unique_interplevel_subclass.
     expanded_order = space.model.get_typeorder_with_empty_usersubcls()
+    if fallback_mm:
+        mm = mm.merge_with(fallback_mm)
     shortcut_method = mm.install_not_sliced(expanded_order)
 
     def operate(*args_w):
@@ -95,31 +97,21 @@
 
 
 def install_is_true(space, mm_nonzero, mm_len):
-    nonzero_shortcut = install(space, mm_nonzero)
-    len_shortcut = install(space, mm_len)
+    shortcut = install(space, mm_nonzero, fallback_mm = mm_len)
     assert 'is_true' not in space.__dict__
 
     def is_true(w_obj):
         # a bit of duplication of the logic from DescrOperation.is_true...
-        # first try 'nonzero'
         try:
-            w_res = nonzero_shortcut(space, w_obj)
+            w_res = shortcut(space, w_obj)
         except FailedToImplement:
             pass
         else:
             # the __nonzero__ method of built-in objects should
-            # always directly return a Bool
-            assert isinstance(w_res, W_BoolObject)
-            return w_res.boolval
-
-        # then try 'len'
-        try:
-            w_res = len_shortcut(space, w_obj)
-        except FailedToImplement:
-            pass
-        else:
-            # the __len__ method of built-in objects typically
-            # returns an unwrappable integer
+            # always directly return a Bool; however, the __len__ method
+            # of built-in objects typically returns an unwrappable integer
+            if isinstance(w_res, W_BoolObject):
+                return w_res.boolval
             try:
                 return space.int_w(w_res) != 0
             except OperationError:

Modified: pypy/trunk/pypy/objspace/std/model.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/model.py	(original)
+++ pypy/trunk/pypy/objspace/std/model.py	Sat Mar  7 18:51:49 2009
@@ -329,3 +329,29 @@
         return self.install(prefix = '__mm_' + self.name,
                 list_of_typeorders = [typeorder]*self.arity,
                 baked_perform_call=baked_perform_call)
+
+    def merge_with(self, other):
+        # Make a new 'merged' multimethod including the union of the two
+        # tables.  In case of conflict, pick the entry from 'self'.
+        if self.arity != other.arity:
+            return self      # XXX that's the case of '**'
+        operatorsymbol = '%s_merge_%s' % (self.name, other.name)
+        assert self.extras == other.extras
+        mm = StdObjSpaceMultiMethod(operatorsymbol, self.arity, **self.extras)
+        #
+        def merge(node1, node2):
+            assert type(node1) is type(node2)
+            if isinstance(node1, dict):
+                d = node1.copy()
+                d.update(node2)
+                for key in node1:
+                    if key in node2:
+                        d[key] = merge(node1[key], node2[key])
+                return d
+            else:
+                assert isinstance(node1, list)
+                assert node1
+                return node1     # pick the entry from 'self'
+        #
+        mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree)
+        return mm

Modified: pypy/trunk/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/objspace.py	(original)
+++ pypy/trunk/pypy/objspace/std/objspace.py	Sat Mar  7 18:51:49 2009
@@ -286,7 +286,14 @@
                 setattr(self, name, boundmethod)  # store into 'space' instance
             elif self.config.objspace.std.builtinshortcut:
                 from pypy.objspace.std import builtinshortcut
-                builtinshortcut.install(self, mm)
+                if name.startswith('inplace_'):
+                    fallback_name = name[len('inplace_'):]
+                    if fallback_name in ('or', 'and'):
+                        fallback_name += '_'
+                    fallback_mm = self.MM.__dict__[fallback_name]
+                else:
+                    fallback_mm = None
+                builtinshortcut.install(self, mm, fallback_mm)
 
         if self.config.objspace.std.builtinshortcut:
             from pypy.objspace.std import builtinshortcut

Modified: pypy/trunk/pypy/objspace/std/test/test_builtinshortcut.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_builtinshortcut.py	(original)
+++ pypy/trunk/pypy/objspace/std/test/test_builtinshortcut.py	Sat Mar  7 18:51:49 2009
@@ -34,6 +34,34 @@
         s.discard(F("abc"))
         assert not s
 
+    def test_inplace_methods(self):
+        assert '__iadd__' not in int.__dict__
+        assert '__iadd__' not in float.__dict__
+        x = 5
+        x += 6.5
+        assert x == 11.5
+
+    def test_inplace_user_subclasses(self):
+        class I(int): pass
+        class F(float): pass
+        x = I(5)
+        x += F(6.5)
+        assert x == 11.5
+        assert type(x) is float
+
+    def test_inplace_override(self):
+        class I(int):
+            def __iadd__(self, other):
+                return 'foo'
+        x = I(5)
+        x += 6
+        assert x == 'foo'
+        x = I(5)
+        x += 6.5
+        assert x == 'foo'
+        assert 5 + 6.5 == 11.5
+
+
 class AppTestSet(test_set.AppTestAppSetTest):
     # this tests tons of funny comparison combinations that can easily go wrong
     def setup_class(cls):



More information about the Pypy-commit mailing list