gh-109598: make PyComplex_RealAsDouble/ImagAsDouble use __complex__ (GH-109647)

`PyComplex_RealAsDouble()`/`PyComplex_ImagAsDouble` now try to convert
an object to a `complex` instance using its `__complex__()` method
before falling back to the ``__float__()`` method.

PyComplex_ImagAsDouble() also will not silently return 0.0 for
non-complex types anymore.  Instead we try to call PyFloat_AsDouble()
and return 0.0 only if this call is successful.
This commit is contained in:
Sergey B Kirpichev 2024-01-15 18:04:17 +03:00 committed by GitHub
parent ac10947ba7
commit 0f2fa6150b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 10 deletions

View file

@ -256,26 +256,51 @@ PyComplex_FromDoubles(double real, double imag)
return PyComplex_FromCComplex(c);
}
static PyObject * try_complex_special_method(PyObject *);
double
PyComplex_RealAsDouble(PyObject *op)
{
double real = -1.0;
if (PyComplex_Check(op)) {
return ((PyComplexObject *)op)->cval.real;
real = ((PyComplexObject *)op)->cval.real;
}
else {
return PyFloat_AsDouble(op);
PyObject* newop = try_complex_special_method(op);
if (newop) {
real = ((PyComplexObject *)newop)->cval.real;
Py_DECREF(newop);
} else if (!PyErr_Occurred()) {
real = PyFloat_AsDouble(op);
}
}
return real;
}
double
PyComplex_ImagAsDouble(PyObject *op)
{
double imag = -1.0;
if (PyComplex_Check(op)) {
return ((PyComplexObject *)op)->cval.imag;
imag = ((PyComplexObject *)op)->cval.imag;
}
else {
return 0.0;
PyObject* newop = try_complex_special_method(op);
if (newop) {
imag = ((PyComplexObject *)newop)->cval.imag;
Py_DECREF(newop);
} else if (!PyErr_Occurred()) {
PyFloat_AsDouble(op);
if (!PyErr_Occurred()) {
imag = 0.0;
}
}
}
return imag;
}
static PyObject *