gh-109598: make PyComplex_RealAsDouble/ImagAsDouble use __complex__ (… · python/cpython@0f2fa61 · GitHub
Skip to content

Commit 0f2fa61

Browse files
authored
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.
1 parent ac10947 commit 0f2fa61

4 files changed

Lines changed: 73 additions & 10 deletions

File tree

Doc/c-api/complex.rst

Lines changed: 18 additions & 0 deletions

Lib/test/test_capi/test_complex.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,14 @@ def test_realasdouble(self):
7777
self.assertEqual(realasdouble(FloatSubclass(4.25)), 4.25)
7878

7979
# Test types with __complex__ dunder method
80-
# Function doesn't support classes with __complex__ dunder, see #109598
81-
self.assertRaises(TypeError, realasdouble, Complex())
80+
self.assertEqual(realasdouble(Complex()), 4.25)
81+
self.assertRaises(TypeError, realasdouble, BadComplex())
82+
with self.assertWarns(DeprecationWarning):
83+
self.assertEqual(realasdouble(BadComplex2()), 4.25)
84+
with warnings.catch_warnings():
85+
warnings.simplefilter("error", DeprecationWarning)
86+
self.assertRaises(DeprecationWarning, realasdouble, BadComplex2())
87+
self.assertRaises(RuntimeError, realasdouble, BadComplex3())
8288

8389
# Test types with __float__ dunder method
8490
self.assertEqual(realasdouble(Float()), 4.25)
@@ -104,11 +110,22 @@ def test_imagasdouble(self):
104110
self.assertEqual(imagasdouble(FloatSubclass(4.25)), 0.0)
105111

106112
# Test types with __complex__ dunder method
107-
# Function doesn't support classes with __complex__ dunder, see #109598
108-
self.assertEqual(imagasdouble(Complex()), 0.0)
113+
self.assertEqual(imagasdouble(Complex()), 0.5)
114+
self.assertRaises(TypeError, imagasdouble, BadComplex())
115+
with self.assertWarns(DeprecationWarning):
116+
self.assertEqual(imagasdouble(BadComplex2()), 0.5)
117+
with warnings.catch_warnings():
118+
warnings.simplefilter("error", DeprecationWarning)
119+
self.assertRaises(DeprecationWarning, imagasdouble, BadComplex2())
120+
self.assertRaises(RuntimeError, imagasdouble, BadComplex3())
121+
122+
# Test types with __float__ dunder method
123+
self.assertEqual(imagasdouble(Float()), 0.0)
124+
self.assertRaises(TypeError, imagasdouble, BadFloat())
125+
with self.assertWarns(DeprecationWarning):
126+
self.assertEqual(imagasdouble(BadFloat2()), 0.0)
109127

110-
# Function returns 0.0 anyway, see #109598
111-
self.assertEqual(imagasdouble(object()), 0.0)
128+
self.assertRaises(TypeError, imagasdouble, object())
112129

113130
# CRASHES imagasdouble(NULL)
114131

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:c:func:`PyComplex_RealAsDouble`/:c:func:`PyComplex_ImagAsDouble` now tries to
2+
convert an object to a :class:`complex` instance using its ``__complex__()`` method
3+
before falling back to the ``__float__()`` method. Patch by Sergey B Kirpichev.

Objects/complexobject.c

Lines changed: 29 additions & 4 deletions

0 commit comments

Comments
 (0)