mirror of https://github.com/python/cpython
bpo-44547: Make Fractions objects instances of typing.SupportsInt (GH-27851)
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
parent
51375388be
commit
d1b24775b4
|
@ -94,6 +94,10 @@ another rational number, or from a string.
|
|||
Underscores are now permitted when creating a :class:`Fraction` instance
|
||||
from a string, following :PEP:`515` rules.
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
:class:`Fraction` implements ``__int__`` now to satisfy
|
||||
``typing.SupportsInt`` instance checks.
|
||||
|
||||
.. attribute:: numerator
|
||||
|
||||
Numerator of the Fraction in lowest term.
|
||||
|
|
|
@ -193,8 +193,12 @@ Improved Modules
|
|||
fractions
|
||||
---------
|
||||
|
||||
Support :PEP:`515`-style initialization of :class:`~fractions.Fraction` from
|
||||
string. (Contributed by Sergey B Kirpichev in :issue:`44258`.)
|
||||
* Support :PEP:`515`-style initialization of :class:`~fractions.Fraction` from
|
||||
string. (Contributed by Sergey B Kirpichev in :issue:`44258`.)
|
||||
|
||||
* :class:`~fractions.Fraction` now implements an ``__int__`` method, so
|
||||
that an ``isinstance(some_fraction, typing.SupportsInt)`` check passes.
|
||||
(Contributed by Mark Dickinson in :issue:`44547`.)
|
||||
|
||||
|
||||
math
|
||||
|
|
|
@ -594,8 +594,15 @@ class Fraction(numbers.Rational):
|
|||
"""abs(a)"""
|
||||
return Fraction(abs(a._numerator), a._denominator, _normalize=False)
|
||||
|
||||
def __int__(a, _index=operator.index):
|
||||
"""int(a)"""
|
||||
if a._numerator < 0:
|
||||
return _index(-(-a._numerator // a._denominator))
|
||||
else:
|
||||
return _index(a._numerator // a._denominator)
|
||||
|
||||
def __trunc__(a):
|
||||
"""trunc(a)"""
|
||||
"""math.trunc(a)"""
|
||||
if a._numerator < 0:
|
||||
return -(-a._numerator // a._denominator)
|
||||
else:
|
||||
|
|
|
@ -8,6 +8,7 @@ import operator
|
|||
import fractions
|
||||
import functools
|
||||
import sys
|
||||
import typing
|
||||
import unittest
|
||||
from copy import copy, deepcopy
|
||||
import pickle
|
||||
|
@ -385,6 +386,47 @@ class FractionTest(unittest.TestCase):
|
|||
|
||||
self.assertTypedEquals(0.1+0j, complex(F(1,10)))
|
||||
|
||||
def testSupportsInt(self):
|
||||
# See bpo-44547.
|
||||
f = F(3, 2)
|
||||
self.assertIsInstance(f, typing.SupportsInt)
|
||||
self.assertEqual(int(f), 1)
|
||||
self.assertEqual(type(int(f)), int)
|
||||
|
||||
def testIntGuaranteesIntReturn(self):
|
||||
# Check that int(some_fraction) gives a result of exact type `int`
|
||||
# even if the fraction is using some other Integral type for its
|
||||
# numerator and denominator.
|
||||
|
||||
class CustomInt(int):
|
||||
"""
|
||||
Subclass of int with just enough machinery to convince the Fraction
|
||||
constructor to produce something with CustomInt numerator and
|
||||
denominator.
|
||||
"""
|
||||
|
||||
@property
|
||||
def numerator(self):
|
||||
return self
|
||||
|
||||
@property
|
||||
def denominator(self):
|
||||
return CustomInt(1)
|
||||
|
||||
def __mul__(self, other):
|
||||
return CustomInt(int(self) * int(other))
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return CustomInt(int(self) // int(other))
|
||||
|
||||
f = F(CustomInt(13), CustomInt(5))
|
||||
|
||||
self.assertIsInstance(f.numerator, CustomInt)
|
||||
self.assertIsInstance(f.denominator, CustomInt)
|
||||
self.assertIsInstance(f, typing.SupportsInt)
|
||||
self.assertEqual(int(f), 2)
|
||||
self.assertEqual(type(int(f)), int)
|
||||
|
||||
def testBoolGuarateesBoolReturn(self):
|
||||
# Ensure that __bool__ is used on numerator which guarantees a bool
|
||||
# return. See also bpo-39274.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Implement ``Fraction.__int__``, so that a :class:`fractions.Fraction`
|
||||
instance ``f`` passes an ``isinstance(f, typing.SupportsInt)`` check.
|
Loading…
Reference in New Issue