diff --git a/_pytest/python_api.py b/_pytest/python_api.py index 89ef9e0a9..541371449 100644 --- a/_pytest/python_api.py +++ b/_pytest/python_api.py @@ -153,6 +153,8 @@ class ApproxScalar(ApproxBase): """ Perform approximate comparisons for single numbers only. """ + DEFAULT_ABSOLUTE_TOLERANCE = 1e-12 + DEFAULT_RELATIVE_TOLERANCE = 1e-6 def __repr__(self): """ @@ -223,7 +225,7 @@ class ApproxScalar(ApproxBase): # Figure out what the absolute tolerance should be. ``self.abs`` is # either None or a value specified by the user. - absolute_tolerance = set_default(self.abs, 1e-12) + absolute_tolerance = set_default(self.abs, self.DEFAULT_ABSOLUTE_TOLERANCE) if absolute_tolerance < 0: raise ValueError("absolute tolerance can't be negative: {}".format(absolute_tolerance)) @@ -241,7 +243,7 @@ class ApproxScalar(ApproxBase): # we've made sure the user didn't ask for an absolute tolerance only, # because we don't want to raise errors about the relative tolerance if # we aren't even going to use it. - relative_tolerance = set_default(self.rel, 1e-6) * abs(self.expected) + relative_tolerance = set_default(self.rel, self.DEFAULT_RELATIVE_TOLERANCE) * abs(self.expected) if relative_tolerance < 0: raise ValueError("relative tolerance can't be negative: {}".format(absolute_tolerance)) @@ -252,6 +254,13 @@ class ApproxScalar(ApproxBase): return max(relative_tolerance, absolute_tolerance) +class ApproxDecimal(ApproxScalar): + from decimal import Decimal + + DEFAULT_ABSOLUTE_TOLERANCE = Decimal('1e-12') + DEFAULT_RELATIVE_TOLERANCE = Decimal('1e-6') + + def approx(expected, rel=None, abs=None, nan_ok=False): """ Assert that two numbers (or two sets of numbers) are equal to each other @@ -401,6 +410,7 @@ def approx(expected, rel=None, abs=None, nan_ok=False): from collections import Mapping, Sequence from _pytest.compat import STRING_TYPES as String + from decimal import Decimal # Delegate the comparison to a class that knows how to deal with the type # of the expected value (e.g. int, float, list, dict, numpy.array, etc). @@ -422,6 +432,8 @@ def approx(expected, rel=None, abs=None, nan_ok=False): cls = ApproxMapping elif isinstance(expected, Sequence) and not isinstance(expected, String): cls = ApproxSequence + elif isinstance(expected, Decimal): + cls = ApproxDecimal else: cls = ApproxScalar diff --git a/changelog/3247.bugfix.rst b/changelog/3247.bugfix.rst new file mode 100644 index 000000000..9483ceeea --- /dev/null +++ b/changelog/3247.bugfix.rst @@ -0,0 +1 @@ +Fix ``TypeError`` issue when using ``approx`` with a ``Decimal`` value. diff --git a/testing/python/approx.py b/testing/python/approx.py index 300e1ce86..341e5fcff 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -249,6 +249,7 @@ class TestApprox(object): (Decimal('-1.000001'), Decimal('-1.0')), ] for a, x in within_1e6: + 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