Skip to content

Commit be149db

Browse files
Update functional test expected output (#5349)
* Add ``confidence`` to all expected functional test outputs * Make OutputLine accept end_line and end_column Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent c056248 commit be149db

File tree

427 files changed

+2889
-2748
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

427 files changed

+2889
-2748
lines changed

ChangeLog

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ Release date: TBA
4444

4545
* Fix exception when pyreverse parses ``property function`` of a class.
4646

47+
* The functional ``testutils`` now accept ``end_lineno`` and ``end_column``. Expected
48+
output files without these will trigger a ``DeprecationWarning``. Expected output files
49+
can be easily updated with the ``python tests/test_functional.py --update-functional-output`` command.
50+
51+
* The functional ``testutils`` now correctly check the distinction betweeen ``HIGH`` and
52+
``UNDEFINED`` confidence. Expected output files without defiend ``confidence`` levels will now
53+
trigger a ``DeprecationWarning``. Expected output files can be easily updated with the
54+
``python tests/test_functional.py --update-functional-output`` command.
55+
4756
* Fix ``accept-no-yields-doc`` and ``accept-no-return-doc`` not allowing missing ``yield`` or
4857
``return`` documentation when a docstring is partially correct
4958

doc/whatsnew/2.12.rst

+9
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ Other Changes
123123

124124
Closes #3031
125125

126+
* The functional ``testutils`` now accept ``end_lineno`` and ``end_column``. Expected
127+
output files without these will trigger a ``DeprecationWarning``. Expected output files
128+
can be easily updated with the ``python tests/test_functional.py --update-functional-output`` command.
129+
130+
* The functional ``testutils`` now correctly check the distinction betweeen ``HIGH`` and
131+
``UNDEFINED`` confidence. Expected output files without defiend ``confidence`` levels will now
132+
trigger a ``DeprecationWarning``. Expected output files can be easily updated with the
133+
``python tests/test_functional.py --update-functional-output`` command.
134+
126135
* ``undefined-variable`` now correctly flags variables which only receive a type annotations
127136
and never get assigned a value
128137

pylint/testutils/output_line.py

+88-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
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

67
from astroid import nodes
78

89
from pylint.constants import PY38_PLUS
9-
from pylint.interfaces import HIGH, UNDEFINED, Confidence
10+
from pylint.interfaces import UNDEFINED, Confidence
1011
from pylint.message.message import Message
1112
from pylint.testutils.constants import UPDATE_OPTION
1213

14+
T = TypeVar("T")
15+
1316

1417
class 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)
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
abstract-class-instantiated:108:4:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated:HIGH
2-
abstract-class-instantiated:109:4:main:Abstract class 'BadClass' with abstract methods instantiated:HIGH
3-
abstract-class-instantiated:110:4:main:Abstract class 'SecondBadClass' with abstract methods instantiated:HIGH
4-
abstract-class-instantiated:111:4:main:Abstract class 'ThirdBadClass' with abstract methods instantiated:HIGH
5-
abstract-class-instantiated:128:4:main2:Abstract class 'FourthBadClass' with abstract methods instantiated:HIGH
6-
abstract-class-instantiated:143:4:main_two:Abstract class 'BadClassTwo' with abstract methods instantiated:HIGH
1+
abstract-class-instantiated:108:4:108:27:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated:UNDEFINED
2+
abstract-class-instantiated:109:4:109:14:main:Abstract class 'BadClass' with abstract methods instantiated:UNDEFINED
3+
abstract-class-instantiated:110:4:110:20:main:Abstract class 'SecondBadClass' with abstract methods instantiated:UNDEFINED
4+
abstract-class-instantiated:111:4:111:19:main:Abstract class 'ThirdBadClass' with abstract methods instantiated:UNDEFINED
5+
abstract-class-instantiated:128:4:128:20:main2:Abstract class 'FourthBadClass' with abstract methods instantiated:UNDEFINED
6+
abstract-class-instantiated:143:4:143:17:main_two:Abstract class 'BadClassTwo' with abstract methods instantiated:UNDEFINED
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
abstract-method:47:0:Concrete:Method 'bbbb' is abstract in class 'Abstract' but is not overridden
2-
abstract-method:70:0:Container:Method '__hash__' is abstract in class 'Structure' but is not overridden
3-
abstract-method:70:0:Container:Method '__iter__' is abstract in class 'Structure' but is not overridden
4-
abstract-method:70:0:Container:Method '__len__' is abstract in class 'Structure' but is not overridden
5-
abstract-method:76:0:Sizable:Method '__contains__' is abstract in class 'Structure' but is not overridden
6-
abstract-method:76:0:Sizable:Method '__hash__' is abstract in class 'Structure' but is not overridden
7-
abstract-method:76:0:Sizable:Method '__iter__' is abstract in class 'Structure' but is not overridden
8-
abstract-method:82:0:Hashable:Method '__contains__' is abstract in class 'Structure' but is not overridden
9-
abstract-method:82:0:Hashable:Method '__iter__' is abstract in class 'Structure' but is not overridden
10-
abstract-method:82:0:Hashable:Method '__len__' is abstract in class 'Structure' but is not overridden
11-
abstract-method:87:0:Iterator:Method '__contains__' is abstract in class 'Structure' but is not overridden
12-
abstract-method:87:0:Iterator:Method '__hash__' is abstract in class 'Structure' but is not overridden
13-
abstract-method:87:0:Iterator:Method '__len__' is abstract in class 'Structure' but is not overridden
14-
abstract-method:106:0:BadComplexMro:Method '__hash__' is abstract in class 'Structure' but is not overridden
15-
abstract-method:106:0:BadComplexMro:Method '__len__' is abstract in class 'AbstractSizable' but is not overridden
16-
abstract-method:106:0:BadComplexMro:Method 'length' is abstract in class 'AbstractSizable' but is not overridden
1+
abstract-method:47:0:51:38:Concrete:Method 'bbbb' is abstract in class 'Abstract' but is not overridden:UNDEFINED
2+
abstract-method:70:0:72:12:Container:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
3+
abstract-method:70:0:72:12:Container:Method '__iter__' is abstract in class 'Structure' but is not overridden:UNDEFINED
4+
abstract-method:70:0:72:12:Container:Method '__len__' is abstract in class 'Structure' but is not overridden:UNDEFINED
5+
abstract-method:76:0:78:17:Sizable:Method '__contains__' is abstract in class 'Structure' but is not overridden:UNDEFINED
6+
abstract-method:76:0:78:17:Sizable:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
7+
abstract-method:76:0:78:17:Sizable:Method '__iter__' is abstract in class 'Structure' but is not overridden:UNDEFINED
8+
abstract-method:82:0:83:17:Hashable:Method '__contains__' is abstract in class 'Structure' but is not overridden:UNDEFINED
9+
abstract-method:82:0:83:17:Hashable:Method '__iter__' is abstract in class 'Structure' but is not overridden:UNDEFINED
10+
abstract-method:82:0:83:17:Hashable:Method '__len__' is abstract in class 'Structure' but is not overridden:UNDEFINED
11+
abstract-method:87:0:91:19:Iterator:Method '__contains__' is abstract in class 'Structure' but is not overridden:UNDEFINED
12+
abstract-method:87:0:91:19:Iterator:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
13+
abstract-method:87:0:91:19:Iterator:Method '__len__' is abstract in class 'Structure' but is not overridden:UNDEFINED
14+
abstract-method:106:0:107:8:BadComplexMro:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
15+
abstract-method:106:0:107:8:BadComplexMro:Method '__len__' is abstract in class 'AbstractSizable' but is not overridden:UNDEFINED
16+
abstract-method:106:0:107:8:BadComplexMro:Method 'length' is abstract in class 'AbstractSizable' but is not overridden:UNDEFINED
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
access-member-before-definition:8:15:Aaaa.__init__:Access to member '_var2' before its definition line 9
2-
access-member-before-definition:28:19:Bbbb.catchme:Access to member '_repo' before its definition line 30
1+
access-member-before-definition:8:15:8:25:Aaaa.__init__:Access to member '_var2' before its definition line 9:UNDEFINED
2+
access-member-before-definition:28:19:28:29:Bbbb.catchme:Access to member '_repo' before its definition line 30:UNDEFINED
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
no-member:10:14:Aaaa.__init__:Instance of 'Aaaa' has no '__name__' member:INFERENCE
2-
no-member:21:22:NewClass.__init__:Instance of 'NewClass' has no '__name__' member:INFERENCE
1+
no-member:10:14:10:27:Aaaa.__init__:Instance of 'Aaaa' has no '__name__' member:INFERENCE
2+
no-member:21:22:21:35:NewClass.__init__:Instance of 'NewClass' has no '__name__' member:INFERENCE
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
protected-access:19:14:MyClass.test:Access to a protected member _haha of a client class:HIGH
2-
protected-access:41:0::Access to a protected member _protected of a client class:HIGH
3-
protected-access:42:6::Access to a protected member _protected of a client class:HIGH
4-
protected-access:43:0::Access to a protected member _cls_protected of a client class:HIGH
5-
protected-access:44:6::Access to a protected member _cls_protected of a client class:HIGH
6-
protected-access:58:19:Issue1031.incorrect_access:Access to a protected member _protected of a client class:HIGH
7-
protected-access:72:48:Issue1802.__eq__:Access to a protected member __private of a client class:HIGH
8-
protected-access:80:32:Issue1802.not_in_special:Access to a protected member _foo of a client class:HIGH
9-
protected-access:100:32:Issue1802.__fake_special__:Access to a protected member _foo of a client class:HIGH
10-
protected-access:162:8:Issue1159.access_other_attr:Access to a protected member _bar of a client class:HIGH
11-
protected-access:163:12:Issue1159.access_other_attr:Access to a protected member _foo of a client class:HIGH
12-
no-member:194:12:Issue1159Subclass.access_missing_member:Instance of 'Issue1159Subclass' has no '_baz' member; maybe '_bar'?:INFERENCE
13-
protected-access:194:12:Issue1159Subclass.access_missing_member:Access to a protected member _baz of a client class:HIGH
14-
attribute-defined-outside-init:203:8:Issue1159Subclass.assign_missing_member:Attribute '_qux' defined outside __init__:HIGH
15-
protected-access:212:8:Issue1159Subclass.access_other_attr:Access to a protected member _bar of a client class:HIGH
16-
protected-access:213:12:Issue1159Subclass.access_other_attr:Access to a protected member _foo of a client class:HIGH
17-
protected-access:232:8:Issue3066.foobar:Access to a protected member _attr of a client class:HIGH
18-
protected-access:233:8:Issue3066.foobar:Access to a protected member _attr of a client class:HIGH
19-
protected-access:236:8:Issue3066.foobar:Access to a protected member _bar of a client class:HIGH
20-
protected-access:237:8:Issue3066.foobar:Access to a protected member _bar of a client class:HIGH
21-
protected-access:247:12:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:HIGH
22-
protected-access:249:12:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:HIGH
23-
protected-access:251:12:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:HIGH
24-
protected-access:253:12:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:HIGH
25-
protected-access:267:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:HIGH
26-
protected-access:268:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:HIGH
27-
protected-access:271:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:HIGH
28-
protected-access:272:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:HIGH
1+
protected-access:19:14:19:31:MyClass.test:Access to a protected member _haha of a client class:UNDEFINED
2+
protected-access:41:0:41:15::Access to a protected member _protected of a client class:UNDEFINED
3+
protected-access:42:6:42:21::Access to a protected member _protected of a client class:UNDEFINED
4+
protected-access:43:0:43:19::Access to a protected member _cls_protected of a client class:UNDEFINED
5+
protected-access:44:6:44:25::Access to a protected member _cls_protected of a client class:UNDEFINED
6+
protected-access:58:19:58:40:Issue1031.incorrect_access:Access to a protected member _protected of a client class:UNDEFINED
7+
protected-access:72:48:72:63:Issue1802.__eq__:Access to a protected member __private of a client class:UNDEFINED
8+
protected-access:80:32:80:42:Issue1802.not_in_special:Access to a protected member _foo of a client class:UNDEFINED
9+
protected-access:100:32:100:42:Issue1802.__fake_special__:Access to a protected member _foo of a client class:UNDEFINED
10+
protected-access:162:8:162:21:Issue1159.access_other_attr:Access to a protected member _bar of a client class:UNDEFINED
11+
protected-access:163:12:163:25:Issue1159.access_other_attr:Access to a protected member _foo of a client class:UNDEFINED
12+
no-member:194:12:194:25:Issue1159Subclass.access_missing_member:Instance of 'Issue1159Subclass' has no '_baz' member; maybe '_bar'?:INFERENCE
13+
protected-access:194:12:194:25:Issue1159Subclass.access_missing_member:Access to a protected member _baz of a client class:UNDEFINED
14+
attribute-defined-outside-init:203:8:203:21:Issue1159Subclass.assign_missing_member:Attribute '_qux' defined outside __init__:UNDEFINED
15+
protected-access:212:8:212:21:Issue1159Subclass.access_other_attr:Access to a protected member _bar of a client class:UNDEFINED
16+
protected-access:213:12:213:25:Issue1159Subclass.access_other_attr:Access to a protected member _foo of a client class:UNDEFINED
17+
protected-access:232:8:232:30:Issue3066.foobar:Access to a protected member _attr of a client class:UNDEFINED
18+
protected-access:233:8:233:37:Issue3066.foobar:Access to a protected member _attr of a client class:UNDEFINED
19+
protected-access:236:8:236:29:Issue3066.foobar:Access to a protected member _bar of a client class:UNDEFINED
20+
protected-access:237:8:237:36:Issue3066.foobar:Access to a protected member _bar of a client class:UNDEFINED
21+
protected-access:247:12:247:27:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
22+
protected-access:249:12:249:41:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
23+
protected-access:251:12:251:26:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:UNDEFINED
24+
protected-access:253:12:253:40:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:UNDEFINED
25+
protected-access:267:16:267:31:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
26+
protected-access:268:16:268:38:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
27+
protected-access:271:16:271:30:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:UNDEFINED
28+
protected-access:272:16:272:37:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:UNDEFINED

0 commit comments

Comments
 (0)