From 671079ef6063fe227460a6c3114625fb6282bbd0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 24 Mar 2017 21:28:43 +0200 Subject: bpo-29894: Deprecate returning an instance of complex subclass from __complex__. (#798) In a future versions of Python this can be an error. --- Lib/test/test_complex.py | 5 +++-- Lib/test/test_getargs2.py | 3 ++- Misc/NEWS | 4 ++++ Objects/complexobject.c | 29 +++++++++++++++++++---------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index cee4934..2d883c5 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -383,8 +383,9 @@ class ComplexTest(unittest.TestCase): def __complex__(self): return None - self.assertAlmostEqual(complex(complex0(1j)), 42j) - self.assertAlmostEqual(complex(complex1(1j)), 2j) + self.assertEqual(complex(complex0(1j)), 42j) + with self.assertWarns(DeprecationWarning): + self.assertEqual(complex(complex1(1j)), 2j) self.assertRaises(TypeError, complex, complex2(1j)) @support.requires_IEEE_754 diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index 8a194aa..e5d9aa6 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -408,7 +408,8 @@ class Float_TestCase(unittest.TestCase): self.assertEqual(getargs_D(ComplexSubclass(7.5+0.25j)), 7.5+0.25j) self.assertEqual(getargs_D(ComplexSubclass2(7.5+0.25j)), 7.5+0.25j) self.assertRaises(TypeError, getargs_D, BadComplex()) - self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j) + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j) self.assertEqual(getargs_D(BadComplex3(7.5+0.25j)), 7.5+0.25j) for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF): diff --git a/Misc/NEWS b/Misc/NEWS index 9b0414a..a5653c8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- +- bpo-29894: The deprecation warning is emitted if __complex__ returns an + instance of a strict subclass of complex. In a future versions of Python + this can be an error. + - bpo-29859: Show correct error messages when any of the pthread_* calls in thread_pthread.h fails. diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 773ddb3..5ebb504 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -274,7 +274,8 @@ PyComplex_ImagAsDouble(PyObject *op) } static PyObject * -try_complex_special_method(PyObject *op) { +try_complex_special_method(PyObject *op) +{ PyObject *f; _Py_IDENTIFIER(__complex__); @@ -282,9 +283,22 @@ try_complex_special_method(PyObject *op) { if (f) { PyObject *res = _PyObject_CallNoArg(f); Py_DECREF(f); - if (res != NULL && !PyComplex_Check(res)) { - PyErr_SetString(PyExc_TypeError, - "__complex__ should return a complex object"); + if (!res || PyComplex_CheckExact(res)) { + return res; + } + if (!PyComplex_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__complex__ returned non-complex (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + /* Issue #29894: warn if 'res' not of exact type complex. */ + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__complex__ returned non-complex (type %.200s). " + "The ability to return an instance of a strict subclass of complex " + "is deprecated, and may be removed in a future version of Python.", + res->ob_type->tp_name)) { Py_DECREF(res); return NULL; } @@ -1030,12 +1044,7 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) } if (tmp == NULL) return NULL; - if (!PyFloat_Check(tmp)) { - PyErr_SetString(PyExc_TypeError, - "float(r) didn't return a float"); - Py_DECREF(tmp); - return NULL; - } + assert(PyFloat_Check(tmp)); cr.real = PyFloat_AsDouble(tmp); cr.imag = 0.0; Py_DECREF(tmp); -- cgit v0.12