mirror of
https://github.com/python/cpython
synced 2024-10-14 10:48:24 +00:00
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 @@ def __format__(self, format_spec, /):
|
||||||
f"for object of type {type(self).__name__!r}"
|
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
|
"""Generates forward and reverse operators given a purely-rational
|
||||||
operator and a function from the operator module.
|
operator and a function from the operator module.
|
||||||
|
|
||||||
|
@ -666,7 +667,7 @@ def forward(a, b):
|
||||||
return monomorphic_operator(a, Fraction(b))
|
return monomorphic_operator(a, Fraction(b))
|
||||||
elif isinstance(b, float):
|
elif isinstance(b, float):
|
||||||
return fallback_operator(float(a), b)
|
return fallback_operator(float(a), b)
|
||||||
elif isinstance(b, complex):
|
elif handle_complex and isinstance(b, complex):
|
||||||
return fallback_operator(complex(a), b)
|
return fallback_operator(complex(a), b)
|
||||||
else:
|
else:
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
@ -679,7 +680,7 @@ def reverse(b, a):
|
||||||
return monomorphic_operator(Fraction(a), b)
|
return monomorphic_operator(Fraction(a), b)
|
||||||
elif isinstance(a, numbers.Real):
|
elif isinstance(a, numbers.Real):
|
||||||
return fallback_operator(float(a), float(b))
|
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))
|
return fallback_operator(complex(a), complex(b))
|
||||||
else:
|
else:
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
@ -830,7 +831,7 @@ def _floordiv(a, b):
|
||||||
"""a // b"""
|
"""a // b"""
|
||||||
return (a.numerator * b.denominator) // (a.denominator * b.numerator)
|
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):
|
def _divmod(a, b):
|
||||||
"""(a // b, a % b)"""
|
"""(a // b, a % b)"""
|
||||||
|
@ -838,14 +839,14 @@ def _divmod(a, b):
|
||||||
div, n_mod = divmod(a.numerator * db, da * b.numerator)
|
div, n_mod = divmod(a.numerator * db, da * b.numerator)
|
||||||
return div, Fraction(n_mod, da * db)
|
return div, Fraction(n_mod, da * db)
|
||||||
|
|
||||||
__divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod)
|
__divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod, False)
|
||||||
|
|
||||||
def _mod(a, b):
|
def _mod(a, b):
|
||||||
"""a % b"""
|
"""a % b"""
|
||||||
da, db = a.denominator, b.denominator
|
da, db = a.denominator, b.denominator
|
||||||
return Fraction((a.numerator * db) % (b.numerator * da), da * db)
|
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):
|
def __pow__(a, b):
|
||||||
"""a ** b
|
"""a ** b
|
||||||
|
|
|
@ -1314,6 +1314,33 @@ def test_float_format_testfile(self):
|
||||||
self.assertEqual(float(format(f, fmt2)), float(rhs))
|
self.assertEqual(float(format(f, fmt2)), float(rhs))
|
||||||
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__':
|
if __name__ == '__main__':
|
||||||
unittest.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 a new issue