mirror of https://github.com/python/cpython
gh-102840: Fix confused traceback when floordiv or mod operations happens between Fraction and complex objects (GH-102842)
This commit is contained in:
parent
597fad07f7
commit
5319c66550
|
@ -579,7 +579,8 @@ class Fraction(numbers.Rational):
|
|||
f"for object of type {type(self).__name__!r}"
|
||||
)
|
||||
|
||||
def _operator_fallbacks(monomorphic_operator, fallback_operator):
|
||||
def _operator_fallbacks(monomorphic_operator, fallback_operator,
|
||||
handle_complex=True):
|
||||
"""Generates forward and reverse operators given a purely-rational
|
||||
operator and a function from the operator module.
|
||||
|
||||
|
@ -666,7 +667,7 @@ class Fraction(numbers.Rational):
|
|||
return monomorphic_operator(a, Fraction(b))
|
||||
elif isinstance(b, float):
|
||||
return fallback_operator(float(a), b)
|
||||
elif isinstance(b, complex):
|
||||
elif handle_complex and isinstance(b, complex):
|
||||
return fallback_operator(complex(a), b)
|
||||
else:
|
||||
return NotImplemented
|
||||
|
@ -679,7 +680,7 @@ class Fraction(numbers.Rational):
|
|||
return monomorphic_operator(Fraction(a), b)
|
||||
elif isinstance(a, numbers.Real):
|
||||
return fallback_operator(float(a), float(b))
|
||||
elif isinstance(a, numbers.Complex):
|
||||
elif handle_complex and isinstance(a, numbers.Complex):
|
||||
return fallback_operator(complex(a), complex(b))
|
||||
else:
|
||||
return NotImplemented
|
||||
|
@ -830,7 +831,7 @@ class Fraction(numbers.Rational):
|
|||
"""a // b"""
|
||||
return (a.numerator * b.denominator) // (a.denominator * b.numerator)
|
||||
|
||||
__floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv)
|
||||
__floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv, False)
|
||||
|
||||
def _divmod(a, b):
|
||||
"""(a // b, a % b)"""
|
||||
|
@ -838,14 +839,14 @@ class Fraction(numbers.Rational):
|
|||
div, n_mod = divmod(a.numerator * db, da * b.numerator)
|
||||
return div, Fraction(n_mod, da * db)
|
||||
|
||||
__divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod)
|
||||
__divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod, False)
|
||||
|
||||
def _mod(a, b):
|
||||
"""a % b"""
|
||||
da, db = a.denominator, b.denominator
|
||||
return Fraction((a.numerator * db) % (b.numerator * da), da * db)
|
||||
|
||||
__mod__, __rmod__ = _operator_fallbacks(_mod, operator.mod)
|
||||
__mod__, __rmod__ = _operator_fallbacks(_mod, operator.mod, False)
|
||||
|
||||
def __pow__(a, b):
|
||||
"""a ** b
|
||||
|
|
|
@ -1314,6 +1314,33 @@ class FractionTest(unittest.TestCase):
|
|||
self.assertEqual(float(format(f, fmt2)), float(rhs))
|
||||
self.assertEqual(float(format(-f, fmt2)), float('-' + rhs))
|
||||
|
||||
def test_complex_handling(self):
|
||||
# See issue gh-102840 for more details.
|
||||
|
||||
a = F(1, 2)
|
||||
b = 1j
|
||||
message = "unsupported operand type(s) for %s: '%s' and '%s'"
|
||||
# test forward
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("%", "Fraction", "complex"),
|
||||
operator.mod, a, b)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("//", "Fraction", "complex"),
|
||||
operator.floordiv, a, b)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("divmod()", "Fraction", "complex"),
|
||||
divmod, a, b)
|
||||
# test reverse
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("%", "complex", "Fraction"),
|
||||
operator.mod, b, a)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("//", "complex", "Fraction"),
|
||||
operator.floordiv, b, a)
|
||||
self.assertRaisesMessage(TypeError,
|
||||
message % ("divmod()", "complex", "Fraction"),
|
||||
divmod, b, a)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Fix confused traceback when floordiv, mod, or divmod operations happens
|
||||
between instances of :class:`fractions.Fraction` and :class:`complex`.
|
||||
|
Loading…
Reference in New Issue