[flake8-pyi] Make PEP-695 functions with multiple type parameters fixable by PYI019 again (#15938)

This commit is contained in:
Alex Waygood 2025-02-04 14:38:22 +00:00 committed by GitHub
parent 24c1cf71cb
commit 5bf0e2e95e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 114 additions and 4 deletions

View file

@ -135,3 +135,7 @@ class NoReturnAnnotations:
def m[S](self: S, other: S): ...
@classmethod
def n[S](cls: type[S], other: S): ...
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: ...

View file

@ -161,3 +161,7 @@ class NoReturnAnnotations:
def m[S](self: S, other: S): ...
@classmethod
def n[S](cls: type[S], other: S): ...
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: ...

View file

@ -1,4 +1,5 @@
use anyhow::{bail, Context};
use itertools::Itertools;
use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
@ -590,20 +591,26 @@ fn remove_pep695_typevar_declaration(
.then(|| Edit::range_deletion(type_params.range));
}
let tvar_index = type_params
// `custom_typevar.range()` will return the range of the name of the typevar binding.
// We need the full range of the `TypeVar` declaration (including any constraints or bounds)
// to determine the correct deletion range.
let (tvar_index, tvar_declaration) = type_params
.iter()
.position(|param| param.range() == custom_typevar.range())?;
.find_position(|param| param.name().range() == custom_typevar.range())?;
let last_index = type_params.len() - 1;
let deletion_range = if tvar_index < last_index {
// def f[A, B, C](): ...
// ^^^ Remove this
TextRange::new(custom_typevar.start(), type_params[tvar_index + 1].start())
TextRange::new(
tvar_declaration.start(),
type_params[tvar_index + 1].start(),
)
} else {
// def f[A, B, C](): ...
// ^^^ Remove this
TextRange::new(type_params[tvar_index - 1].end(), custom_typevar.end())
TextRange::new(type_params[tvar_index - 1].end(), tvar_declaration.end())
};
Some(Edit::range_deletion(deletion_range))

View file

@ -235,3 +235,21 @@ PYI019_0.py:131:40: PYI019 Use `Self` instead of custom TypeVar `_NotATypeVar`
| ^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_NotATypeVar` with `Self`
PYI019_0.py:140:49: PYI019 Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^ PYI019
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:141:63: 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
|
= help: Replace TypeVar `S` with `Self`

View file

@ -274,3 +274,21 @@ PYI019_0.pyi:158:40: PYI019 Use `Self` instead of custom TypeVar `_NotATypeVar`
160 | class NoReturnAnnotations:
|
= help: Replace TypeVar `_NotATypeVar` with `Self`
PYI019_0.pyi:166:49: PYI019 Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
166 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^ PYI019
167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:167:63: PYI019 Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
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: ...
| ^ PYI019
|
= help: Replace TypeVar `S` with `Self`

View file

@ -261,5 +261,25 @@ PYI019_0.py:137:10: PYI019 Use `Self` instead of custom TypeVar `S`
136 | @classmethod
137 | def n[S](cls: type[S], other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
138 |
139 | class MultipleBoundParameters:
|
= help: Replace TypeVar `S` with `Self`
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: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
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
|
= help: Replace TypeVar `S` with `Self`

View file

@ -623,6 +623,7 @@ PYI019_0.pyi:161:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
161 |+ def m(self, other: Self): ...
162 162 | @classmethod
163 163 | def n[S](cls: type[S], other: S): ...
164 164 |
PYI019_0.pyi:163:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
@ -630,6 +631,8 @@ PYI019_0.pyi:163:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
162 | @classmethod
163 | def n[S](cls: type[S], other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
164 |
165 | class MultipleBoundParameters:
|
= help: Replace TypeVar `S` with `Self`
@ -639,3 +642,39 @@ PYI019_0.pyi:163:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
162 162 | @classmethod
163 |- def n[S](cls: type[S], other: S): ...
163 |+ def n(cls, other: Self): ...
164 164 |
165 165 | class MultipleBoundParameters:
166 166 | def m[S: int, T: int](self: S, other: T) -> S: ...
PYI019_0.pyi:166:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
166 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
163 163 | def n[S](cls: type[S], other: S): ...
164 164 |
165 165 | class MultipleBoundParameters:
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: ...
PYI019_0.pyi:167:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
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: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
164 164 |
165 165 | class MultipleBoundParameters:
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: ...