message_definition_store.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  2. # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
  3. import collections
  4. from typing import TYPE_CHECKING, Dict, List, Tuple, ValuesView
  5. from pylint.exceptions import UnknownMessageError
  6. from pylint.message.message_definition import MessageDefinition
  7. from pylint.message.message_id_store import MessageIdStore
  8. if TYPE_CHECKING:
  9. from pylint.checkers import BaseChecker
  10. class MessageDefinitionStore:
  11. """The messages store knows information about every possible message definition but has
  12. no particular state during analysis.
  13. """
  14. def __init__(self) -> None:
  15. self.message_id_store: MessageIdStore = MessageIdStore()
  16. # Primary registry for all active messages definitions.
  17. # It contains the 1:1 mapping from msgid to MessageDefinition.
  18. # Keys are msgid, values are MessageDefinition
  19. self._messages_definitions: Dict[str, MessageDefinition] = {}
  20. # MessageDefinition kept by category
  21. self._msgs_by_category: Dict[str, List[str]] = collections.defaultdict(list)
  22. @property
  23. def messages(self) -> ValuesView[MessageDefinition]:
  24. """The list of all active messages."""
  25. return self._messages_definitions.values()
  26. def register_messages_from_checker(self, checker: "BaseChecker") -> None:
  27. """Register all messages definitions from a checker."""
  28. checker.check_consistency()
  29. for message in checker.messages:
  30. self.register_message(message)
  31. def register_message(self, message: MessageDefinition) -> None:
  32. """Register a MessageDefinition with consistency in mind."""
  33. self.message_id_store.register_message_definition(
  34. message.msgid, message.symbol, message.old_names
  35. )
  36. self._messages_definitions[message.msgid] = message
  37. self._msgs_by_category[message.msgid[0]].append(message.msgid)
  38. def get_message_definitions(self, msgid_or_symbol: str) -> List[MessageDefinition]:
  39. """Returns the Message definition for either a numeric or symbolic id."""
  40. return [
  41. self._messages_definitions[m]
  42. for m in self.message_id_store.get_active_msgids(msgid_or_symbol)
  43. ]
  44. def get_msg_display_string(self, msgid_or_symbol: str) -> str:
  45. """Generates a user-consumable representation of a message."""
  46. message_definitions = self.get_message_definitions(msgid_or_symbol)
  47. if len(message_definitions) == 1:
  48. return repr(message_definitions[0].symbol)
  49. return repr([md.symbol for md in message_definitions])
  50. def help_message(self, msgids_or_symbols: List[str]) -> None:
  51. """Display help messages for the given message identifiers"""
  52. for msgids_or_symbol in msgids_or_symbols:
  53. try:
  54. for message_definition in self.get_message_definitions(
  55. msgids_or_symbol
  56. ):
  57. print(message_definition.format_help(checkerref=True))
  58. print("")
  59. except UnknownMessageError as ex:
  60. print(ex)
  61. print("")
  62. continue
  63. def list_messages(self) -> None:
  64. """Output full messages list documentation in ReST format."""
  65. emittable, non_emittable = self.find_emittable_messages()
  66. print("Emittable messages with current interpreter:")
  67. for msg in emittable:
  68. print(msg.format_help(checkerref=False))
  69. print("\nNon-emittable messages with current interpreter:")
  70. for msg in non_emittable:
  71. print(msg.format_help(checkerref=False))
  72. print("")
  73. def find_emittable_messages(
  74. self,
  75. ) -> Tuple[List[MessageDefinition], List[MessageDefinition]]:
  76. """Finds all emittable and non-emittable messages"""
  77. messages = sorted(self._messages_definitions.values(), key=lambda m: m.msgid)
  78. emittable = []
  79. non_emittable = []
  80. for message in messages:
  81. if message.may_be_emitted():
  82. emittable.append(message)
  83. else:
  84. non_emittable.append(message)
  85. return emittable, non_emittable