From fb8b3002f8f4346b02d968be05aae108ae2103c3 Mon Sep 17 00:00:00 2001 From: Ankit Chaurasia <8670962+sunank200@users.noreply.github.com> Date: Mon, 6 Jan 2025 12:13:59 +0545 Subject: [PATCH] Check arguments and function decorated with @task --- .../test/fixtures/airflow/AIR302_context.py | 48 ++ .../src/rules/airflow/rules/removal_in_3.rs | 133 +++- ...flow__tests__AIR302_AIR302_context.py.snap | 606 ++++++++++-------- 3 files changed, 499 insertions(+), 288 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py index 31aad3834427e..31511c446f2ac 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py @@ -1,9 +1,44 @@ +import pendulum from airflow.models import DAG from airflow.operators.dummy import DummyOperator from datetime import datetime from airflow.plugins_manager import AirflowPlugin from airflow.decorators import task, get_current_context from airflow.models.baseoperator import BaseOperator +from airflow.decorators import dag, task +from airflow.providers.standard.operators.python import PythonOperator + + +def access_invalid_key_in_context(**context): + print("access invalid key", context["conf"]) + + +@task +def access_invalid_key_task_out_of_dag(**context): + print("access invalid key", context.get("conf")) + + + +@dag( + schedule=None, + start_date=pendulum.datetime(2021, 1, 1, tz="UTC"), + catchup=False, + tags=[""], +) +def invalid_dag(): + @task() + def access_invalid_key_task(**context): + print("access invalid key", context.get("conf")) + + task1 = PythonOperator( + task_id="task1", + python_callable=access_invalid_key_in_context, + ) + access_invalid_key_task() >> task1 + access_invalid_key_task_out_of_dag() + + +invalid_dag() @task def print_config(**context): @@ -74,3 +109,16 @@ def execute(self, context): tomorrow_ds = context["tomorrow_ds"] yesterday_ds = context["yesterday_ds"] yesterday_ds_nodash = context["yesterday_ds_nodash"] + +@task +def access_invalid_argument_task_out_of_dag(execution_date, **context): + print("execution date", execution_date) + print("access invalid key", context.get("conf")) + +@task(task_id="print_the_context") +def print_context(ds=None, **kwargs): + """Print the Airflow context and ds variable from the context.""" + print(ds) + print(kwargs.get("tomorrow_ds")) + +run_this = print_context() diff --git a/crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs b/crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs index 01007f6523a83..9791695906bde 100644 --- a/crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs +++ b/crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs @@ -1,8 +1,10 @@ +use crate::checkers::ast::Checker; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, ViolationMetadata}; +use ruff_python_ast::helpers::map_callable; use ruff_python_ast::{ name::QualifiedName, Arguments, Expr, ExprAttribute, ExprCall, ExprContext, ExprName, - ExprStringLiteral, ExprSubscript, StmtClassDef, + ExprStringLiteral, ExprSubscript, Stmt, StmtClassDef, StmtFunctionDef, }; use ruff_python_semantic::analyze::typing; use ruff_python_semantic::Modules; @@ -10,8 +12,6 @@ use ruff_python_semantic::ScopeKind; use ruff_text_size::Ranged; use ruff_text_size::TextRange; -use crate::checkers::ast::Checker; - /// ## What it does /// Checks for uses of deprecated Airflow functions and values. /// @@ -71,6 +71,21 @@ impl Violation for Airflow3Removal { } } +const REMOVED_CONTEXT_KEYS: [&str; 12] = [ + "conf", + "execution_date", + "next_ds", + "next_ds_nodash", + "next_execution_date", + "prev_ds", + "prev_ds_nodash", + "prev_execution_date", + "prev_execution_date_success", + "tomorrow_ds", + "yesterday_ds", + "yesterday_ds_nodash", +]; + fn extract_name_from_slice(slice: &Expr) -> Option { match slice { Expr::StringLiteral(ExprStringLiteral { value, .. }) => Some(value.to_string()), @@ -79,21 +94,6 @@ fn extract_name_from_slice(slice: &Expr) -> Option { } pub(crate) fn removed_context_variable(checker: &mut Checker, expr: &Expr) { - const REMOVED_CONTEXT_KEYS: [&str; 12] = [ - "conf", - "execution_date", - "next_ds", - "next_ds_nodash", - "next_execution_date", - "prev_ds", - "prev_ds_nodash", - "prev_execution_date", - "prev_execution_date_success", - "tomorrow_ds", - "yesterday_ds", - "yesterday_ds_nodash", - ]; - if let Expr::Subscript(ExprSubscript { value, slice, .. }) = expr { if let Expr::Name(ExprName { id, .. }) = &**value { if id.as_str() == "context" { @@ -144,6 +144,7 @@ pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { check_call_arguments(checker, &qualname, arguments); }; check_method(checker, call_expr); + check_context_get(checker, call_expr); } Expr::Attribute(attribute_expr @ ExprAttribute { attr, .. }) => { check_name(checker, expr, attr.range()); @@ -307,6 +308,50 @@ fn check_class_attribute(checker: &mut Checker, attribute_expr: &ExprAttribute) } } +/// Check whether a removed context key is access through context.get("key"). +/// +/// ```python +/// from airflow.decorators import task +/// +/// +/// @task +/// def access_invalid_key_task_out_of_dag(**context): +/// print("access invalid key", context.get("conf")) +/// ``` +fn check_context_get(checker: &mut Checker, call_expr: &ExprCall) { + if is_task_context_referenced(checker, &call_expr.func) { + return; + } + + let Expr::Attribute(ExprAttribute { value, attr, .. }) = &*call_expr.func else { + return; + }; + + if !value + .as_name_expr() + .is_some_and(|name| matches!(name.id.as_str(), "context" | "kwargs")) + { + return; + } + + if attr.as_str() != "get" { + return; + } + + for removed_key in REMOVED_CONTEXT_KEYS { + if let Some(argument) = call_expr.arguments.find_argument_value(removed_key, 0) { + checker.diagnostics.push(Diagnostic::new( + Airflow3Removal { + deprecated: removed_key.to_string(), + replacement: Replacement::None, + }, + argument.range(), + )); + return; + } + } +} + /// Check whether a removed Airflow class method is called. /// /// For example: @@ -909,3 +954,55 @@ fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix _ => false, } } + +fn is_task_context_referenced(checker: &mut Checker, expr: &Expr) -> bool { + let parents: Vec<_> = checker.semantic().current_statements().collect(); + + for stmt in parents { + if let Stmt::FunctionDef(function_def) = stmt { + if is_decorated_with(checker, function_def) { + let arguments = extract_task_function_arguments(function_def); + + for deprecated_arg in REMOVED_CONTEXT_KEYS { + if arguments.contains(&deprecated_arg.to_string()) { + checker.diagnostics.push(Diagnostic::new( + Airflow3Removal { + deprecated: deprecated_arg.to_string(), + replacement: Replacement::None, + }, + expr.range(), + )); + return true; + } + } + } + } + } + + false +} + +fn extract_task_function_arguments(stmt: &StmtFunctionDef) -> Vec { + let mut arguments = Vec::new(); + + for param in &stmt.parameters.args { + arguments.push(param.parameter.name.to_string()); + } + + if let Some(vararg) = &stmt.parameters.kwarg { + arguments.push(format!("**{}", vararg.name)); + } + + arguments +} + +fn is_decorated_with(checker: &mut Checker, stmt: &StmtFunctionDef) -> bool { + stmt.decorator_list.iter().any(|decorator| { + checker + .semantic() + .resolve_qualified_name(map_callable(&decorator.expression)) + .is_some_and(|qualified_name| { + matches!(qualified_name.segments(), ["airflow", "decorators", "task"]) + }) + }) +} diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_context.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_context.py.snap index 1403c8e025ef5..57fb6609788f4 100644 --- a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_context.py.snap +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_context.py.snap @@ -2,377 +2,443 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs snapshot_kind: text --- -AIR302_context.py:14:30: AIR302 `execution_date` is removed in Airflow 3.0 +AIR302_context.py:13:41: AIR302 `conf` is removed in Airflow 3.0 | -13 | # Removed usage - should trigger violations -14 | execution_date = context["execution_date"] +12 | def access_invalid_key_in_context(**context): +13 | print("access invalid key", context["conf"]) + | ^^^^^^ AIR302 + | + +AIR302_context.py:18:45: AIR302 `conf` is removed in Airflow 3.0 + | +16 | @task +17 | def access_invalid_key_task_out_of_dag(**context): +18 | print("access invalid key", context.get("conf")) + | ^^^^^^ AIR302 + | + +AIR302_context.py:31:49: AIR302 `conf` is removed in Airflow 3.0 + | +29 | @task() +30 | def access_invalid_key_task(**context): +31 | print("access invalid key", context.get("conf")) + | ^^^^^^ AIR302 +32 | +33 | task1 = PythonOperator( + | + +AIR302_context.py:49:30: AIR302 `execution_date` is removed in Airflow 3.0 + | +48 | # Removed usage - should trigger violations +49 | execution_date = context["execution_date"] | ^^^^^^^^^^^^^^^^ AIR302 -15 | next_ds = context["next_ds"] -16 | next_ds_nodash = context["next_ds_nodash"] +50 | next_ds = context["next_ds"] +51 | next_ds_nodash = context["next_ds_nodash"] | -AIR302_context.py:15:23: AIR302 `next_ds` is removed in Airflow 3.0 +AIR302_context.py:50:23: AIR302 `next_ds` is removed in Airflow 3.0 | -13 | # Removed usage - should trigger violations -14 | execution_date = context["execution_date"] -15 | next_ds = context["next_ds"] +48 | # Removed usage - should trigger violations +49 | execution_date = context["execution_date"] +50 | next_ds = context["next_ds"] | ^^^^^^^^^ AIR302 -16 | next_ds_nodash = context["next_ds_nodash"] -17 | next_execution_date = context["next_execution_date"] +51 | next_ds_nodash = context["next_ds_nodash"] +52 | next_execution_date = context["next_execution_date"] | -AIR302_context.py:16:30: AIR302 `next_ds_nodash` is removed in Airflow 3.0 +AIR302_context.py:51:30: AIR302 `next_ds_nodash` is removed in Airflow 3.0 | -14 | execution_date = context["execution_date"] -15 | next_ds = context["next_ds"] -16 | next_ds_nodash = context["next_ds_nodash"] +49 | execution_date = context["execution_date"] +50 | next_ds = context["next_ds"] +51 | next_ds_nodash = context["next_ds_nodash"] | ^^^^^^^^^^^^^^^^ AIR302 -17 | next_execution_date = context["next_execution_date"] -18 | prev_ds = context["prev_ds"] +52 | next_execution_date = context["next_execution_date"] +53 | prev_ds = context["prev_ds"] | -AIR302_context.py:17:35: AIR302 `next_execution_date` is removed in Airflow 3.0 +AIR302_context.py:52:35: AIR302 `next_execution_date` is removed in Airflow 3.0 | -15 | next_ds = context["next_ds"] -16 | next_ds_nodash = context["next_ds_nodash"] -17 | next_execution_date = context["next_execution_date"] +50 | next_ds = context["next_ds"] +51 | next_ds_nodash = context["next_ds_nodash"] +52 | next_execution_date = context["next_execution_date"] | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -18 | prev_ds = context["prev_ds"] -19 | prev_ds_nodash = context["prev_ds_nodash"] +53 | prev_ds = context["prev_ds"] +54 | prev_ds_nodash = context["prev_ds_nodash"] | -AIR302_context.py:18:23: AIR302 `prev_ds` is removed in Airflow 3.0 +AIR302_context.py:53:23: AIR302 `prev_ds` is removed in Airflow 3.0 | -16 | next_ds_nodash = context["next_ds_nodash"] -17 | next_execution_date = context["next_execution_date"] -18 | prev_ds = context["prev_ds"] +51 | next_ds_nodash = context["next_ds_nodash"] +52 | next_execution_date = context["next_execution_date"] +53 | prev_ds = context["prev_ds"] | ^^^^^^^^^ AIR302 -19 | prev_ds_nodash = context["prev_ds_nodash"] -20 | prev_execution_date = context["prev_execution_date"] +54 | prev_ds_nodash = context["prev_ds_nodash"] +55 | prev_execution_date = context["prev_execution_date"] | -AIR302_context.py:19:30: AIR302 `prev_ds_nodash` is removed in Airflow 3.0 +AIR302_context.py:54:30: AIR302 `prev_ds_nodash` is removed in Airflow 3.0 | -17 | next_execution_date = context["next_execution_date"] -18 | prev_ds = context["prev_ds"] -19 | prev_ds_nodash = context["prev_ds_nodash"] +52 | next_execution_date = context["next_execution_date"] +53 | prev_ds = context["prev_ds"] +54 | prev_ds_nodash = context["prev_ds_nodash"] | ^^^^^^^^^^^^^^^^ AIR302 -20 | prev_execution_date = context["prev_execution_date"] -21 | prev_execution_date_success = context["prev_execution_date_success"] +55 | prev_execution_date = context["prev_execution_date"] +56 | prev_execution_date_success = context["prev_execution_date_success"] | -AIR302_context.py:20:35: AIR302 `prev_execution_date` is removed in Airflow 3.0 +AIR302_context.py:55:35: AIR302 `prev_execution_date` is removed in Airflow 3.0 | -18 | prev_ds = context["prev_ds"] -19 | prev_ds_nodash = context["prev_ds_nodash"] -20 | prev_execution_date = context["prev_execution_date"] +53 | prev_ds = context["prev_ds"] +54 | prev_ds_nodash = context["prev_ds_nodash"] +55 | prev_execution_date = context["prev_execution_date"] | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -21 | prev_execution_date_success = context["prev_execution_date_success"] -22 | tomorrow_ds = context["tomorrow_ds"] +56 | prev_execution_date_success = context["prev_execution_date_success"] +57 | tomorrow_ds = context["tomorrow_ds"] | -AIR302_context.py:21:43: AIR302 `prev_execution_date_success` is removed in Airflow 3.0 +AIR302_context.py:56:43: AIR302 `prev_execution_date_success` is removed in Airflow 3.0 | -19 | prev_ds_nodash = context["prev_ds_nodash"] -20 | prev_execution_date = context["prev_execution_date"] -21 | prev_execution_date_success = context["prev_execution_date_success"] +54 | prev_ds_nodash = context["prev_ds_nodash"] +55 | prev_execution_date = context["prev_execution_date"] +56 | prev_execution_date_success = context["prev_execution_date_success"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -22 | tomorrow_ds = context["tomorrow_ds"] -23 | yesterday_ds = context["yesterday_ds"] +57 | tomorrow_ds = context["tomorrow_ds"] +58 | yesterday_ds = context["yesterday_ds"] | -AIR302_context.py:22:27: AIR302 `tomorrow_ds` is removed in Airflow 3.0 +AIR302_context.py:57:27: AIR302 `tomorrow_ds` is removed in Airflow 3.0 | -20 | prev_execution_date = context["prev_execution_date"] -21 | prev_execution_date_success = context["prev_execution_date_success"] -22 | tomorrow_ds = context["tomorrow_ds"] +55 | prev_execution_date = context["prev_execution_date"] +56 | prev_execution_date_success = context["prev_execution_date_success"] +57 | tomorrow_ds = context["tomorrow_ds"] | ^^^^^^^^^^^^^ AIR302 -23 | yesterday_ds = context["yesterday_ds"] -24 | yesterday_ds_nodash = context["yesterday_ds_nodash"] +58 | yesterday_ds = context["yesterday_ds"] +59 | yesterday_ds_nodash = context["yesterday_ds_nodash"] | -AIR302_context.py:23:28: AIR302 `yesterday_ds` is removed in Airflow 3.0 +AIR302_context.py:58:28: AIR302 `yesterday_ds` is removed in Airflow 3.0 | -21 | prev_execution_date_success = context["prev_execution_date_success"] -22 | tomorrow_ds = context["tomorrow_ds"] -23 | yesterday_ds = context["yesterday_ds"] +56 | prev_execution_date_success = context["prev_execution_date_success"] +57 | tomorrow_ds = context["tomorrow_ds"] +58 | yesterday_ds = context["yesterday_ds"] | ^^^^^^^^^^^^^^ AIR302 -24 | yesterday_ds_nodash = context["yesterday_ds_nodash"] +59 | yesterday_ds_nodash = context["yesterday_ds_nodash"] | -AIR302_context.py:24:35: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0 +AIR302_context.py:59:35: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0 | -22 | tomorrow_ds = context["tomorrow_ds"] -23 | yesterday_ds = context["yesterday_ds"] -24 | yesterday_ds_nodash = context["yesterday_ds_nodash"] +57 | tomorrow_ds = context["tomorrow_ds"] +58 | yesterday_ds = context["yesterday_ds"] +59 | yesterday_ds_nodash = context["yesterday_ds_nodash"] | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -25 | -26 | with DAG( +60 | +61 | with DAG( | -AIR302_context.py:28:5: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_context.py:63:5: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -26 | with DAG( -27 | dag_id="example_dag", -28 | schedule_interval="@daily", +61 | with DAG( +62 | dag_id="example_dag", +63 | schedule_interval="@daily", | ^^^^^^^^^^^^^^^^^ AIR302 -29 | start_date=datetime(2023, 1, 1), -30 | template_searchpath=["/templates"], +64 | start_date=datetime(2023, 1, 1), +65 | template_searchpath=["/templates"], | = help: Use `schedule` instead ℹ Safe fix -25 25 | -26 26 | with DAG( -27 27 | dag_id="example_dag", -28 |- schedule_interval="@daily", - 28 |+ schedule="@daily", -29 29 | start_date=datetime(2023, 1, 1), -30 30 | template_searchpath=["/templates"], -31 31 | ) as dag: - -AIR302_context.py:32:13: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 - | -30 | template_searchpath=["/templates"], -31 | ) as dag: -32 | task1 = DummyOperator( +60 60 | +61 61 | with DAG( +62 62 | dag_id="example_dag", +63 |- schedule_interval="@daily", + 63 |+ schedule="@daily", +64 64 | start_date=datetime(2023, 1, 1), +65 65 | template_searchpath=["/templates"], +66 66 | ) as dag: + +AIR302_context.py:67:13: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 + | +65 | template_searchpath=["/templates"], +66 | ) as dag: +67 | task1 = DummyOperator( | ^^^^^^^^^^^^^ AIR302 -33 | task_id="task1", -34 | params={ +68 | task_id="task1", +69 | params={ | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_context.py:45:57: AIR302 `execution_date` is removed in Airflow 3.0 +AIR302_context.py:80:57: AIR302 `execution_date` is removed in Airflow 3.0 | -43 | name = "custom_macros" -44 | macros = { -45 | "execution_date_macro": lambda context: context["execution_date"], +78 | name = "custom_macros" +79 | macros = { +80 | "execution_date_macro": lambda context: context["execution_date"], | ^^^^^^^^^^^^^^^^ AIR302 -46 | "next_ds_macro": lambda context: context["next_ds"] -47 | } +81 | "next_ds_macro": lambda context: context["next_ds"] +82 | } | -AIR302_context.py:46:50: AIR302 `next_ds` is removed in Airflow 3.0 +AIR302_context.py:81:50: AIR302 `next_ds` is removed in Airflow 3.0 | -44 | macros = { -45 | "execution_date_macro": lambda context: context["execution_date"], -46 | "next_ds_macro": lambda context: context["next_ds"] +79 | macros = { +80 | "execution_date_macro": lambda context: context["execution_date"], +81 | "next_ds_macro": lambda context: context["next_ds"] | ^^^^^^^^^ AIR302 -47 | } +82 | } | -AIR302_context.py:52:30: AIR302 `execution_date` is removed in Airflow 3.0 +AIR302_context.py:87:30: AIR302 `execution_date` is removed in Airflow 3.0 | -50 | def print_config(): -51 | context = get_current_context() -52 | execution_date = context["execution_date"] +85 | def print_config(): +86 | context = get_current_context() +87 | execution_date = context["execution_date"] | ^^^^^^^^^^^^^^^^ AIR302 -53 | next_ds = context["next_ds"] -54 | next_ds_nodash = context["next_ds_nodash"] +88 | next_ds = context["next_ds"] +89 | next_ds_nodash = context["next_ds_nodash"] | -AIR302_context.py:53:23: AIR302 `next_ds` is removed in Airflow 3.0 +AIR302_context.py:88:23: AIR302 `next_ds` is removed in Airflow 3.0 | -51 | context = get_current_context() -52 | execution_date = context["execution_date"] -53 | next_ds = context["next_ds"] +86 | context = get_current_context() +87 | execution_date = context["execution_date"] +88 | next_ds = context["next_ds"] | ^^^^^^^^^ AIR302 -54 | next_ds_nodash = context["next_ds_nodash"] -55 | next_execution_date = context["next_execution_date"] +89 | next_ds_nodash = context["next_ds_nodash"] +90 | next_execution_date = context["next_execution_date"] | -AIR302_context.py:54:30: AIR302 `next_ds_nodash` is removed in Airflow 3.0 +AIR302_context.py:89:30: AIR302 `next_ds_nodash` is removed in Airflow 3.0 | -52 | execution_date = context["execution_date"] -53 | next_ds = context["next_ds"] -54 | next_ds_nodash = context["next_ds_nodash"] +87 | execution_date = context["execution_date"] +88 | next_ds = context["next_ds"] +89 | next_ds_nodash = context["next_ds_nodash"] | ^^^^^^^^^^^^^^^^ AIR302 -55 | next_execution_date = context["next_execution_date"] -56 | prev_ds = context["prev_ds"] +90 | next_execution_date = context["next_execution_date"] +91 | prev_ds = context["prev_ds"] | -AIR302_context.py:55:35: AIR302 `next_execution_date` is removed in Airflow 3.0 +AIR302_context.py:90:35: AIR302 `next_execution_date` is removed in Airflow 3.0 | -53 | next_ds = context["next_ds"] -54 | next_ds_nodash = context["next_ds_nodash"] -55 | next_execution_date = context["next_execution_date"] +88 | next_ds = context["next_ds"] +89 | next_ds_nodash = context["next_ds_nodash"] +90 | next_execution_date = context["next_execution_date"] | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -56 | prev_ds = context["prev_ds"] -57 | prev_ds_nodash = context["prev_ds_nodash"] +91 | prev_ds = context["prev_ds"] +92 | prev_ds_nodash = context["prev_ds_nodash"] | -AIR302_context.py:56:23: AIR302 `prev_ds` is removed in Airflow 3.0 +AIR302_context.py:91:23: AIR302 `prev_ds` is removed in Airflow 3.0 | -54 | next_ds_nodash = context["next_ds_nodash"] -55 | next_execution_date = context["next_execution_date"] -56 | prev_ds = context["prev_ds"] +89 | next_ds_nodash = context["next_ds_nodash"] +90 | next_execution_date = context["next_execution_date"] +91 | prev_ds = context["prev_ds"] | ^^^^^^^^^ AIR302 -57 | prev_ds_nodash = context["prev_ds_nodash"] -58 | prev_execution_date = context["prev_execution_date"] +92 | prev_ds_nodash = context["prev_ds_nodash"] +93 | prev_execution_date = context["prev_execution_date"] | -AIR302_context.py:57:30: AIR302 `prev_ds_nodash` is removed in Airflow 3.0 +AIR302_context.py:92:30: AIR302 `prev_ds_nodash` is removed in Airflow 3.0 | -55 | next_execution_date = context["next_execution_date"] -56 | prev_ds = context["prev_ds"] -57 | prev_ds_nodash = context["prev_ds_nodash"] +90 | next_execution_date = context["next_execution_date"] +91 | prev_ds = context["prev_ds"] +92 | prev_ds_nodash = context["prev_ds_nodash"] | ^^^^^^^^^^^^^^^^ AIR302 -58 | prev_execution_date = context["prev_execution_date"] -59 | prev_execution_date_success = context["prev_execution_date_success"] +93 | prev_execution_date = context["prev_execution_date"] +94 | prev_execution_date_success = context["prev_execution_date_success"] | -AIR302_context.py:58:35: AIR302 `prev_execution_date` is removed in Airflow 3.0 +AIR302_context.py:93:35: AIR302 `prev_execution_date` is removed in Airflow 3.0 | -56 | prev_ds = context["prev_ds"] -57 | prev_ds_nodash = context["prev_ds_nodash"] -58 | prev_execution_date = context["prev_execution_date"] +91 | prev_ds = context["prev_ds"] +92 | prev_ds_nodash = context["prev_ds_nodash"] +93 | prev_execution_date = context["prev_execution_date"] | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -59 | prev_execution_date_success = context["prev_execution_date_success"] -60 | tomorrow_ds = context["tomorrow_ds"] +94 | prev_execution_date_success = context["prev_execution_date_success"] +95 | tomorrow_ds = context["tomorrow_ds"] | -AIR302_context.py:59:43: AIR302 `prev_execution_date_success` is removed in Airflow 3.0 +AIR302_context.py:94:43: AIR302 `prev_execution_date_success` is removed in Airflow 3.0 | -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"] +92 | prev_ds_nodash = context["prev_ds_nodash"] +93 | prev_execution_date = context["prev_execution_date"] +94 | prev_execution_date_success = context["prev_execution_date_success"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -60 | tomorrow_ds = context["tomorrow_ds"] -61 | yesterday_ds = context["yesterday_ds"] +95 | tomorrow_ds = context["tomorrow_ds"] +96 | yesterday_ds = context["yesterday_ds"] | -AIR302_context.py:60:27: AIR302 `tomorrow_ds` is removed in Airflow 3.0 +AIR302_context.py:95:27: AIR302 `tomorrow_ds` is removed in Airflow 3.0 | -58 | prev_execution_date = context["prev_execution_date"] -59 | prev_execution_date_success = context["prev_execution_date_success"] -60 | tomorrow_ds = context["tomorrow_ds"] +93 | prev_execution_date = context["prev_execution_date"] +94 | prev_execution_date_success = context["prev_execution_date_success"] +95 | tomorrow_ds = context["tomorrow_ds"] | ^^^^^^^^^^^^^ AIR302 -61 | yesterday_ds = context["yesterday_ds"] -62 | yesterday_ds_nodash = context["yesterday_ds_nodash"] +96 | yesterday_ds = context["yesterday_ds"] +97 | yesterday_ds_nodash = context["yesterday_ds_nodash"] | -AIR302_context.py:61:28: AIR302 `yesterday_ds` is removed in Airflow 3.0 +AIR302_context.py:96:28: AIR302 `yesterday_ds` is removed in Airflow 3.0 | -59 | prev_execution_date_success = context["prev_execution_date_success"] -60 | tomorrow_ds = context["tomorrow_ds"] -61 | yesterday_ds = context["yesterday_ds"] +94 | prev_execution_date_success = context["prev_execution_date_success"] +95 | tomorrow_ds = context["tomorrow_ds"] +96 | yesterday_ds = context["yesterday_ds"] | ^^^^^^^^^^^^^^ AIR302 -62 | yesterday_ds_nodash = context["yesterday_ds_nodash"] +97 | yesterday_ds_nodash = context["yesterday_ds_nodash"] | -AIR302_context.py:62:35: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0 +AIR302_context.py:97:35: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0 | -60 | tomorrow_ds = context["tomorrow_ds"] -61 | yesterday_ds = context["yesterday_ds"] -62 | yesterday_ds_nodash = context["yesterday_ds_nodash"] +95 | tomorrow_ds = context["tomorrow_ds"] +96 | yesterday_ds = context["yesterday_ds"] +97 | yesterday_ds_nodash = context["yesterday_ds_nodash"] | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -63 | -64 | class CustomOperator(BaseOperator): - | - -AIR302_context.py:66:34: AIR302 `execution_date` is removed in Airflow 3.0 - | -64 | class CustomOperator(BaseOperator): -65 | def execute(self, context): -66 | execution_date = context["execution_date"] - | ^^^^^^^^^^^^^^^^ AIR302 -67 | next_ds = context["next_ds"] -68 | next_ds_nodash = context["next_ds_nodash"] - | - -AIR302_context.py:67:27: AIR302 `next_ds` is removed in Airflow 3.0 - | -65 | def execute(self, context): -66 | execution_date = context["execution_date"] -67 | next_ds = context["next_ds"] - | ^^^^^^^^^ AIR302 -68 | next_ds_nodash = context["next_ds_nodash"] -69 | next_execution_date = context["next_execution_date"] - | - -AIR302_context.py:68:34: AIR302 `next_ds_nodash` is removed in Airflow 3.0 - | -66 | execution_date = context["execution_date"] -67 | next_ds = context["next_ds"] -68 | next_ds_nodash = context["next_ds_nodash"] - | ^^^^^^^^^^^^^^^^ AIR302 -69 | next_execution_date = context["next_execution_date"] -70 | prev_ds = context["prev_ds"] - | - -AIR302_context.py:69:39: AIR302 `next_execution_date` is removed in Airflow 3.0 - | -67 | next_ds = context["next_ds"] -68 | next_ds_nodash = context["next_ds_nodash"] -69 | next_execution_date = context["next_execution_date"] - | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -70 | prev_ds = context["prev_ds"] -71 | prev_ds_nodash = context["prev_ds_nodash"] - | - -AIR302_context.py:70:27: AIR302 `prev_ds` is removed in Airflow 3.0 - | -68 | next_ds_nodash = context["next_ds_nodash"] -69 | next_execution_date = context["next_execution_date"] -70 | prev_ds = context["prev_ds"] - | ^^^^^^^^^ AIR302 -71 | prev_ds_nodash = context["prev_ds_nodash"] -72 | prev_execution_date = context["prev_execution_date"] - | - -AIR302_context.py:71:34: AIR302 `prev_ds_nodash` is removed in Airflow 3.0 - | -69 | next_execution_date = context["next_execution_date"] -70 | prev_ds = context["prev_ds"] -71 | prev_ds_nodash = context["prev_ds_nodash"] - | ^^^^^^^^^^^^^^^^ AIR302 -72 | prev_execution_date = context["prev_execution_date"] -73 | prev_execution_date_success = context["prev_execution_date_success"] - | - -AIR302_context.py:72:39: AIR302 `prev_execution_date` is removed in Airflow 3.0 - | -70 | prev_ds = context["prev_ds"] -71 | prev_ds_nodash = context["prev_ds_nodash"] -72 | prev_execution_date = context["prev_execution_date"] - | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -73 | prev_execution_date_success = context["prev_execution_date_success"] -74 | tomorrow_ds = context["tomorrow_ds"] - | - -AIR302_context.py:73:47: AIR302 `prev_execution_date_success` is removed in Airflow 3.0 - | -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"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -74 | tomorrow_ds = context["tomorrow_ds"] -75 | yesterday_ds = context["yesterday_ds"] - | - -AIR302_context.py:74:31: AIR302 `tomorrow_ds` is removed in Airflow 3.0 - | -72 | prev_execution_date = context["prev_execution_date"] -73 | prev_execution_date_success = context["prev_execution_date_success"] -74 | tomorrow_ds = context["tomorrow_ds"] - | ^^^^^^^^^^^^^ AIR302 -75 | yesterday_ds = context["yesterday_ds"] -76 | yesterday_ds_nodash = context["yesterday_ds_nodash"] - | - -AIR302_context.py:75:32: AIR302 `yesterday_ds` is removed in Airflow 3.0 - | -73 | prev_execution_date_success = context["prev_execution_date_success"] -74 | tomorrow_ds = context["tomorrow_ds"] -75 | yesterday_ds = context["yesterday_ds"] - | ^^^^^^^^^^^^^^ AIR302 -76 | yesterday_ds_nodash = context["yesterday_ds_nodash"] - | - -AIR302_context.py:76:39: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0 - | -74 | tomorrow_ds = context["tomorrow_ds"] -75 | yesterday_ds = context["yesterday_ds"] -76 | yesterday_ds_nodash = context["yesterday_ds_nodash"] - | ^^^^^^^^^^^^^^^^^^^^^ AIR302 - | +98 | +99 | class CustomOperator(BaseOperator): + | + +AIR302_context.py:101:34: AIR302 `execution_date` is removed in Airflow 3.0 + | + 99 | class CustomOperator(BaseOperator): +100 | def execute(self, context): +101 | execution_date = context["execution_date"] + | ^^^^^^^^^^^^^^^^ AIR302 +102 | next_ds = context["next_ds"] +103 | next_ds_nodash = context["next_ds_nodash"] + | + +AIR302_context.py:102:27: AIR302 `next_ds` is removed in Airflow 3.0 + | +100 | def execute(self, context): +101 | execution_date = context["execution_date"] +102 | next_ds = context["next_ds"] + | ^^^^^^^^^ AIR302 +103 | next_ds_nodash = context["next_ds_nodash"] +104 | next_execution_date = context["next_execution_date"] + | + +AIR302_context.py:103:34: AIR302 `next_ds_nodash` is removed in Airflow 3.0 + | +101 | execution_date = context["execution_date"] +102 | next_ds = context["next_ds"] +103 | next_ds_nodash = context["next_ds_nodash"] + | ^^^^^^^^^^^^^^^^ AIR302 +104 | next_execution_date = context["next_execution_date"] +105 | prev_ds = context["prev_ds"] + | + +AIR302_context.py:104:39: AIR302 `next_execution_date` is removed in Airflow 3.0 + | +102 | next_ds = context["next_ds"] +103 | next_ds_nodash = context["next_ds_nodash"] +104 | next_execution_date = context["next_execution_date"] + | ^^^^^^^^^^^^^^^^^^^^^ AIR302 +105 | prev_ds = context["prev_ds"] +106 | prev_ds_nodash = context["prev_ds_nodash"] + | + +AIR302_context.py:105:27: AIR302 `prev_ds` is removed in Airflow 3.0 + | +103 | next_ds_nodash = context["next_ds_nodash"] +104 | next_execution_date = context["next_execution_date"] +105 | prev_ds = context["prev_ds"] + | ^^^^^^^^^ AIR302 +106 | prev_ds_nodash = context["prev_ds_nodash"] +107 | prev_execution_date = context["prev_execution_date"] + | + +AIR302_context.py:106:34: AIR302 `prev_ds_nodash` is removed in Airflow 3.0 + | +104 | next_execution_date = context["next_execution_date"] +105 | prev_ds = context["prev_ds"] +106 | prev_ds_nodash = context["prev_ds_nodash"] + | ^^^^^^^^^^^^^^^^ AIR302 +107 | prev_execution_date = context["prev_execution_date"] +108 | prev_execution_date_success = context["prev_execution_date_success"] + | + +AIR302_context.py:107:39: AIR302 `prev_execution_date` is removed in Airflow 3.0 + | +105 | prev_ds = context["prev_ds"] +106 | prev_ds_nodash = context["prev_ds_nodash"] +107 | prev_execution_date = context["prev_execution_date"] + | ^^^^^^^^^^^^^^^^^^^^^ AIR302 +108 | prev_execution_date_success = context["prev_execution_date_success"] +109 | tomorrow_ds = context["tomorrow_ds"] + | + +AIR302_context.py:108:47: AIR302 `prev_execution_date_success` is removed in Airflow 3.0 + | +106 | prev_ds_nodash = context["prev_ds_nodash"] +107 | prev_execution_date = context["prev_execution_date"] +108 | prev_execution_date_success = context["prev_execution_date_success"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +109 | tomorrow_ds = context["tomorrow_ds"] +110 | yesterday_ds = context["yesterday_ds"] + | + +AIR302_context.py:109:31: AIR302 `tomorrow_ds` is removed in Airflow 3.0 + | +107 | prev_execution_date = context["prev_execution_date"] +108 | prev_execution_date_success = context["prev_execution_date_success"] +109 | tomorrow_ds = context["tomorrow_ds"] + | ^^^^^^^^^^^^^ AIR302 +110 | yesterday_ds = context["yesterday_ds"] +111 | yesterday_ds_nodash = context["yesterday_ds_nodash"] + | + +AIR302_context.py:110:32: AIR302 `yesterday_ds` is removed in Airflow 3.0 + | +108 | prev_execution_date_success = context["prev_execution_date_success"] +109 | tomorrow_ds = context["tomorrow_ds"] +110 | yesterday_ds = context["yesterday_ds"] + | ^^^^^^^^^^^^^^ AIR302 +111 | yesterday_ds_nodash = context["yesterday_ds_nodash"] + | + +AIR302_context.py:111:39: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0 + | +109 | tomorrow_ds = context["tomorrow_ds"] +110 | yesterday_ds = context["yesterday_ds"] +111 | yesterday_ds_nodash = context["yesterday_ds_nodash"] + | ^^^^^^^^^^^^^^^^^^^^^ AIR302 +112 | +113 | @task + | + +AIR302_context.py:115:5: AIR302 `execution_date` is removed in Airflow 3.0 + | +113 | @task +114 | def access_invalid_argument_task_out_of_dag(execution_date, **context): +115 | print("execution date", execution_date) + | ^^^^^ AIR302 +116 | print("access invalid key", context.get("conf")) + | + +AIR302_context.py:116:5: AIR302 `execution_date` is removed in Airflow 3.0 + | +114 | def access_invalid_argument_task_out_of_dag(execution_date, **context): +115 | print("execution date", execution_date) +116 | print("access invalid key", context.get("conf")) + | ^^^^^ AIR302 +117 | +118 | @task(task_id="print_the_context") + | + +AIR302_context.py:116:33: AIR302 `execution_date` is removed in Airflow 3.0 + | +114 | def access_invalid_argument_task_out_of_dag(execution_date, **context): +115 | print("execution date", execution_date) +116 | print("access invalid key", context.get("conf")) + | ^^^^^^^^^^^ AIR302 +117 | +118 | @task(task_id="print_the_context") + | + +AIR302_context.py:122:22: AIR302 `conf` is removed in Airflow 3.0 + | +120 | """Print the Airflow context and ds variable from the context.""" +121 | print(ds) +122 | print(kwargs.get("tomorrow_ds")) + | ^^^^^^^^^^^^^ AIR302 +123 | +124 | run_this = print_context() + |