From a13e463d6ed9ca227857c8b2b094a877f8e88259 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 11 May 2025 13:23:01 +0300 Subject: [PATCH 01/13] gh-133895: provide C99 Annex G return values for cmath functions Now this information is available as the "value" attribute of the ValueError exception object: ```pycon >>> import cmath >>> try: ... cmath.log(complex(-0.0, 0)) ... except ValueError as exc: ... print(exc.value) ... (-inf+3.141592653589793j) ``` Also uses the AC magic for return value of the cmath.rect(). --- Doc/library/cmath.rst | 6 + Doc/whatsnew/3.15.rst | 8 + Lib/test/test_cmath.py | 9 +- ...-06-01-10-38-00.gh-issue-133895.0X7c-V.rst | 3 + Modules/clinic/cmathmodule.c.h | 162 +++++++++++++++++- Modules/cmathmodule.c | 40 +++-- 6 files changed, 210 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 26518a0458fd81..6dab35474abd99 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -38,6 +38,12 @@ the function is then applied to the result of the conversion. 1.4142135623730951j +Most functions computes and returns the C99 Annex G recommended result. If the +standard recommends raising ``FE_DIVBYZERO`` or ``FE_INVALID`` floating-point +exceptions --- the :exc:`ValueError` is raised and recommended result available +as the ``value`` attribute of the exception object. + + ==================================================== ============================================ **Conversions to and from polar coordinates** -------------------------------------------------------------------------------------------------- diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 6d1f653f086a15..cc3259f43a15c9 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -89,6 +89,14 @@ New modules Improved modules ================ +cmath +----- + +* Provide C99 Annex G return values for :mod:`cmath`'s functions as the + "value" attribute of the ValueError exception object. + (Contributed by Sergey B Kirpichev in :gh:`133895`.) + + difflib ------- diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py index a96a5780b31b6f..0f43944aab45fb 100644 --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -318,13 +318,13 @@ def polar_complex(z): if 'divide-by-zero' in flags or 'invalid' in flags: try: actual = function(arg) - except ValueError: - continue + except ValueError as exc: + actual = exc.value else: self.fail('ValueError not raised in test ' '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) - if 'overflow' in flags: + elif 'overflow' in flags: try: actual = function(arg) except OverflowError: @@ -333,7 +333,8 @@ def polar_complex(z): self.fail('OverflowError not raised in test ' '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) - actual = function(arg) + else: + actual = function(arg) if 'ignore-real-sign' in flags: actual = complex(abs(actual.real), actual.imag) diff --git a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst new file mode 100644 index 00000000000000..05a08f760579db --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst @@ -0,0 +1,3 @@ +Provide C99 Annex G return values for :mod:`cmath`'s functions as the +"value" attribute of the ValueError exception object. Patch by Sergey B +Kirpichev. diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 7f9e65baf120ea..5521714cc88f50 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -36,6 +36,15 @@ cmath_acos(PyObject *module, PyObject *arg) _return_value = cmath_acos_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -78,6 +87,15 @@ cmath_acosh(PyObject *module, PyObject *arg) _return_value = cmath_acosh_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -120,6 +138,15 @@ cmath_asin(PyObject *module, PyObject *arg) _return_value = cmath_asin_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -162,6 +189,15 @@ cmath_asinh(PyObject *module, PyObject *arg) _return_value = cmath_asinh_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -204,6 +240,15 @@ cmath_atan(PyObject *module, PyObject *arg) _return_value = cmath_atan_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -246,6 +291,15 @@ cmath_atanh(PyObject *module, PyObject *arg) _return_value = cmath_atanh_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -288,6 +342,15 @@ cmath_cos(PyObject *module, PyObject *arg) _return_value = cmath_cos_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -330,6 +393,15 @@ cmath_cosh(PyObject *module, PyObject *arg) _return_value = cmath_cosh_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -372,6 +444,15 @@ cmath_exp(PyObject *module, PyObject *arg) _return_value = cmath_exp_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -414,6 +495,15 @@ cmath_log10(PyObject *module, PyObject *arg) _return_value = cmath_log10_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -456,6 +546,15 @@ cmath_sin(PyObject *module, PyObject *arg) _return_value = cmath_sin_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -498,6 +597,15 @@ cmath_sinh(PyObject *module, PyObject *arg) _return_value = cmath_sinh_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -540,6 +648,15 @@ cmath_sqrt(PyObject *module, PyObject *arg) _return_value = cmath_sqrt_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -582,6 +699,15 @@ cmath_tan(PyObject *module, PyObject *arg) _return_value = cmath_tan_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -624,6 +750,15 @@ cmath_tanh(PyObject *module, PyObject *arg) _return_value = cmath_tanh_impl(module, z); if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -744,7 +879,7 @@ PyDoc_STRVAR(cmath_rect__doc__, #define CMATH_RECT_METHODDEF \ {"rect", _PyCFunction_CAST(cmath_rect), METH_FASTCALL, cmath_rect__doc__}, -static PyObject * +static Py_complex cmath_rect_impl(PyObject *module, double r, double phi); static PyObject * @@ -753,6 +888,7 @@ cmath_rect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; double r; double phi; + Py_complex _return_value; if (!_PyArg_CheckPositional("rect", nargs, 2, 2)) { goto exit; @@ -777,7 +913,27 @@ cmath_rect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } } - return_value = cmath_rect_impl(module, r, phi); + _return_value = cmath_rect_impl(module, r, phi); + if (errno == EDOM) { + PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); + goto exit; + } + else if (errno == ERANGE) { + PyErr_SetString(PyExc_OverflowError, "math range error"); + goto exit; + } + else { + return_value = PyComplex_FromCComplex(_return_value); + } exit: return return_value; @@ -985,4 +1141,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=631db17fb1c79d66 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=60c435806bc08ad3 input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 81cbf0d554de3c..d8944ad24b0e18 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -36,6 +36,15 @@ class Py_complex_protected_return_converter(CReturnConverter): data.return_conversion.append(""" if (errno == EDOM) { PyErr_SetString(PyExc_ValueError, "math domain error"); + + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(_return_value); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); goto exit; } else if (errno == ERANGE) { @@ -47,7 +56,7 @@ else { } """.strip()) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=8b27adb674c08321]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=2d92b1a541ef42a3]*/ #if (FLT_RADIX != 2 && FLT_RADIX != 16) #error "Modules/cmathmodule.c expects FLT_RADIX to be 2 or 16" @@ -888,8 +897,21 @@ cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj) y = c_log(y); x = _Py_c_quot(x, y); } - if (errno != 0) - return math_error(); + if (errno) { + PyObject *ret = math_error(); + + if (errno == EDOM) { + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyComplex_FromCComplex(x); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); + } + return ret; + } return PyComplex_FromCComplex(x); } @@ -972,7 +994,7 @@ cmath_polar_impl(PyObject *module, Py_complex z) static Py_complex rect_special_values[7][7]; /*[clinic input] -cmath.rect +cmath.rect -> Py_complex_protected r: double phi: double @@ -981,9 +1003,9 @@ cmath.rect Convert from polar coordinates to rectangular coordinates. [clinic start generated code]*/ -static PyObject * +static Py_complex cmath_rect_impl(PyObject *module, double r, double phi) -/*[clinic end generated code: output=385a0690925df2d5 input=24c5646d147efd69]*/ +/*[clinic end generated code: output=74ff3d17585f3388 input=50e60c5d28c834e6]*/ { Py_complex z; errno = 0; @@ -1027,11 +1049,7 @@ cmath_rect_impl(PyObject *module, double r, double phi) z.imag = r * sin(phi); errno = 0; } - - if (errno != 0) - return math_error(); - else - return PyComplex_FromCComplex(z); + return z; } /*[clinic input] From cea09b7da01460b9d2dfdf92621daddb1ae35b9c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 1 Jun 2025 21:22:17 +0300 Subject: [PATCH 02/13] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/cmath.rst | 6 +++--- Doc/whatsnew/3.15.rst | 2 +- Modules/cmathmodule.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 6dab35474abd99..b471469c357a34 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -38,10 +38,10 @@ the function is then applied to the result of the conversion. 1.4142135623730951j -Most functions computes and returns the C99 Annex G recommended result. If the +Most functions compute and return the C99 Annex G recommended result. If the standard recommends raising ``FE_DIVBYZERO`` or ``FE_INVALID`` floating-point -exceptions --- the :exc:`ValueError` is raised and recommended result available -as the ``value`` attribute of the exception object. +exceptions --- a :exc:`ValueError` is raised and the recommended result +is available as the ``value`` attribute of the exception object. ==================================================== ============================================ diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index aa417fdc176413..4337d7005c6c2d 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -93,7 +93,7 @@ cmath ----- * Provide C99 Annex G return values for :mod:`cmath`'s functions as the - "value" attribute of the ValueError exception object. + ``value`` attribute of the :exc:`ValueError` exception object. (Contributed by Sergey B Kirpichev in :gh:`133895`.) diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index d8944ad24b0e18..a8a77a4e13d4c7 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -43,7 +43,7 @@ if (errno == EDOM) { if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -907,7 +907,7 @@ cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); } return ret; From 5a8012b306fd2e337f8531c76a610c5c32144001 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 1 Jun 2025 21:23:57 +0300 Subject: [PATCH 03/13] Apply suggestions from code review --- .../next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst index 05a08f760579db..818c0089cf3fb7 100644 --- a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst +++ b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst @@ -1,3 +1,3 @@ Provide C99 Annex G return values for :mod:`cmath`'s functions as the -"value" attribute of the ValueError exception object. Patch by Sergey B +`value`` attribute of the :exc:`ValueError` exception object. Patch by Sergey B Kirpichev. From 19162e158af8c78d8a405206a1f701f750fa4ce1 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 1 Jun 2025 21:40:06 +0300 Subject: [PATCH 04/13] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst index 818c0089cf3fb7..7834db64602909 100644 --- a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst +++ b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst @@ -1,3 +1,3 @@ Provide C99 Annex G return values for :mod:`cmath`'s functions as the -`value`` attribute of the :exc:`ValueError` exception object. Patch by Sergey B +``value`` attribute of the :exc:`ValueError` exception object. Patch by Sergey B Kirpichev. From 21f27f3bebc625c6b0ad37e017fb126fb8b0bcf5 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 1 Jun 2025 22:51:33 +0300 Subject: [PATCH 05/13] +1 --- Modules/clinic/cmathmodule.c.h | 34 +++++++++++++++++----------------- Modules/cmathmodule.c | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 5521714cc88f50..699c41986c00ba 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -43,7 +43,7 @@ cmath_acos(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -94,7 +94,7 @@ cmath_acosh(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -145,7 +145,7 @@ cmath_asin(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -196,7 +196,7 @@ cmath_asinh(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -247,7 +247,7 @@ cmath_atan(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -298,7 +298,7 @@ cmath_atanh(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -349,7 +349,7 @@ cmath_cos(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -400,7 +400,7 @@ cmath_cosh(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -451,7 +451,7 @@ cmath_exp(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -502,7 +502,7 @@ cmath_log10(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -553,7 +553,7 @@ cmath_sin(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -604,7 +604,7 @@ cmath_sinh(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -655,7 +655,7 @@ cmath_sqrt(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -706,7 +706,7 @@ cmath_tan(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -757,7 +757,7 @@ cmath_tanh(PyObject *module, PyObject *arg) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -923,7 +923,7 @@ cmath_rect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); goto exit; } @@ -1141,4 +1141,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=60c435806bc08ad3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=178870f279a7be14 input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index a8a77a4e13d4c7..8f0983b0d3e3be 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -56,7 +56,7 @@ else { } """.strip()) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=2d92b1a541ef42a3]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=25da698732cbffe0]*/ #if (FLT_RADIX != 2 && FLT_RADIX != 16) #error "Modules/cmathmodule.c expects FLT_RADIX to be 2 or 16" From 0588bb35cd30db42dbf3c6f86a5973c2551c8717 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 2 Jun 2025 06:48:50 +0300 Subject: [PATCH 06/13] use PyErr_WriteUnraisable --- Modules/clinic/cmathmodule.c.h | 66 +++++++++++++++++----------------- Modules/cmathmodule.c | 10 +++--- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 699c41986c00ba..628605d69015cf 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -40,8 +40,8 @@ cmath_acos(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -91,8 +91,8 @@ cmath_acosh(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -142,8 +142,8 @@ cmath_asin(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -193,8 +193,8 @@ cmath_asinh(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -244,8 +244,8 @@ cmath_atan(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -295,8 +295,8 @@ cmath_atanh(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -346,8 +346,8 @@ cmath_cos(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -397,8 +397,8 @@ cmath_cosh(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -448,8 +448,8 @@ cmath_exp(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -499,8 +499,8 @@ cmath_log10(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -550,8 +550,8 @@ cmath_sin(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -601,8 +601,8 @@ cmath_sinh(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -652,8 +652,8 @@ cmath_sqrt(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -703,8 +703,8 @@ cmath_tan(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -754,8 +754,8 @@ cmath_tanh(PyObject *module, PyObject *arg) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -920,8 +920,8 @@ cmath_rect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -1141,4 +1141,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=178870f279a7be14 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a3adfd04b5b20bc1 input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 8f0983b0d3e3be..d8840596677698 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -40,8 +40,8 @@ if (errno == EDOM) { PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); @@ -56,7 +56,7 @@ else { } """.strip()) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=25da698732cbffe0]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=e8ab0c05f14885e9]*/ #if (FLT_RADIX != 2 && FLT_RADIX != 16) #error "Modules/cmathmodule.c expects FLT_RADIX to be 2 or 16" @@ -904,8 +904,8 @@ cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj) PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(x); - if (value) { - PyObject_SetAttrString(exc, "value", value); + if (!value || PyObject_SetAttrString(exc, "value", value)) { + PyErr_WriteUnraisable(NULL); } Py_XDECREF(value); PyErr_SetRaisedException(exc); From e326374129ae78462cb6982df87574bb7db6604d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 5 Jun 2025 06:57:20 +0300 Subject: [PATCH 07/13] address review: redo exceptions handling, support OverfowError --- Modules/clinic/cmathmodule.c.h | 530 ++++++++++++++++++++++++--------- Modules/cmathmodule.c | 100 +++++-- 2 files changed, 467 insertions(+), 163 deletions(-) diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 628605d69015cf..993ad9f6b4bf8c 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -34,23 +34,38 @@ cmath_acos(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_acos_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -85,23 +100,38 @@ cmath_acosh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_acosh_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -136,23 +166,38 @@ cmath_asin(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_asin_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -187,23 +232,38 @@ cmath_asinh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_asinh_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -238,23 +298,38 @@ cmath_atan(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_atan_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -289,23 +364,38 @@ cmath_atanh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_atanh_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -340,23 +430,38 @@ cmath_cos(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_cos_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -391,23 +496,38 @@ cmath_cosh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_cosh_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -442,23 +562,38 @@ cmath_exp(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_exp_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -493,23 +628,38 @@ cmath_log10(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_log10_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -544,23 +694,38 @@ cmath_sin(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_sin_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -595,23 +760,38 @@ cmath_sinh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_sinh_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -646,23 +826,38 @@ cmath_sqrt(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_sqrt_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -697,23 +892,38 @@ cmath_tan(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_tan_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -748,23 +958,38 @@ cmath_tanh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_tanh_impl(module, z); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -914,23 +1139,38 @@ cmath_rect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } } _return_value = cmath_rect_impl(module, r, phi); - if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); + if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } - else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; - } else { return_value = PyComplex_FromCComplex(_return_value); } @@ -1141,4 +1381,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=a3adfd04b5b20bc1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=29612ef4c43deb17 input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index d8840596677698..30d24c37e0b0c3 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -34,29 +34,44 @@ class Py_complex_protected_return_converter(CReturnConverter): def render(self, function, data): self.declare(data) data.return_conversion.append(""" -if (errno == EDOM) { - PyErr_SetString(PyExc_ValueError, "math domain error"); +if (errno) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + goto exit; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + goto exit; + } - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(_return_value); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + goto exit; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); goto exit; } -else if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, "math range error"); - goto exit; -} else { return_value = PyComplex_FromCComplex(_return_value); } """.strip()) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=e8ab0c05f14885e9]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=2d376a406b8883a3]*/ #if (FLT_RADIX != 2 && FLT_RADIX != 16) #error "Modules/cmathmodule.c expects FLT_RADIX to be 2 or 16" @@ -898,19 +913,41 @@ cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj) x = _Py_c_quot(x, y); } if (errno) { - PyObject *ret = math_error(); + if (errno == EDOM || errno == ERANGE) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + return NULL; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + return NULL; + } - if (errno == EDOM) { - PyObject *exc = PyErr_GetRaisedException(); PyObject *value = PyComplex_FromCComplex(x); if (!value || PyObject_SetAttrString(exc, "value", value)) { - PyErr_WriteUnraisable(NULL); + Py_XDECREF(value); + return NULL; } - Py_XDECREF(value); + Py_DECREF(value); PyErr_SetRaisedException(exc); } - return ret; + else { /* Unexpected math error */ + PyErr_SetFromErrno(PyExc_ValueError); + } + return NULL; } return PyComplex_FromCComplex(x); } @@ -974,8 +1011,35 @@ cmath_polar_impl(PyObject *module, Py_complex z) errno = 0; phi = atan2(z.imag, z.real); /* should not cause any exception */ r = _Py_c_abs(z); /* sets errno to ERANGE on overflow */ - if (errno != 0) - return math_error(); + if (errno != 0) { + if (errno == ERANGE) { + PyObject *exc_type = PyExc_OverflowError; + PyObject *exc_string = PyUnicode_FromString("math range error"); + + if (!exc_string) { + return NULL; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + return NULL; + } + + PyObject *value = Py_BuildValue("dd", r, phi); + + if (!value || PyObject_SetAttrString(exc, "value", value)) { + Py_XDECREF(value); + return NULL; + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); + } + else { /* Unexpected math error */ + PyErr_SetFromErrno(PyExc_ValueError); + } + return NULL; + } else return Py_BuildValue("dd", r, phi); } From 4ebe14fbb4a068af184e6ce907a3376ddcad3abd Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 5 Jun 2025 06:57:58 +0300 Subject: [PATCH 08/13] enable testing of values for OverflowError's --- Lib/test/test_cmath.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py index 0f43944aab45fb..35bac069570e36 100644 --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -327,8 +327,8 @@ def polar_complex(z): elif 'overflow' in flags: try: actual = function(arg) - except OverflowError: - continue + except OverflowError as exc: + actual = exc.value if fn != 'polar' else complex(*exc.value) else: self.fail('OverflowError not raised in test ' '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai)) From 0d7eb635e8e4adea6b586c0e5169c95ae4386e73 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 5 Jun 2025 07:34:07 +0300 Subject: [PATCH 09/13] Correct return values for cosh/sinh in case of overflows --- Modules/cmathmodule.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 30d24c37e0b0c3..39b4905a4d46d2 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -462,6 +462,9 @@ cmath_cosh_impl(PyObject *module, Py_complex z) x_minus_one = z.real - copysign(1., z.real); r.real = cos(z.imag) * cosh(x_minus_one) * Py_MATH_E; r.imag = sin(z.imag) * sinh(x_minus_one) * Py_MATH_E; + if (isnan(r.imag)) { + r.imag = copysign(0., z.real*z.imag); + } } else { r.real = cos(z.imag) * cosh(z.real); r.imag = sin(z.imag) * sinh(z.real); @@ -698,6 +701,9 @@ cmath_sinh_impl(PyObject *module, Py_complex z) x_minus_one = z.real - copysign(1., z.real); r.real = cos(z.imag) * sinh(x_minus_one) * Py_MATH_E; r.imag = sin(z.imag) * cosh(x_minus_one) * Py_MATH_E; + if (isnan(r.imag)) { + r.imag = copysign(0., z.imag); + } } else { r.real = cos(z.imag) * sinh(z.real); r.imag = sin(z.imag) * cosh(z.real); From 6035f811fc5f659fdb46e514338b463834facb2b Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 5 Jun 2025 11:44:38 +0300 Subject: [PATCH 10/13] + docs --- Doc/library/cmath.rst | 6 ++++-- Doc/whatsnew/3.15.rst | 2 +- .../Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index b471469c357a34..606f0c45406a97 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -40,8 +40,10 @@ the function is then applied to the result of the conversion. Most functions compute and return the C99 Annex G recommended result. If the standard recommends raising ``FE_DIVBYZERO`` or ``FE_INVALID`` floating-point -exceptions --- a :exc:`ValueError` is raised and the recommended result -is available as the ``value`` attribute of the exception object. +exceptions --- a :exc:`ValueError` is raised and the recommended result is +available as the ``value`` attribute of the exception object. If range error +occurs due to overflow in any component of the result --- a :exc:`OverflowError` +is raised. ==================================================== ============================================ diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index c8f7e623f6b95a..418a9672ef2662 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -93,7 +93,7 @@ cmath ----- * Provide C99 Annex G return values for :mod:`cmath`'s functions as the - ``value`` attribute of the :exc:`ValueError` exception object. + ``value`` attribute of exception objects. (Contributed by Sergey B Kirpichev in :gh:`133895`.) diff --git a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst index 7834db64602909..d645f6dfd6e6b3 100644 --- a/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst +++ b/Misc/NEWS.d/next/Library/2025-06-01-10-38-00.gh-issue-133895.0X7c-V.rst @@ -1,3 +1,2 @@ Provide C99 Annex G return values for :mod:`cmath`'s functions as the -``value`` attribute of the :exc:`ValueError` exception object. Patch by Sergey B -Kirpichev. +``value`` attribute of exception objects. Patch by Sergey B Kirpichev. From e462a535c3e965465b7a4be0272937b8cf102b9f Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 5 Jun 2025 12:49:16 +0300 Subject: [PATCH 11/13] cleanup --- Modules/clinic/cmathmodule.c.h | 562 ++++----------------------------- Modules/cmathmodule.c | 145 ++++----- 2 files changed, 119 insertions(+), 588 deletions(-) diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h index 993ad9f6b4bf8c..54b65943b484a4 100644 --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -34,41 +34,14 @@ cmath_acos(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_acos_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -100,41 +73,14 @@ cmath_acosh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_acosh_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -166,41 +112,14 @@ cmath_asin(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_asin_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -232,41 +151,14 @@ cmath_asinh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_asinh_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -298,41 +190,14 @@ cmath_atan(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_atan_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -364,41 +229,14 @@ cmath_atanh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_atanh_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -430,41 +268,14 @@ cmath_cos(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_cos_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -496,41 +307,14 @@ cmath_cosh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_cosh_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -562,41 +346,14 @@ cmath_exp(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_exp_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -628,41 +385,14 @@ cmath_log10(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_log10_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -694,41 +424,14 @@ cmath_sin(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_sin_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -760,41 +463,14 @@ cmath_sinh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_sinh_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -826,41 +502,14 @@ cmath_sqrt(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_sqrt_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -892,41 +541,14 @@ cmath_tan(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_tan_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -958,41 +580,14 @@ cmath_tanh(PyObject *module, PyObject *arg) /* modifications for z */ errno = 0; _return_value = cmath_tanh_impl(module, z); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -1139,41 +734,14 @@ cmath_rect(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } } _return_value = cmath_rect_impl(module, r, phi); + return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; - } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; + if (return_value) { + set_cmath_error(return_value); } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } - else { - return_value = PyComplex_FromCComplex(_return_value); - } exit: return return_value; @@ -1381,4 +949,4 @@ cmath_isclose(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=29612ef4c43deb17 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1f9be4ea0ab6951b input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 39b4905a4d46d2..5aad9031aef00c 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -16,6 +16,45 @@ /* For _Py_log1p with workarounds for buggy handling of zeros. */ #include "_math.h" +static void +set_cmath_error(PyObject *value) +{ + if (errno == EDOM || errno == ERANGE) { + PyObject *exc_type; + PyObject *exc_string; + + if (errno == EDOM) { + exc_type = PyExc_ValueError; + exc_string = PyUnicode_FromString("math domain error"); + } + else { + exc_type = PyExc_OverflowError; + exc_string = PyUnicode_FromString("math range error"); + } + if (!exc_string) { + Py_DECREF(value); + return; + } + PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); + + Py_DECREF(exc_string); + if (!exc) { + Py_DECREF(value); + return; + } + if (PyObject_SetAttrString(exc, "value", value)) { + Py_DECREF(value); + return; + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); + } + else { /* Unexpected math error */ + Py_DECREF(value); + PyErr_SetFromErrno(PyExc_ValueError); + } +} + #include "clinic/cmathmodule.c.h" /*[clinic input] module cmath @@ -34,44 +73,17 @@ class Py_complex_protected_return_converter(CReturnConverter): def render(self, function, data): self.declare(data) data.return_conversion.append(""" +return_value = PyComplex_FromCComplex(_return_value); if (errno) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - goto exit; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - goto exit; + if (return_value) { + set_cmath_error(return_value); } - - PyObject *value = PyComplex_FromCComplex(_return_value); - - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - goto exit; - } - Py_DECREF(value); - PyErr_SetRaisedException(exc); + return_value = NULL; goto exit; } -else { - return_value = PyComplex_FromCComplex(_return_value); -} """.strip()) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=2d376a406b8883a3]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=fff1087cce9b4c85]*/ #if (FLT_RADIX != 2 && FLT_RADIX != 16) #error "Modules/cmathmodule.c expects FLT_RADIX to be 2 or 16" @@ -918,44 +930,16 @@ cmath_log_impl(PyObject *module, Py_complex x, PyObject *y_obj) y = c_log(y); x = _Py_c_quot(x, y); } - if (errno) { - if (errno == EDOM || errno == ERANGE) { - PyObject *exc_type; - PyObject *exc_string; - - if (errno == EDOM) { - exc_type = PyExc_ValueError; - exc_string = PyUnicode_FromString("math domain error"); - } - else { - exc_type = PyExc_OverflowError; - exc_string = PyUnicode_FromString("math range error"); - } - if (!exc_string) { - return NULL; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - return NULL; - } - PyObject *value = PyComplex_FromCComplex(x); + PyObject *res = PyComplex_FromCComplex(x); - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - return NULL; - } - Py_DECREF(value); - PyErr_SetRaisedException(exc); - } - else { /* Unexpected math error */ - PyErr_SetFromErrno(PyExc_ValueError); + if (errno) { + if (res) { + set_cmath_error(res); } return NULL; } - return PyComplex_FromCComplex(x); + return res; } @@ -1017,37 +1001,16 @@ cmath_polar_impl(PyObject *module, Py_complex z) errno = 0; phi = atan2(z.imag, z.real); /* should not cause any exception */ r = _Py_c_abs(z); /* sets errno to ERANGE on overflow */ - if (errno != 0) { - if (errno == ERANGE) { - PyObject *exc_type = PyExc_OverflowError; - PyObject *exc_string = PyUnicode_FromString("math range error"); - - if (!exc_string) { - return NULL; - } - PyObject *exc = PyObject_CallOneArg(exc_type, exc_string); - - Py_DECREF(exc_string); - if (!exc) { - return NULL; - } - PyObject *value = Py_BuildValue("dd", r, phi); + PyObject *res = Py_BuildValue("dd", r, phi); - if (!value || PyObject_SetAttrString(exc, "value", value)) { - Py_XDECREF(value); - return NULL; - } - Py_DECREF(value); - PyErr_SetRaisedException(exc); - } - else { /* Unexpected math error */ - PyErr_SetFromErrno(PyExc_ValueError); + if (errno != 0) { + if (res) { + set_cmath_error(res); } return NULL; } - else - return Py_BuildValue("dd", r, phi); + return res; } /* From ecbb8fdb29708927128077e742a62093176180d8 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 8 Jun 2025 15:44:49 +0300 Subject: [PATCH 12/13] Update Doc/library/cmath.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/cmath.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 606f0c45406a97..0b1c6a866829f2 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -38,12 +38,12 @@ the function is then applied to the result of the conversion. 1.4142135623730951j -Most functions compute and return the C99 Annex G recommended result. If the -standard recommends raising ``FE_DIVBYZERO`` or ``FE_INVALID`` floating-point -exceptions --- a :exc:`ValueError` is raised and the recommended result is -available as the ``value`` attribute of the exception object. If range error -occurs due to overflow in any component of the result --- a :exc:`OverflowError` -is raised. +Most functions compute and return the C99 Annex G recommended result. +If the standard recommends raising ``FE_DIVBYZERO`` or ``FE_INVALID`` +floating-point exceptions, a :exc:`ValueError` is raised and the recommended +result is available as the ``value`` attribute of the exception object. +If a range error occurs due to an overflow in any component of the result, +an :exc:`OverflowError` is raised. ==================================================== ============================================ From 881989eda8a52747da78fffc79b7da394aa2c428 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 8 Jun 2025 15:57:53 +0300 Subject: [PATCH 13/13] address review: add comment --- Modules/cmathmodule.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 5aad9031aef00c..f86017b18cbec3 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -16,6 +16,9 @@ /* For _Py_log1p with workarounds for buggy handling of zeros. */ #include "_math.h" +/* A little helper to set 'value' attribute on exceptions. + Warning: steal a reference to value. */ + static void set_cmath_error(PyObject *value) {