[pypy-commit] pypy int_w-refactor: first step: change the meaning of space.int_w: now by default it also accepts objects which implements __int__, except floats. You can trigger the old behavior by passing allow_conversion=False

antocuni noreply at buildbot.pypy.org
Tue Feb 25 18:06:00 CET 2014


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: int_w-refactor
Changeset: r69429:7e1beef017c9
Date: 2014-02-25 10:49 +0100
http://bitbucket.org/pypy/pypy/changeset/7e1beef017c9/

Log:	first step: change the meaning of space.int_w: now by default it
	also accepts objects which implements __int__, except floats. You
	can trigger the old behavior by passing allow_conversion=False

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -201,7 +201,15 @@
     def unicode_w(self, space):
         self._typed_unwrap_error(space, "unicode")
 
-    def int_w(self, space):
+    def int_w(self, space, allow_conversion=True):
+        # note that W_IntObject.int_w has a fast path and W_FloatObject.int_w
+        # raises
+        w_obj = self
+        if allow_conversion:
+            w_obj = space.int(self)
+        return w_obj._int_w(space)
+
+    def _int_w(self, space):
         self._typed_unwrap_error(space, "integer")
 
     def float_w(self, space):
@@ -220,8 +228,7 @@
     def int(self, space):
         w_impl = space.lookup(self, '__int__')
         if w_impl is None:
-            raise oefmt(space.w_TypeError,
-                        "unsupported operand type for int(): '%T'", self)
+            self._typed_unwrap_error(space, "integer")
         w_result = space.get_and_call_function(w_impl, self)
 
         if (space.isinstance_w(w_result, space.w_int) or
@@ -1348,8 +1355,19 @@
                     'argument must be a string without NUL characters'))
         return rstring.assert_str0(result)
 
-    def int_w(self, w_obj):
-        return w_obj.int_w(self)
+    def int_w(self, w_obj, allow_conversion=True):
+        """
+        Unwrap an app-level int object into an interpret-level int.
+        
+        If allow_conversion==True, w_obj might be of any type which implements
+        __int__, *except* floats which are explicitly rejected. This is the
+        same logic as CPython's PyArg_ParseTuple. If you want to also allow
+        floats, you can call space.int_w(space.int(w_obj)).
+
+        If allow_conversion=False, w_obj needs to be an app-level int or a
+        subclass.
+        """
+        return w_obj.int_w(self, allow_conversion)
 
     def int(self, w_obj):
         return w_obj.int(self)
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -106,7 +106,7 @@
     def len(self, x):
         return len(x)
 
-    def int_w(self, x):
+    def int_w(self, x, allow_conversion=True):
         return x
 
     def eq_w(self, x, y):
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -167,6 +167,40 @@
         self.space.setattr(w_oldstyle, self.space.wrap("__call__"), w_func)
         assert is_callable(w_oldstyle)
 
+    def test_int_w(self):
+        space = self.space
+        w_x = space.wrap(42)
+        assert space.int_w(w_x) == 42
+        assert space.int_w(w_x, allow_conversion=False) == 42
+        #
+        w_x = space.wrap(44.0)
+        space.raises_w(space.w_TypeError, space.int_w, w_x)
+        space.raises_w(space.w_TypeError, space.int_w, w_x, allow_conversion=False)
+        #
+        w_instance = self.space.appexec([], """():
+            class MyInt(object):
+                def __int__(self):
+                    return 43
+            return MyInt()
+        """)
+        assert space.int_w(w_instance) == 43
+        space.raises_w(space.w_TypeError, space.int_w, w_instance, allow_conversion=False)
+        #
+        w_instance = self.space.appexec([], """():
+            class MyInt(object):
+                def __int__(self):
+                    return 43
+
+            class AnotherInt(object):
+                def __int__(self):
+                    return MyInt()
+
+            return AnotherInt()
+        """)
+        space.raises_w(space.w_TypeError, space.int_w, w_instance)
+        space.raises_w(space.w_TypeError, space.int_w, w_instance, allow_conversion=False)
+
+
     def test_interp_w(self):
         w = self.space.wrap
         w_bltinfunction = self.space.builtin.get('len')
diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py
--- a/pypy/module/cppyy/test/test_zjit.py
+++ b/pypy/module/cppyy/test/test_zjit.py
@@ -141,7 +141,7 @@
     def is_w(self, w_one, w_two):
         return w_one is w_two
 
-    def int_w(self, w_obj):
+    def int_w(self, w_obj, allow_conversion=True):
         assert isinstance(w_obj, FakeInt)
         return w_obj.val
 
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -157,6 +157,7 @@
         return w_obj.floatval
 
     def int_w(self, w_obj):
+        XXX # fix this
         if isinstance(w_obj, IntObject):
             return w_obj.intval
         elif isinstance(w_obj, FloatObject):
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -366,6 +366,7 @@
 
 class W_IntegerBox(W_NumberBox):
     def int_w(self, space):
+        XXX # fix this
         return space.int_w(self.descr_int(space))
 
 class W_SignedIntegerBox(W_IntegerBox):
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -45,7 +45,7 @@
     def unicode_w(self, space):
         return NonConstant(u"foobar")
 
-    def int_w(self, space):
+    def int_w(self, space, allow_conversion=True):
         return NonConstant(-42)
 
     def uint_w(self, space):
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -34,6 +34,9 @@
     def unwrap(self, space):
         return self.floatval
 
+    def int_w(self, space, allow_conversion=True):
+        self._typed_unwrap_error(space, "integer")
+
     def float_w(self, space):
         return self.floatval
 
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -309,9 +309,13 @@
         """representation for debugging purposes"""
         return "%s(%d)" % (self.__class__.__name__, self.intval)
 
-    def int_w(self, space):
+    def int_w(self, space, allow_conversion=True):
         return int(self.intval)
-    unwrap = int_w
+
+    def _int_w(self, space):
+        return int(self.intval)
+    
+    unwrap = _int_w
 
     def uint_w(self, space):
         intval = self.intval
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -244,7 +244,7 @@
     def fromrarith_int(i):
         return W_LongObject(rbigint.fromrarith_int(i))
 
-    def int_w(self, space):
+    def _int_w(self, space):
         try:
             return self.num.toint()
         except OverflowError:
diff --git a/pypy/objspace/std/smalllongobject.py b/pypy/objspace/std/smalllongobject.py
--- a/pypy/objspace/std/smalllongobject.py
+++ b/pypy/objspace/std/smalllongobject.py
@@ -44,7 +44,7 @@
     def __repr__(self):
         return '<W_SmallLongObject(%d)>' % self.longlong
 
-    def int_w(self, space):
+    def _int_w(self, space):
         a = self.longlong
         b = intmask(a)
         if b == a:
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -1046,7 +1046,7 @@
         assert isinstance(string, str)
         return string
 
-    def int_w(self, integer):
+    def int_w(self, integer, allow_conversion=True):
         assert isinstance(integer, int)
         return integer
 


More information about the pypy-commit mailing list