pytest icon indicating copy to clipboard operation
pytest copied to clipboard

TypeError with pytest.approx on nested dictionaries

Open frexvahi opened this issue 7 years ago • 14 comments

{'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

frexvahi avatar Jan 30 '18 12:01 frexvahi

That seems expected to me.

The-Compiler avatar Jan 30 '18 13:01 The-Compiler

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?

RonnyPfannschmidt avatar Jan 30 '18 13:01 RonnyPfannschmidt

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.

The-Compiler avatar Jan 30 '18 14:01 The-Compiler

Recursively comparing dictionaries might get tricky I think.

nicoddemus avatar Jan 30 '18 21:01 nicoddemus

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.

kdebrab avatar Jan 18 '21 11:01 kdebrab

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

RonnyPfannschmidt avatar Jan 18 '21 12:01 RonnyPfannschmidt

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 avatar Jun 27 '22 10:06 Darkdragon84

@Darkdragon84 nothing I'm aware of - if anything is happening, it would likely be noted in this issue.

The-Compiler avatar Jun 27 '22 10:06 The-Compiler

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 avatar Jun 27 '22 11:06 nicoddemus

@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)

RonnyPfannschmidt avatar Jun 27 '22 13:06 RonnyPfannschmidt

Understood. Good point @nicoddemus I will see what is out there. Thanks folks for the quick reaction 👍

Darkdragon84 avatar Jun 28 '22 08:06 Darkdragon84

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)

rambattu avatar Sep 26 '22 23:09 rambattu

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)

FrankZijlstra avatar Dec 12 '23 12:12 FrankZijlstra