Skip to content

Commit 532be9a

Browse files
Add caching to bottlenecks in the message store (#5605)
Some functions can't be cached without impacting the correctness with the current design. Co-authored-by: Daniël van Noord <[email protected]>
1 parent e815843 commit 532be9a

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

pylint/lint/pylinter.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,11 @@ def _get_message_state_scope(
13891389
return None
13901390

13911391
def _is_one_message_enabled(self, msgid: str, line: Optional[int]) -> bool:
1392-
"""Checks state of a single message"""
1392+
"""Checks state of a single message for the current file
1393+
1394+
This function can't be cached as it depends on self.file_state which can
1395+
change.
1396+
"""
13931397
if line is None:
13941398
return self._msgs_state.get(msgid, True)
13951399
try:
@@ -1426,10 +1430,15 @@ def is_message_enabled(
14261430
line: Optional[int] = None,
14271431
confidence: Optional[interfaces.Confidence] = None,
14281432
) -> bool:
1429-
"""return whether the message associated to the given message id is
1430-
enabled
1433+
"""Return whether this message is enabled for the current file, line and confidence level.
1434+
1435+
This function can't be cached right now as the line is the line of
1436+
the currently analysed file (self.file_state), if it changes, then the
1437+
result for the same msg_descr/line might need to change.
14311438
1432-
msgid may be either a numeric or symbolic message id.
1439+
:param msg_descr: Either the msgid or the symbol for a MessageDefinition
1440+
:param line: The line of the currently analysed file
1441+
:param confidence: The confidence of the message
14331442
"""
14341443
if self.config.confidence and confidence:
14351444
if confidence.name not in self.config.confidence:

pylint/message/message_definition_store.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
33

44
import collections
5+
import functools
56
from typing import TYPE_CHECKING, Dict, List, Tuple, ValuesView
67

78
from pylint.exceptions import UnknownMessageError
@@ -46,8 +47,14 @@ def register_message(self, message: MessageDefinition) -> None:
4647
self._messages_definitions[message.msgid] = message
4748
self._msgs_by_category[message.msgid[0]].append(message.msgid)
4849

50+
@functools.lru_cache()
4951
def get_message_definitions(self, msgid_or_symbol: str) -> List[MessageDefinition]:
50-
"""Returns the Message definition for either a numeric or symbolic id."""
52+
"""Returns the Message definition for either a numeric or symbolic id.
53+
54+
The cache has no limit as its size will likely stay minimal. For each message we store
55+
about 1000 characters, so even if we would have 1000 messages the cache would only
56+
take up ~= 1 Mb.
57+
"""
5158
return [
5259
self._messages_definitions[m]
5360
for m in self.message_id_store.get_active_msgids(msgid_or_symbol)

pylint/message/message_id_store.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
3+
import functools
34
from typing import Dict, List, NoReturn, Optional, Tuple
45

56
from pylint.exceptions import InvalidMessageError, UnknownMessageError
@@ -101,18 +102,23 @@ def _raise_duplicate_msgid(symbol: str, msgid: str, other_msgid: str) -> NoRetur
101102
)
102103
raise InvalidMessageError(error_message)
103104

105+
@functools.lru_cache()
104106
def get_active_msgids(self, msgid_or_symbol: str) -> List[str]:
105-
"""Return msgids but the input can be a symbol."""
106-
# Only msgid can have a digit as second letter
107-
is_msgid: bool = msgid_or_symbol[1:].isdigit()
108-
msgid = None
109-
if is_msgid:
107+
"""Return msgids but the input can be a symbol.
108+
109+
The cache has no limit as its size will likely stay minimal. For each message we store
110+
about 1000 characters, so even if we would have 1000 messages the cache would only
111+
take up ~= 1 Mb.
112+
"""
113+
msgid: Optional[str]
114+
if msgid_or_symbol[1:].isdigit():
115+
# Only msgid can have a digit as second letter
110116
msgid = msgid_or_symbol.upper()
111117
symbol = self.__msgid_to_symbol.get(msgid)
112118
else:
113119
msgid = self.__symbol_to_msgid.get(msgid_or_symbol)
114120
symbol = msgid_or_symbol
115-
if msgid is None or symbol is None or not msgid or not symbol:
121+
if not msgid or not symbol:
116122
error_msg = f"No such message id or symbol '{msgid_or_symbol}'."
117123
raise UnknownMessageError(error_msg)
118124
return self.__old_names.get(msgid, [msgid])

0 commit comments

Comments
 (0)