For dictionaries without floating point numbers we are using the simple a == b
where a
and b
are python dictionaries. This works well until we end up with a
and b
containing floating point numbers somewhere within. They are nested dictionaries so I think that is giving pytest.approx
trouble.
What we want is something that will tell us that these two dictionaries are equal (or approximately equal, but something that won't fail only on floating point approximations):
{"foo": {"bar": 0.30000001}} == {"foo": {"bar": 0.30000002}}
pytest.approx()
is almost what I want, but it doesn't support nested dictionaries. Is there something out there that can do what I want?
You can define your own approximation helper with support for nested dictionaries. Unfortunately, pytest
doesn't support enhancement of approx
with custom comparators, so you have to write your own function; however, it hasn't be too complicated:
import pytest
from collections.abc import Mapping
from _pytest.python_api import ApproxMapping
def my_approx(expected, rel=None, abs=None, nan_ok=False):
if isinstance(expected, Mapping):
return ApproxNestedMapping(expected, rel, abs, nan_ok)
return pytest.approx(expected, rel, abs, nan_ok)
class ApproxNestedMapping(ApproxMapping):
def _yield_comparisons(self, actual):
for k in self.expected.keys():
if isinstance(actual[k], type(self.expected)):
gen = ApproxNestedMapping(
self.expected[k], rel=self.rel, abs=self.abs, nan_ok=self.nan_ok
)._yield_comparisons(actual[k])
for el in gen:
yield el
else:
yield actual[k], self.expected[k]
def _check_type(self):
for key, value in self.expected.items():
if not isinstance(value, type(self.expected)):
super()._check_type()
Now use my_approx
instead of pytest.approx
:
def test_nested():
assert {'foo': {'bar': 0.30000001}} == my_approx({'foo': {'bar': 0.30000002}})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With