This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: Document the meaning of the number in OverflowError
Type: enhancement Stage:
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9, Python 3.8, Python 3.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, eryksun, steven.daprano
Priority: normal Keywords:

Created on 2022-03-26 22:10 by steven.daprano, last changed 2022-04-11 14:59 by admin.

Messages (2)
msg416093 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2022-03-26 22:10
OverflowError sometimes (but not always) includes some sort of numeric code:

>>> 1e+300 ** 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

but the meaning of the 34 is not documented:

help(OverflowError) is no more insightful, saying only:

    __init__(self, /, *args, **kwargs)
        Initialize self.  See help(type(self)) for accurate signature.

Other OverflowError exceptions do not include the numeric code:

>>> math.exp(10000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: math range error

Is it an error code from C? Something to do with the number of digits of precision? An easter-egg to do with The Count Of Monte Cristo?
msg416096 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2022-03-26 22:46
The error code for `1e+300 ** 2` is ERANGE, from calling libm pow(). Since pow() returns a double, there's no way to indicate an error in the return value. Instead, C errno is set to 0 beforehand and checked for a non-zero error value after the call. If the error code isn't ERANGE, then float.__pow__() raises ValueError instead of OverflowError. Here's the relevant snippet from float_pow() in Objects/floatobject.c:

    /* Now iv and iw are finite, iw is nonzero, and iv is
     * positive and not equal to 1.0.  We finally allow
     * the platform pow to step in and do the rest.
    errno = 0;
    ix = pow(iv, iw);
    if (negate_result)
        ix = -ix;

    if (errno != 0) {
        /* We don't expect any errno value other than ERANGE, but
         * the range of libm bugs appears unbounded.
        PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError :
        return NULL;
    return PyFloat_FromDouble(ix);

Here's a direct example using ctypes:

    import ctypes
    import errno

    libm = ctypes.CDLL('', use_errno=True)
    libm.pow.argtypes = (ctypes.c_double, ctypes.c_double)
    libm.pow.restype = ctypes.c_double

    >>> errno.ERANGE
    >>> ctypes.set_errno(0)
    >>> libm.pow(1e300, 2)
    >>> ctypes.get_errno() == errno.ERANGE
Date User Action Args
2022-04-11 14:59:57adminsetgithub: 91290
2022-03-26 22:46:01eryksunsetnosy: + eryksun
messages: + msg416096
2022-03-26 22:10:10steven.dapranocreate