Skip to content

Commit 302375b

Browse files
committed
Prevent 'complex' handling in division methods.
See python/cpython#102842
1 parent 820fdc8 commit 302375b

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ ChangeLog
99
* Generally use ``.as_integer_ratio()`` in the constructor if available.
1010
https://github.com/python/cpython/pull/120271
1111

12+
* Using ``complex`` numbers in division shows better tracebacks.
13+
https://github.com/python/cpython/pull/102842
14+
1215

1316
1.18 (2024-04-03)
1417
-----------------

src/quicktions.pyx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -897,35 +897,35 @@ cdef class Fraction:
897897

898898
def __floordiv__(a, b):
899899
"""a // b"""
900-
return forward(a, b, _floordiv, _math_op_floordiv)
900+
return forward(a, b, _floordiv, _math_op_floordiv, handle_complex=False)
901901

902902
def __rfloordiv__(b, a):
903903
"""a // b"""
904-
return reverse(a, b, _floordiv, _math_op_floordiv)
904+
return reverse(a, b, _floordiv, _math_op_floordiv, handle_complex=False)
905905

906906
def __mod__(a, b):
907907
"""a % b"""
908-
return forward(a, b, _mod, _math_op_mod)
908+
return forward(a, b, _mod, _math_op_mod, handle_complex=False)
909909

910910
def __rmod__(b, a):
911911
"""a % b"""
912-
return reverse(a, b, _mod, _math_op_mod)
912+
return reverse(a, b, _mod, _math_op_mod, handle_complex=False)
913913

914914
def __divmod__(a, b):
915915
"""divmod(self, other): The pair (self // other, self % other).
916916
917917
Sometimes this can be computed faster than the pair of
918918
operations.
919919
"""
920-
return forward(a, b, _divmod, _math_op_divmod)
920+
return forward(a, b, _divmod, _math_op_divmod, handle_complex=False)
921921

922922
def __rdivmod__(b, a):
923923
"""divmod(self, other): The pair (self // other, self % other).
924924
925925
Sometimes this can be computed faster than the pair of
926926
operations.
927927
"""
928-
return reverse(a, b, _divmod, _math_op_divmod)
928+
return reverse(a, b, _divmod, _math_op_divmod, handle_complex=False)
929929

930930
def __pow__(a, b, x):
931931
"""a ** b
@@ -1516,7 +1516,7 @@ cdef:
15161516
ctypedef object (*math_func)(an, ad, bn, bd)
15171517

15181518

1519-
cdef forward(a, b, math_func monomorphic_operator, pyoperator):
1519+
cdef forward(a, b, math_func monomorphic_operator, pyoperator, handle_complex=True):
15201520
an, ad = (<Fraction>a)._numerator, (<Fraction>a)._denominator
15211521
if type(b) is Fraction:
15221522
return monomorphic_operator(an, ad, (<Fraction>b)._numerator, (<Fraction>b)._denominator)
@@ -1526,21 +1526,21 @@ cdef forward(a, b, math_func monomorphic_operator, pyoperator):
15261526
return monomorphic_operator(an, ad, b.numerator, b.denominator)
15271527
elif isinstance(b, float):
15281528
return pyoperator(_as_float(an, ad), b)
1529-
elif isinstance(b, complex):
1529+
elif handle_complex and isinstance(b, complex):
15301530
return pyoperator(complex(a), b)
15311531
else:
15321532
return NotImplemented
15331533

15341534

1535-
cdef reverse(a, b, math_func monomorphic_operator, pyoperator):
1535+
cdef reverse(a, b, math_func monomorphic_operator, pyoperator, handle_complex=True):
15361536
bn, bd = (<Fraction>b)._numerator, (<Fraction>b)._denominator
15371537
if isinstance(a, (int, long)):
15381538
return monomorphic_operator(a, 1, bn, bd)
15391539
elif isinstance(a, Rational):
15401540
return monomorphic_operator(a.numerator, a.denominator, bn, bd)
15411541
elif isinstance(a, Real):
15421542
return pyoperator(float(a), _as_float(bn, bd))
1543-
elif isinstance(a, Complex):
1543+
elif handle_complex and isinstance(a, Complex):
15441544
return pyoperator(complex(a), complex(b))
15451545
else:
15461546
return NotImplemented

src/test_fractions.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,33 @@ def test_float_format_testfile(self):
15351535
self.assertEqual(float(format(f, fmt2)), float(rhs))
15361536
self.assertEqual(float(format(-f, fmt2)), float('-' + rhs))
15371537

1538+
def test_complex_handling(self):
1539+
# See issue gh-102840 for more details.
1540+
1541+
a = F(1, 2)
1542+
b = 1j
1543+
message = "unsupported operand type(s) for %s: '%s' and '%s'"
1544+
# test forward
1545+
self.assertRaisesMessage(TypeError,
1546+
message % ("%", "quicktions.Fraction", "complex"),
1547+
operator.mod, a, b)
1548+
self.assertRaisesMessage(TypeError,
1549+
message % ("//", "quicktions.Fraction", "complex"),
1550+
operator.floordiv, a, b)
1551+
self.assertRaisesMessage(TypeError,
1552+
message % ("divmod()", "quicktions.Fraction", "complex"),
1553+
divmod, a, b)
1554+
# test reverse
1555+
self.assertRaisesMessage(TypeError,
1556+
message % ("%", "complex", "quicktions.Fraction"),
1557+
operator.mod, b, a)
1558+
self.assertRaisesMessage(TypeError,
1559+
message % ("//", "complex", "quicktions.Fraction"),
1560+
operator.floordiv, b, a)
1561+
self.assertRaisesMessage(TypeError,
1562+
message % ("divmod()", "complex", "quicktions.Fraction"),
1563+
divmod, b, a)
1564+
15381565

15391566
class QuicktionsTest(unittest.TestCase):
15401567
_pi = (

0 commit comments

Comments
 (0)