-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add rule to upgrade type alias annotations to keyword (UP040) (#6289)
Adds rule to convert type aliases defined with annotations i.e. `x: TypeAlias = int` to the new PEP-695 syntax e.g. `type x = int`. Does not support using new generic syntax for type variables, will be addressed in a follow-up. Added as part of pyupgrade — ~the code 100 as chosen to avoid collision with real pyupgrade codes~. Part of #4617 Builds on #5062
- Loading branch information
Showing
11 changed files
with
214 additions
and
7 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import typing | ||
from typing import TypeAlias | ||
|
||
# UP040 | ||
x: typing.TypeAlias = int | ||
x: TypeAlias = int | ||
|
||
|
||
# UP040 with generics (todo) | ||
T = typing.TypeVar["T"] | ||
x: typing.TypeAlias = list[T] | ||
|
||
|
||
# OK | ||
x: TypeAlias | ||
x: int = 1 |
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
89 changes: 89 additions & 0 deletions
89
crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs
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,89 @@ | ||
use ruff_python_ast::{Expr, ExprName, Ranged, Stmt, StmtAnnAssign, StmtTypeAlias}; | ||
|
||
use crate::{registry::AsRule, settings::types::PythonVersion}; | ||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; | ||
use ruff_macros::{derive_message_formats, violation}; | ||
use ruff_text_size::TextRange; | ||
|
||
use crate::checkers::ast::Checker; | ||
|
||
/// ## What it does | ||
/// Checks for use of `TypeAlias` annotation for declaring type aliases. | ||
/// | ||
/// ## Why is this bad? | ||
/// The `type` keyword was introduced in Python 3.12 by PEP-695 for defining type aliases. | ||
/// The type keyword is easier to read and provides cleaner support for generics. | ||
/// | ||
/// ## Example | ||
/// ```python | ||
/// ListOfInt: TypeAlias = list[int] | ||
/// ``` | ||
/// | ||
/// Use instead: | ||
/// ```python | ||
/// type ListOfInt = list[int] | ||
/// ``` | ||
#[violation] | ||
pub struct NonPEP695TypeAlias { | ||
name: String, | ||
} | ||
|
||
impl Violation for NonPEP695TypeAlias { | ||
const AUTOFIX: AutofixKind = AutofixKind::Always; | ||
|
||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
let NonPEP695TypeAlias { name } = self; | ||
format!("Type alias `{name}` uses `TypeAlias` annotation instead of the `type` keyword") | ||
} | ||
|
||
fn autofix_title(&self) -> Option<String> { | ||
Some("Use the `type` keyword".to_string()) | ||
} | ||
} | ||
|
||
/// UP040 | ||
pub(crate) fn non_pep695_type_alias(checker: &mut Checker, stmt: &StmtAnnAssign) { | ||
let StmtAnnAssign { | ||
target, | ||
annotation, | ||
value, | ||
.. | ||
} = stmt; | ||
|
||
// Syntax only available in 3.12+ | ||
if checker.settings.target_version < PythonVersion::Py312 { | ||
return; | ||
} | ||
|
||
if !checker | ||
.semantic() | ||
.match_typing_expr(annotation, "TypeAlias") | ||
{ | ||
return; | ||
} | ||
|
||
let Expr::Name(ExprName { id: name, .. }) = target.as_ref() else { | ||
return; | ||
}; | ||
|
||
let Some(value) = value else { | ||
return; | ||
}; | ||
|
||
// TODO(zanie): We should check for generic type variables used in the value and define them | ||
// as type params instead | ||
let mut diagnostic = Diagnostic::new(NonPEP695TypeAlias { name: name.clone() }, stmt.range()); | ||
if checker.patch(diagnostic.kind.rule()) { | ||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement( | ||
checker.generator().stmt(&Stmt::from(StmtTypeAlias { | ||
range: TextRange::default(), | ||
name: target.clone(), | ||
type_params: None, | ||
value: value.clone(), | ||
})), | ||
stmt.range(), | ||
))); | ||
} | ||
checker.diagnostics.push(diagnostic); | ||
} |
4 changes: 4 additions & 0 deletions
4
...ade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_not_applied_py311.snap
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,4 @@ | ||
--- | ||
source: crates/ruff/src/rules/pyupgrade/mod.rs | ||
--- | ||
|
61 changes: 61 additions & 0 deletions
61
...rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap
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,61 @@ | ||
--- | ||
source: crates/ruff/src/rules/pyupgrade/mod.rs | ||
--- | ||
UP040.py:5:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | ||
| | ||
4 | # UP040 | ||
5 | x: typing.TypeAlias = int | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ UP040 | ||
6 | x: TypeAlias = int | ||
| | ||
= help: Use the `type` keyword | ||
|
||
ℹ Fix | ||
2 2 | from typing import TypeAlias | ||
3 3 | | ||
4 4 | # UP040 | ||
5 |-x: typing.TypeAlias = int | ||
5 |+type x = int | ||
6 6 | x: TypeAlias = int | ||
7 7 | | ||
8 8 | | ||
|
||
UP040.py:6:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | ||
| | ||
4 | # UP040 | ||
5 | x: typing.TypeAlias = int | ||
6 | x: TypeAlias = int | ||
| ^^^^^^^^^^^^^^^^^^ UP040 | ||
| | ||
= help: Use the `type` keyword | ||
ℹ Fix | ||
3 3 | | ||
4 4 | # UP040 | ||
5 5 | x: typing.TypeAlias = int | ||
6 |-x: TypeAlias = int | ||
6 |+type x = int | ||
7 7 | | ||
8 8 | | ||
9 9 | # UP040 with generics (todo) | ||
UP040.py:11:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | ||
| | ||
9 | # UP040 with generics (todo) | ||
10 | T = typing.TypeVar["T"] | ||
11 | x: typing.TypeAlias = list[T] | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP040 | ||
| | ||
= help: Use the `type` keyword | ||
ℹ Fix | ||
8 8 | | ||
9 9 | # UP040 with generics (todo) | ||
10 10 | T = typing.TypeVar["T"] | ||
11 |-x: typing.TypeAlias = list[T] | ||
11 |+type x = list[T] | ||
12 12 | | ||
13 13 | | ||
14 14 | # OK | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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