mirror of https://github.com/astral-sh/ruff
[`pyupgrade`] Extend `UP019` to detect `typing_extensions.Text` (`UP019`) (#20825)
Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
abf685b030
commit
9e1aafd0ce
|
|
@ -18,3 +18,20 @@ def print_third_word(word: Hello.Text) -> None:
|
|||
|
||||
def print_fourth_word(word: Goodbye) -> None:
|
||||
print(word)
|
||||
|
||||
|
||||
import typing_extensions
|
||||
import typing_extensions as TypingExt
|
||||
from typing_extensions import Text as TextAlias
|
||||
|
||||
|
||||
def print_fifth_word(word: typing_extensions.Text) -> None:
|
||||
print(word)
|
||||
|
||||
|
||||
def print_sixth_word(word: TypingExt.Text) -> None:
|
||||
print(word)
|
||||
|
||||
|
||||
def print_seventh_word(word: TextAlias) -> None:
|
||||
print(word)
|
||||
|
|
|
|||
|
|
@ -265,3 +265,7 @@ pub(crate) const fn is_fix_read_whole_file_enabled(settings: &LinterSettings) ->
|
|||
pub(crate) const fn is_fix_write_whole_file_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
pub(crate) const fn is_typing_extensions_str_alias_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test_case(Rule::SuperCallWithParameters, Path::new("UP008.py"))]
|
||||
#[test_case(Rule::TypingTextStrAlias, Path::new("UP019.py"))]
|
||||
fn rules_preview(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}__preview", path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
use ruff_python_ast::Expr;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||
use ruff_python_semantic::Modules;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_typing_extensions_str_alias_enabled;
|
||||
use crate::{Edit, Fix, FixAvailability, Violation};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of `typing.Text`.
|
||||
///
|
||||
/// In preview mode, also checks for `typing_extensions.Text`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `typing.Text` is an alias for `str`, and only exists for Python 2
|
||||
/// compatibility. As of Python 3.11, `typing.Text` is deprecated. Use `str`
|
||||
|
|
@ -30,14 +34,16 @@ use crate::{Edit, Fix, FixAvailability, Violation};
|
|||
/// ## References
|
||||
/// - [Python documentation: `typing.Text`](https://docs.python.org/3/library/typing.html#typing.Text)
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct TypingTextStrAlias;
|
||||
pub(crate) struct TypingTextStrAlias {
|
||||
module: TypingModule,
|
||||
}
|
||||
|
||||
impl Violation for TypingTextStrAlias {
|
||||
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
"`typing.Text` is deprecated, use `str`".to_string()
|
||||
format!("`{}.Text` is deprecated, use `str`", self.module)
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> Option<String> {
|
||||
|
|
@ -47,16 +53,26 @@ impl Violation for TypingTextStrAlias {
|
|||
|
||||
/// UP019
|
||||
pub(crate) fn typing_text_str_alias(checker: &Checker, expr: &Expr) {
|
||||
if !checker.semantic().seen_module(Modules::TYPING) {
|
||||
if !checker
|
||||
.semantic()
|
||||
.seen_module(Modules::TYPING | Modules::TYPING_EXTENSIONS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if checker
|
||||
.semantic()
|
||||
.resolve_qualified_name(expr)
|
||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["typing", "Text"]))
|
||||
if let Some(qualified_name) = checker.semantic().resolve_qualified_name(expr) {
|
||||
let segments = qualified_name.segments();
|
||||
let module = match segments {
|
||||
["typing", "Text"] => TypingModule::Typing,
|
||||
["typing_extensions", "Text"]
|
||||
if is_typing_extensions_str_alias_enabled(checker.settings()) =>
|
||||
{
|
||||
let mut diagnostic = checker.report_diagnostic(TypingTextStrAlias, expr.range());
|
||||
TypingModule::TypingExtensions
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let mut diagnostic = checker.report_diagnostic(TypingTextStrAlias { module }, expr.range());
|
||||
diagnostic.add_primary_tag(ruff_db::diagnostic::DiagnosticTag::Deprecated);
|
||||
diagnostic.try_set_fix(|| {
|
||||
let (import_edit, binding) = checker.importer().get_or_import_builtin_symbol(
|
||||
|
|
@ -71,3 +87,18 @@ pub(crate) fn typing_text_str_alias(checker: &Checker, expr: &Expr) {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum TypingModule {
|
||||
Typing,
|
||||
TypingExtensions,
|
||||
}
|
||||
|
||||
impl Display for TypingModule {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
TypingModule::Typing => f.write_str("typing"),
|
||||
TypingModule::TypingExtensions => f.write_str("typing_extensions"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,3 +66,5 @@ help: Replace with `str`
|
|||
- def print_fourth_word(word: Goodbye) -> None:
|
||||
19 + def print_fourth_word(word: str) -> None:
|
||||
20 | print(word)
|
||||
21 |
|
||||
22 |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
|
||||
---
|
||||
UP019 [*] `typing.Text` is deprecated, use `str`
|
||||
--> UP019.py:7:22
|
||||
|
|
||||
7 | def print_word(word: Text) -> None:
|
||||
| ^^^^
|
||||
8 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
4 | from typing import Text as Goodbye
|
||||
5 |
|
||||
6 |
|
||||
- def print_word(word: Text) -> None:
|
||||
7 + def print_word(word: str) -> None:
|
||||
8 | print(word)
|
||||
9 |
|
||||
10 |
|
||||
|
||||
UP019 [*] `typing.Text` is deprecated, use `str`
|
||||
--> UP019.py:11:29
|
||||
|
|
||||
11 | def print_second_word(word: typing.Text) -> None:
|
||||
| ^^^^^^^^^^^
|
||||
12 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
8 | print(word)
|
||||
9 |
|
||||
10 |
|
||||
- def print_second_word(word: typing.Text) -> None:
|
||||
11 + def print_second_word(word: str) -> None:
|
||||
12 | print(word)
|
||||
13 |
|
||||
14 |
|
||||
|
||||
UP019 [*] `typing.Text` is deprecated, use `str`
|
||||
--> UP019.py:15:28
|
||||
|
|
||||
15 | def print_third_word(word: Hello.Text) -> None:
|
||||
| ^^^^^^^^^^
|
||||
16 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
12 | print(word)
|
||||
13 |
|
||||
14 |
|
||||
- def print_third_word(word: Hello.Text) -> None:
|
||||
15 + def print_third_word(word: str) -> None:
|
||||
16 | print(word)
|
||||
17 |
|
||||
18 |
|
||||
|
||||
UP019 [*] `typing.Text` is deprecated, use `str`
|
||||
--> UP019.py:19:29
|
||||
|
|
||||
19 | def print_fourth_word(word: Goodbye) -> None:
|
||||
| ^^^^^^^
|
||||
20 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
16 | print(word)
|
||||
17 |
|
||||
18 |
|
||||
- def print_fourth_word(word: Goodbye) -> None:
|
||||
19 + def print_fourth_word(word: str) -> None:
|
||||
20 | print(word)
|
||||
21 |
|
||||
22 |
|
||||
|
||||
UP019 [*] `typing_extensions.Text` is deprecated, use `str`
|
||||
--> UP019.py:28:28
|
||||
|
|
||||
28 | def print_fifth_word(word: typing_extensions.Text) -> None:
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
29 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
25 | from typing_extensions import Text as TextAlias
|
||||
26 |
|
||||
27 |
|
||||
- def print_fifth_word(word: typing_extensions.Text) -> None:
|
||||
28 + def print_fifth_word(word: str) -> None:
|
||||
29 | print(word)
|
||||
30 |
|
||||
31 |
|
||||
|
||||
UP019 [*] `typing_extensions.Text` is deprecated, use `str`
|
||||
--> UP019.py:32:28
|
||||
|
|
||||
32 | def print_sixth_word(word: TypingExt.Text) -> None:
|
||||
| ^^^^^^^^^^^^^^
|
||||
33 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
29 | print(word)
|
||||
30 |
|
||||
31 |
|
||||
- def print_sixth_word(word: TypingExt.Text) -> None:
|
||||
32 + def print_sixth_word(word: str) -> None:
|
||||
33 | print(word)
|
||||
34 |
|
||||
35 |
|
||||
|
||||
UP019 [*] `typing_extensions.Text` is deprecated, use `str`
|
||||
--> UP019.py:36:30
|
||||
|
|
||||
36 | def print_seventh_word(word: TextAlias) -> None:
|
||||
| ^^^^^^^^^
|
||||
37 | print(word)
|
||||
|
|
||||
help: Replace with `str`
|
||||
33 | print(word)
|
||||
34 |
|
||||
35 |
|
||||
- def print_seventh_word(word: TextAlias) -> None:
|
||||
36 + def print_seventh_word(word: str) -> None:
|
||||
37 | print(word)
|
||||
Loading…
Reference in New Issue