You can make a generic helper function that works for most cases:
def items_equal(xs, ys):
if isinstance(xs, dict) and isinstance(ys, dict):
if len(xs) != len(ys):
return False
for key in xs.keys():
try:
if not items_equal(xs[key], ys[key]):
return False
except KeyError:
return False
return True
elif isinstance(xs, list) and isinstance(ys, list):
if len(xs) != len(ys):
return False
sxs = xs
sys = ys
try:
sxs = sorted(xs)
sys = sorted(ys)
for x, y in zip(sxs, sys):
if not items_equal(x, y):
return False
except TypeError:
ys_copy = ys.copy()
for x in xs:
matches = [i for i, y in enumerate(ys_copy) if items_equal(x, y)]
if len(matches):
del ys_copy[matches[0]]
continue
else:
return False
return True
else:
return xs == ys
Here are the tests:
def test_items_equal_simple():
assert items_equal(1, 1)
assert not items_equal(1, 2)
assert items_equal('Hello', 'Hello')
assert not items_equal('', 'no')
def test_items_equal_complex():
assert items_equal([1, 2, 3], [3, 2, 1])
assert not items_equal([1, 2, 3], [3, 2, 1, 4])
assert not items_equal(
{'one': 1},
{'two': 2}
)
assert items_equal(
{'one': 1, 'two': 2},
{'two': 2, 'one': 1}
)
assert items_equal(
{'one': [1, 2, 3], 'two': [3]},
{'two': [3], 'one': [3, 1, 2]},
)
assert items_equal(
{'four': {'one': 1, 'two': 2}, 'five': 5},
{'five': 5, 'four': {'two': 2, 'one': 1}}
)
assert not items_equal(
{'four': {'one': 1, 'two': 2, 'eight': 8}, 'five': 5},
{'five': 5, 'four': {'two': 2, 'one': 1}}
)
def test_items_equal_dict_in_list():
assert items_equal(
[{'one': 1, 'two': 2}, {'five': 5}],
[{'one': 1, 'two': 2}, {'five': 5}]
)
assert items_equal(
[{'one': 1, 'two': 2}, {'five': 5}],
[{'five': 5}, {'two': 2, 'one': 1}]
)
def test_items_equal_dict_list_dict_list():
assert items_equal(
{'a': [{'d': [{'h': [1, 2, 3], 'i': [4, 5, 6]}], 'e': [{'j': [7, 8], 'k': [9, 10]}]}], 'b': [{'f': [11, 12], 'g': [13, 14]}]},
{'b': [{'f': [12, 11], 'g': [14, 13]}], 'a': [{'d': [{'i': [6, 5, 4], 'h': [3, 2, 1]}], 'e': [{'k': [10, 9], 'j': [8, 7]}]}]},
)
assert not items_equal(
{'a': [{'d': [{'h': [1, 2]}]}]},
{'a': [{'d': [{'h': [1, 2, 3]}]}]}
)
assert not items_equal(
[{'one': 1}, {'two': 2}],
[{'one': 1}, {'one': 1}]
)
assert not items_equal(
[{'one': 1}, {'one': 1}],
[{'one': 1}, {'two': 2}]
)