Skip to content

Commit ccb2434

Browse files
authored
Merge pull request RustPython#3555 from Snowapril/remove_complex_methods
Remove several special method of complex class
2 parents fae4a63 + 3c64486 commit ccb2434

File tree

2 files changed

+102
-59
lines changed

2 files changed

+102
-59
lines changed

Lib/test/test_complex.py

Lines changed: 102 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unittest
2+
import sys
23
from test import support
3-
from test.support import os_helper
44
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
55
INVALID_UNDERSCORE_LITERALS)
66

@@ -12,6 +12,14 @@
1212
NAN = float("nan")
1313
# These tests ensure that complex math does the right thing
1414

15+
ZERO_DIVISION = (
16+
(1+1j, 0+0j),
17+
(1+1j, 0.0),
18+
(1+1j, 0),
19+
(1.0, 0+0j),
20+
(1, 0+0j),
21+
)
22+
1523
class ComplexTest(unittest.TestCase):
1624

1725
def assertAlmostEqual(self, a, b):
@@ -100,20 +108,34 @@ def test_truediv(self):
100108
self.check_div(complex(random(), random()),
101109
complex(random(), random()))
102110

103-
self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j)
104-
self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
105-
106111
self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j)
107-
self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j)
108112

109113
for denom_real, denom_imag in [(0, NAN), (NAN, 0), (NAN, NAN)]:
110114
z = complex(0, 0) / complex(denom_real, denom_imag)
111115
self.assertTrue(isnan(z.real))
112116
self.assertTrue(isnan(z.imag))
113117

118+
def test_truediv_zero_division(self):
119+
for a, b in ZERO_DIVISION:
120+
with self.assertRaises(ZeroDivisionError):
121+
a / b
122+
114123
def test_floordiv(self):
115-
self.assertRaises(TypeError, complex.__floordiv__, 3+0j, 1.5+0j)
116-
self.assertRaises(TypeError, complex.__floordiv__, 3+0j, 0+0j)
124+
with self.assertRaises(TypeError):
125+
(1+1j) // (1+0j)
126+
with self.assertRaises(TypeError):
127+
(1+1j) // 1.0
128+
with self.assertRaises(TypeError):
129+
(1+1j) // 1
130+
with self.assertRaises(TypeError):
131+
1.0 // (1+0j)
132+
with self.assertRaises(TypeError):
133+
1 // (1+0j)
134+
135+
def test_floordiv_zero_division(self):
136+
for a, b in ZERO_DIVISION:
137+
with self.assertRaises(TypeError):
138+
a // b
117139

118140
def test_richcompare(self):
119141
self.assertIs(complex.__eq__(1+1j, 1<<10000), False)
@@ -162,13 +184,32 @@ def check(n, deltas, is_equal, imag = 0.0):
162184

163185
def test_mod(self):
164186
# % is no longer supported on complex numbers
165-
self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
166-
self.assertRaises(TypeError, lambda: (3.33+4.43j) % 0)
167-
self.assertRaises(TypeError, (1+1j).__mod__, 4.3j)
187+
with self.assertRaises(TypeError):
188+
(1+1j) % (1+0j)
189+
with self.assertRaises(TypeError):
190+
(1+1j) % 1.0
191+
with self.assertRaises(TypeError):
192+
(1+1j) % 1
193+
with self.assertRaises(TypeError):
194+
1.0 % (1+0j)
195+
with self.assertRaises(TypeError):
196+
1 % (1+0j)
197+
198+
def test_mod_zero_division(self):
199+
for a, b in ZERO_DIVISION:
200+
with self.assertRaises(TypeError):
201+
a % b
168202

169203
def test_divmod(self):
170204
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
171-
self.assertRaises(TypeError, divmod, 1+1j, 0+0j)
205+
self.assertRaises(TypeError, divmod, 1+1j, 1.0)
206+
self.assertRaises(TypeError, divmod, 1+1j, 1)
207+
self.assertRaises(TypeError, divmod, 1.0, 1+0j)
208+
self.assertRaises(TypeError, divmod, 1, 1+0j)
209+
210+
def test_divmod_zero_division(self):
211+
for a, b in ZERO_DIVISION:
212+
self.assertRaises(TypeError, divmod, a, b)
172213

173214
def test_pow(self):
174215
self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0)
@@ -177,6 +218,7 @@ def test_pow(self):
177218
self.assertAlmostEqual(pow(1j, -1), 1/1j)
178219
self.assertAlmostEqual(pow(1j, 200), 1)
179220
self.assertRaises(ValueError, pow, 1+1j, 1+1j, 1+1j)
221+
self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
180222

181223
a = 3.33+4.43j
182224
self.assertEqual(a ** 0j, 1)
@@ -209,6 +251,54 @@ def test_pow(self):
209251
b = 5.1+2.3j
210252
self.assertRaises(ValueError, pow, a, b, 0)
211253

254+
# Check some boundary conditions; some of these used to invoke
255+
# undefined behaviour (https://bugs.python.org/issue44698). We're
256+
# not actually checking the results of these operations, just making
257+
# sure they don't crash (for example when using clang's
258+
# UndefinedBehaviourSanitizer).
259+
values = (sys.maxsize, sys.maxsize+1, sys.maxsize-1,
260+
-sys.maxsize, -sys.maxsize+1, -sys.maxsize+1)
261+
for real in values:
262+
for imag in values:
263+
with self.subTest(real=real, imag=imag):
264+
c = complex(real, imag)
265+
try:
266+
c ** real
267+
except OverflowError:
268+
pass
269+
try:
270+
c ** c
271+
except OverflowError:
272+
pass
273+
274+
def test_pow_with_small_integer_exponents(self):
275+
# Check that small integer exponents are handled identically
276+
# regardless of their type.
277+
values = [
278+
complex(5.0, 12.0),
279+
complex(5.0e100, 12.0e100),
280+
complex(-4.0, INF),
281+
complex(INF, 0.0),
282+
]
283+
exponents = [-19, -5, -3, -2, -1, 0, 1, 2, 3, 5, 19]
284+
for value in values:
285+
for exponent in exponents:
286+
with self.subTest(value=value, exponent=exponent):
287+
try:
288+
int_pow = value**exponent
289+
except OverflowError:
290+
int_pow = "overflow"
291+
try:
292+
float_pow = value**float(exponent)
293+
except OverflowError:
294+
float_pow = "overflow"
295+
try:
296+
complex_pow = value**complex(exponent)
297+
except OverflowError:
298+
complex_pow = "overflow"
299+
self.assertEqual(str(float_pow), str(int_pow))
300+
self.assertEqual(str(complex_pow), str(int_pow))
301+
212302
def test_boolcontext(self):
213303
for i in range(100):
214304
self.assertTrue(complex(random() + 1e-6, random() + 1e-6))
@@ -509,22 +599,6 @@ def test(v, expected, test_fn=self.assertEqual):
509599
def test_neg(self):
510600
self.assertEqual(-(1+6j), -1-6j)
511601

512-
def test_file(self):
513-
a = 3.33+4.43j
514-
b = 5.1+2.3j
515-
516-
fo = None
517-
try:
518-
fo = open(os_helper.TESTFN, "w")
519-
print(a, b, file=fo)
520-
fo.close()
521-
fo = open(os_helper.TESTFN, "r")
522-
self.assertEqual(fo.read(), ("%s %s\n" % (a, b)))
523-
finally:
524-
if (fo is not None) and (not fo.closed):
525-
fo.close()
526-
os_helper.unlink(os_helper.TESTFN)
527-
528602
def test_getnewargs(self):
529603
self.assertEqual((1+2j).__getnewargs__(), (1.0, 2.0))
530604
self.assertEqual((1-2j).__getnewargs__(), (1.0, -2.0))
@@ -715,8 +789,6 @@ def test_format(self):
715789
self.assertEqual(format(complex(INF, 1), 'F'), 'INF+1.000000j')
716790
self.assertEqual(format(complex(INF, -1), 'F'), 'INF-1.000000j')
717791

718-
def test_main():
719-
support.run_unittest(ComplexTest)
720792

721793
if __name__ == "__main__":
722-
test_main()
794+
unittest.main()

vm/src/builtins/complex.rs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::{
1010
use num_complex::Complex64;
1111
use num_traits::Zero;
1212
use rustpython_common::{float_ops, hash};
13-
use std::convert::Infallible as Never;
1413

1514
/// Create a complex number from a real part and an optional imaginary part.
1615
///
@@ -272,16 +271,6 @@ impl PyComplex {
272271
self.value.conj()
273272
}
274273

275-
#[pymethod(magic)]
276-
fn float(&self, vm: &VirtualMachine) -> PyResult<Never> {
277-
Err(vm.new_type_error(String::from("Can't convert complex to float")))
278-
}
279-
280-
#[pymethod(magic)]
281-
fn int(&self, vm: &VirtualMachine) -> PyResult<Never> {
282-
Err(vm.new_type_error(String::from("Can't convert complex to int")))
283-
}
284-
285274
#[pymethod(name = "__rmul__")]
286275
#[pymethod(magic)]
287276
fn mul(
@@ -310,24 +299,6 @@ impl PyComplex {
310299
self.op(other, |a, b| inner_div(b, a, vm), vm)
311300
}
312301

313-
#[pymethod(name = "__mod__")]
314-
#[pymethod(name = "__rmod__")]
315-
fn mod_(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult<Never> {
316-
Err(vm.new_type_error("can't mod complex numbers.".to_owned()))
317-
}
318-
319-
#[pymethod(name = "__rfloordiv__")]
320-
#[pymethod(magic)]
321-
fn floordiv(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult<Never> {
322-
Err(vm.new_type_error("can't take floor of complex number.".to_owned()))
323-
}
324-
325-
#[pymethod(name = "__rdivmod__")]
326-
#[pymethod(magic)]
327-
fn divmod(&self, _other: PyObjectRef, vm: &VirtualMachine) -> PyResult<Never> {
328-
Err(vm.new_type_error("can't take floor or mod of complex number.".to_owned()))
329-
}
330-
331302
#[pymethod(magic)]
332303
fn pos(&self) -> Complex64 {
333304
self.value

0 commit comments

Comments
 (0)