Skip to content

Commit 5103ef7

Browse files
committed
Add more checks for removed context variables
1 parent c3fb996 commit 5103ef7

File tree

3 files changed

+430
-89
lines changed

3 files changed

+430
-89
lines changed

crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
from airflow.decorators import task
1+
from airflow.models import DAG
2+
from airflow.operators.dummy import DummyOperator
3+
from datetime import datetime
4+
from airflow.plugins_manager import AirflowPlugin
5+
from airflow.decorators import task, get_current_context
6+
from airflow.models.baseoperator import BaseOperator
27

38
@task
49
def print_config(**context):
@@ -17,3 +22,57 @@ def print_config(**context):
1722
tomorrow_ds = context["tomorrow_ds"]
1823
yesterday_ds = context["yesterday_ds"]
1924
yesterday_ds_nodash = context["yesterday_ds_nodash"]
25+
26+
with DAG(
27+
dag_id="example_dag",
28+
schedule_interval="@daily",
29+
start_date=datetime(2023, 1, 1),
30+
template_searchpath=["/templates"],
31+
) as dag:
32+
task1 = DummyOperator(
33+
task_id="task1",
34+
params={
35+
# Removed variables in template
36+
"execution_date": "{{ execution_date }}",
37+
"next_ds": "{{ next_ds }}",
38+
"prev_ds": "{{ prev_ds }}"
39+
},
40+
)
41+
42+
class CustomMacrosPlugin(AirflowPlugin):
43+
name = "custom_macros"
44+
macros = {
45+
"execution_date_macro": lambda context: context["execution_date"],
46+
"next_ds_macro": lambda context: context["next_ds"]
47+
}
48+
49+
@task
50+
def print_config():
51+
context = get_current_context()
52+
execution_date = context["execution_date"]
53+
next_ds = context["next_ds"]
54+
next_ds_nodash = context["next_ds_nodash"]
55+
next_execution_date = context["next_execution_date"]
56+
prev_ds = context["prev_ds"]
57+
prev_ds_nodash = context["prev_ds_nodash"]
58+
prev_execution_date = context["prev_execution_date"]
59+
prev_execution_date_success = context["prev_execution_date_success"]
60+
tomorrow_ds = context["tomorrow_ds"]
61+
yesterday_ds = context["yesterday_ds"]
62+
yesterday_ds_nodash = context["yesterday_ds_nodash"]
63+
64+
class CustomOperator(BaseOperator):
65+
def execute(self, context):
66+
execution_date = context["execution_date"]
67+
next_ds = context["next_ds"]
68+
next_ds_nodash = context["next_ds_nodash"]
69+
next_execution_date = context["next_execution_date"]
70+
prev_ds = context["prev_ds"]
71+
prev_ds_nodash = context["prev_ds_nodash"]
72+
prev_execution_date = context["prev_execution_date"]
73+
prev_execution_date_success = context["prev_execution_date_success"]
74+
tomorrow_ds = context["tomorrow_ds"]
75+
yesterday_ds = context["yesterday_ds"]
76+
yesterday_ds_nodash = context["yesterday_ds_nodash"]
77+
78+

crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum Replacement {
1515
None,
1616
Name(&'static str),
1717
Message(&'static str),
18+
ContextRemovalMessage(&'static str),
1819
}
1920

2021
/// ## What it does
@@ -44,7 +45,6 @@ enum Replacement {
4445
pub(crate) struct Airflow3Removal {
4546
deprecated: String,
4647
replacement: Replacement,
47-
is_context_variable: bool,
4848
}
4949

5050
impl Violation for Airflow3Removal {
@@ -55,19 +55,17 @@ impl Violation for Airflow3Removal {
5555
let Airflow3Removal {
5656
deprecated,
5757
replacement,
58-
is_context_variable,
5958
} = self;
6059
match replacement {
6160
Replacement::None => format!("`{deprecated}` is removed in Airflow 3.0"),
6261
Replacement::Name(_) => {
6362
format!("`{deprecated}` is removed in Airflow 3.0")
6463
}
6564
Replacement::Message(message) => {
66-
if *is_context_variable {
67-
format!("`{deprecated}` {message}")
68-
} else {
69-
format!("`{deprecated}` is removed in Airflow 3.0; {message}")
70-
}
65+
format!("`{deprecated}` is removed in Airflow 3.0; {message}")
66+
}
67+
Replacement::ContextRemovalMessage(message) => {
68+
format!("`{deprecated}` {message}")
7169
}
7270
}
7371
}
@@ -95,7 +93,6 @@ fn diagnostic_for_argument(
9593
Some(name) => Replacement::Name(name),
9694
None => Replacement::None,
9795
},
98-
is_context_variable: false,
9996
},
10097
keyword
10198
.arg
@@ -213,7 +210,6 @@ fn removed_method(checker: &mut Checker, expr: &Expr) {
213210
Airflow3Removal {
214211
deprecated: attr.to_string(),
215212
replacement,
216-
is_context_variable: false,
217213
},
218214
attr.range(),
219215
));
@@ -651,7 +647,6 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) {
651647
Airflow3Removal {
652648
deprecated,
653649
replacement,
654-
is_context_variable: false,
655650
},
656651
ranged.range(),
657652
));
@@ -667,31 +662,32 @@ fn extract_name_from_slice(slice: &Expr) -> Option<String> {
667662
}
668663

669664
pub(crate) fn removed_context_variable(checker: &mut Checker, expr: &Expr) {
665+
const REMOVED_CONTEXT_KEYS: [&str; 12] = [
666+
"conf",
667+
"execution_date",
668+
"next_ds",
669+
"next_ds_nodash",
670+
"next_execution_date",
671+
"prev_ds",
672+
"prev_ds_nodash",
673+
"prev_execution_date",
674+
"prev_execution_date_success",
675+
"tomorrow_ds",
676+
"yesterday_ds",
677+
"yesterday_ds_nodash",
678+
];
679+
670680
if let Expr::Subscript(ExprSubscript { value, slice, .. }) = expr {
671681
if let Expr::Name(ExprName { id, .. }) = &**value {
672682
if id.as_str() == "context" {
673683
if let Some(key) = extract_name_from_slice(slice) {
674-
const REMOVED_CONTEXT_KEYS: [&str; 11] = [
675-
"execution_date",
676-
"next_ds",
677-
"next_ds_nodash",
678-
"next_execution_date",
679-
"prev_ds",
680-
"prev_ds_nodash",
681-
"prev_execution_date",
682-
"prev_execution_date_success",
683-
"tomorrow_ds",
684-
"yesterday_ds",
685-
"yesterday_ds_nodash",
686-
];
687684
if REMOVED_CONTEXT_KEYS.contains(&key.as_str()) {
688685
checker.diagnostics.push(Diagnostic::new(
689686
Airflow3Removal {
690687
deprecated: key,
691-
replacement: Replacement::Message(
692-
"is removed in the Airflow context in Airflow 3.0",
688+
replacement: Replacement::ContextRemovalMessage(
689+
"is removed in Airflow 3.0.",
693690
),
694-
is_context_variable: true,
695691
},
696692
slice.range(),
697693
));
@@ -700,6 +696,23 @@ pub(crate) fn removed_context_variable(checker: &mut Checker, expr: &Expr) {
700696
}
701697
}
702698
}
699+
700+
if let Expr::StringLiteral(ExprStringLiteral { value, .. }) = expr {
701+
let value_str = value.to_string();
702+
for key in REMOVED_CONTEXT_KEYS {
703+
if value_str.contains(&format!("{{{{ {key} }}}}")) {
704+
checker.diagnostics.push(Diagnostic::new(
705+
Airflow3Removal {
706+
deprecated: key.to_string(),
707+
replacement: Replacement::ContextRemovalMessage(
708+
"is removed in Airflow 3.0.",
709+
),
710+
},
711+
expr.range(),
712+
));
713+
}
714+
}
715+
}
703716
}
704717

705718
/// AIR302

0 commit comments

Comments
 (0)