Skip to content

Commit c7f4039

Browse files
[primer] Extract comparison logic into PylintComparator class
Move cross-referencing and JSON loading from CompareCommand into a dedicated PylintComparator class with an abstract Comparator base, enabling future comparator implementations (e.g. AstroidComparator). Closes #6984
1 parent 7f2b8cf commit c7f4039

2 files changed

Lines changed: 80 additions & 42 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
2+
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
3+
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
4+
5+
from __future__ import annotations
6+
7+
import abc
8+
import json
9+
from collections.abc import Iterator
10+
from pathlib import Path
11+
12+
from pylint.reporters.json_reporter import OldJsonExport
13+
from pylint.testutils._primer.primer_command import (
14+
PackageData,
15+
PackageMessages,
16+
)
17+
18+
19+
class Comparator(abc.ABC):
20+
"""Abstract base class for primer comparators."""
21+
22+
missing_messages: PackageMessages
23+
new_messages: PackageMessages
24+
25+
@abc.abstractmethod
26+
def __iter__(
27+
self,
28+
) -> Iterator[tuple[str, PackageData, PackageData]]:
29+
"""Yield (package, missing_messages, new_messages) for packages with
30+
changes.
31+
"""
32+
33+
34+
class PylintComparator(Comparator):
35+
"""Compare two primer runs and compute missing/new messages per package."""
36+
37+
def __init__(
38+
self,
39+
main_data: PackageMessages,
40+
pr_data: PackageMessages,
41+
) -> None:
42+
self.missing_messages: PackageMessages = {}
43+
for package, data in main_data.items():
44+
package_missing_messages: list[OldJsonExport] = []
45+
for message in data["messages"]:
46+
try:
47+
pr_data[package]["messages"].remove(message)
48+
except ValueError:
49+
package_missing_messages.append(message)
50+
self.missing_messages[package] = PackageData(
51+
commit=pr_data[package]["commit"],
52+
messages=package_missing_messages,
53+
)
54+
self.new_messages = pr_data
55+
56+
def __iter__(
57+
self,
58+
) -> Iterator[tuple[str, PackageData, PackageData]]:
59+
for package, missing in self.missing_messages.items():
60+
new = self.new_messages[package]
61+
if not missing["messages"] and not new["messages"]:
62+
print(f"PRIMER: No changes in {package}.")
63+
continue
64+
yield package, missing, new
65+
66+
@staticmethod
67+
def load_json(file_path: Path | str) -> PackageMessages:
68+
with open(file_path, encoding="utf-8") as f:
69+
result: PackageMessages = json.load(f)
70+
return result

pylint/testutils/_primer/primer_compare_command.py

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@
33
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
44
from __future__ import annotations
55

6-
import json
7-
from pathlib import Path, PurePosixPath
6+
from pathlib import PurePosixPath
87

9-
from pylint.reporters.json_reporter import OldJsonExport
8+
from pylint.testutils._primer.comparator import PylintComparator
109
from pylint.testutils._primer.primer_command import (
1110
PackageData,
12-
PackageMessages,
1311
PrimerCommand,
1412
)
1513

@@ -19,63 +17,33 @@
1917
class CompareCommand(PrimerCommand):
2018
def run(self) -> None:
2119
if self.config.batches is None:
22-
main_data = self._load_json(self.config.base_file)
23-
pr_data = self._load_json(self.config.new_file)
20+
main_data = PylintComparator.load_json(self.config.base_file)
21+
pr_data = PylintComparator.load_json(self.config.new_file)
2422
else:
2523
main_data = {}
2624
pr_data = {}
2725
for idx in range(self.config.batches):
2826
main_data.update(
29-
self._load_json(
27+
PylintComparator.load_json(
3028
self.config.base_file.replace("BATCHIDX", "batch" + str(idx))
3129
)
3230
)
3331
pr_data.update(
34-
self._load_json(
32+
PylintComparator.load_json(
3533
self.config.new_file.replace("BATCHIDX", "batch" + str(idx))
3634
)
3735
)
3836

39-
missing_messages_data, new_messages_data = self._cross_reference(
40-
main_data, pr_data
41-
)
42-
comment = self._create_comment(missing_messages_data, new_messages_data)
37+
comparator = PylintComparator(main_data, pr_data)
38+
comment = self._create_comment(comparator)
4339
with open(self.primer_directory / "comment.txt", "w", encoding="utf-8") as f:
4440
f.write(comment)
4541

46-
@staticmethod
47-
def _cross_reference(
48-
main_data: PackageMessages, pr_data: PackageMessages
49-
) -> tuple[PackageMessages, PackageMessages]:
50-
missing_messages_data: PackageMessages = {}
51-
for package, data in main_data.items():
52-
package_missing_messages: list[OldJsonExport] = []
53-
for message in data["messages"]:
54-
try:
55-
pr_data[package]["messages"].remove(message)
56-
except ValueError:
57-
package_missing_messages.append(message)
58-
missing_messages_data[package] = PackageData(
59-
commit=pr_data[package]["commit"], messages=package_missing_messages
60-
)
61-
return missing_messages_data, pr_data
62-
63-
@staticmethod
64-
def _load_json(file_path: Path | str) -> PackageMessages:
65-
with open(file_path, encoding="utf-8") as f:
66-
result: PackageMessages = json.load(f)
67-
return result
68-
69-
def _create_comment(
70-
self, all_missing_messages: PackageMessages, all_new_messages: PackageMessages
71-
) -> str:
42+
def _create_comment(self, comparator: PylintComparator) -> str:
7243
comment = ""
73-
for package, missing_messages in all_missing_messages.items():
44+
for package, missing_messages, new_messages in comparator:
7445
if len(comment) >= MAX_GITHUB_COMMENT_LENGTH:
7546
break
76-
new_messages = all_new_messages[package]
77-
if not missing_messages["messages"] and not new_messages["messages"]:
78-
continue
7947
comment += self._create_comment_for_package(
8048
package, new_messages, missing_messages
8149
)

0 commit comments

Comments
 (0)