Skip to content

Commit 669a400

Browse files
committed
fix: decide a decimal signal by the operands, not by the traceback
1 parent c7acb69 commit 669a400

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

‎assertpy2/_engine/_ordering.py‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,14 @@ def compare(actual: Any, expected: Any) -> int:
109109
if raised_inside(exc):
110110
raise
111111
raise UnorderableError("pair") from None
112-
except decimal.InvalidOperation as exc:
112+
except decimal.InvalidOperation:
113113
# a `Decimal` NaN signals rather than answering. Asked here rather than before the comparison:
114-
# checked first, `'a'` against a NaN read as a verdict where the same pair without one is refused
115-
if raised_inside(exc):
116-
raise
117-
return 0
114+
# checked first, `'a'` against a NaN read as a verdict where the same pair without one is refused.
115+
# The operands decide and not the traceback: measured, a signal comes from one frame under the C
116+
# accelerator and from four under `_pydecimal`, so `raised_inside` answered the interpreter build
117+
if nan_operand(actual) or nan_operand(expected):
118+
return 0
119+
raise
118120
return 0 # neither less nor greater, which is what a float NaN answers and `holds` keeps from reading equal
119121

120122

‎tests/test_numbers.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,29 @@ def test_a_decimal_nan_still_answers_rather_than_signalling():
642642
assert_that(str(caught.value)).is_equal_to("Expected <NaN> to be greater than <1>, but was not.")
643643

644644

645+
def test_a_nan_is_absorbed_however_deep_the_signal_comes_from():
646+
"""The operands decide, not the traceback: `Decimal` signals from one frame or from four.
647+
648+
Measured, the C accelerator raises at the comparison site and `_pydecimal` raises four frames in,
649+
so reading the depth answered which interpreter build was running rather than what was compared.
650+
CI found it on a build this machine does not have.
651+
"""
652+
653+
class Deeply(decimal.Decimal):
654+
def __lt__(self, other):
655+
return self._signal()
656+
657+
def __gt__(self, other):
658+
return self._signal()
659+
660+
def _signal(self):
661+
return decimal.Decimal("NaN") < decimal.Decimal(1)
662+
663+
with pytest.raises(AssertionError) as caught:
664+
assert_that(Deeply("NaN")).is_less_than(decimal.Decimal(1))
665+
assert_that(str(caught.value)).starts_with("Expected <NaN> to be less than <1>")
666+
667+
645668
def test_a_signal_raised_inside_their_own_comparison_travels_out():
646669
"""A bug in the value, not a pair without an order: answering it would send the reader elsewhere."""
647670

0 commit comments

Comments
 (0)