diff options
author | Jacob Walls <jacobtylerwalls@gmail.com> | 2023-05-16 08:25:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-16 14:25:25 +0200 |
commit | 60daec60011d0b3a6be52c9410d1d7ef0179349d (patch) | |
tree | 5bb1d73eb9f8af22ba731a0a64f7bf8f10ba562c | |
parent | d7baf5d43fa8de68c4c169f731ae5af43ce60790 (diff) | |
download | pylint-git-main.tar.gz |
Closes #8660
10 files changed, 71 insertions, 8 deletions
diff --git a/doc/data/messages/p/prefer-typing-namedtuple/bad.py b/doc/data/messages/p/prefer-typing-namedtuple/bad.py new file mode 100644 index 000000000..d555b0f26 --- /dev/null +++ b/doc/data/messages/p/prefer-typing-namedtuple/bad.py @@ -0,0 +1,5 @@ +from collections import namedtuple + +Philosophy = namedtuple( # [prefer-typing-namedtuple] + "Philosophy", ("goodness", "truth", "beauty") +) diff --git a/doc/data/messages/p/prefer-typing-namedtuple/good.py b/doc/data/messages/p/prefer-typing-namedtuple/good.py new file mode 100644 index 000000000..ef094aacd --- /dev/null +++ b/doc/data/messages/p/prefer-typing-namedtuple/good.py @@ -0,0 +1,7 @@ +from typing import NamedTuple + + +class Philosophy(NamedTuple): + goodness: str + truth: bool + beauty: float diff --git a/doc/data/messages/p/prefer-typing-namedtuple/pylintrc b/doc/data/messages/p/prefer-typing-namedtuple/pylintrc new file mode 100644 index 000000000..b001506b6 --- /dev/null +++ b/doc/data/messages/p/prefer-typing-namedtuple/pylintrc @@ -0,0 +1,2 @@ +[MAIN] +load-plugins = pylint.extensions.code_style diff --git a/doc/data/messages/p/prefer-typing-namedtuple/related.rst b/doc/data/messages/p/prefer-typing-namedtuple/related.rst new file mode 100644 index 000000000..a8d3da44c --- /dev/null +++ b/doc/data/messages/p/prefer-typing-namedtuple/related.rst @@ -0,0 +1 @@ +- `typing.NamedTuple <https://docs.python.org/3/library/typing.html#typing.NamedTuple>`_ diff --git a/doc/whatsnew/fragments/8660.extension b/doc/whatsnew/fragments/8660.extension new file mode 100644 index 000000000..2090d03ac --- /dev/null +++ b/doc/whatsnew/fragments/8660.extension @@ -0,0 +1,7 @@ +Add new ``prefer-typing-namedtuple`` message to the ``CodeStyleChecker`` to suggest +rewriting calls to ``collections.namedtuple`` as classes inheriting from ``typing.NamedTuple`` +on Python 3.6+. + +Requires ``load-plugins=pylint.extensions.code_style`` and ``enable=prefer-typing-namedtuple`` to be raised. + +Closes #8660 diff --git a/pylint/checkers/classes/class_checker.py b/pylint/checkers/classes/class_checker.py index 77a795bcb..bdfb0968a 100644 --- a/pylint/checkers/classes/class_checker.py +++ b/pylint/checkers/classes/class_checker.py @@ -6,13 +6,12 @@ from __future__ import annotations -import collections from collections import defaultdict from collections.abc import Callable, Sequence from functools import cached_property from itertools import chain, zip_longest from re import Pattern -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Any, NamedTuple, Union import astroid from astroid import bases, nodes, util @@ -63,12 +62,19 @@ ASTROID_TYPE_COMPARATORS = { # Dealing with useless override detection, with regard # to parameters vs arguments -_CallSignature = collections.namedtuple( - "_CallSignature", "args kws starred_args starred_kws" -) -_ParameterSignature = collections.namedtuple( - "_ParameterSignature", "args kwonlyargs varargs kwargs" -) + +class _CallSignature(NamedTuple): + args: list[str | None] + kws: dict[str | None, str | None] + starred_args: list[str] + starred_kws: list[str] + + +class _ParameterSignature(NamedTuple): + args: list[str] + kwonlyargs: list[str] + varargs: str + kwargs: str def _signature_from_call(call: nodes.Call) -> _CallSignature: diff --git a/pylint/extensions/code_style.py b/pylint/extensions/code_style.py index 5ce1ae476..622601c75 100644 --- a/pylint/extensions/code_style.py +++ b/pylint/extensions/code_style.py @@ -69,6 +69,17 @@ class CodeStyleChecker(BaseChecker): "default_enabled": False, }, ), + "R6105": ( + "Prefer 'typing.NamedTuple' over 'collections.namedtuple'", + "prefer-typing-namedtuple", + "'typing.NamedTuple' uses the well-known 'class' keyword " + "with type-hints for readability (it's also faster as it avoids " + "an internal exec call).\n" + "Disabled by default!", + { + "default_enabled": False, + }, + ), } options = ( ( @@ -89,12 +100,22 @@ class CodeStyleChecker(BaseChecker): def open(self) -> None: py_version = self.linter.config.py_version + self._py36_plus = py_version >= (3, 6) self._py38_plus = py_version >= (3, 8) self._max_length: int = ( self.linter.config.max_line_length_suggestions or self.linter.config.max_line_length ) + @only_required_for_messages("prefer-typing-namedtuple") + def visit_call(self, node: nodes.Call) -> None: + if self._py36_plus: + called = safe_infer(node.func) + if called and called.qname() == "collections.namedtuple": + self.add_message( + "prefer-typing-namedtuple", node=node, confidence=INFERENCE + ) + @only_required_for_messages("consider-using-namedtuple-or-dataclass") def visit_dict(self, node: nodes.Dict) -> None: self._check_dict_consider_namedtuple_dataclass(node) diff --git a/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py new file mode 100644 index 000000000..7b0e7c58d --- /dev/null +++ b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.py @@ -0,0 +1,9 @@ +# pylint: disable=missing-docstring +from collections import namedtuple + +NoteHash = namedtuple('NoteHash', ['Pitch', 'Duration', 'Offset']) # [prefer-typing-namedtuple] + +class SearchMatch( + namedtuple('SearchMatch', ['els', 'index', 'iterator']) # [prefer-typing-namedtuple] +): + """Adapted from primer package `music21`.""" diff --git a/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.rc b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.rc new file mode 100644 index 000000000..ee4eb7e68 --- /dev/null +++ b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.rc @@ -0,0 +1,3 @@ +[MAIN] +load-plugins=pylint.extensions.code_style +enable=prefer-typing-namedtuple diff --git a/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.txt b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.txt new file mode 100644 index 000000000..a9bf6751b --- /dev/null +++ b/tests/functional/ext/code_style/cs_prefer_typing_namedtuple.txt @@ -0,0 +1,2 @@ +prefer-typing-namedtuple:4:11:4:66::Prefer 'typing.NamedTuple' over 'collections.namedtuple':INFERENCE +prefer-typing-namedtuple:7:4:7:59:SearchMatch:Prefer 'typing.NamedTuple' over 'collections.namedtuple':INFERENCE |