From b0fe89180b330f2a75cc2aed763bdd4f86fb844a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Noord?= <13665637+DanielNoord@users.noreply.github.com> Date: Fri, 11 Mar 2022 16:37:03 +0100 Subject: [PATCH 01/12] Create a ``TypeVar`` style for ``invalid-name`` --- ChangeLog | 5 ++ doc/user_guide/options.rst | 4 + doc/whatsnew/2.13.rst | 5 ++ pylint/checkers/base.py | 82 +++++++++++-------- pylint/constants.py | 1 + pylint/utils/linterstats.py | 7 ++ pylintrc | 4 + tests/checkers/unittest_base.py | 50 ++++++++--- .../t/typevar_naming_style_default.py | 72 ++++++++++++++++ .../t/typevar_naming_style_default.txt | 19 +++++ .../functional/t/typevar_naming_style_rgx.py | 15 ++++ .../functional/t/typevar_naming_style_rgx.rc | 2 + .../functional/t/typevar_naming_style_rgx.txt | 3 + 13 files changed, 224 insertions(+), 45 deletions(-) create mode 100644 tests/functional/t/typevar_naming_style_default.py create mode 100644 tests/functional/t/typevar_naming_style_default.txt create mode 100644 tests/functional/t/typevar_naming_style_rgx.py create mode 100644 tests/functional/t/typevar_naming_style_rgx.rc create mode 100644 tests/functional/t/typevar_naming_style_rgx.txt diff --git a/ChangeLog b/ChangeLog index 33dacc56bf..e32e36eda5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -450,6 +450,11 @@ Release date: TBA Insert your changelog randomly, it will reduce merge conflicts (Ie. not necessarily at the end) +* ``invalid-name`` check now also checks ``TypeVar`` for a pattern set with the new option + ``--typevar-rgx`` option or a default ``PascalCase`` based style. + + Closes #3401 + * Added new checker ``typevar-name-missing-variance``. Emitted when a covariant or contravariant ``TypeVar`` does not end with ``_co`` or ``_contra`` respectively or when a ``TypeVar`` is not either but has a suffix. diff --git a/doc/user_guide/options.rst b/doc/user_guide/options.rst index 898c7a60a7..b7401680f0 100644 --- a/doc/user_guide/options.rst +++ b/doc/user_guide/options.rst @@ -39,6 +39,8 @@ name is found in, and not the type of object assigned. +--------------------+---------------------------------------------------------------------------------------------------+ | ``inlinevar`` | Loop variables in list comprehensions and generator expressions. | +--------------------+---------------------------------------------------------------------------------------------------+ +| ``typevar`` | Type variable declared with ``TypeVar``. | ++--------------------+---------------------------------------------------------------------------------------------------+ Default behavior ~~~~~~~~~~~~~~~~ @@ -118,6 +120,8 @@ expression will lead to an instance of ``invalid-name``. .. option:: --inlinevar-rgx= +.. option:: --typevar-rgx= + Multiple naming styles for custom regular expressions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index 96dfa518a9..fa637b6961 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -334,6 +334,11 @@ Other Changes Closes #5360, #3877 +* ``invalid-name`` check now also checks ``TypeVar`` for a pattern set with the new option + ``--typevar-rgx`` option or a default ``PascalCase`` based style. + + Closes #3401 + * Fixed a false positive (affecting unreleased development) for ``used-before-assignment`` involving homonyms between filtered comprehensions and assignments in except blocks. diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py index 71dabd8efc..e677f29262 100644 --- a/pylint/checkers/base.py +++ b/pylint/checkers/base.py @@ -73,7 +73,7 @@ import itertools import re import sys -from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Pattern, cast +from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Pattern, Tuple, cast import astroid from astroid import nodes @@ -189,6 +189,13 @@ class AnyStyle(NamingStyle): "any": AnyStyle, } +# Default patterns for name types that do not have styles +DEFAULT_PATTERNS = { + "typevar": re.compile( + r"^_{0,2}(?:[^\W\da-z_]+|(?:[^\W\da-z_][^\WA-Z_]+)+T?(? None: self._check_redeclared_assign_name([node.target]) -KNOWN_NAME_TYPES = { +# Name types that hae a style option +KNOWN_NAME_TYPES_WITH_STYLE = { "module", "const", "class", @@ -1674,6 +1682,12 @@ def visit_for(self, node: nodes.For) -> None: "inlinevar", } +# Name types that only have a 'rgx' option +KNOWN_NAME_TYPES = { + *KNOWN_NAME_TYPES_WITH_STYLE, + "typevar", +} + DEFAULT_NAMING_STYLES = { "module": "snake_case", "const": "UPPER_CASE", @@ -1693,28 +1707,31 @@ def _create_naming_options(): name_options = [] for name_type in sorted(KNOWN_NAME_TYPES): human_readable_name = constants.HUMAN_READABLE_TYPES[name_type] - default_style = DEFAULT_NAMING_STYLES[name_type] - name_type = name_type.replace("_", "-") - name_options.append( - ( - f"{name_type}-naming-style", - { - "default": default_style, - "type": "choice", - "choices": list(NAMING_STYLES.keys()), - "metavar": "