I am trying to assert that two dictionaries are almost equal, but I can't seem to do that.
Here is an example:
>>> import nose.tools as nt
>>> nt.assert_dict_equal({'a' : 12.4}, {'a' : 5.6 + 6.8})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/unittest/case.py", line 838, in assertDictEqual
self.fail(self._formatMessage(msg, standardMsg))
File "/usr/lib/python2.7/unittest/case.py", line 413, in fail
raise self.failureException(msg)
AssertionError: {'a': 12.4} != {'a': 12.399999999999999}
- {'a': 12.4}
+ {'a': 12.399999999999999}
I would like this to pass, like that:
>>> nt.assert_almost_equal(12.4, 5.6 + 6.8)
I am hoping that I missing something simple like, nt.assert_almost_dict_equal
, or maybe there is parameter that I could pass to nt.assert_dict_equal
that specifies how close floating points should be, but I can't find anything.
Of course, I could just loop over the dictionaries and use nt.assert_almost_equal
to compare the values individually; however, in my case the dictionary is more complicated, so I was hoping to avoid that.
What is the best way to assert that two dictionaries are almost equal?
Using == operator to Compare Two Dictionaries Here we are using the equality comparison operator in Python to compare two dictionaries whether both have the same key value pairs or not.
According to the python doc, you can indeed use the == operator on dictionaries.
You can use the == operator, and it will work. However, when you have specific needs, things become harder. The reason is, Python has no built-in feature allowing us to: compare two dictionaries and check how many pairs are equal.
The compare method cmp() is used in Python to compare values and keys of two dictionaries. If method returns 0 if both dictionaries are equal, 1 if dic1 > dict2 and -1 if dict1 < dict2.
The comment by @dano answered my question:
I copied a function from a link provided by dano
import unittest
import numpy
def assertDeepAlmostEqual(test_case, expected, actual, *args, **kwargs):
"""
Assert that two complex structures have almost equal contents.
Compares lists, dicts and tuples recursively. Checks numeric values
using test_case's :py:meth:`unittest.TestCase.assertAlmostEqual` and
checks all other values with :py:meth:`unittest.TestCase.assertEqual`.
Accepts additional positional and keyword arguments and pass those
intact to assertAlmostEqual() (that's how you specify comparison
precision).
:param test_case: TestCase object on which we can call all of the basic
'assert' methods.
:type test_case: :py:class:`unittest.TestCase` object
"""
is_root = not '__trace' in kwargs
trace = kwargs.pop('__trace', 'ROOT')
try:
if isinstance(expected, (int, float, long, complex)):
test_case.assertAlmostEqual(expected, actual, *args, **kwargs)
elif isinstance(expected, (list, tuple, numpy.ndarray)):
test_case.assertEqual(len(expected), len(actual))
for index in xrange(len(expected)):
v1, v2 = expected[index], actual[index]
assertDeepAlmostEqual(test_case, v1, v2,
__trace=repr(index), *args, **kwargs)
elif isinstance(expected, dict):
test_case.assertEqual(set(expected), set(actual))
for key in expected:
assertDeepAlmostEqual(test_case, expected[key], actual[key],
__trace=repr(key), *args, **kwargs)
else:
test_case.assertEqual(expected, actual)
except AssertionError as exc:
exc.__dict__.setdefault('traces', []).append(trace)
if is_root:
trace = ' -> '.join(reversed(exc.traces))
exc = AssertionError("%s\nTRACE: %s" % (exc.message, trace))
raise exc
# My part, using the function
class TestMyClass(unittest.TestCase):
def test_dicts(self):
assertDeepAlmostEqual(self, {'a' : 12.4}, {'a' : 5.6 + 6.8})
def test_dicts_2(self):
dict_1 = {'a' : {'b' : [12.4, 0.3]}}
dict_2 = {'a' : {'b' : [5.6 + 6.8, 0.1 + 0.2]}}
assertDeepAlmostEqual(self, dict_1, dict_2)
def main():
unittest.main()
if __name__ == "__main__":
main()
Result:
Ran 2 tests in 0.000s
OK
I realize you wouldn't import pandas just to do this but if you happen to be using pandas you can convert the dicts to series and use the assert_series_equal
from pandas.testing
which, by default, has check_exact=False
.
>>> import pandas as pd
>>> from pandas.testing import assert_series_equal
>>> a = pd.Series({'a' : 12.4})
>>> b = pd.Series({'a': 12.399999999999999})
>>> assert_series_equal(a, b)
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