Skip to content

Commit c410066

Browse files
committed
Add assert_dict_equal() (#14)
1 parent 6f2dcc0 commit c410066

4 files changed

Lines changed: 140 additions & 1 deletion

File tree

NEWS.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
News in asserts 0.8.4
22
=====================
33

4+
API Additions
5+
-------------
6+
7+
* Add ``assert_dict_equal()``.
8+
49
Improvements
510
------------
611

asserts/__init__.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,71 @@ def assert_not_almost_equal(first, second, msg_fmt="{msg}",
290290
places=places, delta=delta))
291291

292292

293+
def assert_dict_equal(first, second, key_msg_fmt="{msg}",
294+
value_msg_fmt="{msg}"):
295+
"""Fail unless first dictionary equals second.
296+
297+
The dictionaries are considered equal, if they both contain the same
298+
keys, and their respective values are also equal.
299+
300+
>>> assert_equal({"foo": 5}, {"foo": 5})
301+
>>> assert_equal({"foo": 5}, {})
302+
Traceback (most recent call last):
303+
...
304+
AssertionError: key 'foo' missing from right dict
305+
306+
The following key_msg_fmt arguments are supported, if the keys do not
307+
match:
308+
* msg - the default error message
309+
* first - the first dict
310+
* second - the second dict
311+
* missing_keys - list of keys missing from right
312+
* extra_keys - list of keys missing from left
313+
314+
The following value_msg_fmt arguments are supported, if a value does not
315+
match:
316+
* msg - the default error message
317+
* first - the first dict
318+
* second - the second dict
319+
* key - the key where the value does not match
320+
* first_value - the value in the first dict
321+
* second_value - the value in the second dict
322+
"""
323+
first_keys = set(first.keys())
324+
second_keys = set(second.keys())
325+
missing_keys = list(first_keys - second_keys)
326+
extra_keys = list(second_keys - first_keys)
327+
if missing_keys or extra_keys:
328+
if missing_keys:
329+
if len(missing_keys) == 1:
330+
msg = "key {!r} missing from right dict".format(missing_keys[0])
331+
else:
332+
keys = ", ".join(sorted(repr(k) for k in missing_keys))
333+
msg = "keys {} missing from right dict".format(keys)
334+
else:
335+
if len(extra_keys) == 1:
336+
msg = "extra key {!r} in right dict".format(extra_keys[0])
337+
else:
338+
keys = ", ".join(sorted(repr(k) for k in extra_keys))
339+
msg = "extra keys {} in right dict".format(keys)
340+
if key_msg_fmt:
341+
msg = key_msg_fmt.format(
342+
msg=msg, first=first, second=second,
343+
missing_keys=missing_keys, extra_keys=extra_keys)
344+
raise AssertionError(msg)
345+
for key in first:
346+
first_value = first[key]
347+
second_value = second[key]
348+
msg = "key '{}' differs: {!r} != {!r}".format(
349+
key, first_value, second_value)
350+
if value_msg_fmt:
351+
msg = value_msg_fmt.format(
352+
msg=msg, first=first, second=second,
353+
key=key, first_value=first_value, second_value=second_value)
354+
msg = msg.replace("{", "{{").replace("}", "}}")
355+
assert_equal(first_value, second_value, msg_fmt=msg)
356+
357+
293358
def assert_less(first, second, msg_fmt="{msg}"):
294359
"""Fail if first is not less than second.
295360

asserts/__init__.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def assert_equal(first: Any, second: Any, msg_fmt: Text = ...) -> None: ...
4646
def assert_not_equal(first: Any, second: Any, msg_fmt: Text = ...) -> None: ...
4747
def assert_almost_equal(first: float, second: float, msg_fmt: Text = ..., places: int = ..., delta: float = ...) -> None: ...
4848
def assert_not_almost_equal(first: float, second: float, msg_fmt: Text = ..., places: int = ..., delta: float = ...) -> None: ...
49+
def assert_dict_equal(first: dict, second: dict, key_msg_fmt: Text = ..., value_msg_fmt: Text = ...) -> None: ...
4950
def assert_less(first: Any, second: Any, msg_fmt: Text = ...) -> None: ...
5051
def assert_less_equal(first: Any, second: Any, msg_fmt: Text = ...) -> None: ...
5152
def assert_greater(first: Any, second: Any, msg_fmt: Text = ...) -> None: ...

test_asserts.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
assert_raises_errno,
3838
assert_succeeds,
3939
assert_warns,
40-
assert_warns_regex)
40+
assert_warns_regex, assert_dict_equal)
4141

4242

4343
class _DummyObject(object):
@@ -365,6 +365,74 @@ def test_not_assert_almost_equal__delta_lt_0(self):
365365
else:
366366
raise AssertionError("ValueError not raised")
367367

368+
# assert_dict_equal()
369+
370+
def test_assert_dict_equal__empty_dicts(self):
371+
assert_dict_equal({}, {})
372+
373+
def test_assert_dict_equal__dicts_are_equal(self):
374+
assert_dict_equal({"foo": 5}, {"foo": 5})
375+
376+
def test_assert_dict_equal__one_key_missing_from_right(self):
377+
with _assert_raises_assertion("key 'foo' missing from right dict"):
378+
assert_dict_equal({"bar": 10, "foo": 5}, {"bar": 10})
379+
380+
def test_assert_dict_equal__multiple_keys_missing_from_right(self):
381+
with _assert_raises_assertion(
382+
"keys 'bar', 'foo' missing from right dict"):
383+
assert_dict_equal({"foo": 5, "bar": 10, "baz": 15}, {"baz": 15})
384+
385+
def test_assert_dict_equal__one_key_missing_from_left(self):
386+
with _assert_raises_assertion("extra key 'foo' in right dict"):
387+
assert_dict_equal({"bar": 10}, {"bar": 10, "foo": 5})
388+
389+
def test_assert_dict_equal__multiple_keys_missing_from_left(self):
390+
with _assert_raises_assertion("extra keys 'bar', 'foo' in right dict"):
391+
assert_dict_equal({"baz": 15}, {"foo": 5, "bar": 10, "baz": 15})
392+
393+
def test_assert_dict_equal__values_do_not_match(self):
394+
with _assert_raises_assertion("key 'foo' differs: 15 != 10"):
395+
assert_dict_equal({"foo": 15}, {"foo": 10})
396+
397+
def test_assert_dict_equal__not_string_keys(self):
398+
with _assert_raises_assertion("key 10 missing from right dict"):
399+
assert_dict_equal({10: "foo"}, {})
400+
with _assert_raises_assertion(
401+
"keys 'foo', 5 missing from right dict"):
402+
assert_dict_equal({5: "", "foo": ""}, {})
403+
with _assert_raises_assertion("extra key 10 in right dict"):
404+
assert_dict_equal({}, {10: "foo"})
405+
with _assert_raises_assertion("extra keys 'foo', 5 in right dict"):
406+
assert_dict_equal({}, {5: "", "foo": ""})
407+
408+
def test_assert_dict_equal__message_precedence(self):
409+
with _assert_raises_assertion("key 'foo' missing from right dict"):
410+
assert_dict_equal({"foo": "", "bar": "", "baz": 5},
411+
{"bar": "", "baz": 10, "extra": ""})
412+
with _assert_raises_assertion("extra key 'extra' in right dict"):
413+
assert_dict_equal({"bar": "", "baz": 5},
414+
{"bar": "", "baz": 10, "extra": ""})
415+
416+
def test_assert_dict_equal__custom_key_message(self):
417+
with _assert_raises_assertion(
418+
"key 'foo' missing from right dict;"
419+
"{'foo': ''};{'bar': ''};['foo'];['bar']"):
420+
assert_dict_equal(
421+
{"foo": ""}, {"bar": ""},
422+
key_msg_fmt="{msg};{first!r};{second!r};"
423+
"{missing_keys!r};{extra_keys!r}"
424+
)
425+
426+
def test_assert_dict_equal__custom_value_message(self):
427+
with _assert_raises_assertion(
428+
"key 'foo' differs: 5 != 10;{'foo': 5};{'foo': 10};"
429+
"'foo';5;10"):
430+
assert_dict_equal(
431+
{"foo": 5}, {"foo": 10},
432+
value_msg_fmt="{msg};{first!r};{second!r};"
433+
"{key!r};{first_value};{second_value}"
434+
)
435+
368436
# assert_less()
369437

370438
def test_assert_less(self):

0 commit comments

Comments
 (0)