Coverage for C:\Repos\ekr-pylint\pylint\message\message_definition.py: 24%

74 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-24 10:21 -0500

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# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt 

4 

5from __future__ import annotations 

6 

7import sys 

8from typing import TYPE_CHECKING, Any 

9 

10from astroid import nodes 

11 

12from pylint.constants import _SCOPE_EXEMPT, MSG_TYPES, WarningScope 

13from pylint.exceptions import InvalidMessageError 

14from pylint.utils import normalize_text 

15 

16if TYPE_CHECKING: 

17 from pylint.checkers import BaseChecker 

18 

19 

20class MessageDefinition: 

21 def __init__( 

22 self, 

23 checker: BaseChecker, 

24 msgid: str, 

25 msg: str, 

26 description: str, 

27 symbol: str, 

28 scope: str, 

29 minversion: tuple[int, int] | None = None, 

30 maxversion: tuple[int, int] | None = None, 

31 old_names: list[tuple[str, str]] | None = None, 

32 ) -> None: 

33 self.checker_name = checker.name 

34 self.check_msgid(msgid) 

35 self.msgid = msgid 

36 self.symbol = symbol 

37 self.msg = msg 

38 self.description = description 

39 self.scope = scope 

40 self.minversion = minversion 

41 self.maxversion = maxversion 

42 self.old_names: list[tuple[str, str]] = [] 

43 if old_names: 

44 for old_msgid, old_symbol in old_names: 

45 self.check_msgid(old_msgid) 

46 self.old_names.append( 

47 (old_msgid, old_symbol), 

48 ) 

49 

50 @staticmethod 

51 def check_msgid(msgid: str) -> None: 

52 if len(msgid) != 5: 

53 raise InvalidMessageError(f"Invalid message id {msgid!r}") 

54 if msgid[0] not in MSG_TYPES: 

55 raise InvalidMessageError(f"Bad message type {msgid[0]} in {msgid!r}") 

56 

57 def __eq__(self, other: Any) -> bool: 

58 return ( 

59 isinstance(other, MessageDefinition) 

60 and self.msgid == other.msgid 

61 and self.symbol == other.symbol 

62 ) 

63 

64 def __repr__(self) -> str: 

65 return f"MessageDefinition:{self.symbol} ({self.msgid})" 

66 

67 def __str__(self) -> str: 

68 return f"{repr(self)}:\n{self.msg} {self.description}" 

69 

70 def may_be_emitted(self) -> bool: 

71 """Return True if message may be emitted using the current interpreter.""" 

72 if self.minversion is not None and self.minversion > sys.version_info: 

73 return False 

74 if self.maxversion is not None and self.maxversion <= sys.version_info: 

75 return False 

76 return True 

77 

78 def format_help(self, checkerref: bool = False) -> str: 

79 """Return the help string for the given message id.""" 

80 desc = self.description 

81 if checkerref: 

82 desc += f" This message belongs to the {self.checker_name} checker." 

83 title = self.msg 

84 if self.minversion or self.maxversion: 

85 restr = [] 

86 if self.minversion: 

87 restr.append(f"< {'.'.join(str(n) for n in self.minversion)}") 

88 if self.maxversion: 

89 restr.append(f">= {'.'.join(str(n) for n in self.maxversion)}") 

90 restriction = " or ".join(restr) 

91 if checkerref: 

92 desc += f" It can't be emitted when using Python {restriction}." 

93 else: 

94 desc += ( 

95 f" This message can't be emitted when using Python {restriction}." 

96 ) 

97 msg_help = normalize_text(" ".join(desc.split()), indent=" ") 

98 message_id = f"{self.symbol} ({self.msgid})" 

99 if title != "%s": 

100 title = title.splitlines()[0] 

101 return f":{message_id}: *{title.rstrip(' ')}*\n{msg_help}" 

102 return f":{message_id}:\n{msg_help}" 

103 

104 def check_message_definition( 

105 self, line: int | None, node: nodes.NodeNG | None 

106 ) -> None: 

107 """Check MessageDefinition for possible errors.""" 

108 if self.msgid[0] not in _SCOPE_EXEMPT: 

109 # Fatal messages and reports are special, the node/scope distinction 

110 # does not apply to them. 

111 if self.scope == WarningScope.LINE: 

112 if line is None: 

113 raise InvalidMessageError( 

114 f"Message {self.msgid} must provide line, got None" 

115 ) 

116 if node is not None: 

117 raise InvalidMessageError( 

118 f"Message {self.msgid} must only provide line, " 

119 f"got line={line}, node={node}" 

120 ) 

121 elif self.scope == WarningScope.NODE: 

122 # Node-based warnings may provide an override line. 

123 if node is None: 

124 raise InvalidMessageError( 

125 f"Message {self.msgid} must provide Node, got None" 

126 )