-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[
pyupgrade
] Rename private type parameters in PEP 695 generics (`UP…
…049`) (#15862) ## Summary This is a new rule to implement the renaming of PEP 695 type parameters with leading underscores after they have (presumably) been converted from standalone type variables by either UP046 or UP047. Part of #15642. I'm not 100% sure the fix is always safe, but I haven't come up with any counterexamples yet. `Renamer` seems pretty precise, so I don't think the usual issues with comments apply. I initially tried writing this as a rule that receives a `Stmt` rather than a `Binding`, but in that case the `checker.semantic().current_scope()` was the global scope, rather than the scope of the type parameters as I needed. Most of the other rules using `Renamer` also used `Binding`s, but it does have the downside of offering separate diagnostics for each parameter to rename. ## Test Plan New snapshot tests for UP049 alone and the combination of UP046, UP049, and PYI018. --------- Co-authored-by: Alex Waygood <[email protected]>
- Loading branch information
1 parent
cb71393
commit 6bb3235
Showing
13 changed files
with
736 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP049_0.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# simple case, replace _T in signature and body | ||
class Generic[_T]: | ||
buf: list[_T] | ||
|
||
def append(self, t: _T): | ||
self.buf.append(t) | ||
|
||
|
||
# simple case, replace _T in signature and body | ||
def second[_T](var: tuple[_T]) -> _T: | ||
y: _T = var[1] | ||
return y | ||
|
||
|
||
# one diagnostic for each variable, comments are preserved | ||
def many_generics[ | ||
_T, # first generic | ||
_U, # second generic | ||
](args): | ||
return args | ||
|
||
|
||
# neither of these are currently renamed | ||
from typing import Literal, cast | ||
|
||
|
||
def f[_T](v): | ||
cast("_T", v) | ||
cast("Literal['_T']") | ||
cast("list[_T]", v) |
56 changes: 56 additions & 0 deletions
56
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP049_1.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# bound | ||
class Foo[_T: str]: | ||
var: _T | ||
|
||
|
||
# constraint | ||
class Foo[_T: (str, bytes)]: | ||
var: _T | ||
|
||
|
||
# python 3.13+ default | ||
class Foo[_T = int]: | ||
var: _T | ||
|
||
|
||
# tuple | ||
class Foo[*_Ts]: | ||
var: tuple[*_Ts] | ||
|
||
|
||
# paramspec | ||
class C[**_P]: | ||
var: _P | ||
|
||
|
||
from typing import Callable | ||
|
||
|
||
# each of these will get a separate diagnostic, but at least they'll all get | ||
# fixed | ||
class Everything[_T, _U: str, _V: (int, float), *_W, **_X]: | ||
@staticmethod | ||
def transform(t: _T, u: _U, v: _V) -> tuple[*_W] | Callable[_X, _T] | None: | ||
return None | ||
|
||
|
||
# this should not be fixed because the new name is a keyword, but we still | ||
# offer a diagnostic | ||
class F[_async]: ... | ||
|
||
|
||
# and this should not be fixed because of the conflict with the outer X, but it | ||
# also gets a diagnostic | ||
def f(): | ||
type X = int | ||
|
||
class ScopeConflict[_X]: | ||
var: _X | ||
x: X | ||
|
||
|
||
# these cases should be skipped entirely | ||
def f[_](x: _) -> _: ... | ||
def g[__](x: __) -> __: ... | ||
def h[_T_](x: _T_) -> _T_: ... | ||
def i[__T__](x: __T__) -> __T__: ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.