[flake8-pyi] Make PYI019 autofixable for .py files in preview mode as well as stubs (#15889)
Some checks are pending
CI / cargo test (linux) (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions

This commit is contained in:
Alex Waygood 2025-02-04 16:41:22 +00:00 committed by GitHub
parent 9d83e76a3b
commit 64e64d2681
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 584 additions and 73 deletions

View file

@ -1,4 +1,4 @@
from typing import TypeVar, Self, Type
from typing import TypeVar, Self, Type, cast
_S = TypeVar("_S", bound=BadClass)
_S2 = TypeVar("_S2", BadClass, GoodClass)
@ -56,7 +56,7 @@ class CustomClassMethod:
_S695 = TypeVar("_S695", bound="PEP695Fix")
# Only .pyi gets fixes, no fixes for .py
class PEP695Fix:
def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
@ -139,3 +139,38 @@ 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: ...
class MethodsWithBody:
def m[S](self: S, other: S) -> S:
x: S = other
return x
@classmethod
def n[S](cls: type[S], other: S) -> S:
x: type[S] = type(other)
return x()
class StringizedReferencesCanBeFixed:
def m[S](self: S) -> S:
x = cast("list[tuple[S, S]]", self)
return x
class ButStrangeStringizedReferencesCannotBeFixed:
def m[_T](self: _T) -> _T:
x = cast('list[_\x54]', self)
return x
class DeletionsAreNotTouched:
def m[S](self: S) -> S:
# `S` is not a local variable here, and `del` can only be used with local variables,
# so `del S` here is not actually a reference to the type variable `S`.
# This `del` statement is therefore not touched by the autofix (it raises `UnboundLocalError`
# both before and after the autofix)
del S
return self
class NamesShadowingTypeVarAreNotTouched:
def m[S](self: S) -> S:
type S = int
print(S) # not a reference to the type variable, so not touched by the autofix
return 42

View file

@ -56,7 +56,7 @@ class CustomClassMethod:
_S695 = TypeVar("_S695", bound="PEP695Fix")
# Only .pyi gets fixes, no fixes for .py
class PEP695Fix:
def __new__[S: PEP695Fix](cls: type[S]) -> S: ...

View file

@ -14,8 +14,8 @@ use crate::importer::{ImportRequest, ResolutionError};
use crate::settings::types::PythonVersion;
/// ## What it does
/// Checks for methods that use custom `TypeVar`s in their annotations
/// when they could use `Self` instead.
/// Checks for methods that use custom [`TypeVar`s][typing_TypeVar] in their
/// annotations when they could use [`Self`][Self] instead.
///
/// ## Why is this bad?
/// While the semantics are often identical, using `Self` is more intuitive
@ -49,10 +49,11 @@ use crate::settings::types::PythonVersion;
/// def bar(cls, arg: int) -> Self: ...
/// ```
///
/// ## Fix safety
/// The fix is only available in stub files.
/// It will try to remove all usages and declarations of the custom type variable.
/// Pre-[PEP-695]-style declarations will not be removed.
/// ## Fix behaviour and safety
/// The fix removes all usages and declarations of the custom type variable.
/// [PEP-695]-style `TypeVar` declarations are also removed from the [type parameter list];
/// however, old-style `TypeVar`s do not have their declarations removed. See
/// [`unused-private-type-var`][PYI018] for a rule to clean up unused private type variables.
///
/// If there are any comments within the fix ranges, it will be marked as unsafe.
/// Otherwise, it will be marked as safe.
@ -71,6 +72,10 @@ use crate::settings::types::PythonVersion;
///
/// [PEP 673]: https://peps.python.org/pep-0673/#motivation
/// [PEP 695]: https://peps.python.org/pep-0695/
/// [PYI018]: https://docs.astral.sh/ruff/rules/unused-private-type-var/
/// [type parameter list]: https://docs.python.org/3/reference/compound_stmts.html#type-params
/// [Self]: https://docs.python.org/3/library/typing.html#typing.Self
/// [typing_TypeVar]: https://docs.python.org/3/library/typing.html#typing.TypeVar
#[derive(ViolationMetadata)]
pub(crate) struct CustomTypeVarForSelf {
typevar_name: String,
@ -199,7 +204,7 @@ pub(crate) fn custom_type_var_instead_of_self(
let mut diagnostic = Diagnostic::new(
CustomTypeVarForSelf {
typevar_name: custom_typevar.name(checker).to_string(),
typevar_name: custom_typevar.name(checker.source()).to_string(),
},
diagnostic_range,
);
@ -211,7 +216,6 @@ pub(crate) fn custom_type_var_instead_of_self(
custom_typevar,
self_or_cls_parameter,
self_or_cls_annotation,
function_header_end,
)
});
@ -466,7 +470,7 @@ fn custom_typevar_preview<'a>(
///
/// * Import `Self` if necessary
/// * Remove the first parameter's annotation
/// * Replace other uses of the original type variable elsewhere in the signature with `Self`
/// * Replace other uses of the original type variable elsewhere in the function with `Self`
/// * If it was a PEP-695 type variable, removes that `TypeVar` from the PEP-695 type-parameter list
fn replace_custom_typevar_with_self(
checker: &Checker,
@ -474,19 +478,11 @@ fn replace_custom_typevar_with_self(
custom_typevar: TypeVar,
self_or_cls_parameter: &ast::ParameterWithDefault,
self_or_cls_annotation: &ast::Expr,
function_header_end: TextSize,
) -> anyhow::Result<Option<Fix>> {
if checker.settings.preview.is_disabled() {
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);
}
// (1) Import `Self` (if necessary)
let (import_edit, self_symbol_binding) = import_self(checker, function_def.start())?;
@ -506,18 +502,18 @@ fn replace_custom_typevar_with_self(
other_edits.push(deletion_edit);
}
// (4) Replace all other references to the original type variable elsewhere in the function's header
// with `Self`
let replace_references_range =
TextRange::new(self_or_cls_annotation.end(), function_header_end);
// (4) Replace all other references to the original type variable elsewhere in the function with `Self`
let replace_references_range = TextRange::new(self_or_cls_annotation.end(), function_def.end());
other_edits.extend(replace_typevar_usages_with_self(
replace_typevar_usages_with_self(
custom_typevar,
checker.source(),
self_or_cls_annotation.range(),
&self_symbol_binding,
replace_references_range,
checker.semantic(),
));
&mut other_edits,
)?;
// (5) Determine the safety of the fixes as a whole
let comment_ranges = checker.comment_ranges();
@ -562,21 +558,35 @@ fn import_self(checker: &Checker, position: TextSize) -> Result<(Edit, String),
/// This ensures that no edit in this series will overlap with other edits.
fn replace_typevar_usages_with_self<'a>(
typevar: TypeVar<'a>,
source: &'a str,
self_or_cls_annotation_range: TextRange,
self_symbol_binding: &'a str,
editable_range: TextRange,
semantic: &'a SemanticModel<'a>,
) -> impl Iterator<Item = Edit> + 'a {
typevar
.references(semantic)
.map(Ranged::range)
.filter(move |reference_range| editable_range.contains_range(*reference_range))
.filter(move |reference_range| {
!self_or_cls_annotation_range.contains_range(*reference_range)
})
.map(|reference_range| {
Edit::range_replacement(self_symbol_binding.to_string(), reference_range)
})
edits: &mut Vec<Edit>,
) -> anyhow::Result<()> {
let tvar_name = typevar.name(source);
for reference in typevar.references(semantic) {
let reference_range = reference.range();
if &source[reference_range] != tvar_name {
bail!(
"Cannot autofix: feference in the source code (`{}`) is not equal to the typevar name (`{}`)",
&source[reference_range],
tvar_name
);
}
if !editable_range.contains_range(reference_range) {
continue;
}
if self_or_cls_annotation_range.contains_range(reference_range) {
continue;
}
edits.push(Edit::range_replacement(
self_symbol_binding.to_string(),
reference_range,
));
}
Ok(())
}
/// Create an [`Edit`] removing the `TypeVar` binding from the PEP 695 type parameter list.
@ -624,8 +634,8 @@ impl<'a> TypeVar<'a> {
self.0.kind.is_type_param()
}
fn name(self, checker: &'a Checker) -> &'a str {
self.0.name(checker.source())
fn name(self, source: &'a str) -> &'a str {
self.0.name(source)
}
fn references(

View file

@ -59,7 +59,6 @@ PYI019_0.py:54:32: PYI019 Use `Self` instead of custom TypeVar `S`
PYI019_0.py:61:48: PYI019 Use `Self` instead of custom TypeVar `S`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^ PYI019
@ -251,5 +250,67 @@ PYI019_0.py:141:63: PYI019 Use `Self` instead of custom TypeVar `S`
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
| ^ PYI019
142 |
143 | class MethodsWithBody:
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:144:36: PYI019 Use `Self` instead of custom TypeVar `S`
|
143 | class MethodsWithBody:
144 | def m[S](self: S, other: S) -> S:
| ^ PYI019
145 | x: S = other
146 | return x
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:149:41: PYI019 Use `Self` instead of custom TypeVar `S`
|
148 | @classmethod
149 | def n[S](cls: type[S], other: S) -> S:
| ^ PYI019
150 | x: type[S] = type(other)
151 | return x()
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:154:26: PYI019 Use `Self` instead of custom TypeVar `S`
|
153 | class StringizedReferencesCanBeFixed:
154 | def m[S](self: S) -> S:
| ^ PYI019
155 | x = cast("list[tuple[S, S]]", self)
156 | return x
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:159:28: PYI019 Use `Self` instead of custom TypeVar `_T`
|
158 | class ButStrangeStringizedReferencesCannotBeFixed:
159 | def m[_T](self: _T) -> _T:
| ^^ PYI019
160 | x = cast('list[_\x54]', self)
161 | return x
|
= help: Replace TypeVar `_T` with `Self`
PYI019_0.py:164:26: PYI019 Use `Self` instead of custom TypeVar `S`
|
163 | class DeletionsAreNotTouched:
164 | def m[S](self: S) -> S:
| ^ PYI019
165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 | # so `del S` here is not actually a reference to the type variable `S`.
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:173:26: PYI019 Use `Self` instead of custom TypeVar `S`
|
172 | class NamesShadowingTypeVarAreNotTouched:
173 | def m[S](self: S) -> S:
| ^ PYI019
174 | type S = int
175 | print(S) # not a reference to the type variable, so not touched by the autofix
|
= help: Replace TypeVar `S` with `Self`

View file

@ -59,7 +59,6 @@ PYI019_0.pyi:54:32: PYI019 Use `Self` instead of custom TypeVar `S`
PYI019_0.pyi:61:48: PYI019 Use `Self` instead of custom TypeVar `S`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^ PYI019

View file

@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_0.py:7:16: PYI019 Use `Self` instead of custom TypeVar `_S`
PYI019_0.py:7:16: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
@ -9,14 +9,34 @@ PYI019_0.py:7:16: PYI019 Use `Self` instead of custom TypeVar `_S`
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:10:28: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
4 4 | _S2 = TypeVar("_S2", BadClass, GoodClass)
5 5 |
6 6 | class BadClass:
7 |- def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
7 |+ def __new__(cls, *args: str, **kwargs: int) -> Self: ... # PYI019
8 8 |
9 9 |
10 10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
PYI019_0.py:10:28: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:14:25: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
7 7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
8 8 |
9 9 |
10 |- def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
10 |+ def bad_instance_method(self, arg: bytes) -> Self: ... # PYI019
11 11 |
12 12 |
13 13 | @classmethod
PYI019_0.py:14:25: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
@ -24,7 +44,17 @@ PYI019_0.py:14:25: PYI019 Use `Self` instead of custom TypeVar `_S`
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:18:33: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
11 11 |
12 12 |
13 13 | @classmethod
14 |- def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
14 |+ def bad_class_method(cls, arg: int) -> Self: ... # PYI019
15 15 |
16 16 |
17 17 | @classmethod
PYI019_0.py:18:33: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
@ -32,7 +62,17 @@ PYI019_0.py:18:33: PYI019 Use `Self` instead of custom TypeVar `_S`
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:39:14: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
15 15 |
16 16 |
17 17 | @classmethod
18 |- def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
18 |+ def bad_posonly_class_method(cls, /) -> Self: ... # PYI019
19 19 |
20 20 |
21 21 | @classmethod
PYI019_0.py:39:14: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
@ -41,14 +81,34 @@ PYI019_0.py:39:14: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:42:30: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
36 36 |
37 37 | # Python > 3.12
38 38 | class PEP695BadDunderNew[T]:
39 |- def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
39 |+ def __new__(cls, *args: Any, ** kwargs: Any) -> Self: ... # PYI019
40 40 |
41 41 |
42 42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
PYI019_0.py:42:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:54:11: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
39 39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
40 40 |
41 41 |
42 |- def generic_instance_method[S](self: S) -> S: ... # PYI019
42 |+ def generic_instance_method(self) -> Self: ... # PYI019
43 43 |
44 44 |
45 45 | class PEP695GoodDunderNew[T]:
PYI019_0.py:54:11: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
52 | # in the settings for this test:
53 | @foo_classmethod
@ -57,9 +117,18 @@ PYI019_0.py:54:11: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:61:16: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
51 51 | # due to `foo_classmethod being listed in `pep8_naming.classmethod-decorators`
52 52 | # in the settings for this test:
53 53 | @foo_classmethod
54 |- def foo[S](cls: type[S]) -> S: ... # PYI019
54 |+ def foo(cls) -> Self: ... # PYI019
55 55 |
56 56 |
57 57 | _S695 = TypeVar("_S695", bound="PEP695Fix")
PYI019_0.py:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
@ -68,7 +137,17 @@ PYI019_0.py:61:16: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:63:26: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
58 58 |
59 59 |
60 60 | class PEP695Fix:
61 |- def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
61 |+ def __new__(cls) -> Self: ...
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
PYI019_0.py:63:26: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
@ -79,7 +158,17 @@ PYI019_0.py:63:26: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:65:16: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
60 60 | class PEP695Fix:
61 61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 62 |
63 |- def __init_subclass__[S](cls: type[S]) -> S: ...
63 |+ def __init_subclass__(cls) -> Self: ...
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
PYI019_0.py:65:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
@ -90,7 +179,17 @@ PYI019_0.py:65:16: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:67:16: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
65 |- def __neg__[S: PEP695Fix](self: S) -> S: ...
65 |+ def __neg__(self) -> Self: ...
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
PYI019_0.py:67:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
@ -101,7 +200,17 @@ PYI019_0.py:67:16: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:69:16: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
67 |- def __pos__[S](self: S) -> S: ...
67 |+ def __pos__(self) -> Self: ...
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
PYI019_0.py:69:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
@ -112,7 +221,17 @@ PYI019_0.py:69:16: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:71:16: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
69 |- def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
69 |+ def __add__(self, other: Self) -> Self: ...
70 70 |
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
PYI019_0.py:71:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
@ -123,7 +242,17 @@ PYI019_0.py:71:16: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:74:27: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
71 |- def __sub__[S](self: S, other: S) -> S: ...
71 |+ def __sub__(self, other: Self) -> Self: ...
72 72 |
73 73 | @classmethod
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
PYI019_0.py:74:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
@ -133,7 +262,17 @@ PYI019_0.py:74:27: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:77:29: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
73 73 | @classmethod
74 |- def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
74 |+ def class_method_bound(cls) -> Self: ...
75 75 |
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
PYI019_0.py:77:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
@ -143,7 +282,17 @@ PYI019_0.py:77:29: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:79:30: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
75 75 |
76 76 | @classmethod
77 |- def class_method_unbound[S](cls: type[S]) -> S: ...
77 |+ def class_method_unbound(cls) -> Self: ...
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
PYI019_0.py:79:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
@ -154,7 +303,17 @@ PYI019_0.py:79:30: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:81:32: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 78 |
79 |- def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
79 |+ def instance_method_bound(self) -> Self: ...
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
PYI019_0.py:81:32: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
@ -165,7 +324,17 @@ PYI019_0.py:81:32: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:83:53: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
81 |- def instance_method_unbound[S](self: S) -> S: ...
81 |+ def instance_method_unbound(self) -> Self: ...
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
PYI019_0.py:83:53: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
@ -176,7 +345,17 @@ PYI019_0.py:83:53: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:85:55: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
83 |- def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
83 |+ def instance_method_bound_with_another_parameter(self, other: Self) -> Self: ...
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
PYI019_0.py:85:55: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
@ -187,7 +366,17 @@ PYI019_0.py:85:55: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:87:27: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
85 |- def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
85 |+ def instance_method_unbound_with_another_parameter(self, other: Self) -> Self: ...
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
PYI019_0.py:87:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
@ -198,7 +387,17 @@ PYI019_0.py:87:27: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:89:43: PYI019 Use `Self` instead of custom TypeVar `_S695`
Safe fix
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
87 |- def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
87 |+ def multiple_type_vars[*Ts, T](self, other: Self, /, *args: *Ts, a: T, b: list[T]) -> Self: ...
88 88 |
89 89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
90 90 |
PYI019_0.py:89:43: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
@ -207,7 +406,17 @@ PYI019_0.py:89:43: PYI019 Use `Self` instead of custom TypeVar `_S695`
|
= help: Replace TypeVar `_S695` with `Self`
PYI019_0.py:94:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
89 |- def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
89 |+ def mixing_old_and_new_style_type_vars[T](self, a: T, b: T) -> Self: ...
90 90 |
91 91 |
92 92 | class InvalidButWeDoNotPanic:
PYI019_0.py:94:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
92 | class InvalidButWeDoNotPanic:
93 | @classmethod
@ -217,7 +426,17 @@ PYI019_0.py:94:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:114:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
91 91 |
92 92 | class InvalidButWeDoNotPanic:
93 93 | @classmethod
94 |- def m[S](cls: type[S], /) -> S[int]: ...
94 |+ def m(cls, /) -> Self[int]: ...
95 95 | def n(self: S) -> S[int]: ...
96 96 |
97 97 |
PYI019_0.py:114:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
112 | class SubscriptReturnType:
113 | @classmethod
@ -226,7 +445,17 @@ PYI019_0.py:114:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:118:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
111 111 |
112 112 | class SubscriptReturnType:
113 113 | @classmethod
114 |- def m[S](cls: type[S]) -> type[S]: ... # PYI019
114 |+ def m(cls) -> type[Self]: ... # PYI019
115 115 |
116 116 |
117 117 | class SelfNotUsedInReturnAnnotation:
PYI019_0.py:118:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
117 | class SelfNotUsedInReturnAnnotation:
118 | def m[S](self: S, other: S) -> int: ...
@ -236,7 +465,17 @@ PYI019_0.py:118:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:120:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
115 115 |
116 116 |
117 117 | class SelfNotUsedInReturnAnnotation:
118 |- def m[S](self: S, other: S) -> int: ...
118 |+ def m(self, other: Self) -> int: ...
119 119 | @classmethod
120 120 | def n[S](cls: type[S], other: S) -> int: ...
121 121 |
PYI019_0.py:120:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
118 | def m[S](self: S, other: S) -> int: ...
119 | @classmethod
@ -245,7 +484,17 @@ PYI019_0.py:120:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:135:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
117 117 | class SelfNotUsedInReturnAnnotation:
118 118 | def m[S](self: S, other: S) -> int: ...
119 119 | @classmethod
120 |- def n[S](cls: type[S], other: S) -> int: ...
120 |+ def n(cls, other: Self) -> int: ...
121 121 |
122 122 |
123 123 | class _NotATypeVar: ...
PYI019_0.py:135:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
134 | class NoReturnAnnotations:
135 | def m[S](self: S, other: S): ...
@ -255,7 +504,17 @@ PYI019_0.py:135:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:137:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
132 132 |
133 133 |
134 134 | class NoReturnAnnotations:
135 |- def m[S](self: S, other: S): ...
135 |+ def m(self, other: Self): ...
136 136 | @classmethod
137 137 | def n[S](cls: type[S], other: S): ...
138 138 |
PYI019_0.py:137:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
135 | def m[S](self: S, other: S): ...
136 | @classmethod
@ -266,7 +525,17 @@ PYI019_0.py:137:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:140:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
134 134 | class NoReturnAnnotations:
135 135 | def m[S](self: S, other: S): ...
136 136 | @classmethod
137 |- def n[S](cls: type[S], other: S): ...
137 |+ def n(cls, other: Self): ...
138 138 |
139 139 | class MultipleBoundParameters:
140 140 | def m[S: int, T: int](self: S, other: T) -> S: ...
PYI019_0.py:140:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
@ -275,11 +544,149 @@ PYI019_0.py:140:10: PYI019 Use `Self` instead of custom TypeVar `S`
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:141:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
137 137 | def n[S](cls: type[S], other: S): ...
138 138 |
139 139 | class MultipleBoundParameters:
140 |- def m[S: int, T: int](self: S, other: T) -> S: ...
140 |+ def m[T: int](self, other: T) -> Self: ...
141 141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
142 142 |
143 143 | class MethodsWithBody:
PYI019_0.py:141:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
142 |
143 | class MethodsWithBody:
|
= help: Replace TypeVar `S` with `Self`
Safe fix
138 138 |
139 139 | class MultipleBoundParameters:
140 140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 |- def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
141 |+ def n[T: (int, str)](self, other: T) -> Self: ...
142 142 |
143 143 | class MethodsWithBody:
144 144 | def m[S](self: S, other: S) -> S:
PYI019_0.py:144:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
143 | class MethodsWithBody:
144 | def m[S](self: S, other: S) -> S:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
145 | x: S = other
146 | return x
|
= help: Replace TypeVar `S` with `Self`
Safe fix
141 141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
142 142 |
143 143 | class MethodsWithBody:
144 |- def m[S](self: S, other: S) -> S:
145 |- x: S = other
144 |+ def m(self, other: Self) -> Self:
145 |+ x: Self = other
146 146 | return x
147 147 |
148 148 | @classmethod
PYI019_0.py:149:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
148 | @classmethod
149 | def n[S](cls: type[S], other: S) -> S:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
150 | x: type[S] = type(other)
151 | return x()
|
= help: Replace TypeVar `S` with `Self`
Safe fix
146 146 | return x
147 147 |
148 148 | @classmethod
149 |- def n[S](cls: type[S], other: S) -> S:
150 |- x: type[S] = type(other)
149 |+ def n(cls, other: Self) -> Self:
150 |+ x: type[Self] = type(other)
151 151 | return x()
152 152 |
153 153 | class StringizedReferencesCanBeFixed:
PYI019_0.py:154:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
153 | class StringizedReferencesCanBeFixed:
154 | def m[S](self: S) -> S:
| ^^^^^^^^^^^^^^^^^ PYI019
155 | x = cast("list[tuple[S, S]]", self)
156 | return x
|
= help: Replace TypeVar `S` with `Self`
Safe fix
151 151 | return x()
152 152 |
153 153 | class StringizedReferencesCanBeFixed:
154 |- def m[S](self: S) -> S:
155 |- x = cast("list[tuple[S, S]]", self)
154 |+ def m(self) -> Self:
155 |+ x = cast("list[tuple[Self, Self]]", self)
156 156 | return x
157 157 |
158 158 | class ButStrangeStringizedReferencesCannotBeFixed:
PYI019_0.py:159:10: PYI019 Use `Self` instead of custom TypeVar `_T`
|
158 | class ButStrangeStringizedReferencesCannotBeFixed:
159 | def m[_T](self: _T) -> _T:
| ^^^^^^^^^^^^^^^^^^^^ PYI019
160 | x = cast('list[_\x54]', self)
161 | return x
|
= help: Replace TypeVar `_T` with `Self`
PYI019_0.py:164:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
163 | class DeletionsAreNotTouched:
164 | def m[S](self: S) -> S:
| ^^^^^^^^^^^^^^^^^ PYI019
165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 | # so `del S` here is not actually a reference to the type variable `S`.
|
= help: Replace TypeVar `S` with `Self`
Safe fix
161 161 | return x
162 162 |
163 163 | class DeletionsAreNotTouched:
164 |- def m[S](self: S) -> S:
164 |+ def m(self) -> Self:
165 165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 166 | # so `del S` here is not actually a reference to the type variable `S`.
167 167 | # This `del` statement is therefore not touched by the autofix (it raises `UnboundLocalError`
PYI019_0.py:173:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
172 | class NamesShadowingTypeVarAreNotTouched:
173 | def m[S](self: S) -> S:
| ^^^^^^^^^^^^^^^^^ PYI019
174 | type S = int
175 | print(S) # not a reference to the type variable, so not touched by the autofix
|
= help: Replace TypeVar `S` with `Self`
Safe fix
170 170 | return self
171 171 |
172 172 | class NamesShadowingTypeVarAreNotTouched:
173 |- def m[S](self: S) -> S:
173 |+ def m(self) -> Self:
174 174 | type S = int
175 175 | print(S) # not a reference to the type variable, so not touched by the autofix
176 176 | return 42

View file

@ -129,7 +129,6 @@ PYI019_0.pyi:54:11: PYI019 [*] Use `Self` instead of custom TypeVar `S`
PYI019_0.pyi:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
59 | # Only .pyi gets fixes, no fixes for .py
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
@ -140,7 +139,7 @@ PYI019_0.pyi:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
Safe fix
58 58 |
59 59 | # Only .pyi gets fixes, no fixes for .py
59 59 |
60 60 | class PEP695Fix:
61 |- def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
61 |+ def __new__(cls) -> Self: ...