Skip to content

Commit 671079e

Browse files
bpo-29894: Deprecate returning an instance of complex subclass from __complex__. (#798)
In a future versions of Python this can be an error.
1 parent af7b9ec commit 671079e

File tree

4 files changed

+28
-13
lines changed

4 files changed

+28
-13
lines changed

Lib/test/test_complex.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,9 @@ class complex2(complex):
383383
def __complex__(self):
384384
return None
385385

386-
self.assertAlmostEqual(complex(complex0(1j)), 42j)
387-
self.assertAlmostEqual(complex(complex1(1j)), 2j)
386+
self.assertEqual(complex(complex0(1j)), 42j)
387+
with self.assertWarns(DeprecationWarning):
388+
self.assertEqual(complex(complex1(1j)), 2j)
388389
self.assertRaises(TypeError, complex, complex2(1j))
389390

390391
@support.requires_IEEE_754

Lib/test/test_getargs2.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ def test_D(self):
408408
self.assertEqual(getargs_D(ComplexSubclass(7.5+0.25j)), 7.5+0.25j)
409409
self.assertEqual(getargs_D(ComplexSubclass2(7.5+0.25j)), 7.5+0.25j)
410410
self.assertRaises(TypeError, getargs_D, BadComplex())
411-
self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j)
411+
with self.assertWarns(DeprecationWarning):
412+
self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j)
412413
self.assertEqual(getargs_D(BadComplex3(7.5+0.25j)), 7.5+0.25j)
413414

414415
for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 3.7.0 alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- bpo-29894: The deprecation warning is emitted if __complex__ returns an
14+
instance of a strict subclass of complex. In a future versions of Python
15+
this can be an error.
16+
1317
- bpo-29859: Show correct error messages when any of the pthread_* calls in
1418
thread_pthread.h fails.
1519

Objects/complexobject.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,31 @@ PyComplex_ImagAsDouble(PyObject *op)
274274
}
275275

276276
static PyObject *
277-
try_complex_special_method(PyObject *op) {
277+
try_complex_special_method(PyObject *op)
278+
{
278279
PyObject *f;
279280
_Py_IDENTIFIER(__complex__);
280281

281282
f = _PyObject_LookupSpecial(op, &PyId___complex__);
282283
if (f) {
283284
PyObject *res = _PyObject_CallNoArg(f);
284285
Py_DECREF(f);
285-
if (res != NULL && !PyComplex_Check(res)) {
286-
PyErr_SetString(PyExc_TypeError,
287-
"__complex__ should return a complex object");
286+
if (!res || PyComplex_CheckExact(res)) {
287+
return res;
288+
}
289+
if (!PyComplex_Check(res)) {
290+
PyErr_Format(PyExc_TypeError,
291+
"__complex__ returned non-complex (type %.200s)",
292+
res->ob_type->tp_name);
293+
Py_DECREF(res);
294+
return NULL;
295+
}
296+
/* Issue #29894: warn if 'res' not of exact type complex. */
297+
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
298+
"__complex__ returned non-complex (type %.200s). "
299+
"The ability to return an instance of a strict subclass of complex "
300+
"is deprecated, and may be removed in a future version of Python.",
301+
res->ob_type->tp_name)) {
288302
Py_DECREF(res);
289303
return NULL;
290304
}
@@ -1030,12 +1044,7 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
10301044
}
10311045
if (tmp == NULL)
10321046
return NULL;
1033-
if (!PyFloat_Check(tmp)) {
1034-
PyErr_SetString(PyExc_TypeError,
1035-
"float(r) didn't return a float");
1036-
Py_DECREF(tmp);
1037-
return NULL;
1038-
}
1047+
assert(PyFloat_Check(tmp));
10391048
cr.real = PyFloat_AsDouble(tmp);
10401049
cr.imag = 0.0;
10411050
Py_DECREF(tmp);

0 commit comments

Comments
 (0)