Skip to content

Commit

Permalink
Update functional test expected output (#5349)
Browse files Browse the repository at this point in the history
* Add ``confidence`` to all expected functional test outputs
* Make OutputLine accept end_line and end_column

Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
  • Loading branch information
DanielNoord and Pierre-Sassoulas committed Nov 24, 2021
1 parent c056248 commit be149db
Show file tree
Hide file tree
Showing 427 changed files with 2,889 additions and 2,748 deletions.
9 changes: 9 additions & 0 deletions ChangeLog
Expand Up @@ -44,6 +44,15 @@ Release date: TBA

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

* The functional ``testutils`` now accept ``end_lineno`` and ``end_column``. Expected
output files without these will trigger a ``DeprecationWarning``. Expected output files
can be easily updated with the ``python tests/test_functional.py --update-functional-output`` command.

* The functional ``testutils`` now correctly check the distinction betweeen ``HIGH`` and
``UNDEFINED`` confidence. Expected output files without defiend ``confidence`` levels will now
trigger a ``DeprecationWarning``. Expected output files can be easily updated with the
``python tests/test_functional.py --update-functional-output`` command.

* Fix ``accept-no-yields-doc`` and ``accept-no-return-doc`` not allowing missing ``yield`` or
``return`` documentation when a docstring is partially correct

Expand Down
9 changes: 9 additions & 0 deletions doc/whatsnew/2.12.rst
Expand Up @@ -123,6 +123,15 @@ Other Changes

Closes #3031

* The functional ``testutils`` now accept ``end_lineno`` and ``end_column``. Expected
output files without these will trigger a ``DeprecationWarning``. Expected output files
can be easily updated with the ``python tests/test_functional.py --update-functional-output`` command.

* The functional ``testutils`` now correctly check the distinction betweeen ``HIGH`` and
``UNDEFINED`` confidence. Expected output files without defiend ``confidence`` levels will now
trigger a ``DeprecationWarning``. Expected output files can be easily updated with the
``python tests/test_functional.py --update-functional-output`` command.

* ``undefined-variable`` now correctly flags variables which only receive a type annotations
and never get assigned a value

Expand Down
95 changes: 88 additions & 7 deletions pylint/testutils/output_line.py
@@ -1,15 +1,18 @@
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE

from typing import Any, NamedTuple, Optional, Sequence, Tuple, Union
import warnings
from typing import Any, NamedTuple, Optional, Sequence, Tuple, TypeVar, Union

from astroid import nodes

from pylint.constants import PY38_PLUS
from pylint.interfaces import HIGH, UNDEFINED, Confidence
from pylint.interfaces import UNDEFINED, Confidence
from pylint.message.message import Message
from pylint.testutils.constants import UPDATE_OPTION

T = TypeVar("T")


class MessageTest(NamedTuple):
msg_id: str
Expand All @@ -33,6 +36,8 @@ def __init__(
"symbol",
"line",
"column",
"end_line",
"end_column",
"MyClass.myFunction, (or '')",
"Message",
"confidence",
Expand Down Expand Up @@ -61,41 +66,117 @@ class OutputLine(NamedTuple):
symbol: str
lineno: int
column: int
end_lineno: Optional[int]
end_column: Optional[int]
object: str
msg: str
confidence: str

@classmethod
def from_msg(cls, msg: Message) -> "OutputLine":
"""Create an OutputLine from a Pylint Message"""
column = cls._get_column(msg.column)
end_line = cls._get_py38_none_value(msg.end_line)
end_column = cls._get_py38_none_value(msg.end_column)
return cls(
msg.symbol,
msg.line,
column,
end_line,
end_column,
msg.obj or "",
msg.msg.replace("\r\n", "\n"),
msg.confidence.name if msg.confidence != UNDEFINED else HIGH.name,
msg.confidence.name,
)

@staticmethod
def _get_column(column: str) -> int:
"""Handle column numbers with the exception of pylint < 3.8 not having them
in the ast parser.
"""
if not PY38_PLUS:
# We check the column only for the new better ast parser introduced in python 3.8
return 0 # pragma: no cover
return int(column)

@staticmethod
def _get_py38_none_value(value: T) -> Optional[T]:
"""Handle attributes that are always None on pylint < 3.8 similar to _get_column."""
if not PY38_PLUS:
# We check the value only for the new better ast parser introduced in python 3.8
return None # pragma: no cover
return value

@classmethod
def from_csv(cls, row: Union[Sequence[str], str]) -> "OutputLine":
"""Create an OutputLine from a comma separated list (the functional tests expected
output .txt files).
"""
try:
if isinstance(row, Sequence):
column = cls._get_column(row[2])
if len(row) == 5:
return cls(row[0], int(row[1]), column, row[3], row[4], HIGH.name)
warnings.warn(
"In pylint 3.0 functional tests expected output should always include the "
"expected confidence level, expected end_line and expected end_column. "
"An OutputLine should thus have a length of 8.",
DeprecationWarning,
)
return cls(
row[0],
int(row[1]),
column,
None,
None,
row[3],
row[4],
UNDEFINED.name,
)
if len(row) == 6:
return cls(row[0], int(row[1]), column, row[3], row[4], row[5])
warnings.warn(
"In pylint 3.0 functional tests expected output should always include the "
"expected end_line and expected end_column. An OutputLine should thus have "
"a length of 8.",
DeprecationWarning,
)
return cls(
row[0], int(row[1]), column, None, None, row[3], row[4], row[5]
)
if len(row) == 8:
end_line = cls._get_py38_none_value(row[3])
end_column = cls._get_py38_none_value(row[4])
return cls(
row[0],
int(row[1]),
column,
cls._value_to_optional_int(end_line),
cls._value_to_optional_int(end_column),
row[5],
row[6],
row[7],
)
raise IndexError
except Exception as e:
raise MalformedOutputLineException(row, e) from e

def to_csv(self) -> Tuple[str, str, str, str, str, str]:
return tuple(str(i) for i in self) # type: ignore[return-value] # pylint: disable=not-an-iterable
def to_csv(self) -> Tuple[str, str, str, str, str, str, str, str]:
"""Convert an OutputLine to a tuple of string to be written by a
csv-writer.
"""
return (
str(self.symbol),
str(self.lineno),
str(self.column),
str(self.end_lineno),
str(self.end_column),
str(self.object),
str(self.msg),
str(self.confidence),
)

@staticmethod
def _value_to_optional_int(value: Optional[str]) -> Optional[int]:
"""Checks if a (stringified) value should be None or a Python integer"""
if value == "None" or not value:
return None
return int(value)
12 changes: 6 additions & 6 deletions tests/functional/a/abstract/abstract_class_instantiated.txt
@@ -1,6 +1,6 @@
abstract-class-instantiated:108:4:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated:HIGH
abstract-class-instantiated:109:4:main:Abstract class 'BadClass' with abstract methods instantiated:HIGH
abstract-class-instantiated:110:4:main:Abstract class 'SecondBadClass' with abstract methods instantiated:HIGH
abstract-class-instantiated:111:4:main:Abstract class 'ThirdBadClass' with abstract methods instantiated:HIGH
abstract-class-instantiated:128:4:main2:Abstract class 'FourthBadClass' with abstract methods instantiated:HIGH
abstract-class-instantiated:143:4:main_two:Abstract class 'BadClassTwo' with abstract methods instantiated:HIGH
abstract-class-instantiated:108:4:108:27:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated:UNDEFINED
abstract-class-instantiated:109:4:109:14:main:Abstract class 'BadClass' with abstract methods instantiated:UNDEFINED
abstract-class-instantiated:110:4:110:20:main:Abstract class 'SecondBadClass' with abstract methods instantiated:UNDEFINED
abstract-class-instantiated:111:4:111:19:main:Abstract class 'ThirdBadClass' with abstract methods instantiated:UNDEFINED
abstract-class-instantiated:128:4:128:20:main2:Abstract class 'FourthBadClass' with abstract methods instantiated:UNDEFINED
abstract-class-instantiated:143:4:143:17:main_two:Abstract class 'BadClassTwo' with abstract methods instantiated:UNDEFINED
32 changes: 16 additions & 16 deletions tests/functional/a/abstract/abstract_method.txt
@@ -1,16 +1,16 @@
abstract-method:47:0:Concrete:Method 'bbbb' is abstract in class 'Abstract' but is not overridden
abstract-method:70:0:Container:Method '__hash__' is abstract in class 'Structure' but is not overridden
abstract-method:70:0:Container:Method '__iter__' is abstract in class 'Structure' but is not overridden
abstract-method:70:0:Container:Method '__len__' is abstract in class 'Structure' but is not overridden
abstract-method:76:0:Sizable:Method '__contains__' is abstract in class 'Structure' but is not overridden
abstract-method:76:0:Sizable:Method '__hash__' is abstract in class 'Structure' but is not overridden
abstract-method:76:0:Sizable:Method '__iter__' is abstract in class 'Structure' but is not overridden
abstract-method:82:0:Hashable:Method '__contains__' is abstract in class 'Structure' but is not overridden
abstract-method:82:0:Hashable:Method '__iter__' is abstract in class 'Structure' but is not overridden
abstract-method:82:0:Hashable:Method '__len__' is abstract in class 'Structure' but is not overridden
abstract-method:87:0:Iterator:Method '__contains__' is abstract in class 'Structure' but is not overridden
abstract-method:87:0:Iterator:Method '__hash__' is abstract in class 'Structure' but is not overridden
abstract-method:87:0:Iterator:Method '__len__' is abstract in class 'Structure' but is not overridden
abstract-method:106:0:BadComplexMro:Method '__hash__' is abstract in class 'Structure' but is not overridden
abstract-method:106:0:BadComplexMro:Method '__len__' is abstract in class 'AbstractSizable' but is not overridden
abstract-method:106:0:BadComplexMro:Method 'length' is abstract in class 'AbstractSizable' but is not overridden
abstract-method:47:0:51:38:Concrete:Method 'bbbb' is abstract in class 'Abstract' but is not overridden:UNDEFINED
abstract-method:70:0:72:12:Container:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:70:0:72:12:Container:Method '__iter__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:70:0:72:12:Container:Method '__len__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:76:0:78:17:Sizable:Method '__contains__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:76:0:78:17:Sizable:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:76:0:78:17:Sizable:Method '__iter__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:82:0:83:17:Hashable:Method '__contains__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:82:0:83:17:Hashable:Method '__iter__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:82:0:83:17:Hashable:Method '__len__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:87:0:91:19:Iterator:Method '__contains__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:87:0:91:19:Iterator:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:87:0:91:19:Iterator:Method '__len__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:106:0:107:8:BadComplexMro:Method '__hash__' is abstract in class 'Structure' but is not overridden:UNDEFINED
abstract-method:106:0:107:8:BadComplexMro:Method '__len__' is abstract in class 'AbstractSizable' but is not overridden:UNDEFINED
abstract-method:106:0:107:8:BadComplexMro:Method 'length' is abstract in class 'AbstractSizable' but is not overridden:UNDEFINED
4 changes: 2 additions & 2 deletions tests/functional/a/access/access_member_before_definition.txt
@@ -1,2 +1,2 @@
access-member-before-definition:8:15:Aaaa.__init__:Access to member '_var2' before its definition line 9
access-member-before-definition:28:19:Bbbb.catchme:Access to member '_repo' before its definition line 30
access-member-before-definition:8:15:8:25:Aaaa.__init__:Access to member '_var2' before its definition line 9:UNDEFINED
access-member-before-definition:28:19:28:29:Bbbb.catchme:Access to member '_repo' before its definition line 30:UNDEFINED
4 changes: 2 additions & 2 deletions tests/functional/a/access/access_to__name__.txt
@@ -1,2 +1,2 @@
no-member:10:14:Aaaa.__init__:Instance of 'Aaaa' has no '__name__' member:INFERENCE
no-member:21:22:NewClass.__init__:Instance of 'NewClass' has no '__name__' member:INFERENCE
no-member:10:14:10:27:Aaaa.__init__:Instance of 'Aaaa' has no '__name__' member:INFERENCE
no-member:21:22:21:35:NewClass.__init__:Instance of 'NewClass' has no '__name__' member:INFERENCE
56 changes: 28 additions & 28 deletions tests/functional/a/access/access_to_protected_members.txt
@@ -1,28 +1,28 @@
protected-access:19:14:MyClass.test:Access to a protected member _haha of a client class:HIGH
protected-access:41:0::Access to a protected member _protected of a client class:HIGH
protected-access:42:6::Access to a protected member _protected of a client class:HIGH
protected-access:43:0::Access to a protected member _cls_protected of a client class:HIGH
protected-access:44:6::Access to a protected member _cls_protected of a client class:HIGH
protected-access:58:19:Issue1031.incorrect_access:Access to a protected member _protected of a client class:HIGH
protected-access:72:48:Issue1802.__eq__:Access to a protected member __private of a client class:HIGH
protected-access:80:32:Issue1802.not_in_special:Access to a protected member _foo of a client class:HIGH
protected-access:100:32:Issue1802.__fake_special__:Access to a protected member _foo of a client class:HIGH
protected-access:162:8:Issue1159.access_other_attr:Access to a protected member _bar of a client class:HIGH
protected-access:163:12:Issue1159.access_other_attr:Access to a protected member _foo of a client class:HIGH
no-member:194:12:Issue1159Subclass.access_missing_member:Instance of 'Issue1159Subclass' has no '_baz' member; maybe '_bar'?:INFERENCE
protected-access:194:12:Issue1159Subclass.access_missing_member:Access to a protected member _baz of a client class:HIGH
attribute-defined-outside-init:203:8:Issue1159Subclass.assign_missing_member:Attribute '_qux' defined outside __init__:HIGH
protected-access:212:8:Issue1159Subclass.access_other_attr:Access to a protected member _bar of a client class:HIGH
protected-access:213:12:Issue1159Subclass.access_other_attr:Access to a protected member _foo of a client class:HIGH
protected-access:232:8:Issue3066.foobar:Access to a protected member _attr of a client class:HIGH
protected-access:233:8:Issue3066.foobar:Access to a protected member _attr of a client class:HIGH
protected-access:236:8:Issue3066.foobar:Access to a protected member _bar of a client class:HIGH
protected-access:237:8:Issue3066.foobar:Access to a protected member _bar of a client class:HIGH
protected-access:247:12:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:HIGH
protected-access:249:12:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:HIGH
protected-access:251:12:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:HIGH
protected-access:253:12:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:HIGH
protected-access:267:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:HIGH
protected-access:268:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:HIGH
protected-access:271:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:HIGH
protected-access:272:16:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:HIGH
protected-access:19:14:19:31:MyClass.test:Access to a protected member _haha of a client class:UNDEFINED
protected-access:41:0:41:15::Access to a protected member _protected of a client class:UNDEFINED
protected-access:42:6:42:21::Access to a protected member _protected of a client class:UNDEFINED
protected-access:43:0:43:19::Access to a protected member _cls_protected of a client class:UNDEFINED
protected-access:44:6:44:25::Access to a protected member _cls_protected of a client class:UNDEFINED
protected-access:58:19:58:40:Issue1031.incorrect_access:Access to a protected member _protected of a client class:UNDEFINED
protected-access:72:48:72:63:Issue1802.__eq__:Access to a protected member __private of a client class:UNDEFINED
protected-access:80:32:80:42:Issue1802.not_in_special:Access to a protected member _foo of a client class:UNDEFINED
protected-access:100:32:100:42:Issue1802.__fake_special__:Access to a protected member _foo of a client class:UNDEFINED
protected-access:162:8:162:21:Issue1159.access_other_attr:Access to a protected member _bar of a client class:UNDEFINED
protected-access:163:12:163:25:Issue1159.access_other_attr:Access to a protected member _foo of a client class:UNDEFINED
no-member:194:12:194:25:Issue1159Subclass.access_missing_member:Instance of 'Issue1159Subclass' has no '_baz' member; maybe '_bar'?:INFERENCE
protected-access:194:12:194:25:Issue1159Subclass.access_missing_member:Access to a protected member _baz of a client class:UNDEFINED
attribute-defined-outside-init:203:8:203:21:Issue1159Subclass.assign_missing_member:Attribute '_qux' defined outside __init__:UNDEFINED
protected-access:212:8:212:21:Issue1159Subclass.access_other_attr:Access to a protected member _bar of a client class:UNDEFINED
protected-access:213:12:213:25:Issue1159Subclass.access_other_attr:Access to a protected member _foo of a client class:UNDEFINED
protected-access:232:8:232:30:Issue3066.foobar:Access to a protected member _attr of a client class:UNDEFINED
protected-access:233:8:233:37:Issue3066.foobar:Access to a protected member _attr of a client class:UNDEFINED
protected-access:236:8:236:29:Issue3066.foobar:Access to a protected member _bar of a client class:UNDEFINED
protected-access:237:8:237:36:Issue3066.foobar:Access to a protected member _bar of a client class:UNDEFINED
protected-access:247:12:247:27:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
protected-access:249:12:249:41:Issue3066.Aclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
protected-access:251:12:251:26:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:UNDEFINED
protected-access:253:12:253:40:Issue3066.Aclass.foobar:Access to a protected member _bar of a client class:UNDEFINED
protected-access:267:16:267:31:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
protected-access:268:16:268:38:Issue3066.Aclass.Bclass.foobar:Access to a protected member _attr of a client class:UNDEFINED
protected-access:271:16:271:30:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:UNDEFINED
protected-access:272:16:272:37:Issue3066.Aclass.Bclass.foobar:Access to a protected member _bar of a client class:UNDEFINED

0 comments on commit be149db

Please sign in to comment.