output_line.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. from __future__ import annotations
  5. from collections.abc import Sequence
  6. from typing import Any, NamedTuple, TypeVar
  7. from astroid import nodes
  8. from pylint.interfaces import UNDEFINED, Confidence
  9. from pylint.message.message import Message
  10. _T = TypeVar("_T")
  11. class MessageTest(NamedTuple):
  12. msg_id: str
  13. line: int | None = None
  14. node: nodes.NodeNG | None = None
  15. args: Any | None = None
  16. confidence: Confidence | None = UNDEFINED
  17. col_offset: int | None = None
  18. end_line: int | None = None
  19. end_col_offset: int | None = None
  20. """Used to test messages produced by pylint.
  21. Class name cannot start with Test as pytest doesn't allow constructors in test classes.
  22. """
  23. class OutputLine(NamedTuple):
  24. symbol: str
  25. lineno: int
  26. column: int
  27. end_lineno: int | None
  28. end_column: int | None
  29. object: str
  30. msg: str
  31. confidence: str
  32. @classmethod
  33. def from_msg(cls, msg: Message, check_endline: bool = True) -> OutputLine:
  34. """Create an OutputLine from a Pylint Message."""
  35. column = cls._get_column(msg.column)
  36. end_line = cls._get_end_line_and_end_col(msg.end_line, check_endline)
  37. end_column = cls._get_end_line_and_end_col(msg.end_column, check_endline)
  38. return cls(
  39. msg.symbol,
  40. msg.line,
  41. column,
  42. end_line,
  43. end_column,
  44. msg.obj or "",
  45. msg.msg.replace("\r\n", "\n"),
  46. msg.confidence.name,
  47. )
  48. @staticmethod
  49. def _get_column(column: str | int) -> int:
  50. """Handle column numbers."""
  51. return int(column)
  52. @staticmethod
  53. def _get_end_line_and_end_col(value: _T, check_endline: bool) -> _T | None:
  54. """Used to make end_line and end_column None as indicated by our version
  55. compared to `min_pyver_end_position`.
  56. """
  57. if not check_endline:
  58. return None # pragma: no cover
  59. return value
  60. @classmethod
  61. def from_csv(
  62. cls, row: Sequence[str] | str, check_endline: bool = True
  63. ) -> OutputLine:
  64. """Create an OutputLine from a comma separated list (the functional tests
  65. expected output .txt files).
  66. """
  67. if isinstance(row, str):
  68. row = row.split(",")
  69. try:
  70. line = int(row[1])
  71. column = cls._get_column(row[2])
  72. end_line = cls._value_to_optional_int(
  73. cls._get_end_line_and_end_col(row[3], check_endline)
  74. )
  75. end_column = cls._value_to_optional_int(
  76. cls._get_end_line_and_end_col(row[4], check_endline)
  77. )
  78. # symbol, line, column, end_line, end_column, node, msg, confidences
  79. assert len(row) == 8
  80. return cls(
  81. row[0], line, column, end_line, end_column, row[5], row[6], row[7]
  82. )
  83. except Exception: # pylint: disable=broad-except
  84. # We need this to not fail for the update script to work.
  85. return cls("", 0, 0, None, None, "", "", "")
  86. def to_csv(self) -> tuple[str, str, str, str, str, str, str, str]:
  87. """Convert an OutputLine to a tuple of string to be written by a
  88. csv-writer.
  89. """
  90. return (
  91. str(self.symbol),
  92. str(self.lineno),
  93. str(self.column),
  94. str(self.end_lineno),
  95. str(self.end_column),
  96. str(self.object),
  97. str(self.msg),
  98. str(self.confidence),
  99. )
  100. @staticmethod
  101. def _value_to_optional_int(value: str | None) -> int | None:
  102. """Checks if a (stringified) value should be None or a Python integer."""
  103. if value == "None" or not value:
  104. return None
  105. return int(value)