2018-12-18 22:16:34 +00:00
|
|
|
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
2021-07-01 10:47:58 +00:00
|
|
|
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
|
2022-03-01 15:04:49 +00:00
|
|
|
# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt
|
2018-12-18 22:16:34 +00:00
|
|
|
|
2022-04-14 08:08:13 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2018-12-18 22:16:34 +00:00
|
|
|
import collections
|
2021-12-29 10:13:27 +00:00
|
|
|
import functools
|
2022-04-14 08:08:13 +00:00
|
|
|
from typing import TYPE_CHECKING, ValuesView
|
2018-12-18 22:16:34 +00:00
|
|
|
|
2019-08-10 11:16:34 +00:00
|
|
|
from pylint.exceptions import UnknownMessageError
|
2021-05-30 16:30:14 +00:00
|
|
|
from pylint.message.message_definition import MessageDefinition
|
2019-08-10 11:16:34 +00:00
|
|
|
from pylint.message.message_id_store import MessageIdStore
|
2018-12-18 22:16:34 +00:00
|
|
|
|
2021-10-02 13:52:48 +00:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from pylint.checkers import BaseChecker
|
|
|
|
|
2018-12-18 22:16:34 +00:00
|
|
|
|
2019-07-06 15:37:34 +00:00
|
|
|
class MessageDefinitionStore:
|
2018-12-09 17:26:02 +00:00
|
|
|
|
2019-08-10 11:16:34 +00:00
|
|
|
"""The messages store knows information about every possible message definition but has
|
2018-12-18 22:16:34 +00:00
|
|
|
no particular state during analysis.
|
|
|
|
"""
|
|
|
|
|
2021-10-02 13:52:48 +00:00
|
|
|
def __init__(self) -> None:
|
2021-05-30 16:30:14 +00:00
|
|
|
self.message_id_store: MessageIdStore = MessageIdStore()
|
2019-08-10 11:16:34 +00:00
|
|
|
# Primary registry for all active messages definitions.
|
|
|
|
# It contains the 1:1 mapping from msgid to MessageDefinition.
|
|
|
|
# Keys are msgid, values are MessageDefinition
|
2022-04-14 08:08:13 +00:00
|
|
|
self._messages_definitions: dict[str, MessageDefinition] = {}
|
2019-08-10 11:16:34 +00:00
|
|
|
# MessageDefinition kept by category
|
2022-04-14 08:08:13 +00:00
|
|
|
self._msgs_by_category: dict[str, list[str]] = collections.defaultdict(list)
|
2018-12-18 22:16:34 +00:00
|
|
|
|
|
|
|
@property
|
2021-05-30 16:30:14 +00:00
|
|
|
def messages(self) -> ValuesView[MessageDefinition]:
|
2018-12-18 22:16:34 +00:00
|
|
|
"""The list of all active messages."""
|
|
|
|
return self._messages_definitions.values()
|
|
|
|
|
2022-04-14 08:08:13 +00:00
|
|
|
def register_messages_from_checker(self, checker: BaseChecker) -> None:
|
2021-05-30 16:30:14 +00:00
|
|
|
"""Register all messages definitions from a checker."""
|
2018-12-25 16:54:23 +00:00
|
|
|
checker.check_consistency()
|
|
|
|
for message in checker.messages:
|
|
|
|
self.register_message(message)
|
2018-12-18 22:16:34 +00:00
|
|
|
|
2021-05-30 16:30:14 +00:00
|
|
|
def register_message(self, message: MessageDefinition) -> None:
|
|
|
|
"""Register a MessageDefinition with consistency in mind."""
|
2021-05-31 18:00:53 +00:00
|
|
|
self.message_id_store.register_message_definition(
|
|
|
|
message.msgid, message.symbol, message.old_names
|
|
|
|
)
|
2019-08-10 11:16:34 +00:00
|
|
|
self._messages_definitions[message.msgid] = message
|
2018-12-18 22:16:34 +00:00
|
|
|
self._msgs_by_category[message.msgid[0]].append(message.msgid)
|
|
|
|
|
2022-04-05 14:25:42 +00:00
|
|
|
# Since MessageDefinitionStore is only initialized once
|
|
|
|
# and the arguments are relatively small in size we do not run the
|
2022-01-14 08:37:48 +00:00
|
|
|
# risk of creating a large memory leak.
|
|
|
|
# See discussion in: https://github.com/PyCQA/pylint/pull/5673
|
2022-04-05 14:25:42 +00:00
|
|
|
@functools.lru_cache(maxsize=None) # pylint: disable=cache-max-size-none
|
2022-04-14 08:08:13 +00:00
|
|
|
def get_message_definitions(self, msgid_or_symbol: str) -> list[MessageDefinition]:
|
2021-12-29 10:13:27 +00:00
|
|
|
"""Returns the Message definition for either a numeric or symbolic id.
|
|
|
|
|
|
|
|
The cache has no limit as its size will likely stay minimal. For each message we store
|
|
|
|
about 1000 characters, so even if we would have 1000 messages the cache would only
|
|
|
|
take up ~= 1 Mb.
|
|
|
|
"""
|
2019-08-10 16:28:36 +00:00
|
|
|
return [
|
|
|
|
self._messages_definitions[m]
|
|
|
|
for m in self.message_id_store.get_active_msgids(msgid_or_symbol)
|
|
|
|
]
|
2019-08-10 11:16:34 +00:00
|
|
|
|
2021-05-30 16:30:14 +00:00
|
|
|
def get_msg_display_string(self, msgid_or_symbol: str) -> str:
|
2021-04-26 11:59:44 +00:00
|
|
|
"""Generates a user-consumable representation of a message."""
|
2019-08-10 11:16:34 +00:00
|
|
|
message_definitions = self.get_message_definitions(msgid_or_symbol)
|
2018-12-18 22:16:34 +00:00
|
|
|
if len(message_definitions) == 1:
|
|
|
|
return repr(message_definitions[0].symbol)
|
|
|
|
return repr([md.symbol for md in message_definitions])
|
|
|
|
|
2022-04-14 08:08:13 +00:00
|
|
|
def help_message(self, msgids_or_symbols: list[str]) -> None:
|
2022-02-10 18:30:15 +00:00
|
|
|
"""Display help messages for the given message identifiers."""
|
2019-08-10 11:16:34 +00:00
|
|
|
for msgids_or_symbol in msgids_or_symbols:
|
2018-12-18 22:16:34 +00:00
|
|
|
try:
|
2019-08-10 11:16:34 +00:00
|
|
|
for message_definition in self.get_message_definitions(
|
|
|
|
msgids_or_symbol
|
|
|
|
):
|
2018-12-18 22:16:34 +00:00
|
|
|
print(message_definition.format_help(checkerref=True))
|
|
|
|
print("")
|
|
|
|
except UnknownMessageError as ex:
|
|
|
|
print(ex)
|
|
|
|
print("")
|
|
|
|
continue
|
|
|
|
|
2021-05-30 16:30:14 +00:00
|
|
|
def list_messages(self) -> None:
|
2021-04-26 11:59:44 +00:00
|
|
|
"""Output full messages list documentation in ReST format."""
|
2021-08-03 20:05:11 +00:00
|
|
|
emittable, non_emittable = self.find_emittable_messages()
|
|
|
|
print("Emittable messages with current interpreter:")
|
|
|
|
for msg in emittable:
|
|
|
|
print(msg.format_help(checkerref=False))
|
|
|
|
print("\nNon-emittable messages with current interpreter:")
|
|
|
|
for msg in non_emittable:
|
|
|
|
print(msg.format_help(checkerref=False))
|
|
|
|
print("")
|
|
|
|
|
|
|
|
def find_emittable_messages(
|
|
|
|
self,
|
2022-04-14 08:08:13 +00:00
|
|
|
) -> tuple[list[MessageDefinition], list[MessageDefinition]]:
|
2022-02-10 18:30:15 +00:00
|
|
|
"""Finds all emittable and non-emittable messages."""
|
2018-12-18 22:16:34 +00:00
|
|
|
messages = sorted(self._messages_definitions.values(), key=lambda m: m.msgid)
|
2021-08-03 20:05:11 +00:00
|
|
|
emittable = []
|
|
|
|
non_emittable = []
|
2018-12-18 22:16:34 +00:00
|
|
|
for message in messages:
|
2021-08-03 20:05:11 +00:00
|
|
|
if message.may_be_emitted():
|
|
|
|
emittable.append(message)
|
|
|
|
else:
|
|
|
|
non_emittable.append(message)
|
|
|
|
return emittable, non_emittable
|