Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 25 additions & 19 deletions pylint/testutils/_primer/comparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,50 @@
from collections.abc import Generator
from pathlib import Path

from pylint.reporters.json_reporter import OldJsonExport
from pylint.reporters.json_reporter import JSONMessage
from pylint.testutils._primer.primer_command import (
PackageData,
PackageMessages,
)


class Comparator:
def __init__(
self, base_file: str, new_file: str, batches: int | None = None
) -> None:
self._base_file = base_file
self._new_file = new_file
self._batches = batches
"""Cross-reference two primer JSON outputs and iterate over differences."""

def __iter__(self) -> Generator[tuple[str, PackageData, PackageData]]:
def __init__(self, main_data: PackageMessages, pr_data: PackageMessages) -> None:
self._main_data = main_data
self._pr_data = pr_data

@staticmethod
def from_json(
base_file: Path | str, new_file: Path | str, batches: int | None = None
) -> Comparator:
"""Build a Comparator from JSON file paths, handling batched runs."""
main_data: PackageMessages
if self._batches is None:
main_data = self._load_json(self._base_file)
pr_data = self._load_json(self._new_file)
pr_data: PackageMessages
if batches is None:
main_data = Comparator._load_json(base_file)
pr_data = Comparator._load_json(new_file)
else:
main_data = {}
pr_data = {}
for idx in range(self._batches):
for idx in range(batches):
suffix = f"batch{idx}"
main_data.update(
self._load_json(
self._base_file.replace("BATCHIDX", "batch" + str(idx))
)
Comparator._load_json(str(base_file).replace("BATCHIDX", suffix))
)
pr_data.update(
self._load_json(
self._new_file.replace("BATCHIDX", "batch" + str(idx))
)
Comparator._load_json(str(new_file).replace("BATCHIDX", suffix))
)
return Comparator(main_data, pr_data)

def __iter__(self) -> Generator[tuple[str, PackageData, PackageData]]:
main_data = self._main_data
pr_data = self._pr_data

missing_messages: PackageMessages = {}
for package, data in main_data.items():
package_missing_messages: list[OldJsonExport] = []
package_missing_messages: list[JSONMessage] = []
for message in data["messages"]:
try:
pr_data[package]["messages"].remove(message)
Expand Down
4 changes: 2 additions & 2 deletions pylint/testutils/_primer/primer_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
from pathlib import Path
from typing import TypedDict

from pylint.reporters.json_reporter import OldJsonExport
from pylint.reporters.json_reporter import JSONMessage
from pylint.testutils._primer import PackageToLint


class PackageData(TypedDict):
commit: str
messages: list[OldJsonExport]
messages: list[JSONMessage]


PackageMessages = dict[str, PackageData]
Expand Down
2 changes: 1 addition & 1 deletion pylint/testutils/_primer/primer_compare_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

class CompareCommand(PrimerCommand):
def run(self) -> None:
comparator = Comparator(
comparator = Comparator.from_json(
self.config.base_file, self.config.new_file, self.config.batches
)
comment = self._create_comment(comparator)
Expand Down
14 changes: 7 additions & 7 deletions pylint/testutils/_primer/primer_run_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from pylint.lint import Run
from pylint.message import Message
from pylint.reporters.json_reporter import JSONReporter, OldJsonExport
from pylint.reporters.json_reporter import JSON2Reporter, JSONMessage
from pylint.testutils._primer.package_to_lint import PackageToLint
from pylint.testutils._primer.primer_command import (
PackageData,
Expand Down Expand Up @@ -57,12 +57,12 @@ def run(self) -> None:

@staticmethod
def _filter_fatal_errors(
messages: list[OldJsonExport],
messages: list[JSONMessage],
) -> list[Message]:
"""Separate fatal errors so we can report them independently."""
fatal_msgs: list[Message] = []
for raw_message in messages:
message = JSONReporter.deserialize(raw_message)
message = JSON2Reporter.deserialize(raw_message)
if message.category == "fatal":
if GITHUB_CRASH_TEMPLATE_LOCATION in message.msg:
# Remove the crash template location if we're running on GitHub.
Expand All @@ -73,11 +73,11 @@ def _filter_fatal_errors(

@staticmethod
def _print_msgs(msgs: list[Message]) -> str:
return "\n".join(f"- {JSONReporter.serialize(m)}" for m in msgs)
return "\n".join(f"- {JSON2Reporter.serialize(m)}" for m in msgs)

def _lint_package(
self, package_name: str, data: PackageToLint
) -> tuple[list[OldJsonExport], list[Message]]:
) -> tuple[list[JSONMessage], list[Message]]:
# We want to test all the code we can
enables = ["--enable-all-extensions", "--enable=all"]
# Duplicate code takes too long and is relatively safe
Expand All @@ -86,15 +86,15 @@ def _lint_package(
additional = ["--clear-cache-post-run=y"]
arguments = data.pylint_args + enables + disables + additional
output = StringIO()
reporter = JSONReporter(output)
reporter = JSON2Reporter(output)
print(f"Running 'pylint {', '.join(arguments)}'")
pylint_exit_code = -1
try:
Run(arguments, reporter=reporter)
except SystemExit as e:
pylint_exit_code = int(e.code) # type: ignore[arg-type]
readable_messages: str = output.getvalue()
messages: list[OldJsonExport] = json.loads(readable_messages)
messages: list[JSONMessage] = json.loads(readable_messages)["messages"]
fatal_msgs: list[Message] = []
if pylint_exit_code % 2 == 0:
print(f"Successfully primed {package_name}.")
Expand Down
8 changes: 6 additions & 2 deletions tests/testutils/_primer/batched_cases/main_batch1.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "locally-disabled",
"message": "Locally disabling redefined-builtin (W0622)",
"message-id": "I0011"
"messageId": "I0011",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
},
{
"type": "warning",
Expand All @@ -26,7 +28,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "unknown-option-value",
"message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'",
"message-id": "W0012"
"messageId": "W0012",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
}
]
}
Expand Down
24 changes: 24 additions & 0 deletions tests/testutils/_primer/cases/confidence_changed/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
🤖 **Effect of this PR on checked open source code:** 🤖


**Effect on [astroid](https://github.com/pylint-dev/astroid):**

The following messages are now emitted:

<details>

1) dangerous-default-value:
*Dangerous default value [] as argument*
https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/inference.py#L42
</details>

The following messages are no longer emitted:

<details>

1) dangerous-default-value:
*Dangerous default value [] as argument*
https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/inference.py#L42
</details>

*This comment was generated for commit v2.14.2*
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{ "package": "astroid", "missing": 1, "new": 1 }]
22 changes: 22 additions & 0 deletions tests/testutils/_primer/cases/confidence_changed/main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"astroid": {
"commit": "123456789abcdef",
"messages": [
{
"type": "warning",
"module": "astroid.inference",
"obj": "infer_call",
"line": 42,
"column": 0,
"endLine": 42,
"endColumn": 15,
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/inference.py",
"symbol": "dangerous-default-value",
"message": "Dangerous default value [] as argument",
"messageId": "W0102",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/inference.py"
}
]
}
}
22 changes: 22 additions & 0 deletions tests/testutils/_primer/cases/confidence_changed/pr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"astroid": {
"commit": "123456789abcdef",
"messages": [
{
"type": "warning",
"module": "astroid.inference",
"obj": "infer_call",
"line": 42,
"column": 0,
"endLine": 42,
"endColumn": 15,
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/inference.py",
"symbol": "dangerous-default-value",
"message": "Dangerous default value [] as argument",
"messageId": "W0102",
"confidence": "HIGH",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/inference.py"
}
]
}
}
4 changes: 3 additions & 1 deletion tests/testutils/_primer/cases/line_moved/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py",
"symbol": "too-complex",
"message": "'my_function' is too complex. The McCabe rating is 18",
"message-id": "R1260"
"messageId": "R1260",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py"
}
]
}
Expand Down
4 changes: 3 additions & 1 deletion tests/testutils/_primer/cases/line_moved/pr.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py",
"symbol": "too-complex",
"message": "'my_function' is too complex. The McCabe rating is 18",
"message-id": "R1260"
"messageId": "R1260",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py"
}
]
}
Expand Down
8 changes: 6 additions & 2 deletions tests/testutils/_primer/cases/message_changed/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "locally-disabled",
"message": "Locally disabling redefined-builtin (W0622)",
"message-id": "I0011"
"messageId": "I0011",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
},
{
"type": "warning",
Expand All @@ -26,7 +28,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "unknown-option-value",
"message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'",
"message-id": "W0012"
"messageId": "W0012",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
}
]
}
Expand Down
8 changes: 6 additions & 2 deletions tests/testutils/_primer/cases/message_changed/pr.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "locally-disabled",
"message": "Locally disabling redefined-builtin [we added some text in the message] (W0622)",
"message-id": "I0011"
"messageId": "I0011",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
},
{
"type": "warning",
Expand All @@ -26,7 +28,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "unknown-option-value",
"message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'",
"message-id": "W0012"
"messageId": "W0012",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
}
]
}
Expand Down
8 changes: 6 additions & 2 deletions tests/testutils/_primer/cases/message_changed_line/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py",
"symbol": "too-complex",
"message": "'my_function' is too complex. The McCabe rating is 18",
"message-id": "R1260"
"messageId": "R1260",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py"
},
{
"type": "warning",
Expand All @@ -26,7 +28,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "unknown-option-value",
"message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'",
"message-id": "W0012"
"messageId": "W0012",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
}
]
}
Expand Down
8 changes: 6 additions & 2 deletions tests/testutils/_primer/cases/message_changed_line/pr.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py",
"symbol": "too-complex",
"message": "'my_function' is too complex. The McCabe rating is 17",
"message-id": "R1260"
"messageId": "R1260",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py"
},
{
"type": "warning",
Expand All @@ -26,7 +28,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "unknown-option-value",
"message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'",
"message-id": "W0012"
"messageId": "W0012",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
}
]
}
Expand Down
12 changes: 9 additions & 3 deletions tests/testutils/_primer/cases/mixed_changes/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "locally-disabled",
"message": "Locally disabling redefined-builtin (W0622)",
"message-id": "I0011"
"messageId": "I0011",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
},
{
"type": "convention",
Expand All @@ -26,7 +28,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py",
"symbol": "too-complex",
"message": "'my_function' is too complex. The McCabe rating is 18",
"message-id": "R1260"
"messageId": "R1260",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py"
},
{
"type": "warning",
Expand All @@ -39,7 +43,9 @@
"path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py",
"symbol": "unknown-option-value",
"message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'",
"message-id": "W0012"
"messageId": "W0012",
"confidence": "UNDEFINED",
"absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py"
}
]
}
Expand Down
Loading
Loading