]> granicus.if.org Git - python/commitdiff
Implement the round functionality for PEP 3141, and add tests for it.
authorAlex Martelli <aleaxit@gmail.com>
Wed, 22 Aug 2007 23:21:33 +0000 (23:21 +0000)
committerAlex Martelli <aleaxit@gmail.com>
Wed, 22 Aug 2007 23:21:33 +0000 (23:21 +0000)
Lib/test/test_builtin.py
Python/bltinmodule.c

index d5fc85fe3e8b2f64b950f79192a096ff918eceb8..37ea8ba88520aeee189b656abb9e8c7a6195f75e 100644 (file)
@@ -1474,6 +1474,19 @@ class BuiltinTest(unittest.TestCase):
 
         self.assertRaises(TypeError, round)
 
+        # test generic rounding delegation for reals
+        class TestRound:
+            def __round__(self):
+                return 23
+
+        class TestNoRound:
+            pass
+
+        self.assertEqual(round(TestRound()), 23)
+
+        self.assertRaises(TypeError, round, 1, 2, 3)
+        self.assertRaises(TypeError, round, TestNoRound())
+
     def test_setattr(self):
         setattr(sys, 'spam', 1)
         self.assertEqual(sys.spam, 1)
index 2c163a16e859c2fbb023819fbb9ad4594559d7cb..b55dd5194803c6ccf8853f637baa77935dc9ab93 100644 (file)
@@ -1378,10 +1378,34 @@ builtin_round(PyObject *self, PyObject *args, PyObject *kwds)
        int ndigits = 0;
        int i;
        static char *kwlist[] = {"number", "ndigits", 0};
+       PyObject* real;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|i:round",
-                kwlist, &number, &ndigits))
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:round",
+                kwlist, &real, &ndigits))
                 return NULL;
+
+       if (ndigits == 0) {
+               PyObject *res;
+               PyObject *d = PyObject_GetAttrString(real, "__round__");
+               if (d == NULL && !PyFloat_Check(real)) {
+                       PyErr_SetString(PyExc_TypeError,
+                                       "round() argument must have __round__ attribute or be a float");
+                       return NULL;
+               } 
+               if (d == NULL) {
+                       PyErr_Clear();
+               } else {
+                       res = PyObject_CallFunction(d, "");
+                       Py_DECREF(d);
+                       return res;
+               } 
+       } else if (!PyFloat_Check(real)) {
+               PyErr_SetString(PyExc_TypeError,
+                               "round() argument must have __round__ attribute or be a float");
+               return NULL;
+       }
+
+       number = PyFloat_AsDouble(real);
        f = 1.0;
        i = abs(ndigits);
        while  (--i >= 0)