]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-102840: Fix confused traceback when floordiv or mod operations happens between... 105789/head
authorKirill Podoprigora <kirill.bast9@mail.ru>
Sat, 10 Feb 2024 14:37:19 +0000 (17:37 +0300)
committerGitHub <noreply@github.com>
Sat, 10 Feb 2024 14:37:19 +0000 (16:37 +0200)
Lib/fractions.py
Lib/test/test_fractions.py
Misc/NEWS.d/next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst [new file with mode: 0644]

index 389ab386b6a8a4d4d0c0179c3a4cca7feeaa0f39..f8c6c9c438c73799fe1a9c1c2fd7ebb19dd59718 100644 (file)
@@ -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
index af3cb214ab0ac11474dd4b709f59ed2abc3dbcb1..b45bd098a366845562923b7a8ce85ce486134040 100644 (file)
@@ -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()
diff --git a/Misc/NEWS.d/next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst b/Misc/NEWS.d/next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst
new file mode 100644 (file)
index 0000000..52668a9
--- /dev/null
@@ -0,0 +1,3 @@
+Fix confused traceback when floordiv, mod, or divmod operations happens\r
+between instances of :class:`fractions.Fraction` and :class:`complex`.\r
+\r