bpo-41974: Remove complex.__float__, complex.__floordiv__, etc (GH-22593)
Remove complex special methods __int__, __float__, __floordiv__, __mod__, __divmod__, __rfloordiv__, __rmod__ and __rdivmod__ which always raised a TypeError.
This commit is contained in:
parent
48f305fd12
commit
e2ec0b27c0
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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`.
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -509,23 +509,6 @@ complex_div(PyObject *v, PyObject *w)
|
|||
return PyComplex_FromCComplex(quot);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -562,14 +545,6 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
|
|||
return PyComplex_FromCComplex(p);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue