Skip to content

Commit

Permalink
use a separate entrypoint which directly checks the function definition
Browse files Browse the repository at this point in the history
  • Loading branch information
sunank200 committed Jan 23, 2025
1 parent d96f362 commit c2e6cb2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 41 deletions.
3 changes: 3 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.enabled(Rule::PytestParameterWithDefaultArgument) {
flake8_pytest_style::rules::parameter_with_default_argument(checker, function_def);
}
if checker.enabled(Rule::Airflow3Removal) {
airflow::rules::removed_in_3_function_def(checker, function_def);
}
if checker.enabled(Rule::NonPEP695GenericFunction) {
pyupgrade::rules::non_pep695_generic_function(checker, function_def);
}
Expand Down
92 changes: 51 additions & 41 deletions crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,16 +347,6 @@ fn find_parameter<'a>(
/// print(context.get("conf"))
/// ```
///
/// **Removed context variable as a parameter:**
/// ```python
/// from airflow.decorators import task
///
/// @task
/// def another_task(execution_date, **kwargs):
/// # 'execution_date' is removed in Airflow 3.0
/// pass
/// ```
///
/// **Accessing multiple keys:**
/// ```python
/// from airflow.decorators import task
Expand Down Expand Up @@ -403,37 +393,6 @@ fn check_removed_context_keys_usage(checker: &mut Checker, call_expr: &ExprCall)
if attr.as_str() != "get" {
return;
}
let function_def = {
let mut parents = checker.semantic().current_statements();
parents.find_map(|stmt| {
if let Stmt::FunctionDef(func_def) = stmt {
Some(func_def.clone())
} else {
None
}
})
};

if let Some(func_def) = function_def {
for param in func_def
.parameters
.posonlyargs
.iter()
.chain(func_def.parameters.args.iter())
.chain(func_def.parameters.kwonlyargs.iter())
{
let param_name = param.parameter.name.as_str();
if REMOVED_CONTEXT_KEYS.contains(&param_name) {
checker.diagnostics.push(Diagnostic::new(
Airflow3Removal {
deprecated: param_name.to_string(),
replacement: Replacement::None,
},
param.parameter.name.range(),
));
}
}
}

for removed_key in REMOVED_CONTEXT_KEYS {
if let Some(argument) = call_expr.arguments.find_argument_value(removed_key, 0) {
Expand Down Expand Up @@ -1092,3 +1051,54 @@ fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix
_ => false,
}
}

/// AIR302 Check the function argument for removed context variable.
/// For example:
/// **Removed context variable as a parameter:**
/// ```python
/// from airflow.decorators import task
///
/// @task
/// def another_task(execution_date, **kwargs):
/// # 'execution_date' is removed in Airflow 3.0
/// pass
/// ```
pub(crate) fn removed_in_3_function_def(checker: &mut Checker, function_def: &StmtFunctionDef) {
if !checker.semantic().seen_module(Modules::AIRFLOW) {
return;
}

if !is_airflow_task(function_def, checker.semantic()) {
return;
}

for param in function_def
.parameters
.posonlyargs
.iter()
.chain(function_def.parameters.args.iter())
.chain(function_def.parameters.kwonlyargs.iter())
{
let param_name = param.parameter.name.as_str();
if REMOVED_CONTEXT_KEYS.contains(&param_name) {
checker.diagnostics.push(Diagnostic::new(
Airflow3Removal {
deprecated: param_name.to_string(),
replacement: Replacement::None,
},
param.parameter.name.range(),
));
}
}
}

/// Returns `true` if the given function is decorated with `@airflow.decorators.task`.
fn is_airflow_task(function_def: &StmtFunctionDef, semantic: &SemanticModel) -> bool {
function_def.decorator_list.iter().any(|decorator| {
semantic
.resolve_qualified_name(map_callable(&decorator.expression))
.is_some_and(|qualified_name| {
matches!(qualified_name.segments(), ["airflow", "decorators", "task"])
})
})
}

0 comments on commit c2e6cb2

Please sign in to comment.