From cb8b23d60915206d9ad74fd351a36dd0d4ed1231 Mon Sep 17 00:00:00 2001 From: Vlad Nedelcu Date: Thu, 13 Feb 2025 20:44:11 +0200 Subject: [PATCH] [flake8-pyi] Avoid flagging `custom-typevar-for-self` on metaclass methods (PYI019) (#16141) --- .../resources/test/fixtures/flake8_pyi/PYI019_0.py | 7 +++++++ .../resources/test/fixtures/flake8_pyi/PYI019_0.pyi | 7 +++++++ .../rules/flake8_pyi/rules/custom_type_var_for_self.rs | 10 ++++++++-- ...flake8_pyi__tests__preview_PYI019_PYI019_0.pyi.snap | 5 +++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.py index 6cca6f515a..e502d8fc1f 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.py @@ -174,3 +174,10 @@ class NamesShadowingTypeVarAreNotTouched: type S = int print(S) # not a reference to the type variable, so not touched by the autofix return 42 + + +MetaType = TypeVar("MetaType") + +class MetaTestClass(type): + def m(cls: MetaType) -> MetaType: + return cls diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.pyi index e881c91b41..1f2f17fc1b 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019_0.pyi @@ -165,3 +165,10 @@ class NoReturnAnnotations: class MultipleBoundParameters: def m[S: int, T: int](self: S, other: T) -> S: ... def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ... + + +MetaType = TypeVar("MetaType") + +class MetaTestClass(type): + def m(cls: MetaType) -> MetaType: + return cls diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs index 2900618fba..efe2c4715f 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs @@ -4,6 +4,7 @@ use itertools::Itertools; use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, ViolationMetadata}; use ruff_python_ast as ast; +use ruff_python_semantic::analyze::class::is_metaclass; use ruff_python_semantic::analyze::function_type::{self, FunctionType}; use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload}; use ruff_python_semantic::{Binding, ResolvedReference, ScopeId, SemanticModel}; @@ -128,9 +129,14 @@ pub(crate) fn custom_type_var_instead_of_self( .next()?; let self_or_cls_annotation = self_or_cls_parameter.annotation()?; + let parent_class = current_scope.kind.as_class()?; - // Skip any abstract, static, and overloaded methods. - if is_abstract(decorator_list, semantic) || is_overload(decorator_list, semantic) { + // Skip any abstract/static/overloaded methods, + // and any methods in metaclasses + if is_abstract(decorator_list, semantic) + || is_overload(decorator_list, semantic) + || is_metaclass(parent_class, semantic).is_yes() + { return None; } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__preview_PYI019_PYI019_0.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__preview_PYI019_PYI019_0.pyi.snap index 49da75188b..7c5b794bd5 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__preview_PYI019_PYI019_0.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__preview_PYI019_PYI019_0.pyi.snap @@ -661,6 +661,8 @@ PYI019_0.pyi:166:10: PYI019 [*] Use `Self` instead of custom TypeVar `S` 166 |- def m[S: int, T: int](self: S, other: T) -> S: ... 166 |+ def m[T: int](self, other: T) -> Self: ... 167 167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ... +168 168 | +169 169 | PYI019_0.pyi:167:10: PYI019 [*] Use `Self` instead of custom TypeVar `S` | @@ -677,3 +679,6 @@ PYI019_0.pyi:167:10: PYI019 [*] Use `Self` instead of custom TypeVar `S` 166 166 | def m[S: int, T: int](self: S, other: T) -> S: ... 167 |- def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ... 167 |+ def n[T: (int, str)](self, other: T) -> Self: ... +168 168 | +169 169 | +170 170 | MetaType = TypeVar("MetaType")