]> granicus.if.org Git - python/commitdiff
Fix math.ceil() and math.floor() to fall back to __ceil__ and __floor__
authorGuido van Rossum <guido@python.org>
Thu, 23 Aug 2007 22:56:55 +0000 (22:56 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 23 Aug 2007 22:56:55 +0000 (22:56 +0000)
methods (respectively).  With Keir Mierle.

Lib/test/test_math.py
Modules/mathmodule.c

index c28902b94f34ff73414d3515bfcd65d12708a5de..2d15f3aa41b5e9487ae7babb5b9bfc69ea7a7d60 100644 (file)
@@ -58,6 +58,19 @@ class MathTests(unittest.TestCase):
         self.ftest('ceil(-1.0)', math.ceil(-1.0), -1)
         self.ftest('ceil(-1.5)', math.ceil(-1.5), -1)
 
+        class TestCeil:
+            def __ceil__(self):
+                return 42
+        class TestNoCeil:
+            pass
+        self.ftest('ceil(TestCeil())', math.ceil(TestCeil()), 42)
+        self.assertRaises(TypeError, math.ceil, TestNoCeil())
+
+        t = TestNoCeil()
+        t.__ceil__ = lambda *args: args
+        self.assertRaises(TypeError, math.ceil, t)
+        self.assertRaises(TypeError, math.ceil, t, 0)
+
     def testCos(self):
         self.assertRaises(TypeError, math.cos)
         self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0)
@@ -101,6 +114,19 @@ class MathTests(unittest.TestCase):
         self.ftest('floor(1.23e167)', math.floor(1.23e167), 1.23e167)
         self.ftest('floor(-1.23e167)', math.floor(-1.23e167), -1.23e167)
 
+        class TestFloor:
+            def __floor__(self):
+                return 42
+        class TestNoFloor:
+            pass
+        self.ftest('floor(TestFloor())', math.floor(TestFloor()), 42)
+        self.assertRaises(TypeError, math.floor, TestNoFloor())
+
+        t = TestNoFloor()
+        t.__floor__ = lambda *args: args
+        self.assertRaises(TypeError, math.floor, t)
+        self.assertRaises(TypeError, math.floor, t, 0)
+
     def testFmod(self):
         self.assertRaises(TypeError, math.fmod)
         self.ftest('fmod(10,1)', math.fmod(10,1), 0)
index 3d5640cf14e696df73d070dbb1898838fbf88140..864df234e2777d564c8a55c569fc5c18ee343e55 100644 (file)
@@ -107,9 +107,28 @@ FUNC1(atan, atan,
 FUNC2(atan2, atan2,
       "atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n"
       "Unlike atan(y/x), the signs of both x and y are considered.")
-FUNC1(ceil, ceil,
-      "ceil(x)\n\nReturn the ceiling of x as a float.\n"
-      "This is the smallest integral value >= x.")
+
+static PyObject * math_ceil(PyObject *self, PyObject *number) {
+       static PyObject *ceil_str = NULL;
+       PyObject *method;
+
+       if (ceil_str == NULL) {
+               ceil_str = PyUnicode_FromString("__ceil__");
+               if (ceil_str == NULL)
+                       return NULL;
+       }
+
+       method = _PyType_Lookup(Py_Type(number), ceil_str);
+       if (method == NULL)
+               return math_1(number, ceil);
+       else
+               return PyObject_CallFunction(method, "O", number);
+}
+
+PyDoc_STRVAR(math_ceil_doc,
+            "ceil(x)\n\nReturn the ceiling of x as a float.\n"
+            "This is the smallest integral value >= x.");
+
 FUNC1(cos, cos,
       "cos(x)\n\nReturn the cosine of x (measured in radians).")
 FUNC1(cosh, cosh,
@@ -118,9 +137,28 @@ FUNC1(exp, exp,
       "exp(x)\n\nReturn e raised to the power of x.")
 FUNC1(fabs, fabs,
       "fabs(x)\n\nReturn the absolute value of the float x.")
-FUNC1(floor, floor,
-      "floor(x)\n\nReturn the floor of x as a float.\n"
-      "This is the largest integral value <= x.")
+
+static PyObject * math_floor(PyObject *self, PyObject *number) {
+       static PyObject *floor_str = NULL;
+       PyObject *method;
+
+       if (floor_str == NULL) {
+               floor_str = PyUnicode_FromString("__floor__");
+               if (floor_str == NULL)
+                       return NULL;
+       }
+
+       method = _PyType_Lookup(Py_Type(number), floor_str);
+       if (method == NULL)
+               return math_1(number, floor);
+       else
+               return PyObject_CallFunction(method, "O", number);
+}
+
+PyDoc_STRVAR(math_floor_doc,
+            "floor(x)\n\nReturn the floor of x as a float.\n"
+            "This is the largest integral value <= x.");
+
 FUNC2(fmod, fmod,
       "fmod(x,y)\n\nReturn fmod(x, y), according to platform C."
       "  x % y may differ.")