Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assert that two dictionaries are almost equal

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?

like image 900
Akavall Avatar asked May 08 '14 18:05

Akavall


People also ask

How do you know if two dictionaries are 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.

Can == operator be used on dictionaries?

According to the python doc, you can indeed use the == operator on dictionaries.

How do I tell if two dictionaries are identical in Python?

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.

How does Python compare two dictionaries?

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.


2 Answers

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
like image 126
Akavall Avatar answered Sep 22 '22 04:09

Akavall


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)
like image 41
Bill Avatar answered Sep 24 '22 04:09

Bill