diff options
author | Sergey B Kirpichev <skirpichev@gmail.com> | 2022-09-04 12:15:59 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-04 12:15:59 (GMT) |
commit | 8464b754c4168586b99e2135ccd2567e025625a9 (patch) | |
tree | d4a79892904a7d853a10ed6b6e8dae5f5f428e54 /Lib | |
parent | 9b9394df5fa808f9a125e3e472e7df4c24aea5a1 (diff) | |
download | cpython-8464b754c4168586b99e2135ccd2567e025625a9.zip cpython-8464b754c4168586b99e2135ccd2567e025625a9.tar.gz cpython-8464b754c4168586b99e2135ccd2567e025625a9.tar.bz2 |
gh-68163: Correct conversion of Rational instances to float (GH-25619)
* gh-68163: Correct conversion of Rational instances to float
Also document that numerator/denominator properties are instances of Integral.
Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/numbers.py | 2 | ||||
-rw-r--r-- | Lib/test/test_numeric_tower.py | 28 |
2 files changed, 29 insertions, 1 deletions
diff --git a/Lib/numbers.py b/Lib/numbers.py index 8e37d79..a2913e3 100644 --- a/Lib/numbers.py +++ b/Lib/numbers.py @@ -313,7 +313,7 @@ class Rational(Real): so that ratios of huge integers convert without overflowing. """ - return self.numerator / self.denominator + return int(self.numerator) / int(self.denominator) class Integral(Rational): diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py index c54dedb..9cd85e1 100644 --- a/Lib/test/test_numeric_tower.py +++ b/Lib/test/test_numeric_tower.py @@ -14,6 +14,27 @@ from fractions import Fraction as F _PyHASH_MODULUS = sys.hash_info.modulus _PyHASH_INF = sys.hash_info.inf + +class DummyIntegral(int): + """Dummy Integral class to test conversion of the Rational to float.""" + + def __mul__(self, other): + return DummyIntegral(super().__mul__(other)) + __rmul__ = __mul__ + + def __truediv__(self, other): + return NotImplemented + __rtruediv__ = __truediv__ + + @property + def numerator(self): + return DummyIntegral(self) + + @property + def denominator(self): + return DummyIntegral(1) + + class HashTest(unittest.TestCase): def check_equal_hash(self, x, y): # check both that x and y are equal and that their hashes are equal @@ -121,6 +142,13 @@ class HashTest(unittest.TestCase): self.assertEqual(hash(F(7*_PyHASH_MODULUS, 1)), 0) self.assertEqual(hash(F(-_PyHASH_MODULUS, 1)), 0) + # The numbers ABC doesn't enforce that the "true" division + # of integers produces a float. This tests that the + # Rational.__float__() method has required type conversions. + x = F(DummyIntegral(1), DummyIntegral(2), _normalize=False) + self.assertRaises(TypeError, lambda: x.numerator/x.denominator) + self.assertEqual(float(x), 0.5) + def test_hash_normalization(self): # Test for a bug encountered while changing long_hash. # |