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

@ -77,8 +77,14 @@ class CAPIComplexTest(unittest.TestCase):
self.assertEqual(realasdouble(FloatSubclass(4.25)), 4.25)
# Test types with __complex__ dunder method
# Function doesn't support classes with __complex__ dunder, see #109598
self.assertRaises(TypeError, realasdouble, Complex())
self.assertEqual(realasdouble(Complex()), 4.25)
self.assertRaises(TypeError, realasdouble, BadComplex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(realasdouble(BadComplex2()), 4.25)
with warnings.catch_warnings():
warnings.simplefilter("error", DeprecationWarning)
self.assertRaises(DeprecationWarning, realasdouble, BadComplex2())
self.assertRaises(RuntimeError, realasdouble, BadComplex3())
# Test types with __float__ dunder method
self.assertEqual(realasdouble(Float()), 4.25)
@ -104,11 +110,22 @@ class CAPIComplexTest(unittest.TestCase):
self.assertEqual(imagasdouble(FloatSubclass(4.25)), 0.0)
# Test types with __complex__ dunder method
# Function doesn't support classes with __complex__ dunder, see #109598
self.assertEqual(imagasdouble(Complex()), 0.0)
self.assertEqual(imagasdouble(Complex()), 0.5)
self.assertRaises(TypeError, imagasdouble, BadComplex())
with self.assertWarns(DeprecationWarning):
self.assertEqual(imagasdouble(BadComplex2()), 0.5)
with warnings.catch_warnings():
warnings.simplefilter("error", DeprecationWarning)
self.assertRaises(DeprecationWarning, imagasdouble, BadComplex2())
self.assertRaises(RuntimeError, imagasdouble, BadComplex3())
# Function returns 0.0 anyway, see #109598
self.assertEqual(imagasdouble(object()), 0.0)
# Test types with __float__ dunder method
self.assertEqual(imagasdouble(Float()), 0.0)
self.assertRaises(TypeError, imagasdouble, BadFloat())
with self.assertWarns(DeprecationWarning):
self.assertEqual(imagasdouble(BadFloat2()), 0.0)
self.assertRaises(TypeError, imagasdouble, object())
# CRASHES imagasdouble(NULL)