mirror of
https://fuchsia.googlesource.com/third_party/github.com/pylint-dev/pylint
synced 2024-09-21 16:19:21 +00:00
5124f5409f
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
# 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
|
|
|
|
import collections
|
|
from typing import Any, NamedTuple, Optional, Sequence, Tuple, Union
|
|
|
|
from astroid import nodes
|
|
|
|
from pylint.constants import PY38_PLUS
|
|
from pylint.interfaces import HIGH, UNDEFINED, Confidence
|
|
from pylint.message.message import Message
|
|
from pylint.testutils.constants import UPDATE_OPTION
|
|
|
|
|
|
class MessageTest(
|
|
collections.namedtuple(
|
|
"MessageTest", ["msg_id", "line", "node", "args", "confidence"]
|
|
)
|
|
):
|
|
"""Used to test messages produced by pylint. Class name cannot start with Test as pytest doesn't allow constructors in test classes."""
|
|
|
|
def __new__(
|
|
cls,
|
|
msg_id: str,
|
|
line: Optional[int] = None,
|
|
node: Optional[nodes.NodeNG] = None,
|
|
args: Any = None,
|
|
confidence: Optional[Confidence] = None,
|
|
) -> "MessageTest":
|
|
return tuple.__new__(cls, (msg_id, line, node, args, confidence))
|
|
|
|
def __eq__(self, other: object) -> bool:
|
|
if isinstance(other, MessageTest):
|
|
if self.confidence and other.confidence:
|
|
return super().__eq__(other)
|
|
return tuple(self[:-1]) == tuple(other[:-1])
|
|
return NotImplemented # pragma: no cover
|
|
|
|
|
|
class MalformedOutputLineException(Exception):
|
|
def __init__(
|
|
self,
|
|
row: Union[Sequence[str], str],
|
|
exception: Exception,
|
|
) -> None:
|
|
example = "msg-symbolic-name:42:27:MyClass.my_function:The message"
|
|
other_example = "msg-symbolic-name:7:42::The message"
|
|
expected = [
|
|
"symbol",
|
|
"line",
|
|
"column",
|
|
"MyClass.myFunction, (or '')",
|
|
"Message",
|
|
"confidence",
|
|
]
|
|
reconstructed_row = ""
|
|
i = 0
|
|
try:
|
|
for i, column in enumerate(row):
|
|
reconstructed_row += f"\t{expected[i]}='{column}' ?\n"
|
|
for missing in expected[i + 1 :]:
|
|
reconstructed_row += f"\t{missing}= Nothing provided !\n"
|
|
except IndexError:
|
|
pass
|
|
raw = ":".join(row)
|
|
msg = f"""\
|
|
{exception}
|
|
|
|
Expected '{example}' or '{other_example}' but we got '{raw}':
|
|
{reconstructed_row}
|
|
|
|
Try updating it with: 'python tests/test_functional.py {UPDATE_OPTION}'"""
|
|
Exception.__init__(self, msg)
|
|
|
|
|
|
class OutputLine(NamedTuple):
|
|
symbol: str
|
|
lineno: int
|
|
column: int
|
|
object: str
|
|
msg: str
|
|
confidence: str
|
|
|
|
@classmethod
|
|
def from_msg(cls, msg: Message) -> "OutputLine":
|
|
column = cls._get_column(msg.column)
|
|
return cls(
|
|
msg.symbol,
|
|
msg.line,
|
|
column,
|
|
msg.obj or "",
|
|
msg.msg.replace("\r\n", "\n"),
|
|
msg.confidence.name if msg.confidence != UNDEFINED else HIGH.name,
|
|
)
|
|
|
|
@staticmethod
|
|
def _get_column(column: str) -> int:
|
|
if not PY38_PLUS:
|
|
# We check the column only for the new better ast parser introduced in python 3.8
|
|
return 0 # pragma: no cover
|
|
return int(column)
|
|
|
|
@classmethod
|
|
def from_csv(cls, row: Union[Sequence[str], str]) -> "OutputLine":
|
|
try:
|
|
if isinstance(row, Sequence):
|
|
column = cls._get_column(row[2])
|
|
if len(row) == 5:
|
|
return cls(row[0], int(row[1]), column, row[3], row[4], HIGH.name)
|
|
if len(row) == 6:
|
|
return cls(row[0], int(row[1]), column, row[3], row[4], row[5])
|
|
raise IndexError
|
|
except Exception as e:
|
|
raise MalformedOutputLineException(row, e) from e
|
|
|
|
def to_csv(self) -> Tuple[str, str, str, str, str, str]:
|
|
return tuple(str(i) for i in self) # type: ignore # pylint: disable=not-an-iterable
|