From e292b7b27775e785e10ecf7d75c5d9fb34e7ff1d Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 20 Dec 2024 20:45:58 +0900 Subject: [PATCH 01/12] feat(AIR302): extend the following rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any class in Airflow that inherits these class should not have these methods * `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` --- .../test/fixtures/airflow/AIR302_names.py | 42 +- .../src/rules/airflow/rules/removal_in_3.rs | 22 + ...irflow__tests__AIR302_AIR302_names.py.snap | 1128 ++++++++++------- 3 files changed, 717 insertions(+), 475 deletions(-) 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 e3b4939d9a677..bbf87a3054eb2 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py @@ -96,6 +96,10 @@ PY36, PY37, PY38, PY39, PY310, PY311, PY312 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 @@ -119,6 +123,18 @@ expand_alias_to_datasets 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 @@ -254,6 +270,9 @@ # airflow.www.utils get_sensitive_variables_fields, should_hide_value_for_key + +# methods + from airflow.datasets.manager import DatasetManager dm = DatasetManager() @@ -272,15 +291,34 @@ 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 + + +from airflow.secrets.base_secrets import BaseSecretsBackend + +base_secret_backend = BaseSecretsBackend() +base_secret_backend.get_conn_uri() +base_secret_backend.get_connections() + +from airflow.providers.google.cloud.secrets.secret_manager import ( + CloudSecretManagerBackend, +) + +csm_backend = CloudSecretManagerBackend() +csm_backend.get_conn_uri() +csm_backend.get_connections() + +from airflow.providers.hashicorp.secrets.vault import VaultBackend + +vault_backend = VaultBackend() +vault_backend.get_conn_uri() +vault_backend.get_connections() 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 1374d0cb65da1..d6619a2fef69a 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 @@ -4,8 +4,16 @@ use ruff_python_ast::{name::QualifiedName, Arguments, Expr, ExprAttribute, ExprC use ruff_python_semantic::analyze::typing; use ruff_python_semantic::Modules; use ruff_text_size::Ranged; +use std::sync::LazyLock; use crate::checkers::ast::Checker; +use regex::Regex; + +static SECRET_BACKEND_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"airflow\..*secrets\.\w+\.\w+Backend").unwrap()); + +static AIRFLOW_HOOK_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"airflow\..*hooks\.\w+\.\w+Hook").unwrap()); #[derive(Debug, Eq, PartialEq)] enum Replacement { @@ -196,6 +204,20 @@ fn removed_method(checker: &mut Checker, expr: &Expr) { )), &_ => 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 SECRET_BACKEND_REGEX.is_match(&qualname.segments().join(".")) => match attr.as_str() { + "get_conn_uri" => Some(Replacement::Name("get_conn_value")), + "get_connections" => Some(Replacement::Name("get_connection")), + &_ => None, + }, + _ if AIRFLOW_HOOK_REGEX.is_match(&qualname.segments().join(".")) => match attr.as_str() { + "get_connections" => Some(Replacement::Name("get_connection")), + &_ => None, + }, _ => None, }; if let Some(replacement) = replacement { 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 2400af6ed7e22..079489d488179 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 @@ -72,938 +72,1120 @@ AIR302_names.py:97:1: AIR302 `airflow.Dataset` is removed in Airflow 3.0 97 | DatasetFromRoot | ^^^^^^^^^^^^^^^ AIR302 98 | -99 | # airflow.api_connexion.security +99 | dataset_from_root = DatasetFromRoot() | = 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:99:21: AIR302 `airflow.Dataset` is removed in Airflow 3.0 | - 99 | # airflow.api_connexion.security -100 | requires_access, requires_access_dataset + 97 | DatasetFromRoot + 98 | + 99 | dataset_from_root = DatasetFromRoot() + | ^^^^^^^^^^^^^^^ AIR302 +100 | dataset_from_root.iter_datasets() +101 | dataset_from_root.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.Asset` instead + +AIR302_names.py:100:19: AIR302 `iter_datasets` is removed in Airflow 3.0 + | + 99 | dataset_from_root = DatasetFromRoot() +100 | dataset_from_root.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +101 | dataset_from_root.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:101:19: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | + 99 | dataset_from_root = DatasetFromRoot() +100 | dataset_from_root.iter_datasets() +101 | dataset_from_root.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +102 | +103 | # airflow.api_connexion.security + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:104:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 + | +103 | # airflow.api_connexion.security +104 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^ AIR302 -101 | -102 | # airflow.auth.managers +105 | +106 | # 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:104: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 +103 | # airflow.api_connexion.security +104 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -101 | -102 | # airflow.auth.managers +105 | +106 | # 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:107: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 +106 | # airflow.auth.managers +107 | is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -104 | DatasetDetails +108 | 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:108: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 +106 | # airflow.auth.managers +107 | is_authorized_dataset +108 | DatasetDetails | ^^^^^^^^^^^^^^ AIR302 -105 | -106 | # airflow.configuration +109 | +110 | # 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:111: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 +110 | # airflow.configuration +111 | 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:115: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 +114 | # airflow.contrib.* +115 | AWSAthenaHook | ^^^^^^^^^^^^^ AIR302 -112 | -113 | # airflow.datasets +116 | +117 | # airflow.datasets | -AIR302_names.py:114:1: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 +AIR302_names.py:118:1: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 | -113 | # airflow.datasets -114 | Dataset +117 | # airflow.datasets +118 | Dataset | ^^^^^^^ AIR302 -115 | DatasetAlias -116 | DatasetAliasEvent +119 | DatasetAlias +120 | 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:119:1: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 | -113 | # airflow.datasets -114 | Dataset -115 | DatasetAlias +117 | # airflow.datasets +118 | Dataset +119 | DatasetAlias | ^^^^^^^^^^^^ AIR302 -116 | DatasetAliasEvent -117 | DatasetAll +120 | DatasetAliasEvent +121 | 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:120:1: AIR302 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 | -114 | Dataset -115 | DatasetAlias -116 | DatasetAliasEvent +118 | Dataset +119 | DatasetAlias +120 | DatasetAliasEvent | ^^^^^^^^^^^^^^^^^ AIR302 -117 | DatasetAll -118 | DatasetAny +121 | DatasetAll +122 | DatasetAny | -AIR302_names.py:117:1: AIR302 `airflow.datasets.DatasetAll` is removed in Airflow 3.0 +AIR302_names.py:121:1: AIR302 `airflow.datasets.DatasetAll` is removed in Airflow 3.0 | -115 | DatasetAlias -116 | DatasetAliasEvent -117 | DatasetAll +119 | DatasetAlias +120 | DatasetAliasEvent +121 | DatasetAll | ^^^^^^^^^^ AIR302 -118 | DatasetAny -119 | expand_alias_to_datasets +122 | DatasetAny +123 | 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:122:1: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 | -116 | DatasetAliasEvent -117 | DatasetAll -118 | DatasetAny +120 | DatasetAliasEvent +121 | DatasetAll +122 | DatasetAny | ^^^^^^^^^^ AIR302 -119 | expand_alias_to_datasets -120 | Metadata +123 | expand_alias_to_datasets +124 | 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:123:1: AIR302 `airflow.datasets.expand_alias_to_datasets` is removed in Airflow 3.0 | -117 | DatasetAll -118 | DatasetAny -119 | expand_alias_to_datasets +121 | DatasetAll +122 | DatasetAny +123 | expand_alias_to_datasets | ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -120 | Metadata +124 | 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:124:1: AIR302 `airflow.datasets.metadata.Metadata` is removed in Airflow 3.0 | -118 | DatasetAny -119 | expand_alias_to_datasets -120 | Metadata +122 | DatasetAny +123 | expand_alias_to_datasets +124 | Metadata | ^^^^^^^^ AIR302 -121 | -122 | # airflow.datasets.manager +125 | +126 | 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:126:31: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 + | +124 | Metadata +125 | +126 | dataset_to_test_method_call = Dataset() + | ^^^^^^^ AIR302 +127 | dataset_to_test_method_call.iter_datasets() +128 | dataset_to_test_method_call.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.Asset` instead + +AIR302_names.py:127:29: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +126 | dataset_to_test_method_call = Dataset() +127 | dataset_to_test_method_call.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +128 | dataset_to_test_method_call.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:128:29: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +126 | dataset_to_test_method_call = Dataset() +127 | dataset_to_test_method_call.iter_datasets() +128 | dataset_to_test_method_call.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +129 | +130 | alias_to_test_method_call = DatasetAlias() + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:130:29: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 + | +128 | dataset_to_test_method_call.iter_dataset_aliases() +129 | +130 | alias_to_test_method_call = DatasetAlias() + | ^^^^^^^^^^^^ AIR302 +131 | alias_to_test_method_call.iter_datasets() +132 | alias_to_test_method_call.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.AssetAlias` instead + +AIR302_names.py:131:27: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +130 | alias_to_test_method_call = DatasetAlias() +131 | alias_to_test_method_call.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +132 | alias_to_test_method_call.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:132:27: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +130 | alias_to_test_method_call = DatasetAlias() +131 | alias_to_test_method_call.iter_datasets() +132 | alias_to_test_method_call.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +133 | +134 | any_to_test_method_call = DatasetAny() + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:134:27: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 + | +132 | alias_to_test_method_call.iter_dataset_aliases() +133 | +134 | any_to_test_method_call = DatasetAny() + | ^^^^^^^^^^ AIR302 +135 | any_to_test_method_call.iter_datasets() +136 | any_to_test_method_call.iter_dataset_aliases() + | + = help: Use `airflow.sdk.definitions.asset.AssetAny` instead + +AIR302_names.py:135:25: AIR302 `iter_datasets` is removed in Airflow 3.0 + | +134 | any_to_test_method_call = DatasetAny() +135 | any_to_test_method_call.iter_datasets() + | ^^^^^^^^^^^^^ AIR302 +136 | any_to_test_method_call.iter_dataset_aliases() + | + = help: Use `iter_assets` instead + +AIR302_names.py:136:25: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 + | +134 | any_to_test_method_call = DatasetAny() +135 | any_to_test_method_call.iter_datasets() +136 | any_to_test_method_call.iter_dataset_aliases() + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +137 | +138 | # airflow.datasets.manager + | + = help: Use `iter_asset_aliases` instead + +AIR302_names.py:139:17: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 | -122 | # airflow.datasets.manager -123 | DatasetManager, dataset_manager, resolve_dataset_manager +138 | # airflow.datasets.manager +139 | DatasetManager, dataset_manager, resolve_dataset_manager | ^^^^^^^^^^^^^^^ AIR302 -124 | -125 | # airflow.lineage.hook +140 | +141 | # airflow.lineage.hook | = 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:139:34: AIR302 `airflow.datasets.manager.resolve_dataset_manager` is removed in Airflow 3.0 | -122 | # airflow.datasets.manager -123 | DatasetManager, dataset_manager, resolve_dataset_manager +138 | # airflow.datasets.manager +139 | DatasetManager, dataset_manager, resolve_dataset_manager | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -124 | -125 | # airflow.lineage.hook +140 | +141 | # airflow.lineage.hook | = 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:142:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 | -125 | # airflow.lineage.hook -126 | DatasetLineageInfo +141 | # airflow.lineage.hook +142 | DatasetLineageInfo | ^^^^^^^^^^^^^^^^^^ AIR302 -127 | -128 | # airflow.listeners.spec.dataset +143 | +144 | # 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:145: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 +144 | # airflow.listeners.spec.dataset +145 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -130 | -131 | # airflow.metrics.validators +146 | +147 | # 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:145: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 +144 | # airflow.listeners.spec.dataset +145 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -130 | -131 | # airflow.metrics.validators +146 | +147 | # 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:148:1: AIR302 `airflow.metrics.validators.AllowListValidator` is removed in Airflow 3.0 | -131 | # airflow.metrics.validators -132 | AllowListValidator, BlockListValidator +147 | # airflow.metrics.validators +148 | AllowListValidator, BlockListValidator | ^^^^^^^^^^^^^^^^^^ AIR302 -133 | -134 | # airflow.operators.dummy_operator +149 | +150 | # 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:148:21: AIR302 `airflow.metrics.validators.BlockListValidator` is removed in Airflow 3.0 | -131 | # airflow.metrics.validators -132 | AllowListValidator, BlockListValidator +147 | # airflow.metrics.validators +148 | AllowListValidator, BlockListValidator | ^^^^^^^^^^^^^^^^^^ AIR302 -133 | -134 | # airflow.operators.dummy_operator +149 | +150 | # 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:151:16: AIR302 `airflow.operators.dummy_operator.EmptyOperator` is removed in Airflow 3.0 | -134 | # airflow.operators.dummy_operator -135 | dummy_operator.EmptyOperator +150 | # airflow.operators.dummy_operator +151 | dummy_operator.EmptyOperator | ^^^^^^^^^^^^^ AIR302 -136 | dummy_operator.DummyOperator +152 | 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:152: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 +150 | # airflow.operators.dummy_operator +151 | dummy_operator.EmptyOperator +152 | dummy_operator.DummyOperator | ^^^^^^^^^^^^^ AIR302 -137 | -138 | # airflow.operators.bash_operator +153 | +154 | # 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:155:1: AIR302 `airflow.operators.bash_operator.BashOperator` is removed in Airflow 3.0 | -138 | # airflow.operators.bash_operator -139 | BashOperator +154 | # airflow.operators.bash_operator +155 | BashOperator | ^^^^^^^^^^^^ AIR302 -140 | -141 | # airflow.operators.branch_operator +156 | +157 | # 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:158:1: AIR302 `airflow.operators.branch_operator.BaseBranchOperator` is removed in Airflow 3.0 | -141 | # airflow.operators.branch_operator -142 | BaseBranchOperator +157 | # airflow.operators.branch_operator +158 | BaseBranchOperator | ^^^^^^^^^^^^^^^^^^ AIR302 -143 | -144 | # airflow.operators.dummy +159 | +160 | # airflow.operators.dummy | = 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:161:16: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 | -144 | # airflow.operators.dummy -145 | EmptyOperator, DummyOperator +160 | # airflow.operators.dummy +161 | EmptyOperator, DummyOperator | ^^^^^^^^^^^^^ AIR302 -146 | -147 | # airflow.operators.email_operator +162 | +163 | # 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:164:1: AIR302 `airflow.operators.email_operator.EmailOperator` is removed in Airflow 3.0 | -147 | # airflow.operators.email_operator -148 | EmailOperator +163 | # airflow.operators.email_operator +164 | EmailOperator | ^^^^^^^^^^^^^ AIR302 -149 | -150 | # airflow.operators.subdag.* +165 | +166 | # airflow.operators.subdag.* | = 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:167:1: AIR302 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0; The whole `airflow.subdag` module has been removed. | -150 | # airflow.operators.subdag.* -151 | SubDagOperator +166 | # airflow.operators.subdag.* +167 | SubDagOperator | ^^^^^^^^^^^^^^ AIR302 -152 | -153 | # airflow.providers.amazon +168 | +169 | # 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:170:13: AIR302 `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0 | -153 | # airflow.providers.amazon -154 | AvpEntities.DATASET +169 | # airflow.providers.amazon +170 | AvpEntities.DATASET | ^^^^^^^ AIR302 -155 | s3.create_dataset -156 | s3.convert_dataset_to_openlineage +171 | s3.create_dataset +172 | 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:171: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 +169 | # airflow.providers.amazon +170 | AvpEntities.DATASET +171 | s3.create_dataset | ^^^^^^^^^^^^^^ AIR302 -156 | s3.convert_dataset_to_openlineage -157 | s3.sanitize_uri +172 | s3.convert_dataset_to_openlineage +173 | 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:172: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 +170 | AvpEntities.DATASET +171 | s3.create_dataset +172 | s3.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -157 | s3.sanitize_uri +173 | 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:173: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 +171 | s3.create_dataset +172 | s3.convert_dataset_to_openlineage +173 | s3.sanitize_uri | ^^^^^^^^^^^^ AIR302 -158 | -159 | # airflow.providers.common.io +174 | +175 | # 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:176: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 +175 | # airflow.providers.common.io +176 | common_io_file.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -161 | common_io_file.create_dataset -162 | common_io_file.sanitize_uri +177 | common_io_file.create_dataset +178 | 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:177: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 +175 | # airflow.providers.common.io +176 | common_io_file.convert_dataset_to_openlineage +177 | common_io_file.create_dataset | ^^^^^^^^^^^^^^ AIR302 -162 | common_io_file.sanitize_uri +178 | 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:178: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 +176 | common_io_file.convert_dataset_to_openlineage +177 | common_io_file.create_dataset +178 | common_io_file.sanitize_uri | ^^^^^^^^^^^^ AIR302 -163 | -164 | # airflow.providers.fab +179 | +180 | # 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:181: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 +180 | # airflow.providers.fab +181 | fab_auth_manager.is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -166 | -167 | # airflow.providers.google +182 | +183 | # 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:186:5: AIR302 `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0 | -168 | bigquery.sanitize_uri -169 | -170 | gcs.create_dataset +184 | bigquery.sanitize_uri +185 | +186 | gcs.create_dataset | ^^^^^^^^^^^^^^ AIR302 -171 | gcs.sanitize_uri -172 | gcs.convert_dataset_to_openlineage +187 | gcs.sanitize_uri +188 | 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:187:5: AIR302 `airflow.providers.google.datasets.gcs.sanitize_uri` is removed in Airflow 3.0 | -170 | gcs.create_dataset -171 | gcs.sanitize_uri +186 | gcs.create_dataset +187 | gcs.sanitize_uri | ^^^^^^^^^^^^ AIR302 -172 | gcs.convert_dataset_to_openlineage +188 | 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:188: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 +186 | gcs.create_dataset +187 | gcs.sanitize_uri +188 | gcs.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -173 | -174 | # airflow.providers.mysql +189 | +190 | # 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:191:7: AIR302 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0 | -174 | # airflow.providers.mysql -175 | mysql.sanitize_uri +190 | # airflow.providers.mysql +191 | mysql.sanitize_uri | ^^^^^^^^^^^^ AIR302 -176 | -177 | # airflow.providers.openlineage +192 | +193 | # 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:194:1: AIR302 `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0 | -177 | # airflow.providers.openlineage -178 | DatasetInfo, translate_airflow_dataset +193 | # airflow.providers.openlineage +194 | DatasetInfo, translate_airflow_dataset | ^^^^^^^^^^^ AIR302 -179 | -180 | # airflow.providers.postgres +195 | +196 | # 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:194:14: AIR302 `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0 | -177 | # airflow.providers.openlineage -178 | DatasetInfo, translate_airflow_dataset +193 | # airflow.providers.openlineage +194 | DatasetInfo, translate_airflow_dataset | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -179 | -180 | # airflow.providers.postgres +195 | +196 | # 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:197:10: AIR302 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0 | -180 | # airflow.providers.postgres -181 | postgres.sanitize_uri +196 | # airflow.providers.postgres +197 | postgres.sanitize_uri | ^^^^^^^^^^^^ AIR302 -182 | -183 | # airflow.providers.trino +198 | +199 | # 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:200:7: AIR302 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0 | -183 | # airflow.providers.trino -184 | trino.sanitize_uri +199 | # airflow.providers.trino +200 | trino.sanitize_uri | ^^^^^^^^^^^^ AIR302 -185 | -186 | # airflow.secrets +201 | +202 | # 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:203:1: AIR302 `airflow.secrets.local_filesystem.get_connection` is removed in Airflow 3.0 | -186 | # airflow.secrets -187 | get_connection, load_connections +202 | # airflow.secrets +203 | get_connection, load_connections | ^^^^^^^^^^^^^^ AIR302 -188 | -189 | # airflow.security.permissions +204 | +205 | # 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:203:17: AIR302 `airflow.secrets.local_filesystem.load_connections` is removed in Airflow 3.0 | -186 | # airflow.secrets -187 | get_connection, load_connections +202 | # airflow.secrets +203 | get_connection, load_connections | ^^^^^^^^^^^^^^^^ AIR302 -188 | -189 | # airflow.security.permissions +204 | +205 | # 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:206:1: AIR302 `airflow.security.permissions.RESOURCE_DATASET` is removed in Airflow 3.0 | -189 | # airflow.security.permissions -190 | RESOURCE_DATASET +205 | # airflow.security.permissions +206 | RESOURCE_DATASET | ^^^^^^^^^^^^^^^^ AIR302 -191 | -192 | # airflow.sensors.base_sensor_operator +207 | +208 | # 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:209:1: AIR302 `airflow.sensors.base_sensor_operator.BaseSensorOperator` is removed in Airflow 3.0 | -192 | # airflow.sensors.base_sensor_operator -193 | BaseSensorOperator +208 | # airflow.sensors.base_sensor_operator +209 | BaseSensorOperator | ^^^^^^^^^^^^^^^^^^ AIR302 -194 | -195 | # airflow.sensors.date_time_sensor +210 | +211 | # 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:212:1: AIR302 `airflow.sensors.date_time_sensor.DateTimeSensor` is removed in Airflow 3.0 | -195 | # airflow.sensors.date_time_sensor -196 | DateTimeSensor +211 | # airflow.sensors.date_time_sensor +212 | DateTimeSensor | ^^^^^^^^^^^^^^ AIR302 -197 | -198 | # airflow.sensors.external_task +213 | +214 | # 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:215:1: AIR302 `airflow.sensors.external_task.ExternalTaskSensorLink` is removed in Airflow 3.0 | -198 | # airflow.sensors.external_task -199 | ExternalTaskSensorLinkFromExternalTask +214 | # airflow.sensors.external_task +215 | ExternalTaskSensorLinkFromExternalTask | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -200 | -201 | # airflow.sensors.external_task_sensor +216 | +217 | # 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:218:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskMarker` is removed in Airflow 3.0 | -201 | # airflow.sensors.external_task_sensor -202 | ExternalTaskMarker +217 | # airflow.sensors.external_task_sensor +218 | ExternalTaskMarker | ^^^^^^^^^^^^^^^^^^ AIR302 -203 | ExternalTaskSensor -204 | ExternalTaskSensorLinkFromExternalTaskSensor +219 | ExternalTaskSensor +220 | 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:219:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensor` is removed in Airflow 3.0 | -201 | # airflow.sensors.external_task_sensor -202 | ExternalTaskMarker -203 | ExternalTaskSensor +217 | # airflow.sensors.external_task_sensor +218 | ExternalTaskMarker +219 | ExternalTaskSensor | ^^^^^^^^^^^^^^^^^^ AIR302 -204 | ExternalTaskSensorLinkFromExternalTaskSensor +220 | 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:220:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensorLink` is removed in Airflow 3.0 | -202 | ExternalTaskMarker -203 | ExternalTaskSensor -204 | ExternalTaskSensorLinkFromExternalTaskSensor +218 | ExternalTaskMarker +219 | ExternalTaskSensor +220 | ExternalTaskSensorLinkFromExternalTaskSensor | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -205 | -206 | # airflow.sensors.time_delta_sensor +221 | +222 | # 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:223:1: AIR302 `airflow.sensors.time_delta_sensor.TimeDeltaSensor` is removed in Airflow 3.0 | -206 | # airflow.sensors.time_delta_sensor -207 | TimeDeltaSensor +222 | # airflow.sensors.time_delta_sensor +223 | TimeDeltaSensor | ^^^^^^^^^^^^^^^ AIR302 -208 | -209 | # airflow.timetables +224 | +225 | # 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:226:1: AIR302 `airflow.timetables.datasets.DatasetOrTimeSchedule` is removed in Airflow 3.0 | -209 | # airflow.timetables -210 | DatasetOrTimeSchedule +225 | # airflow.timetables +226 | DatasetOrTimeSchedule | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -211 | DatasetTriggeredTimetable +227 | 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:227:1: AIR302 `airflow.timetables.simple.DatasetTriggeredTimetable` is removed in Airflow 3.0 | -209 | # airflow.timetables -210 | DatasetOrTimeSchedule -211 | DatasetTriggeredTimetable +225 | # airflow.timetables +226 | DatasetOrTimeSchedule +227 | DatasetTriggeredTimetable | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -212 | -213 | # airflow.triggers.external_task +228 | +229 | # 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:230:1: AIR302 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 | -213 | # airflow.triggers.external_task -214 | TaskStateTrigger +229 | # airflow.triggers.external_task +230 | TaskStateTrigger | ^^^^^^^^^^^^^^^^ AIR302 -215 | -216 | # airflow.utils.date +231 | +232 | # airflow.utils.date | -AIR302_names.py:217:7: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 +AIR302_names.py:233:7: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 | -216 | # airflow.utils.date -217 | dates.date_range +232 | # airflow.utils.date +233 | dates.date_range | ^^^^^^^^^^ AIR302 -218 | dates.days_ago +234 | 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:234: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 +232 | # airflow.utils.date +233 | dates.date_range +234 | dates.days_ago | ^^^^^^^^ AIR302 -219 | -220 | date_range +235 | +236 | 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:236:1: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 | -218 | dates.days_ago -219 | -220 | date_range +234 | dates.days_ago +235 | +236 | date_range | ^^^^^^^^^^ AIR302 -221 | days_ago -222 | infer_time_unit +237 | days_ago +238 | 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:237:1: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 | -220 | date_range -221 | days_ago +236 | date_range +237 | days_ago | ^^^^^^^^ AIR302 -222 | infer_time_unit -223 | parse_execution_date +238 | infer_time_unit +239 | 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:238:1: AIR302 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 | -220 | date_range -221 | days_ago -222 | infer_time_unit +236 | date_range +237 | days_ago +238 | infer_time_unit | ^^^^^^^^^^^^^^^ AIR302 -223 | parse_execution_date -224 | round_time +239 | parse_execution_date +240 | round_time | -AIR302_names.py:223:1: AIR302 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 +AIR302_names.py:239: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 +237 | days_ago +238 | infer_time_unit +239 | parse_execution_date | ^^^^^^^^^^^^^^^^^^^^ AIR302 -224 | round_time -225 | scale_time_units +240 | round_time +241 | scale_time_units | -AIR302_names.py:224:1: AIR302 `airflow.utils.dates.round_time` is removed in Airflow 3.0 +AIR302_names.py:240:1: AIR302 `airflow.utils.dates.round_time` is removed in Airflow 3.0 | -222 | infer_time_unit -223 | parse_execution_date -224 | round_time +238 | infer_time_unit +239 | parse_execution_date +240 | round_time | ^^^^^^^^^^ AIR302 -225 | scale_time_units +241 | scale_time_units | -AIR302_names.py:225:1: AIR302 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 +AIR302_names.py:241: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 +239 | parse_execution_date +240 | round_time +241 | scale_time_units | ^^^^^^^^^^^^^^^^ AIR302 -226 | -227 | # This one was not deprecated. +242 | +243 | # 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:248:1: AIR302 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 | -231 | # airflow.utils.dag_cycle_tester -232 | test_cycle +247 | # airflow.utils.dag_cycle_tester +248 | test_cycle | ^^^^^^^^^^ AIR302 -233 | -234 | # airflow.utils.decorators +249 | +250 | # 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:251: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 +250 | # airflow.utils.decorators +251 | apply_defaults | ^^^^^^^^^^^^^^ AIR302 -236 | -237 | # airflow.utils.file +252 | +253 | # airflow.utils.file | -AIR302_names.py:238:1: AIR302 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0 +AIR302_names.py:254:1: AIR302 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0 | -237 | # airflow.utils.file -238 | TemporaryDirectory, mkdirs +253 | # airflow.utils.file +254 | TemporaryDirectory, mkdirs | ^^^^^^^^^^^^^^^^^^ AIR302 -239 | -240 | # airflow.utils.helpers +255 | +256 | # airflow.utils.helpers | -AIR302_names.py:238:21: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 +AIR302_names.py:254:21: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 | -237 | # airflow.utils.file -238 | TemporaryDirectory, mkdirs +253 | # airflow.utils.file +254 | TemporaryDirectory, mkdirs | ^^^^^^ AIR302 -239 | -240 | # airflow.utils.helpers +255 | +256 | # 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:257:1: AIR302 `airflow.utils.helpers.chain` is removed in Airflow 3.0 | -240 | # airflow.utils.helpers -241 | chain, cross_downstream +256 | # airflow.utils.helpers +257 | chain, cross_downstream | ^^^^^ AIR302 -242 | -243 | # airflow.utils.state +258 | +259 | # 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:257:8: AIR302 `airflow.utils.helpers.cross_downstream` is removed in Airflow 3.0 | -240 | # airflow.utils.helpers -241 | chain, cross_downstream +256 | # airflow.utils.helpers +257 | chain, cross_downstream | ^^^^^^^^^^^^^^^^ AIR302 -242 | -243 | # airflow.utils.state +258 | +259 | # 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:260:1: AIR302 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 | -243 | # airflow.utils.state -244 | SHUTDOWN, terminating_states +259 | # airflow.utils.state +260 | SHUTDOWN, terminating_states | ^^^^^^^^ AIR302 -245 | -246 | # airflow.utils.trigger_rule +261 | +262 | # airflow.utils.trigger_rule | -AIR302_names.py:244:11: AIR302 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 +AIR302_names.py:260:11: AIR302 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 | -243 | # airflow.utils.state -244 | SHUTDOWN, terminating_states +259 | # airflow.utils.state +260 | SHUTDOWN, terminating_states | ^^^^^^^^^^^^^^^^^^ AIR302 -245 | -246 | # airflow.utils.trigger_rule +261 | +262 | # 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:263:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 | -246 | # airflow.utils.trigger_rule -247 | TriggerRule.DUMMY +262 | # airflow.utils.trigger_rule +263 | TriggerRule.DUMMY | ^^^^^ AIR302 -248 | TriggerRule.NONE_FAILED_OR_SKIPPED +264 | 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:264: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 +262 | # airflow.utils.trigger_rule +263 | TriggerRule.DUMMY +264 | TriggerRule.NONE_FAILED_OR_SKIPPED | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -249 | -250 | # airflow.www.auth +265 | +266 | # airflow.www.auth | -AIR302_names.py:251:1: AIR302 `airflow.www.auth.has_access` is removed in Airflow 3.0 +AIR302_names.py:267:1: AIR302 `airflow.www.auth.has_access` is removed in Airflow 3.0 | -250 | # airflow.www.auth -251 | has_access +266 | # airflow.www.auth +267 | has_access | ^^^^^^^^^^ AIR302 -252 | has_access_dataset +268 | 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:268: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 +266 | # airflow.www.auth +267 | has_access +268 | has_access_dataset | ^^^^^^^^^^^^^^^^^^ AIR302 -253 | -254 | # airflow.www.utils +269 | +270 | # 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:271: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 +270 | # airflow.www.utils +271 | 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:271: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 +270 | # airflow.www.utils +271 | 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 +AIR302_names.py:279:4: AIR302 `register_dataset_change` is removed in Airflow 3.0 | -259 | dm = DatasetManager() -260 | dm.register_dataset_change() +278 | dm = DatasetManager() +279 | dm.register_dataset_change() | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -261 | dm.create_datasets() -262 | dm.notify_dataset_created() +280 | dm.create_datasets() +281 | dm.notify_dataset_created() | = help: Use `register_asset_change` instead -AIR302_names.py:261:4: AIR302 `create_datasets` is removed in Airflow 3.0 +AIR302_names.py:280:4: AIR302 `create_datasets` is removed in Airflow 3.0 | -259 | dm = DatasetManager() -260 | dm.register_dataset_change() -261 | dm.create_datasets() +278 | dm = DatasetManager() +279 | dm.register_dataset_change() +280 | dm.create_datasets() | ^^^^^^^^^^^^^^^ AIR302 -262 | dm.notify_dataset_created() -263 | dm.notify_dataset_changed() +281 | dm.notify_dataset_created() +282 | dm.notify_dataset_changed() | = help: Use `create_assets` instead -AIR302_names.py:262:4: AIR302 `notify_dataset_created` is removed in Airflow 3.0 +AIR302_names.py:281: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() +279 | dm.register_dataset_change() +280 | dm.create_datasets() +281 | dm.notify_dataset_created() | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -263 | dm.notify_dataset_changed() -264 | dm.notify_dataset_alias_created() +282 | dm.notify_dataset_changed() +283 | 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 +AIR302_names.py:282: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() +280 | dm.create_datasets() +281 | dm.notify_dataset_created() +282 | dm.notify_dataset_changed() | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -264 | dm.notify_dataset_alias_created() +283 | 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 +AIR302_names.py:283: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() +281 | dm.notify_dataset_created() +282 | dm.notify_dataset_changed() +283 | 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 +AIR302_names.py:289:5: AIR302 `create_dataset` is removed in Airflow 3.0 | -269 | hlc = HookLineageCollector() -270 | hlc.create_dataset() +288 | hlc = HookLineageCollector() +289 | hlc.create_dataset() | ^^^^^^^^^^^^^^ AIR302 -271 | hlc.add_input_dataset() -272 | hlc.add_output_dataset() +290 | hlc.add_input_dataset() +291 | hlc.add_output_dataset() | = help: Use `create_asset` instead -AIR302_names.py:271:5: AIR302 `add_input_dataset` is removed in Airflow 3.0 +AIR302_names.py:290:5: AIR302 `add_input_dataset` is removed in Airflow 3.0 | -269 | hlc = HookLineageCollector() -270 | hlc.create_dataset() -271 | hlc.add_input_dataset() +288 | hlc = HookLineageCollector() +289 | hlc.create_dataset() +290 | hlc.add_input_dataset() | ^^^^^^^^^^^^^^^^^ AIR302 -272 | hlc.add_output_dataset() -273 | hlc.collected_datasets() +291 | hlc.add_output_dataset() +292 | hlc.collected_datasets() | = help: Use `add_input_asset` instead -AIR302_names.py:272:5: AIR302 `add_output_dataset` is removed in Airflow 3.0 +AIR302_names.py:291: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() +289 | hlc.create_dataset() +290 | hlc.add_input_dataset() +291 | hlc.add_output_dataset() | ^^^^^^^^^^^^^^^^^^ AIR302 -273 | hlc.collected_datasets() +292 | hlc.collected_datasets() | = help: Use `add_output_asset` instead -AIR302_names.py:273:5: AIR302 `collected_datasets` is removed in Airflow 3.0 +AIR302_names.py:292:5: AIR302 `collected_datasets` is removed in Airflow 3.0 | -271 | hlc.add_input_dataset() -272 | hlc.add_output_dataset() -273 | hlc.collected_datasets() +290 | hlc.add_input_dataset() +291 | hlc.add_output_dataset() +292 | hlc.collected_datasets() | ^^^^^^^^^^^^^^^^^^ AIR302 +293 | +294 | from airflow.providers.amazon.auth_manager.aws_auth_manager import AwsAuthManager | = help: Use `collected_assets` instead -AIR302_names.py:279:5: AIR302 `is_authorized_dataset` is removed in Airflow 3.0 +AIR302_names.py:297:5: AIR302 `is_authorized_dataset` is removed in Airflow 3.0 | -278 | aam = AwsAuthManager() -279 | aam.is_authorized_dataset() +296 | aam = AwsAuthManager() +297 | aam.is_authorized_dataset() | ^^^^^^^^^^^^^^^^^^^^^ AIR302 +298 | +299 | from airflow.providers_manager import ProvidersManager | = help: Use `is_authorized_asset` instead + +AIR302_names.py:309:21: AIR302 `get_conn_uri` is removed in Airflow 3.0 + | +308 | base_secret_backend = BaseSecretsBackend() +309 | base_secret_backend.get_conn_uri() + | ^^^^^^^^^^^^ AIR302 +310 | base_secret_backend.get_connections() + | + = help: Use `get_conn_value` instead + +AIR302_names.py:310:21: AIR302 `get_connections` is removed in Airflow 3.0 + | +308 | base_secret_backend = BaseSecretsBackend() +309 | base_secret_backend.get_conn_uri() +310 | base_secret_backend.get_connections() + | ^^^^^^^^^^^^^^^ AIR302 +311 | +312 | from airflow.providers.google.cloud.secrets.secret_manager import ( + | + = help: Use `get_connection` instead + +AIR302_names.py:317:13: AIR302 `get_conn_uri` is removed in Airflow 3.0 + | +316 | csm_backend = CloudSecretManagerBackend() +317 | csm_backend.get_conn_uri() + | ^^^^^^^^^^^^ AIR302 +318 | csm_backend.get_connections() + | + = help: Use `get_conn_value` instead + +AIR302_names.py:318:13: AIR302 `get_connections` is removed in Airflow 3.0 + | +316 | csm_backend = CloudSecretManagerBackend() +317 | csm_backend.get_conn_uri() +318 | csm_backend.get_connections() + | ^^^^^^^^^^^^^^^ AIR302 +319 | +320 | from airflow.providers.hashicorp.secrets.vault import VaultBackend + | + = help: Use `get_connection` instead + +AIR302_names.py:323:15: AIR302 `get_conn_uri` is removed in Airflow 3.0 + | +322 | vault_backend = VaultBackend() +323 | vault_backend.get_conn_uri() + | ^^^^^^^^^^^^ AIR302 +324 | vault_backend.get_connections() + | + = help: Use `get_conn_value` instead + +AIR302_names.py:324:15: AIR302 `get_connections` is removed in Airflow 3.0 + | +322 | vault_backend = VaultBackend() +323 | vault_backend.get_conn_uri() +324 | vault_backend.get_connections() + | ^^^^^^^^^^^^^^^ AIR302 + | + = help: Use `get_connection` instead From 1483804487e41e1833ee0eaed33eff221a478311 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 20 Dec 2024 23:41:33 +0900 Subject: [PATCH 02/12] feat(AIR302): add function removed_class_attribute and the following rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `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` --- .../test/fixtures/airflow/AIR302_names.py | 12 +++++ .../src/rules/airflow/rules/removal_in_3.rs | 48 ++++++++++++++++- ...irflow__tests__AIR302_AIR302_names.py.snap | 52 +++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) 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 bbf87a3054eb2..d17dc244d9b82 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py @@ -322,3 +322,15 @@ vault_backend = VaultBackend() vault_backend.get_conn_uri() vault_backend.get_connections() + +from airflow.providers_manager import ProvidersManager + +provider_manager = ProvidersManager() +provider_manager.dataset_factories +provider_manager.dataset_uri_handlers +provider_manager.dataset_to_openlineage_converters + +from airflow.lineage.hook import DatasetLineageInfo + +dl_info = DatasetLineageInfo() +dl_info.dataset 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 d6619a2fef69a..c734b32bf7907 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 @@ -163,6 +163,49 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: }; } +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; + }; + + // checker.diagnostics.push(Diagnostic::new( + // Airflow3Removal { + // deprecated: qualname.to_string(), + // replacement: Replacement::Name("te"), + // }, + // attr.range(), + // )); + + 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"] => 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(), + )); + } +} + fn removed_method(checker: &mut Checker, expr: &Expr) { let Expr::Call(ExprCall { func, .. }) = expr else { return; @@ -684,7 +727,10 @@ pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { removed_method(checker, expr); } - Expr::Attribute(ExprAttribute { attr: ranged, .. }) => removed_name(checker, expr, ranged), + Expr::Attribute(ExprAttribute { attr: ranged, .. }) => { + removed_name(checker, expr, ranged); + removed_class_attribute(checker, expr); + } ranged @ Expr::Name(_) => removed_name(checker, expr, ranged), _ => {} } 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 079489d488179..36d67198fd857 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 @@ -1132,6 +1132,15 @@ AIR302_names.py:297:5: AIR302 `is_authorized_dataset` is removed in Airflow 3.0 | = help: Use `is_authorized_asset` instead +AIR302_names.py:303:4: AIR302 `dataset_factories` is removed in Airflow 3.0 + | +301 | pm = ProvidersManager() +302 | pm.initialize_providers_asset_uri_resources() +303 | pm.dataset_factories + | ^^^^^^^^^^^^^^^^^ AIR302 + | + = help: Use `asset_factories` instead + AIR302_names.py:309:21: AIR302 `get_conn_uri` is removed in Airflow 3.0 | 308 | base_secret_backend = BaseSecretsBackend() @@ -1187,5 +1196,48 @@ AIR302_names.py:324:15: AIR302 `get_connections` is removed in Airflow 3.0 323 | vault_backend.get_conn_uri() 324 | vault_backend.get_connections() | ^^^^^^^^^^^^^^^ AIR302 +325 | +326 | from airflow.providers_manager import ProvidersManager | = help: Use `get_connection` instead + +AIR302_names.py:329:18: AIR302 `dataset_factories` is removed in Airflow 3.0 + | +328 | provider_manager = ProvidersManager() +329 | provider_manager.dataset_factories + | ^^^^^^^^^^^^^^^^^ AIR302 +330 | provider_manager.dataset_uri_handlers +331 | provider_manager.dataset_to_openlineage_converters + | + = help: Use `asset_factories` instead + +AIR302_names.py:330:18: AIR302 `dataset_uri_handlers` is removed in Airflow 3.0 + | +328 | provider_manager = ProvidersManager() +329 | provider_manager.dataset_factories +330 | provider_manager.dataset_uri_handlers + | ^^^^^^^^^^^^^^^^^^^^ AIR302 +331 | provider_manager.dataset_to_openlineage_converters + | + = help: Use `asset_uri_handlers` instead + +AIR302_names.py:331:18: AIR302 `dataset_to_openlineage_converters` is removed in Airflow 3.0 + | +329 | provider_manager.dataset_factories +330 | provider_manager.dataset_uri_handlers +331 | provider_manager.dataset_to_openlineage_converters + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 +332 | +333 | from airflow.lineage.hook import DatasetLineageInfo + | + = help: Use `asset_to_openlineage_converters` instead + +AIR302_names.py:335:11: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 + | +333 | from airflow.lineage.hook import DatasetLineageInfo +334 | +335 | dl_info = DatasetLineageInfo() + | ^^^^^^^^^^^^^^^^^^ AIR302 +336 | dl_info.dataset + | + = help: Use `airflow.lineage.hook.AssetLineageInfo` instead From 1743f029f1bda4a5df1f0623fefd28fe3bc27bd0 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 25 Dec 2024 12:31:52 +0900 Subject: [PATCH 03/12] refactor(AIR302): refactor regex usage --- .../airflow/AIR302_class_attribute.py | 59 +++++ .../test/fixtures/airflow/AIR302_names.py | 65 ------ crates/ruff_linter/src/rules/airflow/mod.rs | 1 + .../src/rules/airflow/rules/removal_in_3.rs | 66 ++++-- ...sts__AIR302_AIR302_class_attribute.py.snap | 220 ++++++++++++++++++ ...irflow__tests__AIR302_AIR302_names.py.snap | 213 ----------------- 6 files changed, 330 insertions(+), 294 deletions(-) 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_class_attribute.py.snap 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 0000000000000..1128f7c11e863 --- /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 d17dc244d9b82..430d1acd3461b 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py @@ -269,68 +269,3 @@ # airflow.www.utils get_sensitive_variables_fields, should_hide_value_for_key - - -# methods - -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 - - -from airflow.secrets.base_secrets import BaseSecretsBackend - -base_secret_backend = BaseSecretsBackend() -base_secret_backend.get_conn_uri() -base_secret_backend.get_connections() - -from airflow.providers.google.cloud.secrets.secret_manager import ( - CloudSecretManagerBackend, -) - -csm_backend = CloudSecretManagerBackend() -csm_backend.get_conn_uri() -csm_backend.get_connections() - -from airflow.providers.hashicorp.secrets.vault import VaultBackend - -vault_backend = VaultBackend() -vault_backend.get_conn_uri() -vault_backend.get_connections() - -from airflow.providers_manager import ProvidersManager - -provider_manager = ProvidersManager() -provider_manager.dataset_factories -provider_manager.dataset_uri_handlers -provider_manager.dataset_to_openlineage_converters - -from airflow.lineage.hook import DatasetLineageInfo - -dl_info = DatasetLineageInfo() -dl_info.dataset diff --git a/crates/ruff_linter/src/rules/airflow/mod.rs b/crates/ruff_linter/src/rules/airflow/mod.rs index 4aa5d618c4329..0eafbda606b8a 100644 --- a/crates/ruff_linter/src/rules/airflow/mod.rs +++ b/crates/ruff_linter/src/rules/airflow/mod.rs @@ -16,6 +16,7 @@ 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::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 c734b32bf7907..96fe5603f715e 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 @@ -4,16 +4,58 @@ use ruff_python_ast::{name::QualifiedName, Arguments, Expr, ExprAttribute, ExprC use ruff_python_semantic::analyze::typing; use ruff_python_semantic::Modules; use ruff_text_size::Ranged; -use std::sync::LazyLock; use crate::checkers::ast::Checker; -use regex::Regex; -static SECRET_BACKEND_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"airflow\..*secrets\.\w+\.\w+Backend").unwrap()); +fn is_airflow_secret_backend(qualname: &QualifiedName) -> bool { + match qualname.segments() { + ["airflow", "secrets", rest @ ..] => { + if let Some(last_element) = rest.last() { + last_element.ends_with("Backend") + } else { + false + } + } + + ["airflow", "providers", rest @ ..] => { + // Ensure 'operators' exists somewhere in the middle + if let (Some(pos), Some(last_element)) = + (rest.iter().position(|&s| s == "secrets"), rest.last()) + { + pos + 1 < rest.len() && last_element.ends_with("Backend") // Check that 'operators' is not the last element + } else { + false + } + } -static AIRFLOW_HOOK_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"airflow\..*hooks\.\w+\.\w+Hook").unwrap()); + _ => false, + } +} + +fn is_airflow_hook(qualname: &QualifiedName) -> bool { + match qualname.segments() { + ["airflow", "hooks", rest @ ..] => { + if let Some(last_element) = rest.last() { + last_element.ends_with("Hook") + } else { + false + } + } + + ["airflow", "providers", rest @ ..] => { + // Ensure 'operators' exists somewhere in the middle + if let (Some(pos), Some(last_element)) = + (rest.iter().position(|&s| s == "hooks"), rest.last()) + { + pos + 1 < rest.len() && last_element.ends_with("Hook") + } else { + false + } + } + + _ => false, + } +} #[derive(Debug, Eq, PartialEq)] enum Replacement { @@ -172,14 +214,6 @@ fn removed_class_attribute(checker: &mut Checker, expr: &Expr) { return; }; - // checker.diagnostics.push(Diagnostic::new( - // Airflow3Removal { - // deprecated: qualname.to_string(), - // replacement: Replacement::Name("te"), - // }, - // attr.range(), - // )); - let replacement = match *qualname.segments() { ["airflow", "providers_manager", "ProvidersManager"] => match attr.as_str() { "dataset_factories" => Some(Replacement::Name("asset_factories")), @@ -252,12 +286,12 @@ fn removed_method(checker: &mut Checker, expr: &Expr) { "iter_dataset_aliases" => Some(Replacement::Name("iter_asset_aliases")), &_ => None, }, - _ if SECRET_BACKEND_REGEX.is_match(&qualname.segments().join(".")) => match attr.as_str() { + _ if is_airflow_secret_backend(&qualname) => match attr.as_str() { "get_conn_uri" => Some(Replacement::Name("get_conn_value")), "get_connections" => Some(Replacement::Name("get_connection")), &_ => None, }, - _ if AIRFLOW_HOOK_REGEX.is_match(&qualname.segments().join(".")) => match attr.as_str() { + _ if is_airflow_hook(&qualname) => match attr.as_str() { "get_connections" => Some(Replacement::Name("get_connection")), &_ => None, }, 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 0000000000000..dfd70e3ab0d5e --- /dev/null +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_class_attribute.py.snap @@ -0,0 +1,220 @@ +--- +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 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 36d67198fd857..8850117bc961d 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 @@ -1028,216 +1028,3 @@ AIR302_names.py:271:33: AIR302 `airflow.www.utils.should_hide_value_for_key` is | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.utils.log.secrets_masker.should_hide_value_for_key` instead - -AIR302_names.py:279:4: AIR302 `register_dataset_change` is removed in Airflow 3.0 - | -278 | dm = DatasetManager() -279 | dm.register_dataset_change() - | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -280 | dm.create_datasets() -281 | dm.notify_dataset_created() - | - = help: Use `register_asset_change` instead - -AIR302_names.py:280:4: AIR302 `create_datasets` is removed in Airflow 3.0 - | -278 | dm = DatasetManager() -279 | dm.register_dataset_change() -280 | dm.create_datasets() - | ^^^^^^^^^^^^^^^ AIR302 -281 | dm.notify_dataset_created() -282 | dm.notify_dataset_changed() - | - = help: Use `create_assets` instead - -AIR302_names.py:281:4: AIR302 `notify_dataset_created` is removed in Airflow 3.0 - | -279 | dm.register_dataset_change() -280 | dm.create_datasets() -281 | dm.notify_dataset_created() - | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -282 | dm.notify_dataset_changed() -283 | dm.notify_dataset_alias_created() - | - = help: Use `notify_asset_created` instead - -AIR302_names.py:282:4: AIR302 `notify_dataset_changed` is removed in Airflow 3.0 - | -280 | dm.create_datasets() -281 | dm.notify_dataset_created() -282 | dm.notify_dataset_changed() - | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -283 | dm.notify_dataset_alias_created() - | - = help: Use `notify_asset_changed` instead - -AIR302_names.py:283:4: AIR302 `notify_dataset_alias_created` is removed in Airflow 3.0 - | -281 | dm.notify_dataset_created() -282 | dm.notify_dataset_changed() -283 | dm.notify_dataset_alias_created() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 - | - = help: Use `notify_asset_alias_created` instead - -AIR302_names.py:289:5: AIR302 `create_dataset` is removed in Airflow 3.0 - | -288 | hlc = HookLineageCollector() -289 | hlc.create_dataset() - | ^^^^^^^^^^^^^^ AIR302 -290 | hlc.add_input_dataset() -291 | hlc.add_output_dataset() - | - = help: Use `create_asset` instead - -AIR302_names.py:290:5: AIR302 `add_input_dataset` is removed in Airflow 3.0 - | -288 | hlc = HookLineageCollector() -289 | hlc.create_dataset() -290 | hlc.add_input_dataset() - | ^^^^^^^^^^^^^^^^^ AIR302 -291 | hlc.add_output_dataset() -292 | hlc.collected_datasets() - | - = help: Use `add_input_asset` instead - -AIR302_names.py:291:5: AIR302 `add_output_dataset` is removed in Airflow 3.0 - | -289 | hlc.create_dataset() -290 | hlc.add_input_dataset() -291 | hlc.add_output_dataset() - | ^^^^^^^^^^^^^^^^^^ AIR302 -292 | hlc.collected_datasets() - | - = help: Use `add_output_asset` instead - -AIR302_names.py:292:5: AIR302 `collected_datasets` is removed in Airflow 3.0 - | -290 | hlc.add_input_dataset() -291 | hlc.add_output_dataset() -292 | hlc.collected_datasets() - | ^^^^^^^^^^^^^^^^^^ AIR302 -293 | -294 | from airflow.providers.amazon.auth_manager.aws_auth_manager import AwsAuthManager - | - = help: Use `collected_assets` instead - -AIR302_names.py:297:5: AIR302 `is_authorized_dataset` is removed in Airflow 3.0 - | -296 | aam = AwsAuthManager() -297 | aam.is_authorized_dataset() - | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -298 | -299 | from airflow.providers_manager import ProvidersManager - | - = help: Use `is_authorized_asset` instead - -AIR302_names.py:303:4: AIR302 `dataset_factories` is removed in Airflow 3.0 - | -301 | pm = ProvidersManager() -302 | pm.initialize_providers_asset_uri_resources() -303 | pm.dataset_factories - | ^^^^^^^^^^^^^^^^^ AIR302 - | - = help: Use `asset_factories` instead - -AIR302_names.py:309:21: AIR302 `get_conn_uri` is removed in Airflow 3.0 - | -308 | base_secret_backend = BaseSecretsBackend() -309 | base_secret_backend.get_conn_uri() - | ^^^^^^^^^^^^ AIR302 -310 | base_secret_backend.get_connections() - | - = help: Use `get_conn_value` instead - -AIR302_names.py:310:21: AIR302 `get_connections` is removed in Airflow 3.0 - | -308 | base_secret_backend = BaseSecretsBackend() -309 | base_secret_backend.get_conn_uri() -310 | base_secret_backend.get_connections() - | ^^^^^^^^^^^^^^^ AIR302 -311 | -312 | from airflow.providers.google.cloud.secrets.secret_manager import ( - | - = help: Use `get_connection` instead - -AIR302_names.py:317:13: AIR302 `get_conn_uri` is removed in Airflow 3.0 - | -316 | csm_backend = CloudSecretManagerBackend() -317 | csm_backend.get_conn_uri() - | ^^^^^^^^^^^^ AIR302 -318 | csm_backend.get_connections() - | - = help: Use `get_conn_value` instead - -AIR302_names.py:318:13: AIR302 `get_connections` is removed in Airflow 3.0 - | -316 | csm_backend = CloudSecretManagerBackend() -317 | csm_backend.get_conn_uri() -318 | csm_backend.get_connections() - | ^^^^^^^^^^^^^^^ AIR302 -319 | -320 | from airflow.providers.hashicorp.secrets.vault import VaultBackend - | - = help: Use `get_connection` instead - -AIR302_names.py:323:15: AIR302 `get_conn_uri` is removed in Airflow 3.0 - | -322 | vault_backend = VaultBackend() -323 | vault_backend.get_conn_uri() - | ^^^^^^^^^^^^ AIR302 -324 | vault_backend.get_connections() - | - = help: Use `get_conn_value` instead - -AIR302_names.py:324:15: AIR302 `get_connections` is removed in Airflow 3.0 - | -322 | vault_backend = VaultBackend() -323 | vault_backend.get_conn_uri() -324 | vault_backend.get_connections() - | ^^^^^^^^^^^^^^^ AIR302 -325 | -326 | from airflow.providers_manager import ProvidersManager - | - = help: Use `get_connection` instead - -AIR302_names.py:329:18: AIR302 `dataset_factories` is removed in Airflow 3.0 - | -328 | provider_manager = ProvidersManager() -329 | provider_manager.dataset_factories - | ^^^^^^^^^^^^^^^^^ AIR302 -330 | provider_manager.dataset_uri_handlers -331 | provider_manager.dataset_to_openlineage_converters - | - = help: Use `asset_factories` instead - -AIR302_names.py:330:18: AIR302 `dataset_uri_handlers` is removed in Airflow 3.0 - | -328 | provider_manager = ProvidersManager() -329 | provider_manager.dataset_factories -330 | provider_manager.dataset_uri_handlers - | ^^^^^^^^^^^^^^^^^^^^ AIR302 -331 | provider_manager.dataset_to_openlineage_converters - | - = help: Use `asset_uri_handlers` instead - -AIR302_names.py:331:18: AIR302 `dataset_to_openlineage_converters` is removed in Airflow 3.0 - | -329 | provider_manager.dataset_factories -330 | provider_manager.dataset_uri_handlers -331 | provider_manager.dataset_to_openlineage_converters - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -332 | -333 | from airflow.lineage.hook import DatasetLineageInfo - | - = help: Use `asset_to_openlineage_converters` instead - -AIR302_names.py:335:11: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 - | -333 | from airflow.lineage.hook import DatasetLineageInfo -334 | -335 | dl_info = DatasetLineageInfo() - | ^^^^^^^^^^^^^^^^^^ AIR302 -336 | dl_info.dataset - | - = help: Use `airflow.lineage.hook.AssetLineageInfo` instead From aa049d50715308ca1f083cecfd9296d2314ff428 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 25 Dec 2024 17:08:53 +0900 Subject: [PATCH 04/12] feat(AIR302): argument `sla` is removed and argument `task_concurrency` is renamed as `max_active_tis_per_dag` in all airflow operators --- .../test/fixtures/airflow/AIR302_args.py | 36 +-- .../src/rules/airflow/rules/removal_in_3.rs | 90 ++++-- ...airflow__tests__AIR302_AIR302_args.py.snap | 270 ++++++++++-------- 3 files changed, 234 insertions(+), 162 deletions(-) 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 28142c87caac1..2432725e78ac9 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,12 @@ -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 datetime import timedelta +from airflow import DAG, dag 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.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") @@ -49,27 +47,21 @@ def decorator_deprecated_operator_args(): trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( task_id="trigger_dagrun_op1", execution_date="2024-12-04" ) - trigger_dagrun_op2 = TriggerDagRunOperator( - task_id="trigger_dagrun_op2", execution_date="2024-12-04" - ) + trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") 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( - task_id="dof_task_sensor", use_task_execution_day=True - ) - dof_task_sensor2 = DayOfWeekSensor( - task_id="dof_task_sensor2", use_task_execution_day=True - ) + dof_task_sensor = weekday.DayOfWeekSensor(task_id="dof_task_sensor", use_task_execution_day=True) + dof_task_sensor2 = DayOfWeekSensor(task_id="dof_task_sensor2", use_task_execution_day=True) - bdow_op = weekday.BranchDayOfWeekOperator( - task_id="bdow_op", use_task_execution_day=True - ) + bdow_op = weekday.BranchDayOfWeekOperator(task_id="bdow_op", use_task_execution_day=True) bdow_op2 = BranchDayOfWeekOperator(task_id="bdow_op2", use_task_execution_day=True) trigger_dagrun_op >> trigger_dagrun_op2 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 96fe5603f715e..d5fb4a88ba0b8 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 @@ -7,8 +7,8 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -fn is_airflow_secret_backend(qualname: &QualifiedName) -> bool { - match qualname.segments() { +fn is_airflow_secret_backend(segments: &[&str]) -> bool { + match segments { ["airflow", "secrets", rest @ ..] => { if let Some(last_element) = rest.last() { last_element.ends_with("Backend") @@ -18,11 +18,10 @@ fn is_airflow_secret_backend(qualname: &QualifiedName) -> bool { } ["airflow", "providers", rest @ ..] => { - // Ensure 'operators' exists somewhere in the middle if let (Some(pos), Some(last_element)) = (rest.iter().position(|&s| s == "secrets"), rest.last()) { - pos + 1 < rest.len() && last_element.ends_with("Backend") // Check that 'operators' is not the last element + pos + 1 < rest.len() && last_element.ends_with("Backend") } else { false } @@ -43,7 +42,6 @@ fn is_airflow_hook(qualname: &QualifiedName) -> bool { } ["airflow", "providers", rest @ ..] => { - // Ensure 'operators' exists somewhere in the middle if let (Some(pos), Some(last_element)) = (rest.iter().position(|&s| s == "hooks"), rest.last()) { @@ -57,6 +55,30 @@ fn is_airflow_hook(qualname: &QualifiedName) -> bool { } } +fn is_airflow_operator(segments: &[&str]) -> bool { + match segments { + ["airflow", "operators", rest @ ..] => { + if let Some(last_element) = rest.last() { + last_element.ends_with("Operator") + } else { + false + } + } + + ["airflow", "providers", rest @ ..] => { + if let (Some(pos), Some(last_element)) = + (rest.iter().position(|&s| s == "operators"), rest.last()) + { + pos + 1 < rest.len() && last_element.ends_with("Operator") + } else { + false + } + } + + _ => false, + } +} + #[derive(Debug, Eq, PartialEq)] enum Replacement { None, @@ -173,34 +195,50 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: None::<&str>, )); } - ["airflow", .., "operators", "trigger_dagrun", "TriggerDagRunOperator"] => { + _ if is_airflow_operator(qualname.segments()) => { checker.diagnostics.extend(diagnostic_for_argument( arguments, - "execution_date", + "sla", 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"), + "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"), + )); + } + _ => {} + } } + _ => {} }; } @@ -286,7 +324,7 @@ fn removed_method(checker: &mut Checker, expr: &Expr) { "iter_dataset_aliases" => Some(Replacement::Name("iter_asset_aliases")), &_ => None, }, - _ if is_airflow_secret_backend(&qualname) => match attr.as_str() { + _ 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, 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 bd90b530f0883..763d7f11c0f7b 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,217 @@ 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:13: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") +11 | DAG(dag_id="class_schedule", schedule="@hourly") +12 | +13 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") | ^^^^^^^^^^^^^^^^^ AIR302 -16 | -17 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +14 | +15 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | = help: Use `schedule` instead ℹ Safe fix +10 10 | +11 11 | DAG(dag_id="class_schedule", schedule="@hourly") 12 12 | -13 13 | DAG(dag_id="class_schedule", schedule="@hourly") +13 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") + 13 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") 14 14 | -15 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") - 15 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") +15 15 | DAG(dag_id="class_timetable", timetable=NullTimetable()) 16 16 | -17 17 | DAG(dag_id="class_timetable", timetable=NullTimetable()) -18 18 | -AIR302_args.py:17:31: AIR302 [*] `timetable` is removed in Airflow 3.0 +AIR302_args.py:15: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()) +13 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +14 | +15 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | ^^^^^^^^^ AIR302 | = help: Use `schedule` instead ℹ Safe fix +12 12 | +13 13 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") 14 14 | -15 15 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +15 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) + 15 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) 16 16 | -17 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) - 17 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) -18 18 | -19 19 | -20 20 | def sla_callback(*arg, **kwargs): +17 17 | +18 18 | def sla_callback(*arg, **kwargs): -AIR302_args.py:24:34: AIR302 `sla_miss_callback` is removed in Airflow 3.0 +AIR302_args.py:22:34: AIR302 `sla_miss_callback` is removed in Airflow 3.0 | -24 | DAG(dag_id="class_sla_callback", sla_miss_callback=sla_callback) +22 | 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:30:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -32 | @dag(schedule_interval="0 * * * *") +30 | @dag(schedule_interval="0 * * * *") | ^^^^^^^^^^^^^^^^^ AIR302 -33 | def decorator_schedule_interval(): -34 | pass +31 | def decorator_schedule_interval(): +32 | 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 | - -AIR302_args.py:37:6: AIR302 [*] `timetable` is removed in Airflow 3.0 - | -37 | @dag(timetable=NullTimetable()) +27 27 | pass +28 28 | +29 29 | +30 |-@dag(schedule_interval="0 * * * *") + 30 |+@dag(schedule="0 * * * *") +31 31 | def decorator_schedule_interval(): +32 32 | pass +33 33 | + +AIR302_args.py:35:6: AIR302 [*] `timetable` is removed in Airflow 3.0 + | +35 | @dag(timetable=NullTimetable()) | ^^^^^^^^^ AIR302 -38 | def decorator_timetable(): -39 | pass +36 | def decorator_timetable(): +37 | 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 | - -AIR302_args.py:42:6: AIR302 `sla_miss_callback` is removed in Airflow 3.0 - | -42 | @dag(sla_miss_callback=sla_callback) +32 32 | pass +33 33 | +34 34 | +35 |-@dag(timetable=NullTimetable()) + 35 |+@dag(schedule=NullTimetable()) +36 36 | def decorator_timetable(): +37 37 | pass +38 38 | + +AIR302_args.py:40:6: AIR302 `sla_miss_callback` is removed in Airflow 3.0 + | +40 | @dag(sla_miss_callback=sla_callback) | ^^^^^^^^^^^^^^^^^ AIR302 -43 | def decorator_sla_callback(): -44 | pass +41 | def decorator_sla_callback(): +42 | pass | -AIR302_args.py:50:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 +AIR302_args.py:48: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" +46 | def decorator_deprecated_operator_args(): +47 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +48 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" | ^^^^^^^^^^^^^^ AIR302 -51 | ) -52 | trigger_dagrun_op2 = TriggerDagRunOperator( +49 | ) +50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") | = 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" - | ^^^^^^^^^^^^^^ AIR302 -54 | ) +45 45 | @dag() +46 46 | def decorator_deprecated_operator_args(): +47 47 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +48 |- task_id="trigger_dagrun_op1", execution_date="2024-12-04" + 48 |+ task_id="trigger_dagrun_op1", logical_date="2024-12-04" +49 49 | ) +50 50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +51 51 | + +AIR302_args.py:50:78: AIR302 [*] `execution_date` is removed in Airflow 3.0 + | +48 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" +49 | ) +50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") + | ^^^^^^^^^^^^^^ AIR302 +51 | +52 | branch_dt_op = datetime.BranchDateTimeOperator( | = 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" +47 47 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +48 48 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" +49 49 | ) +50 |- trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") + 50 |+ trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", logical_date="2024-12-04") +51 51 | +52 52 | branch_dt_op = datetime.BranchDateTimeOperator( +53 53 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + +AIR302_args.py:53:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 + | +52 | branch_dt_op = datetime.BranchDateTimeOperator( +53 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 +54 | ) +55 | branch_dt_op2 = BranchDateTimeOperator( + | + = help: Use `use_task_logical_date` instead + +ℹ Safe fix +50 50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +51 51 | +52 52 | branch_dt_op = datetime.BranchDateTimeOperator( +53 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + 53 |+ task_id="branch_dt_op", use_task_logical_date=True, task_concurrency=5 54 54 | ) -55 55 | -56 56 | branch_dt_op = datetime.BranchDateTimeOperator( +55 55 | branch_dt_op2 = BranchDateTimeOperator( +56 56 | task_id="branch_dt_op2", -AIR302_args.py:57:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 +AIR302_args.py:53:62: AIR302 [*] `task_concurrency` is removed in Airflow 3.0 | -56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 | task_id="branch_dt_op", use_task_execution_day=True - | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -58 | ) -59 | branch_dt_op2 = BranchDateTimeOperator( +52 | branch_dt_op = datetime.BranchDateTimeOperator( +53 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + | ^^^^^^^^^^^^^^^^ AIR302 +54 | ) +55 | branch_dt_op2 = BranchDateTimeOperator( | - = help: Use `use_task_logical_date` instead + = help: Use `max_active_tis_per_dag` instead ℹ Safe fix +50 50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +51 51 | +52 52 | branch_dt_op = datetime.BranchDateTimeOperator( +53 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + 53 |+ task_id="branch_dt_op", use_task_execution_day=True, max_active_tis_per_dag=5 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 | ) +55 55 | branch_dt_op2 = BranchDateTimeOperator( +56 56 | task_id="branch_dt_op2", + +AIR302_args.py:57:9: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 + | +55 | branch_dt_op2 = BranchDateTimeOperator( +56 | task_id="branch_dt_op2", +57 | use_task_execution_day=True, + | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 +58 | sla=timedelta(seconds=10), +59 | ) | = 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 -61 61 | ) -62 62 | -63 63 | dof_task_sensor = weekday.DayOfWeekSensor( +54 54 | ) +55 55 | branch_dt_op2 = BranchDateTimeOperator( +56 56 | task_id="branch_dt_op2", +57 |- use_task_execution_day=True, + 57 |+ use_task_logical_date=True, +58 58 | sla=timedelta(seconds=10), +59 59 | ) +60 60 | + +AIR302_args.py:58:9: AIR302 [*] `sla` is removed in Airflow 3.0 + | +56 | task_id="branch_dt_op2", +57 | use_task_execution_day=True, +58 | sla=timedelta(seconds=10), + | ^^^ AIR302 +59 | ) + | + = help: Use `logical_date` instead + +ℹ Safe fix +55 55 | branch_dt_op2 = BranchDateTimeOperator( +56 56 | task_id="branch_dt_op2", +57 57 | use_task_execution_day=True, +58 |- sla=timedelta(seconds=10), + 58 |+ logical_date=timedelta(seconds=10), +59 59 | ) +60 60 | +61 61 | dof_task_sensor = weekday.DayOfWeekSensor(task_id="dof_task_sensor", use_task_execution_day=True) From 39d545b738205bc07c989a12517827c67c9fee4b Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 25 Dec 2024 17:38:27 +0900 Subject: [PATCH 05/12] feat(AIR302): argument "filename_template" is removed in task handlers --- .../test/fixtures/airflow/AIR302_args.py | 11 + .../src/rules/airflow/rules/removal_in_3.rs | 29 +- ...airflow__tests__AIR302_AIR302_args.py.snap | 313 ++++++++++-------- 3 files changed, 206 insertions(+), 147 deletions(-) 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 2432725e78ac9..1ed4516b112a8 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py @@ -3,6 +3,10 @@ from airflow import DAG, dag from airflow.operators.datetime import BranchDateTimeOperator 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.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 @@ -68,3 +72,10 @@ 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") 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 d5fb4a88ba0b8..5a3fd3a3d5d02 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 @@ -79,6 +79,24 @@ fn is_airflow_operator(segments: &[&str]) -> bool { } } +fn is_airflow_task_handler(segments: &[&str]) -> bool { + match segments { + ["airflow", "utils", "log", "file_task_handler", "FileTaskHandler"] => true, + + ["airflow", "providers", rest @ ..] => { + if let (Some(pos), Some(last_element)) = + (rest.iter().position(|&s| s == "log"), rest.last()) + { + pos + 1 < rest.len() && last_element.ends_with("TaskHandler") + } else { + false + } + } + + _ => false, + } +} + #[derive(Debug, Eq, PartialEq)] enum Replacement { None, @@ -195,12 +213,17 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: None::<&str>, )); } - _ if is_airflow_operator(qualname.segments()) => { + _ if is_airflow_task_handler(qualname.segments()) => { checker.diagnostics.extend(diagnostic_for_argument( arguments, - "sla", - Some("logical_date"), + "filename_template", + None::<&str>, )); + } + _ 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", 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 763d7f11c0f7b..6352746dedb09 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,217 +2,242 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs snapshot_kind: text --- -AIR302_args.py:13:39: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_args.py:17:39: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -11 | DAG(dag_id="class_schedule", schedule="@hourly") -12 | -13 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +15 | DAG(dag_id="class_schedule", schedule="@hourly") +16 | +17 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") | ^^^^^^^^^^^^^^^^^ AIR302 -14 | -15 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +18 | +19 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | = help: Use `schedule` instead ℹ Safe fix -10 10 | -11 11 | DAG(dag_id="class_schedule", schedule="@hourly") -12 12 | -13 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") - 13 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") 14 14 | -15 15 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +15 15 | DAG(dag_id="class_schedule", schedule="@hourly") 16 16 | +17 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") + 17 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") +18 18 | +19 19 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +20 20 | -AIR302_args.py:15:31: AIR302 [*] `timetable` is removed in Airflow 3.0 +AIR302_args.py:19:31: AIR302 [*] `timetable` is removed in Airflow 3.0 | -13 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") -14 | -15 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +17 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +18 | +19 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | ^^^^^^^^^ AIR302 | = help: Use `schedule` instead ℹ Safe fix -12 12 | -13 13 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") -14 14 | -15 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) - 15 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) 16 16 | -17 17 | -18 18 | def sla_callback(*arg, **kwargs): +17 17 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +18 18 | +19 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) + 19 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) +20 20 | +21 21 | +22 22 | def sla_callback(*arg, **kwargs): -AIR302_args.py:22:34: AIR302 `sla_miss_callback` is removed in Airflow 3.0 +AIR302_args.py:26:34: AIR302 `sla_miss_callback` is removed in Airflow 3.0 | -22 | DAG(dag_id="class_sla_callback", sla_miss_callback=sla_callback) +26 | DAG(dag_id="class_sla_callback", sla_miss_callback=sla_callback) | ^^^^^^^^^^^^^^^^^ AIR302 | -AIR302_args.py:30:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_args.py:34:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -30 | @dag(schedule_interval="0 * * * *") +34 | @dag(schedule_interval="0 * * * *") | ^^^^^^^^^^^^^^^^^ AIR302 -31 | def decorator_schedule_interval(): -32 | pass +35 | def decorator_schedule_interval(): +36 | pass | = help: Use `schedule` instead ℹ Safe fix -27 27 | pass -28 28 | -29 29 | -30 |-@dag(schedule_interval="0 * * * *") - 30 |+@dag(schedule="0 * * * *") -31 31 | def decorator_schedule_interval(): -32 32 | pass +31 31 | pass +32 32 | 33 33 | +34 |-@dag(schedule_interval="0 * * * *") + 34 |+@dag(schedule="0 * * * *") +35 35 | def decorator_schedule_interval(): +36 36 | pass +37 37 | -AIR302_args.py:35:6: AIR302 [*] `timetable` is removed in Airflow 3.0 +AIR302_args.py:39:6: AIR302 [*] `timetable` is removed in Airflow 3.0 | -35 | @dag(timetable=NullTimetable()) +39 | @dag(timetable=NullTimetable()) | ^^^^^^^^^ AIR302 -36 | def decorator_timetable(): -37 | pass +40 | def decorator_timetable(): +41 | pass | = help: Use `schedule` instead ℹ Safe fix -32 32 | pass -33 33 | -34 34 | -35 |-@dag(timetable=NullTimetable()) - 35 |+@dag(schedule=NullTimetable()) -36 36 | def decorator_timetable(): -37 37 | pass +36 36 | pass +37 37 | 38 38 | +39 |-@dag(timetable=NullTimetable()) + 39 |+@dag(schedule=NullTimetable()) +40 40 | def decorator_timetable(): +41 41 | pass +42 42 | -AIR302_args.py:40:6: AIR302 `sla_miss_callback` is removed in Airflow 3.0 +AIR302_args.py:44:6: AIR302 `sla_miss_callback` is removed in Airflow 3.0 | -40 | @dag(sla_miss_callback=sla_callback) +44 | @dag(sla_miss_callback=sla_callback) | ^^^^^^^^^^^^^^^^^ AIR302 -41 | def decorator_sla_callback(): -42 | pass +45 | def decorator_sla_callback(): +46 | pass | -AIR302_args.py:48:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 +AIR302_args.py:52:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 | -46 | def decorator_deprecated_operator_args(): -47 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -48 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" +50 | def decorator_deprecated_operator_args(): +51 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +52 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" | ^^^^^^^^^^^^^^ AIR302 -49 | ) -50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +53 | ) +54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") | = help: Use `logical_date` instead ℹ Safe fix -45 45 | @dag() -46 46 | def decorator_deprecated_operator_args(): -47 47 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -48 |- task_id="trigger_dagrun_op1", execution_date="2024-12-04" - 48 |+ task_id="trigger_dagrun_op1", logical_date="2024-12-04" -49 49 | ) -50 50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") -51 51 | - -AIR302_args.py:50:78: AIR302 [*] `execution_date` is removed in Airflow 3.0 - | -48 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" -49 | ) -50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +49 49 | @dag() +50 50 | def decorator_deprecated_operator_args(): +51 51 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +52 |- task_id="trigger_dagrun_op1", execution_date="2024-12-04" + 52 |+ task_id="trigger_dagrun_op1", logical_date="2024-12-04" +53 53 | ) +54 54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +55 55 | + +AIR302_args.py:54:78: AIR302 [*] `execution_date` is removed in Airflow 3.0 + | +52 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" +53 | ) +54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") | ^^^^^^^^^^^^^^ AIR302 -51 | -52 | branch_dt_op = datetime.BranchDateTimeOperator( +55 | +56 | branch_dt_op = datetime.BranchDateTimeOperator( | = help: Use `logical_date` instead ℹ Safe fix -47 47 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -48 48 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" -49 49 | ) -50 |- trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") - 50 |+ trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", logical_date="2024-12-04") -51 51 | -52 52 | branch_dt_op = datetime.BranchDateTimeOperator( -53 53 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 - -AIR302_args.py:53:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 - | -52 | branch_dt_op = datetime.BranchDateTimeOperator( -53 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 +51 51 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( +52 52 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" +53 53 | ) +54 |- trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") + 54 |+ trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", logical_date="2024-12-04") +55 55 | +56 56 | branch_dt_op = datetime.BranchDateTimeOperator( +57 57 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + +AIR302_args.py:57:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 + | +56 | branch_dt_op = datetime.BranchDateTimeOperator( +57 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -54 | ) -55 | branch_dt_op2 = BranchDateTimeOperator( +58 | ) +59 | branch_dt_op2 = BranchDateTimeOperator( | = help: Use `use_task_logical_date` instead ℹ Safe fix -50 50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") -51 51 | -52 52 | branch_dt_op = datetime.BranchDateTimeOperator( -53 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 - 53 |+ task_id="branch_dt_op", use_task_logical_date=True, task_concurrency=5 -54 54 | ) -55 55 | branch_dt_op2 = BranchDateTimeOperator( -56 56 | task_id="branch_dt_op2", - -AIR302_args.py:53:62: AIR302 [*] `task_concurrency` is removed in Airflow 3.0 - | -52 | branch_dt_op = datetime.BranchDateTimeOperator( -53 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 +54 54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +55 55 | +56 56 | branch_dt_op = datetime.BranchDateTimeOperator( +57 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + 57 |+ task_id="branch_dt_op", use_task_logical_date=True, task_concurrency=5 +58 58 | ) +59 59 | branch_dt_op2 = BranchDateTimeOperator( +60 60 | task_id="branch_dt_op2", + +AIR302_args.py:57:62: AIR302 [*] `task_concurrency` is removed in Airflow 3.0 + | +56 | branch_dt_op = datetime.BranchDateTimeOperator( +57 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 | ^^^^^^^^^^^^^^^^ AIR302 -54 | ) -55 | branch_dt_op2 = BranchDateTimeOperator( +58 | ) +59 | branch_dt_op2 = BranchDateTimeOperator( | = help: Use `max_active_tis_per_dag` instead ℹ Safe fix -50 50 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") -51 51 | -52 52 | branch_dt_op = datetime.BranchDateTimeOperator( -53 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 - 53 |+ task_id="branch_dt_op", use_task_execution_day=True, max_active_tis_per_dag=5 -54 54 | ) -55 55 | branch_dt_op2 = BranchDateTimeOperator( -56 56 | task_id="branch_dt_op2", - -AIR302_args.py:57:9: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 - | -55 | branch_dt_op2 = BranchDateTimeOperator( -56 | task_id="branch_dt_op2", -57 | use_task_execution_day=True, +54 54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +55 55 | +56 56 | branch_dt_op = datetime.BranchDateTimeOperator( +57 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 + 57 |+ task_id="branch_dt_op", use_task_execution_day=True, max_active_tis_per_dag=5 +58 58 | ) +59 59 | branch_dt_op2 = BranchDateTimeOperator( +60 60 | task_id="branch_dt_op2", + +AIR302_args.py:61:9: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 + | +59 | branch_dt_op2 = BranchDateTimeOperator( +60 | task_id="branch_dt_op2", +61 | use_task_execution_day=True, | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -58 | sla=timedelta(seconds=10), -59 | ) +62 | sla=timedelta(seconds=10), +63 | ) | = help: Use `use_task_logical_date` instead ℹ Safe fix -54 54 | ) -55 55 | branch_dt_op2 = BranchDateTimeOperator( -56 56 | task_id="branch_dt_op2", -57 |- use_task_execution_day=True, - 57 |+ use_task_logical_date=True, -58 58 | sla=timedelta(seconds=10), -59 59 | ) -60 60 | - -AIR302_args.py:58:9: AIR302 [*] `sla` is removed in Airflow 3.0 - | -56 | task_id="branch_dt_op2", -57 | use_task_execution_day=True, -58 | sla=timedelta(seconds=10), +58 58 | ) +59 59 | branch_dt_op2 = BranchDateTimeOperator( +60 60 | task_id="branch_dt_op2", +61 |- use_task_execution_day=True, + 61 |+ use_task_logical_date=True, +62 62 | sla=timedelta(seconds=10), +63 63 | ) +64 64 | + +AIR302_args.py:62:9: AIR302 `sla` is removed in Airflow 3.0 + | +60 | task_id="branch_dt_op2", +61 | use_task_execution_day=True, +62 | sla=timedelta(seconds=10), | ^^^ AIR302 -59 | ) +63 | ) | - = help: Use `logical_date` instead -ℹ Safe fix -55 55 | branch_dt_op2 = BranchDateTimeOperator( -56 56 | task_id="branch_dt_op2", -57 57 | use_task_execution_day=True, -58 |- sla=timedelta(seconds=10), - 58 |+ logical_date=timedelta(seconds=10), -59 59 | ) -60 60 | -61 61 | dof_task_sensor = weekday.DayOfWeekSensor(task_id="dof_task_sensor", use_task_execution_day=True) +AIR302_args.py:78:15: AIR302 `filename_template` is removed in Airflow 3.0 + | +77 | # deprecated filename_template arugment in FileTaskHandler +78 | S3TaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +79 | HdfsTaskHandler(filename_template="/tmp/test") +80 | ElasticsearchTaskHandler(filename_template="/tmp/test") + | + +AIR302_args.py:79:17: AIR302 `filename_template` is removed in Airflow 3.0 + | +77 | # deprecated filename_template arugment in FileTaskHandler +78 | S3TaskHandler(filename_template="/tmp/test") +79 | HdfsTaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +80 | ElasticsearchTaskHandler(filename_template="/tmp/test") +81 | GCSTaskHandler(filename_template="/tmp/test") + | + +AIR302_args.py:80:26: AIR302 `filename_template` is removed in Airflow 3.0 + | +78 | S3TaskHandler(filename_template="/tmp/test") +79 | HdfsTaskHandler(filename_template="/tmp/test") +80 | ElasticsearchTaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 +81 | GCSTaskHandler(filename_template="/tmp/test") + | + +AIR302_args.py:81:16: AIR302 `filename_template` is removed in Airflow 3.0 + | +79 | HdfsTaskHandler(filename_template="/tmp/test") +80 | ElasticsearchTaskHandler(filename_template="/tmp/test") +81 | GCSTaskHandler(filename_template="/tmp/test") + | ^^^^^^^^^^^^^^^^^ AIR302 + | From 316126cf3890fe40fb63d36d3986f497817593cf Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 26 Dec 2024 10:51:50 +0900 Subject: [PATCH 06/12] feat(AIR302): extension "executors", "operators", "sensors", "hooks" have been removed in AirflowPlugin --- .../fixtures/airflow/AIR302_airflow_plugin.py | 29 ++++++++++++ .../src/checkers/ast/analyze/expression.rs | 3 ++ crates/ruff_linter/src/rules/airflow/mod.rs | 1 + .../src/rules/airflow/rules/removal_in_3.rs | 46 ++++++++++++++++++- ...ests__AIR302_AIR302_airflow_plugin.py.snap | 43 +++++++++++++++++ 5 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/airflow/AIR302_airflow_plugin.py create mode 100644 crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_airflow_plugin.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 0000000000000..117c691eca97b --- /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/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 052d54d652430..64ab6a448b9b1 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 0eafbda606b8a..2f2e7dded7bb0 100644 --- a/crates/ruff_linter/src/rules/airflow/mod.rs +++ b/crates/ruff_linter/src/rules/airflow/mod.rs @@ -17,6 +17,7 @@ mod tests { #[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 5a3fd3a3d5d02..5dbfbbfc3d6f9 100644 --- a/crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs +++ b/crates/ruff_linter/src/rules/airflow/rules/removal_in_3.rs @@ -1,8 +1,12 @@ 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; @@ -806,6 +810,37 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { } } +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(), + )); + } + } +} + /// AIR302 pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { if !checker.semantic().seen_module(Modules::AIRFLOW) { @@ -826,7 +861,14 @@ pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { removed_name(checker, expr, ranged); removed_class_attribute(checker, expr); } - ranged @ Expr::Name(_) => removed_name(checker, expr, ranged), + 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); + } + } + } _ => {} } } 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 0000000000000..e94bafe216c1c --- /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] + | From 7ca2d283c101fe01a172119c629603fbfa8a7cee Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 26 Dec 2024 17:06:29 +0900 Subject: [PATCH 07/12] feat(AIR302): argument appbuilder is now removed in BaseAuthManager and its subclasses --- .../test/fixtures/airflow/AIR302_args.py | 19 +- .../src/rules/airflow/rules/removal_in_3.rs | 38 ++ ...airflow__tests__AIR302_AIR302_args.py.snap | 327 +++++++++--------- 3 files changed, 221 insertions(+), 163 deletions(-) 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 1ed4516b112a8..6955295b799f5 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_args.py @@ -6,6 +6,7 @@ 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 @@ -51,7 +52,9 @@ def decorator_deprecated_operator_args(): trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( task_id="trigger_dagrun_op1", execution_date="2024-12-04" ) - trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") + trigger_dagrun_op2 = TriggerDagRunOperator( + task_id="trigger_dagrun_op2", execution_date="2024-12-04" + ) branch_dt_op = datetime.BranchDateTimeOperator( task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 @@ -62,10 +65,16 @@ def decorator_deprecated_operator_args(): sla=timedelta(seconds=10), ) - dof_task_sensor = weekday.DayOfWeekSensor(task_id="dof_task_sensor", use_task_execution_day=True) - dof_task_sensor2 = DayOfWeekSensor(task_id="dof_task_sensor2", use_task_execution_day=True) + dof_task_sensor = weekday.DayOfWeekSensor( + task_id="dof_task_sensor", use_task_execution_day=True + ) + dof_task_sensor2 = DayOfWeekSensor( + task_id="dof_task_sensor2", use_task_execution_day=True + ) - bdow_op = weekday.BranchDayOfWeekOperator(task_id="bdow_op", use_task_execution_day=True) + bdow_op = weekday.BranchDayOfWeekOperator( + task_id="bdow_op", use_task_execution_day=True + ) bdow_op2 = BranchDayOfWeekOperator(task_id="bdow_op2", use_task_execution_day=True) trigger_dagrun_op >> trigger_dagrun_op2 @@ -79,3 +88,5 @@ def decorator_deprecated_operator_args(): HdfsTaskHandler(filename_template="/tmp/test") ElasticsearchTaskHandler(filename_template="/tmp/test") GCSTaskHandler(filename_template="/tmp/test") + +FabAuthManager(None) 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 5dbfbbfc3d6f9..063a0f38ae23b 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 @@ -35,6 +35,30 @@ fn is_airflow_secret_backend(segments: &[&str]) -> bool { } } +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, + } +} + fn is_airflow_hook(qualname: &QualifiedName) -> bool { match qualname.segments() { ["airflow", "hooks", rest @ ..] => { @@ -217,6 +241,20 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: None::<&str>, )); } + _ 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(), + )); + } + } _ if is_airflow_task_handler(qualname.segments()) => { checker.diagnostics.extend(diagnostic_for_argument( arguments, 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 6352746dedb09..39a4da150e591 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,242 +2,251 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs snapshot_kind: text --- -AIR302_args.py:17:39: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_args.py:18:39: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -15 | DAG(dag_id="class_schedule", schedule="@hourly") -16 | -17 | 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 -18 | -19 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +19 | +20 | DAG(dag_id="class_timetable", timetable=NullTimetable()) | = help: Use `schedule` instead ℹ Safe fix -14 14 | -15 15 | DAG(dag_id="class_schedule", schedule="@hourly") -16 16 | -17 |-DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") - 17 |+DAG(dag_id="class_schedule_interval", schedule="@hourly") -18 18 | -19 19 | DAG(dag_id="class_timetable", timetable=NullTimetable()) -20 20 | - -AIR302_args.py:19:31: AIR302 [*] `timetable` is removed in Airflow 3.0 - | -17 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") -18 | -19 | DAG(dag_id="class_timetable", timetable=NullTimetable()) +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:20:31: AIR302 [*] `timetable` is removed in Airflow 3.0 + | +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 -16 16 | -17 17 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") -18 18 | -19 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) - 19 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) -20 20 | +17 17 | +18 18 | DAG(dag_id="class_schedule_interval", schedule_interval="@hourly") +19 19 | +20 |-DAG(dag_id="class_timetable", timetable=NullTimetable()) + 20 |+DAG(dag_id="class_timetable", schedule=NullTimetable()) 21 21 | -22 22 | def sla_callback(*arg, **kwargs): +22 22 | +23 23 | def sla_callback(*arg, **kwargs): -AIR302_args.py:26: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 | -26 | 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:34:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 +AIR302_args.py:35:6: AIR302 [*] `schedule_interval` is removed in Airflow 3.0 | -34 | @dag(schedule_interval="0 * * * *") +35 | @dag(schedule_interval="0 * * * *") | ^^^^^^^^^^^^^^^^^ AIR302 -35 | def decorator_schedule_interval(): -36 | pass +36 | def decorator_schedule_interval(): +37 | pass | = help: Use `schedule` instead ℹ Safe fix -31 31 | pass -32 32 | +32 32 | pass 33 33 | -34 |-@dag(schedule_interval="0 * * * *") - 34 |+@dag(schedule="0 * * * *") -35 35 | def decorator_schedule_interval(): -36 36 | pass -37 37 | +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:39:6: AIR302 [*] `timetable` is removed in Airflow 3.0 +AIR302_args.py:40:6: AIR302 [*] `timetable` is removed in Airflow 3.0 | -39 | @dag(timetable=NullTimetable()) +40 | @dag(timetable=NullTimetable()) | ^^^^^^^^^ AIR302 -40 | def decorator_timetable(): -41 | pass +41 | def decorator_timetable(): +42 | pass | = help: Use `schedule` instead ℹ Safe fix -36 36 | pass -37 37 | +37 37 | pass 38 38 | -39 |-@dag(timetable=NullTimetable()) - 39 |+@dag(schedule=NullTimetable()) -40 40 | def decorator_timetable(): -41 41 | pass -42 42 | +39 39 | +40 |-@dag(timetable=NullTimetable()) + 40 |+@dag(schedule=NullTimetable()) +41 41 | def decorator_timetable(): +42 42 | pass +43 43 | -AIR302_args.py:44: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 | -44 | @dag(sla_miss_callback=sla_callback) +45 | @dag(sla_miss_callback=sla_callback) | ^^^^^^^^^^^^^^^^^ AIR302 -45 | def decorator_sla_callback(): -46 | pass +46 | def decorator_sla_callback(): +47 | pass | -AIR302_args.py:52:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 +AIR302_args.py:53:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 | -50 | def decorator_deprecated_operator_args(): -51 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -52 | task_id="trigger_dagrun_op1", 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 -53 | ) -54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") +54 | ) +55 | trigger_dagrun_op2 = TriggerDagRunOperator( | = help: Use `logical_date` instead ℹ Safe fix -49 49 | @dag() -50 50 | def decorator_deprecated_operator_args(): -51 51 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -52 |- task_id="trigger_dagrun_op1", execution_date="2024-12-04" - 52 |+ task_id="trigger_dagrun_op1", logical_date="2024-12-04" -53 53 | ) -54 54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") -55 55 | - -AIR302_args.py:54:78: AIR302 [*] `execution_date` is removed in Airflow 3.0 - | -52 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" -53 | ) -54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") - | ^^^^^^^^^^^^^^ AIR302 -55 | -56 | branch_dt_op = datetime.BranchDateTimeOperator( +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 | trigger_dagrun_op2 = TriggerDagRunOperator( +56 56 | task_id="trigger_dagrun_op2", execution_date="2024-12-04" + +AIR302_args.py:56:39: AIR302 [*] `execution_date` is removed in Airflow 3.0 + | +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 -51 51 | trigger_dagrun_op = trigger_dagrun.TriggerDagRunOperator( -52 52 | task_id="trigger_dagrun_op1", execution_date="2024-12-04" -53 53 | ) -54 |- trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") - 54 |+ trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", logical_date="2024-12-04") -55 55 | -56 56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 57 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 - -AIR302_args.py:57:33: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 - | -56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 +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( +61 | ) +62 | branch_dt_op2 = BranchDateTimeOperator( | = help: Use `use_task_logical_date` instead ℹ Safe fix -54 54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") -55 55 | -56 56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 - 57 |+ task_id="branch_dt_op", use_task_logical_date=True, task_concurrency=5 -58 58 | ) -59 59 | branch_dt_op2 = BranchDateTimeOperator( -60 60 | task_id="branch_dt_op2", - -AIR302_args.py:57:62: AIR302 [*] `task_concurrency` is removed in Airflow 3.0 - | -56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 | task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 +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 | 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 -58 | ) -59 | branch_dt_op2 = BranchDateTimeOperator( +61 | ) +62 | branch_dt_op2 = BranchDateTimeOperator( | = help: Use `max_active_tis_per_dag` instead ℹ Safe fix -54 54 | trigger_dagrun_op2 = TriggerDagRunOperator(task_id="trigger_dagrun_op2", execution_date="2024-12-04") -55 55 | -56 56 | branch_dt_op = datetime.BranchDateTimeOperator( -57 |- task_id="branch_dt_op", use_task_execution_day=True, task_concurrency=5 - 57 |+ task_id="branch_dt_op", use_task_execution_day=True, max_active_tis_per_dag=5 -58 58 | ) -59 59 | branch_dt_op2 = BranchDateTimeOperator( -60 60 | task_id="branch_dt_op2", - -AIR302_args.py:61:9: AIR302 [*] `use_task_execution_day` is removed in Airflow 3.0 - | -59 | branch_dt_op2 = BranchDateTimeOperator( -60 | task_id="branch_dt_op2", -61 | use_task_execution_day=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_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 -62 | sla=timedelta(seconds=10), -63 | ) +65 | sla=timedelta(seconds=10), +66 | ) | = help: Use `use_task_logical_date` instead ℹ Safe fix -58 58 | ) -59 59 | branch_dt_op2 = BranchDateTimeOperator( -60 60 | task_id="branch_dt_op2", -61 |- use_task_execution_day=True, - 61 |+ use_task_logical_date=True, -62 62 | sla=timedelta(seconds=10), -63 63 | ) -64 64 | - -AIR302_args.py:62:9: AIR302 `sla` is removed in Airflow 3.0 - | -60 | task_id="branch_dt_op2", -61 | use_task_execution_day=True, -62 | sla=timedelta(seconds=10), +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 -63 | ) +66 | ) | -AIR302_args.py:78:15: AIR302 `filename_template` is removed in Airflow 3.0 +AIR302_args.py:87:15: AIR302 `filename_template` is removed in Airflow 3.0 | -77 | # deprecated filename_template arugment in FileTaskHandler -78 | S3TaskHandler(filename_template="/tmp/test") +86 | # deprecated filename_template arugment in FileTaskHandler +87 | S3TaskHandler(filename_template="/tmp/test") | ^^^^^^^^^^^^^^^^^ AIR302 -79 | HdfsTaskHandler(filename_template="/tmp/test") -80 | ElasticsearchTaskHandler(filename_template="/tmp/test") +88 | HdfsTaskHandler(filename_template="/tmp/test") +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") | -AIR302_args.py:79:17: AIR302 `filename_template` is removed in Airflow 3.0 +AIR302_args.py:88:17: AIR302 `filename_template` is removed in Airflow 3.0 | -77 | # deprecated filename_template arugment in FileTaskHandler -78 | S3TaskHandler(filename_template="/tmp/test") -79 | HdfsTaskHandler(filename_template="/tmp/test") +86 | # deprecated filename_template arugment in FileTaskHandler +87 | S3TaskHandler(filename_template="/tmp/test") +88 | HdfsTaskHandler(filename_template="/tmp/test") | ^^^^^^^^^^^^^^^^^ AIR302 -80 | ElasticsearchTaskHandler(filename_template="/tmp/test") -81 | GCSTaskHandler(filename_template="/tmp/test") +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") +90 | GCSTaskHandler(filename_template="/tmp/test") | -AIR302_args.py:80:26: AIR302 `filename_template` is removed in Airflow 3.0 +AIR302_args.py:89:26: AIR302 `filename_template` is removed in Airflow 3.0 | -78 | S3TaskHandler(filename_template="/tmp/test") -79 | HdfsTaskHandler(filename_template="/tmp/test") -80 | ElasticsearchTaskHandler(filename_template="/tmp/test") +87 | S3TaskHandler(filename_template="/tmp/test") +88 | HdfsTaskHandler(filename_template="/tmp/test") +89 | ElasticsearchTaskHandler(filename_template="/tmp/test") | ^^^^^^^^^^^^^^^^^ AIR302 -81 | GCSTaskHandler(filename_template="/tmp/test") +90 | GCSTaskHandler(filename_template="/tmp/test") | -AIR302_args.py:81:16: AIR302 `filename_template` is removed in Airflow 3.0 +AIR302_args.py:90:16: AIR302 `filename_template` is removed in Airflow 3.0 | -79 | HdfsTaskHandler(filename_template="/tmp/test") -80 | ElasticsearchTaskHandler(filename_template="/tmp/test") -81 | GCSTaskHandler(filename_template="/tmp/test") +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 | From 8026d7712ce6d479efa9f261a276a058ba7f4799 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 27 Dec 2024 20:45:20 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat(AIR302):=20airflow.hooks.base=5Fhook?= =?UTF-8?q?.BaseHook=20=E2=86=92=20airflow.hooks.base.BaseHook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/fixtures/airflow/AIR302_names.py | 4 + .../src/rules/airflow/rules/removal_in_3.rs | 5 + ...irflow__tests__AIR302_AIR302_names.py.snap | 1052 +++++++++-------- 3 files changed, 540 insertions(+), 521 deletions(-) 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 430d1acd3461b..823264e8aa4f6 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py @@ -36,6 +36,7 @@ dataset_manager, resolve_dataset_manager, ) +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 @@ -138,6 +139,9 @@ # airflow.datasets.manager DatasetManager, dataset_manager, resolve_dataset_manager +# airflow.hooks +BaseHook() + # airflow.lineage.hook DatasetLineageInfo 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 063a0f38ae23b..3f718d95daeaf 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 @@ -592,6 +592,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(( 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 8850117bc961d..299374e4ced8d 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,1029 +2,1039 @@ 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 +AIR302_names.py:97:1: AIR302 `airflow.PY36` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ AIR302 -97 | DatasetFromRoot +98 | DatasetFromRoot | = help: Use `sys.version_info` instead -AIR302_names.py:96:7: AIR302 `airflow.PY37` is removed in Airflow 3.0 +AIR302_names.py:97:7: AIR302 `airflow.PY37` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ AIR302 -97 | DatasetFromRoot +98 | DatasetFromRoot | = help: Use `sys.version_info` instead -AIR302_names.py:96:13: AIR302 `airflow.PY38` is removed in Airflow 3.0 +AIR302_names.py:97:13: AIR302 `airflow.PY38` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ AIR302 -97 | DatasetFromRoot +98 | DatasetFromRoot | = help: Use `sys.version_info` instead -AIR302_names.py:96:19: AIR302 `airflow.PY39` is removed in Airflow 3.0 +AIR302_names.py:97:19: AIR302 `airflow.PY39` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ AIR302 -97 | DatasetFromRoot +98 | DatasetFromRoot | = help: Use `sys.version_info` instead -AIR302_names.py:96:25: AIR302 `airflow.PY310` is removed in Airflow 3.0 +AIR302_names.py:97:25: AIR302 `airflow.PY310` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^^ AIR302 -97 | DatasetFromRoot +98 | DatasetFromRoot | = help: Use `sys.version_info` instead -AIR302_names.py:96:32: AIR302 `airflow.PY311` is removed in Airflow 3.0 +AIR302_names.py:97:32: AIR302 `airflow.PY311` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^^ AIR302 -97 | DatasetFromRoot +98 | DatasetFromRoot | = help: Use `sys.version_info` instead -AIR302_names.py:96:39: AIR302 `airflow.PY312` is removed in Airflow 3.0 +AIR302_names.py:97:39: AIR302 `airflow.PY312` is removed in Airflow 3.0 | -95 | # airflow root -96 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +96 | # airflow root +97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^^ AIR302 -97 | DatasetFromRoot +98 | 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 | dataset_from_root = DatasetFromRoot() - | - = help: Use `airflow.sdk.definitions.asset.Asset` instead +AIR302_names.py:98:1: AIR302 `airflow.Dataset` is removed in Airflow 3.0 + | + 96 | # airflow root + 97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 + 98 | DatasetFromRoot + | ^^^^^^^^^^^^^^^ AIR302 + 99 | +100 | dataset_from_root = DatasetFromRoot() + | + = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:99:21: AIR302 `airflow.Dataset` is removed in Airflow 3.0 +AIR302_names.py:100:21: AIR302 `airflow.Dataset` is removed in Airflow 3.0 | - 97 | DatasetFromRoot - 98 | - 99 | dataset_from_root = DatasetFromRoot() + 98 | DatasetFromRoot + 99 | +100 | dataset_from_root = DatasetFromRoot() | ^^^^^^^^^^^^^^^ AIR302 -100 | dataset_from_root.iter_datasets() -101 | dataset_from_root.iter_dataset_aliases() +101 | dataset_from_root.iter_datasets() +102 | dataset_from_root.iter_dataset_aliases() | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:100:19: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:101:19: AIR302 `iter_datasets` is removed in Airflow 3.0 | - 99 | dataset_from_root = DatasetFromRoot() -100 | dataset_from_root.iter_datasets() +100 | dataset_from_root = DatasetFromRoot() +101 | dataset_from_root.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -101 | dataset_from_root.iter_dataset_aliases() +102 | dataset_from_root.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:101:19: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:102:19: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | - 99 | dataset_from_root = DatasetFromRoot() -100 | dataset_from_root.iter_datasets() -101 | dataset_from_root.iter_dataset_aliases() +100 | dataset_from_root = DatasetFromRoot() +101 | dataset_from_root.iter_datasets() +102 | dataset_from_root.iter_dataset_aliases() | ^^^^^^^^^^^^^^^^^^^^ AIR302 -102 | -103 | # airflow.api_connexion.security +103 | +104 | # airflow.api_connexion.security | = help: Use `iter_asset_aliases` instead -AIR302_names.py:104:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 +AIR302_names.py:105:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 | -103 | # airflow.api_connexion.security -104 | requires_access, requires_access_dataset +104 | # airflow.api_connexion.security +105 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^ AIR302 -105 | -106 | # airflow.auth.managers +106 | +107 | # airflow.auth.managers | = help: Use `airflow.api_connexion.security.requires_access_*` instead -AIR302_names.py:104:18: AIR302 `airflow.api_connexion.security.requires_access_dataset` is removed in Airflow 3.0 +AIR302_names.py:105:18: AIR302 `airflow.api_connexion.security.requires_access_dataset` is removed in Airflow 3.0 | -103 | # airflow.api_connexion.security -104 | requires_access, requires_access_dataset +104 | # airflow.api_connexion.security +105 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -105 | -106 | # airflow.auth.managers +106 | +107 | # airflow.auth.managers | = help: Use `airflow.api_connexion.security.requires_access_asset` instead -AIR302_names.py:107:1: AIR302 `airflow.auth.managers.base_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 +AIR302_names.py:108:1: AIR302 `airflow.auth.managers.base_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 | -106 | # airflow.auth.managers -107 | is_authorized_dataset +107 | # airflow.auth.managers +108 | is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -108 | DatasetDetails +109 | DatasetDetails | = help: Use `airflow.auth.managers.base_auth_manager.is_authorized_asset` instead -AIR302_names.py:108:1: AIR302 `airflow.auth.managers.models.resource_details.DatasetDetails` is removed in Airflow 3.0 +AIR302_names.py:109:1: AIR302 `airflow.auth.managers.models.resource_details.DatasetDetails` is removed in Airflow 3.0 | -106 | # airflow.auth.managers -107 | is_authorized_dataset -108 | DatasetDetails +107 | # airflow.auth.managers +108 | is_authorized_dataset +109 | DatasetDetails | ^^^^^^^^^^^^^^ AIR302 -109 | -110 | # airflow.configuration +110 | +111 | # airflow.configuration | = help: Use `airflow.auth.managers.models.resource_details.AssetDetails` instead -AIR302_names.py:111:1: AIR302 `airflow.configuration.get` is removed in Airflow 3.0 +AIR302_names.py:112:1: AIR302 `airflow.configuration.get` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^ AIR302 | = help: Use `airflow.configuration.conf.get` instead -AIR302_names.py:111:6: AIR302 `airflow.configuration.getboolean` is removed in Airflow 3.0 +AIR302_names.py:112:6: AIR302 `airflow.configuration.getboolean` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.getboolean` instead -AIR302_names.py:111:18: AIR302 `airflow.configuration.getfloat` is removed in Airflow 3.0 +AIR302_names.py:112:18: AIR302 `airflow.configuration.getfloat` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.getfloat` instead -AIR302_names.py:111:28: AIR302 `airflow.configuration.getint` is removed in Airflow 3.0 +AIR302_names.py:112:28: AIR302 `airflow.configuration.getint` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.getint` instead -AIR302_names.py:111:36: AIR302 `airflow.configuration.has_option` is removed in Airflow 3.0 +AIR302_names.py:112:36: AIR302 `airflow.configuration.has_option` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.has_option` instead -AIR302_names.py:111:48: AIR302 `airflow.configuration.remove_option` is removed in Airflow 3.0 +AIR302_names.py:112:48: AIR302 `airflow.configuration.remove_option` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.remove_option` instead -AIR302_names.py:111:63: AIR302 `airflow.configuration.as_dict` is removed in Airflow 3.0 +AIR302_names.py:112:63: AIR302 `airflow.configuration.as_dict` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^^^^^ AIR302 | = help: Use `airflow.configuration.conf.as_dict` instead -AIR302_names.py:111:72: AIR302 `airflow.configuration.set` is removed in Airflow 3.0 +AIR302_names.py:112:72: AIR302 `airflow.configuration.set` is removed in Airflow 3.0 | -110 | # airflow.configuration -111 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set +111 | # airflow.configuration +112 | get, getboolean, getfloat, getint, has_option, remove_option, as_dict, set | ^^^ AIR302 | = help: Use `airflow.configuration.conf.set` instead -AIR302_names.py:115: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:116:1: AIR302 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0; The whole `airflow.contrib` module has been removed. | -114 | # airflow.contrib.* -115 | AWSAthenaHook +115 | # airflow.contrib.* +116 | AWSAthenaHook | ^^^^^^^^^^^^^ AIR302 -116 | -117 | # airflow.datasets +117 | +118 | # airflow.datasets | -AIR302_names.py:118:1: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 +AIR302_names.py:119:1: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 | -117 | # airflow.datasets -118 | Dataset +118 | # airflow.datasets +119 | Dataset | ^^^^^^^ AIR302 -119 | DatasetAlias -120 | DatasetAliasEvent +120 | DatasetAlias +121 | DatasetAliasEvent | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:119:1: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 +AIR302_names.py:120:1: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 | -117 | # airflow.datasets -118 | Dataset -119 | DatasetAlias +118 | # airflow.datasets +119 | Dataset +120 | DatasetAlias | ^^^^^^^^^^^^ AIR302 -120 | DatasetAliasEvent -121 | DatasetAll +121 | DatasetAliasEvent +122 | DatasetAll | = help: Use `airflow.sdk.definitions.asset.AssetAlias` instead -AIR302_names.py:120:1: AIR302 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 +AIR302_names.py:121:1: AIR302 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 | -118 | Dataset -119 | DatasetAlias -120 | DatasetAliasEvent +119 | Dataset +120 | DatasetAlias +121 | DatasetAliasEvent | ^^^^^^^^^^^^^^^^^ AIR302 -121 | DatasetAll -122 | DatasetAny +122 | DatasetAll +123 | DatasetAny | -AIR302_names.py:121:1: AIR302 `airflow.datasets.DatasetAll` is removed in Airflow 3.0 +AIR302_names.py:122:1: AIR302 `airflow.datasets.DatasetAll` is removed in Airflow 3.0 | -119 | DatasetAlias -120 | DatasetAliasEvent -121 | DatasetAll +120 | DatasetAlias +121 | DatasetAliasEvent +122 | DatasetAll | ^^^^^^^^^^ AIR302 -122 | DatasetAny -123 | expand_alias_to_datasets +123 | DatasetAny +124 | expand_alias_to_datasets | = help: Use `airflow.sdk.definitions.asset.AssetAll` instead -AIR302_names.py:122:1: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 +AIR302_names.py:123:1: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 | -120 | DatasetAliasEvent -121 | DatasetAll -122 | DatasetAny +121 | DatasetAliasEvent +122 | DatasetAll +123 | DatasetAny | ^^^^^^^^^^ AIR302 -123 | expand_alias_to_datasets -124 | Metadata +124 | expand_alias_to_datasets +125 | Metadata | = help: Use `airflow.sdk.definitions.asset.AssetAny` instead -AIR302_names.py:123:1: AIR302 `airflow.datasets.expand_alias_to_datasets` is removed in Airflow 3.0 +AIR302_names.py:124:1: AIR302 `airflow.datasets.expand_alias_to_datasets` is removed in Airflow 3.0 | -121 | DatasetAll -122 | DatasetAny -123 | expand_alias_to_datasets +122 | DatasetAll +123 | DatasetAny +124 | expand_alias_to_datasets | ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -124 | Metadata +125 | Metadata | = help: Use `airflow.sdk.definitions.asset.expand_alias_to_assets` instead -AIR302_names.py:124:1: AIR302 `airflow.datasets.metadata.Metadata` is removed in Airflow 3.0 +AIR302_names.py:125:1: AIR302 `airflow.datasets.metadata.Metadata` is removed in Airflow 3.0 | -122 | DatasetAny -123 | expand_alias_to_datasets -124 | Metadata +123 | DatasetAny +124 | expand_alias_to_datasets +125 | Metadata | ^^^^^^^^ AIR302 -125 | -126 | dataset_to_test_method_call = Dataset() +126 | +127 | dataset_to_test_method_call = Dataset() | = help: Use `airflow.sdk.definitions.asset.metadata.Metadata` instead -AIR302_names.py:126:31: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 +AIR302_names.py:127:31: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 | -124 | Metadata -125 | -126 | dataset_to_test_method_call = Dataset() +125 | Metadata +126 | +127 | dataset_to_test_method_call = Dataset() | ^^^^^^^ AIR302 -127 | dataset_to_test_method_call.iter_datasets() -128 | dataset_to_test_method_call.iter_dataset_aliases() +128 | dataset_to_test_method_call.iter_datasets() +129 | dataset_to_test_method_call.iter_dataset_aliases() | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:127:29: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:128:29: AIR302 `iter_datasets` is removed in Airflow 3.0 | -126 | dataset_to_test_method_call = Dataset() -127 | dataset_to_test_method_call.iter_datasets() +127 | dataset_to_test_method_call = Dataset() +128 | dataset_to_test_method_call.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -128 | dataset_to_test_method_call.iter_dataset_aliases() +129 | dataset_to_test_method_call.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:128:29: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:129:29: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -126 | dataset_to_test_method_call = Dataset() -127 | dataset_to_test_method_call.iter_datasets() -128 | dataset_to_test_method_call.iter_dataset_aliases() +127 | dataset_to_test_method_call = Dataset() +128 | dataset_to_test_method_call.iter_datasets() +129 | dataset_to_test_method_call.iter_dataset_aliases() | ^^^^^^^^^^^^^^^^^^^^ AIR302 -129 | -130 | alias_to_test_method_call = DatasetAlias() +130 | +131 | alias_to_test_method_call = DatasetAlias() | = help: Use `iter_asset_aliases` instead -AIR302_names.py:130:29: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 +AIR302_names.py:131:29: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 | -128 | dataset_to_test_method_call.iter_dataset_aliases() -129 | -130 | alias_to_test_method_call = DatasetAlias() +129 | dataset_to_test_method_call.iter_dataset_aliases() +130 | +131 | alias_to_test_method_call = DatasetAlias() | ^^^^^^^^^^^^ AIR302 -131 | alias_to_test_method_call.iter_datasets() -132 | alias_to_test_method_call.iter_dataset_aliases() +132 | alias_to_test_method_call.iter_datasets() +133 | alias_to_test_method_call.iter_dataset_aliases() | = help: Use `airflow.sdk.definitions.asset.AssetAlias` instead -AIR302_names.py:131:27: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:132:27: AIR302 `iter_datasets` is removed in Airflow 3.0 | -130 | alias_to_test_method_call = DatasetAlias() -131 | alias_to_test_method_call.iter_datasets() +131 | alias_to_test_method_call = DatasetAlias() +132 | alias_to_test_method_call.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -132 | alias_to_test_method_call.iter_dataset_aliases() +133 | alias_to_test_method_call.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:132:27: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:133:27: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -130 | alias_to_test_method_call = DatasetAlias() -131 | alias_to_test_method_call.iter_datasets() -132 | alias_to_test_method_call.iter_dataset_aliases() +131 | alias_to_test_method_call = DatasetAlias() +132 | alias_to_test_method_call.iter_datasets() +133 | alias_to_test_method_call.iter_dataset_aliases() | ^^^^^^^^^^^^^^^^^^^^ AIR302 -133 | -134 | any_to_test_method_call = DatasetAny() +134 | +135 | any_to_test_method_call = DatasetAny() | = help: Use `iter_asset_aliases` instead -AIR302_names.py:134:27: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 +AIR302_names.py:135:27: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 | -132 | alias_to_test_method_call.iter_dataset_aliases() -133 | -134 | any_to_test_method_call = DatasetAny() +133 | alias_to_test_method_call.iter_dataset_aliases() +134 | +135 | any_to_test_method_call = DatasetAny() | ^^^^^^^^^^ AIR302 -135 | any_to_test_method_call.iter_datasets() -136 | any_to_test_method_call.iter_dataset_aliases() +136 | any_to_test_method_call.iter_datasets() +137 | any_to_test_method_call.iter_dataset_aliases() | = help: Use `airflow.sdk.definitions.asset.AssetAny` instead -AIR302_names.py:135:25: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:136:25: AIR302 `iter_datasets` is removed in Airflow 3.0 | -134 | any_to_test_method_call = DatasetAny() -135 | any_to_test_method_call.iter_datasets() +135 | any_to_test_method_call = DatasetAny() +136 | any_to_test_method_call.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -136 | any_to_test_method_call.iter_dataset_aliases() +137 | any_to_test_method_call.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:136:25: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:137:25: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -134 | any_to_test_method_call = DatasetAny() -135 | any_to_test_method_call.iter_datasets() -136 | any_to_test_method_call.iter_dataset_aliases() +135 | any_to_test_method_call = DatasetAny() +136 | any_to_test_method_call.iter_datasets() +137 | any_to_test_method_call.iter_dataset_aliases() | ^^^^^^^^^^^^^^^^^^^^ AIR302 -137 | -138 | # airflow.datasets.manager +138 | +139 | # airflow.datasets.manager | = help: Use `iter_asset_aliases` instead -AIR302_names.py:139:17: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 +AIR302_names.py:140:17: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 | -138 | # airflow.datasets.manager -139 | DatasetManager, dataset_manager, resolve_dataset_manager +139 | # airflow.datasets.manager +140 | DatasetManager, dataset_manager, resolve_dataset_manager | ^^^^^^^^^^^^^^^ AIR302 -140 | -141 | # airflow.lineage.hook +141 | +142 | # airflow.hooks | = help: Use `airflow.assets.manager` instead -AIR302_names.py:139:34: AIR302 `airflow.datasets.manager.resolve_dataset_manager` is removed in Airflow 3.0 +AIR302_names.py:140:34: AIR302 `airflow.datasets.manager.resolve_dataset_manager` is removed in Airflow 3.0 | -138 | # airflow.datasets.manager -139 | DatasetManager, dataset_manager, resolve_dataset_manager +139 | # airflow.datasets.manager +140 | DatasetManager, dataset_manager, resolve_dataset_manager | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -140 | -141 | # airflow.lineage.hook +141 | +142 | # airflow.hooks | = help: Use `airflow.assets.resolve_asset_manager` instead -AIR302_names.py:142:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 +AIR302_names.py:143:1: AIR302 `airflow.hooks.base_hook.BaseHook` is removed in Airflow 3.0 | -141 | # airflow.lineage.hook -142 | DatasetLineageInfo +142 | # airflow.hooks +143 | BaseHook() + | ^^^^^^^^ AIR302 +144 | +145 | # airflow.lineage.hook + | + = help: Use `airflow.hooks.base.BaseHook` instead + +AIR302_names.py:146:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 + | +145 | # airflow.lineage.hook +146 | DatasetLineageInfo | ^^^^^^^^^^^^^^^^^^ AIR302 -143 | -144 | # airflow.listeners.spec.dataset +147 | +148 | # airflow.listeners.spec.dataset | = help: Use `airflow.lineage.hook.AssetLineageInfo` instead -AIR302_names.py:145:1: AIR302 `airflow.listeners.spec.dataset.on_dataset_changed` is removed in Airflow 3.0 +AIR302_names.py:149:1: AIR302 `airflow.listeners.spec.dataset.on_dataset_changed` is removed in Airflow 3.0 | -144 | # airflow.listeners.spec.dataset -145 | on_dataset_changed, on_dataset_created +148 | # airflow.listeners.spec.dataset +149 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -146 | -147 | # airflow.metrics.validators +150 | +151 | # airflow.metrics.validators | = help: Use `airflow.listeners.spec.asset.on_asset_changed` instead -AIR302_names.py:145:21: AIR302 `airflow.listeners.spec.dataset.on_dataset_created` is removed in Airflow 3.0 +AIR302_names.py:149:21: AIR302 `airflow.listeners.spec.dataset.on_dataset_created` is removed in Airflow 3.0 | -144 | # airflow.listeners.spec.dataset -145 | on_dataset_changed, on_dataset_created +148 | # airflow.listeners.spec.dataset +149 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -146 | -147 | # airflow.metrics.validators +150 | +151 | # airflow.metrics.validators | = help: Use `airflow.listeners.spec.asset.on_asset_created` instead -AIR302_names.py:148:1: AIR302 `airflow.metrics.validators.AllowListValidator` is removed in Airflow 3.0 +AIR302_names.py:152:1: AIR302 `airflow.metrics.validators.AllowListValidator` is removed in Airflow 3.0 | -147 | # airflow.metrics.validators -148 | AllowListValidator, BlockListValidator +151 | # airflow.metrics.validators +152 | AllowListValidator, BlockListValidator | ^^^^^^^^^^^^^^^^^^ AIR302 -149 | -150 | # airflow.operators.dummy_operator +153 | +154 | # airflow.operators.dummy_operator | = help: Use `airflow.metrics.validators.PatternAllowListValidator` instead -AIR302_names.py:148:21: AIR302 `airflow.metrics.validators.BlockListValidator` is removed in Airflow 3.0 +AIR302_names.py:152:21: AIR302 `airflow.metrics.validators.BlockListValidator` is removed in Airflow 3.0 | -147 | # airflow.metrics.validators -148 | AllowListValidator, BlockListValidator +151 | # airflow.metrics.validators +152 | AllowListValidator, BlockListValidator | ^^^^^^^^^^^^^^^^^^ AIR302 -149 | -150 | # airflow.operators.dummy_operator +153 | +154 | # airflow.operators.dummy_operator | = help: Use `airflow.metrics.validators.PatternBlockListValidator` instead -AIR302_names.py:151:16: AIR302 `airflow.operators.dummy_operator.EmptyOperator` is removed in Airflow 3.0 +AIR302_names.py:155:16: AIR302 `airflow.operators.dummy_operator.EmptyOperator` is removed in Airflow 3.0 | -150 | # airflow.operators.dummy_operator -151 | dummy_operator.EmptyOperator +154 | # airflow.operators.dummy_operator +155 | dummy_operator.EmptyOperator | ^^^^^^^^^^^^^ AIR302 -152 | dummy_operator.DummyOperator +156 | dummy_operator.DummyOperator | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:152:16: AIR302 `airflow.operators.dummy_operator.DummyOperator` is removed in Airflow 3.0 +AIR302_names.py:156:16: AIR302 `airflow.operators.dummy_operator.DummyOperator` is removed in Airflow 3.0 | -150 | # airflow.operators.dummy_operator -151 | dummy_operator.EmptyOperator -152 | dummy_operator.DummyOperator +154 | # airflow.operators.dummy_operator +155 | dummy_operator.EmptyOperator +156 | dummy_operator.DummyOperator | ^^^^^^^^^^^^^ AIR302 -153 | -154 | # airflow.operators.bash_operator +157 | +158 | # airflow.operators.bash_operator | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:155:1: AIR302 `airflow.operators.bash_operator.BashOperator` is removed in Airflow 3.0 +AIR302_names.py:159:1: AIR302 `airflow.operators.bash_operator.BashOperator` is removed in Airflow 3.0 | -154 | # airflow.operators.bash_operator -155 | BashOperator +158 | # airflow.operators.bash_operator +159 | BashOperator | ^^^^^^^^^^^^ AIR302 -156 | -157 | # airflow.operators.branch_operator +160 | +161 | # airflow.operators.branch_operator | = help: Use `airflow.operators.bash.BashOperator` instead -AIR302_names.py:158:1: AIR302 `airflow.operators.branch_operator.BaseBranchOperator` is removed in Airflow 3.0 +AIR302_names.py:162:1: AIR302 `airflow.operators.branch_operator.BaseBranchOperator` is removed in Airflow 3.0 | -157 | # airflow.operators.branch_operator -158 | BaseBranchOperator +161 | # airflow.operators.branch_operator +162 | BaseBranchOperator | ^^^^^^^^^^^^^^^^^^ AIR302 -159 | -160 | # airflow.operators.dummy +163 | +164 | # airflow.operators.dummy | = help: Use `airflow.operators.branch.BaseBranchOperator` instead -AIR302_names.py:161:16: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 +AIR302_names.py:165:16: AIR302 `airflow.operators.dummy.DummyOperator` is removed in Airflow 3.0 | -160 | # airflow.operators.dummy -161 | EmptyOperator, DummyOperator +164 | # airflow.operators.dummy +165 | EmptyOperator, DummyOperator | ^^^^^^^^^^^^^ AIR302 -162 | -163 | # airflow.operators.email_operator +166 | +167 | # airflow.operators.email_operator | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:164:1: AIR302 `airflow.operators.email_operator.EmailOperator` is removed in Airflow 3.0 +AIR302_names.py:168:1: AIR302 `airflow.operators.email_operator.EmailOperator` is removed in Airflow 3.0 | -163 | # airflow.operators.email_operator -164 | EmailOperator +167 | # airflow.operators.email_operator +168 | EmailOperator | ^^^^^^^^^^^^^ AIR302 -165 | -166 | # airflow.operators.subdag.* +169 | +170 | # airflow.operators.subdag.* | = help: Use `airflow.operators.email.EmailOperator` instead -AIR302_names.py:167:1: AIR302 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0; The whole `airflow.subdag` module has been removed. +AIR302_names.py:171:1: AIR302 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0; The whole `airflow.subdag` module has been removed. | -166 | # airflow.operators.subdag.* -167 | SubDagOperator +170 | # airflow.operators.subdag.* +171 | SubDagOperator | ^^^^^^^^^^^^^^ AIR302 -168 | -169 | # airflow.providers.amazon +172 | +173 | # airflow.providers.amazon | -AIR302_names.py:170:13: AIR302 `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0 +AIR302_names.py:174:13: AIR302 `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.DATASET` is removed in Airflow 3.0 | -169 | # airflow.providers.amazon -170 | AvpEntities.DATASET +173 | # airflow.providers.amazon +174 | AvpEntities.DATASET | ^^^^^^^ AIR302 -171 | s3.create_dataset -172 | s3.convert_dataset_to_openlineage +175 | s3.create_dataset +176 | s3.convert_dataset_to_openlineage | = help: Use `airflow.providers.amazon.auth_manager.avp.entities.AvpEntities.ASSET` instead -AIR302_names.py:171:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.create_dataset` is removed in Airflow 3.0 +AIR302_names.py:175:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.create_dataset` is removed in Airflow 3.0 | -169 | # airflow.providers.amazon -170 | AvpEntities.DATASET -171 | s3.create_dataset +173 | # airflow.providers.amazon +174 | AvpEntities.DATASET +175 | s3.create_dataset | ^^^^^^^^^^^^^^ AIR302 -172 | s3.convert_dataset_to_openlineage -173 | s3.sanitize_uri +176 | s3.convert_dataset_to_openlineage +177 | s3.sanitize_uri | = help: Use `airflow.providers.amazon.aws.assets.s3.create_asset` instead -AIR302_names.py:172:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.convert_dataset_to_openlineage` is removed in Airflow 3.0 +AIR302_names.py:176:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.convert_dataset_to_openlineage` is removed in Airflow 3.0 | -170 | AvpEntities.DATASET -171 | s3.create_dataset -172 | s3.convert_dataset_to_openlineage +174 | AvpEntities.DATASET +175 | s3.create_dataset +176 | s3.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -173 | s3.sanitize_uri +177 | s3.sanitize_uri | = help: Use `airflow.providers.amazon.aws.assets.s3.convert_asset_to_openlineage` instead -AIR302_names.py:173:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:177:4: AIR302 `airflow.providers.amazon.aws.datasets.s3.sanitize_uri` is removed in Airflow 3.0 | -171 | s3.create_dataset -172 | s3.convert_dataset_to_openlineage -173 | s3.sanitize_uri +175 | s3.create_dataset +176 | s3.convert_dataset_to_openlineage +177 | s3.sanitize_uri | ^^^^^^^^^^^^ AIR302 -174 | -175 | # airflow.providers.common.io +178 | +179 | # airflow.providers.common.io | = help: Use `airflow.providers.amazon.aws.assets.s3.sanitize_uri` instead -AIR302_names.py:176:16: AIR302 `airflow.providers.common.io.datasets.file.convert_dataset_to_openlineage` is removed in Airflow 3.0 +AIR302_names.py:180:16: AIR302 `airflow.providers.common.io.datasets.file.convert_dataset_to_openlineage` is removed in Airflow 3.0 | -175 | # airflow.providers.common.io -176 | common_io_file.convert_dataset_to_openlineage +179 | # airflow.providers.common.io +180 | common_io_file.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -177 | common_io_file.create_dataset -178 | common_io_file.sanitize_uri +181 | common_io_file.create_dataset +182 | common_io_file.sanitize_uri | = help: Use `airflow.providers.common.io.assets.file.convert_asset_to_openlineage` instead -AIR302_names.py:177:16: AIR302 `airflow.providers.common.io.datasets.file.create_dataset` is removed in Airflow 3.0 +AIR302_names.py:181:16: AIR302 `airflow.providers.common.io.datasets.file.create_dataset` is removed in Airflow 3.0 | -175 | # airflow.providers.common.io -176 | common_io_file.convert_dataset_to_openlineage -177 | common_io_file.create_dataset +179 | # airflow.providers.common.io +180 | common_io_file.convert_dataset_to_openlineage +181 | common_io_file.create_dataset | ^^^^^^^^^^^^^^ AIR302 -178 | common_io_file.sanitize_uri +182 | common_io_file.sanitize_uri | = help: Use `airflow.providers.common.io.assets.file.create_asset` instead -AIR302_names.py:178:16: AIR302 `airflow.providers.common.io.datasets.file.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:182:16: AIR302 `airflow.providers.common.io.datasets.file.sanitize_uri` is removed in Airflow 3.0 | -176 | common_io_file.convert_dataset_to_openlineage -177 | common_io_file.create_dataset -178 | common_io_file.sanitize_uri +180 | common_io_file.convert_dataset_to_openlineage +181 | common_io_file.create_dataset +182 | common_io_file.sanitize_uri | ^^^^^^^^^^^^ AIR302 -179 | -180 | # airflow.providers.fab +183 | +184 | # airflow.providers.fab | = help: Use `airflow.providers.common.io.assets.file.sanitize_uri` instead -AIR302_names.py:181:18: AIR302 `airflow.providers.fab.auth_manager.fab_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 +AIR302_names.py:185:18: AIR302 `airflow.providers.fab.auth_manager.fab_auth_manager.is_authorized_dataset` is removed in Airflow 3.0 | -180 | # airflow.providers.fab -181 | fab_auth_manager.is_authorized_dataset +184 | # airflow.providers.fab +185 | fab_auth_manager.is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -182 | -183 | # airflow.providers.google +186 | +187 | # airflow.providers.google | = help: Use `airflow.providers.fab.auth_manager.fab_auth_manager.is_authorized_asset` instead -AIR302_names.py:186:5: AIR302 `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0 +AIR302_names.py:190:5: AIR302 `airflow.providers.google.datasets.gcs.create_dataset` is removed in Airflow 3.0 | -184 | bigquery.sanitize_uri -185 | -186 | gcs.create_dataset +188 | bigquery.sanitize_uri +189 | +190 | gcs.create_dataset | ^^^^^^^^^^^^^^ AIR302 -187 | gcs.sanitize_uri -188 | gcs.convert_dataset_to_openlineage +191 | gcs.sanitize_uri +192 | gcs.convert_dataset_to_openlineage | = help: Use `airflow.providers.google.assets.gcs.create_asset` instead -AIR302_names.py:187:5: AIR302 `airflow.providers.google.datasets.gcs.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:191:5: AIR302 `airflow.providers.google.datasets.gcs.sanitize_uri` is removed in Airflow 3.0 | -186 | gcs.create_dataset -187 | gcs.sanitize_uri +190 | gcs.create_dataset +191 | gcs.sanitize_uri | ^^^^^^^^^^^^ AIR302 -188 | gcs.convert_dataset_to_openlineage +192 | gcs.convert_dataset_to_openlineage | = help: Use `airflow.providers.google.assets.gcs.sanitize_uri` instead -AIR302_names.py:188:5: AIR302 `airflow.providers.google.datasets.gcs.convert_dataset_to_openlineage` is removed in Airflow 3.0 +AIR302_names.py:192:5: AIR302 `airflow.providers.google.datasets.gcs.convert_dataset_to_openlineage` is removed in Airflow 3.0 | -186 | gcs.create_dataset -187 | gcs.sanitize_uri -188 | gcs.convert_dataset_to_openlineage +190 | gcs.create_dataset +191 | gcs.sanitize_uri +192 | gcs.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -189 | -190 | # airflow.providers.mysql +193 | +194 | # airflow.providers.mysql | = help: Use `airflow.providers.google.assets.gcs.convert_asset_to_openlineage` instead -AIR302_names.py:191:7: AIR302 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:195:7: AIR302 `airflow.providers.mysql.datasets.mysql.sanitize_uri` is removed in Airflow 3.0 | -190 | # airflow.providers.mysql -191 | mysql.sanitize_uri +194 | # airflow.providers.mysql +195 | mysql.sanitize_uri | ^^^^^^^^^^^^ AIR302 -192 | -193 | # airflow.providers.openlineage +196 | +197 | # airflow.providers.openlineage | = help: Use `airflow.providers.mysql.assets.mysql.sanitize_uri` instead -AIR302_names.py:194:1: AIR302 `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0 +AIR302_names.py:198:1: AIR302 `airflow.providers.openlineage.utils.utils.DatasetInfo` is removed in Airflow 3.0 | -193 | # airflow.providers.openlineage -194 | DatasetInfo, translate_airflow_dataset +197 | # airflow.providers.openlineage +198 | DatasetInfo, translate_airflow_dataset | ^^^^^^^^^^^ AIR302 -195 | -196 | # airflow.providers.postgres +199 | +200 | # airflow.providers.postgres | = help: Use `airflow.providers.openlineage.utils.utils.AssetInfo` instead -AIR302_names.py:194:14: AIR302 `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0 +AIR302_names.py:198:14: AIR302 `airflow.providers.openlineage.utils.utils.translate_airflow_dataset` is removed in Airflow 3.0 | -193 | # airflow.providers.openlineage -194 | DatasetInfo, translate_airflow_dataset +197 | # airflow.providers.openlineage +198 | DatasetInfo, translate_airflow_dataset | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -195 | -196 | # airflow.providers.postgres +199 | +200 | # airflow.providers.postgres | = help: Use `airflow.providers.openlineage.utils.utils.translate_airflow_asset` instead -AIR302_names.py:197:10: AIR302 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:201:10: AIR302 `airflow.providers.postgres.datasets.postgres.sanitize_uri` is removed in Airflow 3.0 | -196 | # airflow.providers.postgres -197 | postgres.sanitize_uri +200 | # airflow.providers.postgres +201 | postgres.sanitize_uri | ^^^^^^^^^^^^ AIR302 -198 | -199 | # airflow.providers.trino +202 | +203 | # airflow.providers.trino | = help: Use `airflow.providers.postgres.assets.postgres.sanitize_uri` instead -AIR302_names.py:200:7: AIR302 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0 +AIR302_names.py:204:7: AIR302 `airflow.providers.trino.datasets.trino.sanitize_uri` is removed in Airflow 3.0 | -199 | # airflow.providers.trino -200 | trino.sanitize_uri +203 | # airflow.providers.trino +204 | trino.sanitize_uri | ^^^^^^^^^^^^ AIR302 -201 | -202 | # airflow.secrets +205 | +206 | # airflow.secrets | = help: Use `airflow.providers.trino.assets.trino.sanitize_uri` instead -AIR302_names.py:203:1: AIR302 `airflow.secrets.local_filesystem.get_connection` is removed in Airflow 3.0 +AIR302_names.py:207:1: AIR302 `airflow.secrets.local_filesystem.get_connection` is removed in Airflow 3.0 | -202 | # airflow.secrets -203 | get_connection, load_connections +206 | # airflow.secrets +207 | get_connection, load_connections | ^^^^^^^^^^^^^^ AIR302 -204 | -205 | # airflow.security.permissions +208 | +209 | # airflow.security.permissions | = help: Use `airflow.secrets.local_filesystem.load_connections_dict` instead -AIR302_names.py:203:17: AIR302 `airflow.secrets.local_filesystem.load_connections` is removed in Airflow 3.0 +AIR302_names.py:207:17: AIR302 `airflow.secrets.local_filesystem.load_connections` is removed in Airflow 3.0 | -202 | # airflow.secrets -203 | get_connection, load_connections +206 | # airflow.secrets +207 | get_connection, load_connections | ^^^^^^^^^^^^^^^^ AIR302 -204 | -205 | # airflow.security.permissions +208 | +209 | # airflow.security.permissions | = help: Use `airflow.secrets.local_filesystem.load_connections_dict` instead -AIR302_names.py:206:1: AIR302 `airflow.security.permissions.RESOURCE_DATASET` is removed in Airflow 3.0 +AIR302_names.py:210:1: AIR302 `airflow.security.permissions.RESOURCE_DATASET` is removed in Airflow 3.0 | -205 | # airflow.security.permissions -206 | RESOURCE_DATASET +209 | # airflow.security.permissions +210 | RESOURCE_DATASET | ^^^^^^^^^^^^^^^^ AIR302 -207 | -208 | # airflow.sensors.base_sensor_operator +211 | +212 | # airflow.sensors.base_sensor_operator | = help: Use `airflow.security.permissions.RESOURCE_ASSET` instead -AIR302_names.py:209:1: AIR302 `airflow.sensors.base_sensor_operator.BaseSensorOperator` is removed in Airflow 3.0 +AIR302_names.py:213:1: AIR302 `airflow.sensors.base_sensor_operator.BaseSensorOperator` is removed in Airflow 3.0 | -208 | # airflow.sensors.base_sensor_operator -209 | BaseSensorOperator +212 | # airflow.sensors.base_sensor_operator +213 | BaseSensorOperator | ^^^^^^^^^^^^^^^^^^ AIR302 -210 | -211 | # airflow.sensors.date_time_sensor +214 | +215 | # airflow.sensors.date_time_sensor | = help: Use `airflow.sensors.base.BaseSensorOperator` instead -AIR302_names.py:212:1: AIR302 `airflow.sensors.date_time_sensor.DateTimeSensor` is removed in Airflow 3.0 +AIR302_names.py:216:1: AIR302 `airflow.sensors.date_time_sensor.DateTimeSensor` is removed in Airflow 3.0 | -211 | # airflow.sensors.date_time_sensor -212 | DateTimeSensor +215 | # airflow.sensors.date_time_sensor +216 | DateTimeSensor | ^^^^^^^^^^^^^^ AIR302 -213 | -214 | # airflow.sensors.external_task +217 | +218 | # airflow.sensors.external_task | = help: Use `airflow.sensors.date_time.DateTimeSensor` instead -AIR302_names.py:215:1: AIR302 `airflow.sensors.external_task.ExternalTaskSensorLink` is removed in Airflow 3.0 +AIR302_names.py:219:1: AIR302 `airflow.sensors.external_task.ExternalTaskSensorLink` is removed in Airflow 3.0 | -214 | # airflow.sensors.external_task -215 | ExternalTaskSensorLinkFromExternalTask +218 | # airflow.sensors.external_task +219 | ExternalTaskSensorLinkFromExternalTask | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -216 | -217 | # airflow.sensors.external_task_sensor +220 | +221 | # airflow.sensors.external_task_sensor | = help: Use `airflow.sensors.external_task.ExternalDagLink` instead -AIR302_names.py:218:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskMarker` is removed in Airflow 3.0 +AIR302_names.py:222:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskMarker` is removed in Airflow 3.0 | -217 | # airflow.sensors.external_task_sensor -218 | ExternalTaskMarker +221 | # airflow.sensors.external_task_sensor +222 | ExternalTaskMarker | ^^^^^^^^^^^^^^^^^^ AIR302 -219 | ExternalTaskSensor -220 | ExternalTaskSensorLinkFromExternalTaskSensor +223 | ExternalTaskSensor +224 | ExternalTaskSensorLinkFromExternalTaskSensor | = help: Use `airflow.sensors.external_task.ExternalTaskMarker` instead -AIR302_names.py:219:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensor` is removed in Airflow 3.0 +AIR302_names.py:223:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensor` is removed in Airflow 3.0 | -217 | # airflow.sensors.external_task_sensor -218 | ExternalTaskMarker -219 | ExternalTaskSensor +221 | # airflow.sensors.external_task_sensor +222 | ExternalTaskMarker +223 | ExternalTaskSensor | ^^^^^^^^^^^^^^^^^^ AIR302 -220 | ExternalTaskSensorLinkFromExternalTaskSensor +224 | ExternalTaskSensorLinkFromExternalTaskSensor | = help: Use `airflow.sensors.external_task.ExternalTaskSensor` instead -AIR302_names.py:220:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensorLink` is removed in Airflow 3.0 +AIR302_names.py:224:1: AIR302 `airflow.sensors.external_task_sensor.ExternalTaskSensorLink` is removed in Airflow 3.0 | -218 | ExternalTaskMarker -219 | ExternalTaskSensor -220 | ExternalTaskSensorLinkFromExternalTaskSensor +222 | ExternalTaskMarker +223 | ExternalTaskSensor +224 | ExternalTaskSensorLinkFromExternalTaskSensor | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -221 | -222 | # airflow.sensors.time_delta_sensor +225 | +226 | # airflow.sensors.time_delta_sensor | = help: Use `airflow.sensors.external_task.ExternalDagLink` instead -AIR302_names.py:223:1: AIR302 `airflow.sensors.time_delta_sensor.TimeDeltaSensor` is removed in Airflow 3.0 +AIR302_names.py:227:1: AIR302 `airflow.sensors.time_delta_sensor.TimeDeltaSensor` is removed in Airflow 3.0 | -222 | # airflow.sensors.time_delta_sensor -223 | TimeDeltaSensor +226 | # airflow.sensors.time_delta_sensor +227 | TimeDeltaSensor | ^^^^^^^^^^^^^^^ AIR302 -224 | -225 | # airflow.timetables +228 | +229 | # airflow.timetables | = help: Use `airflow.sensors.time_delta.TimeDeltaSensor` instead -AIR302_names.py:226:1: AIR302 `airflow.timetables.datasets.DatasetOrTimeSchedule` is removed in Airflow 3.0 +AIR302_names.py:230:1: AIR302 `airflow.timetables.datasets.DatasetOrTimeSchedule` is removed in Airflow 3.0 | -225 | # airflow.timetables -226 | DatasetOrTimeSchedule +229 | # airflow.timetables +230 | DatasetOrTimeSchedule | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -227 | DatasetTriggeredTimetable +231 | DatasetTriggeredTimetable | = help: Use `airflow.timetables.assets.AssetOrTimeSchedule` instead -AIR302_names.py:227:1: AIR302 `airflow.timetables.simple.DatasetTriggeredTimetable` is removed in Airflow 3.0 +AIR302_names.py:231:1: AIR302 `airflow.timetables.simple.DatasetTriggeredTimetable` is removed in Airflow 3.0 | -225 | # airflow.timetables -226 | DatasetOrTimeSchedule -227 | DatasetTriggeredTimetable +229 | # airflow.timetables +230 | DatasetOrTimeSchedule +231 | DatasetTriggeredTimetable | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -228 | -229 | # airflow.triggers.external_task +232 | +233 | # airflow.triggers.external_task | = help: Use `airflow.timetables.simple.AssetTriggeredTimetable` instead -AIR302_names.py:230:1: AIR302 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 +AIR302_names.py:234:1: AIR302 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 | -229 | # airflow.triggers.external_task -230 | TaskStateTrigger +233 | # airflow.triggers.external_task +234 | TaskStateTrigger | ^^^^^^^^^^^^^^^^ AIR302 -231 | -232 | # airflow.utils.date +235 | +236 | # airflow.utils.date | -AIR302_names.py:233:7: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 +AIR302_names.py:237:7: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 | -232 | # airflow.utils.date -233 | dates.date_range +236 | # airflow.utils.date +237 | dates.date_range | ^^^^^^^^^^ AIR302 -234 | dates.days_ago +238 | dates.days_ago | = help: Use `airflow.timetables.` instead -AIR302_names.py:234:7: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 +AIR302_names.py:238:7: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 | -232 | # airflow.utils.date -233 | dates.date_range -234 | dates.days_ago +236 | # airflow.utils.date +237 | dates.date_range +238 | dates.days_ago | ^^^^^^^^ AIR302 -235 | -236 | date_range +239 | +240 | date_range | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:236:1: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 +AIR302_names.py:240:1: AIR302 `airflow.utils.dates.date_range` is removed in Airflow 3.0 | -234 | dates.days_ago -235 | -236 | date_range +238 | dates.days_ago +239 | +240 | date_range | ^^^^^^^^^^ AIR302 -237 | days_ago -238 | infer_time_unit +241 | days_ago +242 | infer_time_unit | = help: Use `airflow.timetables.` instead -AIR302_names.py:237:1: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 +AIR302_names.py:241:1: AIR302 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 | -236 | date_range -237 | days_ago +240 | date_range +241 | days_ago | ^^^^^^^^ AIR302 -238 | infer_time_unit -239 | parse_execution_date +242 | infer_time_unit +243 | parse_execution_date | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:238:1: AIR302 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 +AIR302_names.py:242:1: AIR302 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 | -236 | date_range -237 | days_ago -238 | infer_time_unit +240 | date_range +241 | days_ago +242 | infer_time_unit | ^^^^^^^^^^^^^^^ AIR302 -239 | parse_execution_date -240 | round_time +243 | parse_execution_date +244 | round_time | -AIR302_names.py:239:1: AIR302 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 +AIR302_names.py:243:1: AIR302 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 | -237 | days_ago -238 | infer_time_unit -239 | parse_execution_date +241 | days_ago +242 | infer_time_unit +243 | parse_execution_date | ^^^^^^^^^^^^^^^^^^^^ AIR302 -240 | round_time -241 | scale_time_units +244 | round_time +245 | scale_time_units | -AIR302_names.py:240:1: AIR302 `airflow.utils.dates.round_time` is removed in Airflow 3.0 +AIR302_names.py:244:1: AIR302 `airflow.utils.dates.round_time` is removed in Airflow 3.0 | -238 | infer_time_unit -239 | parse_execution_date -240 | round_time +242 | infer_time_unit +243 | parse_execution_date +244 | round_time | ^^^^^^^^^^ AIR302 -241 | scale_time_units +245 | scale_time_units | -AIR302_names.py:241:1: AIR302 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 +AIR302_names.py:245:1: AIR302 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 | -239 | parse_execution_date -240 | round_time -241 | scale_time_units +243 | parse_execution_date +244 | round_time +245 | scale_time_units | ^^^^^^^^^^^^^^^^ AIR302 -242 | -243 | # This one was not deprecated. +246 | +247 | # This one was not deprecated. | -AIR302_names.py:248:1: AIR302 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 +AIR302_names.py:252:1: AIR302 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 | -247 | # airflow.utils.dag_cycle_tester -248 | test_cycle +251 | # airflow.utils.dag_cycle_tester +252 | test_cycle | ^^^^^^^^^^ AIR302 -249 | -250 | # airflow.utils.decorators +253 | +254 | # airflow.utils.decorators | -AIR302_names.py:251: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:255:1: AIR302 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0; `apply_defaults` is now unconditionally done and can be safely removed. | -250 | # airflow.utils.decorators -251 | apply_defaults +254 | # airflow.utils.decorators +255 | apply_defaults | ^^^^^^^^^^^^^^ AIR302 -252 | -253 | # airflow.utils.file +256 | +257 | # airflow.utils.file | -AIR302_names.py:254:1: AIR302 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0 +AIR302_names.py:258:1: AIR302 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0 | -253 | # airflow.utils.file -254 | TemporaryDirectory, mkdirs +257 | # airflow.utils.file +258 | TemporaryDirectory, mkdirs | ^^^^^^^^^^^^^^^^^^ AIR302 -255 | -256 | # airflow.utils.helpers +259 | +260 | # airflow.utils.helpers | -AIR302_names.py:254:21: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 +AIR302_names.py:258:21: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 | -253 | # airflow.utils.file -254 | TemporaryDirectory, mkdirs +257 | # airflow.utils.file +258 | TemporaryDirectory, mkdirs | ^^^^^^ AIR302 -255 | -256 | # airflow.utils.helpers +259 | +260 | # airflow.utils.helpers | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:257:1: AIR302 `airflow.utils.helpers.chain` is removed in Airflow 3.0 +AIR302_names.py:261:1: AIR302 `airflow.utils.helpers.chain` is removed in Airflow 3.0 | -256 | # airflow.utils.helpers -257 | chain, cross_downstream +260 | # airflow.utils.helpers +261 | chain, cross_downstream | ^^^^^ AIR302 -258 | -259 | # airflow.utils.state +262 | +263 | # airflow.utils.state | = help: Use `airflow.models.baseoperator.chain` instead -AIR302_names.py:257:8: AIR302 `airflow.utils.helpers.cross_downstream` is removed in Airflow 3.0 +AIR302_names.py:261:8: AIR302 `airflow.utils.helpers.cross_downstream` is removed in Airflow 3.0 | -256 | # airflow.utils.helpers -257 | chain, cross_downstream +260 | # airflow.utils.helpers +261 | chain, cross_downstream | ^^^^^^^^^^^^^^^^ AIR302 -258 | -259 | # airflow.utils.state +262 | +263 | # airflow.utils.state | = help: Use `airflow.models.baseoperator.cross_downstream` instead -AIR302_names.py:260:1: AIR302 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 +AIR302_names.py:264:1: AIR302 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 | -259 | # airflow.utils.state -260 | SHUTDOWN, terminating_states +263 | # airflow.utils.state +264 | SHUTDOWN, terminating_states | ^^^^^^^^ AIR302 -261 | -262 | # airflow.utils.trigger_rule +265 | +266 | # airflow.utils.trigger_rule | -AIR302_names.py:260:11: AIR302 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 +AIR302_names.py:264:11: AIR302 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 | -259 | # airflow.utils.state -260 | SHUTDOWN, terminating_states +263 | # airflow.utils.state +264 | SHUTDOWN, terminating_states | ^^^^^^^^^^^^^^^^^^ AIR302 -261 | -262 | # airflow.utils.trigger_rule +265 | +266 | # airflow.utils.trigger_rule | -AIR302_names.py:263:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 +AIR302_names.py:267:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 | -262 | # airflow.utils.trigger_rule -263 | TriggerRule.DUMMY +266 | # airflow.utils.trigger_rule +267 | TriggerRule.DUMMY | ^^^^^ AIR302 -264 | TriggerRule.NONE_FAILED_OR_SKIPPED +268 | TriggerRule.NONE_FAILED_OR_SKIPPED | -AIR302_names.py:264:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0 +AIR302_names.py:268:13: AIR302 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0 | -262 | # airflow.utils.trigger_rule -263 | TriggerRule.DUMMY -264 | TriggerRule.NONE_FAILED_OR_SKIPPED +266 | # airflow.utils.trigger_rule +267 | TriggerRule.DUMMY +268 | TriggerRule.NONE_FAILED_OR_SKIPPED | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -265 | -266 | # airflow.www.auth +269 | +270 | # airflow.www.auth | -AIR302_names.py:267:1: AIR302 `airflow.www.auth.has_access` is removed in Airflow 3.0 +AIR302_names.py:271:1: AIR302 `airflow.www.auth.has_access` is removed in Airflow 3.0 | -266 | # airflow.www.auth -267 | has_access +270 | # airflow.www.auth +271 | has_access | ^^^^^^^^^^ AIR302 -268 | has_access_dataset +272 | has_access_dataset | = help: Use `airflow.www.auth.has_access_*` instead -AIR302_names.py:268:1: AIR302 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0 +AIR302_names.py:272:1: AIR302 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0 | -266 | # airflow.www.auth -267 | has_access -268 | has_access_dataset +270 | # airflow.www.auth +271 | has_access +272 | has_access_dataset | ^^^^^^^^^^^^^^^^^^ AIR302 -269 | -270 | # airflow.www.utils +273 | +274 | # airflow.www.utils | = help: Use `airflow.www.auth.has_access_dataset.has_access_asset` instead -AIR302_names.py:271:1: AIR302 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0 +AIR302_names.py:275:1: AIR302 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0 | -270 | # airflow.www.utils -271 | get_sensitive_variables_fields, should_hide_value_for_key +274 | # airflow.www.utils +275 | get_sensitive_variables_fields, should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.utils.log.secrets_masker.get_sensitive_variables_fields` instead -AIR302_names.py:271:33: AIR302 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0 +AIR302_names.py:275:33: AIR302 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0 | -270 | # airflow.www.utils -271 | get_sensitive_variables_fields, should_hide_value_for_key +274 | # airflow.www.utils +275 | get_sensitive_variables_fields, should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.utils.log.secrets_masker.should_hide_value_for_key` instead From c59cdd25de80b12e1018bfdcd68173c8c6c7638a Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Mon, 30 Dec 2024 23:09:36 +0900 Subject: [PATCH 09/12] refactor(AIR303): refactor utility functions with is_airflow_builtin_or_provider --- .../src/rules/airflow/rules/removal_in_3.rs | 238 +++++++----------- 1 file changed, 96 insertions(+), 142 deletions(-) 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 3f718d95daeaf..0f6831317f419 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 @@ -11,45 +11,21 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -fn is_airflow_secret_backend(segments: &[&str]) -> bool { +fn is_airflow_builtin_or_provider(segments: &[&str], module: &str, symbol_suffix: &str) -> bool { match segments { - ["airflow", "secrets", rest @ ..] => { - if let Some(last_element) = rest.last() { - last_element.ends_with("Backend") - } else { - false - } - } - ["airflow", "providers", rest @ ..] => { if let (Some(pos), Some(last_element)) = - (rest.iter().position(|&s| s == "secrets"), rest.last()) + (rest.iter().position(|&s| s == module), rest.last()) { - pos + 1 < rest.len() && last_element.ends_with("Backend") - } else { - false - } - } - - _ => false, - } -} - -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") + pos + 1 < rest.len() && last_element.ends_with(symbol_suffix) } 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") + ["airflow", rest @ ..] => { + if let (Some(start_element), Some(last_element)) = (rest.first(), rest.last()) { + start_element.starts_with(module) & last_element.ends_with(symbol_suffix) } else { false } @@ -59,35 +35,27 @@ fn is_airflow_auth_manager(segments: &[&str]) -> bool { } } -fn is_airflow_hook(qualname: &QualifiedName) -> bool { - match qualname.segments() { - ["airflow", "hooks", rest @ ..] => { - if let Some(last_element) = rest.last() { - last_element.ends_with("Hook") - } else { - false - } - } - - ["airflow", "providers", rest @ ..] => { - if let (Some(pos), Some(last_element)) = - (rest.iter().position(|&s| s == "hooks"), rest.last()) - { - pos + 1 < rest.len() && last_element.ends_with("Hook") - } else { - false - } - } +fn is_airflow_secret_backend(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "secrets", "Backend") +} - _ => false, - } +fn is_airflow_hook(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "hooks", "Hook") } fn is_airflow_operator(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "operators", "Operator") +} + +fn is_airflow_task_handler(segments: &[&str]) -> bool { + is_airflow_builtin_or_provider(segments, "log", "TaskHandler") +} + +fn is_airflow_auth_manager(segments: &[&str]) -> bool { match segments { - ["airflow", "operators", rest @ ..] => { + ["airflow", "auth", "manager", rest @ ..] => { if let Some(last_element) = rest.last() { - last_element.ends_with("Operator") + last_element.ends_with("AuthManager") } else { false } @@ -95,27 +63,9 @@ fn is_airflow_operator(segments: &[&str]) -> bool { ["airflow", "providers", rest @ ..] => { if let (Some(pos), Some(last_element)) = - (rest.iter().position(|&s| s == "operators"), rest.last()) - { - pos + 1 < rest.len() && last_element.ends_with("Operator") - } else { - false - } - } - - _ => false, - } -} - -fn is_airflow_task_handler(segments: &[&str]) -> bool { - match segments { - ["airflow", "utils", "log", "file_task_handler", "FileTaskHandler"] => true, - - ["airflow", "providers", rest @ ..] => { - if let (Some(pos), Some(last_element)) = - (rest.iter().position(|&s| s == "log"), rest.last()) + (rest.iter().position(|&s| s == "auth_manager"), rest.last()) { - pos + 1 < rest.len() && last_element.ends_with("TaskHandler") + pos + 1 < rest.len() && last_element.ends_with("AuthManager") } else { false } @@ -241,70 +191,68 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: None::<&str>, )); } - _ 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(), - )); - } - } - _ if is_airflow_task_handler(qualname.segments()) => { - checker.diagnostics.extend(diagnostic_for_argument( - arguments, - "filename_template", - None::<&str>, - )); - } - _ 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"), + _ => { + 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(), )); } - ["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"), - )); + } 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"), + )); + } + _ => {} } - _ => {} } } - - _ => {} }; } @@ -389,16 +337,22 @@ fn removed_method(checker: &mut Checker, expr: &Expr) { "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, - }, - _ if is_airflow_hook(&qualname) => match attr.as_str() { - "get_connections" => Some(Replacement::Name("get_connection")), - &_ => None, - }, - _ => 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( From a50ea8600d6731e1381164905214d77cc8d11e39 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Mon, 30 Dec 2024 23:28:28 +0900 Subject: [PATCH 10/12] feat(AIR302): extend the following rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `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` --- .../test/fixtures/airflow/AIR302_names.py | 87 +- .../src/rules/airflow/rules/removal_in_3.rs | 51 +- ...irflow__tests__AIR302_AIR302_names.py.snap | 1199 +++++++++-------- 3 files changed, 732 insertions(+), 605 deletions(-) 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 823264e8aa4f6..ff6d7b0ee6cd6 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR302_names.py @@ -30,12 +30,12 @@ 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 @@ -43,8 +43,16 @@ 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 @@ -86,7 +94,7 @@ 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 @@ -95,7 +103,7 @@ # airflow root PY36, PY37, PY38, PY39, PY310, PY311, PY312 -DatasetFromRoot +DatasetFromRoot() dataset_from_root = DatasetFromRoot() dataset_from_root.iter_datasets() @@ -106,23 +114,23 @@ # 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() @@ -137,38 +145,51 @@ 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 @@ -195,7 +216,7 @@ mysql.sanitize_uri # airflow.providers.openlineage -DatasetInfo, translate_airflow_dataset +DatasetInfo(), translate_airflow_dataset # airflow.providers.postgres postgres.sanitize_uri @@ -210,28 +231,28 @@ 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 @@ -255,7 +276,7 @@ apply_defaults # airflow.utils.file -TemporaryDirectory, mkdirs +TemporaryDirector(), mkdirs # airflow.utils.helpers chain, cross_downstream 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 0f6831317f419..14edb568c6a7e 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 @@ -560,10 +560,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"), @@ -592,6 +588,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"), 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 299374e4ced8d..0b9980d54909d 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,1039 +2,1102 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs snapshot_kind: text --- -AIR302_names.py:97:1: AIR302 `airflow.PY36` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:7: AIR302 `airflow.PY37` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:13: AIR302 `airflow.PY38` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:19: AIR302 `airflow.PY39` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:25: AIR302 `airflow.PY310` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:32: AIR302 `airflow.PY311` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:97:39: AIR302 `airflow.PY312` is removed in Airflow 3.0 - | -96 | # airflow root -97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - | ^^^^^ AIR302 -98 | DatasetFromRoot - | - = help: Use `sys.version_info` instead - -AIR302_names.py:98:1: AIR302 `airflow.Dataset` is removed in Airflow 3.0 - | - 96 | # airflow root - 97 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 - 98 | DatasetFromRoot +AIR302_names.py:105:1: AIR302 `airflow.PY36` 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: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 - 99 | -100 | dataset_from_root = DatasetFromRoot() +107 | +108 | dataset_from_root = DatasetFromRoot() | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:100:21: AIR302 `airflow.Dataset` is removed in Airflow 3.0 +AIR302_names.py:108:21: AIR302 `airflow.Dataset` is removed in Airflow 3.0 | - 98 | DatasetFromRoot - 99 | -100 | dataset_from_root = DatasetFromRoot() +106 | DatasetFromRoot() +107 | +108 | dataset_from_root = DatasetFromRoot() | ^^^^^^^^^^^^^^^ AIR302 -101 | dataset_from_root.iter_datasets() -102 | dataset_from_root.iter_dataset_aliases() +109 | dataset_from_root.iter_datasets() +110 | dataset_from_root.iter_dataset_aliases() | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:101:19: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:109:19: AIR302 `iter_datasets` is removed in Airflow 3.0 | -100 | dataset_from_root = DatasetFromRoot() -101 | dataset_from_root.iter_datasets() +108 | dataset_from_root = DatasetFromRoot() +109 | dataset_from_root.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -102 | dataset_from_root.iter_dataset_aliases() +110 | dataset_from_root.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:102:19: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:110:19: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -100 | dataset_from_root = DatasetFromRoot() -101 | dataset_from_root.iter_datasets() -102 | dataset_from_root.iter_dataset_aliases() +108 | dataset_from_root = DatasetFromRoot() +109 | dataset_from_root.iter_datasets() +110 | dataset_from_root.iter_dataset_aliases() | ^^^^^^^^^^^^^^^^^^^^ AIR302 -103 | -104 | # airflow.api_connexion.security +111 | +112 | # airflow.api_connexion.security | = help: Use `iter_asset_aliases` instead -AIR302_names.py:105:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 +AIR302_names.py:113:1: AIR302 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 | -104 | # airflow.api_connexion.security -105 | requires_access, requires_access_dataset +112 | # airflow.api_connexion.security +113 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^ AIR302 -106 | -107 | # airflow.auth.managers +114 | +115 | # airflow.auth.managers | = help: Use `airflow.api_connexion.security.requires_access_*` instead -AIR302_names.py:105: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 | -104 | # airflow.api_connexion.security -105 | requires_access, requires_access_dataset +112 | # airflow.api_connexion.security +113 | requires_access, requires_access_dataset | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -106 | -107 | # airflow.auth.managers +114 | +115 | # airflow.auth.managers | = help: Use `airflow.api_connexion.security.requires_access_asset` instead -AIR302_names.py:108: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 | -107 | # airflow.auth.managers -108 | is_authorized_dataset +115 | # airflow.auth.managers +116 | is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -109 | DatasetDetails +117 | DatasetDetails() | = help: Use `airflow.auth.managers.base_auth_manager.is_authorized_asset` instead -AIR302_names.py:109: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 | -107 | # airflow.auth.managers -108 | is_authorized_dataset -109 | DatasetDetails +115 | # airflow.auth.managers +116 | is_authorized_dataset +117 | DatasetDetails() | ^^^^^^^^^^^^^^ AIR302 -110 | -111 | # airflow.configuration +118 | +119 | # airflow.configuration | = help: Use `airflow.auth.managers.models.resource_details.AssetDetails` instead -AIR302_names.py:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:112: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 | -111 | # airflow.configuration -112 | 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:116: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. | -115 | # airflow.contrib.* -116 | AWSAthenaHook +123 | # airflow.contrib.* +124 | AWSAthenaHook() | ^^^^^^^^^^^^^ AIR302 -117 | -118 | # airflow.datasets +125 | +126 | # airflow.datasets | -AIR302_names.py:119: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 | -118 | # airflow.datasets -119 | Dataset +126 | # airflow.datasets +127 | Dataset() | ^^^^^^^ AIR302 -120 | DatasetAlias -121 | DatasetAliasEvent +128 | DatasetAlias() +129 | DatasetAliasEvent() | = help: Use `airflow.sdk.definitions.asset.Asset` instead -AIR302_names.py:120: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 | -118 | # airflow.datasets -119 | Dataset -120 | DatasetAlias +126 | # airflow.datasets +127 | Dataset() +128 | DatasetAlias() | ^^^^^^^^^^^^ AIR302 -121 | DatasetAliasEvent -122 | DatasetAll +129 | DatasetAliasEvent() +130 | DatasetAll() | = help: Use `airflow.sdk.definitions.asset.AssetAlias` instead -AIR302_names.py:121: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 | -119 | Dataset -120 | DatasetAlias -121 | DatasetAliasEvent +127 | Dataset() +128 | DatasetAlias() +129 | DatasetAliasEvent() | ^^^^^^^^^^^^^^^^^ AIR302 -122 | DatasetAll -123 | DatasetAny +130 | DatasetAll() +131 | DatasetAny() | -AIR302_names.py:122: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 | -120 | DatasetAlias -121 | DatasetAliasEvent -122 | DatasetAll +128 | DatasetAlias() +129 | DatasetAliasEvent() +130 | DatasetAll() | ^^^^^^^^^^ AIR302 -123 | DatasetAny -124 | expand_alias_to_datasets +131 | DatasetAny() +132 | expand_alias_to_datasets | = help: Use `airflow.sdk.definitions.asset.AssetAll` instead -AIR302_names.py:123: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 | -121 | DatasetAliasEvent -122 | DatasetAll -123 | DatasetAny +129 | DatasetAliasEvent() +130 | DatasetAll() +131 | DatasetAny() | ^^^^^^^^^^ AIR302 -124 | expand_alias_to_datasets -125 | Metadata +132 | expand_alias_to_datasets +133 | Metadata() | = help: Use `airflow.sdk.definitions.asset.AssetAny` instead -AIR302_names.py:124: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 | -122 | DatasetAll -123 | DatasetAny -124 | expand_alias_to_datasets +130 | DatasetAll() +131 | DatasetAny() +132 | expand_alias_to_datasets | ^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -125 | Metadata +133 | Metadata() | = help: Use `airflow.sdk.definitions.asset.expand_alias_to_assets` instead -AIR302_names.py:125: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 | -123 | DatasetAny -124 | expand_alias_to_datasets -125 | Metadata +131 | DatasetAny() +132 | expand_alias_to_datasets +133 | Metadata() | ^^^^^^^^ AIR302 -126 | -127 | dataset_to_test_method_call = Dataset() +134 | +135 | dataset_to_test_method_call = Dataset() | = help: Use `airflow.sdk.definitions.asset.metadata.Metadata` instead -AIR302_names.py:127:31: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 +AIR302_names.py:135:31: AIR302 `airflow.datasets.Dataset` is removed in Airflow 3.0 | -125 | Metadata -126 | -127 | dataset_to_test_method_call = Dataset() +133 | Metadata() +134 | +135 | dataset_to_test_method_call = Dataset() | ^^^^^^^ AIR302 -128 | dataset_to_test_method_call.iter_datasets() -129 | dataset_to_test_method_call.iter_dataset_aliases() +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:128:29: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:136:29: AIR302 `iter_datasets` is removed in Airflow 3.0 | -127 | dataset_to_test_method_call = Dataset() -128 | dataset_to_test_method_call.iter_datasets() +135 | dataset_to_test_method_call = Dataset() +136 | dataset_to_test_method_call.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -129 | dataset_to_test_method_call.iter_dataset_aliases() +137 | dataset_to_test_method_call.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:129:29: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:137:29: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -127 | dataset_to_test_method_call = Dataset() -128 | dataset_to_test_method_call.iter_datasets() -129 | dataset_to_test_method_call.iter_dataset_aliases() +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 -130 | -131 | alias_to_test_method_call = DatasetAlias() +138 | +139 | alias_to_test_method_call = DatasetAlias() | = help: Use `iter_asset_aliases` instead -AIR302_names.py:131:29: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 +AIR302_names.py:139:29: AIR302 `airflow.datasets.DatasetAlias` is removed in Airflow 3.0 | -129 | dataset_to_test_method_call.iter_dataset_aliases() -130 | -131 | alias_to_test_method_call = DatasetAlias() +137 | dataset_to_test_method_call.iter_dataset_aliases() +138 | +139 | alias_to_test_method_call = DatasetAlias() | ^^^^^^^^^^^^ AIR302 -132 | alias_to_test_method_call.iter_datasets() -133 | alias_to_test_method_call.iter_dataset_aliases() +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:132:27: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:140:27: AIR302 `iter_datasets` is removed in Airflow 3.0 | -131 | alias_to_test_method_call = DatasetAlias() -132 | alias_to_test_method_call.iter_datasets() +139 | alias_to_test_method_call = DatasetAlias() +140 | alias_to_test_method_call.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -133 | alias_to_test_method_call.iter_dataset_aliases() +141 | alias_to_test_method_call.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:133:27: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:141:27: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -131 | alias_to_test_method_call = DatasetAlias() -132 | alias_to_test_method_call.iter_datasets() -133 | alias_to_test_method_call.iter_dataset_aliases() +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 -134 | -135 | any_to_test_method_call = DatasetAny() +142 | +143 | any_to_test_method_call = DatasetAny() | = help: Use `iter_asset_aliases` instead -AIR302_names.py:135:27: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 +AIR302_names.py:143:27: AIR302 `airflow.datasets.DatasetAny` is removed in Airflow 3.0 | -133 | alias_to_test_method_call.iter_dataset_aliases() -134 | -135 | any_to_test_method_call = DatasetAny() +141 | alias_to_test_method_call.iter_dataset_aliases() +142 | +143 | any_to_test_method_call = DatasetAny() | ^^^^^^^^^^ AIR302 -136 | any_to_test_method_call.iter_datasets() -137 | any_to_test_method_call.iter_dataset_aliases() +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:136:25: AIR302 `iter_datasets` is removed in Airflow 3.0 +AIR302_names.py:144:25: AIR302 `iter_datasets` is removed in Airflow 3.0 | -135 | any_to_test_method_call = DatasetAny() -136 | any_to_test_method_call.iter_datasets() +143 | any_to_test_method_call = DatasetAny() +144 | any_to_test_method_call.iter_datasets() | ^^^^^^^^^^^^^ AIR302 -137 | any_to_test_method_call.iter_dataset_aliases() +145 | any_to_test_method_call.iter_dataset_aliases() | = help: Use `iter_assets` instead -AIR302_names.py:137:25: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 +AIR302_names.py:145:25: AIR302 `iter_dataset_aliases` is removed in Airflow 3.0 | -135 | any_to_test_method_call = DatasetAny() -136 | any_to_test_method_call.iter_datasets() -137 | any_to_test_method_call.iter_dataset_aliases() +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 -138 | -139 | # airflow.datasets.manager +146 | +147 | # airflow.datasets.manager | = help: Use `iter_asset_aliases` instead -AIR302_names.py:140:17: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 +AIR302_names.py:148:19: AIR302 `airflow.datasets.manager.dataset_manager` is removed in Airflow 3.0 | -139 | # airflow.datasets.manager -140 | DatasetManager, dataset_manager, resolve_dataset_manager - | ^^^^^^^^^^^^^^^ AIR302 -141 | -142 | # airflow.hooks +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:140: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 | -139 | # airflow.datasets.manager -140 | DatasetManager, dataset_manager, resolve_dataset_manager - | ^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -141 | -142 | # airflow.hooks +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:143:1: AIR302 `airflow.hooks.base_hook.BaseHook` is removed in Airflow 3.0 +AIR302_names.py:151:1: AIR302 `airflow.hooks.base_hook.BaseHook` is removed in Airflow 3.0 | -142 | # airflow.hooks -143 | BaseHook() +150 | # airflow.hooks +151 | BaseHook() | ^^^^^^^^ AIR302 -144 | -145 | # airflow.lineage.hook +152 | +153 | # airflow.lineage.hook | = help: Use `airflow.hooks.base.BaseHook` instead -AIR302_names.py:146:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 +AIR302_names.py:154:1: AIR302 `airflow.lineage.hook.DatasetLineageInfo` is removed in Airflow 3.0 | -145 | # airflow.lineage.hook -146 | DatasetLineageInfo +153 | # airflow.lineage.hook +154 | DatasetLineageInfo() | ^^^^^^^^^^^^^^^^^^ AIR302 -147 | -148 | # airflow.listeners.spec.dataset +155 | +156 | # airflow.listeners.spec.dataset | = help: Use `airflow.lineage.hook.AssetLineageInfo` instead -AIR302_names.py:149: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 | -148 | # airflow.listeners.spec.dataset -149 | on_dataset_changed, on_dataset_created +156 | # airflow.listeners.spec.dataset +157 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -150 | -151 | # airflow.metrics.validators +158 | +159 | # airflow.metrics.validators | = help: Use `airflow.listeners.spec.asset.on_asset_changed` instead -AIR302_names.py:149: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 | -148 | # airflow.listeners.spec.dataset -149 | on_dataset_changed, on_dataset_created +156 | # airflow.listeners.spec.dataset +157 | on_dataset_changed, on_dataset_created | ^^^^^^^^^^^^^^^^^^ AIR302 -150 | -151 | # airflow.metrics.validators +158 | +159 | # airflow.metrics.validators | = help: Use `airflow.listeners.spec.asset.on_asset_created` instead -AIR302_names.py:152: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 | -151 | # airflow.metrics.validators -152 | AllowListValidator, BlockListValidator +159 | # airflow.metrics.validators +160 | AllowListValidator(), BlockListValidator() | ^^^^^^^^^^^^^^^^^^ AIR302 -153 | -154 | # airflow.operators.dummy_operator +161 | +162 | # airflow.operators.dummy_operator | = help: Use `airflow.metrics.validators.PatternAllowListValidator` instead -AIR302_names.py:152: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 | -151 | # airflow.metrics.validators -152 | AllowListValidator, BlockListValidator - | ^^^^^^^^^^^^^^^^^^ AIR302 -153 | -154 | # 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:155: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 | -154 | # airflow.operators.dummy_operator -155 | dummy_operator.EmptyOperator +162 | # airflow.operators.dummy_operator +163 | dummy_operator.EmptyOperator() | ^^^^^^^^^^^^^ AIR302 -156 | dummy_operator.DummyOperator +164 | dummy_operator.DummyOperator() | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:156: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 | -154 | # airflow.operators.dummy_operator -155 | dummy_operator.EmptyOperator -156 | dummy_operator.DummyOperator +162 | # airflow.operators.dummy_operator +163 | dummy_operator.EmptyOperator() +164 | dummy_operator.DummyOperator() | ^^^^^^^^^^^^^ AIR302 -157 | -158 | # airflow.operators.bash_operator +165 | +166 | # airflow.operators.bash_operator | = help: Use `airflow.operators.empty.EmptyOperator` instead -AIR302_names.py:159: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 | -158 | # airflow.operators.bash_operator -159 | BashOperator +166 | # airflow.operators.bash_operator +167 | BashOperator() | ^^^^^^^^^^^^ AIR302 -160 | -161 | # airflow.operators.branch_operator +168 | +169 | # airflow.operators.branch_operator | = help: Use `airflow.operators.bash.BashOperator` instead -AIR302_names.py:162: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 | -161 | # airflow.operators.branch_operator -162 | BaseBranchOperator +169 | # airflow.operators.branch_operator +170 | BaseBranchOperator() | ^^^^^^^^^^^^^^^^^^ AIR302 -163 | -164 | # airflow.operators.dummy +171 | +172 | # airflow.operators.dagrun_operator | = help: Use `airflow.operators.branch.BaseBranchOperator` instead -AIR302_names.py:165: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 | -164 | # airflow.operators.dummy -165 | EmptyOperator, DummyOperator - | ^^^^^^^^^^^^^ AIR302 -166 | -167 | # 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:168: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 | -167 | # airflow.operators.email_operator -168 | EmailOperator +179 | # airflow.operators.email_operator +180 | EmailOperator() | ^^^^^^^^^^^^^ AIR302 -169 | -170 | # airflow.operators.subdag.* +181 | +182 | # airflow.operators.latest_only_operator | = help: Use `airflow.operators.email.EmailOperator` instead -AIR302_names.py:171: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 + | +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 | -170 | # airflow.operators.subdag.* -171 | SubDagOperator +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 +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 -172 | -173 | # airflow.providers.amazon +193 | +194 | # airflow.providers.amazon | -AIR302_names.py:174: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 | -173 | # airflow.providers.amazon -174 | AvpEntities.DATASET +194 | # airflow.providers.amazon +195 | AvpEntities.DATASET | ^^^^^^^ AIR302 -175 | s3.create_dataset -176 | 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:175: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 | -173 | # airflow.providers.amazon -174 | AvpEntities.DATASET -175 | s3.create_dataset +194 | # airflow.providers.amazon +195 | AvpEntities.DATASET +196 | s3.create_dataset | ^^^^^^^^^^^^^^ AIR302 -176 | s3.convert_dataset_to_openlineage -177 | 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:176: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 | -174 | AvpEntities.DATASET -175 | s3.create_dataset -176 | s3.convert_dataset_to_openlineage +195 | AvpEntities.DATASET +196 | s3.create_dataset +197 | s3.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -177 | s3.sanitize_uri +198 | s3.sanitize_uri | = help: Use `airflow.providers.amazon.aws.assets.s3.convert_asset_to_openlineage` instead -AIR302_names.py:177: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 | -175 | s3.create_dataset -176 | s3.convert_dataset_to_openlineage -177 | s3.sanitize_uri +196 | s3.create_dataset +197 | s3.convert_dataset_to_openlineage +198 | s3.sanitize_uri | ^^^^^^^^^^^^ AIR302 -178 | -179 | # airflow.providers.common.io +199 | +200 | # airflow.providers.common.io | = help: Use `airflow.providers.amazon.aws.assets.s3.sanitize_uri` instead -AIR302_names.py:180: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 | -179 | # airflow.providers.common.io -180 | common_io_file.convert_dataset_to_openlineage +200 | # airflow.providers.common.io +201 | common_io_file.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -181 | common_io_file.create_dataset -182 | 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:181: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 | -179 | # airflow.providers.common.io -180 | common_io_file.convert_dataset_to_openlineage -181 | 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 -182 | 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:182: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 | -180 | common_io_file.convert_dataset_to_openlineage -181 | common_io_file.create_dataset -182 | 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 -183 | -184 | # airflow.providers.fab +204 | +205 | # airflow.providers.fab | = help: Use `airflow.providers.common.io.assets.file.sanitize_uri` instead -AIR302_names.py:185: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 | -184 | # airflow.providers.fab -185 | fab_auth_manager.is_authorized_dataset +205 | # airflow.providers.fab +206 | fab_auth_manager.is_authorized_dataset | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -186 | -187 | # 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:190: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 | -188 | bigquery.sanitize_uri -189 | -190 | gcs.create_dataset +209 | bigquery.sanitize_uri +210 | +211 | gcs.create_dataset | ^^^^^^^^^^^^^^ AIR302 -191 | gcs.sanitize_uri -192 | 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:191: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 | -190 | gcs.create_dataset -191 | gcs.sanitize_uri +211 | gcs.create_dataset +212 | gcs.sanitize_uri | ^^^^^^^^^^^^ AIR302 -192 | gcs.convert_dataset_to_openlineage +213 | gcs.convert_dataset_to_openlineage | = help: Use `airflow.providers.google.assets.gcs.sanitize_uri` instead -AIR302_names.py:192: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 | -190 | gcs.create_dataset -191 | gcs.sanitize_uri -192 | gcs.convert_dataset_to_openlineage +211 | gcs.create_dataset +212 | gcs.sanitize_uri +213 | gcs.convert_dataset_to_openlineage | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -193 | -194 | # airflow.providers.mysql +214 | +215 | # airflow.providers.mysql | = help: Use `airflow.providers.google.assets.gcs.convert_asset_to_openlineage` instead -AIR302_names.py:195: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 | -194 | # airflow.providers.mysql -195 | mysql.sanitize_uri +215 | # airflow.providers.mysql +216 | mysql.sanitize_uri | ^^^^^^^^^^^^ AIR302 -196 | -197 | # airflow.providers.openlineage +217 | +218 | # airflow.providers.openlineage | = help: Use `airflow.providers.mysql.assets.mysql.sanitize_uri` instead -AIR302_names.py:198: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 | -197 | # airflow.providers.openlineage -198 | DatasetInfo, translate_airflow_dataset +218 | # airflow.providers.openlineage +219 | DatasetInfo(), translate_airflow_dataset | ^^^^^^^^^^^ AIR302 -199 | -200 | # airflow.providers.postgres +220 | +221 | # airflow.providers.postgres | = help: Use `airflow.providers.openlineage.utils.utils.AssetInfo` instead -AIR302_names.py:198: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 | -197 | # airflow.providers.openlineage -198 | DatasetInfo, translate_airflow_dataset - | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -199 | -200 | # 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:201: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 | -200 | # airflow.providers.postgres -201 | postgres.sanitize_uri +221 | # airflow.providers.postgres +222 | postgres.sanitize_uri | ^^^^^^^^^^^^ AIR302 -202 | -203 | # airflow.providers.trino +223 | +224 | # airflow.providers.trino | = help: Use `airflow.providers.postgres.assets.postgres.sanitize_uri` instead -AIR302_names.py:204: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 | -203 | # airflow.providers.trino -204 | trino.sanitize_uri +224 | # airflow.providers.trino +225 | trino.sanitize_uri | ^^^^^^^^^^^^ AIR302 -205 | -206 | # airflow.secrets +226 | +227 | # airflow.secrets | = help: Use `airflow.providers.trino.assets.trino.sanitize_uri` instead -AIR302_names.py:207: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 | -206 | # airflow.secrets -207 | get_connection, load_connections +227 | # airflow.secrets +228 | get_connection, load_connections | ^^^^^^^^^^^^^^ AIR302 -208 | -209 | # airflow.security.permissions +229 | +230 | # airflow.security.permissions | = help: Use `airflow.secrets.local_filesystem.load_connections_dict` instead -AIR302_names.py:207: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 | -206 | # airflow.secrets -207 | get_connection, load_connections +227 | # airflow.secrets +228 | get_connection, load_connections | ^^^^^^^^^^^^^^^^ AIR302 -208 | -209 | # airflow.security.permissions +229 | +230 | # airflow.security.permissions | = help: Use `airflow.secrets.local_filesystem.load_connections_dict` instead -AIR302_names.py:210: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 | -209 | # airflow.security.permissions -210 | RESOURCE_DATASET +230 | # airflow.security.permissions +231 | RESOURCE_DATASET | ^^^^^^^^^^^^^^^^ AIR302 -211 | -212 | # airflow.sensors.base_sensor_operator +232 | +233 | # airflow.sensors.base_sensor_operator | = help: Use `airflow.security.permissions.RESOURCE_ASSET` instead -AIR302_names.py:213: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 | -212 | # airflow.sensors.base_sensor_operator -213 | BaseSensorOperator +233 | # airflow.sensors.base_sensor_operator +234 | BaseSensorOperator() | ^^^^^^^^^^^^^^^^^^ AIR302 -214 | -215 | # airflow.sensors.date_time_sensor +235 | +236 | # airflow.sensors.date_time_sensor | = help: Use `airflow.sensors.base.BaseSensorOperator` instead -AIR302_names.py:216: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 | -215 | # airflow.sensors.date_time_sensor -216 | DateTimeSensor +236 | # airflow.sensors.date_time_sensor +237 | DateTimeSensor() | ^^^^^^^^^^^^^^ AIR302 -217 | -218 | # airflow.sensors.external_task +238 | +239 | # airflow.sensors.external_task | = help: Use `airflow.sensors.date_time.DateTimeSensor` instead -AIR302_names.py:219: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 | -218 | # airflow.sensors.external_task -219 | ExternalTaskSensorLinkFromExternalTask +239 | # airflow.sensors.external_task +240 | ExternalTaskSensorLinkFromExternalTask() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -220 | -221 | # airflow.sensors.external_task_sensor +241 | +242 | # airflow.sensors.external_task_sensor | = help: Use `airflow.sensors.external_task.ExternalDagLink` instead -AIR302_names.py:222: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 | -221 | # airflow.sensors.external_task_sensor -222 | ExternalTaskMarker +242 | # airflow.sensors.external_task_sensor +243 | ExternalTaskMarker() | ^^^^^^^^^^^^^^^^^^ AIR302 -223 | ExternalTaskSensor -224 | ExternalTaskSensorLinkFromExternalTaskSensor +244 | ExternalTaskSensor() +245 | ExternalTaskSensorLinkFromExternalTaskSensor() | = help: Use `airflow.sensors.external_task.ExternalTaskMarker` instead -AIR302_names.py:223: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 | -221 | # airflow.sensors.external_task_sensor -222 | ExternalTaskMarker -223 | ExternalTaskSensor +242 | # airflow.sensors.external_task_sensor +243 | ExternalTaskMarker() +244 | ExternalTaskSensor() | ^^^^^^^^^^^^^^^^^^ AIR302 -224 | ExternalTaskSensorLinkFromExternalTaskSensor +245 | ExternalTaskSensorLinkFromExternalTaskSensor() | = help: Use `airflow.sensors.external_task.ExternalTaskSensor` instead -AIR302_names.py:224: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 | -222 | ExternalTaskMarker -223 | ExternalTaskSensor -224 | ExternalTaskSensorLinkFromExternalTaskSensor +243 | ExternalTaskMarker() +244 | ExternalTaskSensor() +245 | ExternalTaskSensorLinkFromExternalTaskSensor() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -225 | -226 | # airflow.sensors.time_delta_sensor +246 | +247 | # airflow.sensors.time_delta_sensor | = help: Use `airflow.sensors.external_task.ExternalDagLink` instead -AIR302_names.py:227: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 | -226 | # airflow.sensors.time_delta_sensor -227 | TimeDeltaSensor +247 | # airflow.sensors.time_delta_sensor +248 | TimeDeltaSensor() | ^^^^^^^^^^^^^^^ AIR302 -228 | -229 | # airflow.timetables +249 | +250 | # airflow.timetables | = help: Use `airflow.sensors.time_delta.TimeDeltaSensor` instead -AIR302_names.py:230: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 | -229 | # airflow.timetables -230 | DatasetOrTimeSchedule +250 | # airflow.timetables +251 | DatasetOrTimeSchedule() | ^^^^^^^^^^^^^^^^^^^^^ AIR302 -231 | DatasetTriggeredTimetable +252 | DatasetTriggeredTimetable() | = help: Use `airflow.timetables.assets.AssetOrTimeSchedule` instead -AIR302_names.py:231: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 | -229 | # airflow.timetables -230 | DatasetOrTimeSchedule -231 | DatasetTriggeredTimetable +250 | # airflow.timetables +251 | DatasetOrTimeSchedule() +252 | DatasetTriggeredTimetable() | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 -232 | -233 | # airflow.triggers.external_task +253 | +254 | # airflow.triggers.external_task | = help: Use `airflow.timetables.simple.AssetTriggeredTimetable` instead -AIR302_names.py:234: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 | -233 | # airflow.triggers.external_task -234 | TaskStateTrigger +254 | # airflow.triggers.external_task +255 | TaskStateTrigger() | ^^^^^^^^^^^^^^^^ AIR302 -235 | -236 | # airflow.utils.date +256 | +257 | # airflow.utils.date | -AIR302_names.py:237: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 | -236 | # airflow.utils.date -237 | dates.date_range +257 | # airflow.utils.date +258 | dates.date_range | ^^^^^^^^^^ AIR302 -238 | dates.days_ago +259 | dates.days_ago | = help: Use `airflow.timetables.` instead -AIR302_names.py:238: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 | -236 | # airflow.utils.date -237 | dates.date_range -238 | dates.days_ago +257 | # airflow.utils.date +258 | dates.date_range +259 | dates.days_ago | ^^^^^^^^ AIR302 -239 | -240 | date_range +260 | +261 | date_range | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:240: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 | -238 | dates.days_ago -239 | -240 | date_range +259 | dates.days_ago +260 | +261 | date_range | ^^^^^^^^^^ AIR302 -241 | days_ago -242 | infer_time_unit +262 | days_ago +263 | infer_time_unit | = help: Use `airflow.timetables.` instead -AIR302_names.py:241: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 | -240 | date_range -241 | days_ago +261 | date_range +262 | days_ago | ^^^^^^^^ AIR302 -242 | infer_time_unit -243 | parse_execution_date +263 | infer_time_unit +264 | parse_execution_date | = help: Use `pendulum.today('UTC').add(days=-N, ...)` instead -AIR302_names.py:242: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 | -240 | date_range -241 | days_ago -242 | infer_time_unit +261 | date_range +262 | days_ago +263 | infer_time_unit | ^^^^^^^^^^^^^^^ AIR302 -243 | parse_execution_date -244 | round_time +264 | parse_execution_date +265 | round_time | -AIR302_names.py:243: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 | -241 | days_ago -242 | infer_time_unit -243 | parse_execution_date +262 | days_ago +263 | infer_time_unit +264 | parse_execution_date | ^^^^^^^^^^^^^^^^^^^^ AIR302 -244 | round_time -245 | scale_time_units +265 | round_time +266 | scale_time_units | -AIR302_names.py:244: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 | -242 | infer_time_unit -243 | parse_execution_date -244 | round_time +263 | infer_time_unit +264 | parse_execution_date +265 | round_time | ^^^^^^^^^^ AIR302 -245 | scale_time_units +266 | scale_time_units | -AIR302_names.py:245: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 | -243 | parse_execution_date -244 | round_time -245 | scale_time_units +264 | parse_execution_date +265 | round_time +266 | scale_time_units | ^^^^^^^^^^^^^^^^ AIR302 -246 | -247 | # This one was not deprecated. +267 | +268 | # This one was not deprecated. | -AIR302_names.py:252: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 | -251 | # airflow.utils.dag_cycle_tester -252 | test_cycle +272 | # airflow.utils.dag_cycle_tester +273 | test_cycle | ^^^^^^^^^^ AIR302 -253 | -254 | # airflow.utils.decorators +274 | +275 | # airflow.utils.decorators | -AIR302_names.py:255: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. | -254 | # airflow.utils.decorators -255 | apply_defaults +275 | # airflow.utils.decorators +276 | apply_defaults | ^^^^^^^^^^^^^^ AIR302 -256 | -257 | # airflow.utils.file - | - -AIR302_names.py:258:1: AIR302 `airflow.utils.file.TemporaryDirectory` is removed in Airflow 3.0 - | -257 | # airflow.utils.file -258 | TemporaryDirectory, mkdirs - | ^^^^^^^^^^^^^^^^^^ AIR302 -259 | -260 | # airflow.utils.helpers +277 | +278 | # airflow.utils.file | -AIR302_names.py:258:21: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 +AIR302_names.py:279:22: AIR302 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 | -257 | # airflow.utils.file -258 | TemporaryDirectory, mkdirs - | ^^^^^^ AIR302 -259 | -260 | # 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:261: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 | -260 | # airflow.utils.helpers -261 | chain, cross_downstream +281 | # airflow.utils.helpers +282 | chain, cross_downstream | ^^^^^ AIR302 -262 | -263 | # airflow.utils.state +283 | +284 | # airflow.utils.state | = help: Use `airflow.models.baseoperator.chain` instead -AIR302_names.py:261: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 | -260 | # airflow.utils.helpers -261 | chain, cross_downstream +281 | # airflow.utils.helpers +282 | chain, cross_downstream | ^^^^^^^^^^^^^^^^ AIR302 -262 | -263 | # airflow.utils.state +283 | +284 | # airflow.utils.state | = help: Use `airflow.models.baseoperator.cross_downstream` instead -AIR302_names.py:264: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 | -263 | # airflow.utils.state -264 | SHUTDOWN, terminating_states +284 | # airflow.utils.state +285 | SHUTDOWN, terminating_states | ^^^^^^^^ AIR302 -265 | -266 | # airflow.utils.trigger_rule +286 | +287 | # airflow.utils.trigger_rule | -AIR302_names.py:264: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 | -263 | # airflow.utils.state -264 | SHUTDOWN, terminating_states +284 | # airflow.utils.state +285 | SHUTDOWN, terminating_states | ^^^^^^^^^^^^^^^^^^ AIR302 -265 | -266 | # airflow.utils.trigger_rule +286 | +287 | # airflow.utils.trigger_rule | -AIR302_names.py:267: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 | -266 | # airflow.utils.trigger_rule -267 | TriggerRule.DUMMY +287 | # airflow.utils.trigger_rule +288 | TriggerRule.DUMMY | ^^^^^ AIR302 -268 | TriggerRule.NONE_FAILED_OR_SKIPPED +289 | TriggerRule.NONE_FAILED_OR_SKIPPED | -AIR302_names.py:268: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 | -266 | # airflow.utils.trigger_rule -267 | TriggerRule.DUMMY -268 | TriggerRule.NONE_FAILED_OR_SKIPPED +287 | # airflow.utils.trigger_rule +288 | TriggerRule.DUMMY +289 | TriggerRule.NONE_FAILED_OR_SKIPPED | ^^^^^^^^^^^^^^^^^^^^^^ AIR302 -269 | -270 | # airflow.www.auth +290 | +291 | # airflow.www.auth | -AIR302_names.py:271: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 | -270 | # airflow.www.auth -271 | has_access +291 | # airflow.www.auth +292 | has_access | ^^^^^^^^^^ AIR302 -272 | has_access_dataset +293 | has_access_dataset | = help: Use `airflow.www.auth.has_access_*` instead -AIR302_names.py:272: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 | -270 | # airflow.www.auth -271 | has_access -272 | has_access_dataset +291 | # airflow.www.auth +292 | has_access +293 | has_access_dataset | ^^^^^^^^^^^^^^^^^^ AIR302 -273 | -274 | # airflow.www.utils +294 | +295 | # airflow.www.utils | = help: Use `airflow.www.auth.has_access_dataset.has_access_asset` instead -AIR302_names.py:275: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 | -274 | # airflow.www.utils -275 | get_sensitive_variables_fields, should_hide_value_for_key +295 | # airflow.www.utils +296 | get_sensitive_variables_fields, should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.utils.log.secrets_masker.get_sensitive_variables_fields` instead -AIR302_names.py:275: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 | -274 | # airflow.www.utils -275 | get_sensitive_variables_fields, should_hide_value_for_key +295 | # airflow.www.utils +296 | get_sensitive_variables_fields, should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^ AIR302 | = help: Use `airflow.utils.log.secrets_masker.should_hide_value_for_key` instead From b332d0706a89fa8788103375db800713968be996 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 31 Dec 2024 09:45:50 +0900 Subject: [PATCH 11/12] refactor(AIR302): rewrite utility functions and add doc string to all utility functions --- .../src/rules/airflow/rules/removal_in_3.rs | 292 +++++++++++------- 1 file changed, 174 insertions(+), 118 deletions(-) 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 14edb568c6a7e..3f01633c3e882 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 @@ -11,77 +11,6 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -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()) - { - pos + 1 < rest.len() && last_element.ends_with(symbol_suffix) - } else { - false - } - } - - ["airflow", rest @ ..] => { - if let (Some(start_element), Some(last_element)) = (rest.first(), rest.last()) { - start_element.starts_with(module) & last_element.ends_with(symbol_suffix) - } else { - false - } - } - - _ => false, - } -} - -fn is_airflow_secret_backend(segments: &[&str]) -> bool { - is_airflow_builtin_or_provider(segments, "secrets", "Backend") -} - -fn is_airflow_hook(segments: &[&str]) -> bool { - is_airflow_builtin_or_provider(segments, "hooks", "Hook") -} - -fn is_airflow_operator(segments: &[&str]) -> bool { - is_airflow_builtin_or_provider(segments, "operators", "Operator") -} - -fn is_airflow_task_handler(segments: &[&str]) -> bool { - is_airflow_builtin_or_provider(segments, "log", "TaskHandler") -} - -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, - } -} - -#[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. /// @@ -141,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), - ); +/// AIR302 +pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { + if !checker.semantic().seen_module(Modules::AIRFLOW) { + return; + } - if let Some(replacement) = replacement { - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - replacement.to_string(), - diagnostic.range, - ))); + 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); + } + } + } + _ => {} } +} - Some(diagnostic) +#[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() { @@ -256,6 +200,13 @@ fn removed_argument(checker: &mut Checker, qualname: &QualifiedName, arguments: }; } +// 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; @@ -291,6 +242,14 @@ fn removed_class_attribute(checker: &mut Checker, expr: &Expr) { } } +// 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; @@ -365,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 @@ -850,6 +814,12 @@ fn removed_name(checker: &mut Checker, expr: &Expr, ranged: impl Ranged) { } } +// 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, @@ -881,34 +851,120 @@ fn removed_airflow_plugin_extension( } } -/// AIR302 -pub(crate) fn removed_in_3(checker: &mut Checker, expr: &Expr) { - if !checker.semantic().seen_module(Modules::AIRFLOW) { - return; +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, + ))); } - match expr { - Expr::Call(ExprCall { - func, arguments, .. - }) => { - if let Some(qualname) = checker.semantic().resolve_qualified_name(func) { - removed_argument(checker, &qualname, arguments); - }; + Some(diagnostic) +} - removed_method(checker, expr); +/// 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 + } } - Expr::Attribute(ExprAttribute { attr: ranged, .. }) => { - removed_name(checker, expr, ranged); - removed_class_attribute(checker, expr); + + ["airflow", first, rest @ ..] => { + if let Some(last) = rest.last() { + *first == module && last.ends_with(symbol_suffix) + } else { + false + } } - 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); - } + + _ => 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, } } From ff3ebca9f2a9b6d23d8feddbb49d54022bd3ccd1 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 31 Dec 2024 09:49:33 +0900 Subject: [PATCH 12/12] fix(AIR302): fix missing DatasetLineageInfo rule --- .../ruff_linter/src/rules/airflow/rules/removal_in_3.rs | 2 +- ..._airflow__tests__AIR302_AIR302_class_attribute.py.snap | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) 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 3f01633c3e882..fa4f0ded1e50f 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 @@ -225,7 +225,7 @@ fn removed_class_attribute(checker: &mut Checker, expr: &Expr) { } &_ => None, }, - ["airflow", "lineage", "hook"] => match attr.as_str() { + ["airflow", "lineage", "hook", "DatasetLineageInfo"] => match attr.as_str() { "dataset" => Some(Replacement::Name("asset")), &_ => None, }, 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 index dfd70e3ab0d5e..4066c8e63d673 100644 --- 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 @@ -218,3 +218,11 @@ AIR302_class_attribute.py:58:11: AIR302 `airflow.lineage.hook.DatasetLineageInfo 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