Compare commits
12 Commits
david/comp
...
deprecated
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c76e15a45d | ||
|
|
d0aff2bbff | ||
|
|
65db31f0e1 | ||
|
|
c2c37b8052 | ||
|
|
51613d9107 | ||
|
|
f20e70cd62 | ||
|
|
4737824345 | ||
|
|
1961b76d03 | ||
|
|
62a1e55705 | ||
|
|
8a7ec4c0a3 | ||
|
|
9b9540c3cd | ||
|
|
ccafaf8e30 |
119
crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py
vendored
Normal file
119
crates/ruff_linter/resources/test/fixtures/airflow/AIR302_context.py
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
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.models.baseoperator import BaseOperator
|
||||
from airflow.decorators import dag, task
|
||||
from airflow.providers.standard.operators.python import PythonOperator
|
||||
from airflow.utils.context import get_current_context
|
||||
|
||||
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):
|
||||
# This should not throw an error as logical_date is part of airflow context.
|
||||
logical_date = context["logical_date"]
|
||||
|
||||
# Removed usage - should trigger violations
|
||||
execution_date = context["execution_date"]
|
||||
next_ds = context["next_ds"]
|
||||
next_ds_nodash = context["next_ds_nodash"]
|
||||
next_execution_date = context["next_execution_date"]
|
||||
prev_ds = context["prev_ds"]
|
||||
prev_ds_nodash = context["prev_ds_nodash"]
|
||||
prev_execution_date = context["prev_execution_date"]
|
||||
prev_execution_date_success = context["prev_execution_date_success"]
|
||||
tomorrow_ds = context["tomorrow_ds"]
|
||||
yesterday_ds = context["yesterday_ds"]
|
||||
yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
||||
with DAG(
|
||||
dag_id="example_dag",
|
||||
schedule_interval="@daily",
|
||||
start_date=datetime(2023, 1, 1),
|
||||
template_searchpath=["/templates"],
|
||||
) as dag:
|
||||
task1 = DummyOperator(
|
||||
task_id="task1",
|
||||
params={
|
||||
# Removed variables in template
|
||||
"execution_date": "{{ execution_date }}",
|
||||
"next_ds": "{{ next_ds }}",
|
||||
"prev_ds": "{{ prev_ds }}"
|
||||
},
|
||||
)
|
||||
|
||||
class CustomMacrosPlugin(AirflowPlugin):
|
||||
name = "custom_macros"
|
||||
macros = {
|
||||
"execution_date_macro": lambda context: context["execution_date"],
|
||||
"next_ds_macro": lambda context: context["next_ds"]
|
||||
}
|
||||
|
||||
@task
|
||||
def print_config():
|
||||
context = get_current_context()
|
||||
execution_date = context["execution_date"]
|
||||
next_ds = context["next_ds"]
|
||||
next_ds_nodash = context["next_ds_nodash"]
|
||||
next_execution_date = context["next_execution_date"]
|
||||
prev_ds = context["prev_ds"]
|
||||
prev_ds_nodash = context["prev_ds_nodash"]
|
||||
prev_execution_date = context["prev_execution_date"]
|
||||
prev_execution_date_success = context["prev_execution_date_success"]
|
||||
tomorrow_ds = context["tomorrow_ds"]
|
||||
yesterday_ds = context["yesterday_ds"]
|
||||
yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
||||
class CustomOperator(BaseOperator):
|
||||
def execute(self, context):
|
||||
execution_date = context["execution_date"]
|
||||
next_ds = context["next_ds"]
|
||||
next_ds_nodash = context["next_ds_nodash"]
|
||||
next_execution_date = context["next_execution_date"]
|
||||
prev_ds = context["prev_ds"]
|
||||
prev_ds_nodash = context["prev_ds_nodash"]
|
||||
prev_execution_date = context["prev_execution_date"]
|
||||
prev_execution_date_success = context["prev_execution_date_success"]
|
||||
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, tomorrow_ds, logical_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"))
|
||||
c = get_current_context()
|
||||
c.get("execution_date")
|
||||
@@ -175,7 +175,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::NonPEP646Unpack) {
|
||||
pyupgrade::rules::use_pep646_unpack(checker, subscript);
|
||||
}
|
||||
|
||||
if checker.enabled(Rule::Airflow3Removal) {
|
||||
airflow::rules::removed_in_3(checker, expr);
|
||||
}
|
||||
pandas_vet::rules::subscript(checker, value, expr);
|
||||
}
|
||||
Expr::Tuple(ast::ExprTuple {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Stmt::Return(_) => {
|
||||
if checker.enabled(Rule::ReturnOutsideFunction) {
|
||||
|
||||
@@ -18,6 +18,7 @@ mod tests {
|
||||
#[test_case(Rule::Airflow3Removal, Path::new("AIR302_names.py"))]
|
||||
#[test_case(Rule::Airflow3Removal, Path::new("AIR302_class_attribute.py"))]
|
||||
#[test_case(Rule::Airflow3Removal, Path::new("AIR302_airflow_plugin.py"))]
|
||||
#[test_case(Rule::Airflow3Removal, Path::new("AIR302_context.py"))]
|
||||
#[test_case(Rule::Airflow3MovedToProvider, Path::new("AIR303.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
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::AnyParameterRef;
|
||||
use ruff_python_ast::{
|
||||
name::QualifiedName, Arguments, Expr, ExprAttribute, ExprCall, ExprContext, ExprName,
|
||||
StmtClassDef,
|
||||
ExprStringLiteral, ExprSubscript, Stmt, StmtClassDef, StmtFunctionDef,
|
||||
};
|
||||
use ruff_python_semantic::analyze::typing;
|
||||
use ruff_python_semantic::Modules;
|
||||
use ruff_python_semantic::ScopeKind;
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
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 +73,64 @@ 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<String> {
|
||||
match slice {
|
||||
Expr::StringLiteral(ExprStringLiteral { value, .. }) => Some(value.to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a subscript expression accesses a removed Airflow context variable.
|
||||
/// If a removed key is found, push a corresponding diagnostic.
|
||||
fn removed_context_variable(checker: &mut Checker, subscript: &ExprSubscript) {
|
||||
let ExprSubscript { value, slice, .. } = subscript;
|
||||
|
||||
let is_context_arg = if let Expr::Name(ExprName { id, .. }) = &**value {
|
||||
id.as_str() == "context" || id.as_str().starts_with("**")
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let is_current_context =
|
||||
if let Some(qualname) = typing::resolve_assignment(value, checker.semantic()) {
|
||||
matches!(
|
||||
qualname.segments(),
|
||||
["airflow", "utils", "context", "get_current_context"]
|
||||
)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if is_context_arg || is_current_context {
|
||||
if let Some(key) = extract_name_from_slice(slice) {
|
||||
if REMOVED_CONTEXT_KEYS.contains(&key.as_str()) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
Airflow3Removal {
|
||||
deprecated: key,
|
||||
replacement: Replacement::None,
|
||||
},
|
||||
slice.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// AIR302
|
||||
pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) {
|
||||
if !checker.semantic().seen_module(Modules::AIRFLOW) {
|
||||
@@ -87,6 +147,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());
|
||||
@@ -100,10 +161,43 @@ pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Subscript(subscript_expr) => {
|
||||
removed_context_variable(checker, subscript_expr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// AIR302
|
||||
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(¶m_name) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
Airflow3Removal {
|
||||
deprecated: param_name.to_string(),
|
||||
replacement: Replacement::None,
|
||||
},
|
||||
param.parameter.name.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum Replacement {
|
||||
None,
|
||||
@@ -247,6 +341,143 @@ fn check_class_attribute(checker: &mut Checker, attribute_expr: &ExprAttribute)
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the parameter definition for a given name expression in a function.
|
||||
fn find_parameter<'a>(
|
||||
semantic: &'a SemanticModel,
|
||||
name: &'a ExprName,
|
||||
) -> Option<AnyParameterRef<'a>> {
|
||||
let binding_id = semantic.only_binding(name)?;
|
||||
let binding = semantic.binding(binding_id);
|
||||
let StmtFunctionDef { parameters, .. } = binding.statement(semantic)?.as_function_def_stmt()?;
|
||||
parameters
|
||||
.iter()
|
||||
.find(|parameter| parameter.name().range() == binding.range())
|
||||
}
|
||||
|
||||
/// Checks whether an Airflow 3.0–removed context key is used in a function decorated with `@task`.
|
||||
///
|
||||
/// Specifically, it flags two scenarios for task decorated function:
|
||||
/// 1. A removed context variable passed in as a function parameter name (e.g., `execution_date`).
|
||||
/// 2. A removed context key accessed via `context.get("...")`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// **Removed key used in `context.get(...)`:**
|
||||
/// ```python
|
||||
/// from airflow.decorators import task
|
||||
///
|
||||
/// @task
|
||||
/// def my_task(**context):
|
||||
/// # 'conf' is removed in Airflow 3.0
|
||||
/// 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
|
||||
///
|
||||
/// @task
|
||||
/// def more_keys(**context):
|
||||
/// # 'prev_ds' is also removed in Airflow 3.0
|
||||
/// print(context.get("prev_ds"))
|
||||
/// ```
|
||||
fn check_context_get(checker: &mut Checker, call_expr: &ExprCall) {
|
||||
if !is_taskflow(checker) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Expr::Attribute(ExprAttribute { value, attr, .. }) = &*call_expr.func else {
|
||||
return;
|
||||
};
|
||||
|
||||
let is_named_context = if let Expr::Name(name) = &**value {
|
||||
if let Some(parameter) = find_parameter(checker.semantic(), name) {
|
||||
matches!(parameter.name().as_str(), "context" | "kwargs")
|
||||
|| parameter.name().as_str().starts_with("**")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let is_assigned_from_gcc =
|
||||
if let Some(qualname) = typing::resolve_assignment(value, checker.semantic()) {
|
||||
matches!(
|
||||
qualname.segments(),
|
||||
["airflow", "utils", "context", "get_current_context"]
|
||||
)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !(is_named_context || is_assigned_from_gcc) {
|
||||
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) {
|
||||
if let Expr::StringLiteral(ExprStringLiteral { value, .. }) = argument {
|
||||
if value == removed_key {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
Airflow3Removal {
|
||||
deprecated: removed_key.to_string(),
|
||||
replacement: Replacement::None,
|
||||
},
|
||||
argument.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the function is decorated by @task
|
||||
///
|
||||
///
|
||||
/// Examples for the above patterns:
|
||||
/// ```python
|
||||
/// from airflow.decorators import task
|
||||
///
|
||||
///
|
||||
/// @task
|
||||
/// def access_invalid_key_task_out_of_dag(**context):
|
||||
/// print("access invalid key", context.get("conf"))
|
||||
/// ```
|
||||
fn is_taskflow(checker: &mut Checker) -> bool {
|
||||
let mut parents = checker.semantic().current_statements();
|
||||
if let Some(Stmt::FunctionDef(StmtFunctionDef { decorator_list, .. })) =
|
||||
parents.find(|stmt| stmt.is_function_def_stmt())
|
||||
{
|
||||
for decorator in decorator_list {
|
||||
if checker
|
||||
.semantic()
|
||||
.resolve_qualified_name(map_callable(&decorator.expression))
|
||||
.is_some_and(|qualified_name| {
|
||||
matches!(qualified_name.segments(), ["airflow", "decorators", "task"])
|
||||
})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Check whether a removed Airflow class method is called.
|
||||
///
|
||||
/// For example:
|
||||
@@ -855,3 +1086,14 @@ fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,0 +1,455 @@
|
||||
---
|
||||
source: crates/ruff_linter/src/rules/airflow/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
AIR302_context.py:12:41: AIR302 `conf` is removed in Airflow 3.0
|
||||
|
|
||||
11 | def access_invalid_key_in_context(**context):
|
||||
12 | print("access invalid key", context["conf"])
|
||||
| ^^^^^^ AIR302
|
||||
13 |
|
||||
14 | @task
|
||||
|
|
||||
|
||||
AIR302_context.py:16:45: AIR302 `conf` is removed in Airflow 3.0
|
||||
|
|
||||
14 | @task
|
||||
15 | def access_invalid_key_task_out_of_dag(**context):
|
||||
16 | print("access invalid key", context.get("conf"))
|
||||
| ^^^^^^ AIR302
|
||||
17 |
|
||||
18 | @dag(
|
||||
|
|
||||
|
||||
AIR302_context.py:27:49: AIR302 `conf` is removed in Airflow 3.0
|
||||
|
|
||||
25 | @task()
|
||||
26 | def access_invalid_key_task(**context):
|
||||
27 | print("access invalid key", context.get("conf"))
|
||||
| ^^^^^^ AIR302
|
||||
28 |
|
||||
29 | task1 = PythonOperator(
|
||||
|
|
||||
|
||||
AIR302_context.py:44:30: AIR302 `execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
43 | # Removed usage - should trigger violations
|
||||
44 | execution_date = context["execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
45 | next_ds = context["next_ds"]
|
||||
46 | next_ds_nodash = context["next_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:45:23: AIR302 `next_ds` is removed in Airflow 3.0
|
||||
|
|
||||
43 | # Removed usage - should trigger violations
|
||||
44 | execution_date = context["execution_date"]
|
||||
45 | next_ds = context["next_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
46 | next_ds_nodash = context["next_ds_nodash"]
|
||||
47 | next_execution_date = context["next_execution_date"]
|
||||
|
|
||||
|
||||
AIR302_context.py:46:30: AIR302 `next_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
44 | execution_date = context["execution_date"]
|
||||
45 | next_ds = context["next_ds"]
|
||||
46 | next_ds_nodash = context["next_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
47 | next_execution_date = context["next_execution_date"]
|
||||
48 | prev_ds = context["prev_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:47:35: AIR302 `next_execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
45 | next_ds = context["next_ds"]
|
||||
46 | next_ds_nodash = context["next_ds_nodash"]
|
||||
47 | next_execution_date = context["next_execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
48 | prev_ds = context["prev_ds"]
|
||||
49 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:48:23: AIR302 `prev_ds` is removed in Airflow 3.0
|
||||
|
|
||||
46 | next_ds_nodash = context["next_ds_nodash"]
|
||||
47 | next_execution_date = context["next_execution_date"]
|
||||
48 | prev_ds = context["prev_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
49 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
50 | prev_execution_date = context["prev_execution_date"]
|
||||
|
|
||||
|
||||
AIR302_context.py:49:30: AIR302 `prev_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
47 | next_execution_date = context["next_execution_date"]
|
||||
48 | prev_ds = context["prev_ds"]
|
||||
49 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
50 | prev_execution_date = context["prev_execution_date"]
|
||||
51 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
|
|
||||
|
||||
AIR302_context.py:50:35: AIR302 `prev_execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
48 | prev_ds = context["prev_ds"]
|
||||
49 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
50 | prev_execution_date = context["prev_execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
51 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
52 | tomorrow_ds = context["tomorrow_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:51:43: AIR302 `prev_execution_date_success` is removed in Airflow 3.0
|
||||
|
|
||||
49 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
50 | prev_execution_date = context["prev_execution_date"]
|
||||
51 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
52 | tomorrow_ds = context["tomorrow_ds"]
|
||||
53 | yesterday_ds = context["yesterday_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:52:27: AIR302 `tomorrow_ds` is removed in Airflow 3.0
|
||||
|
|
||||
50 | prev_execution_date = context["prev_execution_date"]
|
||||
51 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
52 | tomorrow_ds = context["tomorrow_ds"]
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
53 | yesterday_ds = context["yesterday_ds"]
|
||||
54 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:53:28: AIR302 `yesterday_ds` is removed in Airflow 3.0
|
||||
|
|
||||
51 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
52 | tomorrow_ds = context["tomorrow_ds"]
|
||||
53 | yesterday_ds = context["yesterday_ds"]
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
54 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:54:35: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
52 | tomorrow_ds = context["tomorrow_ds"]
|
||||
53 | yesterday_ds = context["yesterday_ds"]
|
||||
54 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
55 |
|
||||
56 | with DAG(
|
||||
|
|
||||
|
||||
AIR302_context.py:58:5: AIR302 [*] `schedule_interval` is removed in Airflow 3.0
|
||||
|
|
||||
56 | with DAG(
|
||||
57 | dag_id="example_dag",
|
||||
58 | schedule_interval="@daily",
|
||||
| ^^^^^^^^^^^^^^^^^ AIR302
|
||||
59 | start_date=datetime(2023, 1, 1),
|
||||
60 | template_searchpath=["/templates"],
|
||||
|
|
||||
= help: Use `schedule` instead
|
||||
|
||||
ℹ Safe fix
|
||||
55 55 |
|
||||
56 56 | with DAG(
|
||||
57 57 | dag_id="example_dag",
|
||||
58 |- schedule_interval="@daily",
|
||||
58 |+ schedule="@daily",
|
||||
59 59 | start_date=datetime(2023, 1, 1),
|
||||
60 60 | template_searchpath=["/templates"],
|
||||
61 61 | ) as dag:
|
||||
|
||||
AIR302_context.py:62:13: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0
|
||||
|
|
||||
60 | template_searchpath=["/templates"],
|
||||
61 | ) as dag:
|
||||
62 | task1 = DummyOperator(
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
63 | task_id="task1",
|
||||
64 | params={
|
||||
|
|
||||
= help: Use `airflow.operators.empty.EmptyOperator` instead
|
||||
|
||||
AIR302_context.py:75:57: AIR302 `execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
73 | name = "custom_macros"
|
||||
74 | macros = {
|
||||
75 | "execution_date_macro": lambda context: context["execution_date"],
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
76 | "next_ds_macro": lambda context: context["next_ds"]
|
||||
77 | }
|
||||
|
|
||||
|
||||
AIR302_context.py:76:50: AIR302 `next_ds` is removed in Airflow 3.0
|
||||
|
|
||||
74 | macros = {
|
||||
75 | "execution_date_macro": lambda context: context["execution_date"],
|
||||
76 | "next_ds_macro": lambda context: context["next_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
77 | }
|
||||
|
|
||||
|
||||
AIR302_context.py:82:30: AIR302 `execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
80 | def print_config():
|
||||
81 | context = get_current_context()
|
||||
82 | execution_date = context["execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
83 | next_ds = context["next_ds"]
|
||||
84 | next_ds_nodash = context["next_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:83:23: AIR302 `next_ds` is removed in Airflow 3.0
|
||||
|
|
||||
81 | context = get_current_context()
|
||||
82 | execution_date = context["execution_date"]
|
||||
83 | next_ds = context["next_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
84 | next_ds_nodash = context["next_ds_nodash"]
|
||||
85 | next_execution_date = context["next_execution_date"]
|
||||
|
|
||||
|
||||
AIR302_context.py:84:30: AIR302 `next_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
82 | execution_date = context["execution_date"]
|
||||
83 | next_ds = context["next_ds"]
|
||||
84 | next_ds_nodash = context["next_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
85 | next_execution_date = context["next_execution_date"]
|
||||
86 | prev_ds = context["prev_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:85:35: AIR302 `next_execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
83 | next_ds = context["next_ds"]
|
||||
84 | next_ds_nodash = context["next_ds_nodash"]
|
||||
85 | next_execution_date = context["next_execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
86 | prev_ds = context["prev_ds"]
|
||||
87 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:86:23: AIR302 `prev_ds` is removed in Airflow 3.0
|
||||
|
|
||||
84 | next_ds_nodash = context["next_ds_nodash"]
|
||||
85 | next_execution_date = context["next_execution_date"]
|
||||
86 | prev_ds = context["prev_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
87 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
88 | prev_execution_date = context["prev_execution_date"]
|
||||
|
|
||||
|
||||
AIR302_context.py:87:30: AIR302 `prev_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
85 | next_execution_date = context["next_execution_date"]
|
||||
86 | prev_ds = context["prev_ds"]
|
||||
87 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
88 | prev_execution_date = context["prev_execution_date"]
|
||||
89 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
|
|
||||
|
||||
AIR302_context.py:88:35: AIR302 `prev_execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
86 | prev_ds = context["prev_ds"]
|
||||
87 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
88 | prev_execution_date = context["prev_execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
89 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
90 | tomorrow_ds = context["tomorrow_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:89:43: AIR302 `prev_execution_date_success` is removed in Airflow 3.0
|
||||
|
|
||||
87 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
88 | prev_execution_date = context["prev_execution_date"]
|
||||
89 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
90 | tomorrow_ds = context["tomorrow_ds"]
|
||||
91 | yesterday_ds = context["yesterday_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:90:27: AIR302 `tomorrow_ds` is removed in Airflow 3.0
|
||||
|
|
||||
88 | prev_execution_date = context["prev_execution_date"]
|
||||
89 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
90 | tomorrow_ds = context["tomorrow_ds"]
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
91 | yesterday_ds = context["yesterday_ds"]
|
||||
92 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:91:28: AIR302 `yesterday_ds` is removed in Airflow 3.0
|
||||
|
|
||||
89 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
90 | tomorrow_ds = context["tomorrow_ds"]
|
||||
91 | yesterday_ds = context["yesterday_ds"]
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
92 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:92:35: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
90 | tomorrow_ds = context["tomorrow_ds"]
|
||||
91 | yesterday_ds = context["yesterday_ds"]
|
||||
92 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
93 |
|
||||
94 | class CustomOperator(BaseOperator):
|
||||
|
|
||||
|
||||
AIR302_context.py:96:34: AIR302 `execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
94 | class CustomOperator(BaseOperator):
|
||||
95 | def execute(self, context):
|
||||
96 | execution_date = context["execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
97 | next_ds = context["next_ds"]
|
||||
98 | next_ds_nodash = context["next_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:97:27: AIR302 `next_ds` is removed in Airflow 3.0
|
||||
|
|
||||
95 | def execute(self, context):
|
||||
96 | execution_date = context["execution_date"]
|
||||
97 | next_ds = context["next_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
98 | next_ds_nodash = context["next_ds_nodash"]
|
||||
99 | next_execution_date = context["next_execution_date"]
|
||||
|
|
||||
|
||||
AIR302_context.py:98:34: AIR302 `next_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
96 | execution_date = context["execution_date"]
|
||||
97 | next_ds = context["next_ds"]
|
||||
98 | next_ds_nodash = context["next_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
99 | next_execution_date = context["next_execution_date"]
|
||||
100 | prev_ds = context["prev_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:99:39: AIR302 `next_execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
97 | next_ds = context["next_ds"]
|
||||
98 | next_ds_nodash = context["next_ds_nodash"]
|
||||
99 | next_execution_date = context["next_execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
100 | prev_ds = context["prev_ds"]
|
||||
101 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:100:27: AIR302 `prev_ds` is removed in Airflow 3.0
|
||||
|
|
||||
98 | next_ds_nodash = context["next_ds_nodash"]
|
||||
99 | next_execution_date = context["next_execution_date"]
|
||||
100 | prev_ds = context["prev_ds"]
|
||||
| ^^^^^^^^^ AIR302
|
||||
101 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
102 | prev_execution_date = context["prev_execution_date"]
|
||||
|
|
||||
|
||||
AIR302_context.py:101:34: AIR302 `prev_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
99 | next_execution_date = context["next_execution_date"]
|
||||
100 | prev_ds = context["prev_ds"]
|
||||
101 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
102 | prev_execution_date = context["prev_execution_date"]
|
||||
103 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
|
|
||||
|
||||
AIR302_context.py:102:39: AIR302 `prev_execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
100 | prev_ds = context["prev_ds"]
|
||||
101 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
102 | prev_execution_date = context["prev_execution_date"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
103 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
104 | tomorrow_ds = context["tomorrow_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:103:47: AIR302 `prev_execution_date_success` is removed in Airflow 3.0
|
||||
|
|
||||
101 | prev_ds_nodash = context["prev_ds_nodash"]
|
||||
102 | prev_execution_date = context["prev_execution_date"]
|
||||
103 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
104 | tomorrow_ds = context["tomorrow_ds"]
|
||||
105 | yesterday_ds = context["yesterday_ds"]
|
||||
|
|
||||
|
||||
AIR302_context.py:104:31: AIR302 `tomorrow_ds` is removed in Airflow 3.0
|
||||
|
|
||||
102 | prev_execution_date = context["prev_execution_date"]
|
||||
103 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
104 | tomorrow_ds = context["tomorrow_ds"]
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
105 | yesterday_ds = context["yesterday_ds"]
|
||||
106 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:105:32: AIR302 `yesterday_ds` is removed in Airflow 3.0
|
||||
|
|
||||
103 | prev_execution_date_success = context["prev_execution_date_success"]
|
||||
104 | tomorrow_ds = context["tomorrow_ds"]
|
||||
105 | yesterday_ds = context["yesterday_ds"]
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
106 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
|
|
||||
|
||||
AIR302_context.py:106:39: AIR302 `yesterday_ds_nodash` is removed in Airflow 3.0
|
||||
|
|
||||
104 | tomorrow_ds = context["tomorrow_ds"]
|
||||
105 | yesterday_ds = context["yesterday_ds"]
|
||||
106 | yesterday_ds_nodash = context["yesterday_ds_nodash"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ AIR302
|
||||
107 |
|
||||
108 | @task
|
||||
|
|
||||
|
||||
AIR302_context.py:109:45: AIR302 `execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
108 | @task
|
||||
109 | def access_invalid_argument_task_out_of_dag(execution_date, tomorrow_ds, logical_date, **context):
|
||||
| ^^^^^^^^^^^^^^ AIR302
|
||||
110 | print("execution date", execution_date)
|
||||
111 | print("access invalid key", context.get("conf"))
|
||||
|
|
||||
|
||||
AIR302_context.py:109:61: AIR302 `tomorrow_ds` is removed in Airflow 3.0
|
||||
|
|
||||
108 | @task
|
||||
109 | def access_invalid_argument_task_out_of_dag(execution_date, tomorrow_ds, logical_date, **context):
|
||||
| ^^^^^^^^^^^ AIR302
|
||||
110 | print("execution date", execution_date)
|
||||
111 | print("access invalid key", context.get("conf"))
|
||||
|
|
||||
|
||||
AIR302_context.py:111:45: AIR302 `conf` is removed in Airflow 3.0
|
||||
|
|
||||
109 | def access_invalid_argument_task_out_of_dag(execution_date, tomorrow_ds, logical_date, **context):
|
||||
110 | print("execution date", execution_date)
|
||||
111 | print("access invalid key", context.get("conf"))
|
||||
| ^^^^^^ AIR302
|
||||
112 |
|
||||
113 | @task(task_id="print_the_context")
|
||||
|
|
||||
|
||||
AIR302_context.py:117:22: AIR302 `tomorrow_ds` is removed in Airflow 3.0
|
||||
|
|
||||
115 | """Print the Airflow context and ds variable from the context."""
|
||||
116 | print(ds)
|
||||
117 | print(kwargs.get("tomorrow_ds"))
|
||||
| ^^^^^^^^^^^^^ AIR302
|
||||
118 | c = get_current_context()
|
||||
119 | c.get("execution_date")
|
||||
|
|
||||
|
||||
AIR302_context.py:119:11: AIR302 `execution_date` is removed in Airflow 3.0
|
||||
|
|
||||
117 | print(kwargs.get("tomorrow_ds"))
|
||||
118 | c = get_current_context()
|
||||
119 | c.get("execution_date")
|
||||
| ^^^^^^^^^^^^^^^^ AIR302
|
||||
|
|
||||
Reference in New Issue
Block a user