diff --git a/crates/ruff_linter/resources/test/fixtures/airflow/AIR301_names.py b/crates/ruff_linter/resources/test/fixtures/airflow/AIR301_names.py index 640f855f05..68e5435884 100644 --- a/crates/ruff_linter/resources/test/fixtures/airflow/AIR301_names.py +++ b/crates/ruff_linter/resources/test/fixtures/airflow/AIR301_names.py @@ -12,6 +12,7 @@ from airflow import ( from airflow.api_connexion.security import requires_access from airflow.contrib.aws_athena_hook import AWSAthenaHook from airflow.datasets import DatasetAliasEvent +from airflow.operators.postgres_operator import Mapping from airflow.operators.subdag import SubDagOperator from airflow.secrets.cache import SecretCache from airflow.secrets.local_filesystem import LocalFilesystemBackend @@ -52,6 +53,8 @@ DatasetAliasEvent() # airflow.operators.subdag.* SubDagOperator() +# airflow.operators.postgres_operator +Mapping() # airflow.secrets # get_connection diff --git a/crates/ruff_linter/src/rules/airflow/helpers.rs b/crates/ruff_linter/src/rules/airflow/helpers.rs index b5997e916f..d33e7c32e2 100644 --- a/crates/ruff_linter/src/rules/airflow/helpers.rs +++ b/crates/ruff_linter/src/rules/airflow/helpers.rs @@ -37,7 +37,6 @@ pub(crate) enum Replacement { #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) enum ProviderReplacement { - None, AutoImport { module: &'static str, name: &'static str, diff --git a/crates/ruff_linter/src/rules/airflow/rules/moved_to_provider_in_3.rs b/crates/ruff_linter/src/rules/airflow/rules/moved_to_provider_in_3.rs index e22d6fbd62..88035562ca 100644 --- a/crates/ruff_linter/src/rules/airflow/rules/moved_to_provider_in_3.rs +++ b/crates/ruff_linter/src/rules/airflow/rules/moved_to_provider_in_3.rs @@ -50,9 +50,6 @@ impl Violation for Airflow3MovedToProvider<'_> { replacement, } = self; match replacement { - ProviderReplacement::None => { - format!("`{deprecated}` is removed in Airflow 3.0") - } ProviderReplacement::AutoImport { name: _, module: _, @@ -85,7 +82,6 @@ impl Violation for Airflow3MovedToProvider<'_> { provider, version, } => Some((module, name.as_str(), provider, version)), - ProviderReplacement::None => None, } { Some(format!( "Install `apache-airflow-providers-{provider}>={version}` and use `{name}` from `{module}` instead." @@ -1020,7 +1016,6 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan provider: "postgres", version: "1.0.0", }, - ["airflow", "operators", "postgres_operator", "Mapping"] => ProviderReplacement::None, // apache-airflow-providers-presto ["airflow", "hooks", "presto_hook", "PrestoHook"] => ProviderReplacement::AutoImport { @@ -1209,16 +1204,6 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan ProviderReplacement::SourceModuleMovedToProvider { module, name, .. } => { (module, name.as_str()) } - ProviderReplacement::None => { - checker.report_diagnostic( - Airflow3MovedToProvider { - deprecated: qualified_name, - replacement, - }, - ranged, - ); - return; - } }; if is_guarded_by_try_except(expr, module, name, checker.semantic()) { 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 4d822812c0..a3d3e3bc95 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 @@ -704,6 +704,7 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) { ["airflow", "operators", "subdag", ..] => { Replacement::Message("The whole `airflow.subdag` module has been removed.") } + ["airflow", "operators", "postgres_operator", "Mapping"] => Replacement::None, ["airflow", "operators", "python", "get_current_context"] => Replacement::AutoImport { module: "airflow.sdk", name: "get_current_context", diff --git a/crates/ruff_linter/src/rules/airflow/rules/suggested_to_move_to_provider_in_3.rs b/crates/ruff_linter/src/rules/airflow/rules/suggested_to_move_to_provider_in_3.rs index 5f88370c37..42c647e61a 100644 --- a/crates/ruff_linter/src/rules/airflow/rules/suggested_to_move_to_provider_in_3.rs +++ b/crates/ruff_linter/src/rules/airflow/rules/suggested_to_move_to_provider_in_3.rs @@ -65,9 +65,6 @@ impl Violation for Airflow3SuggestedToMoveToProvider<'_> { replacement, } = self; match replacement { - ProviderReplacement::None => { - format!("`{deprecated}` is removed in Airflow 3.0") - } ProviderReplacement::AutoImport { name: _, module: _, @@ -91,7 +88,6 @@ impl Violation for Airflow3SuggestedToMoveToProvider<'_> { fn fix_title(&self) -> Option { let Airflow3SuggestedToMoveToProvider { replacement, .. } = self; match replacement { - ProviderReplacement::None => None, ProviderReplacement::AutoImport { module, name, @@ -319,16 +315,6 @@ fn check_names_moved_to_provider(checker: &Checker, expr: &Expr, ranged: TextRan ProviderReplacement::SourceModuleMovedToProvider { module, name, .. } => { (module, name.as_str()) } - ProviderReplacement::None => { - checker.report_diagnostic( - Airflow3SuggestedToMoveToProvider { - deprecated: qualified_name, - replacement: replacement.clone(), - }, - ranged.range(), - ); - return; - } }; if is_guarded_by_try_except(expr, module, name, checker.semantic()) { diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR301_AIR301_names.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR301_AIR301_names.py.snap index db6c2744af..95b78f3d97 100644 --- a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR301_AIR301_names.py.snap +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR301_AIR301_names.py.snap @@ -2,350 +2,362 @@ source: crates/ruff_linter/src/rules/airflow/mod.rs --- AIR301 `airflow.PY36` is removed in Airflow 3.0 - --> AIR301_names.py:39:1 + --> AIR301_names.py:40:1 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.PY37` is removed in Airflow 3.0 - --> AIR301_names.py:39:7 + --> AIR301_names.py:40:7 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.PY38` is removed in Airflow 3.0 - --> AIR301_names.py:39:13 + --> AIR301_names.py:40:13 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.PY39` is removed in Airflow 3.0 - --> AIR301_names.py:39:19 + --> AIR301_names.py:40:19 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.PY310` is removed in Airflow 3.0 - --> AIR301_names.py:39:25 + --> AIR301_names.py:40:25 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.PY311` is removed in Airflow 3.0 - --> AIR301_names.py:39:32 + --> AIR301_names.py:40:32 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.PY312` is removed in Airflow 3.0 - --> AIR301_names.py:39:39 + --> AIR301_names.py:40:39 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 | ^^^^^ -40 | -41 | # airflow.api_connexion.security +41 | +42 | # airflow.api_connexion.security | help: Use `sys.version_info` instead AIR301 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 - --> AIR301_names.py:42:1 + --> AIR301_names.py:43:1 | -41 | # airflow.api_connexion.security -42 | requires_access +42 | # airflow.api_connexion.security +43 | requires_access | ^^^^^^^^^^^^^^^ -43 | -44 | # airflow.contrib.* +44 | +45 | # airflow.contrib.* | help: Use `airflow.api_fastapi.core_api.security.requires_access_*` instead AIR301 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0 - --> AIR301_names.py:45:1 + --> AIR301_names.py:46:1 | -44 | # airflow.contrib.* -45 | AWSAthenaHook() +45 | # airflow.contrib.* +46 | AWSAthenaHook() | ^^^^^^^^^^^^^ | help: The whole `airflow.contrib` module has been removed. AIR301 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 - --> AIR301_names.py:49:1 + --> AIR301_names.py:50:1 | -48 | # airflow.datasets -49 | DatasetAliasEvent() +49 | # airflow.datasets +50 | DatasetAliasEvent() | ^^^^^^^^^^^^^^^^^ | AIR301 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0 - --> AIR301_names.py:53:1 + --> AIR301_names.py:54:1 | -52 | # airflow.operators.subdag.* -53 | SubDagOperator() +53 | # airflow.operators.subdag.* +54 | SubDagOperator() | ^^^^^^^^^^^^^^ +55 | +56 | # airflow.operators.postgres_operator | help: The whole `airflow.subdag` module has been removed. -AIR301 [*] `airflow.secrets.cache.SecretCache` is removed in Airflow 3.0 - --> AIR301_names.py:61:1 +AIR301 `airflow.operators.postgres_operator.Mapping` is removed in Airflow 3.0 + --> AIR301_names.py:57:1 | -60 | # airflow.secrets.cache -61 | SecretCache() +56 | # airflow.operators.postgres_operator +57 | Mapping() + | ^^^^^^^ +58 | +59 | # airflow.secrets + | + +AIR301 [*] `airflow.secrets.cache.SecretCache` is removed in Airflow 3.0 + --> AIR301_names.py:64:1 + | +63 | # airflow.secrets.cache +64 | SecretCache() | ^^^^^^^^^^^ | help: Use `SecretCache` from `airflow.sdk` instead. -13 | from airflow.contrib.aws_athena_hook import AWSAthenaHook 14 | from airflow.datasets import DatasetAliasEvent -15 | from airflow.operators.subdag import SubDagOperator +15 | from airflow.operators.postgres_operator import Mapping +16 | from airflow.operators.subdag import SubDagOperator - from airflow.secrets.cache import SecretCache -16 | from airflow.secrets.local_filesystem import LocalFilesystemBackend -17 | from airflow.triggers.external_task import TaskStateTrigger -18 | from airflow.utils import dates +17 | from airflow.secrets.local_filesystem import LocalFilesystemBackend +18 | from airflow.triggers.external_task import TaskStateTrigger +19 | from airflow.utils import dates -------------------------------------------------------------------------------- -33 | from airflow.utils.trigger_rule import TriggerRule -34 | from airflow.www.auth import has_access, has_access_dataset -35 | from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key -36 + from airflow.sdk import SecretCache -37 | -38 | # airflow root -39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 +34 | from airflow.utils.trigger_rule import TriggerRule +35 | from airflow.www.auth import has_access, has_access_dataset +36 | from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key +37 + from airflow.sdk import SecretCache +38 | +39 | # airflow root +40 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 note: This is an unsafe fix and may change runtime behavior AIR301 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 - --> AIR301_names.py:65:1 - | -64 | # airflow.triggers.external_task -65 | TaskStateTrigger() - | ^^^^^^^^^^^^^^^^ -66 | -67 | # airflow.utils.date - | - -AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0 --> AIR301_names.py:68:1 | -67 | # airflow.utils.date -68 | dates.date_range +67 | # airflow.triggers.external_task +68 | TaskStateTrigger() | ^^^^^^^^^^^^^^^^ -69 | dates.days_ago +69 | +70 | # airflow.utils.date | -AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 - --> AIR301_names.py:69:1 - | -67 | # airflow.utils.date -68 | dates.date_range -69 | dates.days_ago - | ^^^^^^^^^^^^^^ -70 | -71 | date_range - | -help: Use `pendulum.today('UTC').add(days=-N, ...)` instead - AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0 --> AIR301_names.py:71:1 | -69 | dates.days_ago -70 | -71 | date_range - | ^^^^^^^^^^ -72 | days_ago -73 | infer_time_unit +70 | # airflow.utils.date +71 | dates.date_range + | ^^^^^^^^^^^^^^^^ +72 | dates.days_ago | AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 --> AIR301_names.py:72:1 | -71 | date_range -72 | days_ago +70 | # airflow.utils.date +71 | dates.date_range +72 | dates.days_ago + | ^^^^^^^^^^^^^^ +73 | +74 | date_range + | +help: Use `pendulum.today('UTC').add(days=-N, ...)` instead + +AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0 + --> AIR301_names.py:74:1 + | +72 | dates.days_ago +73 | +74 | date_range + | ^^^^^^^^^^ +75 | days_ago +76 | infer_time_unit + | + +AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 + --> AIR301_names.py:75:1 + | +74 | date_range +75 | days_ago | ^^^^^^^^ -73 | infer_time_unit -74 | parse_execution_date +76 | infer_time_unit +77 | parse_execution_date | help: Use `pendulum.today('UTC').add(days=-N, ...)` instead AIR301 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 - --> AIR301_names.py:73:1 + --> AIR301_names.py:76:1 | -71 | date_range -72 | days_ago -73 | infer_time_unit +74 | date_range +75 | days_ago +76 | infer_time_unit | ^^^^^^^^^^^^^^^ -74 | parse_execution_date -75 | round_time +77 | parse_execution_date +78 | round_time | AIR301 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 - --> AIR301_names.py:74:1 + --> AIR301_names.py:77:1 | -72 | days_ago -73 | infer_time_unit -74 | parse_execution_date +75 | days_ago +76 | infer_time_unit +77 | parse_execution_date | ^^^^^^^^^^^^^^^^^^^^ -75 | round_time -76 | scale_time_units +78 | round_time +79 | scale_time_units | AIR301 `airflow.utils.dates.round_time` is removed in Airflow 3.0 - --> AIR301_names.py:75:1 + --> AIR301_names.py:78:1 | -73 | infer_time_unit -74 | parse_execution_date -75 | round_time +76 | infer_time_unit +77 | parse_execution_date +78 | round_time | ^^^^^^^^^^ -76 | scale_time_units +79 | scale_time_units | AIR301 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 - --> AIR301_names.py:76:1 + --> AIR301_names.py:79:1 | -74 | parse_execution_date -75 | round_time -76 | scale_time_units +77 | parse_execution_date +78 | round_time +79 | scale_time_units | ^^^^^^^^^^^^^^^^ -77 | -78 | # This one was not deprecated. +80 | +81 | # This one was not deprecated. | AIR301 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 - --> AIR301_names.py:83:1 + --> AIR301_names.py:86:1 | -82 | # airflow.utils.dag_cycle_tester -83 | test_cycle +85 | # airflow.utils.dag_cycle_tester +86 | test_cycle | ^^^^^^^^^^ | AIR301 `airflow.utils.db.create_session` is removed in Airflow 3.0 - --> AIR301_names.py:87:1 + --> AIR301_names.py:90:1 | -86 | # airflow.utils.db -87 | create_session +89 | # airflow.utils.db +90 | create_session | ^^^^^^^^^^^^^^ -88 | -89 | # airflow.utils.decorators +91 | +92 | # airflow.utils.decorators | AIR301 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0 - --> AIR301_names.py:90:1 + --> AIR301_names.py:93:1 | -89 | # airflow.utils.decorators -90 | apply_defaults +92 | # airflow.utils.decorators +93 | apply_defaults | ^^^^^^^^^^^^^^ -91 | -92 | # airflow.utils.file +94 | +95 | # airflow.utils.file | help: `apply_defaults` is now unconditionally done and can be safely removed. AIR301 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 - --> AIR301_names.py:93:1 + --> AIR301_names.py:96:1 | -92 | # airflow.utils.file -93 | mkdirs +95 | # airflow.utils.file +96 | mkdirs | ^^^^^^ | help: Use `pathlib.Path({path}).mkdir` instead AIR301 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 - --> AIR301_names.py:97:1 - | -96 | # airflow.utils.state -97 | SHUTDOWN - | ^^^^^^^^ -98 | terminating_states - | + --> AIR301_names.py:100:1 + | + 99 | # airflow.utils.state +100 | SHUTDOWN + | ^^^^^^^^ +101 | terminating_states + | AIR301 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 - --> AIR301_names.py:98:1 + --> AIR301_names.py:101:1 | - 96 | # airflow.utils.state - 97 | SHUTDOWN - 98 | terminating_states + 99 | # airflow.utils.state +100 | SHUTDOWN +101 | terminating_states | ^^^^^^^^^^^^^^^^^^ - 99 | -100 | # airflow.utils.trigger_rule +102 | +103 | # airflow.utils.trigger_rule | AIR301 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 - --> AIR301_names.py:101:1 + --> AIR301_names.py:104:1 | -100 | # airflow.utils.trigger_rule -101 | TriggerRule.DUMMY +103 | # airflow.utils.trigger_rule +104 | TriggerRule.DUMMY | ^^^^^^^^^^^^^^^^^ -102 | TriggerRule.NONE_FAILED_OR_SKIPPED +105 | TriggerRule.NONE_FAILED_OR_SKIPPED | AIR301 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0 - --> AIR301_names.py:102:1 + --> AIR301_names.py:105:1 | -100 | # airflow.utils.trigger_rule -101 | TriggerRule.DUMMY -102 | TriggerRule.NONE_FAILED_OR_SKIPPED +103 | # airflow.utils.trigger_rule +104 | TriggerRule.DUMMY +105 | TriggerRule.NONE_FAILED_OR_SKIPPED | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | AIR301 `airflow.www.auth.has_access` is removed in Airflow 3.0 - --> AIR301_names.py:106:1 + --> AIR301_names.py:109:1 | -105 | # airflow.www.auth -106 | has_access +108 | # airflow.www.auth +109 | has_access | ^^^^^^^^^^ -107 | has_access_dataset +110 | has_access_dataset | AIR301 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0 - --> AIR301_names.py:107:1 + --> AIR301_names.py:110:1 | -105 | # airflow.www.auth -106 | has_access -107 | has_access_dataset +108 | # airflow.www.auth +109 | has_access +110 | has_access_dataset | ^^^^^^^^^^^^^^^^^^ -108 | -109 | # airflow.www.utils +111 | +112 | # airflow.www.utils | AIR301 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0 - --> AIR301_names.py:110:1 + --> AIR301_names.py:113:1 | -109 | # airflow.www.utils -110 | get_sensitive_variables_fields +112 | # airflow.www.utils +113 | get_sensitive_variables_fields | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -111 | should_hide_value_for_key +114 | should_hide_value_for_key | AIR301 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0 - --> AIR301_names.py:111:1 + --> AIR301_names.py:114:1 | -109 | # airflow.www.utils -110 | get_sensitive_variables_fields -111 | should_hide_value_for_key +112 | # airflow.www.utils +113 | get_sensitive_variables_fields +114 | should_hide_value_for_key | ^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_postgres.py.snap b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_postgres.py.snap index e2397c6bbe..b3d3f529e7 100644 --- a/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_postgres.py.snap +++ b/crates/ruff_linter/src/rules/airflow/snapshots/ruff_linter__rules__airflow__tests__AIR302_AIR302_postgres.py.snap @@ -20,11 +20,3 @@ help: Install `apache-airflow-providers-postgres>=1.0.0` and use `PostgresHook` 6 | PostgresHook() 7 | Mapping() note: This is an unsafe fix and may change runtime behavior - -AIR302 `airflow.operators.postgres_operator.Mapping` is removed in Airflow 3.0 - --> AIR302_postgres.py:7:1 - | -6 | PostgresHook() -7 | Mapping() - | ^^^^^^^ - |