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) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy