11use ruff_python_ast:: Expr ;
2+ use std:: fmt:: { Display , Formatter } ;
23
34use ruff_macros:: { ViolationMetadata , derive_message_formats} ;
45use ruff_python_semantic:: Modules ;
56use ruff_text_size:: Ranged ;
67
78use crate :: checkers:: ast:: Checker ;
9+ use crate :: preview:: is_typing_extensions_str_alias_enabled;
810use crate :: { Edit , Fix , FixAvailability , Violation } ;
911
1012/// ## What it does
1113/// Checks for uses of `typing.Text`.
1214///
15+ /// In preview mode, also checks for `typing_extensions.Text`.
16+ ///
1317/// ## Why is this bad?
1418/// `typing.Text` is an alias for `str`, and only exists for Python 2
1519/// compatibility. As of Python 3.11, `typing.Text` is deprecated. Use `str`
@@ -30,14 +34,16 @@ use crate::{Edit, Fix, FixAvailability, Violation};
3034/// ## References
3135/// - [Python documentation: `typing.Text`](https://docs.python.org/3/library/typing.html#typing.Text)
3236#[ derive( ViolationMetadata ) ]
33- pub ( crate ) struct TypingTextStrAlias ;
37+ pub ( crate ) struct TypingTextStrAlias {
38+ module : TypingModule ,
39+ }
3440
3541impl Violation for TypingTextStrAlias {
3642 const FIX_AVAILABILITY : FixAvailability = FixAvailability :: Sometimes ;
3743
3844 #[ derive_message_formats]
3945 fn message ( & self ) -> String {
40- "`typing .Text` is deprecated, use `str`". to_string ( )
46+ format ! ( "`{} .Text` is deprecated, use `str`", self . module )
4147 }
4248
4349 fn fix_title ( & self ) -> Option < String > {
@@ -47,16 +53,26 @@ impl Violation for TypingTextStrAlias {
4753
4854/// UP019
4955pub ( crate ) fn typing_text_str_alias ( checker : & Checker , expr : & Expr ) {
50- if !checker. semantic ( ) . seen_module ( Modules :: TYPING ) {
56+ if !checker
57+ . semantic ( )
58+ . seen_module ( Modules :: TYPING | Modules :: TYPING_EXTENSIONS )
59+ {
5160 return ;
5261 }
5362
54- if checker
55- . semantic ( )
56- . resolve_qualified_name ( expr)
57- . is_some_and ( |qualified_name| matches ! ( qualified_name. segments( ) , [ "typing" , "Text" ] ) )
58- {
59- let mut diagnostic = checker. report_diagnostic ( TypingTextStrAlias , expr. range ( ) ) ;
63+ if let Some ( qualified_name) = checker. semantic ( ) . resolve_qualified_name ( expr) {
64+ let segments = qualified_name. segments ( ) ;
65+ let module = match segments {
66+ [ "typing" , "Text" ] => TypingModule :: Typing ,
67+ [ "typing_extensions" , "Text" ]
68+ if is_typing_extensions_str_alias_enabled ( checker. settings ( ) ) =>
69+ {
70+ TypingModule :: TypingExtensions
71+ }
72+ _ => return ,
73+ } ;
74+
75+ let mut diagnostic = checker. report_diagnostic ( TypingTextStrAlias { module } , expr. range ( ) ) ;
6076 diagnostic. add_primary_tag ( ruff_db:: diagnostic:: DiagnosticTag :: Deprecated ) ;
6177 diagnostic. try_set_fix ( || {
6278 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) {
7187 } ) ;
7288 }
7389}
90+
91+ #[ derive( Copy , Clone , Debug ) ]
92+ enum TypingModule {
93+ Typing ,
94+ TypingExtensions ,
95+ }
96+
97+ impl Display for TypingModule {
98+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
99+ match self {
100+ TypingModule :: Typing => f. write_str ( "typing" ) ,
101+ TypingModule :: TypingExtensions => f. write_str ( "typing_extensions" ) ,
102+ }
103+ }
104+ }
0 commit comments