pytest
pytest copied to clipboard
TypeError with pytest.approx on nested dictionaries
{'a': {'b': 0.2 + 0.1}} == pytest.approx({'a': {'b': 0.3}})
~/.conda/lib/python3.6/site-packages/_pytest/python_api.py in __eq__(self, actual)
195 # other or not. The abs() calls are for compatibility with complex
196 # numbers.
--> 197 if math.isnan(abs(self.expected)):
198 return self.nan_ok and math.isnan(abs(actual))
199
TypeError: bad operand type for abs(): 'dict'
Pytest 3.3.2 on python 3.6.4 (Anaconda) Ubuntu 16.04
That seems expected to me.
we should perhaps raise a better error message
im reasonably sure that assert {'a': {'b': 0.2 + 0.1}} == {'a': {'b': pytest.approx(0.3)}}
should be workable (with maybe some rough edges)
does anyone want to try?
I think it'd be quite unusual to do additional type checking here (EAFP applies :wink:). You'll probably get similar error messages if you do pytest.approx({'a': None})
or whatever.
Recursively comparing dictionaries might get tricky I think.
One can find an implementation of approx with support for nested dictionaries here: https://stackoverflow.com/a/56048692/1551810. It would be great if pytest could support this natively.
its important to have a definition of whats expected wrt additional/missing keys wrt nested dictionaries, plus its not hard to put approx instances actually in dictionaries as well
so we should find a clear spec of what approx should do, write it down in the docs and then go for it
Hi! Any progress on this? It would help tremendously and save me from writing tons and tons of ugly boilerplate code for approximate comparisons of deeply nested dataclasses (or their dictifications)
@Darkdragon84 nothing I'm aware of - if anything is happening, it would likely be noted in this issue.
Btw I would vote for not reusing pytest.approx
to compare nested dictionaries, instead using a new API, because that can be more flexible in being configurable (for example, what do do regarding missing keys, etc).
@nicoddemus we might want to set up a new pytest plugin for other assert helpers (pytest-unordered, and a few other items could go there for incubation)
Understood. Good point @nicoddemus I will see what is out there. Thanks folks for the quick reaction 👍
deepdiff module is a good alternative for nested dictionaries
{'a': {'b': 0.2 + 0.1}} == pytest.approx({'a': {'b': 0.3}})
becomes
assert not deepdiff.DeepDiff({'a': {'b': 0.2 + 0.1}}, {'a': {'b': 0.3}}, ignore_order=True, significant_digits=6)
This can be fixed with a single line change:
Instead of https://github.com/pytest-dev/pytest/blob/dfc910ee90cbe70d8d8b079190fa75ca2a5ef067/src/_pytest/python_api.py#L90
a == approx(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) for a, x in self._yield_comparisons(actual)
will do the trick, along with removing the TypeError in ApproxMapping (https://github.com/pytest-dev/pytest/blob/dfc910ee90cbe70d8d8b079190fa75ca2a5ef067/src/_pytest/python_api.py#L307)