1+ use crate :: importer:: ImportRequest ;
2+
13use crate :: rules:: airflow:: helpers:: ProviderReplacement ;
2- use ruff_diagnostics:: { Diagnostic , Violation } ;
4+ use ruff_diagnostics:: { Diagnostic , Edit , Fix , FixAvailability , Violation } ;
35use ruff_macros:: { derive_message_formats, ViolationMetadata } ;
46use ruff_python_ast:: { Expr , ExprAttribute } ;
57use ruff_python_semantic:: Modules ;
@@ -34,6 +36,7 @@ pub(crate) struct Airflow3SuggestedToMoveToProvider {
3436}
3537
3638impl Violation for Airflow3SuggestedToMoveToProvider {
39+ const FIX_AVAILABILITY : FixAvailability = FixAvailability :: Sometimes ;
3740 #[ derive_message_formats]
3841 fn message ( & self ) -> String {
3942 let Airflow3SuggestedToMoveToProvider {
@@ -124,14 +127,16 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
124127
125128 let replacement = match qualified_name. segments ( ) {
126129 // apache-airflow-providers-standard
127- [ "airflow" , "hooks" , "filesystem" , "FSHook" ] => ProviderReplacement :: ProviderName {
128- name : "airflow.providers.standard.hooks.filesystem.FSHook" ,
130+ [ "airflow" , "hooks" , "filesystem" , "FSHook" ] => ProviderReplacement :: AutoImport {
131+ module : "airflow.providers.standard.hooks.filesystem" ,
132+ name : "FSHook" ,
129133 provider : "standard" ,
130134 version : "0.0.1" ,
131135 } ,
132136 [ "airflow" , "hooks" , "package_index" , "PackageIndexHook" ] => {
133- ProviderReplacement :: ProviderName {
134- name : "airflow.providers.standard.hooks.package_index.PackageIndexHook" ,
137+ ProviderReplacement :: AutoImport {
138+ module : "airflow.providers.standard.hooks.package_index" ,
139+ name : "PackageIndexHook" ,
135140 provider : "standard" ,
136141 version : "0.0.1" ,
137142 }
@@ -144,8 +149,9 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
144149 version : "0.0.3" ,
145150 }
146151 }
147- [ "airflow" , "operators" , "bash" , "BashOperator" ] => ProviderReplacement :: ProviderName {
148- name : "airflow.providers.standard.operators.bash.BashOperator" ,
152+ [ "airflow" , "operators" , "bash" , "BashOperator" ] => ProviderReplacement :: AutoImport {
153+ module : "airflow.providers.standard.operators.bash" ,
154+ name : "BashOperator" ,
149155 provider : "standard" ,
150156 version : "0.0.1" ,
151157 } ,
@@ -165,14 +171,16 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
165171 version : "0.0.2" ,
166172 }
167173 }
168- [ "airflow" , "operators" , "empty" , "EmptyOperator" ] => ProviderReplacement :: ProviderName {
169- name : "airflow.providers.standard.operators.empty.EmptyOperator" ,
174+ [ "airflow" , "operators" , "empty" , "EmptyOperator" ] => ProviderReplacement :: AutoImport {
175+ module : "airflow.providers.standard.operators.empty" ,
176+ name : "EmptyOperator" ,
170177 provider : "standard" ,
171178 version : "0.0.2" ,
172179 } ,
173180 [ "airflow" , "operators" , "latest_only" , "LatestOnlyOperator" ] => {
174- ProviderReplacement :: ProviderName {
175- name : "airflow.providers.standard.operators.latest_only.LatestOnlyOperator" ,
181+ ProviderReplacement :: AutoImport {
182+ module : "airflow.providers.standard.operators.latest_only" ,
183+ name : "LatestOnlyOperator" ,
176184 provider : "standard" ,
177185 version : "0.0.3" ,
178186 }
@@ -187,8 +195,9 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
187195 version : "0.0.1" ,
188196 } ,
189197 [ "airflow" , "operators" , "weekday" , "BranchDayOfWeekOperator" ] => {
190- ProviderReplacement :: ProviderName {
191- name : "airflow.providers.standard.operators.weekday.BranchDayOfWeekOperator" ,
198+ ProviderReplacement :: AutoImport {
199+ module : "airflow.providers.standard.operators.weekday" ,
200+ name : "BranchDayOfWeekOperator" ,
192201 provider : "standard" ,
193202 version : "0.0.1" ,
194203 }
@@ -209,8 +218,9 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
209218 version : "0.0.3" ,
210219 }
211220 }
212- [ "airflow" , "sensors" , "filesystem" , "FileSensor" ] => ProviderReplacement :: ProviderName {
213- name : "airflow.providers.standard.sensors.filesystem.FileSensor" ,
221+ [ "airflow" , "sensors" , "filesystem" , "FileSensor" ] => ProviderReplacement :: AutoImport {
222+ module : "airflow.providers.standard.sensors.filesystem" ,
223+ name : "FileSensor" ,
214224 provider : "standard" ,
215225 version : "0.0.2" ,
216226 } ,
@@ -230,8 +240,9 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
230240 version : "0.0.1" ,
231241 }
232242 }
233- [ "airflow" , "sensors" , "weekday" , "DayOfWeekSensor" ] => ProviderReplacement :: ProviderName {
234- name : "airflow.providers.standard.sensors.weekday.DayOfWeekSensor" ,
243+ [ "airflow" , "sensors" , "weekday" , "DayOfWeekSensor" ] => ProviderReplacement :: AutoImport {
244+ module : "airflow.providers.standard.sensors.weekday" ,
245+ name : "DayOfWeekSensor" ,
235246 provider : "standard" ,
236247 version : "0.0.1" ,
237248 } ,
@@ -243,8 +254,9 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
243254 version : "0.0.3" ,
244255 }
245256 }
246- [ "airflow" , "triggers" , "file" , "FileTrigger" ] => ProviderReplacement :: ProviderName {
247- name : "airflow.providers.standard.triggers.file.FileTrigger" ,
257+ [ "airflow" , "triggers" , "file" , "FileTrigger" ] => ProviderReplacement :: AutoImport {
258+ module : "airflow.providers.standard.triggers.file" ,
259+ name : "FileTrigger" ,
248260 provider : "standard" ,
249261 version : "0.0.3" ,
250262 } ,
@@ -258,11 +270,32 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan
258270 }
259271 _ => return ,
260272 } ;
261- checker. report_diagnostic ( Diagnostic :: new (
273+
274+ let mut diagnostic = Diagnostic :: new (
262275 Airflow3SuggestedToMoveToProvider {
263276 deprecated : qualified_name. to_string ( ) ,
264- replacement,
277+ replacement : replacement . clone ( ) ,
265278 } ,
266279 ranged. range ( ) ,
267- ) ) ;
280+ ) ;
281+
282+ if let ProviderReplacement :: AutoImport {
283+ module,
284+ name,
285+ provider : _,
286+ version : _,
287+ } = replacement
288+ {
289+ diagnostic. try_set_fix ( || {
290+ let ( import_edit, binding) = checker. importer ( ) . get_or_import_symbol (
291+ & ImportRequest :: import_from ( module, name) ,
292+ expr. start ( ) ,
293+ checker. semantic ( ) ,
294+ ) ?;
295+ let replacement_edit = Edit :: range_replacement ( binding, ranged. range ( ) ) ;
296+ Ok ( Fix :: safe_edits ( import_edit, [ replacement_edit] ) )
297+ } ) ;
298+ }
299+
300+ checker. report_diagnostic ( diagnostic) ;
268301}
0 commit comments