diff --git a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_airflow_plugin.py b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_airflow_plugin.py new file mode 100644 index 0000000000..117c691eca --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_airflow_plugin.py @@ -0,0 +1,29 @@ +from airflow.plugins_manager import AirflowPlugin + + +class AirflowTestPlugin(AirflowPlugin): + name = "test_plugin" + # --- Invalid extensions start + operators = [PluginOperator] + sensors = [PluginSensorOperator] + hooks = [PluginHook] + executors = [PluginExecutor] + # --- Invalid extensions end + macros = [plugin_macro] + flask_blueprints = [bp] + appbuilder_views = [v_appbuilder_package] + appbuilder_menu_items = [appbuilder_mitem, appbuilder_mitem_toplevel] + global_operator_extra_links = [ + AirflowLink(), + GithubLink(), + ] + operator_extra_links = [ + GoogleLink(), + AirflowLink2(), + CustomOpLink(), + CustomBaseIndexOpLink(1), + ] + timetables = [CustomCronDataIntervalTimetable] + listeners = [empty_listener, ClassBasedListener()] + ti_deps = [CustomTestTriggerRule()] + priority_weight_strategies = [CustomPriorityWeightStrategy] diff --git a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py index 28142c87ca..6955295b79 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py @@ -1,14 +1,17 @@ +from datetime import timedelta + from airflow import DAG, dag -from airflow.timetables.simple import NullTimetable - -from airflow.operators.trigger_dagrun import TriggerDagRunOperator -from airflow.providers.standard.operators import trigger_dagrun - from airflow.operators.datetime import BranchDateTimeOperator -from airflow.providers.standard.operators import datetime - -from airflow.sensors.weekday import DayOfWeekSensor, BranchDayOfWeekOperator +from airflow.operators.trigger_dagrun import TriggerDagRunOperator +from airflow.providers.amazon.aws.log.s3_task_handler import S3TaskHandler +from airflow.providers.apache.hdfs.log.hdfs_task_handler import HdfsTaskHandler +from airflow.providers.elasticsearch.log.es_task_handler import ElasticsearchTaskHandler +from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager +from airflow.providers.google.cloud.log.gcs_task_handler import GCSTaskHandler +from airflow.providers.standard.operators import datetime, trigger_dagrun from airflow.providers.standard.sensors import weekday +from airflow.sensors.weekday import BranchDayOfWeekOperator, DayOfWeekSensor +from airflow.timetables.simple import NullTimetable DAG(dag_id="class_schedule", schedule="@hourly") @@ -54,10 +57,12 @@ def decorator_deprecated_operator_args(): ) branch_dt_op = datetime.BranchDateTimeOperator( - task_id="branch_dt_op", use_task_execution_day=True + task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 ) branch_dt_op2 = BranchDateTimeOperator( - task_id="branch_dt_op2", use_task_execution_day=True + task_id="branch_dt_op2", + use_task_execution_day=True, + sla=timedelta(seconds=10), ) dof_task_sensor = weekday.DayOfWeekSensor( @@ -76,3 +81,12 @@ def decorator_deprecated_operator_args(): branch_dt_op >> branch_dt_op2 dof_task_sensor >> dof_task_sensor2 bdow_op >> bdow_op2 + + +# deprecated filename_template arugment in FileTaskHandler +S3TaskHandler(filename_template="/tmp/test") +HdfsTaskHandler(filename_template="/tmp/test") +ElasticsearchTaskHandler(filename_template="/tmp/test") +GCSTaskHandler(filename_template="/tmp/test") + +FabAuthManager(None) diff --git a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_class_attribute.py b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_class_attribute.py new file mode 100644 index 0000000000..1128f7c11e --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_class_attribute.py @@ -0,0 +1,59 @@ +from airflow.datasets.manager import DatasetManager +from airflow.lineage.hook import DatasetLineageInfo, HookLineageCollector +from airflow.providers.amazon.auth_manager.aws_auth_manager import AwsAuthManager +from airflow.providers.apache.beam.hooks import BeamHook, NotAir302HookError +from airflow.providers.google.cloud.secrets.secret_manager import ( + CloudSecretManagerBackend, +) +from airflow.providers.hashicorp.secrets.vault import NotAir302SecretError, VaultBackend +from airflow.providers_manager import ProvidersManager +from airflow.secrets.base_secrets import BaseSecretsBackend + +dm = DatasetManager() +dm.register_dataset_change() +dm.create_datasets() +dm.notify_dataset_created() +dm.notify_dataset_changed() +dm.notify_dataset_alias_created() + +hlc = HookLineageCollector() +hlc.create_dataset() +hlc.add_input_dataset() +hlc.add_output_dataset() +hlc.collected_datasets() + +aam = AwsAuthManager() +aam.is_authorized_dataset() + +pm = ProvidersManager() +pm.initialize_providers_asset_uri_resources() +pm.dataset_factories + +base_secret_backend = BaseSecretsBackend() +base_secret_backend.get_conn_uri() +base_secret_backend.get_connections() + +csm_backend = CloudSecretManagerBackend() +csm_backend.get_conn_uri() +csm_backend.get_connections() + +vault_backend = VaultBackend() +vault_backend.get_conn_uri() +vault_backend.get_connections() + +not_an_error = NotAir302SecretError() +not_an_error.get_conn_uri() + +beam_hook = BeamHook() +beam_hook.get_conn_uri() + +not_an_error = NotAir302HookError() +not_an_error.get_conn_uri() + +provider_manager = ProvidersManager() +provider_manager.dataset_factories +provider_manager.dataset_uri_handlers +provider_manager.dataset_to_openlineage_converters + +dl_info = DatasetLineageInfo() +dl_info.dataset diff --git a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py index e3b4939d9a..ff6d7b0ee6 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py @@ -30,20 +30,29 @@ from airflow.datasets import ( DatasetAny, expand_alias_to_datasets, ) -from airflow.datasets.metadata import Metadata from airflow.datasets.manager import ( DatasetManager, dataset_manager, resolve_dataset_manager, ) +from airflow.datasets.metadata import Metadata +from airflow.hooks.base_hook import BaseHook from airflow.lineage.hook import DatasetLineageInfo from airflow.listeners.spec.dataset import on_dataset_changed, on_dataset_created from airflow.metrics.validators import AllowListValidator, BlockListValidator from airflow.operators import dummy_operator from airflow.operators.bash_operator import BashOperator from airflow.operators.branch_operator import BaseBranchOperator +from airflow.operators.dagrun_operator import TriggerDagRunLink, TriggerDagRunOperator from airflow.operators.dummy import DummyOperator, EmptyOperator from airflow.operators.email_operator import EmailOperator +from airflow.operators.latest_only_operator import LatestOnlyOperator +from airflow.operators.python_operator import ( + BranchPythonOperator, + PythonOperator, + PythonVirtualenvOperator, + ShortCircuitOperator, +) from airflow.operators.subdag import SubDagOperator from airflow.providers.amazon.auth_manager.avp.entities import AvpEntities from airflow.providers.amazon.aws.datasets import s3 @@ -85,7 +94,7 @@ from airflow.utils.dates import ( scale_time_units, ) from airflow.utils.decorators import apply_defaults -from airflow.utils.file import TemporaryDirectory, mkdirs +from airflow.utils.file import mkdirs from airflow.utils.helpers import chain, cross_downstream from airflow.utils.state import SHUTDOWN, terminating_states from airflow.utils.trigger_rule import TriggerRule @@ -94,61 +103,93 @@ from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_ # airflow root PY36, PY37, PY38, PY39, PY310, PY311, PY312 -DatasetFromRoot +DatasetFromRoot() + +dataset_from_root = DatasetFromRoot() +dataset_from_root.iter_datasets() +dataset_from_root.iter_dataset_aliases() # airflow.api_connexion.security requires_access, requires_access_dataset # airflow.auth.managers is_authorized_dataset -DatasetDetails +DatasetDetails() # airflow.configuration get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set # airflow.contrib.* -AWSAthenaHook +AWSAthenaHook() # airflow.datasets -Dataset -DatasetAlias -DatasetAliasEvent -DatasetAll -DatasetAny +Dataset() +DatasetAlias() +DatasetAliasEvent() +DatasetAll() +DatasetAny() expand_alias_to_datasets -Metadata +Metadata() + +dataset_to_test_method_call = Dataset() +dataset_to_test_method_call.iter_datasets() +dataset_to_test_method_call.iter_dataset_aliases() + +alias_to_test_method_call = DatasetAlias() +alias_to_test_method_call.iter_datasets() +alias_to_test_method_call.iter_dataset_aliases() + +any_to_test_method_call = DatasetAny() +any_to_test_method_call.iter_datasets() +any_to_test_method_call.iter_dataset_aliases() # airflow.datasets.manager -DatasetManager, dataset_manager, resolve_dataset_manager +DatasetManager(), dataset_manager, resolve_dataset_manager + +# airflow.hooks +BaseHook() # airflow.lineage.hook -DatasetLineageInfo +DatasetLineageInfo() # airflow.listeners.spec.dataset on_dataset_changed, on_dataset_created # airflow.metrics.validators -AllowListValidator, BlockListValidator +AllowListValidator(), BlockListValidator() # airflow.operators.dummy_operator -dummy_operator.EmptyOperator -dummy_operator.DummyOperator +dummy_operator.EmptyOperator() +dummy_operator.DummyOperator() # airflow.operators.bash_operator -BashOperator +BashOperator() # airflow.operators.branch_operator -BaseBranchOperator +BaseBranchOperator() + +# airflow.operators.dagrun_operator +TriggerDagRunLink() +TriggerDagRunOperator() # airflow.operators.dummy -EmptyOperator, DummyOperator +EmptyOperator(), DummyOperator() # airflow.operators.email_operator -EmailOperator +EmailOperator() + +# airflow.operators.latest_only_operator +LatestOnlyOperator() + +# airflow.operators.python_operator +BranchPythonOperator() +PythonOperator() +PythonVirtualenvOperator() +ShortCircuitOperator() # airflow.operators.subdag.* -SubDagOperator +SubDagOperator() # airflow.providers.amazon AvpEntities.DATASET @@ -175,7 +216,7 @@ gcs.convert_dataset_to_openlineage mysql.sanitize_uri # airflow.providers.openlineage -DatasetInfo, translate_airflow_dataset +DatasetInfo(), translate_airflow_dataset # airflow.providers.postgres postgres.sanitize_uri @@ -190,28 +231,28 @@ get_connection, load_connections RESOURCE_DATASET # airflow.sensors.base_sensor_operator -BaseSensorOperator +BaseSensorOperator() # airflow.sensors.date_time_sensor -DateTimeSensor +DateTimeSensor() # airflow.sensors.external_task -ExternalTaskSensorLinkFromExternalTask +ExternalTaskSensorLinkFromExternalTask() # airflow.sensors.external_task_sensor -ExternalTaskMarker -ExternalTaskSensor -ExternalTaskSensorLinkFromExternalTaskSensor +ExternalTaskMarker() +ExternalTaskSensor() +ExternalTaskSensorLinkFromExternalTaskSensor() # airflow.sensors.time_delta_sensor -TimeDeltaSensor +TimeDeltaSensor() # airflow.timetables -DatasetOrTimeSchedule -DatasetTriggeredTimetable +DatasetOrTimeSchedule() +DatasetTriggeredTimetable() # airflow.triggers.external_task -TaskStateTrigger +TaskStateTrigger() # airflow.utils.date dates.date_range @@ -235,7 +276,7 @@ test_cycle apply_defaults # airflow.utils.file -TemporaryDirectory, mkdirs +TemporaryDirector(), mkdirs # airflow.utils.helpers chain, cross_downstream @@ -253,34 +294,3 @@ has_access_dataset # airflow.www.utils get_sensitive_variables_fields, should_hide_value_for_key - -from airflow.datasets.manager import DatasetManager - -dm = DatasetManager() -dm.register_dataset_change() -dm.create_datasets() -dm.notify_dataset_created() -dm.notify_dataset_changed() -dm.notify_dataset_alias_created() - - -from airflow.lineage.hook import HookLineageCollector - -hlc = HookLineageCollector() -hlc.create_dataset() -hlc.add_input_dataset() -hlc.add_output_dataset() -hlc.collected_datasets() - - -from airflow.providers.amazon.auth_manager.aws_auth_manager import AwsAuthManager - -aam = AwsAuthManager() -aam.is_authorized_dataset() - - -from airflow.providers_manager import ProvidersManager - -pm = ProvidersManager() -pm.initialize_providers_asset_uri_resources() -pm.dataset_factories diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 052d54d652..64ab6a448b 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -279,6 +279,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { ); } } + if checker.enabled(Rule::Airflow3Removal) { + airflow::rules::removed_in_3(checker, expr); + } if checker.enabled(Rule::MixedCaseVariableInGlobalScope) { if matches!(checker.semantic.current_scope().kind, ScopeKind::Module) { pep8_naming::rules::mixed_case_variable_in_global_scope( diff --git a/crates/ruff_linter/src/rules/airflow/mod.rs b/crates/ruff_linter/src/rules/airflow/mod.rs index 4aa5d618c4..2f2e7dded7 100644 --- a/crates/ruff_linter/src/rules/airflow/mod.rs +++ b/crates/ruff_linter/src/rules/airflow/mod.rs @@ -16,6 +16,8 @@ mod tests { #[test_case(Rule::AirflowDagNoScheduleArgument, Path::new("AIR301.py"))] #[test_case(Rule::Airflow3Removal, Path::new("AIR302_args.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_airflow_plugin.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()); 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 1374d0cb65..fa4f0ded1e 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,19 +1,16 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, ViolationMetadata}; -use ruff_python_ast::{name::QualifiedName, Arguments, Expr, ExprAttribute, ExprCall}; +use ruff_python_ast::{ + name::QualifiedName, Arguments, Expr, ExprAttribute, ExprCall, ExprContext, ExprName, + StmtClassDef, +}; use ruff_python_semantic::analyze::typing; use ruff_python_semantic::Modules; +use ruff_python_semantic::ScopeKind; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -#[derive(Debug, Eq, PartialEq)] -enum Replacement { - None, - Name(&'static str), - Message(&'static str), -} - /// ## What it does /// Checks for uses of deprecated Airflow functions and values. /// @@ -73,36 +70,51 @@ impl Violation for Airflow3Removal { } } -fn diagnostic_for_argument( - arguments: &Arguments, - deprecated: &str, - replacement: Option<&'static str>, -) -> Option { - let keyword = arguments.find_keyword(deprecated)?; - let mut diagnostic = Diagnostic::new( - Airflow3Removal { - deprecated: (*deprecated).to_string(), - replacement: match replacement { - Some(name) => Replacement::Name(name), - None => Replacement::None, - }, - }, - keyword - .arg - .as_ref() - .map_or_else(|| keyword.range(), Ranged::range), - ); - - if let Some(replacement) = replacement { - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - replacement.to_string(), - diagnostic.range, - ))); +/// AIR302 +pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { + if !checker.semantic().seen_module(Modules::AIRFLOW) { + return; } - Some(diagnostic) + match expr { + Expr::Call(ExprCall { + func, arguments, .. + }) => { + if let Some(qualname) = checker.semantic().resolve_qualified_name(func) { + removed_argument(checker, &qualname, arguments); + }; + + removed_method(checker, expr); + } + Expr::Attribute(ExprAttribute { attr: ranged, .. }) => { + removed_name(checker, expr, ranged); + removed_class_attribute(checker, expr); + } + ranged @ Expr::Name(ExprName { id, ctx, .. }) => { + removed_name(checker, expr, ranged); + if ctx == &ExprContext::Store { + if let ScopeKind::Class(class_def) = &checker.semantic().current_scope().kind { + removed_airflow_plugin_extension(checker, expr, id, class_def); + } + } + } + _ => {} + } } +#[derive(Debug, Eq, PartialEq)] +enum Replacement { + None, + Name(&'static str), + Message(&'static str), +} + +// Check whether a removed Airflow argument is passed. +// +// Example: +// +// from airflow import DAG +// DAG(schedule_interval="@daily") fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: &Arguments) { #[allow(clippy::single_match)] match qualname.segments() { @@ -123,38 +135,121 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: None::<&str>, )); } - ["airflow", .., "operators", "trigger_dagrun", "TriggerDagRunOperator"] => { - checker.diagnostics.extend(diagnostic_for_argument( - arguments, - "execution_date", - Some("logical_date"), - )); + _ => { + if is_airflow_auth_manager(qualname.segments()) { + if !arguments.is_empty() { + checker.diagnostics.push(Diagnostic::new( + Airflow3Removal { + // deprecated: (*arguments).to_string(), + deprecated: "appbuilder".to_string(), + replacement: Replacement::Message( + "The constructor takes no parameter now.", + ), + }, + arguments.range(), + )); + } + } else if is_airflow_task_handler(qualname.segments()) { + checker.diagnostics.extend(diagnostic_for_argument( + arguments, + "filename_template", + None::<&str>, + )); + } else if is_airflow_operator(qualname.segments()) { + checker + .diagnostics + .extend(diagnostic_for_argument(arguments, "sla", None::<&str>)); + checker.diagnostics.extend(diagnostic_for_argument( + arguments, + "task_concurrency", + Some("max_active_tis_per_dag"), + )); + match qualname.segments() { + ["airflow", .., "operators", "trigger_dagrun", "TriggerDagRunOperator"] => { + checker.diagnostics.extend(diagnostic_for_argument( + arguments, + "execution_date", + Some("logical_date"), + )); + } + ["airflow", .., "operators", "datetime", "BranchDateTimeOperator"] => { + checker.diagnostics.extend(diagnostic_for_argument( + arguments, + "use_task_execution_day", + Some("use_task_logical_date"), + )); + } + ["airflow", .., "operators", "weekday", "DayOfWeekSensor"] => { + checker.diagnostics.extend(diagnostic_for_argument( + arguments, + "use_task_execution_day", + Some("use_task_logical_date"), + )); + } + ["airflow", .., "operators", "weekday", "BranchDayOfWeekOperator"] => { + checker.diagnostics.extend(diagnostic_for_argument( + arguments, + "use_task_execution_day", + Some("use_task_logical_date"), + )); + } + _ => {} + } + } } - ["airflow", .., "operators", "datetime", "BranchDateTimeOperator"] => { - checker.diagnostics.extend(diagnostic_for_argument( - arguments, - "use_task_execution_day", - Some("use_task_logical_date"), - )); - } - ["airflow", .., "operators", "weekday", "DayOfWeekSensor"] => { - checker.diagnostics.extend(diagnostic_for_argument( - arguments, - "use_task_execution_day", - Some("use_task_logical_date"), - )); - } - ["airflow", .., "operators", "weekday", "BranchDayOfWeekOperator"] => { - checker.diagnostics.extend(diagnostic_for_argument( - arguments, - "use_task_execution_day", - Some("use_task_logical_date"), - )); - } - _ => {} }; } +// Check whether a removed Airflow class attribute (include property) is called. +// +// Example: +// +// from airflow.linesage.hook import DatasetLineageInfo +// info = DatasetLineageInfo() +// info.dataset +fn removed_class_attribute(checker: &mut Checker, expr: &Expr) { + let Expr::Attribute(ExprAttribute { attr, value, .. }) = expr else { + return; + }; + + let Some(qualname) = typing::resolve_assignment(value, checker.semantic()) else { + return; + }; + + let replacement = match *qualname.segments() { + ["airflow", "providers_manager", "ProvidersManager"] => match attr.as_str() { + "dataset_factories" => Some(Replacement::Name("asset_factories")), + "dataset_uri_handlers" => Some(Replacement::Name("asset_uri_handlers")), + "dataset_to_openlineage_converters" => { + Some(Replacement::Name("asset_to_openlineage_converters")) + } + &_ => None, + }, + ["airflow", "lineage", "hook", "DatasetLineageInfo"] => match attr.as_str() { + "dataset" => Some(Replacement::Name("asset")), + &_ => None, + }, + _ => None, + }; + if let Some(replacement) = replacement { + checker.diagnostics.push(Diagnostic::new( + Airflow3Removal { + deprecated: attr.to_string(), + replacement, + }, + attr.range(), + )); + } +} + +// Check whether a removed Airflow class method is called. +// +// Example: +// +// from airflow.datasets.manager import DatasetManager +// +// manager = DatasetManager() +// manger.register_datsaet_change() fn removed_method(checker: &mut Checker, expr: &Expr) { let Expr::Call(ExprCall { func, .. }) = expr else { return; @@ -196,7 +291,27 @@ fn removed_method(checker: &mut Checker, expr: &Expr) { )), &_ => None, }, - _ => None, + ["airflow", "datasets", ..] | ["airflow", "Dataset"] => match attr.as_str() { + "iter_datasets" => Some(Replacement::Name("iter_assets")), + "iter_dataset_aliases" => Some(Replacement::Name("iter_asset_aliases")), + &_ => None, + }, + _ => { + if is_airflow_secret_backend(qualname.segments()) { + match attr.as_str() { + "get_conn_uri" => Some(Replacement::Name("get_conn_value")), + "get_connections" => Some(Replacement::Name("get_connection")), + &_ => None, + } + } else if is_airflow_hook(qualname.segments()) { + match attr.as_str() { + "get_connections" => Some(Replacement::Name("get_connection")), + &_ => None, + } + } else { + None + } + } }; if let Some(replacement) = replacement { checker.diagnostics.push(Diagnostic::new( @@ -209,6 +324,11 @@ fn removed_method(checker: &mut Checker, expr: &Expr) { } } +// Check whether a removed Airflow name is used. +// +// Example: +// +// from airflow.operators.subdag import SubDagOperator fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { let result = checker @@ -390,6 +510,11 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { qualname.to_string(), Replacement::Name("airflow.lineage.hook.AssetLineageInfo"), )), + // airflow.hooks + ["airflow", "hooks", "base_hook", "BaseHook"] => Some(( + qualname.to_string(), + Replacement::Name("airflow.hooks.base.BaseHook"), + )), // airflow.operators ["airflow", "operators", "subdag", ..] => { Some(( @@ -399,10 +524,6 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { ), )) }, - ["airflow", "sensors", "external_task", "ExternalTaskSensorLink"] => Some(( - qualname.to_string(), - Replacement::Name("airflow.sensors.external_task.ExternalDagLink"), - )), ["airflow", "operators", "bash_operator", "BashOperator"] => Some(( qualname.to_string(), Replacement::Name("airflow.operators.bash.BashOperator"), @@ -431,6 +552,53 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { qualname.to_string(), Replacement::Name("airflow.operators.email.EmailOperator"), )), + ["airflow", "operators", "dagrun_operator", "TriggerDagRunLink"] => Some(( + qualname.to_string(), + Replacement::Name( + "airflow.operators.trigger_dagrun.TriggerDagRunLink", + ), + )), + ["airflow", "operators", "dagrun_operator", "TriggerDagRunOperator"] => Some(( + qualname.to_string(), + Replacement::Name( + "airflow.operators.trigger_dagrun.TriggerDagRunOperator", + ), + )), + ["airflow", "operators", "python_operator", "BranchPythonOperator"] => Some(( + qualname.to_string(), + Replacement::Name( + "airflow.operators.python.BranchPythonOperator", + ), + )), + ["airflow", "operators", "python_operator", "PythonOperator"] => Some(( + qualname.to_string(), + Replacement::Name( + "airflow.operators.python.PythonOperator", + ), + )), + ["airflow", "operators", "python_operator", "PythonVirtualenvOperator"] => Some(( + qualname.to_string(), + Replacement::Name( + "airflow.operators.python.PythonVirtualenvOperator", + ), + )), + ["airflow", "operators", "python_operator", "ShortCircuitOperator"] => Some(( + qualname.to_string(), + Replacement::Name( + "airflow.operators.python.ShortCircuitOperator", + ), + )), + ["airflow", "operators", "latest_only_operator", "LatestOnlyOperator"] => Some(( + qualname.to_string(), + Replacement::Name( + " airflow.operators.latest_only.LatestOnlyOperator", + ), + )), + // airflow.sensors + ["airflow", "sensors", "external_task", "ExternalTaskSensorLink"] => Some(( + qualname.to_string(), + Replacement::Name("airflow.sensors.external_task.ExternalDagLink"), + )), ["airflow", "sensors", "base_sensor_operator", "BaseSensorOperator"] => Some(( qualname.to_string(), Replacement::Name("airflow.sensors.base.BaseSensorOperator"), @@ -646,24 +814,157 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { } } -/// AIR302 -pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { - if !checker.semantic().seen_module(Modules::AIRFLOW) { - return; - } - - match expr { - Expr::Call(ExprCall { - func, arguments, .. - }) => { - if let Some(qualname) = checker.semantic().resolve_qualified_name(func) { - removed_argument(checker, &qualname, arguments); - }; - - removed_method(checker, expr); +// Check whether a customized Airflow plugin contains removed extensions. +// +// Example: +// +// class CustomizePlugin(AirflowPlugin) +// executors = "some.third.party.executor" +fn removed_airflow_plugin_extension( + checker: &mut Checker, + expr: &Expr, + name: &str, + class_def: &StmtClassDef, +) { + if matches!(name, "executors" | "operators" | "sensors" | "hooks") { + if class_def.bases().iter().any(|expr| { + checker + .semantic() + .resolve_qualified_name(expr) + .is_some_and(|qualified_name| { + matches!( + qualified_name.segments(), + ["airflow", "plugins_manager", "AirflowPlugin"] + ) + }) + }) { + checker.diagnostics.push(Diagnostic::new( + Airflow3Removal { + deprecated: name.to_string(), + replacement: Replacement::Message( + "This extension should just be imported as a regular python module.", + ), + }, + expr.range(), + )); } - Expr::Attribute(ExprAttribute { attr: ranged, .. }) => removed_name(checker, expr, ranged), - ranged @ Expr::Name(_) => removed_name(checker, expr, ranged), - _ => {} + } +} + +fn diagnostic_for_argument( + arguments: &Arguments, + deprecated: &str, + replacement: Option<&'static str>, +) -> Option { + let keyword = arguments.find_keyword(deprecated)?; + let mut diagnostic = Diagnostic::new( + Airflow3Removal { + deprecated: (*deprecated).to_string(), + replacement: match replacement { + Some(name) => Replacement::Name(name), + None => Replacement::None, + }, + }, + keyword + .arg + .as_ref() + .map_or_else(|| keyword.range(), Ranged::range), + ); + + if let Some(replacement) = replacement { + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + replacement.to_string(), + diagnostic.range, + ))); + } + + Some(diagnostic) +} + +/// Check whether the segments corresponding to the fully qualified name points to a symbol that's +/// either a builtin or coming from one of the providers in Airflow. +/// +/// The pattern it looks for are: +/// - `airflow.providers.**..**.*` for providers +/// - `airflow..**.*` for builtins +/// +/// where `**` is one or more segments separated by a dot, and `*` is one or more characters. +/// +/// Examples for the above patterns: +/// - `airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend` (provider) +/// - `airflow.secrets.base_secrets.BaseSecretsBackend` (builtin) +fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix: &str) -> bool { + match segments { + ["airflow", "providers", rest @ ..] => { + if let (Some(pos), Some(last_element)) = + (rest.iter().position(|&s| s == module), rest.last()) + { + // Check that the module is not the last element i.e., there's a symbol that's + // being used from the `module` that ends with `symbol_suffix`. + pos + 1 < rest.len() && last_element.ends_with(symbol_suffix) + } else { + false + } + } + + ["airflow", first, rest @ ..] => { + if let Some(last) = rest.last() { + *first == module && last.ends_with(symbol_suffix) + } else { + false + } + } + + _ => false, + } +} + +/// Check whether the symbol is coming from the `secrets` builtin or provider module which ends +/// with `Backend`. +fn is_airflow_secret_backend(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "secrets", "Backend") +} + +/// Check whether the symbol is coming from the `hooks` builtin or provider module which ends +/// with `Hook`. +fn is_airflow_hook(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "hooks", "Hook") +} + +/// Check whether the symbol is coming from the `operators` builtin or provider module which ends +/// with `Operator`. +fn is_airflow_operator(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "operators", "Operator") +} + +/// Check whether the symbol is coming from the `log` builtin or provider module which ends +/// with `TaskHandler`. +fn is_airflow_task_handler(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "log", "TaskHandler") +} + +/// Check whether the symbol is coming from the `auth.manager` builtin or provider `auth_manager` module which ends +/// with `AuthManager`. +fn is_airflow_auth_manager(segments: &[&str]) -> bool { + match segments { + ["airflow", "auth", "manager", rest @ ..] => { + if let Some(last_element) = rest.last() { + last_element.ends_with("AuthManager") + } else { + false + } + } + + ["airflow", "providers", rest @ ..] => { + if let (Some(pos), Some(last_element)) = + (rest.iter().position(|&s| s == "auth_manager"), rest.last()) + { + pos + 1 < rest.len() && last_element.ends_with("AuthManager") + } else { + false + } + } + + _ => false, } } diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_airflow_plugin.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_airflow_plugin.py.snap new file mode 100644 index 0000000000..e94bafe216 --- /dev/null +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_airflow_plugin.py.snap @@ -0,0 +1,43 @@ +--- +source: crates/ruff_linter/src/rules/airflow/mod.rs +snapshot_kind: text +--- +AIR302_airflow_plugin.py:7:5: AIR302 `operators` is removed in Airflow 3.0; This extension should just be imported as a regular python module. + | +5 | name = "test_plugin" +6 | # --- Invalid extensions start +7 | operators = [PluginOperator] + | ^^^^^^^^^ AIR302 +8 | sensors = [PluginSensorOperator] +9 | hooks = [PluginHook] + | + +AIR302_airflow_plugin.py:8:5: AIR302 `sensors` is removed in Airflow 3.0; This extension should just be imported as a regular python module. + | + 6 | # --- Invalid extensions start + 7 | operators = [PluginOperator] + 8 | sensors = [PluginSensorOperator] + | ^^^^^^^ AIR302 + 9 | hooks = [PluginHook] +10 | executors = [PluginExecutor] + | + +AIR302_airflow_plugin.py:9:5: AIR302 `hooks` is removed in Airflow 3.0; This extension should just be imported as a regular python module. + | + 7 | operators = [PluginOperator] + 8 | sensors = [PluginSensorOperator] + 9 | hooks = [PluginHook] + | ^^^^^ AIR302 +10 | executors = [PluginExecutor] +11 | # --- Invalid extensions end + | + +AIR302_airflow_plugin.py:10:5: AIR302 `executors` is removed in Airflow 3.0; This extension should just be imported as a regular python module. + | + 8 | sensors = [PluginSensorOperator] + 9 | hooks = [PluginHook] +10 | executors = [PluginExecutor] + | ^^^^^^^^^ AIR302 +11 | # --- Invalid extensions end +12 | macros = [plugin_macro] + | diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_args.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_args.py.snap index bd90b530f0..39a4da150e 100644 --- a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_args.py.snap +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_args.py.snap @@ -2,175 +2,251 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs snapshot_kind: text --- -AIR302_args.py:15:39: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_args.py:18:39: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -13 | DAG(dag_id="class_schedule", schedule="@hourly") -14 | -15 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +16 | DAG(dag_id="class_schedule", schedule="@hourly") +17 | +18 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") | ^^^^^^^^^^^^^^^^^ AIR302 -16 | -17 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +19 | +20 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | = help: Use `schedule` instead ℹ Safe fix -12 12 | -13 13 | DAG(dag_id="class_schedule", schedule="@hourly") -14 14 | -15 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") - 15 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") -16 16 | -17 17 | DAG(dag_id="class_timetable", timetable=NullTimetable()) -18 18 | +15 15 | +16 16 | DAG(dag_id="class_schedule", schedule="@hourly") +17 17 | +18 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") + 18 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") +19 19 | +20 20 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +21 21 | -AIR302_args.py:17:31: AIR302 [*] `timetable` is removed in Airflow 3.0 +AIR302_args.py:20:31: AIR302 [*] `timetable` is removed in Airflow 3.0 | -15 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") -16 | -17 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +18 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +19 | +20 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | ^^^^^^^^^ AIR302 | = help: Use `schedule` instead ℹ Safe fix -14 14 | -15 15 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") -16 16 | -17 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) - 17 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) -18 18 | +17 17 | +18 18 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") 19 19 | -20 20 | def sla_callback(*arg, **kwargs): +20 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) + 20 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) +21 21 | +22 22 | +23 23 | def sla_callback(*arg, **kwargs): -AIR302_args.py:24:34: AIR302 `sla_miss_callback` is removed in Airflow 3.0 +AIR302_args.py:27:34: AIR302 `sla_miss_callback` is removed in Airflow 3.0 | -24 | DAG(dag_id="class_sla_callback", sla_miss_callback=sla_callback) +27 | DAG(dag_id="class_sla_callback", sla_miss_callback=sla_callback) | ^^^^^^^^^^^^^^^^^ AIR302 | -AIR302_args.py:32:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_args.py:35:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -32 | @dag(schedule_interval="0 * * * *") +35 | @dag(schedule_interval="0 * * * *") | ^^^^^^^^^^^^^^^^^ AIR302 -33 | def decorator_schedule_interval(): -34 | pass +36 | def decorator_schedule_interval(): +37 | pass | = help: Use `schedule` instead ℹ Safe fix -29 29 | pass -30 30 | -31 31 | -32 |-@dag(schedule_interval="0 * * * *") - 32 |+@dag(schedule="0 * * * *") -33 33 | def decorator_schedule_interval(): -34 34 | pass -35 35 | +32 32 | pass +33 33 | +34 34 | +35 |-@dag(schedule_interval="0 * * * *") + 35 |+@dag(schedule="0 * * * *") +36 36 | def decorator_schedule_interval(): +37 37 | pass +38 38 | -AIR302_args.py:37:6: AIR302 [*] `timetable` is removed in Airflow 3.0 +AIR302_args.py:40:6: AIR302 [*] `timetable` is removed in Airflow 3.0 | -37 | @dag(timetable=NullTimetable()) +40 | @dag(timetable=NullTimetable()) | ^^^^^^^^^ AIR302 -38 | def decorator_timetable(): -39 | pass +41 | def decorator_timetable(): +42 | pass | = help: Use `schedule` instead ℹ Safe fix -34 34 | pass -35 35 | -36 36 | -37 |-@dag(timetable=NullTimetable()) - 37 |+@dag(schedule=NullTimetable()) -38 38 | def decorator_timetable(): -39 39 | pass -40 40 | +37 37 | pass +38 38 | +39 39 | +40 |-@dag(timetable=NullTimetable()) + 40 |+@dag(schedule=NullTimetable()) +41 41 | def decorator_timetable(): +42 42 | pass +43 43 | -AIR302_args.py:42:6: AIR302 `sla_miss_callback` is removed in Airflow 3.0 +AIR302_args.py:45:6: AIR302 `sla_miss_callback` is removed in Airflow 3.0 | -42 | @dag(sla_miss_callback=sla_callback) +45 | @dag(sla_miss_callback=sla_callback) | ^^^^^^^^^^^^^^^^^ AIR302 -43 | def decorator_sla_callback(): -44 | pass +46 | def decorator_sla_callback(): +47 | pass | -AIR302_args.py:50:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 - | -48 | def decorator_deprecated_operator_args(): -49 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -50 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" - | ^^^^^^^^^^^^^^ AIR302 -51 | ) -52 | trigger_dagrun_op2 = TriggerDagRunOperator( - | - = help: Use `logical_date` instead - -ℹ Safe fix -47 47 | @dag() -48 48 | def decorator_deprecated_operator_args(): -49 49 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -50 |- task_id="trigger_dagrun_op1", execution_date="2024-12-04" - 50 |+ task_id="trigger_dagrun_op1", logical_date="2024-12-04" -51 51 | ) -52 52 | trigger_dagrun_op2 = TriggerDagRunOperator( -53 53 | task_id="trigger_dagrun_op2", execution_date="2024-12-04" - AIR302_args.py:53:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 | -51 | ) -52 | trigger_dagrun_op2 = TriggerDagRunOperator( -53 | task_id="trigger_dagrun_op2", execution_date="2024-12-04" +51 | def decorator_deprecated_operator_args(): +52 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +53 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" | ^^^^^^^^^^^^^^ AIR302 54 | ) +55 | trigger_dagrun_op2 = TriggerDagRunOperator( | = help: Use `logical_date` instead ℹ Safe fix -50 50 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" -51 51 | ) -52 52 | trigger_dagrun_op2 = TriggerDagRunOperator( -53 |- task_id="trigger_dagrun_op2", execution_date="2024-12-04" - 53 |+ task_id="trigger_dagrun_op2", logical_date="2024-12-04" +50 50 | @dag() +51 51 | def decorator_deprecated_operator_args(): +52 52 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +53 |- task_id="trigger_dagrun_op1", execution_date="2024-12-04" + 53 |+ task_id="trigger_dagrun_op1", logical_date="2024-12-04" 54 54 | ) -55 55 | -56 56 | branch_dt_op = datetime.BranchDateTimeOperator( +55 55 | trigger_dagrun_op2 = TriggerDagRunOperator( +56 56 | task_id="trigger_dagrun_op2", execution_date="2024-12-04" -AIR302_args.py:57:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 +AIR302_args.py:56:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 | -56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 | task_id="branch_dt_op", use_task_execution_day=True +54 | ) +55 | trigger_dagrun_op2 = TriggerDagRunOperator( +56 | task_id="trigger_dagrun_op2", execution_date="2024-12-04" + | ^^^^^^^^^^^^^^ AIR302 +57 | ) + | + = help: Use `logical_date` instead + +ℹ Safe fix +53 53 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" +54 54 | ) +55 55 | trigger_dagrun_op2 = TriggerDagRunOperator( +56 |- task_id="trigger_dagrun_op2", execution_date="2024-12-04" + 56 |+ task_id="trigger_dagrun_op2", logical_date="2024-12-04" +57 57 | ) +58 58 | +59 59 | branch_dt_op = datetime.BranchDateTimeOperator( + +AIR302_args.py:60:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 + | +59 | branch_dt_op = datetime.BranchDateTimeOperator( +60 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -58 | ) -59 | branch_dt_op2 = BranchDateTimeOperator( - | - = help: Use `use_task_logical_date` instead - -ℹ Safe fix -54 54 | ) -55 55 | -56 56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 |- task_id="branch_dt_op", use_task_execution_day=True - 57 |+ task_id="branch_dt_op", use_task_logical_date=True -58 58 | ) -59 59 | branch_dt_op2 = BranchDateTimeOperator( -60 60 | task_id="branch_dt_op2", use_task_execution_day=True - -AIR302_args.py:60:34: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 - | -58 | ) -59 | branch_dt_op2 = BranchDateTimeOperator( -60 | task_id="branch_dt_op2", use_task_execution_day=True - | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 61 | ) +62 | branch_dt_op2 = BranchDateTimeOperator( | = help: Use `use_task_logical_date` instead ℹ Safe fix -57 57 | task_id="branch_dt_op", use_task_execution_day=True -58 58 | ) -59 59 | branch_dt_op2 = BranchDateTimeOperator( -60 |- task_id="branch_dt_op2", use_task_execution_day=True - 60 |+ task_id="branch_dt_op2", use_task_logical_date=True +57 57 | ) +58 58 | +59 59 | branch_dt_op = datetime.BranchDateTimeOperator( +60 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + 60 |+ task_id="branch_dt_op", use_task_logical_date=True, task_concurrency=5 61 61 | ) -62 62 | -63 63 | dof_task_sensor = weekday.DayOfWeekSensor( +62 62 | branch_dt_op2 = BranchDateTimeOperator( +63 63 | task_id="branch_dt_op2", + +AIR302_args.py:60:62: AIR302 [*] `task_concurrency` is removed in Airflow 3.0 + | +59 | branch_dt_op = datetime.BranchDateTimeOperator( +60 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + | ^^^^^^^^^^^^^^^^ AIR302 +61 | ) +62 | branch_dt_op2 = BranchDateTimeOperator( + | + = help: Use `max_active_tis_per_dag` instead + +ℹ Safe fix +57 57 | ) +58 58 | +59 59 | branch_dt_op = datetime.BranchDateTimeOperator( +60 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + 60 |+ task_id="branch_dt_op", use_task_execution_day=True, max_active_tis_per_dag=5 +61 61 | ) +62 62 | branch_dt_op2 = BranchDateTimeOperator( +63 63 | task_id="branch_dt_op2", + +AIR302_args.py:64:9: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 + | +62 | branch_dt_op2 = BranchDateTimeOperator( +63 | task_id="branch_dt_op2", +64 | use_task_execution_day=True, + | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 +65 | sla=timedelta(seconds=10), +66 | ) + | + = help: Use `use_task_logical_date` instead + +ℹ Safe fix +61 61 | ) +62 62 | branch_dt_op2 = BranchDateTimeOperator( +63 63 | task_id="branch_dt_op2", +64 |- use_task_execution_day=True, + 64 |+ use_task_logical_date=True, +65 65 | sla=timedelta(seconds=10), +66 66 | ) +67 67 | + +AIR302_args.py:65:9: AIR302 `sla` is removed in Airflow 3.0 + | +63 | task_id="branch_dt_op2", +64 | use_task_execution_day=True, +65 | sla=timedelta(seconds=10), + | ^^^ AIR302 +66 | ) + | + +AIR302_args.py:87:15: AIR302 `filename_template` is removed in Airflow 3.0 + | +86 | # deprecated filename_template arugment in FileTaskHandler +87 | S3TaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +88 | HdfsTaskHandler(filename_template="/tmp/test") +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") + | + +AIR302_args.py:88:17: AIR302 `filename_template` is removed in Airflow 3.0 + | +86 | # deprecated filename_template arugment in FileTaskHandler +87 | S3TaskHandler(filename_template="/tmp/test") +88 | HdfsTaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") +90 | GCSTaskHandler(filename_template="/tmp/test") + | + +AIR302_args.py:89:26: AIR302 `filename_template` is removed in Airflow 3.0 + | +87 | S3TaskHandler(filename_template="/tmp/test") +88 | HdfsTaskHandler(filename_template="/tmp/test") +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +90 | GCSTaskHandler(filename_template="/tmp/test") + | + +AIR302_args.py:90:16: AIR302 `filename_template` is removed in Airflow 3.0 + | +88 | HdfsTaskHandler(filename_template="/tmp/test") +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") +90 | GCSTaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +91 | +92 | FabAuthManager(None) + | + +AIR302_args.py:92:15: AIR302 `appbuilder` is removed in Airflow 3.0; The constructor takes no parameter now. + | +90 | GCSTaskHandler(filename_template="/tmp/test") +91 | +92 | FabAuthManager(None) + | ^^^^^^ AIR302 + | diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_class_attribute.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_class_attribute.py.snap new file mode 100644 index 0000000000..4066c8e63d --- /dev/null +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_class_attribute.py.snap @@ -0,0 +1,228 @@ +--- +source: crates/ruff_linter/src/rules/airflow/mod.rs +snapshot_kind: text +--- +AIR302_class_attribute.py:13:4: AIR302 `register_dataset_change` is removed in Airflow 3.0 + | +12 | dm = DatasetManager() +13 | dm.register_dataset_change() + | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +14 | dm.create_datasets() +15 | dm.notify_dataset_created() + | + = help: Use `register_asset_change` instead + +AIR302_class_attribute.py:14:4: AIR302 `create_datasets` is removed in Airflow 3.0 + | +12 | dm = DatasetManager() +13 | dm.register_dataset_change() +14 | dm.create_datasets() + | ^^^^^^^^^^^^^^^ AIR302 +15 | dm.notify_dataset_created() +16 | dm.notify_dataset_changed() + | + = help: Use `create_assets` instead + +AIR302_class_attribute.py:15:4: AIR302 `notify_dataset_created` is removed in Airflow 3.0 + | +13 | dm.register_dataset_change() +14 | dm.create_datasets() +15 | dm.notify_dataset_created() + | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 +16 | dm.notify_dataset_changed() +17 | dm.notify_dataset_alias_created() + | + = help: Use `notify_asset_created` instead + +AIR302_class_attribute.py:16:4: AIR302 `notify_dataset_changed` is removed in Airflow 3.0 + | +14 | dm.create_datasets() +15 | dm.notify_dataset_created() +16 | dm.notify_dataset_changed() + | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 +17 | dm.notify_dataset_alias_created() + | + = help: Use `notify_asset_changed` instead + +AIR302_class_attribute.py:17:4: AIR302 `notify_dataset_alias_created` is removed in Airflow 3.0 + | +15 | dm.notify_dataset_created() +16 | dm.notify_dataset_changed() +17 | dm.notify_dataset_alias_created() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +18 | +19 | hlc = HookLineageCollector() + | + = help: Use `notify_asset_alias_created` instead + +AIR302_class_attribute.py:20:5: AIR302 `create_dataset` is removed in Airflow 3.0 + | +19 | hlc = HookLineageCollector() +20 | hlc.create_dataset() + | ^^^^^^^^^^^^^^ AIR302 +21 | hlc.add_input_dataset() +22 | hlc.add_output_dataset() + | + = help: Use `create_asset` instead + +AIR302_class_attribute.py:21:5: AIR302 `add_input_dataset` is removed in Airflow 3.0 + | +19 | hlc = HookLineageCollector() +20 | hlc.create_dataset() +21 | hlc.add_input_dataset() + | ^^^^^^^^^^^^^^^^^ AIR302 +22 | hlc.add_output_dataset() +23 | hlc.collected_datasets() + | + = help: Use `add_input_asset` instead + +AIR302_class_attribute.py:22:5: AIR302 `add_output_dataset` is removed in Airflow 3.0 + | +20 | hlc.create_dataset() +21 | hlc.add_input_dataset() +22 | hlc.add_output_dataset() + | ^^^^^^^^^^^^^^^^^^ AIR302 +23 | hlc.collected_datasets() + | + = help: Use `add_output_asset` instead + +AIR302_class_attribute.py:23:5: AIR302 `collected_datasets` is removed in Airflow 3.0 + | +21 | hlc.add_input_dataset() +22 | hlc.add_output_dataset() +23 | hlc.collected_datasets() + | ^^^^^^^^^^^^^^^^^^ AIR302 +24 | +25 | aam = AwsAuthManager() + | + = help: Use `collected_assets` instead + +AIR302_class_attribute.py:26:5: AIR302 `is_authorized_dataset` is removed in Airflow 3.0 + | +25 | aam = AwsAuthManager() +26 | aam.is_authorized_dataset() + | ^^^^^^^^^^^^^^^^^^^^^ AIR302 +27 | +28 | pm = ProvidersManager() + | + = help: Use `is_authorized_asset` instead + +AIR302_class_attribute.py:30:4: AIR302 `dataset_factories` is removed in Airflow 3.0 + | +28 | pm = ProvidersManager() +29 | pm.initialize_providers_asset_uri_resources() +30 | pm.dataset_factories + | ^^^^^^^^^^^^^^^^^ AIR302 +31 | +32 | base_secret_backend = BaseSecretsBackend() + | + = help: Use `asset_factories` instead + +AIR302_class_attribute.py:33:21: AIR302 `get_conn_uri` is removed in Airflow 3.0 + | +32 | base_secret_backend = BaseSecretsBackend() +33 | base_secret_backend.get_conn_uri() + | ^^^^^^^^^^^^ AIR302 +34 | base_secret_backend.get_connections() + | + = help: Use `get_conn_value` instead + +AIR302_class_attribute.py:34:21: AIR302 `get_connections` is removed in Airflow 3.0 + | +32 | base_secret_backend = BaseSecretsBackend() +33 | base_secret_backend.get_conn_uri() +34 | base_secret_backend.get_connections() + | ^^^^^^^^^^^^^^^ AIR302 +35 | +36 | csm_backend = CloudSecretManagerBackend() + | + = help: Use `get_connection` instead + +AIR302_class_attribute.py:37:13: AIR302 `get_conn_uri` is removed in Airflow 3.0 + | +36 | csm_backend = CloudSecretManagerBackend() +37 | csm_backend.get_conn_uri() + | ^^^^^^^^^^^^ AIR302 +38 | csm_backend.get_connections() + | + = help: Use `get_conn_value` instead + +AIR302_class_attribute.py:38:13: AIR302 `get_connections` is removed in Airflow 3.0 + | +36 | csm_backend = CloudSecretManagerBackend() +37 | csm_backend.get_conn_uri() +38 | csm_backend.get_connections() + | ^^^^^^^^^^^^^^^ AIR302 +39 | +40 | vault_backend = VaultBackend() + | + = help: Use `get_connection` instead + +AIR302_class_attribute.py:41:15: AIR302 `get_conn_uri` is removed in Airflow 3.0 + | +40 | vault_backend = VaultBackend() +41 | vault_backend.get_conn_uri() + | ^^^^^^^^^^^^ AIR302 +42 | vault_backend.get_connections() + | + = help: Use `get_conn_value` instead + +AIR302_class_attribute.py:42:15: AIR302 `get_connections` is removed in Airflow 3.0 + | +40 | vault_backend = VaultBackend() +41 | vault_backend.get_conn_uri() +42 | vault_backend.get_connections() + | ^^^^^^^^^^^^^^^ AIR302 +43 | +44 | not_an_error = NotAir302SecretError() + | + = help: Use `get_connection` instead + +AIR302_class_attribute.py:54:18: AIR302 `dataset_factories` is removed in Airflow 3.0 + | +53 | provider_manager = ProvidersManager() +54 | provider_manager.dataset_factories + | ^^^^^^^^^^^^^^^^^ AIR302 +55 | provider_manager.dataset_uri_handlers +56 | provider_manager.dataset_to_openlineage_converters + | + = help: Use `asset_factories` instead + +AIR302_class_attribute.py:55:18: AIR302 `dataset_uri_handlers` is removed in Airflow 3.0 + | +53 | provider_manager = ProvidersManager() +54 | provider_manager.dataset_factories +55 | provider_manager.dataset_uri_handlers + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +56 | provider_manager.dataset_to_openlineage_converters + | + = help: Use `asset_uri_handlers` instead + +AIR302_class_attribute.py:56:18: AIR302 `dataset_to_openlineage_converters` is removed in Airflow 3.0 + | +54 | provider_manager.dataset_factories +55 | provider_manager.dataset_uri_handlers +56 | provider_manager.dataset_to_openlineage_converters + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +57 | +58 | dl_info = DatasetLineageInfo() + | + = help: Use `asset_to_openlineage_converters` instead + +AIR302_class_attribute.py:58:11: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 + | +56 | provider_manager.dataset_to_openlineage_converters +57 | +58 | dl_info = DatasetLineageInfo() + | ^^^^^^^^^^^^^^^^^^ AIR302 +59 | dl_info.dataset + | + = help: Use `airflow.lineage.hook.AssetLineageInfo` instead + +AIR302_class_attribute.py:59:9: AIR302 `dataset` is removed in Airflow 3.0 + | +58 | dl_info = DatasetLineageInfo() +59 | dl_info.dataset + | ^^^^^^^ AIR302 + | + = help: Use `asset` instead diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_names.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_names.py.snap index 2400af6ed7..0b9980d549 100644 --- a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_names.py.snap +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_names.py.snap @@ -2,1008 +2,1102 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs snapshot_kind: text --- -AIR302_names.py:96:1: AIR302 `airflow.PY36` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:96:7: AIR302 `airflow.PY37` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:96:13: AIR302 `airflow.PY38` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:96:19: AIR302 `airflow.PY39` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:96:25: AIR302 `airflow.PY310` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:96:32: AIR302 `airflow.PY311` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:96:39: AIR302 `airflow.PY312` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^^ AIR302 -97 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:1: AIR302 `airflow.Dataset` is removed in Airflow 3.0 - | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 -97 | DatasetFromRoot - | ^^^^^^^^^^^^^^^ AIR302 -98 | -99 | # airflow.api_connexion.security - | - = help: Use `airflow.sdk.definitions.asset.Asset` instead - -AIR302_names.py:100:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 +AIR302_names.py:105:1: AIR302 `airflow.PY36` is removed in Airflow 3.0 | - 99 | # airflow.api_connexion.security -100 | requires_access, requires_access_dataset +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:105:7: AIR302 `airflow.PY37` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:105:13: AIR302 `airflow.PY38` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:105:19: AIR302 `airflow.PY39` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:105:25: AIR302 `airflow.PY310` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:105:32: AIR302 `airflow.PY311` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:105:39: AIR302 `airflow.PY312` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + | ^^^^^ AIR302 +106 | DatasetFromRoot() + | + = help: Use `sys.version_info` instead + +AIR302_names.py:106:1: AIR302 `airflow.Dataset` is removed in Airflow 3.0 + | +104 | # airflow root +105 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +106 | DatasetFromRoot() | ^^^^^^^^^^^^^^^ AIR302 -101 | -102 | # airflow.auth.managers +107 | +108 | dataset_from_root = DatasetFromRoot() + | + = help: Use `airflow.sdk.definitions.asset.Asset` instead + +AIR302_names.py:108:21: AIR302 `airflow.Dataset` is removed in Airflow 3.0 + | +106 | DatasetFromRoot() +107 | +108 | dataset_from_root = DatasetFromRoot() + | ^^^^^^^^^^^^^^^ AIR302 +109 | dataset_from_root.iter_datasets() +110 | dataset_from_root.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.Asset` instead + +AIR302_names.py:109:19: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +108 | dataset_from_root = DatasetFromRoot() +109 | dataset_from_root.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +110 | dataset_from_root.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:110:19: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +108 | dataset_from_root = DatasetFromRoot() +109 | dataset_from_root.iter_datasets() +110 | dataset_from_root.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +111 | +112 | # airflow.api_connexion.security + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:113:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 + | +112 | # airflow.api_connexion.security +113 | requires_access, requires_access_dataset + | ^^^^^^^^^^^^^^^ AIR302 +114 | +115 | # airflow.auth.managers | = help: Use `airflow.api_connexion.security.requires_access_*` instead -AIR302_names.py:100:18: AIR302 `airflow.api_connexion.security.requires_access_dataset` is removed in Airflow 3.0 +AIR302_names.py:113:18: AIR302 `airflow.api_connexion.security.requires_access_dataset` is removed in Airflow 3.0 | - 99 | # airflow.api_connexion.security -100 | requires_access, requires_access_dataset +112 | # airflow.api_connexion.security +113 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -101 | -102 | # airflow.auth.managers +114 | +115 | # airflow.auth.managers | = help: Use `airflow.api_connexion.security.requires_access_asset` instead -AIR302_names.py:103:1: AIR302 `airflow.auth.managers.base_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 +AIR302_names.py:116:1: AIR302 `airflow.auth.managers.base_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 | -102 | # airflow.auth.managers -103 | is_authorized_dataset +115 | # airflow.auth.managers +116 | is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -104 | DatasetDetails +117 | DatasetDetails() | = help: Use `airflow.auth.managers.base_auth_manager.is_authorized_asset` instead -AIR302_names.py:104:1: AIR302 `airflow.auth.managers.models.resource_details.DatasetDetails` is removed in Airflow 3.0 +AIR302_names.py:117:1: AIR302 `airflow.auth.managers.models.resource_details.DatasetDetails` is removed in Airflow 3.0 | -102 | # airflow.auth.managers -103 | is_authorized_dataset -104 | DatasetDetails +115 | # airflow.auth.managers +116 | is_authorized_dataset +117 | DatasetDetails() | ^^^^^^^^^^^^^^ AIR302 -105 | -106 | # airflow.configuration +118 | +119 | # airflow.configuration | = help: Use `airflow.auth.managers.models.resource_details.AssetDetails` instead -AIR302_names.py:107:1: AIR302 `airflow.configuration.get` is removed in Airflow 3.0 +AIR302_names.py:120:1: AIR302 `airflow.configuration.get` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^ AIR302 | = help: Use `airflow.configuration.conf.get` instead -AIR302_names.py:107:6: AIR302 `airflow.configuration.getboolean` is removed in Airflow 3.0 +AIR302_names.py:120:6: AIR302 `airflow.configuration.getboolean` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.getboolean` instead -AIR302_names.py:107:18: AIR302 `airflow.configuration.getfloat` is removed in Airflow 3.0 +AIR302_names.py:120:18: AIR302 `airflow.configuration.getfloat` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.getfloat` instead -AIR302_names.py:107:28: AIR302 `airflow.configuration.getint` is removed in Airflow 3.0 +AIR302_names.py:120:28: AIR302 `airflow.configuration.getint` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.getint` instead -AIR302_names.py:107:36: AIR302 `airflow.configuration.has_option` is removed in Airflow 3.0 +AIR302_names.py:120:36: AIR302 `airflow.configuration.has_option` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.has_option` instead -AIR302_names.py:107:48: AIR302 `airflow.configuration.remove_option` is removed in Airflow 3.0 +AIR302_names.py:120:48: AIR302 `airflow.configuration.remove_option` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.remove_option` instead -AIR302_names.py:107:63: AIR302 `airflow.configuration.as_dict` is removed in Airflow 3.0 +AIR302_names.py:120:63: AIR302 `airflow.configuration.as_dict` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.as_dict` instead -AIR302_names.py:107:72: AIR302 `airflow.configuration.set` is removed in Airflow 3.0 +AIR302_names.py:120:72: AIR302 `airflow.configuration.set` is removed in Airflow 3.0 | -106 | # airflow.configuration -107 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +119 | # airflow.configuration +120 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^ AIR302 | = help: Use `airflow.configuration.conf.set` instead -AIR302_names.py:111:1: AIR302 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0; The whole `airflow.contrib` module has been removed. +AIR302_names.py:124:1: AIR302 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0; The whole `airflow.contrib` module has been removed. | -110 | # airflow.contrib.* -111 | AWSAthenaHook +123 | # airflow.contrib.* +124 | AWSAthenaHook() | ^^^^^^^^^^^^^ AIR302 -112 | -113 | # airflow.datasets +125 | +126 | # airflow.datasets | -AIR302_names.py:114:1: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 +AIR302_names.py:127:1: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 | -113 | # airflow.datasets -114 | Dataset +126 | # airflow.datasets +127 | Dataset() | ^^^^^^^ AIR302 -115 | DatasetAlias -116 | DatasetAliasEvent +128 | DatasetAlias() +129 | DatasetAliasEvent() | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:115:1: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 +AIR302_names.py:128:1: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 | -113 | # airflow.datasets -114 | Dataset -115 | DatasetAlias +126 | # airflow.datasets +127 | Dataset() +128 | DatasetAlias() | ^^^^^^^^^^^^ AIR302 -116 | DatasetAliasEvent -117 | DatasetAll +129 | DatasetAliasEvent() +130 | DatasetAll() | = help: Use `airflow.sdk.definitions.asset.AssetAlias` instead -AIR302_names.py:116:1: AIR302 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 +AIR302_names.py:129:1: AIR302 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 | -114 | Dataset -115 | DatasetAlias -116 | DatasetAliasEvent +127 | Dataset() +128 | DatasetAlias() +129 | DatasetAliasEvent() | ^^^^^^^^^^^^^^^^^ AIR302 -117 | DatasetAll -118 | DatasetAny +130 | DatasetAll() +131 | DatasetAny() | -AIR302_names.py:117:1: AIR302 `airflow.datasets.DatasetAll` is removed in Airflow 3.0 +AIR302_names.py:130:1: AIR302 `airflow.datasets.DatasetAll` is removed in Airflow 3.0 | -115 | DatasetAlias -116 | DatasetAliasEvent -117 | DatasetAll +128 | DatasetAlias() +129 | DatasetAliasEvent() +130 | DatasetAll() | ^^^^^^^^^^ AIR302 -118 | DatasetAny -119 | expand_alias_to_datasets +131 | DatasetAny() +132 | expand_alias_to_datasets | = help: Use `airflow.sdk.definitions.asset.AssetAll` instead -AIR302_names.py:118:1: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 +AIR302_names.py:131:1: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 | -116 | DatasetAliasEvent -117 | DatasetAll -118 | DatasetAny +129 | DatasetAliasEvent() +130 | DatasetAll() +131 | DatasetAny() | ^^^^^^^^^^ AIR302 -119 | expand_alias_to_datasets -120 | Metadata +132 | expand_alias_to_datasets +133 | Metadata() | = help: Use `airflow.sdk.definitions.asset.AssetAny` instead -AIR302_names.py:119:1: AIR302 `airflow.datasets.expand_alias_to_datasets` is removed in Airflow 3.0 +AIR302_names.py:132:1: AIR302 `airflow.datasets.expand_alias_to_datasets` is removed in Airflow 3.0 | -117 | DatasetAll -118 | DatasetAny -119 | expand_alias_to_datasets +130 | DatasetAll() +131 | DatasetAny() +132 | expand_alias_to_datasets | ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -120 | Metadata +133 | Metadata() | = help: Use `airflow.sdk.definitions.asset.expand_alias_to_assets` instead -AIR302_names.py:120:1: AIR302 `airflow.datasets.metadata.Metadata` is removed in Airflow 3.0 +AIR302_names.py:133:1: AIR302 `airflow.datasets.metadata.Metadata` is removed in Airflow 3.0 | -118 | DatasetAny -119 | expand_alias_to_datasets -120 | Metadata +131 | DatasetAny() +132 | expand_alias_to_datasets +133 | Metadata() | ^^^^^^^^ AIR302 -121 | -122 | # airflow.datasets.manager +134 | +135 | dataset_to_test_method_call = Dataset() | = help: Use `airflow.sdk.definitions.asset.metadata.Metadata` instead -AIR302_names.py:123:17: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 +AIR302_names.py:135:31: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 | -122 | # airflow.datasets.manager -123 | DatasetManager, dataset_manager, resolve_dataset_manager - | ^^^^^^^^^^^^^^^ AIR302 -124 | -125 | # airflow.lineage.hook +133 | Metadata() +134 | +135 | dataset_to_test_method_call = Dataset() + | ^^^^^^^ AIR302 +136 | dataset_to_test_method_call.iter_datasets() +137 | dataset_to_test_method_call.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.Asset` instead + +AIR302_names.py:136:29: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +135 | dataset_to_test_method_call = Dataset() +136 | dataset_to_test_method_call.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +137 | dataset_to_test_method_call.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:137:29: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +135 | dataset_to_test_method_call = Dataset() +136 | dataset_to_test_method_call.iter_datasets() +137 | dataset_to_test_method_call.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +138 | +139 | alias_to_test_method_call = DatasetAlias() + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:139:29: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 + | +137 | dataset_to_test_method_call.iter_dataset_aliases() +138 | +139 | alias_to_test_method_call = DatasetAlias() + | ^^^^^^^^^^^^ AIR302 +140 | alias_to_test_method_call.iter_datasets() +141 | alias_to_test_method_call.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.AssetAlias` instead + +AIR302_names.py:140:27: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +139 | alias_to_test_method_call = DatasetAlias() +140 | alias_to_test_method_call.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +141 | alias_to_test_method_call.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:141:27: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +139 | alias_to_test_method_call = DatasetAlias() +140 | alias_to_test_method_call.iter_datasets() +141 | alias_to_test_method_call.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +142 | +143 | any_to_test_method_call = DatasetAny() + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:143:27: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 + | +141 | alias_to_test_method_call.iter_dataset_aliases() +142 | +143 | any_to_test_method_call = DatasetAny() + | ^^^^^^^^^^ AIR302 +144 | any_to_test_method_call.iter_datasets() +145 | any_to_test_method_call.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.AssetAny` instead + +AIR302_names.py:144:25: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +143 | any_to_test_method_call = DatasetAny() +144 | any_to_test_method_call.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +145 | any_to_test_method_call.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:145:25: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +143 | any_to_test_method_call = DatasetAny() +144 | any_to_test_method_call.iter_datasets() +145 | any_to_test_method_call.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +146 | +147 | # airflow.datasets.manager + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:148:19: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 + | +147 | # airflow.datasets.manager +148 | DatasetManager(), dataset_manager, resolve_dataset_manager + | ^^^^^^^^^^^^^^^ AIR302 +149 | +150 | # airflow.hooks | = help: Use `airflow.assets.manager` instead -AIR302_names.py:123:34: AIR302 `airflow.datasets.manager.resolve_dataset_manager` is removed in Airflow 3.0 +AIR302_names.py:148:36: AIR302 `airflow.datasets.manager.resolve_dataset_manager` is removed in Airflow 3.0 | -122 | # airflow.datasets.manager -123 | DatasetManager, dataset_manager, resolve_dataset_manager - | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -124 | -125 | # airflow.lineage.hook +147 | # airflow.datasets.manager +148 | DatasetManager(), dataset_manager, resolve_dataset_manager + | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +149 | +150 | # airflow.hooks | = help: Use `airflow.assets.resolve_asset_manager` instead -AIR302_names.py:126:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 +AIR302_names.py:151:1: AIR302 `airflow.hooks.base_hook.BaseHook` is removed in Airflow 3.0 | -125 | # airflow.lineage.hook -126 | DatasetLineageInfo +150 | # airflow.hooks +151 | BaseHook() + | ^^^^^^^^ AIR302 +152 | +153 | # airflow.lineage.hook + | + = help: Use `airflow.hooks.base.BaseHook` instead + +AIR302_names.py:154:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 + | +153 | # airflow.lineage.hook +154 | DatasetLineageInfo() | ^^^^^^^^^^^^^^^^^^ AIR302 -127 | -128 | # airflow.listeners.spec.dataset +155 | +156 | # airflow.listeners.spec.dataset | = help: Use `airflow.lineage.hook.AssetLineageInfo` instead -AIR302_names.py:129:1: AIR302 `airflow.listeners.spec.dataset.on_dataset_changed` is removed in Airflow 3.0 +AIR302_names.py:157:1: AIR302 `airflow.listeners.spec.dataset.on_dataset_changed` is removed in Airflow 3.0 | -128 | # airflow.listeners.spec.dataset -129 | on_dataset_changed, on_dataset_created +156 | # airflow.listeners.spec.dataset +157 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -130 | -131 | # airflow.metrics.validators +158 | +159 | # airflow.metrics.validators | = help: Use `airflow.listeners.spec.asset.on_asset_changed` instead -AIR302_names.py:129:21: AIR302 `airflow.listeners.spec.dataset.on_dataset_created` is removed in Airflow 3.0 +AIR302_names.py:157:21: AIR302 `airflow.listeners.spec.dataset.on_dataset_created` is removed in Airflow 3.0 | -128 | # airflow.listeners.spec.dataset -129 | on_dataset_changed, on_dataset_created +156 | # airflow.listeners.spec.dataset +157 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -130 | -131 | # airflow.metrics.validators +158 | +159 | # airflow.metrics.validators | = help: Use `airflow.listeners.spec.asset.on_asset_created` instead -AIR302_names.py:132:1: AIR302 `airflow.metrics.validators.AllowListValidator` is removed in Airflow 3.0 +AIR302_names.py:160:1: AIR302 `airflow.metrics.validators.AllowListValidator` is removed in Airflow 3.0 | -131 | # airflow.metrics.validators -132 | AllowListValidator, BlockListValidator +159 | # airflow.metrics.validators +160 | AllowListValidator(), BlockListValidator() | ^^^^^^^^^^^^^^^^^^ AIR302 -133 | -134 | # airflow.operators.dummy_operator +161 | +162 | # airflow.operators.dummy_operator | = help: Use `airflow.metrics.validators.PatternAllowListValidator` instead -AIR302_names.py:132:21: AIR302 `airflow.metrics.validators.BlockListValidator` is removed in Airflow 3.0 +AIR302_names.py:160:23: AIR302 `airflow.metrics.validators.BlockListValidator` is removed in Airflow 3.0 | -131 | # airflow.metrics.validators -132 | AllowListValidator, BlockListValidator - | ^^^^^^^^^^^^^^^^^^ AIR302 -133 | -134 | # airflow.operators.dummy_operator +159 | # airflow.metrics.validators +160 | AllowListValidator(), BlockListValidator() + | ^^^^^^^^^^^^^^^^^^ AIR302 +161 | +162 | # airflow.operators.dummy_operator | = help: Use `airflow.metrics.validators.PatternBlockListValidator` instead -AIR302_names.py:135:16: AIR302 `airflow.operators.dummy_operator.EmptyOperator` is removed in Airflow 3.0 +AIR302_names.py:163:16: AIR302 `airflow.operators.dummy_operator.EmptyOperator` is removed in Airflow 3.0 | -134 | # airflow.operators.dummy_operator -135 | dummy_operator.EmptyOperator +162 | # airflow.operators.dummy_operator +163 | dummy_operator.EmptyOperator() | ^^^^^^^^^^^^^ AIR302 -136 | dummy_operator.DummyOperator +164 | dummy_operator.DummyOperator() | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:136:16: AIR302 `airflow.operators.dummy_operator.DummyOperator` is removed in Airflow 3.0 +AIR302_names.py:164:16: AIR302 `airflow.operators.dummy_operator.DummyOperator` is removed in Airflow 3.0 | -134 | # airflow.operators.dummy_operator -135 | dummy_operator.EmptyOperator -136 | dummy_operator.DummyOperator +162 | # airflow.operators.dummy_operator +163 | dummy_operator.EmptyOperator() +164 | dummy_operator.DummyOperator() | ^^^^^^^^^^^^^ AIR302 -137 | -138 | # airflow.operators.bash_operator +165 | +166 | # airflow.operators.bash_operator | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:139:1: AIR302 `airflow.operators.bash_operator.BashOperator` is removed in Airflow 3.0 +AIR302_names.py:167:1: AIR302 `airflow.operators.bash_operator.BashOperator` is removed in Airflow 3.0 | -138 | # airflow.operators.bash_operator -139 | BashOperator +166 | # airflow.operators.bash_operator +167 | BashOperator() | ^^^^^^^^^^^^ AIR302 -140 | -141 | # airflow.operators.branch_operator +168 | +169 | # airflow.operators.branch_operator | = help: Use `airflow.operators.bash.BashOperator` instead -AIR302_names.py:142:1: AIR302 `airflow.operators.branch_operator.BaseBranchOperator` is removed in Airflow 3.0 +AIR302_names.py:170:1: AIR302 `airflow.operators.branch_operator.BaseBranchOperator` is removed in Airflow 3.0 | -141 | # airflow.operators.branch_operator -142 | BaseBranchOperator +169 | # airflow.operators.branch_operator +170 | BaseBranchOperator() | ^^^^^^^^^^^^^^^^^^ AIR302 -143 | -144 | # airflow.operators.dummy +171 | +172 | # airflow.operators.dagrun_operator | = help: Use `airflow.operators.branch.BaseBranchOperator` instead -AIR302_names.py:145:16: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 +AIR302_names.py:173:1: AIR302 `airflow.operators.dagrun_operator.TriggerDagRunLink` is removed in Airflow 3.0 | -144 | # airflow.operators.dummy -145 | EmptyOperator, DummyOperator - | ^^^^^^^^^^^^^ AIR302 -146 | -147 | # airflow.operators.email_operator +172 | # airflow.operators.dagrun_operator +173 | TriggerDagRunLink() + | ^^^^^^^^^^^^^^^^^ AIR302 +174 | TriggerDagRunOperator() + | + = help: Use `airflow.operators.trigger_dagrun.TriggerDagRunLink` instead + +AIR302_names.py:174:1: AIR302 `airflow.operators.dagrun_operator.TriggerDagRunOperator` is removed in Airflow 3.0 + | +172 | # airflow.operators.dagrun_operator +173 | TriggerDagRunLink() +174 | TriggerDagRunOperator() + | ^^^^^^^^^^^^^^^^^^^^^ AIR302 +175 | +176 | # airflow.operators.dummy + | + = help: Use `airflow.operators.trigger_dagrun.TriggerDagRunOperator` instead + +AIR302_names.py:177:18: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 + | +176 | # airflow.operators.dummy +177 | EmptyOperator(), DummyOperator() + | ^^^^^^^^^^^^^ AIR302 +178 | +179 | # airflow.operators.email_operator | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:148:1: AIR302 `airflow.operators.email_operator.EmailOperator` is removed in Airflow 3.0 +AIR302_names.py:180:1: AIR302 `airflow.operators.email_operator.EmailOperator` is removed in Airflow 3.0 | -147 | # airflow.operators.email_operator -148 | EmailOperator +179 | # airflow.operators.email_operator +180 | EmailOperator() | ^^^^^^^^^^^^^ AIR302 -149 | -150 | # airflow.operators.subdag.* +181 | +182 | # airflow.operators.latest_only_operator | = help: Use `airflow.operators.email.EmailOperator` instead -AIR302_names.py:151:1: AIR302 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0; The whole `airflow.subdag` module has been removed. +AIR302_names.py:183:1: AIR302 `airflow.operators.latest_only_operator.LatestOnlyOperator` is removed in Airflow 3.0 | -150 | # airflow.operators.subdag.* -151 | SubDagOperator +182 | # airflow.operators.latest_only_operator +183 | LatestOnlyOperator() + | ^^^^^^^^^^^^^^^^^^ AIR302 +184 | +185 | # airflow.operators.python_operator + | + = help: Use ` airflow.operators.latest_only.LatestOnlyOperator` instead + +AIR302_names.py:186:1: AIR302 `airflow.operators.python_operator.BranchPythonOperator` is removed in Airflow 3.0 + | +185 | # airflow.operators.python_operator +186 | BranchPythonOperator() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +187 | PythonOperator() +188 | PythonVirtualenvOperator() + | + = help: Use `airflow.operators.python.BranchPythonOperator` instead + +AIR302_names.py:187:1: AIR302 `airflow.operators.python_operator.PythonOperator` is removed in Airflow 3.0 + | +185 | # airflow.operators.python_operator +186 | BranchPythonOperator() +187 | PythonOperator() | ^^^^^^^^^^^^^^ AIR302 -152 | -153 | # airflow.providers.amazon +188 | PythonVirtualenvOperator() +189 | ShortCircuitOperator() + | + = help: Use `airflow.operators.python.PythonOperator` instead + +AIR302_names.py:188:1: AIR302 `airflow.operators.python_operator.PythonVirtualenvOperator` is removed in Airflow 3.0 + | +186 | BranchPythonOperator() +187 | PythonOperator() +188 | PythonVirtualenvOperator() + | ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +189 | ShortCircuitOperator() + | + = help: Use `airflow.operators.python.PythonVirtualenvOperator` instead + +AIR302_names.py:189:1: AIR302 `airflow.operators.python_operator.ShortCircuitOperator` is removed in Airflow 3.0 + | +187 | PythonOperator() +188 | PythonVirtualenvOperator() +189 | ShortCircuitOperator() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +190 | +191 | # airflow.operators.subdag.* + | + = help: Use `airflow.operators.python.ShortCircuitOperator` instead + +AIR302_names.py:192:1: AIR302 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0; The whole `airflow.subdag` module has been removed. + | +191 | # airflow.operators.subdag.* +192 | SubDagOperator() + | ^^^^^^^^^^^^^^ AIR302 +193 | +194 | # airflow.providers.amazon | -AIR302_names.py:154:13: AIR302 `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0 +AIR302_names.py:195:13: AIR302 `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0 | -153 | # airflow.providers.amazon -154 | AvpEntities.DATASET +194 | # airflow.providers.amazon +195 | AvpEntities.DATASET | ^^^^^^^ AIR302 -155 | s3.create_dataset -156 | s3.convert_dataset_to_openlineage +196 | s3.create_dataset +197 | s3.convert_dataset_to_openlineage | = help: Use `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.ASSET` instead -AIR302_names.py:155:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.create_dataset` is removed in Airflow 3.0 +AIR302_names.py:196:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.create_dataset` is removed in Airflow 3.0 | -153 | # airflow.providers.amazon -154 | AvpEntities.DATASET -155 | s3.create_dataset +194 | # airflow.providers.amazon +195 | AvpEntities.DATASET +196 | s3.create_dataset | ^^^^^^^^^^^^^^ AIR302 -156 | s3.convert_dataset_to_openlineage -157 | s3.sanitize_uri +197 | s3.convert_dataset_to_openlineage +198 | s3.sanitize_uri | = help: Use `airflow.providers.amazon.aws.assets.s3.create_asset` instead -AIR302_names.py:156:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.convert_dataset_to_openlineage` is removed in Airflow 3.0 +AIR302_names.py:197:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.convert_dataset_to_openlineage` is removed in Airflow 3.0 | -154 | AvpEntities.DATASET -155 | s3.create_dataset -156 | s3.convert_dataset_to_openlineage +195 | AvpEntities.DATASET +196 | s3.create_dataset +197 | s3.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -157 | s3.sanitize_uri +198 | s3.sanitize_uri | = help: Use `airflow.providers.amazon.aws.assets.s3.convert_asset_to_openlineage` instead -AIR302_names.py:157:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:198:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.sanitize_uri` is removed in Airflow 3.0 | -155 | s3.create_dataset -156 | s3.convert_dataset_to_openlineage -157 | s3.sanitize_uri +196 | s3.create_dataset +197 | s3.convert_dataset_to_openlineage +198 | s3.sanitize_uri | ^^^^^^^^^^^^ AIR302 -158 | -159 | # airflow.providers.common.io +199 | +200 | # airflow.providers.common.io | = help: Use `airflow.providers.amazon.aws.assets.s3.sanitize_uri` instead -AIR302_names.py:160:16: AIR302 `airflow.providers.common.io.datasets.file.convert_dataset_to_openlineage` is removed in Airflow 3.0 +AIR302_names.py:201:16: AIR302 `airflow.providers.common.io.datasets.file.convert_dataset_to_openlineage` is removed in Airflow 3.0 | -159 | # airflow.providers.common.io -160 | common_io_file.convert_dataset_to_openlineage +200 | # airflow.providers.common.io +201 | common_io_file.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -161 | common_io_file.create_dataset -162 | common_io_file.sanitize_uri +202 | common_io_file.create_dataset +203 | common_io_file.sanitize_uri | = help: Use `airflow.providers.common.io.assets.file.convert_asset_to_openlineage` instead -AIR302_names.py:161:16: AIR302 `airflow.providers.common.io.datasets.file.create_dataset` is removed in Airflow 3.0 +AIR302_names.py:202:16: AIR302 `airflow.providers.common.io.datasets.file.create_dataset` is removed in Airflow 3.0 | -159 | # airflow.providers.common.io -160 | common_io_file.convert_dataset_to_openlineage -161 | common_io_file.create_dataset +200 | # airflow.providers.common.io +201 | common_io_file.convert_dataset_to_openlineage +202 | common_io_file.create_dataset | ^^^^^^^^^^^^^^ AIR302 -162 | common_io_file.sanitize_uri +203 | common_io_file.sanitize_uri | = help: Use `airflow.providers.common.io.assets.file.create_asset` instead -AIR302_names.py:162:16: AIR302 `airflow.providers.common.io.datasets.file.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:203:16: AIR302 `airflow.providers.common.io.datasets.file.sanitize_uri` is removed in Airflow 3.0 | -160 | common_io_file.convert_dataset_to_openlineage -161 | common_io_file.create_dataset -162 | common_io_file.sanitize_uri +201 | common_io_file.convert_dataset_to_openlineage +202 | common_io_file.create_dataset +203 | common_io_file.sanitize_uri | ^^^^^^^^^^^^ AIR302 -163 | -164 | # airflow.providers.fab +204 | +205 | # airflow.providers.fab | = help: Use `airflow.providers.common.io.assets.file.sanitize_uri` instead -AIR302_names.py:165:18: AIR302 `airflow.providers.fab.auth_manager.fab_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 +AIR302_names.py:206:18: AIR302 `airflow.providers.fab.auth_manager.fab_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 | -164 | # airflow.providers.fab -165 | fab_auth_manager.is_authorized_dataset +205 | # airflow.providers.fab +206 | fab_auth_manager.is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -166 | -167 | # airflow.providers.google +207 | +208 | # airflow.providers.google | = help: Use `airflow.providers.fab.auth_manager.fab_auth_manager.is_authorized_asset` instead -AIR302_names.py:170:5: AIR302 `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0 +AIR302_names.py:211:5: AIR302 `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0 | -168 | bigquery.sanitize_uri -169 | -170 | gcs.create_dataset +209 | bigquery.sanitize_uri +210 | +211 | gcs.create_dataset | ^^^^^^^^^^^^^^ AIR302 -171 | gcs.sanitize_uri -172 | gcs.convert_dataset_to_openlineage +212 | gcs.sanitize_uri +213 | gcs.convert_dataset_to_openlineage | = help: Use `airflow.providers.google.assets.gcs.create_asset` instead -AIR302_names.py:171:5: AIR302 `airflow.providers.google.datasets.gcs.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:212:5: AIR302 `airflow.providers.google.datasets.gcs.sanitize_uri` is removed in Airflow 3.0 | -170 | gcs.create_dataset -171 | gcs.sanitize_uri +211 | gcs.create_dataset +212 | gcs.sanitize_uri | ^^^^^^^^^^^^ AIR302 -172 | gcs.convert_dataset_to_openlineage +213 | gcs.convert_dataset_to_openlineage | = help: Use `airflow.providers.google.assets.gcs.sanitize_uri` instead -AIR302_names.py:172:5: AIR302 `airflow.providers.google.datasets.gcs.convert_dataset_to_openlineage` is removed in Airflow 3.0 +AIR302_names.py:213:5: AIR302 `airflow.providers.google.datasets.gcs.convert_dataset_to_openlineage` is removed in Airflow 3.0 | -170 | gcs.create_dataset -171 | gcs.sanitize_uri -172 | gcs.convert_dataset_to_openlineage +211 | gcs.create_dataset +212 | gcs.sanitize_uri +213 | gcs.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -173 | -174 | # airflow.providers.mysql +214 | +215 | # airflow.providers.mysql | = help: Use `airflow.providers.google.assets.gcs.convert_asset_to_openlineage` instead -AIR302_names.py:175:7: AIR302 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:216:7: AIR302 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0 | -174 | # airflow.providers.mysql -175 | mysql.sanitize_uri +215 | # airflow.providers.mysql +216 | mysql.sanitize_uri | ^^^^^^^^^^^^ AIR302 -176 | -177 | # airflow.providers.openlineage +217 | +218 | # airflow.providers.openlineage | = help: Use `airflow.providers.mysql.assets.mysql.sanitize_uri` instead -AIR302_names.py:178:1: AIR302 `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0 +AIR302_names.py:219:1: AIR302 `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0 | -177 | # airflow.providers.openlineage -178 | DatasetInfo, translate_airflow_dataset +218 | # airflow.providers.openlineage +219 | DatasetInfo(), translate_airflow_dataset | ^^^^^^^^^^^ AIR302 -179 | -180 | # airflow.providers.postgres +220 | +221 | # airflow.providers.postgres | = help: Use `airflow.providers.openlineage.utils.utils.AssetInfo` instead -AIR302_names.py:178:14: AIR302 `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0 +AIR302_names.py:219:16: AIR302 `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0 | -177 | # airflow.providers.openlineage -178 | DatasetInfo, translate_airflow_dataset - | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -179 | -180 | # airflow.providers.postgres +218 | # airflow.providers.openlineage +219 | DatasetInfo(), translate_airflow_dataset + | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +220 | +221 | # airflow.providers.postgres | = help: Use `airflow.providers.openlineage.utils.utils.translate_airflow_asset` instead -AIR302_names.py:181:10: AIR302 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:222:10: AIR302 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0 | -180 | # airflow.providers.postgres -181 | postgres.sanitize_uri +221 | # airflow.providers.postgres +222 | postgres.sanitize_uri | ^^^^^^^^^^^^ AIR302 -182 | -183 | # airflow.providers.trino +223 | +224 | # airflow.providers.trino | = help: Use `airflow.providers.postgres.assets.postgres.sanitize_uri` instead -AIR302_names.py:184:7: AIR302 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:225:7: AIR302 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0 | -183 | # airflow.providers.trino -184 | trino.sanitize_uri +224 | # airflow.providers.trino +225 | trino.sanitize_uri | ^^^^^^^^^^^^ AIR302 -185 | -186 | # airflow.secrets +226 | +227 | # airflow.secrets | = help: Use `airflow.providers.trino.assets.trino.sanitize_uri` instead -AIR302_names.py:187:1: AIR302 `airflow.secrets.local_filesystem.get_connection` is removed in Airflow 3.0 +AIR302_names.py:228:1: AIR302 `airflow.secrets.local_filesystem.get_connection` is removed in Airflow 3.0 | -186 | # airflow.secrets -187 | get_connection, load_connections +227 | # airflow.secrets +228 | get_connection, load_connections | ^^^^^^^^^^^^^^ AIR302 -188 | -189 | # airflow.security.permissions +229 | +230 | # airflow.security.permissions | = help: Use `airflow.secrets.local_filesystem.load_connections_dict` instead -AIR302_names.py:187:17: AIR302 `airflow.secrets.local_filesystem.load_connections` is removed in Airflow 3.0 +AIR302_names.py:228:17: AIR302 `airflow.secrets.local_filesystem.load_connections` is removed in Airflow 3.0 | -186 | # airflow.secrets -187 | get_connection, load_connections +227 | # airflow.secrets +228 | get_connection, load_connections | ^^^^^^^^^^^^^^^^ AIR302 -188 | -189 | # airflow.security.permissions +229 | +230 | # airflow.security.permissions | = help: Use `airflow.secrets.local_filesystem.load_connections_dict` instead -AIR302_names.py:190:1: AIR302 `airflow.security.permissions.RESOURCE_DATASET` is removed in Airflow 3.0 +AIR302_names.py:231:1: AIR302 `airflow.security.permissions.RESOURCE_DATASET` is removed in Airflow 3.0 | -189 | # airflow.security.permissions -190 | RESOURCE_DATASET +230 | # airflow.security.permissions +231 | RESOURCE_DATASET | ^^^^^^^^^^^^^^^^ AIR302 -191 | -192 | # airflow.sensors.base_sensor_operator +232 | +233 | # airflow.sensors.base_sensor_operator | = help: Use `airflow.security.permissions.RESOURCE_ASSET` instead -AIR302_names.py:193:1: AIR302 `airflow.sensors.base_sensor_operator.BaseSensorOperator` is removed in Airflow 3.0 +AIR302_names.py:234:1: AIR302 `airflow.sensors.base_sensor_operator.BaseSensorOperator` is removed in Airflow 3.0 | -192 | # airflow.sensors.base_sensor_operator -193 | BaseSensorOperator +233 | # airflow.sensors.base_sensor_operator +234 | BaseSensorOperator() | ^^^^^^^^^^^^^^^^^^ AIR302 -194 | -195 | # airflow.sensors.date_time_sensor +235 | +236 | # airflow.sensors.date_time_sensor | = help: Use `airflow.sensors.base.BaseSensorOperator` instead -AIR302_names.py:196:1: AIR302 `airflow.sensors.date_time_sensor.DateTimeSensor` is removed in Airflow 3.0 +AIR302_names.py:237:1: AIR302 `airflow.sensors.date_time_sensor.DateTimeSensor` is removed in Airflow 3.0 | -195 | # airflow.sensors.date_time_sensor -196 | DateTimeSensor +236 | # airflow.sensors.date_time_sensor +237 | DateTimeSensor() | ^^^^^^^^^^^^^^ AIR302 -197 | -198 | # airflow.sensors.external_task +238 | +239 | # airflow.sensors.external_task | = help: Use `airflow.sensors.date_time.DateTimeSensor` instead -AIR302_names.py:199:1: AIR302 `airflow.sensors.external_task.ExternalTaskSensorLink` is removed in Airflow 3.0 +AIR302_names.py:240:1: AIR302 `airflow.sensors.external_task.ExternalTaskSensorLink` is removed in Airflow 3.0 | -198 | # airflow.sensors.external_task -199 | ExternalTaskSensorLinkFromExternalTask +239 | # airflow.sensors.external_task +240 | ExternalTaskSensorLinkFromExternalTask() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -200 | -201 | # airflow.sensors.external_task_sensor +241 | +242 | # airflow.sensors.external_task_sensor | = help: Use `airflow.sensors.external_task.ExternalDagLink` instead -AIR302_names.py:202:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskMarker` is removed in Airflow 3.0 +AIR302_names.py:243:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskMarker` is removed in Airflow 3.0 | -201 | # airflow.sensors.external_task_sensor -202 | ExternalTaskMarker +242 | # airflow.sensors.external_task_sensor +243 | ExternalTaskMarker() | ^^^^^^^^^^^^^^^^^^ AIR302 -203 | ExternalTaskSensor -204 | ExternalTaskSensorLinkFromExternalTaskSensor +244 | ExternalTaskSensor() +245 | ExternalTaskSensorLinkFromExternalTaskSensor() | = help: Use `airflow.sensors.external_task.ExternalTaskMarker` instead -AIR302_names.py:203:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensor` is removed in Airflow 3.0 +AIR302_names.py:244:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensor` is removed in Airflow 3.0 | -201 | # airflow.sensors.external_task_sensor -202 | ExternalTaskMarker -203 | ExternalTaskSensor +242 | # airflow.sensors.external_task_sensor +243 | ExternalTaskMarker() +244 | ExternalTaskSensor() | ^^^^^^^^^^^^^^^^^^ AIR302 -204 | ExternalTaskSensorLinkFromExternalTaskSensor +245 | ExternalTaskSensorLinkFromExternalTaskSensor() | = help: Use `airflow.sensors.external_task.ExternalTaskSensor` instead -AIR302_names.py:204:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensorLink` is removed in Airflow 3.0 +AIR302_names.py:245:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensorLink` is removed in Airflow 3.0 | -202 | ExternalTaskMarker -203 | ExternalTaskSensor -204 | ExternalTaskSensorLinkFromExternalTaskSensor +243 | ExternalTaskMarker() +244 | ExternalTaskSensor() +245 | ExternalTaskSensorLinkFromExternalTaskSensor() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -205 | -206 | # airflow.sensors.time_delta_sensor +246 | +247 | # airflow.sensors.time_delta_sensor | = help: Use `airflow.sensors.external_task.ExternalDagLink` instead -AIR302_names.py:207:1: AIR302 `airflow.sensors.time_delta_sensor.TimeDeltaSensor` is removed in Airflow 3.0 +AIR302_names.py:248:1: AIR302 `airflow.sensors.time_delta_sensor.TimeDeltaSensor` is removed in Airflow 3.0 | -206 | # airflow.sensors.time_delta_sensor -207 | TimeDeltaSensor +247 | # airflow.sensors.time_delta_sensor +248 | TimeDeltaSensor() | ^^^^^^^^^^^^^^^ AIR302 -208 | -209 | # airflow.timetables +249 | +250 | # airflow.timetables | = help: Use `airflow.sensors.time_delta.TimeDeltaSensor` instead -AIR302_names.py:210:1: AIR302 `airflow.timetables.datasets.DatasetOrTimeSchedule` is removed in Airflow 3.0 +AIR302_names.py:251:1: AIR302 `airflow.timetables.datasets.DatasetOrTimeSchedule` is removed in Airflow 3.0 | -209 | # airflow.timetables -210 | DatasetOrTimeSchedule +250 | # airflow.timetables +251 | DatasetOrTimeSchedule() | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -211 | DatasetTriggeredTimetable +252 | DatasetTriggeredTimetable() | = help: Use `airflow.timetables.assets.AssetOrTimeSchedule` instead -AIR302_names.py:211:1: AIR302 `airflow.timetables.simple.DatasetTriggeredTimetable` is removed in Airflow 3.0 +AIR302_names.py:252:1: AIR302 `airflow.timetables.simple.DatasetTriggeredTimetable` is removed in Airflow 3.0 | -209 | # airflow.timetables -210 | DatasetOrTimeSchedule -211 | DatasetTriggeredTimetable +250 | # airflow.timetables +251 | DatasetOrTimeSchedule() +252 | DatasetTriggeredTimetable() | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -212 | -213 | # airflow.triggers.external_task +253 | +254 | # airflow.triggers.external_task | = help: Use `airflow.timetables.simple.AssetTriggeredTimetable` instead -AIR302_names.py:214:1: AIR302 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 +AIR302_names.py:255:1: AIR302 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 | -213 | # airflow.triggers.external_task -214 | TaskStateTrigger +254 | # airflow.triggers.external_task +255 | TaskStateTrigger() | ^^^^^^^^^^^^^^^^ AIR302 -215 | -216 | # airflow.utils.date +256 | +257 | # airflow.utils.date | -AIR302_names.py:217:7: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 +AIR302_names.py:258:7: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 | -216 | # airflow.utils.date -217 | dates.date_range +257 | # airflow.utils.date +258 | dates.date_range | ^^^^^^^^^^ AIR302 -218 | dates.days_ago +259 | dates.days_ago | = help: Use `airflow.timetables.` instead -AIR302_names.py:218:7: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 +AIR302_names.py:259:7: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 | -216 | # airflow.utils.date -217 | dates.date_range -218 | dates.days_ago +257 | # airflow.utils.date +258 | dates.date_range +259 | dates.days_ago | ^^^^^^^^ AIR302 -219 | -220 | date_range +260 | +261 | date_range | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:220:1: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 +AIR302_names.py:261:1: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 | -218 | dates.days_ago -219 | -220 | date_range +259 | dates.days_ago +260 | +261 | date_range | ^^^^^^^^^^ AIR302 -221 | days_ago -222 | infer_time_unit +262 | days_ago +263 | infer_time_unit | = help: Use `airflow.timetables.` instead -AIR302_names.py:221:1: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 +AIR302_names.py:262:1: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 | -220 | date_range -221 | days_ago +261 | date_range +262 | days_ago | ^^^^^^^^ AIR302 -222 | infer_time_unit -223 | parse_execution_date +263 | infer_time_unit +264 | parse_execution_date | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:222:1: AIR302 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 +AIR302_names.py:263:1: AIR302 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 | -220 | date_range -221 | days_ago -222 | infer_time_unit +261 | date_range +262 | days_ago +263 | infer_time_unit | ^^^^^^^^^^^^^^^ AIR302 -223 | parse_execution_date -224 | round_time +264 | parse_execution_date +265 | round_time | -AIR302_names.py:223:1: AIR302 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 +AIR302_names.py:264:1: AIR302 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 | -221 | days_ago -222 | infer_time_unit -223 | parse_execution_date +262 | days_ago +263 | infer_time_unit +264 | parse_execution_date | ^^^^^^^^^^^^^^^^^^^^ AIR302 -224 | round_time -225 | scale_time_units +265 | round_time +266 | scale_time_units | -AIR302_names.py:224:1: AIR302 `airflow.utils.dates.round_time` is removed in Airflow 3.0 +AIR302_names.py:265:1: AIR302 `airflow.utils.dates.round_time` is removed in Airflow 3.0 | -222 | infer_time_unit -223 | parse_execution_date -224 | round_time +263 | infer_time_unit +264 | parse_execution_date +265 | round_time | ^^^^^^^^^^ AIR302 -225 | scale_time_units +266 | scale_time_units | -AIR302_names.py:225:1: AIR302 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 +AIR302_names.py:266:1: AIR302 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 | -223 | parse_execution_date -224 | round_time -225 | scale_time_units +264 | parse_execution_date +265 | round_time +266 | scale_time_units | ^^^^^^^^^^^^^^^^ AIR302 -226 | -227 | # This one was not deprecated. +267 | +268 | # This one was not deprecated. | -AIR302_names.py:232:1: AIR302 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 +AIR302_names.py:273:1: AIR302 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 | -231 | # airflow.utils.dag_cycle_tester -232 | test_cycle +272 | # airflow.utils.dag_cycle_tester +273 | test_cycle | ^^^^^^^^^^ AIR302 -233 | -234 | # airflow.utils.decorators +274 | +275 | # airflow.utils.decorators | -AIR302_names.py:235:1: AIR302 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0; `apply_defaults` is now unconditionally done and can be safely removed. +AIR302_names.py:276:1: AIR302 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0; `apply_defaults` is now unconditionally done and can be safely removed. | -234 | # airflow.utils.decorators -235 | apply_defaults +275 | # airflow.utils.decorators +276 | apply_defaults | ^^^^^^^^^^^^^^ AIR302 -236 | -237 | # airflow.utils.file +277 | +278 | # airflow.utils.file | -AIR302_names.py:238:1: AIR302 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0 +AIR302_names.py:279:22: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 | -237 | # airflow.utils.file -238 | TemporaryDirectory, mkdirs - | ^^^^^^^^^^^^^^^^^^ AIR302 -239 | -240 | # airflow.utils.helpers - | - -AIR302_names.py:238:21: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 - | -237 | # airflow.utils.file -238 | TemporaryDirectory, mkdirs - | ^^^^^^ AIR302 -239 | -240 | # airflow.utils.helpers +278 | # airflow.utils.file +279 | TemporaryDirector(), mkdirs + | ^^^^^^ AIR302 +280 | +281 | # airflow.utils.helpers | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:241:1: AIR302 `airflow.utils.helpers.chain` is removed in Airflow 3.0 +AIR302_names.py:282:1: AIR302 `airflow.utils.helpers.chain` is removed in Airflow 3.0 | -240 | # airflow.utils.helpers -241 | chain, cross_downstream +281 | # airflow.utils.helpers +282 | chain, cross_downstream | ^^^^^ AIR302 -242 | -243 | # airflow.utils.state +283 | +284 | # airflow.utils.state | = help: Use `airflow.models.baseoperator.chain` instead -AIR302_names.py:241:8: AIR302 `airflow.utils.helpers.cross_downstream` is removed in Airflow 3.0 +AIR302_names.py:282:8: AIR302 `airflow.utils.helpers.cross_downstream` is removed in Airflow 3.0 | -240 | # airflow.utils.helpers -241 | chain, cross_downstream +281 | # airflow.utils.helpers +282 | chain, cross_downstream | ^^^^^^^^^^^^^^^^ AIR302 -242 | -243 | # airflow.utils.state +283 | +284 | # airflow.utils.state | = help: Use `airflow.models.baseoperator.cross_downstream` instead -AIR302_names.py:244:1: AIR302 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 +AIR302_names.py:285:1: AIR302 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 | -243 | # airflow.utils.state -244 | SHUTDOWN, terminating_states +284 | # airflow.utils.state +285 | SHUTDOWN, terminating_states | ^^^^^^^^ AIR302 -245 | -246 | # airflow.utils.trigger_rule +286 | +287 | # airflow.utils.trigger_rule | -AIR302_names.py:244:11: AIR302 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 +AIR302_names.py:285:11: AIR302 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 | -243 | # airflow.utils.state -244 | SHUTDOWN, terminating_states +284 | # airflow.utils.state +285 | SHUTDOWN, terminating_states | ^^^^^^^^^^^^^^^^^^ AIR302 -245 | -246 | # airflow.utils.trigger_rule +286 | +287 | # airflow.utils.trigger_rule | -AIR302_names.py:247:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 +AIR302_names.py:288:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 | -246 | # airflow.utils.trigger_rule -247 | TriggerRule.DUMMY +287 | # airflow.utils.trigger_rule +288 | TriggerRule.DUMMY | ^^^^^ AIR302 -248 | TriggerRule.NONE_FAILED_OR_SKIPPED +289 | TriggerRule.NONE_FAILED_OR_SKIPPED | -AIR302_names.py:248:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0 +AIR302_names.py:289:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0 | -246 | # airflow.utils.trigger_rule -247 | TriggerRule.DUMMY -248 | TriggerRule.NONE_FAILED_OR_SKIPPED +287 | # airflow.utils.trigger_rule +288 | TriggerRule.DUMMY +289 | TriggerRule.NONE_FAILED_OR_SKIPPED | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -249 | -250 | # airflow.www.auth +290 | +291 | # airflow.www.auth | -AIR302_names.py:251:1: AIR302 `airflow.www.auth.has_access` is removed in Airflow 3.0 +AIR302_names.py:292:1: AIR302 `airflow.www.auth.has_access` is removed in Airflow 3.0 | -250 | # airflow.www.auth -251 | has_access +291 | # airflow.www.auth +292 | has_access | ^^^^^^^^^^ AIR302 -252 | has_access_dataset +293 | has_access_dataset | = help: Use `airflow.www.auth.has_access_*` instead -AIR302_names.py:252:1: AIR302 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0 +AIR302_names.py:293:1: AIR302 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0 | -250 | # airflow.www.auth -251 | has_access -252 | has_access_dataset +291 | # airflow.www.auth +292 | has_access +293 | has_access_dataset | ^^^^^^^^^^^^^^^^^^ AIR302 -253 | -254 | # airflow.www.utils +294 | +295 | # airflow.www.utils | = help: Use `airflow.www.auth.has_access_dataset.has_access_asset` instead -AIR302_names.py:255:1: AIR302 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0 +AIR302_names.py:296:1: AIR302 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0 | -254 | # airflow.www.utils -255 | get_sensitive_variables_fields, should_hide_value_for_key +295 | # airflow.www.utils +296 | get_sensitive_variables_fields, should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -256 | -257 | from airflow.datasets.manager import DatasetManager | = help: Use `airflow.utils.log.secrets_masker.get_sensitive_variables_fields` instead -AIR302_names.py:255:33: AIR302 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0 +AIR302_names.py:296:33: AIR302 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0 | -254 | # airflow.www.utils -255 | get_sensitive_variables_fields, should_hide_value_for_key +295 | # airflow.www.utils +296 | get_sensitive_variables_fields, should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -256 | -257 | from airflow.datasets.manager import DatasetManager | = help: Use `airflow.utils.log.secrets_masker.should_hide_value_for_key` instead - -AIR302_names.py:260:4: AIR302 `register_dataset_change` is removed in Airflow 3.0 - | -259 | dm = DatasetManager() -260 | dm.register_dataset_change() - | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -261 | dm.create_datasets() -262 | dm.notify_dataset_created() - | - = help: Use `register_asset_change` instead - -AIR302_names.py:261:4: AIR302 `create_datasets` is removed in Airflow 3.0 - | -259 | dm = DatasetManager() -260 | dm.register_dataset_change() -261 | dm.create_datasets() - | ^^^^^^^^^^^^^^^ AIR302 -262 | dm.notify_dataset_created() -263 | dm.notify_dataset_changed() - | - = help: Use `create_assets` instead - -AIR302_names.py:262:4: AIR302 `notify_dataset_created` is removed in Airflow 3.0 - | -260 | dm.register_dataset_change() -261 | dm.create_datasets() -262 | dm.notify_dataset_created() - | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -263 | dm.notify_dataset_changed() -264 | dm.notify_dataset_alias_created() - | - = help: Use `notify_asset_created` instead - -AIR302_names.py:263:4: AIR302 `notify_dataset_changed` is removed in Airflow 3.0 - | -261 | dm.create_datasets() -262 | dm.notify_dataset_created() -263 | dm.notify_dataset_changed() - | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -264 | dm.notify_dataset_alias_created() - | - = help: Use `notify_asset_changed` instead - -AIR302_names.py:264:4: AIR302 `notify_dataset_alias_created` is removed in Airflow 3.0 - | -262 | dm.notify_dataset_created() -263 | dm.notify_dataset_changed() -264 | dm.notify_dataset_alias_created() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 - | - = help: Use `notify_asset_alias_created` instead - -AIR302_names.py:270:5: AIR302 `create_dataset` is removed in Airflow 3.0 - | -269 | hlc = HookLineageCollector() -270 | hlc.create_dataset() - | ^^^^^^^^^^^^^^ AIR302 -271 | hlc.add_input_dataset() -272 | hlc.add_output_dataset() - | - = help: Use `create_asset` instead - -AIR302_names.py:271:5: AIR302 `add_input_dataset` is removed in Airflow 3.0 - | -269 | hlc = HookLineageCollector() -270 | hlc.create_dataset() -271 | hlc.add_input_dataset() - | ^^^^^^^^^^^^^^^^^ AIR302 -272 | hlc.add_output_dataset() -273 | hlc.collected_datasets() - | - = help: Use `add_input_asset` instead - -AIR302_names.py:272:5: AIR302 `add_output_dataset` is removed in Airflow 3.0 - | -270 | hlc.create_dataset() -271 | hlc.add_input_dataset() -272 | hlc.add_output_dataset() - | ^^^^^^^^^^^^^^^^^^ AIR302 -273 | hlc.collected_datasets() - | - = help: Use `add_output_asset` instead - -AIR302_names.py:273:5: AIR302 `collected_datasets` is removed in Airflow 3.0 - | -271 | hlc.add_input_dataset() -272 | hlc.add_output_dataset() -273 | hlc.collected_datasets() - | ^^^^^^^^^^^^^^^^^^ AIR302 - | - = help: Use `collected_assets` instead - -AIR302_names.py:279:5: AIR302 `is_authorized_dataset` is removed in Airflow 3.0 - | -278 | aam = AwsAuthManager() -279 | aam.is_authorized_dataset() - | ^^^^^^^^^^^^^^^^^^^^^ AIR302 - | - = help: Use `is_authorized_asset` instead