2001-08-08 19:27:20 -03:00
|
|
|
"""Tests for binary operators on subtypes of built-in types."""
|
|
|
|
|
|
|
|
import unittest
|
2008-05-20 18:35:26 -03:00
|
|
|
from test import support
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def gcd(a, b):
|
|
|
|
"""Greatest common divisor using Euclid's algorithm."""
|
|
|
|
while a:
|
|
|
|
a, b = b%a, a
|
|
|
|
return b
|
|
|
|
|
|
|
|
def isint(x):
|
|
|
|
"""Test whether an object is an instance of int or long."""
|
2007-01-15 12:59:06 -04:00
|
|
|
return isinstance(x, int) or isinstance(x, int)
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def isnum(x):
|
|
|
|
"""Test whether an object is an instance of a built-in numeric type."""
|
Merged revisions 83212,83829,83833,83838-83839,83878,84019,84025,84028,84032,84036 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k
........
r83212 | florent.xicluna | 2010-07-28 18:39:41 +0200 (mer., 28 juil. 2010) | 2 lines
Syntax cleanup.
........
r83829 | florent.xicluna | 2010-08-08 18:16:07 +0200 (dim., 08 août 2010) | 2 lines
Use unittest specific methods for some urllib test cases. And replace urllib2 with urllib.request in comments.
........
r83833 | florent.xicluna | 2010-08-08 18:25:27 +0200 (dim., 08 août 2010) | 2 lines
Add test case for the HTTPResponse being an iterable. Follow-up of issue #4608.
........
r83838 | florent.xicluna | 2010-08-08 20:03:44 +0200 (dim., 08 août 2010) | 2 lines
Typo.
........
r83839 | florent.xicluna | 2010-08-08 20:06:13 +0200 (dim., 08 août 2010) | 2 lines
Issue #7564: Skip test_ioctl if another process is attached to /dev/tty.
........
r83878 | florent.xicluna | 2010-08-09 10:29:08 +0200 (lun., 09 août 2010) | 1 line
Merge the 2to3 script from /sandbox/trunk/2to3/2to3, revision 72867 (latest).
........
r84019 | florent.xicluna | 2010-08-14 17:56:42 +0200 (sam., 14 août 2010) | 11 lines
Merged manually from 2.7 branch to 3.x trunk.
------------------------------------------------------------------------
r79925 | nick.coghlan | 2010-04-10 16:24:36 +0200 (sam. 10 avril 2010)
Try to turn some buildbots green by allowing test_multiprocessing to
pass even if it hits the sys.exc_clear code in the threading module, and
improve the test coverage by making the ctypes dependencies a bit more
granular (two of the cited ctypes objects don't exist on my system)
------------------------------------------------------------------------
........
r84025 | florent.xicluna | 2010-08-14 18:56:27 +0200 (sam., 14 août 2010) | 1 line
List Misc/python-config.in in Misc/README. Fix few typos.
........
r84028 | florent.xicluna | 2010-08-14 19:02:49 +0200 (sam., 14 août 2010) | 1 line
Fix order.
........
r84032 | florent.xicluna | 2010-08-14 19:15:31 +0200 (sam., 14 août 2010) | 1 line
Convert to spaces.
........
r84036 | florent.xicluna | 2010-08-14 20:03:19 +0200 (sam., 14 août 2010) | 1 line
Remove bad merge (from svnmerge r82301)
........
2010-08-14 15:24:40 -03:00
|
|
|
for T in int, float, complex:
|
2001-08-08 19:27:20 -03:00
|
|
|
if isinstance(x, T):
|
|
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def isRat(x):
|
|
|
|
"""Test wheter an object is an instance of the Rat class."""
|
|
|
|
return isinstance(x, Rat)
|
|
|
|
|
|
|
|
class Rat(object):
|
|
|
|
|
|
|
|
"""Rational number implemented as a normalized pair of longs."""
|
|
|
|
|
|
|
|
__slots__ = ['_Rat__num', '_Rat__den']
|
|
|
|
|
2007-01-15 12:59:06 -04:00
|
|
|
def __init__(self, num=0, den=1):
|
2001-08-08 19:27:20 -03:00
|
|
|
"""Constructor: Rat([num[, den]]).
|
|
|
|
|
|
|
|
The arguments must be ints or longs, and default to (0, 1)."""
|
|
|
|
if not isint(num):
|
2007-08-29 20:37:32 -03:00
|
|
|
raise TypeError("Rat numerator must be int or long (%r)" % num)
|
2001-08-08 19:27:20 -03:00
|
|
|
if not isint(den):
|
2007-08-29 20:37:32 -03:00
|
|
|
raise TypeError("Rat denominator must be int or long (%r)" % den)
|
2001-08-08 19:27:20 -03:00
|
|
|
# But the zero is always on
|
|
|
|
if den == 0:
|
2007-08-29 20:37:32 -03:00
|
|
|
raise ZeroDivisionError("zero denominator")
|
2001-08-08 19:27:20 -03:00
|
|
|
g = gcd(den, num)
|
2007-01-15 12:59:06 -04:00
|
|
|
self.__num = int(num//g)
|
|
|
|
self.__den = int(den//g)
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def _get_num(self):
|
|
|
|
"""Accessor function for read-only 'num' attribute of Rat."""
|
|
|
|
return self.__num
|
2001-09-06 18:56:42 -03:00
|
|
|
num = property(_get_num, None)
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def _get_den(self):
|
|
|
|
"""Accessor function for read-only 'den' attribute of Rat."""
|
|
|
|
return self.__den
|
2001-09-06 18:56:42 -03:00
|
|
|
den = property(_get_den, None)
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
"""Convert a Rat to an string resembling a Rat constructor call."""
|
|
|
|
return "Rat(%d, %d)" % (self.__num, self.__den)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
"""Convert a Rat to a string resembling a decimal numeric value."""
|
|
|
|
return str(float(self))
|
|
|
|
|
|
|
|
def __float__(self):
|
|
|
|
"""Convert a Rat to a float."""
|
|
|
|
return self.__num*1.0/self.__den
|
|
|
|
|
|
|
|
def __int__(self):
|
|
|
|
"""Convert a Rat to an int; self.den must be 1."""
|
|
|
|
if self.__den == 1:
|
|
|
|
try:
|
|
|
|
return int(self.__num)
|
|
|
|
except OverflowError:
|
2007-08-29 20:37:32 -03:00
|
|
|
raise OverflowError("%s too large to convert to int" %
|
2001-08-08 19:27:20 -03:00
|
|
|
repr(self))
|
2007-08-29 20:37:32 -03:00
|
|
|
raise ValueError("can't convert %s to int" % repr(self))
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def __add__(self, other):
|
|
|
|
"""Add two Rats, or a Rat and a number."""
|
|
|
|
if isint(other):
|
|
|
|
other = Rat(other)
|
|
|
|
if isRat(other):
|
|
|
|
return Rat(self.__num*other.__den + other.__num*self.__den,
|
|
|
|
self.__den*other.__den)
|
|
|
|
if isnum(other):
|
|
|
|
return float(self) + other
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
__radd__ = __add__
|
|
|
|
|
|
|
|
def __sub__(self, other):
|
|
|
|
"""Subtract two Rats, or a Rat and a number."""
|
|
|
|
if isint(other):
|
|
|
|
other = Rat(other)
|
|
|
|
if isRat(other):
|
|
|
|
return Rat(self.__num*other.__den - other.__num*self.__den,
|
|
|
|
self.__den*other.__den)
|
|
|
|
if isnum(other):
|
|
|
|
return float(self) - other
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
def __rsub__(self, other):
|
|
|
|
"""Subtract two Rats, or a Rat and a number (reversed args)."""
|
|
|
|
if isint(other):
|
|
|
|
other = Rat(other)
|
|
|
|
if isRat(other):
|
|
|
|
return Rat(other.__num*self.__den - self.__num*other.__den,
|
|
|
|
self.__den*other.__den)
|
|
|
|
if isnum(other):
|
|
|
|
return other - float(self)
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
"""Multiply two Rats, or a Rat and a number."""
|
|
|
|
if isRat(other):
|
|
|
|
return Rat(self.__num*other.__num, self.__den*other.__den)
|
|
|
|
if isint(other):
|
|
|
|
return Rat(self.__num*other, self.__den)
|
|
|
|
if isnum(other):
|
|
|
|
return float(self)*other
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
__rmul__ = __mul__
|
|
|
|
|
|
|
|
def __truediv__(self, other):
|
|
|
|
"""Divide two Rats, or a Rat and a number."""
|
|
|
|
if isRat(other):
|
|
|
|
return Rat(self.__num*other.__den, self.__den*other.__num)
|
|
|
|
if isint(other):
|
|
|
|
return Rat(self.__num, self.__den*other)
|
|
|
|
if isnum(other):
|
|
|
|
return float(self) / other
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
def __rtruediv__(self, other):
|
|
|
|
"""Divide two Rats, or a Rat and a number (reversed args)."""
|
|
|
|
if isRat(other):
|
|
|
|
return Rat(other.__num*self.__den, other.__den*self.__num)
|
|
|
|
if isint(other):
|
|
|
|
return Rat(other*self.__den, self.__num)
|
|
|
|
if isnum(other):
|
|
|
|
return other / float(self)
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
def __floordiv__(self, other):
|
|
|
|
"""Divide two Rats, returning the floored result."""
|
|
|
|
if isint(other):
|
|
|
|
other = Rat(other)
|
|
|
|
elif not isRat(other):
|
|
|
|
return NotImplemented
|
|
|
|
x = self/other
|
|
|
|
return x.__num // x.__den
|
|
|
|
|
|
|
|
def __rfloordiv__(self, other):
|
|
|
|
"""Divide two Rats, returning the floored result (reversed args)."""
|
|
|
|
x = other/self
|
|
|
|
return x.__num // x.__den
|
|
|
|
|
|
|
|
def __divmod__(self, other):
|
|
|
|
"""Divide two Rats, returning quotient and remainder."""
|
|
|
|
if isint(other):
|
|
|
|
other = Rat(other)
|
|
|
|
elif not isRat(other):
|
|
|
|
return NotImplemented
|
|
|
|
x = self//other
|
|
|
|
return (x, self - other * x)
|
|
|
|
|
|
|
|
def __rdivmod__(self, other):
|
2005-04-30 02:50:19 -03:00
|
|
|
"""Divide two Rats, returning quotient and remainder (reversed args)."""
|
2001-08-08 19:27:20 -03:00
|
|
|
if isint(other):
|
|
|
|
other = Rat(other)
|
|
|
|
elif not isRat(other):
|
|
|
|
return NotImplemented
|
|
|
|
return divmod(other, self)
|
|
|
|
|
|
|
|
def __mod__(self, other):
|
|
|
|
"""Take one Rat modulo another."""
|
|
|
|
return divmod(self, other)[1]
|
|
|
|
|
|
|
|
def __rmod__(self, other):
|
|
|
|
"""Take one Rat modulo another (reversed args)."""
|
|
|
|
return divmod(other, self)[1]
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
"""Compare two Rats for equality."""
|
|
|
|
if isint(other):
|
|
|
|
return self.__den == 1 and self.__num == other
|
|
|
|
if isRat(other):
|
|
|
|
return self.__num == other.__num and self.__den == other.__den
|
|
|
|
if isnum(other):
|
|
|
|
return float(self) == other
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
"""Compare two Rats for inequality."""
|
|
|
|
return not self == other
|
|
|
|
|
|
|
|
class RatTestCase(unittest.TestCase):
|
|
|
|
"""Unit tests for Rat class and its support utilities."""
|
|
|
|
|
|
|
|
def test_gcd(self):
|
|
|
|
self.assertEqual(gcd(10, 12), 2)
|
|
|
|
self.assertEqual(gcd(10, 15), 5)
|
|
|
|
self.assertEqual(gcd(10, 11), 1)
|
|
|
|
self.assertEqual(gcd(100, 15), 5)
|
|
|
|
self.assertEqual(gcd(-10, 2), -2)
|
|
|
|
self.assertEqual(gcd(10, -2), 2)
|
|
|
|
self.assertEqual(gcd(-10, -2), -2)
|
|
|
|
for i in range(1, 20):
|
|
|
|
for j in range(1, 20):
|
2009-08-13 05:51:18 -03:00
|
|
|
self.assertTrue(gcd(i, j) > 0)
|
|
|
|
self.assertTrue(gcd(-i, j) < 0)
|
|
|
|
self.assertTrue(gcd(i, -j) > 0)
|
|
|
|
self.assertTrue(gcd(-i, -j) < 0)
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
def test_constructor(self):
|
|
|
|
a = Rat(10, 15)
|
|
|
|
self.assertEqual(a.num, 2)
|
|
|
|
self.assertEqual(a.den, 3)
|
2007-01-15 12:59:06 -04:00
|
|
|
a = Rat(10, 15)
|
2001-08-08 19:27:20 -03:00
|
|
|
self.assertEqual(a.num, 2)
|
|
|
|
self.assertEqual(a.den, 3)
|
|
|
|
a = Rat(10, -15)
|
|
|
|
self.assertEqual(a.num, -2)
|
|
|
|
self.assertEqual(a.den, 3)
|
|
|
|
a = Rat(-10, 15)
|
|
|
|
self.assertEqual(a.num, -2)
|
|
|
|
self.assertEqual(a.den, 3)
|
|
|
|
a = Rat(-10, -15)
|
|
|
|
self.assertEqual(a.num, 2)
|
|
|
|
self.assertEqual(a.den, 3)
|
|
|
|
a = Rat(7)
|
|
|
|
self.assertEqual(a.num, 7)
|
|
|
|
self.assertEqual(a.den, 1)
|
|
|
|
try:
|
|
|
|
a = Rat(1, 0)
|
|
|
|
except ZeroDivisionError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
self.fail("Rat(1, 0) didn't raise ZeroDivisionError")
|
|
|
|
for bad in "0", 0.0, 0j, (), [], {}, None, Rat, unittest:
|
|
|
|
try:
|
|
|
|
a = Rat(bad)
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
self.fail("Rat(%r) didn't raise TypeError" % bad)
|
|
|
|
try:
|
|
|
|
a = Rat(1, bad)
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
self.fail("Rat(1, %r) didn't raise TypeError" % bad)
|
|
|
|
|
|
|
|
def test_add(self):
|
|
|
|
self.assertEqual(Rat(2, 3) + Rat(1, 3), 1)
|
|
|
|
self.assertEqual(Rat(2, 3) + 1, Rat(5, 3))
|
|
|
|
self.assertEqual(1 + Rat(2, 3), Rat(5, 3))
|
|
|
|
self.assertEqual(1.0 + Rat(1, 2), 1.5)
|
|
|
|
self.assertEqual(Rat(1, 2) + 1.0, 1.5)
|
|
|
|
|
|
|
|
def test_sub(self):
|
|
|
|
self.assertEqual(Rat(7, 2) - Rat(7, 5), Rat(21, 10))
|
|
|
|
self.assertEqual(Rat(7, 5) - 1, Rat(2, 5))
|
|
|
|
self.assertEqual(1 - Rat(3, 5), Rat(2, 5))
|
|
|
|
self.assertEqual(Rat(3, 2) - 1.0, 0.5)
|
|
|
|
self.assertEqual(1.0 - Rat(1, 2), 0.5)
|
|
|
|
|
|
|
|
def test_mul(self):
|
|
|
|
self.assertEqual(Rat(2, 3) * Rat(5, 7), Rat(10, 21))
|
|
|
|
self.assertEqual(Rat(10, 3) * 3, 10)
|
|
|
|
self.assertEqual(3 * Rat(10, 3), 10)
|
|
|
|
self.assertEqual(Rat(10, 5) * 0.5, 1.0)
|
|
|
|
self.assertEqual(0.5 * Rat(10, 5), 1.0)
|
|
|
|
|
|
|
|
def test_div(self):
|
|
|
|
self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
|
|
|
|
self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
|
|
|
|
self.assertEqual(2 / Rat(5), Rat(2, 5))
|
|
|
|
self.assertEqual(3.0 * Rat(1, 2), 1.5)
|
|
|
|
self.assertEqual(Rat(1, 2) * 3.0, 1.5)
|
|
|
|
|
|
|
|
def test_floordiv(self):
|
|
|
|
self.assertEqual(Rat(10) // Rat(4), 2)
|
|
|
|
self.assertEqual(Rat(10, 3) // Rat(4, 3), 2)
|
|
|
|
self.assertEqual(Rat(10) // 4, 2)
|
|
|
|
self.assertEqual(10 // Rat(4), 2)
|
|
|
|
|
|
|
|
def test_eq(self):
|
|
|
|
self.assertEqual(Rat(10), Rat(20, 2))
|
|
|
|
self.assertEqual(Rat(10), 10)
|
|
|
|
self.assertEqual(10, Rat(10))
|
|
|
|
self.assertEqual(Rat(10), 10.0)
|
|
|
|
self.assertEqual(10.0, Rat(10))
|
|
|
|
|
2008-06-28 20:34:00 -03:00
|
|
|
def test_true_div(self):
|
|
|
|
self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
|
|
|
|
self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
|
|
|
|
self.assertEqual(2 / Rat(5), Rat(2, 5))
|
|
|
|
self.assertEqual(3.0 * Rat(1, 2), 1.5)
|
|
|
|
self.assertEqual(Rat(1, 2) * 3.0, 1.5)
|
|
|
|
self.assertEqual(eval('1/2'), 0.5)
|
2001-08-08 19:27:20 -03:00
|
|
|
|
|
|
|
# XXX Ran out of steam; TO DO: divmod, div, future division
|
|
|
|
|
2001-09-20 18:33:42 -03:00
|
|
|
def test_main():
|
2008-05-20 18:35:26 -03:00
|
|
|
support.run_unittest(RatTestCase)
|
2001-09-20 18:33:42 -03:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
test_main()
|