Skip to content

Commit 71bbbdb

Browse files
authored
Check node location attributes in unittests and update tests (#5383)
* Allow checking of `end_col_offset` and `end_lineno` in unittests * Allow checking of `col_offset` in unittests * Allow checking of `lineno` in unittests * Update tests for ``TestVariablesChecker`` * Fix ``TestMultiNamingStyle`` * Update tests for ``TestImportsChecker`` * Add location attributes to messages of ``TestTypeChecker`` * Add location params to ``TestMessage``'s of ``TestDeprecatedChecker`` * Add location params to ``TestMessage``'s of ``TestTypeCheckerOnDecorators`` * Add changelog and ``DeprecationWarning``
1 parent 78eed6a commit 71bbbdb

File tree

10 files changed

+239
-15
lines changed

10 files changed

+239
-15
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ Release date: TBA
6767

6868
Closes #5371
6969

70+
* The ``testutils`` for unittests now accept ``end_lineno`` and ``end_column``. Tests
71+
without these will trigger a ``DeprecationWarning``.
72+
7073
..
7174
Insert your changelog randomly, it will reduce merge conflicts
7275
(Ie. not necessarily at the end)

doc/whatsnew/2.13.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,6 @@ Other Changes
7070

7171
* The ``PyLinter`` class will now be initialiazed with a ``TextReporter``
7272
as its reporter if none is provided.
73+
74+
* The ``testutils`` for unittests now accept ``end_lineno`` and ``end_column``. Tests
75+
without these will trigger a ``DeprecationWarning``.

pylint/testutils/checker_test_case.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
33

44
import contextlib
5-
from typing import Dict, Optional, Type
5+
import warnings
6+
from typing import Dict, Generator, Optional, Type
67

8+
from pylint.constants import PY38_PLUS
79
from pylint.testutils.global_test_linter import linter
10+
from pylint.testutils.output_line import MessageTest
811
from pylint.testutils.unittest_linter import UnittestLinter
912
from pylint.utils import ASTWalker
1013

@@ -29,7 +32,7 @@ def assertNoMessages(self):
2932
yield
3033

3134
@contextlib.contextmanager
32-
def assertAddsMessages(self, *messages):
35+
def assertAddsMessages(self, *messages: MessageTest) -> Generator[None, None, None]:
3336
"""Assert that exactly the given method adds the given messages.
3437
3538
The list of messages must exactly match *all* the messages added by the
@@ -45,7 +48,33 @@ def assertAddsMessages(self, *messages):
4548
"Expected messages did not match actual.\n"
4649
f"\nExpected:\n{expected}\n\nGot:\n{got_str}\n"
4750
)
48-
assert got == list(messages), msg
51+
52+
assert len(messages) == len(got), msg
53+
54+
for expected_msg, gotten_msg in zip(messages, got):
55+
assert expected_msg.msg_id == gotten_msg.msg_id, msg
56+
assert expected_msg.line == gotten_msg.line, msg
57+
assert expected_msg.node == gotten_msg.node, msg
58+
assert expected_msg.args == gotten_msg.args, msg
59+
assert expected_msg.confidence == gotten_msg.confidence, msg
60+
assert expected_msg.col_offset == gotten_msg.col_offset, msg
61+
if PY38_PLUS:
62+
# pylint: disable=fixme
63+
# TODO: Require end_line and end_col_offset and remove the warning
64+
if not expected_msg.end_line == gotten_msg.end_line:
65+
warnings.warn(
66+
f"The end_line attribute of {gotten_msg} does not match "
67+
f"the expected value in {expected_msg}. In pylint 3.0 correct end_line "
68+
"attributes will be required for MessageTest.",
69+
DeprecationWarning,
70+
)
71+
if not expected_msg.end_col_offset == gotten_msg.end_col_offset:
72+
warnings.warn(
73+
f"The end_col_offset attribute of {gotten_msg} does not match "
74+
f"the expected value in {expected_msg}. In pylint 3.0 correct end_col_offset "
75+
"attributes will be required for MessageTest.",
76+
DeprecationWarning,
77+
)
4978

5079
def walk(self, node):
5180
"""recursive walk on the given node"""

pylint/testutils/output_line.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class MessageTest(NamedTuple):
2121
args: Optional[Any] = None
2222
confidence: Optional[Confidence] = UNDEFINED
2323
col_offset: Optional[int] = None
24+
end_line: Optional[int] = None
25+
end_col_offset: Optional[int] = None
2426
"""Used to test messages produced by pylint. Class name cannot start with Test as pytest doesn't allow constructors in test classes."""
2527

2628

pylint/testutils/unittest_linter.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ def add_message(
3030
self,
3131
msg_id: str,
3232
line: Optional[int] = None,
33+
# pylint: disable=fixme
34+
# TODO: Make node non optional
3335
node: Optional[nodes.NodeNG] = None,
3436
args: Any = None,
3537
confidence: Optional[Confidence] = None,
@@ -41,16 +43,28 @@ def add_message(
4143
# If confidence is None we set it to UNDEFINED as well in PyLinter
4244
if confidence is None:
4345
confidence = UNDEFINED
46+
if not line and node:
47+
line = node.fromlineno
4448
# pylint: disable=fixme
45-
# TODO: Test col_offset
46-
# pylint: disable=fixme
47-
# TODO: Initialize col_offset on every node (can be None) -> astroid
48-
# if col_offset is None and hasattr(node, "col_offset"):
49-
# col_offset = node.col_offset
50-
# pylint: disable=fixme
51-
# TODO: Test end_lineno and end_col_offset :)
49+
# TODO: Initialize col_offset, end_lineno and end_col_offset on every node -> astroid
50+
# See https://github.com/PyCQA/astroid/issues/1273
51+
if col_offset is None and node and hasattr(node, "col_offset"):
52+
col_offset = node.col_offset
53+
if not end_lineno and node and hasattr(node, "end_lineno"):
54+
end_lineno = node.end_lineno
55+
if not end_col_offset and node and hasattr(node, "end_col_offset"):
56+
end_col_offset = node.end_col_offset
5257
self._messages.append(
53-
MessageTest(msg_id, line, node, args, confidence, col_offset)
58+
MessageTest(
59+
msg_id,
60+
line,
61+
node,
62+
args,
63+
confidence,
64+
col_offset,
65+
end_lineno,
66+
end_col_offset,
67+
)
5468
)
5569

5670
@staticmethod

tests/checkers/unittest_base.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ class CLASSC(object): #@
6464
"the `UP` group in the '(?:(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern",
6565
),
6666
confidence=HIGH,
67+
line=2,
68+
col_offset=0,
69+
end_line=3,
70+
end_col_offset=8,
6771
)
6872
with self.assertAddsMessages(message):
6973
cls = None
@@ -94,6 +98,10 @@ class CLASSC(object): #@
9498
"'(?:(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern",
9599
),
96100
confidence=HIGH,
101+
line=2,
102+
col_offset=0,
103+
end_line=3,
104+
end_col_offset=8,
97105
),
98106
MessageTest(
99107
"invalid-name",
@@ -104,6 +112,10 @@ class CLASSC(object): #@
104112
"the `down` group in the '(?:(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern",
105113
),
106114
confidence=HIGH,
115+
line=6,
116+
col_offset=0,
117+
end_line=7,
118+
end_col_offset=8,
107119
),
108120
]
109121
with self.assertAddsMessages(*messages):
@@ -139,6 +151,10 @@ def FUNC(): #@
139151
"the `down` group in the '(?:(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern",
140152
),
141153
confidence=HIGH,
154+
line=6,
155+
col_offset=0,
156+
end_line=7,
157+
end_col_offset=8,
142158
)
143159
with self.assertAddsMessages(message):
144160
func = None
@@ -172,6 +188,10 @@ def UPPER(): #@
172188
"the `down` group in the '(?:(?P<ignore>FOO)|(?P<UP>[A-Z]+)|(?P<down>[a-z]+))$' pattern",
173189
),
174190
confidence=HIGH,
191+
line=8,
192+
col_offset=0,
193+
end_line=9,
194+
end_col_offset=8,
175195
)
176196
with self.assertAddsMessages(message):
177197
func = None

0 commit comments

Comments
 (0)