Skip to content

Commit f58d4c5

Browse files
[primer] Simplify residual pairing to single-sided bucketing
Drop the separate ``_position_key`` helper — its one-liner is called exactly twice — and lift the "same warning" explanation into the ``_pair_by_position`` docstring where it belongs. Bucket only the *new* side and walk ``old_residuals`` once, popping from each matching bucket. That removes the dual ``old_by_key`` dictionary and the ``paired_old_ids`` / ``paired_new_ids`` shadow bookkeeping — we can build ``final_missing`` inline in the old-side walk, and ``final_new`` still reads from the untouched input list.
1 parent 47b0f40 commit f58d4c5

1 file changed

Lines changed: 17 additions & 31 deletions

File tree

pylint/testutils/_primer/comparator.py

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,46 +34,32 @@ class PackageDiff(NamedTuple):
3434
changed: list[ChangedMessage] # same message, altered line / text
3535

3636

37-
def _position_key(msg: JSONMessage) -> tuple[str, str, str]:
38-
"""Key that identifies a message independently of its text or location.
39-
40-
Two messages that share (symbol, path, obj) are the "same warning" — if
41-
they differ only in line numbers or message text, they should be reported as
42-
*changed* rather than as a separate removal + addition.
43-
"""
44-
return (msg["symbol"], msg["path"], msg["obj"])
45-
46-
4737
def _pair_by_position(
4838
old_residuals: list[JSONMessage], new_residuals: list[JSONMessage]
4939
) -> tuple[list[ChangedMessage], list[JSONMessage], list[JSONMessage]]:
50-
"""Pair residual messages by position key ``(symbol, path, obj)``.
40+
"""Pair residual messages by ``(symbol, path, obj)`` in input order.
5141
52-
Messages that share the same key are paired 1:1 in order. Any left-over
53-
messages remain as genuinely missing or genuinely new.
54-
55-
Returns ``(paired, unmatched_old, unmatched_new)``.
42+
Two messages sharing that key are the "same warning" — if they differ only
43+
in line numbers or message text, they should be reported as *changed*
44+
rather than as a separate removal + addition. Leftovers on each side are
45+
genuinely missing or genuinely new.
5646
"""
57-
old_by_key: dict[tuple[str, str, str], list[JSONMessage]] = defaultdict(list)
5847
new_by_key: dict[tuple[str, str, str], list[JSONMessage]] = defaultdict(list)
59-
for m in old_residuals:
60-
old_by_key[_position_key(m)].append(m)
6148
for m in new_residuals:
62-
new_by_key[_position_key(m)].append(m)
49+
new_by_key[m["symbol"], m["path"], m["obj"]].append(m)
6350

6451
paired: list[ChangedMessage] = []
65-
paired_old_ids: set[int] = set()
66-
paired_new_ids: set[int] = set()
67-
for key in old_by_key:
68-
if key not in new_by_key:
69-
continue
70-
for old, new in zip(old_by_key[key], new_by_key[key]):
52+
final_missing: list[JSONMessage] = []
53+
matched_new: set[int] = set()
54+
for old in old_residuals:
55+
bucket = new_by_key.get((old["symbol"], old["path"], old["obj"]))
56+
if bucket:
57+
new = bucket.pop(0)
7158
paired.append(ChangedMessage(old=old, new=new))
72-
paired_old_ids.add(id(old))
73-
paired_new_ids.add(id(new))
74-
75-
final_missing = [m for m in old_residuals if id(m) not in paired_old_ids]
76-
final_new = [m for m in new_residuals if id(m) not in paired_new_ids]
59+
matched_new.add(id(new))
60+
else:
61+
final_missing.append(old)
62+
final_new = [m for m in new_residuals if id(m) not in matched_new]
7763
return paired, final_missing, final_new
7864

7965

@@ -96,7 +82,7 @@ def message_diff(change: ChangedMessage) -> str:
9682
"""
9783
old, new = change.old, change.new
9884
changed_keys: set[str] = set()
99-
for key in set(old) | set(new):
85+
for key in old.keys() | new.keys():
10086
if old.get(key) != new.get(key):
10187
changed_keys.add(key)
10288

0 commit comments

Comments
 (0)