Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/pyupgrade/UP040.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,10 @@ class Foo:
| str
),
)


# A sole starred constraint needs a trailing comma in the PEP 695 constraint tuple.
constraints = (int, str)
T_starred = TypeVar("T_starred", *constraints)
StarredList: TypeAlias = list[T_starred]
StarredAlias = TypeAliasType("StarredAlias", list[T_starred], type_params=(T_starred,))
17 changes: 17 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/pyupgrade/UP046_0.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,20 @@ class DefaultOnlyTypeVar(Generic[W]): # -> [W = int]
class Outer:
class Inner(Generic[T]):
var: T


# A sole starred constraint needs a trailing comma in the PEP 695 constraint tuple.
constraints = (int, str)
U = TypeVar("U", *constraints)


class StarredConstraints(Generic[U]):
var: U


# Mixed constraints retain both the explicit and unpacked types.
V = TypeVar("V", bool, *constraints)


class MixedConstraints(Generic[V]):
var: V
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,12 @@ def multi_param(t: list[T], c: Callable[[T], None]) -> T:
def outer():
def inner(t: T) -> T:
return t


# A sole starred constraint needs a trailing comma in the PEP 695 constraint tuple.
constraints = (int, str)
U = TypeVar("U", *constraints)


def starred_constraints(var: U) -> U:
return var
11 changes: 10 additions & 1 deletion crates/ruff_linter/resources/test/fixtures/ruff/RUF053.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,16 @@ class C[T: [a]](Generic[_A]): ...

# Existing bounds should not be deparenthesized.
# class C[T: (_Y := int)](Generic[_A]): ... # TODO: Uncomment this
# class C[T: (*a,)](Generic[_A]): ... # TODO: Uncomment this


# A sole starred constraint needs a trailing comma in the PEP 695 constraint tuple.
constraints = (str, bytes)
_H = TypeVar('_H', *constraints)
class C[T](Generic[_H]): ...


# Existing starred constraint tuples retain their trailing comma.
class C[T: (*constraints,)](Generic[_A]): ...


### No errors
Expand Down
20 changes: 13 additions & 7 deletions crates/ruff_linter/src/rules/pyupgrade/rules/pep695/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,21 @@ impl Display for DisplayTypeVar<'_> {
}
TypeVarRestriction::AnyStr => f.write_str("(bytes, str)")?,
TypeVarRestriction::Constraint(vec) => {
let len = vec.len();
f.write_str("(")?;
for (i, v) in vec.iter().enumerate() {
f.write_str(&self.source[v.range()])?;
if i < len - 1 {
f.write_str(", ")?;
match vec.as_slice() {
// A single starred expression needs a comma to form a constraint tuple:
// `TypeVar("T", *constraints)` becomes `T: (*constraints,)`.
[element] => {
write!(f, "({element},)", element = &self.source[element.range()])?;
}
_ => {
write!(
f,
"({})",
vec.iter()
.format_with(", ", |expr, f| f(&&self.source[expr.range()])),
)?;
}
}
f.write_str(")")?;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,5 +497,39 @@ help: Use the `type` keyword
- ),
- )
148 + )
149 |
|
note: This is an unsafe fix and may change runtime behavior
UP040 [*] Type alias `StarredList` uses `TypeAlias` annotation instead of the `type` keyword
--> UP040.py:157:1
|
155 | constraints = (int, str)
156 | T_starred = TypeVar("T_starred", *constraints)
157 | StarredList: TypeAlias = list[T_starred]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
158 | StarredAlias = TypeAliasType("StarredAlias", list[T_starred], type_params=(T_starred,))
|
help: Use the `type` keyword
|
156 | T_starred = TypeVar("T_starred", *constraints)
- StarredList: TypeAlias = list[T_starred]
157 + type StarredList[T_starred: (*constraints,)] = list[T_starred]
158 | StarredAlias = TypeAliasType("StarredAlias", list[T_starred], type_params=(T_starred,))
|
note: This is an unsafe fix and may change runtime behavior
UP040 [*] Type alias `StarredAlias` uses `TypeAliasType` assignment instead of the `type` keyword
--> UP040.py:158:1
|
156 | T_starred = TypeVar("T_starred", *constraints)
157 | StarredList: TypeAlias = list[T_starred]
158 | StarredAlias = TypeAliasType("StarredAlias", list[T_starred], type_params=(T_starred,))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: Use the `type` keyword
|
157 | StarredList: TypeAlias = list[T_starred]
- StarredAlias = TypeAliasType("StarredAlias", list[T_starred], type_params=(T_starred,))
158 + type StarredAlias[T_starred: (*constraints,)] = list[T_starred]
|
note: This is an unsafe fix and may change runtime behavior
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,35 @@ UP046 Generic class `TooManyGenerics` uses `Generic` subclass instead of type pa
100 | var: S
|
help: Use type parameters

UP046 [*] Generic class `StarredConstraints` uses `Generic` subclass instead of type parameters
--> UP046_0.py:152:26
|
152 | class StarredConstraints(Generic[U]):
| ^^^^^^^^^^
153 | var: U
|
help: Use type parameters
|
151 |
- class StarredConstraints(Generic[U]):
152 + class StarredConstraints[U: (*constraints,)]:
153 | var: U
|
note: This is an unsafe fix and may change runtime behavior

UP046 [*] Generic class `MixedConstraints` uses `Generic` subclass instead of type parameters
--> UP046_0.py:160:24
|
160 | class MixedConstraints(Generic[V]):
| ^^^^^^^^^^
161 | var: V
|
help: Use type parameters
|
159 |
- class MixedConstraints(Generic[V]):
160 + class MixedConstraints[V: (bool, *constraints)]:
161 | var: V
|
note: This is an unsafe fix and may change runtime behavior
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,19 @@ help: Use type parameters
57 | c(t[0])
|
note: This is an unsafe fix and may change runtime behavior

UP047 [*] Generic function `starred_constraints` should use type parameters
--> UP047_0.py:73:5
|
73 | def starred_constraints(var: U) -> U:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
74 | return var
|
help: Use type parameters
|
72 |
- def starred_constraints(var: U) -> U:
73 + def starred_constraints[U: (*constraints,)](var: U) -> U:
74 | return var
|
note: This is an unsafe fix and may change runtime behavior
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ help: Remove `Generic` base class
|
94 | # Single-element constraints should not be converted to a bound.
- class C[T: (str,)](Generic[_A]): ...
95 + class C[T: (str), _A]: ...
95 + class C[T: (str,), _A]: ...
96 | class C[T: [a]](Generic[_A]): ...
|
note: This is an unsafe fix and may change runtime behavior
Expand All @@ -449,3 +449,34 @@ help: Remove `Generic` base class
97 |
|
note: This is an unsafe fix and may change runtime behavior

RUF053 [*] Class with type parameter list inherits from `Generic`
--> RUF053.py:106:12
|
104 | constraints = (str, bytes)
105 | _H = TypeVar('_H', *constraints)
106 | class C[T](Generic[_H]): ...
| ^^^^^^^^^^^
help: Remove `Generic` base class
|
105 | _H = TypeVar('_H', *constraints)
- class C[T](Generic[_H]): ...
106 + class C[T, _H: (*constraints,)]: ...
107 |
|
note: This is an unsafe fix and may change runtime behavior

RUF053 [*] Class with type parameter list inherits from `Generic`
--> RUF053.py:110:29
|
109 | # Existing starred constraint tuples retain their trailing comma.
110 | class C[T: (*constraints,)](Generic[_A]): ...
| ^^^^^^^^^^^
help: Remove `Generic` base class
|
109 | # Existing starred constraint tuples retain their trailing comma.
- class C[T: (*constraints,)](Generic[_A]): ...
110 + class C[T: (*constraints,), _A]: ...
111 |
|
note: This is an unsafe fix and may change runtime behavior
Loading