From cdcc509a583bcd4742ae19f8b8cd5077c0b34299 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Fri, 17 May 2024 09:16:45 +0200 Subject: [PATCH] Don't emit incorrect-variance for type parameters (PEP 695) (#9638) (cherry picked from commit fbc1ed32b34f7f253c61a85b04297f241b427119) --- doc/whatsnew/fragments/9638.false_positive | 5 +++++ pylint/checkers/base/name_checker/checker.py | 11 +++++++++-- tests/functional/t/type/typevar_naming_style_py312.py | 6 ++++++ .../functional/t/type/typevar_naming_style_py312.txt | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 doc/whatsnew/fragments/9638.false_positive diff --git a/doc/whatsnew/fragments/9638.false_positive b/doc/whatsnew/fragments/9638.false_positive new file mode 100644 index 0000000000..8076ad555c --- /dev/null +++ b/doc/whatsnew/fragments/9638.false_positive @@ -0,0 +1,5 @@ +Don't emit ``typevar-name-incorrect-variance`` warnings for PEP 695 style TypeVars. +The variance is inferred automatically by the type checker. +Adding ``_co`` or ``_contra`` suffix can help to reason about TypeVar. + +Refs #9638 diff --git a/pylint/checkers/base/name_checker/checker.py b/pylint/checkers/base/name_checker/checker.py index f6e1df5956..68f5767206 100644 --- a/pylint/checkers/base/name_checker/checker.py +++ b/pylint/checkers/base/name_checker/checker.py @@ -60,6 +60,7 @@ class TypeVarVariance(Enum): covariant = auto() contravariant = auto() double_variant = auto() + inferred = auto() def _get_properties(config: argparse.Namespace) -> tuple[set[str], set[str]]: @@ -623,6 +624,7 @@ def _assigns_typealias(node: nodes.NodeNG | None) -> bool: def _check_typevar(self, name: str, node: nodes.AssignName) -> None: """Check for TypeVar lint violations.""" + variance: TypeVarVariance = TypeVarVariance.invariant if isinstance(node.parent, nodes.Assign): keywords = node.assign_type().value.keywords args = node.assign_type().value.args @@ -634,8 +636,8 @@ def _check_typevar(self, name: str, node: nodes.AssignName) -> None: else: # PEP 695 generic type nodes keywords = () args = () + variance = TypeVarVariance.inferred - variance = TypeVarVariance.invariant name_arg = None for kw in keywords: if variance == TypeVarVariance.double_variant: @@ -659,7 +661,12 @@ def _check_typevar(self, name: str, node: nodes.AssignName) -> None: if name_arg is None and args and isinstance(args[0], nodes.Const): name_arg = args[0].value - if variance == TypeVarVariance.double_variant: + if variance == TypeVarVariance.inferred: + # Ignore variance check for PEP 695 type parameters. + # The variance is inferred by the type checker. + # Adding _co or _contra suffix can help to reason about TypeVar. + pass + elif variance == TypeVarVariance.double_variant: self.add_message( "typevar-double-variance", node=node, diff --git a/tests/functional/t/type/typevar_naming_style_py312.py b/tests/functional/t/type/typevar_naming_style_py312.py index 378290219f..9f04080c0d 100644 --- a/tests/functional/t/type/typevar_naming_style_py312.py +++ b/tests/functional/t/type/typevar_naming_style_py312.py @@ -1,4 +1,10 @@ """PEP 695 generic typing nodes""" +from collections.abc import Sequence + type Point[T] = tuple[T, ...] type Point[t] = tuple[t, ...] # [invalid-name] + +# Don't report typevar-name-incorrect-variance for type parameter +# The variance is determined by the type checker +type Array[T_co] = Sequence[T_co] diff --git a/tests/functional/t/type/typevar_naming_style_py312.txt b/tests/functional/t/type/typevar_naming_style_py312.txt index babe2a57bb..239378379b 100644 --- a/tests/functional/t/type/typevar_naming_style_py312.txt +++ b/tests/functional/t/type/typevar_naming_style_py312.txt @@ -1 +1 @@ -invalid-name:4:11:4:12::"Type variable name ""t"" doesn't conform to predefined naming style":HIGH +invalid-name:6:11:6:12::"Type variable name ""t"" doesn't conform to predefined naming style":HIGH