1
1
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
2
2
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
3
3
4
- from typing import Any , NamedTuple , Optional , Sequence , Tuple , Union
4
+ import warnings
5
+ from typing import Any , NamedTuple , Optional , Sequence , Tuple , TypeVar , Union
5
6
6
7
from astroid import nodes
7
8
8
9
from pylint .constants import PY38_PLUS
9
- from pylint .interfaces import HIGH , UNDEFINED , Confidence
10
+ from pylint .interfaces import UNDEFINED , Confidence
10
11
from pylint .message .message import Message
11
12
from pylint .testutils .constants import UPDATE_OPTION
12
13
14
+ T = TypeVar ("T" )
15
+
13
16
14
17
class MessageTest (NamedTuple ):
15
18
msg_id : str
@@ -33,6 +36,8 @@ def __init__(
33
36
"symbol" ,
34
37
"line" ,
35
38
"column" ,
39
+ "end_line" ,
40
+ "end_column" ,
36
41
"MyClass.myFunction, (or '')" ,
37
42
"Message" ,
38
43
"confidence" ,
@@ -61,41 +66,117 @@ class OutputLine(NamedTuple):
61
66
symbol : str
62
67
lineno : int
63
68
column : int
69
+ end_lineno : Optional [int ]
70
+ end_column : Optional [int ]
64
71
object : str
65
72
msg : str
66
73
confidence : str
67
74
68
75
@classmethod
69
76
def from_msg (cls , msg : Message ) -> "OutputLine" :
77
+ """Create an OutputLine from a Pylint Message"""
70
78
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 )
71
81
return cls (
72
82
msg .symbol ,
73
83
msg .line ,
74
84
column ,
85
+ end_line ,
86
+ end_column ,
75
87
msg .obj or "" ,
76
88
msg .msg .replace ("\r \n " , "\n " ),
77
- msg .confidence .name if msg . confidence != UNDEFINED else HIGH . name ,
89
+ msg .confidence .name ,
78
90
)
79
91
80
92
@staticmethod
81
93
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
+ """
82
97
if not PY38_PLUS :
83
98
# We check the column only for the new better ast parser introduced in python 3.8
84
99
return 0 # pragma: no cover
85
100
return int (column )
86
101
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
+
87
110
@classmethod
88
111
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
+ """
89
115
try :
90
116
if isinstance (row , Sequence ):
91
117
column = cls ._get_column (row [2 ])
92
118
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
+ )
94
135
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
+ )
96
158
raise IndexError
97
159
except Exception as e :
98
160
raise MalformedOutputLineException (row , e ) from e
99
161
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