Skip to content

Commit adb2eb0

Browse files
Extract Comparator class from CompareCommand
Move JSON loading, batching, and cross-referencing logic into a dedicated Comparator class. CompareCommand.run() now delegates to the Comparator and iterates over it to build the comment.
1 parent 712ee39 commit adb2eb0

3 files changed

Lines changed: 138 additions & 59 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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 json
8+
from collections.abc import Generator
9+
from pathlib import Path
10+
11+
from pylint.reporters.json_reporter import OldJsonExport
12+
from pylint.testutils._primer.primer_command import (
13+
PackageData,
14+
PackageMessages,
15+
)
16+
17+
18+
class Comparator:
19+
def __init__(
20+
self, base_file: str, new_file: str, batches: int | None = None
21+
) -> None:
22+
main_data: PackageMessages
23+
if batches is None:
24+
main_data = self._load_json(base_file)
25+
self.pr_data = self._load_json(new_file)
26+
else:
27+
main_data = {}
28+
self.pr_data = {}
29+
for idx in range(batches):
30+
main_data.update(
31+
self._load_json(base_file.replace("BATCHIDX", "batch" + str(idx)))
32+
)
33+
self.pr_data.update(
34+
self._load_json(new_file.replace("BATCHIDX", "batch" + str(idx)))
35+
)
36+
37+
self.missing_messages: PackageMessages = {}
38+
for package, data in main_data.items():
39+
package_missing_messages: list[OldJsonExport] = []
40+
for message in data["messages"]:
41+
try:
42+
self.pr_data[package]["messages"].remove(message)
43+
except ValueError:
44+
package_missing_messages.append(message)
45+
self.missing_messages[package] = PackageData(
46+
commit=self.pr_data[package]["commit"],
47+
messages=package_missing_messages,
48+
)
49+
50+
def __iter__(
51+
self,
52+
) -> Generator[tuple[str, PackageData, PackageData]]:
53+
for package, missing_messages in self.missing_messages.items():
54+
new_messages = self.pr_data[package]
55+
if not missing_messages["messages"] and not new_messages["messages"]:
56+
continue
57+
yield package, missing_messages, new_messages
58+
59+
@staticmethod
60+
def _load_json(file_path: Path | str) -> PackageMessages:
61+
with open(file_path, encoding="utf-8") as f:
62+
result: PackageMessages = json.load(f)
63+
return result

pylint/testutils/_primer/primer_compare_command.py

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,79 +3,28 @@
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
10-
from pylint.testutils._primer.primer_command import (
11-
PackageData,
12-
PackageMessages,
13-
PrimerCommand,
14-
)
8+
from pylint.testutils._primer.comparator import Comparator
9+
from pylint.testutils._primer.primer_command import PackageData, PrimerCommand
1510

1611
MAX_GITHUB_COMMENT_LENGTH = 65536
1712

1813

1914
class CompareCommand(PrimerCommand):
2015
def run(self) -> None:
21-
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)
24-
else:
25-
main_data = {}
26-
pr_data = {}
27-
for idx in range(self.config.batches):
28-
main_data.update(
29-
self._load_json(
30-
self.config.base_file.replace("BATCHIDX", "batch" + str(idx))
31-
)
32-
)
33-
pr_data.update(
34-
self._load_json(
35-
self.config.new_file.replace("BATCHIDX", "batch" + str(idx))
36-
)
37-
)
38-
39-
missing_messages_data, new_messages_data = self._cross_reference(
40-
main_data, pr_data
16+
comparator = Comparator(
17+
self.config.base_file, self.config.new_file, self.config.batches
4118
)
42-
comment = self._create_comment(missing_messages_data, new_messages_data)
19+
comment = self._create_comment(comparator)
4320
with open(self.primer_directory / "comment.txt", "w", encoding="utf-8") as f:
4421
f.write(comment)
4522

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:
23+
def _create_comment(self, comparator: Comparator) -> str:
7224
comment = ""
73-
for package, missing_messages in all_missing_messages.items():
25+
for package, missing_messages, new_messages in comparator:
7426
if len(comment) >= MAX_GITHUB_COMMENT_LENGTH:
7527
break
76-
new_messages = all_new_messages[package]
77-
if not missing_messages["messages"] and not new_messages["messages"]:
78-
continue
7928
comment += self._create_comment_for_package(
8029
package, new_messages, missing_messages
8130
)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 pathlib import Path
6+
7+
import pytest
8+
9+
from pylint.testutils._primer.comparator import Comparator
10+
11+
FIXTURES_PATH = Path(__file__).parent / "fixtures"
12+
13+
14+
@pytest.mark.parametrize(
15+
("fixture", "main_file", "pr_file", "batches", "expected_packages", "expected_missing", "expected_new"),
16+
[
17+
pytest.param(
18+
"both_empty", "main.json", "pr.json", None, [], [], [],
19+
id="both_empty",
20+
),
21+
pytest.param(
22+
"no_change", "main.json", "pr.json", None, [], [], [],
23+
id="no_change",
24+
),
25+
pytest.param(
26+
"new_message", "main.json", "pr.json", None,
27+
["astroid"], [0], [1],
28+
id="new_message",
29+
),
30+
pytest.param(
31+
"removed_message", "main.json", "pr.json", None,
32+
["astroid"], [1], [0],
33+
id="removed_message",
34+
),
35+
pytest.param(
36+
"message_changed", "main.json", "pr.json", None,
37+
["astroid"], [1], [1],
38+
id="message_changed",
39+
),
40+
pytest.param(
41+
"batched", "main_BATCHIDX.json", "pr_BATCHIDX.json", 2,
42+
["astroid"], [2], [0],
43+
id="batched",
44+
),
45+
],
46+
)
47+
def test_comparator(
48+
fixture: str,
49+
main_file: str,
50+
pr_file: str,
51+
batches: int | None,
52+
expected_packages: list[str],
53+
expected_missing: list[int],
54+
expected_new: list[int],
55+
) -> None:
56+
directory = FIXTURES_PATH / fixture
57+
comparator = Comparator(str(directory / main_file), str(directory / pr_file), batches)
58+
results = list(comparator)
59+
assert len(results) == len(expected_packages)
60+
for (package, missing, new), exp_pkg, exp_miss, exp_new in zip(
61+
results, expected_packages, expected_missing, expected_new
62+
):
63+
assert package == exp_pkg
64+
assert len(missing["messages"]) == exp_miss
65+
assert len(new["messages"]) == exp_new
66+
# Iterating twice yields the same results
67+
assert results == list(comparator)

0 commit comments

Comments
 (0)