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
33
4- from typing import Any , NamedTuple , Optional , Sequence , Tuple , Union
4+ import warnings
5+ from typing import Any , NamedTuple , Optional , Sequence , Tuple , TypeVar , Union
56
67from astroid import nodes
78
89from pylint .constants import PY38_PLUS
9- from pylint .interfaces import HIGH , UNDEFINED , Confidence
10+ from pylint .interfaces import UNDEFINED , Confidence
1011from pylint .message .message import Message
1112from pylint .testutils .constants import UPDATE_OPTION
1213
14+ T = TypeVar ("T" )
15+
1316
1417class MessageTest (NamedTuple ):
1518 msg_id : str
@@ -33,6 +36,8 @@ def __init__(
3336 "symbol" ,
3437 "line" ,
3538 "column" ,
39+ "end_line" ,
40+ "end_column" ,
3641 "MyClass.myFunction, (or '')" ,
3742 "Message" ,
3843 "confidence" ,
@@ -61,41 +66,117 @@ class OutputLine(NamedTuple):
6166 symbol : str
6267 lineno : int
6368 column : int
69+ end_lineno : Optional [int ]
70+ end_column : Optional [int ]
6471 object : str
6572 msg : str
6673 confidence : str
6774
6875 @classmethod
6976 def from_msg (cls , msg : Message ) -> "OutputLine" :
77+ """Create an OutputLine from a Pylint Message"""
7078 column = cls ._get_column (msg .column )
79+ end_line = cls ._get_py38_none_value (msg .end_line )
80+ end_column = cls ._get_py38_none_value (msg .end_column )
7181 return cls (
7282 msg .symbol ,
7383 msg .line ,
7484 column ,
85+ end_line ,
86+ end_column ,
7587 msg .obj or "" ,
7688 msg .msg .replace ("\r \n " , "\n " ),
77- msg .confidence .name if msg . confidence != UNDEFINED else HIGH . name ,
89+ msg .confidence .name ,
7890 )
7991
8092 @staticmethod
8193 def _get_column (column : str ) -> int :
94+ """Handle column numbers with the exception of pylint < 3.8 not having them
95+ in the ast parser.
96+ """
8297 if not PY38_PLUS :
8398 # We check the column only for the new better ast parser introduced in python 3.8
8499 return 0 # pragma: no cover
85100 return int (column )
86101
102+ @staticmethod
103+ def _get_py38_none_value (value : T ) -> Optional [T ]:
104+ """Handle attributes that are always None on pylint < 3.8 similar to _get_column."""
105+ if not PY38_PLUS :
106+ # We check the value only for the new better ast parser introduced in python 3.8
107+ return None # pragma: no cover
108+ return value
109+
87110 @classmethod
88111 def from_csv (cls , row : Union [Sequence [str ], str ]) -> "OutputLine" :
112+ """Create an OutputLine from a comma separated list (the functional tests expected
113+ output .txt files).
114+ """
89115 try :
90116 if isinstance (row , Sequence ):
91117 column = cls ._get_column (row [2 ])
92118 if len (row ) == 5 :
93- return cls (row [0 ], int (row [1 ]), column , row [3 ], row [4 ], HIGH .name )
119+ warnings .warn (
120+ "In pylint 3.0 functional tests expected output should always include the "
121+ "expected confidence level, expected end_line and expected end_column. "
122+ "An OutputLine should thus have a length of 8." ,
123+ DeprecationWarning ,
124+ )
125+ return cls (
126+ row [0 ],
127+ int (row [1 ]),
128+ column ,
129+ None ,
130+ None ,
131+ row [3 ],
132+ row [4 ],
133+ UNDEFINED .name ,
134+ )
94135 if len (row ) == 6 :
95- return cls (row [0 ], int (row [1 ]), column , row [3 ], row [4 ], row [5 ])
136+ warnings .warn (
137+ "In pylint 3.0 functional tests expected output should always include the "
138+ "expected end_line and expected end_column. An OutputLine should thus have "
139+ "a length of 8." ,
140+ DeprecationWarning ,
141+ )
142+ return cls (
143+ row [0 ], int (row [1 ]), column , None , None , row [3 ], row [4 ], row [5 ]
144+ )
145+ if len (row ) == 8 :
146+ end_line = cls ._get_py38_none_value (row [3 ])
147+ end_column = cls ._get_py38_none_value (row [4 ])
148+ return cls (
149+ row [0 ],
150+ int (row [1 ]),
151+ column ,
152+ cls ._value_to_optional_int (end_line ),
153+ cls ._value_to_optional_int (end_column ),
154+ row [5 ],
155+ row [6 ],
156+ row [7 ],
157+ )
96158 raise IndexError
97159 except Exception as e :
98160 raise MalformedOutputLineException (row , e ) from e
99161
100- def to_csv (self ) -> Tuple [str , str , str , str , str , str ]:
101- return tuple (str (i ) for i in self ) # type: ignore[return-value] # pylint: disable=not-an-iterable
162+ def to_csv (self ) -> Tuple [str , str , str , str , str , str , str , str ]:
163+ """Convert an OutputLine to a tuple of string to be written by a
164+ csv-writer.
165+ """
166+ return (
167+ str (self .symbol ),
168+ str (self .lineno ),
169+ str (self .column ),
170+ str (self .end_lineno ),
171+ str (self .end_column ),
172+ str (self .object ),
173+ str (self .msg ),
174+ str (self .confidence ),
175+ )
176+
177+ @staticmethod
178+ def _value_to_optional_int (value : Optional [str ]) -> Optional [int ]:
179+ """Checks if a (stringified) value should be None or a Python integer"""
180+ if value == "None" or not value :
181+ return None
182+ return int (value )
0 commit comments