fix a corner case where float(x) would not call x.__float__() for a float subtype
authorStefan Behnel <stefan_ml@behnel.de>
Mon, 28 Jan 2013 21:04:04 +0000 (22:04 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Mon, 28 Jan 2013 21:04:04 +0000 (22:04 +0100)
Cython/Utility/Optimize.c
tests/run/int_float_builtins_as_casts_T400.pyx

index b04078e..4bb41a1 100644 (file)
@@ -476,8 +476,16 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj) {
 #if CYTHON_COMPILING_IN_PYPY
     float_value = PyNumber_Float(obj);
 #else
-    if (Py_TYPE(obj)->tp_as_number && Py_TYPE(obj)->tp_as_number->nb_float) {
-        return PyFloat_AsDouble(obj);
+    PyNumberMethods *nb = Py_TYPE(obj)->tp_as_number;
+    if (likely(nb) && likely(nb->nb_float)) {
+        float_value = nb->nb_float(obj);
+        if (likely(float_value) && unlikely(!PyFloat_Check(float_value))) {
+            PyErr_Format(PyExc_TypeError,
+                "__float__ returned non-float (type %.200s)",
+                Py_TYPE(float_value)->tp_name);
+            Py_DECREF(float_value);
+            goto bad;
+        }
     } else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) {
 #if PY_MAJOR_VERSION >= 3
         float_value = PyFloat_FromString(obj);
index c18ee01..beca903 100644 (file)
@@ -137,3 +137,37 @@ def double_to_double_int(double x):
     """
     cdef double r = int(x)
     return r
+
+
+class MyFloat(float):
+    """
+    >>> x = MyFloat(1.0)
+    >>> x
+    1.0
+    >>> float(x)
+    12.0
+    >>> x.float()
+    12.0
+    """
+    def __float__(self):
+        return 12.0
+
+    def float(self):
+        return float(self)
+
+
+class MyInt(int):
+    """
+    >>> x = MyInt(1)
+    >>> x
+    1
+    >>> int(x)
+    2
+    >>> x.int()
+    2
+    """
+    def __int__(self):
+        return 2
+
+    def int(self):
+        return int(self)