From 253c274afac077063c48ffddbedbcdb1a4dc2a1a Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 31 Dec 2024 13:19:18 +0900 Subject: [PATCH] [`airflow`] Extend rule to check class attributes, methods, arguments (`AIR302`) (#15083) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Airflow 3.0 removes various deprecated functions, members, modules, and other values. They have been deprecated in 2.x, but the removal causes incompatibilities that we want to detect. This PR add rules for the following. * Removed class attribute * `airflow.providers_manager.ProvidersManager.dataset_factories` → `airflow.providers_manager.ProvidersManager.asset_factories` * `airflow.providers_manager.ProvidersManager.dataset_uri_handlers` → `airflow.providers_manager.ProvidersManager.asset_uri_handlers` * `airflow.providers_manager.ProvidersManager.dataset_to_openlineage_converters` → `airflow.providers_manager.ProvidersManager.asset_to_openlineage_converters` * `airflow.lineage.hook.DatasetLineageInfo.dataset` → `airflow.lineage.hook.AssetLineageInfo.asset` * Removed class method (subclasses in airflow should also checked) * `airflow.secrets.base_secrets.BaseSecretsBackend.get_conn_uri` → `airflow.secrets.base_secrets.BaseSecretsBackend.get_conn_value` * `airflow.secrets.base_secrets.BaseSecretsBackend.get_connections` → `airflow.secrets.base_secrets.BaseSecretsBackend.get_connection` * `airflow.hooks.base.BaseHook.get_connections` → use `get_connection` * `airflow.datasets.BaseDataset.iter_datasets` → `airflow.sdk.definitions.asset.BaseAsset.iter_assets` * `airflow.datasets.BaseDataset.iter_dataset_aliases` → `airflow.sdk.definitions.asset.BaseAsset.iter_asset_aliases` * Removed constructor args (subclasses in airflow should also checked) * argument `filename_template` in`airflow.utils.log.file_task_handler.FileTaskHandler` * in `BaseOperator` * `sla` * `task_concurrency` → `max_active_tis_per_dag` * in `BaseAuthManager` * `appbuilder` * Removed class variable (subclasses anywhere should be checked) * in `airflow.plugins_manager.AirflowPlugin` * `executors` (from #43289) * `hooks` * `operators` * `sensors` * Replaced names * `airflow.hooks.base_hook.BaseHook` → `airflow.hooks.base.BaseHook` * `airflow.operators.dagrun_operator.TriggerDagRunLink` → `airflow.operators.trigger_dagrun.TriggerDagRunLink` * `airflow.operators.dagrun_operator.TriggerDagRunOperator` → `airflow.operators.trigger_dagrun.TriggerDagRunOperator` * `airflow.operators.python_operator.BranchPythonOperator` → `airflow.operators.python.BranchPythonOperator` * `airflow.operators.python_operator.PythonOperator` → `airflow.operators.python.PythonOperator` * `airflow.operators.python_operator.PythonVirtualenvOperator` → `airflow.operators.python.PythonVirtualenvOperator` * `airflow.operators.python_operator.ShortCircuitOperator` → `airflow.operators.python.ShortCircuitOperator` * `airflow.operators.latest_only_operator.LatestOnlyOperator` → `airflow.operators.latest_only.LatestOnlyOperator` In additional to the changes above, this PR also add utility functions and improve docstring. ## Test Plan A test fixture is included in the PR. --- .../fixtures/airflow/AIR302_airflow_plugin.py | 29 + .../test/fixtures/airflow/AIR302_args.py | 34 +- .../airflow/AIR302_class_attribute.py | 59 + .../test/fixtures/airflow/AIR302_names.py | 138 +- .../src/checkers/ast/analyze/expression.rs | 3 + crates/ruff_linter/src/rules/airflow/mod.rs | 2 + .../src/rules/airflow/rules/removal_in_3.rs | 471 ++++-- ...ests__AIR302_AIR302_airflow_plugin.py.snap | 43 + ...airflow__tests__AIR302_AIR302_args.py.snap | 310 ++-- ...sts__AIR302_AIR302_class_attribute.py.snap | 228 +++ ...irflow__tests__AIR302_AIR302_names.py.snap | 1306 +++++++++-------- 11 files changed, 1741 insertions(+), 882 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/airflow/AIR302_airflow_plugin.py create mode 100644 crates/ruff_linter/resources/test/fixtures/airflow/AIR302_class_attribute.py create mode 100644 crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_airflow_plugin.py.snap create mode 100644 crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_class_attribute.py.snap 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