[flake8-pyi] Fix incorrect behaviour of custom-typevar-return-type preview-mode autofix if typing was already imported (PYI019) (#15853)

This commit is contained in:
Alex Waygood 2025-01-31 16:46:31 +00:00 committed by GitHub
parent b2cb757fa8
commit 0d191a13c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 153 additions and 119 deletions

View file

@ -0,0 +1,4 @@
import typing
class F:
def m[S](self: S) -> S: ...

View file

@ -136,8 +136,9 @@ mod tests {
Ok(())
}
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019.py"))]
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019.pyi"))]
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019_0.py"))]
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019_0.pyi"))]
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019_1.pyi"))]
fn custom_classmethod_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
@ -154,20 +155,26 @@ mod tests {
Ok(())
}
#[test]
fn custom_classmethod_rules_preview() -> Result<()> {
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019_0.pyi"))]
#[test_case(Rule::CustomTypeVarReturnType, Path::new("PYI019_1.pyi"))]
fn custom_classmethod_rules_preview(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview_{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_pyi/PYI019.pyi"),
Path::new("flake8_pyi").join(path).as_path(),
&settings::LinterSettings {
pep8_naming: pep8_naming::settings::Settings {
classmethod_decorators: vec!["foo_classmethod".to_string()],
..pep8_naming::settings::Settings::default()
},
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(Rule::CustomTypeVarReturnType)
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(diagnostics);
assert_messages!(snapshot, diagnostics);
Ok(())
}

View file

@ -1,5 +1,6 @@
use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::importer::{ImportRequest, ResolutionError};
use crate::settings::types::PythonVersion;
use itertools::Itertools;
use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
@ -9,7 +10,7 @@ use ruff_python_ast::{
use ruff_python_semantic::analyze::function_type::{self, FunctionType};
use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::{Ranged, TextRange};
use ruff_text_size::{Ranged, TextRange, TextSize};
/// ## What it does
/// Checks for methods that define a custom `TypeVar` for their return type
@ -270,12 +271,8 @@ fn add_diagnostic(checker: &mut Checker, function_def: &ast::StmtFunctionDef, re
returns.range(),
);
// See `replace_custom_typevar_with_self`'s doc comment
if in_stub {
if let Some(fix) = replace_custom_typevar_with_self(checker, function_def, returns) {
diagnostic.set_fix(fix);
}
}
diagnostic
.try_set_optional_fix(|| replace_custom_typevar_with_self(checker, function_def, returns));
checker.diagnostics.push(diagnostic);
}
@ -288,10 +285,6 @@ fn add_diagnostic(checker: &mut Checker, function_def: &ast::StmtFunctionDef, re
/// * Replace other uses of the original type variable elsewhere in the signature with `Self`
/// * Remove that type variable from the PEP 695 type parameter list
///
/// This fix cannot be suggested for non-stubs,
/// as a non-stub fix would have to deal with references in body/at runtime as well,
/// which is substantially harder and requires a type-aware backend.
///
/// The fourth step above has the same problem.
/// This function thus only does replacements for the simplest of cases
/// and will mark the fix as unsafe if an annotation cannot be handled.
@ -299,55 +292,58 @@ fn replace_custom_typevar_with_self(
checker: &Checker,
function_def: &ast::StmtFunctionDef,
returns: &Expr,
) -> Option<Fix> {
) -> anyhow::Result<Option<Fix>> {
if checker.settings.preview.is_disabled() {
return None;
return Ok(None);
}
// This fix cannot be suggested for non-stubs,
// as a non-stub fix would have to deal with references in body/at runtime as well,
// which is substantially harder and requires a type-aware backend.
if !checker.source_type.is_stub() {
return Ok(None);
}
// Non-`Name` return annotations are not currently autofixed
let typevar_name = &returns.as_name_expr()?.id;
let Expr::Name(typevar_name) = &returns else {
return Ok(None);
};
let typevar_name = &typevar_name.id;
let (import_edit, self_symbol_binding) = import_self(checker, returns.start())?;
let mut all_edits = vec![
replace_return_annotation_with_self(returns),
import_edit,
replace_return_annotation_with_self(self_symbol_binding, returns),
remove_first_parameter_annotation(&function_def.parameters),
];
let edit = import_self(checker, returns.range())?;
all_edits.push(edit);
all_edits.extend(remove_typevar_declaration(
function_def.type_params.as_deref(),
typevar_name,
));
if let Some(edit) =
remove_typevar_declaration(function_def.type_params.as_deref(), typevar_name)
{
all_edits.push(edit);
}
let (mut edits, fix_applicability) =
let (edits, fix_applicability) =
replace_typevar_usages_with_self(&function_def.parameters, typevar_name);
all_edits.append(&mut edits);
all_edits.extend(edits);
let (first, rest) = (all_edits.swap_remove(0), all_edits);
Some(Fix::applicable_edits(first, rest, fix_applicability))
Ok(Some(Fix::applicable_edits(first, rest, fix_applicability)))
}
fn import_self(checker: &Checker, return_range: TextRange) -> Option<Edit> {
// From PYI034's fix
let target_version = checker.settings.target_version.as_tuple();
let source_module = if target_version >= (3, 11) {
fn import_self(checker: &Checker, position: TextSize) -> Result<(Edit, String), ResolutionError> {
// See also PYI034's fix
let source_module = if checker.settings.target_version >= PythonVersion::Py311 {
"typing"
} else {
"typing_extensions"
};
let (importer, semantic) = (checker.importer(), checker.semantic());
let request = ImportRequest::import_from(source_module, "Self");
let position = return_range.start();
let (edit, ..) = importer
.get_or_import_symbol(&request, position, semantic)
.ok()?;
Some(edit)
importer.get_or_import_symbol(&request, position, semantic)
}
fn remove_first_parameter_annotation(parameters: &Parameters) -> Edit {
@ -362,8 +358,8 @@ fn remove_first_parameter_annotation(parameters: &Parameters) -> Edit {
Edit::deletion(name_end, annotation_end)
}
fn replace_return_annotation_with_self(returns: &Expr) -> Edit {
Edit::range_replacement("Self".to_string(), returns.range())
fn replace_return_annotation_with_self(self_symbol_binding: String, returns: &Expr) -> Edit {
Edit::range_replacement(self_symbol_binding, returns.range())
}
fn replace_typevar_usages_with_self(

View file

@ -1,34 +1,34 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019.py:7:62: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:7:62: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
| ^^ PYI019
|
PYI019.py:10:54: PYI019 Methods like `bad_instance_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:10:54: PYI019 Methods like `bad_instance_method` should return `Self` instead of a custom `TypeVar`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^ PYI019
|
PYI019.py:14:54: PYI019 Methods like `bad_class_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:14:54: PYI019 Methods like `bad_class_method` should return `Self` instead of a custom `TypeVar`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
| ^^ PYI019
|
PYI019.py:18:55: PYI019 Methods like `bad_posonly_class_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:18:55: PYI019 Methods like `bad_posonly_class_method` should return `Self` instead of a custom `TypeVar`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
| ^^ PYI019
|
PYI019.py:39:63: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:39:63: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
@ -36,13 +36,13 @@ PYI019.py:39:63: PYI019 Methods like `__new__` should return `Self` instead of a
| ^ PYI019
|
PYI019.py:42:46: PYI019 Methods like `generic_instance_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:42:46: PYI019 Methods like `generic_instance_method` should return `Self` instead of a custom `TypeVar`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^ PYI019
|
PYI019.py:54:32: PYI019 Methods like `foo` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:54:32: PYI019 Methods like `foo` should return `Self` instead of a custom `TypeVar`
|
52 | # in the settings for this test:
53 | @foo_classmethod
@ -50,7 +50,7 @@ PYI019.py:54:32: PYI019 Methods like `foo` should return `Self` instead of a cus
| ^ PYI019
|
PYI019.py:61:48: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:61:48: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
@ -60,7 +60,7 @@ PYI019.py:61:48: PYI019 Methods like `__new__` should return `Self` instead of a
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
|
PYI019.py:63:47: PYI019 Methods like `__init_subclass__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:63:47: PYI019 Methods like `__init_subclass__` should return `Self` instead of a custom `TypeVar`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
@ -70,7 +70,7 @@ PYI019.py:63:47: PYI019 Methods like `__init_subclass__` should return `Self` in
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
|
PYI019.py:65:43: PYI019 Methods like `__neg__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:65:43: PYI019 Methods like `__neg__` should return `Self` instead of a custom `TypeVar`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
@ -80,7 +80,7 @@ PYI019.py:65:43: PYI019 Methods like `__neg__` should return `Self` instead of a
67 | def __pos__[S](self: S) -> S: ...
|
PYI019.py:67:32: PYI019 Methods like `__pos__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:67:32: PYI019 Methods like `__pos__` should return `Self` instead of a custom `TypeVar`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
@ -90,7 +90,7 @@ PYI019.py:67:32: PYI019 Methods like `__pos__` should return `Self` instead of a
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
|
PYI019.py:69:53: PYI019 Methods like `__add__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:69:53: PYI019 Methods like `__add__` should return `Self` instead of a custom `TypeVar`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
@ -100,7 +100,7 @@ PYI019.py:69:53: PYI019 Methods like `__add__` should return `Self` instead of a
71 | def __sub__[S](self: S, other: S) -> S: ...
|
PYI019.py:71:42: PYI019 Methods like `__sub__` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:71:42: PYI019 Methods like `__sub__` should return `Self` instead of a custom `TypeVar`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
@ -110,7 +110,7 @@ PYI019.py:71:42: PYI019 Methods like `__sub__` should return `Self` instead of a
73 | @classmethod
|
PYI019.py:74:59: PYI019 Methods like `class_method_bound` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:74:59: PYI019 Methods like `class_method_bound` should return `Self` instead of a custom `TypeVar`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
@ -119,7 +119,7 @@ PYI019.py:74:59: PYI019 Methods like `class_method_bound` should return `Self` i
76 | @classmethod
|
PYI019.py:77:50: PYI019 Methods like `class_method_unbound` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:77:50: PYI019 Methods like `class_method_unbound` should return `Self` instead of a custom `TypeVar`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
@ -128,7 +128,7 @@ PYI019.py:77:50: PYI019 Methods like `class_method_unbound` should return `Self`
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
|
PYI019.py:79:57: PYI019 Methods like `instance_method_bound` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:79:57: PYI019 Methods like `instance_method_bound` should return `Self` instead of a custom `TypeVar`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
@ -138,7 +138,7 @@ PYI019.py:79:57: PYI019 Methods like `instance_method_bound` should return `Self
81 | def instance_method_unbound[S](self: S) -> S: ...
|
PYI019.py:81:48: PYI019 Methods like `instance_method_unbound` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:81:48: PYI019 Methods like `instance_method_unbound` should return `Self` instead of a custom `TypeVar`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
@ -148,7 +148,7 @@ PYI019.py:81:48: PYI019 Methods like `instance_method_unbound` should return `Se
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
|
PYI019.py:83:90: PYI019 Methods like `instance_method_bound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:83:90: PYI019 Methods like `instance_method_bound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
@ -158,7 +158,7 @@ PYI019.py:83:90: PYI019 Methods like `instance_method_bound_with_another_paramet
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
|
PYI019.py:85:81: PYI019 Methods like `instance_method_unbound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:85:81: PYI019 Methods like `instance_method_unbound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
@ -168,7 +168,7 @@ PYI019.py:85:81: PYI019 Methods like `instance_method_unbound_with_another_param
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
|
PYI019.py:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` instead of a custom `TypeVar`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
@ -178,7 +178,7 @@ PYI019.py:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` i
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
|
PYI019.py:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should return `Self` instead of a custom `TypeVar`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
@ -186,7 +186,7 @@ PYI019.py:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should
| ^^^^^ PYI019
|
PYI019.py:102:40: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:102:40: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
|
100 | class UsesFullyQualifiedType:
101 | @classmethod
@ -194,7 +194,7 @@ PYI019.py:102:40: PYI019 Methods like `m` should return `Self` instead of a cust
| ^ PYI019
|
PYI019.py:114:31: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
PYI019_0.py:114:31: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
|
112 | class SubscriptReturnType:
113 | @classmethod

View file

@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019.pyi:7:62: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:7:62: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
@ -9,14 +9,14 @@ PYI019.pyi:7:62: PYI019 Methods like `__new__` should return `Self` instead of a
|
= help: Replace with `Self`
PYI019.pyi:10:54: PYI019 Methods like `bad_instance_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:10:54: PYI019 Methods like `bad_instance_method` should return `Self` instead of a custom `TypeVar`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^ PYI019
|
= help: Replace with `Self`
PYI019.pyi:14:54: PYI019 Methods like `bad_class_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:14:54: PYI019 Methods like `bad_class_method` should return `Self` instead of a custom `TypeVar`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
@ -24,7 +24,7 @@ PYI019.pyi:14:54: PYI019 Methods like `bad_class_method` should return `Self` in
|
= help: Replace with `Self`
PYI019.pyi:18:55: PYI019 Methods like `bad_posonly_class_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:18:55: PYI019 Methods like `bad_posonly_class_method` should return `Self` instead of a custom `TypeVar`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
@ -32,7 +32,7 @@ PYI019.pyi:18:55: PYI019 Methods like `bad_posonly_class_method` should return `
|
= help: Replace with `Self`
PYI019.pyi:39:63: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:39:63: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
@ -41,14 +41,14 @@ PYI019.pyi:39:63: PYI019 Methods like `__new__` should return `Self` instead of
|
= help: Replace with `Self`
PYI019.pyi:42:46: PYI019 Methods like `generic_instance_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:42:46: PYI019 Methods like `generic_instance_method` should return `Self` instead of a custom `TypeVar`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^ PYI019
|
= help: Replace with `Self`
PYI019.pyi:54:32: PYI019 Methods like `foo` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:54:32: PYI019 Methods like `foo` should return `Self` instead of a custom `TypeVar`
|
52 | # in the settings for this test:
53 | @foo_classmethod
@ -57,7 +57,7 @@ PYI019.pyi:54:32: PYI019 Methods like `foo` should return `Self` instead of a cu
|
= help: Replace with `Self`
PYI019.pyi:61:48: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:61:48: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
@ -68,7 +68,7 @@ PYI019.pyi:61:48: PYI019 Methods like `__new__` should return `Self` instead of
|
= help: Replace with `Self`
PYI019.pyi:63:47: PYI019 Methods like `__init_subclass__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:63:47: PYI019 Methods like `__init_subclass__` should return `Self` instead of a custom `TypeVar`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
@ -79,7 +79,7 @@ PYI019.pyi:63:47: PYI019 Methods like `__init_subclass__` should return `Self` i
|
= help: Replace with `Self`
PYI019.pyi:65:43: PYI019 Methods like `__neg__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:65:43: PYI019 Methods like `__neg__` should return `Self` instead of a custom `TypeVar`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
@ -90,7 +90,7 @@ PYI019.pyi:65:43: PYI019 Methods like `__neg__` should return `Self` instead of
|
= help: Replace with `Self`
PYI019.pyi:67:32: PYI019 Methods like `__pos__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:67:32: PYI019 Methods like `__pos__` should return `Self` instead of a custom `TypeVar`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
@ -101,7 +101,7 @@ PYI019.pyi:67:32: PYI019 Methods like `__pos__` should return `Self` instead of
|
= help: Replace with `Self`
PYI019.pyi:69:53: PYI019 Methods like `__add__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:69:53: PYI019 Methods like `__add__` should return `Self` instead of a custom `TypeVar`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
@ -112,7 +112,7 @@ PYI019.pyi:69:53: PYI019 Methods like `__add__` should return `Self` instead of
|
= help: Replace with `Self`
PYI019.pyi:71:42: PYI019 Methods like `__sub__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:71:42: PYI019 Methods like `__sub__` should return `Self` instead of a custom `TypeVar`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
@ -123,7 +123,7 @@ PYI019.pyi:71:42: PYI019 Methods like `__sub__` should return `Self` instead of
|
= help: Replace with `Self`
PYI019.pyi:74:59: PYI019 Methods like `class_method_bound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:74:59: PYI019 Methods like `class_method_bound` should return `Self` instead of a custom `TypeVar`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
@ -133,7 +133,7 @@ PYI019.pyi:74:59: PYI019 Methods like `class_method_bound` should return `Self`
|
= help: Replace with `Self`
PYI019.pyi:77:50: PYI019 Methods like `class_method_unbound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:77:50: PYI019 Methods like `class_method_unbound` should return `Self` instead of a custom `TypeVar`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
@ -143,7 +143,7 @@ PYI019.pyi:77:50: PYI019 Methods like `class_method_unbound` should return `Self
|
= help: Replace with `Self`
PYI019.pyi:79:57: PYI019 Methods like `instance_method_bound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:79:57: PYI019 Methods like `instance_method_bound` should return `Self` instead of a custom `TypeVar`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
@ -154,7 +154,7 @@ PYI019.pyi:79:57: PYI019 Methods like `instance_method_bound` should return `Sel
|
= help: Replace with `Self`
PYI019.pyi:81:48: PYI019 Methods like `instance_method_unbound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:81:48: PYI019 Methods like `instance_method_unbound` should return `Self` instead of a custom `TypeVar`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
@ -165,7 +165,7 @@ PYI019.pyi:81:48: PYI019 Methods like `instance_method_unbound` should return `S
|
= help: Replace with `Self`
PYI019.pyi:83:90: PYI019 Methods like `instance_method_bound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:83:90: PYI019 Methods like `instance_method_bound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
@ -176,7 +176,7 @@ PYI019.pyi:83:90: PYI019 Methods like `instance_method_bound_with_another_parame
|
= help: Replace with `Self`
PYI019.pyi:85:81: PYI019 Methods like `instance_method_unbound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:85:81: PYI019 Methods like `instance_method_unbound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
@ -187,7 +187,7 @@ PYI019.pyi:85:81: PYI019 Methods like `instance_method_unbound_with_another_para
|
= help: Replace with `Self`
PYI019.pyi:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` instead of a custom `TypeVar`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
@ -198,7 +198,7 @@ PYI019.pyi:87:94: PYI019 Methods like `multiple_type_vars` should return `Self`
|
= help: Replace with `Self`
PYI019.pyi:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should return `Self` instead of a custom `TypeVar`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
@ -207,7 +207,7 @@ PYI019.pyi:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` shoul
|
= help: Replace with `Self`
PYI019.pyi:102:40: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:102:40: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
|
100 | class UsesFullyQualifiedType:
101 | @classmethod
@ -216,7 +216,7 @@ PYI019.pyi:102:40: PYI019 Methods like `m` should return `Self` instead of a cus
|
= help: Replace with `Self`
PYI019.pyi:114:31: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:114:31: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
|
112 | class SubscriptReturnType:
113 | @classmethod
@ -225,7 +225,7 @@ PYI019.pyi:114:31: PYI019 Methods like `m` should return `Self` instead of a cus
|
= help: Replace with `Self`
PYI019.pyi:118:29: PYI019 Methods like `f` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:118:29: PYI019 Methods like `f` should return `Self` instead of a custom `TypeVar`
|
117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
118 | def f[T, S](self: S) -> S: ...

View file

@ -0,0 +1,10 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_1.pyi:4:26: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
|
3 | class F:
4 | def m[S](self: S) -> S: ...
| ^ PYI019
|
= help: Replace with `Self`

View file

@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019.pyi:7:62: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:7:62: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
@ -19,7 +19,7 @@ PYI019.pyi:7:62: PYI019 Methods like `__new__` should return `Self` instead of a
9 9 |
10 10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
PYI019.pyi:10:54: PYI019 Methods like `bad_instance_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:10:54: PYI019 Methods like `bad_instance_method` should return `Self` instead of a custom `TypeVar`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^ PYI019
@ -36,7 +36,7 @@ PYI019.pyi:10:54: PYI019 Methods like `bad_instance_method` should return `Self`
12 12 |
13 13 | @classmethod
PYI019.pyi:14:54: PYI019 Methods like `bad_class_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:14:54: PYI019 Methods like `bad_class_method` should return `Self` instead of a custom `TypeVar`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
@ -54,7 +54,7 @@ PYI019.pyi:14:54: PYI019 Methods like `bad_class_method` should return `Self` in
16 16 |
17 17 | @classmethod
PYI019.pyi:18:55: PYI019 [*] Methods like `bad_posonly_class_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:18:55: PYI019 [*] Methods like `bad_posonly_class_method` should return `Self` instead of a custom `TypeVar`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
@ -72,7 +72,7 @@ PYI019.pyi:18:55: PYI019 [*] Methods like `bad_posonly_class_method` should retu
20 20 |
21 21 | @classmethod
PYI019.pyi:39:63: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:39:63: PYI019 Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
@ -91,7 +91,7 @@ PYI019.pyi:39:63: PYI019 Methods like `__new__` should return `Self` instead of
41 41 |
42 42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
PYI019.pyi:42:46: PYI019 [*] Methods like `generic_instance_method` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:42:46: PYI019 [*] Methods like `generic_instance_method` should return `Self` instead of a custom `TypeVar`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^ PYI019
@ -108,7 +108,7 @@ PYI019.pyi:42:46: PYI019 [*] Methods like `generic_instance_method` should retur
44 44 |
45 45 | class PEP695GoodDunderNew[T]:
PYI019.pyi:54:32: PYI019 [*] Methods like `foo` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:54:32: PYI019 [*] Methods like `foo` should return `Self` instead of a custom `TypeVar`
|
52 | # in the settings for this test:
53 | @foo_classmethod
@ -127,7 +127,7 @@ PYI019.pyi:54:32: PYI019 [*] Methods like `foo` should return `Self` instead of
56 56 |
57 57 | _S695 = TypeVar("_S695", bound="PEP695Fix")
PYI019.pyi:61:48: PYI019 [*] Methods like `__new__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:61:48: PYI019 [*] Methods like `__new__` should return `Self` instead of a custom `TypeVar`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
@ -148,7 +148,7 @@ PYI019.pyi:61:48: PYI019 [*] Methods like `__new__` should return `Self` instead
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
PYI019.pyi:63:47: PYI019 [*] Methods like `__init_subclass__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:63:47: PYI019 [*] Methods like `__init_subclass__` should return `Self` instead of a custom `TypeVar`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
@ -169,7 +169,7 @@ PYI019.pyi:63:47: PYI019 [*] Methods like `__init_subclass__` should return `Sel
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
PYI019.pyi:65:43: PYI019 [*] Methods like `__neg__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:65:43: PYI019 [*] Methods like `__neg__` should return `Self` instead of a custom `TypeVar`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
@ -190,7 +190,7 @@ PYI019.pyi:65:43: PYI019 [*] Methods like `__neg__` should return `Self` instead
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
PYI019.pyi:67:32: PYI019 [*] Methods like `__pos__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:67:32: PYI019 [*] Methods like `__pos__` should return `Self` instead of a custom `TypeVar`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
@ -211,7 +211,7 @@ PYI019.pyi:67:32: PYI019 [*] Methods like `__pos__` should return `Self` instead
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
PYI019.pyi:69:53: PYI019 [*] Methods like `__add__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:69:53: PYI019 [*] Methods like `__add__` should return `Self` instead of a custom `TypeVar`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
@ -232,7 +232,7 @@ PYI019.pyi:69:53: PYI019 [*] Methods like `__add__` should return `Self` instead
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
PYI019.pyi:71:42: PYI019 [*] Methods like `__sub__` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:71:42: PYI019 [*] Methods like `__sub__` should return `Self` instead of a custom `TypeVar`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
@ -253,7 +253,7 @@ PYI019.pyi:71:42: PYI019 [*] Methods like `__sub__` should return `Self` instead
73 73 | @classmethod
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
PYI019.pyi:74:59: PYI019 [*] Methods like `class_method_bound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:74:59: PYI019 [*] Methods like `class_method_bound` should return `Self` instead of a custom `TypeVar`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
@ -273,7 +273,7 @@ PYI019.pyi:74:59: PYI019 [*] Methods like `class_method_bound` should return `Se
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
PYI019.pyi:77:50: PYI019 [*] Methods like `class_method_unbound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:77:50: PYI019 [*] Methods like `class_method_unbound` should return `Self` instead of a custom `TypeVar`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
@ -293,7 +293,7 @@ PYI019.pyi:77:50: PYI019 [*] Methods like `class_method_unbound` should return `
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
PYI019.pyi:79:57: PYI019 [*] Methods like `instance_method_bound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:79:57: PYI019 [*] Methods like `instance_method_bound` should return `Self` instead of a custom `TypeVar`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
@ -314,7 +314,7 @@ PYI019.pyi:79:57: PYI019 [*] Methods like `instance_method_bound` should return
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
PYI019.pyi:81:48: PYI019 [*] Methods like `instance_method_unbound` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:81:48: PYI019 [*] Methods like `instance_method_unbound` should return `Self` instead of a custom `TypeVar`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
@ -335,7 +335,7 @@ PYI019.pyi:81:48: PYI019 [*] Methods like `instance_method_unbound` should retur
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
PYI019.pyi:83:90: PYI019 [*] Methods like `instance_method_bound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:83:90: PYI019 [*] Methods like `instance_method_bound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
@ -356,7 +356,7 @@ PYI019.pyi:83:90: PYI019 [*] Methods like `instance_method_bound_with_another_pa
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
PYI019.pyi:85:81: PYI019 [*] Methods like `instance_method_unbound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:85:81: PYI019 [*] Methods like `instance_method_unbound_with_another_parameter` should return `Self` instead of a custom `TypeVar`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
@ -377,7 +377,7 @@ PYI019.pyi:85:81: PYI019 [*] Methods like `instance_method_unbound_with_another_
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
PYI019.pyi:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:87:94: PYI019 Methods like `multiple_type_vars` should return `Self` instead of a custom `TypeVar`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
@ -398,7 +398,7 @@ PYI019.pyi:87:94: PYI019 Methods like `multiple_type_vars` should return `Self`
89 89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
90 90 |
PYI019.pyi:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` should return `Self` instead of a custom `TypeVar`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
@ -417,7 +417,7 @@ PYI019.pyi:89:75: PYI019 Methods like `mixing_old_and_new_style_type_vars` shoul
91 91 |
92 92 | class InvalidButWeDoNotPanic:
PYI019.pyi:102:40: PYI019 [*] Methods like `m` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:102:40: PYI019 [*] Methods like `m` should return `Self` instead of a custom `TypeVar`
|
100 | class UsesFullyQualifiedType:
101 | @classmethod
@ -436,7 +436,7 @@ PYI019.pyi:102:40: PYI019 [*] Methods like `m` should return `Self` instead of a
104 104 |
105 105 | def shadowed_type():
PYI019.pyi:114:31: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:114:31: PYI019 Methods like `m` should return `Self` instead of a custom `TypeVar`
|
112 | class SubscriptReturnType:
113 | @classmethod
@ -445,7 +445,7 @@ PYI019.pyi:114:31: PYI019 Methods like `m` should return `Self` instead of a cus
|
= help: Replace with `Self`
PYI019.pyi:118:29: PYI019 [*] Methods like `f` should return `Self` instead of a custom `TypeVar`
PYI019_0.pyi:118:29: PYI019 [*] Methods like `f` should return `Self` instead of a custom `TypeVar`
|
117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
118 | def f[T, S](self: S) -> S: ...

View file

@ -0,0 +1,17 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_1.pyi:4:26: PYI019 [*] Methods like `m` should return `Self` instead of a custom `TypeVar`
|
3 | class F:
4 | def m[S](self: S) -> S: ...
| ^ PYI019
|
= help: Replace with `Self`
Safe fix
1 1 | import typing
2 2 |
3 3 | class F:
4 |- def m[S](self: S) -> S: ...
4 |+ def m(self) -> typing.Self: ...