Skip to content
Merged
158 changes: 157 additions & 1 deletion Lib/test/test_abstract_numbers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
"""Unit tests for numbers.py."""

import abc
import math
import operator
import unittest
from numbers import Complex, Real, Rational, Integral
from numbers import Complex, Real, Rational, Integral, Number


def concretize(cls):
def not_implemented(*args, **kwargs):
raise NotImplementedError()

for name in dir(cls):
try:
value = getattr(cls, name)
if value.__isabstractmethod__:
setattr(cls, name, not_implemented)
except AttributeError:
pass
abc.update_abstractmethods(cls)
return cls


class TestNumbers(unittest.TestCase):
def test_int(self):
self.assertTrue(issubclass(int, Integral))
self.assertTrue(issubclass(int, Rational))
self.assertTrue(issubclass(int, Real))
self.assertTrue(issubclass(int, Complex))
self.assertTrue(issubclass(int, Number))

self.assertEqual(7, int(7).real)
self.assertEqual(0, int(7).imag)
Expand All @@ -18,17 +38,23 @@ def test_int(self):
self.assertEqual(1, int(7).denominator)

def test_float(self):
self.assertFalse(issubclass(float, Integral))
self.assertFalse(issubclass(float, Rational))
self.assertTrue(issubclass(float, Real))
self.assertTrue(issubclass(float, Complex))
self.assertTrue(issubclass(float, Number))

self.assertEqual(7.3, float(7.3).real)
self.assertEqual(0, float(7.3).imag)
self.assertEqual(7.3, float(7.3).conjugate())
self.assertEqual(-7.3, float(-7.3).conjugate())

def test_complex(self):
self.assertFalse(issubclass(complex, Integral))
self.assertFalse(issubclass(complex, Rational))
self.assertFalse(issubclass(complex, Real))
self.assertTrue(issubclass(complex, Complex))
self.assertTrue(issubclass(complex, Number))

c1, c2 = complex(3, 2), complex(4,1)
# XXX: This is not ideal, but see the comment in math_trunc().
Expand All @@ -40,5 +66,135 @@ def test_complex(self):
self.assertRaises(TypeError, int, c1)


class TestNumbersDefaultMethods(unittest.TestCase):
def test_complex(self):
@concretize
class MyComplex(Complex):
def __init__(self, real, imag):
self.r = real
self.i = imag

@property
def real(self):
return self.r

@property
def imag(self):
return self.i

def __add__(self, other):
if isinstance(other, Complex):
return MyComplex(self.imag + other.imag,
self.real + other.real)
raise NotImplementedError

def __neg__(self):
return MyComplex(-self.real, -self.imag)

def __eq__(self, other):
if isinstance(other, Complex):
return self.imag == other.imag and self.real == other.real
if isinstance(other, Number):
return self.imag == 0 and self.real == other.real

# test __bool__
self.assertTrue(bool(MyComplex(1, 1)))
self.assertTrue(bool(MyComplex(0, 1)))
self.assertTrue(bool(MyComplex(1, 0)))
self.assertFalse(bool(MyComplex(0, 0)))

# test __sub__
self.assertEqual(MyComplex(2, 3) - complex(1, 2), MyComplex(1, 1))

# test __rsub__
self.assertEqual(complex(2, 3) - MyComplex(1, 2), MyComplex(1, 1))

def test_real(self):
@concretize
class MyReal(Real):
def __init__(self, n):
self.n = n

def __pos__(self):
return self.n

def __float__(self):
return float(self.n)

def __floordiv__(self, other):
return self.n // other

def __rfloordiv__(self, other):
return other // self.n

def __mod__(self, other):
return self.n % other

def __rmod__(self, other):
return other % self.n

# test __divmod__
self.assertEqual(divmod(MyReal(3), 2), (1, 1))

# test __rdivmod__
self.assertEqual(divmod(3, MyReal(2)), (1, 1))

# test __complex__
self.assertEqual(complex(MyReal(1)), 1+0j)

# test real
self.assertEqual(MyReal(3).real, 3)

# test imag
self.assertEqual(MyReal(3).imag, 0)

# test conjugate
self.assertEqual(MyReal(123).conjugate(), 123)


def test_rational(self):
@concretize
class MyRational(Rational):
def __init__(self, numerator, denominator):
self.n = numerator
self.d = denominator

@property
def numerator(self):
return self.n

@property
def denominator(self):
return self.d

# test__float__
self.assertEqual(float(MyRational(5, 2)), 2.5)


def test_integral(self):
@concretize
class MyIntegral(Integral):
def __init__(self, n):
self.n = n

def __pos__(self):
return self.n

def __int__(self):
return self.n

# test __index__
self.assertEqual(operator.index(MyIntegral(123)), 123)

# test __float__
self.assertEqual(float(MyIntegral(123)), 123.0)

# test numerator
self.assertEqual(MyIntegral(123).numerator, 123)

# test denominator
self.assertEqual(MyIntegral(123).denominator, 1)


if __name__ == "__main__":
unittest.main()