[pypy-commit] pypy default: Tweaks for CPython 2.7 compatibility:

arigo noreply at buildbot.pypy.org
Wed Aug 15 18:06:21 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r56730:3c783b31f9da
Date: 2012-08-15 18:06 +0200
http://bitbucket.org/pypy/pypy/changeset/3c783b31f9da/

Log:	Tweaks for CPython 2.7 compatibility:

	- __nonzero__ must return a bool or an int, but not a long

	- if there is no __nonzero__, fall back to __len__, but then
	handle the result in the same way as len() would, e.g. allowing a
	long or a custom class with an __int__.

diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -229,13 +229,15 @@
         return space.get_and_call_function(w_descr, w_obj, w_name)
 
     def is_true(space, w_obj):
-        method = "__nonzero__"
-        w_descr = space.lookup(w_obj, method)
+        w_descr = space.lookup(w_obj, "__nonzero__")
         if w_descr is None:
-            method = "__len__"
-            w_descr = space.lookup(w_obj, method)
+            w_descr = space.lookup(w_obj, "__len__")
             if w_descr is None:
                 return True
+            # call __len__
+            w_res = space.get_and_call_function(w_descr, w_obj)
+            return space._check_len_result(w_res) != 0
+        # call __nonzero__
         w_res = space.get_and_call_function(w_descr, w_obj)
         # more shortcuts for common cases
         if space.is_w(w_res, space.w_False):
@@ -245,11 +247,10 @@
         w_restype = space.type(w_res)
         # Note there is no check for bool here because the only possible
         # instances of bool are w_False and w_True, which are checked above.
-        if (space.is_w(w_restype, space.w_int) or
-            space.is_w(w_restype, space.w_long)):
+        if space.is_w(w_restype, space.w_int):
             return space.int_w(w_res) != 0
         else:
-            msg = "%s should return bool or integer" % (method,)
+            msg = "__nonzero__ should return bool or integer"
             raise OperationError(space.w_TypeError, space.wrap(msg))
 
     def nonzero(space, w_obj):
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -658,7 +658,7 @@
         class X(object):
             def __len__(self): return 1L
             __nonzero__ = __len__
-        assert X()
+        raises(TypeError, bool, X())  # must return bool or int, not long
         del X.__nonzero__
         assert X()
 
@@ -668,6 +668,7 @@
             def __len__(self):
                 return sys.maxsize + 1
         raises(OverflowError, len, X())
+        raises(OverflowError, bool, X())
 
     def test_len_underflow(self):
         import sys
@@ -675,10 +676,12 @@
             def __len__(self):
                 return -1
         raises(ValueError, len, X())
+        raises(ValueError, bool, X())
         class Y(object):
             def __len__(self):
                 return -1L
         raises(ValueError, len, Y())
+        raises(ValueError, bool, Y())
 
     def test_len_custom__int__(self):
         class X(object):
@@ -691,8 +694,12 @@
 
         l = len(X(3.0))
         assert l == 3 and type(l) is int
+        assert X(3.0)
+        assert not X(0.0)
         l = len(X(X(2)))
         assert l == 2 and type(l) is int
+        assert X(X(2))
+        assert not X(X(0))
 
     def test_bool___contains__(self):
         class X(object):


More information about the pypy-commit mailing list