From a5b96d832090af8b90b0362c135e5deeb5ad9c47 Mon Sep 17 00:00:00 2001 From: Eclips4 Date: Mon, 20 Mar 2023 13:25:30 +0200 Subject: [PATCH 1/9] Fix confused traceback --- Lib/fractions.py | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index c95db0730e5b6d..00ebf3b59ad6a7 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -611,29 +611,33 @@ class doesn't subclass a concrete type, there's no """ def forward(a, b): - if isinstance(b, Fraction): - return monomorphic_operator(a, b) - elif isinstance(b, int): - return monomorphic_operator(a, Fraction(b)) - elif isinstance(b, float): - return fallback_operator(float(a), b) - elif isinstance(b, complex): - return fallback_operator(complex(a), b) - else: - return NotImplemented + try: + if isinstance(b, Fraction): + return monomorphic_operator(a, b) + elif isinstance(b, int): + return monomorphic_operator(a, Fraction(b)) + elif isinstance(b, float): + return fallback_operator(float(a), b) + elif isinstance(b, complex): + return fallback_operator(complex(a), b) + except TypeError: + pass + return NotImplemented forward.__name__ = '__' + fallback_operator.__name__ + '__' forward.__doc__ = monomorphic_operator.__doc__ def reverse(b, a): - if isinstance(a, numbers.Rational): - # Includes ints. - return monomorphic_operator(Fraction(a), b) - elif isinstance(a, numbers.Real): - return fallback_operator(float(a), float(b)) - elif isinstance(a, numbers.Complex): - return fallback_operator(complex(a), complex(b)) - else: - return NotImplemented + try: + if isinstance(a, numbers.Rational): + # Includes ints. + return monomorphic_operator(Fraction(a), b) + elif isinstance(a, numbers.Real): + return fallback_operator(float(a), float(b)) + elif isinstance(a, numbers.Complex): + return fallback_operator(complex(a), complex(b)) + except TypeError: + pass + return NotImplemented reverse.__name__ = '__r' + fallback_operator.__name__ + '__' reverse.__doc__ = monomorphic_operator.__doc__ From 31dca350c8c27ddaf71016ddb8fc869c110c69ca Mon Sep 17 00:00:00 2001 From: Eclips4 Date: Mon, 20 Mar 2023 14:31:39 +0200 Subject: [PATCH 2/9] Add tests --- Lib/test/test_fractions.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index e112f49d2e7944..8ff91d4e21b5af 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -1220,6 +1220,29 @@ def test_invalid_formats(self): with self.assertRaises(ValueError): format(fraction, spec) + def test_traceback_in_mod_and_floordiv_with_complex_objects(self): + # See issue-102840 for more details. + + a = F(1, 2) + b = 1j + mod = lambda x, y: x % y + floordiv = lambda x, y: x // y + message = "unsupported operand type(s) for %s: %s and %s" + # test forward + self.assertRaisesMessage(TypeError, + message % ("%", "'Fraction'", "'complex'"), + mod, a, b) + self.assertRaisesMessage(TypeError, + message % ("//", "'Fraction'", "'complex'"), + floordiv, a, b) + # test reverse + self.assertRaisesMessage(TypeError, + message % ("%", "'complex'", "'Fraction'"), + mod, b, a) + self.assertRaisesMessage(TypeError, + message % ("//", "'complex'", "'Fraction'"), + floordiv, b, a) + if __name__ == '__main__': unittest.main() From b03522eda8809bc5a638f6f27ecf7516b2bf6576 Mon Sep 17 00:00:00 2001 From: Eclips4 <80244920+Eclips4@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:58:45 +0300 Subject: [PATCH 3/9] Add sugestion from skirpichev Co-authored-by: Sergey B Kirpichev --- Lib/test/test_fractions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 8ff91d4e21b5af..c8a4112012241f 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -1221,7 +1221,7 @@ def test_invalid_formats(self): format(fraction, spec) def test_traceback_in_mod_and_floordiv_with_complex_objects(self): - # See issue-102840 for more details. + # See issue gh-102840 for more details. a = F(1, 2) b = 1j From 5f878ea426a464df6fb573e6921039bb0f5266bc Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Mon, 1 Jan 2024 22:42:17 +0300 Subject: [PATCH 4/9] Fix indent --- Lib/test/test_fractions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 921291e4e63a09..e2b17ef06255b1 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -1290,7 +1290,7 @@ def test_float_format_testfile(self): self.assertEqual(float(format(f, fmt2)), float(rhs)) self.assertEqual(float(format(-f, fmt2)), float('-' + rhs)) - def test_traceback_in_mod_and_floordiv_with_complex_objects(self): + def test_traceback_in_mod_and_floordiv_with_complex_objects(self): # See issue gh-102840 for more details. a = F(1, 2) From a8721d12d49f1b0905cc450b04dadceb6bf56bc9 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sat, 10 Feb 2024 14:28:24 +0200 Subject: [PATCH 5/9] Add handle_complex parameter to _operator_fallbacks. Add tests for divmod --- Lib/fractions.py | 52 ++++++++++++++++++-------------------- Lib/test/test_fractions.py | 18 ++++++++----- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index e993a516334bca..748c07074a4581 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -579,7 +579,7 @@ def __format__(self, format_spec, /): 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=False): """Generates forward and reverse operators given a purely-rational operator and a function from the operator module. @@ -660,33 +660,29 @@ class doesn't subclass a concrete type, there's no """ def forward(a, b): - try: - if isinstance(b, Fraction): - return monomorphic_operator(a, b) - elif isinstance(b, int): - return monomorphic_operator(a, Fraction(b)) - elif isinstance(b, float): - return fallback_operator(float(a), b) - elif isinstance(b, complex): - return fallback_operator(complex(a), b) - except TypeError: - pass - return NotImplemented + if isinstance(b, Fraction): + return monomorphic_operator(a, b) + elif isinstance(b, int): + return monomorphic_operator(a, Fraction(b)) + elif isinstance(b, float): + return fallback_operator(float(a), b) + elif handle_complex and isinstance(b, complex): + return fallback_operator(complex(a), b) + else: + return NotImplemented forward.__name__ = '__' + fallback_operator.__name__ + '__' forward.__doc__ = monomorphic_operator.__doc__ def reverse(b, a): - try: - if isinstance(a, numbers.Rational): - # Includes ints. - return monomorphic_operator(Fraction(a), b) - elif isinstance(a, numbers.Real): - return fallback_operator(float(a), float(b)) - elif isinstance(a, numbers.Complex): - return fallback_operator(complex(a), complex(b)) - except TypeError: - pass - return NotImplemented + if isinstance(a, numbers.Rational): + # Includes ints. + return monomorphic_operator(Fraction(a), b) + elif isinstance(a, numbers.Real): + return fallback_operator(float(a), float(b)) + elif handle_complex and isinstance(a, numbers.Complex): + return fallback_operator(complex(a), complex(b)) + else: + return NotImplemented reverse.__name__ = '__r' + fallback_operator.__name__ + '__' reverse.__doc__ = monomorphic_operator.__doc__ @@ -774,7 +770,7 @@ def _add(a, b): return Fraction._from_coprime_ints(t, s * db) return Fraction._from_coprime_ints(t // g2, s * (db // g2)) - __add__, __radd__ = _operator_fallbacks(_add, operator.add) + __add__, __radd__ = _operator_fallbacks(_add, operator.add, True) def _sub(a, b): """a - b""" @@ -790,7 +786,7 @@ def _sub(a, b): return Fraction._from_coprime_ints(t, s * db) return Fraction._from_coprime_ints(t // g2, s * (db // g2)) - __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub) + __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub, True) def _mul(a, b): """a * b""" @@ -806,7 +802,7 @@ def _mul(a, b): da //= g2 return Fraction._from_coprime_ints(na * nb, db * da) - __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul) + __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul, True) def _div(a, b): """a / b""" @@ -828,7 +824,7 @@ def _div(a, b): n, d = -n, -d return Fraction._from_coprime_ints(n, d) - __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv) + __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv, True) def _floordiv(a, b): """a // b""" diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index e2b17ef06255b1..5dfec53af85ad7 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -1290,28 +1290,32 @@ def test_float_format_testfile(self): self.assertEqual(float(format(f, fmt2)), float(rhs)) self.assertEqual(float(format(-f, fmt2)), float('-' + rhs)) - def test_traceback_in_mod_and_floordiv_with_complex_objects(self): + def test_complex_handling(self): # See issue gh-102840 for more details. a = F(1, 2) b = 1j - mod = lambda x, y: x % y - floordiv = lambda x, y: x // y message = "unsupported operand type(s) for %s: %s and %s" # test forward self.assertRaisesMessage(TypeError, message % ("%", "'Fraction'", "'complex'"), - mod, a, b) + operator.mod, a, b) self.assertRaisesMessage(TypeError, message % ("//", "'Fraction'", "'complex'"), - floordiv, a, b) + operator.floordiv, a, b) + self.assertRaisesMessage(TypeError, + message % ("divmod()", "'Fraction'", "'complex'"), + divmod, a, b) # test reverse self.assertRaisesMessage(TypeError, message % ("%", "'complex'", "'Fraction'"), - mod, b, a) + operator.mod, b, a) self.assertRaisesMessage(TypeError, message % ("//", "'complex'", "'Fraction'"), - floordiv, b, a) + operator.floordiv, b, a) + self.assertRaisesMessage(TypeError, + message % ("divmod()", "'complex'", "'Fraction'"), + divmod, b, a) if __name__ == '__main__': From 2e75353e3a2f03252c541e6fe07bab3506f4cdd7 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sat, 10 Feb 2024 15:22:33 +0200 Subject: [PATCH 6/9] Apply suggestions from Serhiy --- Lib/fractions.py | 3 ++- Lib/test/test_fractions.py | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 748c07074a4581..51db4572070df8 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -579,7 +579,8 @@ def __format__(self, format_spec, /): f"for object of type {type(self).__name__!r}" ) - def _operator_fallbacks(monomorphic_operator, fallback_operator, handle_complex=False): + def _operator_fallbacks(monomorphic_operator, fallback_operator, + handle_complex=False): """Generates forward and reverse operators given a purely-rational operator and a function from the operator module. diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 5dfec53af85ad7..56cbc9b1bade24 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -1295,26 +1295,26 @@ def test_complex_handling(self): a = F(1, 2) b = 1j - message = "unsupported operand type(s) for %s: %s and %s" + message = "unsupported operand type(s) for %s: '%s' and '%s'" # test forward self.assertRaisesMessage(TypeError, - message % ("%", "'Fraction'", "'complex'"), + message % ("%", "Fraction", "complex"), operator.mod, a, b) self.assertRaisesMessage(TypeError, - message % ("//", "'Fraction'", "'complex'"), + message % ("//", "Fraction", "complex"), operator.floordiv, a, b) self.assertRaisesMessage(TypeError, - message % ("divmod()", "'Fraction'", "'complex'"), + message % ("divmod()", "Fraction", "complex"), divmod, a, b) # test reverse self.assertRaisesMessage(TypeError, - message % ("%", "'complex'", "'Fraction'"), + message % ("%", "complex", "Fraction"), operator.mod, b, a) self.assertRaisesMessage(TypeError, - message % ("//", "'complex'", "'Fraction'"), + message % ("//", "complex", "Fraction"), operator.floordiv, b, a) self.assertRaisesMessage(TypeError, - message % ("divmod()", "'complex'", "'Fraction'"), + message % ("divmod()", "complex", "Fraction"), divmod, b, a) From 3013f909f23dd484d8ab0497af30c8440314c394 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sat, 10 Feb 2024 15:31:29 +0200 Subject: [PATCH 7/9] Add a NEWS entry --- .../next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst 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 index 00000000000000..6021f7a8c33fd4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst @@ -0,0 +1,2 @@ +Fix confused traceback when floordiv, mod, or divmod operations happens +between instances of :class:`fractions.Fraction` and :class:`complex` From fc773eb8a81bc567290dec7108ca24e600982e6a Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sat, 10 Feb 2024 15:49:49 +0200 Subject: [PATCH 8/9] Apply suggestion from Sergey --- Lib/fractions.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 51db4572070df8..430eb7b76e678a 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -580,7 +580,7 @@ def __format__(self, format_spec, /): ) def _operator_fallbacks(monomorphic_operator, fallback_operator, - handle_complex=False): + handle_complex=True): """Generates forward and reverse operators given a purely-rational operator and a function from the operator module. @@ -771,7 +771,7 @@ def _add(a, b): return Fraction._from_coprime_ints(t, s * db) return Fraction._from_coprime_ints(t // g2, s * (db // g2)) - __add__, __radd__ = _operator_fallbacks(_add, operator.add, True) + __add__, __radd__ = _operator_fallbacks(_add, operator.add) def _sub(a, b): """a - b""" @@ -787,7 +787,7 @@ def _sub(a, b): return Fraction._from_coprime_ints(t, s * db) return Fraction._from_coprime_ints(t // g2, s * (db // g2)) - __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub, True) + __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub) def _mul(a, b): """a * b""" @@ -803,7 +803,7 @@ def _mul(a, b): da //= g2 return Fraction._from_coprime_ints(na * nb, db * da) - __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul, True) + __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul) def _div(a, b): """a / b""" @@ -825,13 +825,13 @@ def _div(a, b): n, d = -n, -d return Fraction._from_coprime_ints(n, d) - __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv, True) + __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv) def _floordiv(a, b): """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)""" @@ -839,14 +839,14 @@ def _divmod(a, b): 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 From 489b95d1206a1a638b63b32ec0a6d994379263e7 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sat, 10 Feb 2024 16:15:03 +0200 Subject: [PATCH 9/9] Update Misc/NEWS.d/next/Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst Co-authored-by: Serhiy Storchaka --- .../Library/2024-02-10-15-24-20.gh-issue-102840.4mnDq1.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 6021f7a8c33fd4..52668a9424a976 100644 --- 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 @@ -1,2 +1,3 @@ Fix confused traceback when floordiv, mod, or divmod operations happens -between instances of :class:`fractions.Fraction` and :class:`complex` +between instances of :class:`fractions.Fraction` and :class:`complex`. + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy