@@ -347,16 +347,6 @@ fn find_parameter<'a>(
347
347
/// print(context.get("conf"))
348
348
/// ```
349
349
///
350
- /// **Removed context variable as a parameter:**
351
- /// ```python
352
- /// from airflow.decorators import task
353
- ///
354
- /// @task
355
- /// def another_task(execution_date, **kwargs):
356
- /// # 'execution_date' is removed in Airflow 3.0
357
- /// pass
358
- /// ```
359
- ///
360
350
/// **Accessing multiple keys:**
361
351
/// ```python
362
352
/// from airflow.decorators import task
@@ -403,37 +393,6 @@ fn check_removed_context_keys_usage(checker: &mut Checker, call_expr: &ExprCall)
403
393
if attr. as_str ( ) != "get" {
404
394
return ;
405
395
}
406
- let function_def = {
407
- let mut parents = checker. semantic ( ) . current_statements ( ) ;
408
- parents. find_map ( |stmt| {
409
- if let Stmt :: FunctionDef ( func_def) = stmt {
410
- Some ( func_def. clone ( ) )
411
- } else {
412
- None
413
- }
414
- } )
415
- } ;
416
-
417
- if let Some ( func_def) = function_def {
418
- for param in func_def
419
- . parameters
420
- . posonlyargs
421
- . iter ( )
422
- . chain ( func_def. parameters . args . iter ( ) )
423
- . chain ( func_def. parameters . kwonlyargs . iter ( ) )
424
- {
425
- let param_name = param. parameter . name . as_str ( ) ;
426
- if REMOVED_CONTEXT_KEYS . contains ( & param_name) {
427
- checker. diagnostics . push ( Diagnostic :: new (
428
- Airflow3Removal {
429
- deprecated : param_name. to_string ( ) ,
430
- replacement : Replacement :: None ,
431
- } ,
432
- param. parameter . name . range ( ) ,
433
- ) ) ;
434
- }
435
- }
436
- }
437
396
438
397
for removed_key in REMOVED_CONTEXT_KEYS {
439
398
if let Some ( argument) = call_expr. arguments . find_argument_value ( removed_key, 0 ) {
@@ -1092,3 +1051,54 @@ fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix
1092
1051
_ => false ,
1093
1052
}
1094
1053
}
1054
+
1055
+ /// AIR302 Check the function argument for removed context variable.
1056
+ /// For example:
1057
+ /// **Removed context variable as a parameter:**
1058
+ /// ```python
1059
+ /// from airflow.decorators import task
1060
+ ///
1061
+ /// @task
1062
+ /// def another_task(execution_date, **kwargs):
1063
+ /// # 'execution_date' is removed in Airflow 3.0
1064
+ /// pass
1065
+ /// ```
1066
+ pub ( crate ) fn removed_in_3_function_def ( checker : & mut Checker , function_def : & StmtFunctionDef ) {
1067
+ if !checker. semantic ( ) . seen_module ( Modules :: AIRFLOW ) {
1068
+ return ;
1069
+ }
1070
+
1071
+ if !is_airflow_task ( function_def, checker. semantic ( ) ) {
1072
+ return ;
1073
+ }
1074
+
1075
+ for param in function_def
1076
+ . parameters
1077
+ . posonlyargs
1078
+ . iter ( )
1079
+ . chain ( function_def. parameters . args . iter ( ) )
1080
+ . chain ( function_def. parameters . kwonlyargs . iter ( ) )
1081
+ {
1082
+ let param_name = param. parameter . name . as_str ( ) ;
1083
+ if REMOVED_CONTEXT_KEYS . contains ( & param_name) {
1084
+ checker. diagnostics . push ( Diagnostic :: new (
1085
+ Airflow3Removal {
1086
+ deprecated : param_name. to_string ( ) ,
1087
+ replacement : Replacement :: None ,
1088
+ } ,
1089
+ param. parameter . name . range ( ) ,
1090
+ ) ) ;
1091
+ }
1092
+ }
1093
+ }
1094
+
1095
+ /// Returns `true` if the given function is decorated with `@airflow.decorators.task`.
1096
+ fn is_airflow_task ( function_def : & StmtFunctionDef , semantic : & SemanticModel ) -> bool {
1097
+ function_def. decorator_list . iter ( ) . any ( |decorator| {
1098
+ semantic
1099
+ . resolve_qualified_name ( map_callable ( & decorator. expression ) )
1100
+ . is_some_and ( |qualified_name| {
1101
+ matches ! ( qualified_name. segments( ) , [ "airflow" , "decorators" , "task" ] )
1102
+ } )
1103
+ } )
1104
+ }
0 commit comments