From 2bfdc0aaa60cb4ded592e3282e53f224a4991b77 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 1 Jun 2025 14:37:36 +0300 Subject: [PATCH 1/2] gh-133895: provide C99 Annex F return values for math functions Now this information is available as the "value" attribute of the ValueError exception object: ```pycon >>> import math >>> try: ... math.gamma(-0.0) ... except ValueError as exc: ... print(exc.value) ... -inf ``` --- Doc/library/math.rst | 5 ++++- Doc/whatsnew/3.15.rst | 8 ++++++++ Lib/test/test_math.py | 18 ++++++++---------- ...5-06-01-16-10-07.gh-issue-133895.1-SE2w.rst | 2 ++ Modules/mathmodule.c | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 11d3b756e21322..f371cd03f77856 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -822,7 +822,10 @@ Constants :exc:`ValueError` for invalid operations like ``sqrt(-1.0)`` or ``log(0.0)`` (where C99 Annex F recommends signaling invalid operation or divide-by-zero), and :exc:`OverflowError` for results that overflow (for example, - ``exp(1000.0)``). A NaN will not be returned from any of the functions + ``exp(1000.0)``). The Annex F recommended result is available as + the ``value`` property of the :exc:`ValueError` exception. + + A NaN will not be returned from any of the functions above unless one or more of the input arguments was a NaN; in that case, most functions will return a NaN, but (again following C99 Annex F) there are some exceptions to this rule, for example ``pow(float('nan'), 0.0)`` or diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 244ce327763f57..5b8610791ebcf3 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -105,6 +105,14 @@ difflib (Contributed by Jiahao Li in :gh:`134580`.) +math +---- + +* Provide C99 Annex F return values for :mod:`math`'s functions as the + "value" attribute of the ValueError exception object. + (Contributed by Sergey B Kirpichev in :gh:`133895`.) + + shelve ------ diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index d14336f8bac498..9d2fa47f2418d7 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -2069,15 +2069,14 @@ def test_testfile(self): func = getattr(math, fn) - if 'invalid' in flags or 'divide-by-zero' in flags: - er = 'ValueError' - elif 'overflow' in flags: + if 'overflow' in flags: er = 'OverflowError' try: result = func(ar) - except ValueError: - result = 'ValueError' + except ValueError as exc: + self.assertTrue('invalid' in flags or 'divide-by-zero' in flags) + result = exc.value except OverflowError: result = 'OverflowError' @@ -2110,15 +2109,14 @@ def test_mtestfile(self): for id, fn, arg, expected, flags in parse_mtestfile(math_testcases): func = getattr(math, fn) - if 'invalid' in flags or 'divide-by-zero' in flags: - expected = 'ValueError' - elif 'overflow' in flags: + if 'overflow' in flags: expected = 'OverflowError' try: got = func(arg) - except ValueError: - got = 'ValueError' + except ValueError as exc: + got = exc.value + self.assertTrue('invalid' in flags or 'divide-by-zero' in flags) except OverflowError: got = 'OverflowError' diff --git a/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst b/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst new file mode 100644 index 00000000000000..b9de9401753c5c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst @@ -0,0 +1,2 @@ +Provide C99 Annex F return values for :mod:`math`'s functions as the "value" +attribute of the ValueError exception object. Patch by Sergey B Kirpichev. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 71d9c1387f5780..eae0dc8655114e 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -840,6 +840,20 @@ math_lcm_impl(PyObject *module, PyObject * const *args, } +static void +set_exc_value(double x) +{ + PyObject *exc = PyErr_GetRaisedException(); + PyObject *value = PyFloat_FromDouble(x); + + if (value) { + PyObject_SetAttrString(exc, "value", value); + } + Py_DECREF(value); + PyErr_SetRaisedException(exc); +} + + /* Call is_error when errno != 0, and where x is the result libm * returned. is_error will usually set up an exception and return * true (1), but may return false (0) without setting up an exception. @@ -852,6 +866,7 @@ is_error(double x, int raise_edom) if (errno == EDOM) { if (raise_edom) { PyErr_SetString(PyExc_ValueError, "math domain error"); + set_exc_value(x); } } @@ -954,6 +969,7 @@ math_1(PyObject *arg, double (*func) (double), int can_overflow, else { PyErr_SetString(PyExc_ValueError, "math domain error"); } + set_exc_value(r); return NULL; } @@ -979,6 +995,7 @@ math_1a(PyObject *arg, double (*func) (double), const char *err_msg) PyMem_Free(buf); } } + set_exc_value(r); return NULL; } return PyFloat_FromDouble(r); From c1eb063213f9aeb607d95ed4b91e4ad289a61ab7 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 1 Jun 2025 21:24:55 +0300 Subject: [PATCH 2/2] 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/whatsnew/3.15.rst | 2 +- .../Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst | 4 ++-- Modules/mathmodule.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 5b8610791ebcf3..f726ae3df731fe 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -109,7 +109,7 @@ math ---- * Provide C99 Annex F return values for :mod:`math`'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/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst b/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst index b9de9401753c5c..c0657d650c6705 100644 --- a/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst +++ b/Misc/NEWS.d/next/Library/2025-06-01-16-10-07.gh-issue-133895.1-SE2w.rst @@ -1,2 +1,2 @@ -Provide C99 Annex F return values for :mod:`math`'s functions as the "value" -attribute of the ValueError exception object. Patch by Sergey B Kirpichev. +Provide C99 Annex F return values for :mod:`math`'s functions as the ``value`` +attribute of the :exc:`ValueError` exception object. Patch by Sergey B Kirpichev. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index eae0dc8655114e..8eddb6046e57b3 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -849,7 +849,7 @@ set_exc_value(double x) if (value) { PyObject_SetAttrString(exc, "value", value); } - Py_DECREF(value); + Py_XDECREF(value); PyErr_SetRaisedException(exc); }