suppose I got two nested dicts with arrays of dicts inside, i want to check if the values are close enough.
== doesnt work since it doesnt check for array values
extending the ApproxMapping class doesnt work either
dict1 = {
'a': 1,
'b': [
{'c': [{'d': 32.069},{'e': 32.420}]}
]
}
dict2 = {
'a': 1,
'b': [
{'c': [{'d': 32.070},{'e': 32.421}]}
]
}
How can I check they are almost equal, is there anyway i can override the pytest.approx method to work for nested dicts and arrays?
CodePudding user response:
Checkout the deepdiff
library:
from deepdiff import DeepDiff
dict1 = {
'a': 1,
'b': [
{'c': [{'d': 32.069},{'e': 32.420}]}
]
}
dict2 = {
'a': 1,
'b': [
{'c': [{'d': 32.070},{'e': 32.421}]}
]
}
diff = DeepDiff(dict1, dict2, significant_digits=2)
print(diff) # {}
CodePudding user response:
Here's a pure Python approach, if you want one:
def assert_values_almost_equal(value1, value2, tolerance=1e-5):
if isinstance(value1, dict):
assert_dicts_almost_equal(value1, value2, tolerance=tolerance)
elif isinstance(value1, list):
assert_sequences_almost_equal(value1, value2, tolerance=tolerance)
elif isinstance(value1, (int, float)):
assert_numbers_almost_equal(value1, value2, tolerance=tolerance)
else:
assert value1 == value2, f'Value 1: {n1} != Value 2: {n2}'
def assert_dicts_almost_equal(d1, d2, tolerance=1e-5):
for (k1, v1), (k2, v2) in zip(d1.items(), d2.items()):
assert_values_almost_equal(k1, k2, tolerance=tolerance)
assert_values_almost_equal(v1, v2, tolerance=tolerance)
def assert_sequences_almost_equal(s1, s2, tolerance=1e-5):
for e1, e2 in zip(s1, s2):
assert_values_almost_equal(e1, e2, tolerance=tolerance)
def assert_numbers_almost_equal(n1, n2, tolerance=1e-5):
assert abs(n1 - n2) < tolerance, f'Number 1: {n1} != Number 2: {n2}'
Note that if you want to test other data types not covered in assert_values_almost_equal
(e.g. numpy arrays), you'll need to add the proper function, along with the corresponding isinstance
check (use np.testing.assert_array_almost_equal
for the assertion if you need to do this).
Testing:
dict1 = {
'a': 1,
'b': [
{'c': [{'d': 32.069},{'e': 32.420}]}
]
}
dict2 = {
'a': 1,
'b': [
{'c': [{'d': 32.070},{'e': 32.421}]}
]
}
# passes
assert_dicts_almost_equal(dict1, dict2, tolerance=0.1)
# AssertionError: Number 1: 32.069 != Number 2: 32.07
assert_dicts_almost_equal(dict1, dict2, tolerance=0.0001)