summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/whatsnew/3.10.rst6
-rw-r--r--Lib/test/test_complex.py62
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-10-08-09-58-19.bpo-41974.8B-q8O.rst4
-rw-r--r--Objects/abstract.c10
-rw-r--r--Objects/bytesobject.c2
-rw-r--r--Objects/complexobject.c59
-rw-r--r--Objects/floatobject.c2
-rw-r--r--Objects/unicodeobject.c2
8 files changed, 81 insertions, 66 deletions
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 4ada4be..7401ba7 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -255,6 +255,12 @@ Deprecated
Removed
=======
+* Removed special methods ``__int__``, ``__float__``, ``__floordiv__``,
+ ``__mod__``, ``__divmod__``, ``__rfloordiv__``, ``__rmod__`` and
+ ``__rdivmod__`` of the :class:`complex` class. They always raised
+ a :exc:`TypeError`.
+ (Contributed by Serhiy Storchaka in :issue:`41974`.)
+
* The ``ParserBase.error()`` method from the private and undocumented ``_markupbase``
module has been removed. :class:`html.parser.HTMLParser` is the only subclass of
``ParserBase`` and its ``error()`` implementation has already been removed in
diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py
index d1f241f..af39ee8 100644
--- a/Lib/test/test_complex.py
+++ b/Lib/test/test_complex.py
@@ -11,6 +11,14 @@ INF = float("inf")
NAN = float("nan")
# These tests ensure that complex math does the right thing
+ZERO_DIVISION = (
+ (1+1j, 0+0j),
+ (1+1j, 0.0),
+ (1+1j, 0),
+ (1.0, 0+0j),
+ (1, 0+0j),
+)
+
class ComplexTest(unittest.TestCase):
def assertAlmostEqual(self, a, b):
@@ -99,20 +107,34 @@ class ComplexTest(unittest.TestCase):
self.check_div(complex(random(), random()),
complex(random(), random()))
- self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j)
- self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
-
self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j)
- self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j)
for denom_real, denom_imag in [(0, NAN), (NAN, 0), (NAN, NAN)]:
z = complex(0, 0) / complex(denom_real, denom_imag)
self.assertTrue(isnan(z.real))
self.assertTrue(isnan(z.imag))
+ def test_truediv_zero_division(self):
+ for a, b in ZERO_DIVISION:
+ with self.assertRaises(ZeroDivisionError):
+ a / b
+
def test_floordiv(self):
- self.assertRaises(TypeError, complex.__floordiv__, 3+0j, 1.5+0j)
- self.assertRaises(TypeError, complex.__floordiv__, 3+0j, 0+0j)
+ with self.assertRaises(TypeError):
+ (1+1j) // (1+0j)
+ with self.assertRaises(TypeError):
+ (1+1j) // 1.0
+ with self.assertRaises(TypeError):
+ (1+1j) // 1
+ with self.assertRaises(TypeError):
+ 1.0 // (1+0j)
+ with self.assertRaises(TypeError):
+ 1 // (1+0j)
+
+ def test_floordiv_zero_division(self):
+ for a, b in ZERO_DIVISION:
+ with self.assertRaises(TypeError):
+ a // b
def test_richcompare(self):
self.assertIs(complex.__eq__(1+1j, 1<<10000), False)
@@ -159,13 +181,32 @@ class ComplexTest(unittest.TestCase):
def test_mod(self):
# % is no longer supported on complex numbers
- self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
- self.assertRaises(TypeError, lambda: (3.33+4.43j) % 0)
- self.assertRaises(TypeError, (1+1j).__mod__, 4.3j)
+ with self.assertRaises(TypeError):
+ (1+1j) % (1+0j)
+ with self.assertRaises(TypeError):
+ (1+1j) % 1.0
+ with self.assertRaises(TypeError):
+ (1+1j) % 1
+ with self.assertRaises(TypeError):
+ 1.0 % (1+0j)
+ with self.assertRaises(TypeError):
+ 1 % (1+0j)
+
+ def test_mod_zero_division(self):
+ for a, b in ZERO_DIVISION:
+ with self.assertRaises(TypeError):
+ a % b
def test_divmod(self):
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
- self.assertRaises(TypeError, divmod, 1+1j, 0+0j)
+ self.assertRaises(TypeError, divmod, 1+1j, 1.0)
+ self.assertRaises(TypeError, divmod, 1+1j, 1)
+ self.assertRaises(TypeError, divmod, 1.0, 1+0j)
+ self.assertRaises(TypeError, divmod, 1, 1+0j)
+
+ def test_divmod_zero_division(self):
+ for a, b in ZERO_DIVISION:
+ self.assertRaises(TypeError, divmod, a, b)
def test_pow(self):
self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0)
@@ -174,6 +215,7 @@ class ComplexTest(unittest.TestCase):
self.assertAlmostEqual(pow(1j, -1), 1/1j)
self.assertAlmostEqual(pow(1j, 200), 1)
self.assertRaises(ValueError, pow, 1+1j, 1+1j, 1+1j)
+ self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
a = 3.33+4.43j
self.assertEqual(a ** 0j, 1)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-10-08-09-58-19.bpo-41974.8B-q8O.rst b/Misc/NEWS.d/next/Core and Builtins/2020-10-08-09-58-19.bpo-41974.8B-q8O.rst
new file mode 100644
index 0000000..034cfed
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-10-08-09-58-19.bpo-41974.8B-q8O.rst
@@ -0,0 +1,4 @@
+Removed special methods ``__int__``, ``__float__``, ``__floordiv__``,
+``__mod__``, ``__divmod__``, ``__rfloordiv__``, ``__rmod__`` and
+``__rdivmod__`` of the :class:`complex` class. They always raised
+a :exc:`TypeError`.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index c30fb4e..2ab3371 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -747,10 +747,10 @@ done:
int
PyNumber_Check(PyObject *o)
{
- return o && Py_TYPE(o)->tp_as_number &&
- (Py_TYPE(o)->tp_as_number->nb_index ||
- Py_TYPE(o)->tp_as_number->nb_int ||
- Py_TYPE(o)->tp_as_number->nb_float);
+ if (o == NULL)
+ return 0;
+ PyNumberMethods *nb = Py_TYPE(o)->tp_as_number;
+ return nb && (nb->nb_index || nb->nb_int || nb->nb_float || PyComplex_Check(o));
}
/* Binary operators */
@@ -1461,7 +1461,7 @@ PyNumber_Long(PyObject *o)
}
return type_error("int() argument must be a string, a bytes-like object "
- "or a number, not '%.200s'", o);
+ "or a real number, not '%.200s'", o);
}
PyObject *
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 836a736..990730c 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -522,7 +522,7 @@ formatlong(PyObject *v, int flags, int prec, int type)
PyErr_Format(PyExc_TypeError,
"%%%c format: %s is required, not %.200s", type,
(type == 'o' || type == 'x' || type == 'X') ? "an integer"
- : "a number",
+ : "a real number",
Py_TYPE(v)->tp_name);
return NULL;
}
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index 69f6c17b..5ab839a 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -510,23 +510,6 @@ complex_div(PyObject *v, PyObject *w)
}
static PyObject *
-complex_remainder(PyObject *v, PyObject *w)
-{
- PyErr_SetString(PyExc_TypeError,
- "can't mod complex numbers.");
- return NULL;
-}
-
-
-static PyObject *
-complex_divmod(PyObject *v, PyObject *w)
-{
- PyErr_SetString(PyExc_TypeError,
- "can't take floor or mod of complex number.");
- return NULL;
-}
-
-static PyObject *
complex_pow(PyObject *v, PyObject *w, PyObject *z)
{
Py_complex p;
@@ -563,14 +546,6 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
}
static PyObject *
-complex_int_div(PyObject *v, PyObject *w)
-{
- PyErr_SetString(PyExc_TypeError,
- "can't take floor of complex number.");
- return NULL;
-}
-
-static PyObject *
complex_neg(PyComplexObject *v)
{
Py_complex neg;
@@ -668,22 +643,6 @@ Unimplemented:
Py_RETURN_NOTIMPLEMENTED;
}
-static PyObject *
-complex_int(PyObject *v)
-{
- PyErr_SetString(PyExc_TypeError,
- "can't convert complex to int");
- return NULL;
-}
-
-static PyObject *
-complex_float(PyObject *v)
-{
- PyErr_SetString(PyExc_TypeError,
- "can't convert complex to float");
- return NULL;
-}
-
/*[clinic input]
complex.conjugate
@@ -966,7 +925,9 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
}
nbr = Py_TYPE(r)->tp_as_number;
- if (nbr == NULL || (nbr->nb_float == NULL && nbr->nb_index == NULL)) {
+ if (nbr == NULL ||
+ (nbr->nb_float == NULL && nbr->nb_index == NULL && !PyComplex_Check(r)))
+ {
PyErr_Format(PyExc_TypeError,
"complex() first argument must be a string or a number, "
"not '%.200s'",
@@ -978,7 +939,9 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
}
if (i != NULL) {
nbi = Py_TYPE(i)->tp_as_number;
- if (nbi == NULL || (nbi->nb_float == NULL && nbi->nb_index == NULL)) {
+ if (nbi == NULL ||
+ (nbi->nb_float == NULL && nbi->nb_index == NULL && !PyComplex_Check(i)))
+ {
PyErr_Format(PyExc_TypeError,
"complex() second argument must be a number, "
"not '%.200s'",
@@ -1057,8 +1020,8 @@ static PyNumberMethods complex_as_number = {
(binaryfunc)complex_add, /* nb_add */
(binaryfunc)complex_sub, /* nb_subtract */
(binaryfunc)complex_mul, /* nb_multiply */
- (binaryfunc)complex_remainder, /* nb_remainder */
- (binaryfunc)complex_divmod, /* nb_divmod */
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
(ternaryfunc)complex_pow, /* nb_power */
(unaryfunc)complex_neg, /* nb_negative */
(unaryfunc)complex_pos, /* nb_positive */
@@ -1070,9 +1033,9 @@ static PyNumberMethods complex_as_number = {
0, /* nb_and */
0, /* nb_xor */
0, /* nb_or */
- complex_int, /* nb_int */
+ 0, /* nb_int */
0, /* nb_reserved */
- complex_float, /* nb_float */
+ 0, /* nb_float */
0, /* nb_inplace_add */
0, /* nb_inplace_subtract */
0, /* nb_inplace_multiply*/
@@ -1083,7 +1046,7 @@ static PyNumberMethods complex_as_number = {
0, /* nb_inplace_and */
0, /* nb_inplace_xor */
0, /* nb_inplace_or */
- (binaryfunc)complex_int_div, /* nb_floor_divide */
+ 0, /* nb_floor_divide */
(binaryfunc)complex_div, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d0af0ea..828bde1 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -215,7 +215,7 @@ PyFloat_FromString(PyObject *v)
}
else {
PyErr_Format(PyExc_TypeError,
- "float() argument must be a string or a number, not '%.200s'",
+ "float() argument must be a string or a real number, not '%.200s'",
Py_TYPE(v)->tp_name);
return NULL;
}
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 6ae06a5..01e5c72 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -14839,7 +14839,7 @@ wrongtype:
break;
default:
PyErr_Format(PyExc_TypeError,
- "%%%c format: a number is required, "
+ "%%%c format: a real number is required, "
"not %.200s",
type, Py_TYPE(v)->tp_name);
break;