1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt
from __future__ import annotations
import json
import sys
import warnings
from io import StringIO
from pylint.lint import Run
from pylint.message import Message
from pylint.reporters import JSONReporter
from pylint.reporters.json_reporter import OldJsonExport
from pylint.testutils._primer.package_to_lint import PackageToLint
from pylint.testutils._primer.primer_command import PrimerCommand
GITHUB_CRASH_TEMPLATE_LOCATION = "/home/runner/.cache"
CRASH_TEMPLATE_INTRO = "There is a pre-filled template"
class RunCommand(PrimerCommand):
def run(self) -> None:
packages: dict[str, list[OldJsonExport]] = {}
astroid_errors: list[Message] = []
other_fatal_msgs: list[Message] = []
for package, data in self.packages.items():
messages, p_astroid_errors, p_other_fatal_msgs = self._lint_package(
package, data
)
astroid_errors += p_astroid_errors
other_fatal_msgs += p_other_fatal_msgs
packages[package] = messages
plural = "s" if len(other_fatal_msgs) > 1 else ""
assert not other_fatal_msgs, (
f"We encountered {len(other_fatal_msgs)} fatal error message{plural}"
" that can't be attributed to bleeding edge astroid alone (see log)."
)
path = (
self.primer_directory
/ f"output_{'.'.join(str(i) for i in sys.version_info[:3])}_{self.config.type}.txt"
)
print(f"Writing result in {path}")
with open(path, "w", encoding="utf-8") as f:
json.dump(packages, f)
@staticmethod
def _filter_astroid_errors(
messages: list[OldJsonExport],
) -> tuple[list[Message], list[Message]]:
"""Separate fatal errors caused by astroid so we can report them
independently.
"""
astroid_errors = []
other_fatal_msgs = []
for raw_message in messages:
message = JSONReporter.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.
# We were falsely getting "new" errors when the timestamp changed.
message.msg = message.msg.rsplit(CRASH_TEMPLATE_INTRO)[0]
if message.symbol == "astroid-error":
astroid_errors.append(message)
else:
other_fatal_msgs.append(message)
return astroid_errors, other_fatal_msgs
@staticmethod
def _print_msgs(msgs: list[Message]) -> str:
return "\n".join(f"- {JSONReporter.serialize(m)}" for m in msgs)
def _lint_package(
self, package_name: str, data: PackageToLint
) -> tuple[list[OldJsonExport], list[Message], 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
# TODO: Find a way to allow cyclic-import and compare output correctly
disables = ["--disable=duplicate-code,cyclic-import"]
arguments = data.pylint_args + enables + disables
output = StringIO()
reporter = JSONReporter(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)
readable_messages: str = output.getvalue()
messages: list[OldJsonExport] = json.loads(readable_messages)
astroid_errors: list[Message] = []
other_fatal_msgs: list[Message] = []
if pylint_exit_code % 2 == 0:
print(f"Successfully primed {package_name}.")
else:
astroid_errors, other_fatal_msgs = self._filter_astroid_errors(messages)
print(f"Encountered fatal errors while priming {package_name} !\n")
if other_fatal_msgs:
print(
"Fatal messages unrelated to astroid:\n"
f"{self._print_msgs(other_fatal_msgs)}\n\n"
)
if astroid_errors:
warnings.warn(
f"Fatal messages that could be related to bleeding edge astroid:\n"
f"{self._print_msgs(astroid_errors)}\n\n"
)
return messages, astroid_errors, other_fatal_msgs
|