|
14 | 14 |
|
15 | 15 | from . import result |
16 | 16 | from .util import (strclass, safe_repr, _count_diff_all_purpose, |
17 | | - _count_diff_hashable, _common_shorten_repr) |
| 17 | + _count_diff_hashable, _common_shorten_repr, |
| 18 | + _shorten, _MIN_END_LEN, _MAX_LENGTH) |
18 | 19 |
|
19 | 20 | __unittest = True |
20 | 21 |
|
@@ -1202,15 +1203,50 @@ def assertIsNot(self, expr1, expr2, msg=None): |
1202 | 1203 | standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),) |
1203 | 1204 | self.fail(self._formatMessage(msg, standardMsg)) |
1204 | 1205 |
|
1205 | | - def assertDictEqual(self, d1, d2, msg=None): |
1206 | | - self.assertIsInstance(d1, dict, 'First argument is not a dictionary') |
1207 | | - self.assertIsInstance(d2, dict, 'Second argument is not a dictionary') |
| 1206 | + def assertDictEqual(self, d1: dict, d2: dict, msg: str | None = None): |
| 1207 | + self.assertIsInstance(d1, dict, "First argument is not a dictionary") |
| 1208 | + self.assertIsInstance(d2, dict, "Second argument is not a dictionary") |
1208 | 1209 |
|
1209 | 1210 | if d1 != d2: |
1210 | | - standardMsg = '%s != %s' % _common_shorten_repr(d1, d2) |
1211 | | - diff = ('\n' + '\n'.join(difflib.ndiff( |
1212 | | - pprint.pformat(d1).splitlines(), |
1213 | | - pprint.pformat(d2).splitlines()))) |
| 1211 | + standardMsg = "%s != %s" % _common_shorten_repr(d1, d2) |
| 1212 | + |
| 1213 | + d1keys = set(d1.keys()) |
| 1214 | + d2keys = set(d2.keys()) |
| 1215 | + d1extrakeys = d1keys - d2keys |
| 1216 | + d2extrakeys = d2keys - d1keys |
| 1217 | + commonkeys = d1keys & d2keys |
| 1218 | + lines = [] |
| 1219 | + def _value_repr(value): |
| 1220 | + return _shorten(safe_repr(value), _MAX_LENGTH//2-_MIN_END_LEN, _MIN_END_LEN) |
| 1221 | + def _justified_values(d, keys, prefix): |
| 1222 | + items = [(_value_repr(key), _value_repr(d[key])) for key in sorted(keys)] |
| 1223 | + justify_width = max(len(key) for key, value in items) |
| 1224 | + justify_width = max(min(justify_width, _MAX_LENGTH - _MIN_END_LEN - 2), 4) |
| 1225 | + return (" %s %s: %s," % (prefix, key.ljust(justify_width), value) for key, value in items) |
| 1226 | + if commonkeys: |
| 1227 | + commonvalues = [] |
| 1228 | + for key in sorted(commonkeys): |
| 1229 | + if d1[key] == d2[key]: |
| 1230 | + commonvalues.append(key) |
| 1231 | + commonkeys.remove(key) |
| 1232 | + if commonvalues: |
| 1233 | + lines.append(" Keys in both dicts with identical values:") |
| 1234 | + lines.extend(_justified_values(d1, commonvalues, " ")) |
| 1235 | + if commonkeys: |
| 1236 | + lines.append(" Keys in both dicts with differing values:") |
| 1237 | + for key in sorted(commonkeys): |
| 1238 | + key_repr = _value_repr(key) |
| 1239 | + lines.append(" - %s: %s," % (key_repr, _value_repr(d1[key]))) |
| 1240 | + lines.append(" + %s: %s," % (key_repr, _value_repr(d2[key]))) |
| 1241 | + if d1extrakeys: |
| 1242 | + lines.append(" Keys in the first dict but not the second:") |
| 1243 | + lines.extend(_justified_values(d1, d1extrakeys, "-")) |
| 1244 | + if d2extrakeys: |
| 1245 | + lines.append(" Keys in the second dict but not the first:") |
| 1246 | + lines.extend(_justified_values(d2, d2extrakeys, "+")) |
| 1247 | + |
| 1248 | + diff = "\n{\n%s\n}" % '\n'.join(lines) |
| 1249 | + |
1214 | 1250 | standardMsg = self._truncateMessage(standardMsg, diff) |
1215 | 1251 | self.fail(self._formatMessage(msg, standardMsg)) |
1216 | 1252 |
|
|
0 commit comments