Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f3e83a4

Browse files
bpo-40801: Add float.from_number() and complex.from_number()
They are alternate constructors which only accept numbers (including objects with special methods __float__, __complex__ and __index__), but not strings.
1 parent 82e5c28 commit f3e83a4

File tree

6 files changed

+237
-86
lines changed

6 files changed

+237
-86
lines changed

Lib/test/test_complex.py

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,42 @@
99

1010
INF = float("inf")
1111
NAN = float("nan")
12+
13+
class ComplexSubclass(complex):
14+
pass
15+
16+
class OtherComplexSubclass(complex):
17+
pass
18+
19+
class MyIndex:
20+
def __init__(self, value):
21+
self.value = value
22+
23+
def __index__(self):
24+
return self.value
25+
26+
class MyInt:
27+
def __init__(self, value):
28+
self.value = value
29+
30+
def __int__(self):
31+
return self.value
32+
33+
class FloatLike:
34+
def __init__(self, value):
35+
self.value = value
36+
37+
def __float__(self):
38+
return self.value
39+
40+
class ComplexLike:
41+
def __init__(self, value):
42+
self.value = value
43+
44+
def __complex__(self):
45+
return self.value
46+
47+
1248
# These tests ensure that complex math does the right thing
1349

1450
ZERO_DIVISION = (
@@ -257,19 +293,11 @@ def test_conjugate(self):
257293
self.assertClose(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
258294

259295
def test_constructor(self):
260-
class OS:
261-
def __init__(self, value): self.value = value
262-
def __complex__(self): return self.value
263-
class NS(object):
264-
def __init__(self, value): self.value = value
265-
def __complex__(self): return self.value
266-
self.assertEqual(complex(OS(1+10j)), 1+10j)
267-
self.assertEqual(complex(NS(1+10j)), 1+10j)
268-
self.assertRaises(TypeError, complex, OS(None))
269-
self.assertRaises(TypeError, complex, NS(None))
296+
self.assertEqual(complex(ComplexLike(1+10j)), 1+10j)
297+
self.assertRaises(TypeError, complex, ComplexLike(None))
270298
self.assertRaises(TypeError, complex, {})
271-
self.assertRaises(TypeError, complex, NS(1.5))
272-
self.assertRaises(TypeError, complex, NS(1))
299+
self.assertRaises(TypeError, complex, ComplexLike(1.5))
300+
self.assertRaises(TypeError, complex, ComplexLike(1))
273301

274302
self.assertAlmostEqual(complex("1+10j"), 1+10j)
275303
self.assertAlmostEqual(complex(10), 10+0j)
@@ -316,8 +344,7 @@ def __complex__(self): return self.value
316344
self.assertAlmostEqual(complex('-1e-500j'), 0.0 - 0.0j)
317345
self.assertAlmostEqual(complex('-1e-500+1e-500j'), -0.0 + 0.0j)
318346

319-
class complex2(complex): pass
320-
self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j)
347+
self.assertAlmostEqual(complex(ComplexSubclass(1+1j)), 1+1j)
321348
self.assertAlmostEqual(complex(real=17, imag=23), 17+23j)
322349
self.assertAlmostEqual(complex(real=17+23j), 17+23j)
323350
self.assertAlmostEqual(complex(real=17+23j, imag=23), 17+46j)
@@ -399,33 +426,17 @@ def __complex__(self):
399426

400427
self.assertRaises(EvilExc, complex, evilcomplex())
401428

402-
class float2:
403-
def __init__(self, value):
404-
self.value = value
405-
def __float__(self):
406-
return self.value
407-
408-
self.assertAlmostEqual(complex(float2(42.)), 42)
409-
self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
410-
self.assertRaises(TypeError, complex, float2(None))
411-
412-
class MyIndex:
413-
def __init__(self, value):
414-
self.value = value
415-
def __index__(self):
416-
return self.value
429+
self.assertAlmostEqual(complex(FloatLike(42.)), 42)
430+
self.assertAlmostEqual(complex(real=FloatLike(17.), imag=FloatLike(23.)), 17+23j)
431+
self.assertRaises(TypeError, complex, FloatLike(None))
417432

418433
self.assertAlmostEqual(complex(MyIndex(42)), 42.0+0.0j)
419434
self.assertAlmostEqual(complex(123, MyIndex(42)), 123.0+42.0j)
420435
self.assertRaises(OverflowError, complex, MyIndex(2**2000))
421436
self.assertRaises(OverflowError, complex, 123, MyIndex(2**2000))
422437

423-
class MyInt:
424-
def __int__(self):
425-
return 42
426-
427-
self.assertRaises(TypeError, complex, MyInt())
428-
self.assertRaises(TypeError, complex, 123, MyInt())
438+
self.assertRaises(TypeError, complex, MyInt(42))
439+
self.assertRaises(TypeError, complex, 123, MyInt(42))
429440

430441
class complex0(complex):
431442
"""Test usage of __complex__() when inheriting from 'complex'"""
@@ -452,24 +463,22 @@ def __complex__(self):
452463

453464
@support.requires_IEEE_754
454465
def test_constructor_special_numbers(self):
455-
class complex2(complex):
456-
pass
457466
for x in 0.0, -0.0, INF, -INF, NAN:
458467
for y in 0.0, -0.0, INF, -INF, NAN:
459468
with self.subTest(x=x, y=y):
460469
z = complex(x, y)
461470
self.assertFloatsAreIdentical(z.real, x)
462471
self.assertFloatsAreIdentical(z.imag, y)
463-
z = complex2(x, y)
464-
self.assertIs(type(z), complex2)
472+
z = ComplexSubclass(x, y)
473+
self.assertIs(type(z), ComplexSubclass)
465474
self.assertFloatsAreIdentical(z.real, x)
466475
self.assertFloatsAreIdentical(z.imag, y)
467-
z = complex(complex2(x, y))
476+
z = complex(ComplexSubclass(x, y))
468477
self.assertIs(type(z), complex)
469478
self.assertFloatsAreIdentical(z.real, x)
470479
self.assertFloatsAreIdentical(z.imag, y)
471-
z = complex2(complex(x, y))
472-
self.assertIs(type(z), complex2)
480+
z = ComplexSubclass(complex(x, y))
481+
self.assertIs(type(z), ComplexSubclass)
473482
self.assertFloatsAreIdentical(z.real, x)
474483
self.assertFloatsAreIdentical(z.imag, y)
475484

@@ -485,6 +494,35 @@ def test_underscores(self):
485494
if not any(ch in lit for ch in 'xXoObB'):
486495
self.assertRaises(ValueError, complex, lit)
487496

497+
def test_from_number(self, cls=complex):
498+
def eq(actual, expected):
499+
self.assertEqual(actual, expected)
500+
self.assertIs(type(actual), cls)
501+
502+
eq(cls.from_number(3.14), 3.14+0j)
503+
eq(cls.from_number(3.14j), 3.14j)
504+
eq(cls.from_number(314), 314.0+0j)
505+
eq(cls.from_number(OtherComplexSubclass(3.14, 2.72)), 3.14+2.72j)
506+
eq(cls.from_number(ComplexLike(3.14+2.72j)), 3.14+2.72j)
507+
eq(cls.from_number(FloatLike(3.14)), 3.14+0j)
508+
eq(cls.from_number(MyIndex(314)), 314.0+0j)
509+
510+
cNAN = complex(NAN, NAN)
511+
x = cls.from_number(cNAN)
512+
self.assertTrue(x != x)
513+
self.assertIs(type(x), cls)
514+
if cls is complex:
515+
self.assertIs(cls.from_number(cNAN), cNAN)
516+
517+
self.assertRaises(TypeError, cls.from_number, '3.14')
518+
self.assertRaises(TypeError, cls.from_number, b'3.14')
519+
self.assertRaises(TypeError, cls.from_number, MyInt(314))
520+
self.assertRaises(TypeError, cls.from_number, {})
521+
self.assertRaises(TypeError, cls.from_number)
522+
523+
def test_from_number_subclass(self):
524+
self.test_from_number(ComplexSubclass)
525+
488526
def test_hash(self):
489527
for x in range(-30, 30):
490528
self.assertEqual(hash(x), hash(complex(x, 0)))

Lib/test/test_float.py

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,28 @@ class FloatSubclass(float):
3131
class OtherFloatSubclass(float):
3232
pass
3333

34+
class MyIndex:
35+
def __init__(self, value):
36+
self.value = value
37+
38+
def __index__(self):
39+
return self.value
40+
41+
class MyInt:
42+
def __init__(self, value):
43+
self.value = value
44+
45+
def __int__(self):
46+
return self.value
47+
48+
class FloatLike:
49+
def __init__(self, value):
50+
self.value = value
51+
52+
def __float__(self):
53+
return self.value
54+
55+
3456
class GeneralFloatCases(unittest.TestCase):
3557

3658
def test_float(self):
@@ -176,10 +198,6 @@ def test_float_with_comma(self):
176198

177199
def test_floatconversion(self):
178200
# Make sure that calls to __float__() work properly
179-
class Foo1(object):
180-
def __float__(self):
181-
return 42.
182-
183201
class Foo2(float):
184202
def __float__(self):
185203
return 42.
@@ -201,50 +219,65 @@ class FooStr(str):
201219
def __float__(self):
202220
return float(str(self)) + 1
203221

204-
self.assertEqual(float(Foo1()), 42.)
222+
self.assertEqual(float(FloatLike(42.)), 42.)
205223
self.assertEqual(float(Foo2()), 42.)
206224
with self.assertWarns(DeprecationWarning):
207225
self.assertEqual(float(Foo3(21)), 42.)
208226
self.assertRaises(TypeError, float, Foo4(42))
209227
self.assertEqual(float(FooStr('8')), 9.)
210228

211-
class Foo5:
212-
def __float__(self):
213-
return ""
214-
self.assertRaises(TypeError, time.sleep, Foo5())
229+
self.assertRaises(TypeError, time.sleep, FloatLike(""))
215230

216231
# Issue #24731
217-
class F:
218-
def __float__(self):
219-
return OtherFloatSubclass(42.)
232+
f = FloatLike(OtherFloatSubclass(42.))
220233
with self.assertWarns(DeprecationWarning):
221-
self.assertEqual(float(F()), 42.)
234+
self.assertEqual(float(f), 42.)
222235
with self.assertWarns(DeprecationWarning):
223-
self.assertIs(type(float(F())), float)
236+
self.assertIs(type(float(f)), float)
224237
with self.assertWarns(DeprecationWarning):
225-
self.assertEqual(FloatSubclass(F()), 42.)
238+
self.assertEqual(FloatSubclass(f), 42.)
226239
with self.assertWarns(DeprecationWarning):
227-
self.assertIs(type(FloatSubclass(F())), FloatSubclass)
228-
229-
class MyIndex:
230-
def __init__(self, value):
231-
self.value = value
232-
def __index__(self):
233-
return self.value
240+
self.assertIs(type(FloatSubclass(f)), FloatSubclass)
234241

235242
self.assertEqual(float(MyIndex(42)), 42.0)
236243
self.assertRaises(OverflowError, float, MyIndex(2**2000))
237-
238-
class MyInt:
239-
def __int__(self):
240-
return 42
241-
242-
self.assertRaises(TypeError, float, MyInt())
244+
self.assertRaises(TypeError, float, MyInt(42))
243245

244246
def test_keyword_args(self):
245247
with self.assertRaisesRegex(TypeError, 'keyword argument'):
246248
float(x='3.14')
247249

250+
def assertEqualAndType(self, actual, expected_value, expected_type):
251+
self.assertEqual(actual, expected_value)
252+
self.assertIs(type(actual), expected_type)
253+
254+
def test_from_number(self, cls=float):
255+
def eq(actual, expected):
256+
self.assertEqual(actual, expected)
257+
self.assertIs(type(actual), cls)
258+
259+
eq(cls.from_number(3.14), 3.14)
260+
eq(cls.from_number(314), 314.0)
261+
eq(cls.from_number(OtherFloatSubclass(3.14)), 3.14)
262+
eq(cls.from_number(FloatLike(3.14)), 3.14)
263+
eq(cls.from_number(MyIndex(314)), 314.0)
264+
265+
x = cls.from_number(NAN)
266+
self.assertTrue(x != x)
267+
self.assertIs(type(x), cls)
268+
if cls is float:
269+
self.assertIs(cls.from_number(NAN), NAN)
270+
271+
self.assertRaises(TypeError, cls.from_number, '3.14')
272+
self.assertRaises(TypeError, cls.from_number, b'3.14')
273+
self.assertRaises(TypeError, cls.from_number, 3.14j)
274+
self.assertRaises(TypeError, cls.from_number, MyInt(314))
275+
self.assertRaises(TypeError, cls.from_number, {})
276+
self.assertRaises(TypeError, cls.from_number)
277+
278+
def test_from_number_subclass(self):
279+
self.test_from_number(FloatSubclass)
280+
248281
def test_is_integer(self):
249282
self.assertFalse((1.1).is_integer())
250283
self.assertTrue((1.).is_integer())

Objects/clinic/complexobject.c.h

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/clinic/floatobject.c.h

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)