Compare commits
12 Commits
0.10.0
...
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) {
|
if checker.enabled(Rule::NonPEP646Unpack) {
|
||||||
pyupgrade::rules::use_pep646_unpack(checker, subscript);
|
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);
|
pandas_vet::rules::subscript(checker, value, expr);
|
||||||
}
|
}
|
||||||
Expr::Tuple(ast::ExprTuple {
|
Expr::Tuple(ast::ExprTuple {
|
||||||
|
|||||||
@@ -376,6 +376,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::PytestParameterWithDefaultArgument) {
|
if checker.enabled(Rule::PytestParameterWithDefaultArgument) {
|
||||||
flake8_pytest_style::rules::parameter_with_default_argument(checker, function_def);
|
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(_) => {
|
Stmt::Return(_) => {
|
||||||
if checker.enabled(Rule::ReturnOutsideFunction) {
|
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_names.py"))]
|
||||||
#[test_case(Rule::Airflow3Removal, Path::new("AIR302_class_attribute.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_airflow_plugin.py"))]
|
||||||
|
#[test_case(Rule::Airflow3Removal, Path::new("AIR302_context.py"))]
|
||||||
#[test_case(Rule::Airflow3MovedToProvider, Path::new("AIR303.py"))]
|
#[test_case(Rule::Airflow3MovedToProvider, Path::new("AIR303.py"))]
|
||||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
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_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
use ruff_python_ast::helpers::map_callable;
|
||||||
|
use ruff_python_ast::AnyParameterRef;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
name::QualifiedName, Arguments, Expr, ExprAttribute, ExprCall, ExprContext, ExprName,
|
name::QualifiedName, Arguments, Expr, ExprAttribute, ExprCall, ExprContext, ExprName,
|
||||||
StmtClassDef,
|
ExprStringLiteral, ExprSubscript, Stmt, StmtClassDef, StmtFunctionDef,
|
||||||
};
|
};
|
||||||
use ruff_python_semantic::analyze::typing;
|
use ruff_python_semantic::analyze::typing;
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::Modules;
|
||||||
use ruff_python_semantic::ScopeKind;
|
use ruff_python_semantic::ScopeKind;
|
||||||
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of deprecated Airflow functions and values.
|
/// 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
|
/// AIR302
|
||||||
pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) {
|
pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) {
|
||||||
if !checker.semantic().seen_module(Modules::AIRFLOW) {
|
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_call_arguments(checker, &qualname, arguments);
|
||||||
};
|
};
|
||||||
check_method(checker, call_expr);
|
check_method(checker, call_expr);
|
||||||
|
check_context_get(checker, call_expr);
|
||||||
}
|
}
|
||||||
Expr::Attribute(attribute_expr @ ExprAttribute { attr, .. }) => {
|
Expr::Attribute(attribute_expr @ ExprAttribute { attr, .. }) => {
|
||||||
check_name(checker, expr, attr.range());
|
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)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
enum Replacement {
|
enum Replacement {
|
||||||
None,
|
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.
|
/// Check whether a removed Airflow class method is called.
|
||||||
///
|
///
|
||||||
/// For example:
|
/// For example:
|
||||||
@@ -855,3 +1086,14 @@ fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix
|
|||||||
_ => false,
|
_ => 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