diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index 4174a55b5..a56eb05dd 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -455,8 +455,21 @@ class ApproxScalar(ApproxBase): if math.isinf(abs(self.expected)): return False - # Return true if the two numbers are within the tolerance. - result: bool = abs(self.expected - actual) <= self.tolerance + # Return true if the two numbers are within the tolerance. In order to + # be flexible about which types are supported, try making the + # comparison in two ways. The first requires that the actual value can + # be subtracted from the expected value. This is necessary for complex + # numbers, which don't implement comparison operators. The second + # requires that the actual and expected values can be compared. This + # is necessary for comparing Decimals with floats, see #8495. + result: bool + try: + result = abs(self.expected - actual) <= self.tolerance + except TypeError: + low = self.expected - self.tolerance + high = self.expected + self.tolerance + result = low <= actual <= high + return result # Ignore type because of https://github.com/python/mypy/issues/4266. diff --git a/testing/python/approx.py b/testing/python/approx.py index 69743cdbe..59bf9ad54 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -556,15 +556,20 @@ class TestApprox: def test_decimal(self): within_1e6 = [ - (Decimal("1.000001"), Decimal("1.0")), - (Decimal("-1.000001"), Decimal("-1.0")), + (Decimal("1.0000005"), Decimal("1.0"), Decimal), + (Decimal("-1.0000005"), Decimal("-1.0"), Decimal), + (Decimal("1.0000005"), 1.0, float), + (Decimal("-1.0000005"), -1.0, float), ] - for a, x in within_1e6: + for a, x, T in within_1e6: + # Need to test the default values here, because some code is needed + # to account for the fact that you can't add floats to decimals. assert a == approx(x) - assert a == approx(x, rel=Decimal("5e-6"), abs=0) - assert a != approx(x, rel=Decimal("5e-7"), abs=0) - assert approx(x, rel=Decimal("5e-6"), abs=0) == a - assert approx(x, rel=Decimal("5e-7"), abs=0) != a + + assert a == approx(x, rel=T("1e-6"), abs=0) + assert a != approx(x, rel=T("1e-7"), abs=0) + assert approx(x, rel=T("1e-6"), abs=0) == a + assert approx(x, rel=T("1e-7"), abs=0) != a def test_fraction(self): within_1e6 = [