]> granicus.if.org Git - python/commitdiff
Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 23 Jun 2015 12:31:11 +0000 (14:31 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 23 Jun 2015 12:31:11 +0000 (14:31 +0200)
Lib/test/test_cmath.py
Misc/NEWS
Modules/_testcapimodule.c
Modules/cmathmodule.c

index 4db6b2b991baad909362e518a9a90c353df2b1f4..68bf16e51aaabece747e90d3fccf835ef52b6d43 100644 (file)
@@ -1,4 +1,4 @@
-from test.support import run_unittest, requires_IEEE_754
+from test.support import run_unittest, requires_IEEE_754, cpython_only
 from test.test_math import parse_testfile, test_file
 import unittest
 import cmath, math
@@ -381,17 +381,48 @@ class CMathTests(unittest.TestCase):
             self.rAssertAlmostEqual(expected.imag, actual.imag,
                                         msg=error_message)
 
-    def assertCISEqual(self, a, b):
-        eps = 1E-7
-        if abs(a[0] - b[0]) > eps or abs(a[1] - b[1]) > eps:
-            self.fail((a ,b))
+    def check_polar(self, func):
+        def check(arg, expected):
+            got = func(arg)
+            for e, g in zip(expected, got):
+                self.rAssertAlmostEqual(e, g)
+        check(0, (0., 0.))
+        check(1, (1., 0.))
+        check(-1, (1., pi))
+        check(1j, (1., pi / 2))
+        check(-3j, (3., -pi / 2))
+        inf = float('inf')
+        check(complex(inf, 0), (inf, 0.))
+        check(complex(-inf, 0), (inf, pi))
+        check(complex(3, inf), (inf, pi / 2))
+        check(complex(5, -inf), (inf, -pi / 2))
+        check(complex(inf, inf), (inf, pi / 4))
+        check(complex(inf, -inf), (inf, -pi / 4))
+        check(complex(-inf, inf), (inf, 3 * pi / 4))
+        check(complex(-inf, -inf), (inf, -3 * pi / 4))
+        nan = float('nan')
+        check(complex(nan, 0), (nan, nan))
+        check(complex(0, nan), (nan, nan))
+        check(complex(nan, nan), (nan, nan))
+        check(complex(inf, nan), (inf, nan))
+        check(complex(-inf, nan), (inf, nan))
+        check(complex(nan, inf), (inf, nan))
+        check(complex(nan, -inf), (inf, nan))
 
     def test_polar(self):
-        self.assertCISEqual(polar(0), (0., 0.))
-        self.assertCISEqual(polar(1.), (1., 0.))
-        self.assertCISEqual(polar(-1.), (1., pi))
-        self.assertCISEqual(polar(1j), (1., pi/2))
-        self.assertCISEqual(polar(-1j), (1., -pi/2))
+        self.check_polar(polar)
+
+    @cpython_only
+    def test_polar_errno(self):
+        # Issue #24489: check a previously set C errno doesn't disturb polar()
+        from _testcapi import set_errno
+        def polar_with_errno_set(z):
+            set_errno(11)
+            try:
+                return polar(z)
+            finally:
+                set_errno(0)
+        self.check_polar(polar_with_errno_set)
 
     def test_phase(self):
         self.assertAlmostEqual(phase(0), 0.)
index b2f49600ac25393607456c0c6e2542aabcc68132..7205e93841da153b2ee416df7ed09016c26b8e25 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -60,6 +60,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().
+
 - Issue #5633: Fixed timeit when the statement is a string and the setup is not.
 
 - Issue #24326: Fixed audioop.ratecv() with non-default weightB argument.
index cf4b0e14f012a11c7e435ac78e0b65caeafbd97c..8ebe9709b7923121f921059c26c496a55674875d 100644 (file)
@@ -1783,6 +1783,18 @@ raise_exception(PyObject *self, PyObject *args)
     return NULL;
 }
 
+static PyObject *
+set_errno(PyObject *self, PyObject *args)
+{
+    int new_errno;
+
+    if (!PyArg_ParseTuple(args, "i:set_errno", &new_errno))
+        return NULL;
+
+    errno = new_errno;
+    Py_RETURN_NONE;
+}
+
 static PyObject *
 test_set_exc_info(PyObject *self, PyObject *args)
 {
@@ -3208,6 +3220,7 @@ pymarshal_read_object_from_file(PyObject* self, PyObject *args)
 static PyMethodDef TestMethods[] = {
     {"raise_exception",         raise_exception,                 METH_VARARGS},
     {"raise_memoryerror",   (PyCFunction)raise_memoryerror,  METH_NOARGS},
+    {"set_errno",               set_errno,                       METH_VARARGS},
     {"test_config",             (PyCFunction)test_config,        METH_NOARGS},
     {"test_sizeof_c_types",     (PyCFunction)test_sizeof_c_types, METH_NOARGS},
     {"test_datetime_capi",  test_datetime_capi,              METH_NOARGS},
index eb2853cedd209b34d6a0e792d21040b45bbc5e60..b341c343e1d7ecd03d3a82e955f4b2a61ecce6da 100644 (file)
@@ -941,9 +941,10 @@ cmath_polar(PyObject *self, PyObject *args)
     double r, phi;
     if (!PyArg_ParseTuple(args, "D:polar", &z))
         return NULL;
+    errno = 0;
     PyFPE_START_PROTECT("polar function", return 0)
     phi = c_atan2(z); /* should not cause any exception */
-    r = c_abs(z); /* sets errno to ERANGE on overflow;  otherwise 0 */
+    r = c_abs(z); /* sets errno to ERANGE on overflow */
     PyFPE_END_PROTECT(r)
     if (errno != 0)
         return math_error();