Add AIR301 rule (#17707)

<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Add "airflow.secrets.cache.SecretCache" →
"airflow.sdk.cache.SecretCache" rule

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->

---------

Co-authored-by: Wei Lee <weilee.rx@gmail.com>
This commit is contained in:
Sneha Prabhu 2025-08-11 18:44:43 +05:30 committed by GitHub
parent c433865801
commit 6bc52f2855
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 194 additions and 160 deletions

View File

@ -13,6 +13,7 @@ from airflow.api_connexion.security import requires_access
from airflow.contrib.aws_athena_hook import AWSAthenaHook from airflow.contrib.aws_athena_hook import AWSAthenaHook
from airflow.datasets import DatasetAliasEvent from airflow.datasets import DatasetAliasEvent
from airflow.operators.subdag import SubDagOperator from airflow.operators.subdag import SubDagOperator
from airflow.secrets.cache import SecretCache
from airflow.secrets.local_filesystem import LocalFilesystemBackend from airflow.secrets.local_filesystem import LocalFilesystemBackend
from airflow.triggers.external_task import TaskStateTrigger from airflow.triggers.external_task import TaskStateTrigger
from airflow.utils import dates from airflow.utils import dates
@ -56,6 +57,9 @@ SubDagOperator()
# get_connection # get_connection
LocalFilesystemBackend() LocalFilesystemBackend()
# airflow.secrets.cache
SecretCache()
# airflow.triggers.external_task # airflow.triggers.external_task
TaskStateTrigger() TaskStateTrigger()

View File

@ -710,6 +710,10 @@ fn check_name(checker: &Checker, expr: &Expr, range: TextRange) {
}, },
// airflow.secrets // airflow.secrets
["airflow", "secrets", "cache", "SecretCache"] => Replacement::AutoImport {
module: "airflow.sdk",
name: "SecretCache",
},
["airflow", "secrets", "local_filesystem", "load_connections"] => Replacement::AutoImport { ["airflow", "secrets", "local_filesystem", "load_connections"] => Replacement::AutoImport {
module: "airflow.secrets.local_filesystem", module: "airflow.secrets.local_filesystem",
name: "load_connections_dict", name: "load_connections_dict",

View File

@ -2,325 +2,351 @@
source: crates/ruff_linter/src/rules/airflow/mod.rs source: crates/ruff_linter/src/rules/airflow/mod.rs
--- ---
AIR301 `airflow.PY36` is removed in Airflow 3.0 AIR301 `airflow.PY36` is removed in Airflow 3.0
--> AIR301_names.py:38:1 --> AIR301_names.py:39:1
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^ | ^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.PY37` is removed in Airflow 3.0 AIR301 `airflow.PY37` is removed in Airflow 3.0
--> AIR301_names.py:38:7 --> AIR301_names.py:39:7
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^ | ^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.PY38` is removed in Airflow 3.0 AIR301 `airflow.PY38` is removed in Airflow 3.0
--> AIR301_names.py:38:13 --> AIR301_names.py:39:13
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^ | ^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.PY39` is removed in Airflow 3.0 AIR301 `airflow.PY39` is removed in Airflow 3.0
--> AIR301_names.py:38:19 --> AIR301_names.py:39:19
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^ | ^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.PY310` is removed in Airflow 3.0 AIR301 `airflow.PY310` is removed in Airflow 3.0
--> AIR301_names.py:38:25 --> AIR301_names.py:39:25
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^^ | ^^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.PY311` is removed in Airflow 3.0 AIR301 `airflow.PY311` is removed in Airflow 3.0
--> AIR301_names.py:38:32 --> AIR301_names.py:39:32
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^^ | ^^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.PY312` is removed in Airflow 3.0 AIR301 `airflow.PY312` is removed in Airflow 3.0
--> AIR301_names.py:38:39 --> AIR301_names.py:39:39
| |
37 | # airflow root 38 | # airflow root
38 | PY36, PY37, PY38, PY39, PY310, PY311, PY312 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
| ^^^^^ | ^^^^^
39 | 40 |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
| |
help: Use `sys.version_info` instead help: Use `sys.version_info` instead
AIR301 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0 AIR301 `airflow.api_connexion.security.requires_access` is removed in Airflow 3.0
--> AIR301_names.py:41:1 --> AIR301_names.py:42:1
| |
40 | # airflow.api_connexion.security 41 | # airflow.api_connexion.security
41 | requires_access 42 | requires_access
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
42 | 43 |
43 | # airflow.contrib.* 44 | # airflow.contrib.*
| |
help: Use `airflow.api_fastapi.core_api.security.requires_access_*` instead 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 `airflow.contrib.aws_athena_hook.AWSAthenaHook` is removed in Airflow 3.0
--> AIR301_names.py:44:1 --> AIR301_names.py:45:1
| |
43 | # airflow.contrib.* 44 | # airflow.contrib.*
44 | AWSAthenaHook() 45 | AWSAthenaHook()
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
help: The whole `airflow.contrib` module has been removed. help: The whole `airflow.contrib` module has been removed.
AIR301 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0 AIR301 `airflow.datasets.DatasetAliasEvent` is removed in Airflow 3.0
--> AIR301_names.py:48:1 --> AIR301_names.py:49:1
| |
47 | # airflow.datasets 48 | # airflow.datasets
48 | DatasetAliasEvent() 49 | DatasetAliasEvent()
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
| |
AIR301 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0 AIR301 `airflow.operators.subdag.SubDagOperator` is removed in Airflow 3.0
--> AIR301_names.py:52:1 --> AIR301_names.py:53:1
| |
51 | # airflow.operators.subdag.* 52 | # airflow.operators.subdag.*
52 | SubDagOperator() 53 | SubDagOperator()
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
| |
help: The whole `airflow.subdag` module has been removed. help: The whole `airflow.subdag` module has been removed.
AIR301 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0 AIR301 [*] `airflow.secrets.cache.SecretCache` is removed in Airflow 3.0
--> AIR301_names.py:61:1 --> AIR301_names.py:61:1
| |
60 | # airflow.triggers.external_task 60 | # airflow.secrets.cache
61 | TaskStateTrigger() 61 | SecretCache()
| ^^^^^^^^^^^
|
help: Use `SecretCache` from `airflow.sdk` instead.
Unsafe fix
13 13 | from airflow.contrib.aws_athena_hook import AWSAthenaHook
14 14 | from airflow.datasets import DatasetAliasEvent
15 15 | from airflow.operators.subdag import SubDagOperator
16 |-from airflow.secrets.cache import SecretCache
17 16 | from airflow.secrets.local_filesystem import LocalFilesystemBackend
18 17 | from airflow.triggers.external_task import TaskStateTrigger
19 18 | from airflow.utils import dates
--------------------------------------------------------------------------------
34 33 | from airflow.utils.trigger_rule import TriggerRule
35 34 | from airflow.www.auth import has_access, has_access_dataset
36 35 | from airflow.www.utils import get_sensitive_variables_fields, should_hide_value_for_key
36 |+from airflow.sdk import SecretCache
37 37 |
38 38 | # airflow root
39 39 | PY36, PY37, PY38, PY39, PY310, PY311, PY312
AIR301 `airflow.triggers.external_task.TaskStateTrigger` is removed in Airflow 3.0
--> AIR301_names.py:65:1
|
64 | # airflow.triggers.external_task
65 | TaskStateTrigger()
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
62 | 66 |
63 | # airflow.utils.date 67 | # airflow.utils.date
| |
AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0
--> AIR301_names.py:64:1 --> AIR301_names.py:68:1
| |
63 | # airflow.utils.date 67 | # airflow.utils.date
64 | dates.date_range 68 | dates.date_range
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
65 | dates.days_ago 69 | dates.days_ago
| |
AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0
--> AIR301_names.py:65:1 --> AIR301_names.py:69:1
| |
63 | # airflow.utils.date 67 | # airflow.utils.date
64 | dates.date_range 68 | dates.date_range
65 | dates.days_ago 69 | dates.days_ago
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
66 | 70 |
67 | date_range 71 | date_range
| |
help: Use `pendulum.today('UTC').add(days=-N, ...)` instead help: Use `pendulum.today('UTC').add(days=-N, ...)` instead
AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.date_range` is removed in Airflow 3.0
--> AIR301_names.py:67:1 --> AIR301_names.py:71:1
| |
65 | dates.days_ago 69 | dates.days_ago
66 | 70 |
67 | date_range 71 | date_range
| ^^^^^^^^^^ | ^^^^^^^^^^
68 | days_ago 72 | days_ago
69 | infer_time_unit 73 | infer_time_unit
| |
AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.days_ago` is removed in Airflow 3.0
--> AIR301_names.py:68:1 --> AIR301_names.py:72:1
| |
67 | date_range 71 | date_range
68 | days_ago 72 | days_ago
| ^^^^^^^^ | ^^^^^^^^
69 | infer_time_unit 73 | infer_time_unit
70 | parse_execution_date 74 | parse_execution_date
| |
help: Use `pendulum.today('UTC').add(days=-N, ...)` instead help: Use `pendulum.today('UTC').add(days=-N, ...)` instead
AIR301 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.infer_time_unit` is removed in Airflow 3.0
--> AIR301_names.py:69:1 --> AIR301_names.py:73:1
| |
67 | date_range 71 | date_range
68 | days_ago 72 | days_ago
69 | infer_time_unit 73 | infer_time_unit
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
70 | parse_execution_date 74 | parse_execution_date
71 | round_time 75 | round_time
| |
AIR301 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.parse_execution_date` is removed in Airflow 3.0
--> AIR301_names.py:70:1 --> AIR301_names.py:74:1
| |
68 | days_ago 72 | days_ago
69 | infer_time_unit 73 | infer_time_unit
70 | parse_execution_date 74 | parse_execution_date
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
71 | round_time 75 | round_time
72 | scale_time_units 76 | scale_time_units
| |
AIR301 `airflow.utils.dates.round_time` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.round_time` is removed in Airflow 3.0
--> AIR301_names.py:71:1 --> AIR301_names.py:75:1
| |
69 | infer_time_unit 73 | infer_time_unit
70 | parse_execution_date 74 | parse_execution_date
71 | round_time 75 | round_time
| ^^^^^^^^^^ | ^^^^^^^^^^
72 | scale_time_units 76 | scale_time_units
| |
AIR301 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0 AIR301 `airflow.utils.dates.scale_time_units` is removed in Airflow 3.0
--> AIR301_names.py:72:1 --> AIR301_names.py:76:1
| |
70 | parse_execution_date 74 | parse_execution_date
71 | round_time 75 | round_time
72 | scale_time_units 76 | scale_time_units
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
73 | 77 |
74 | # This one was not deprecated. 78 | # This one was not deprecated.
| |
AIR301 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0 AIR301 `airflow.utils.dag_cycle_tester.test_cycle` is removed in Airflow 3.0
--> AIR301_names.py:79:1 --> AIR301_names.py:83:1
| |
78 | # airflow.utils.dag_cycle_tester 82 | # airflow.utils.dag_cycle_tester
79 | test_cycle 83 | test_cycle
| ^^^^^^^^^^ | ^^^^^^^^^^
| |
AIR301 `airflow.utils.db.create_session` is removed in Airflow 3.0 AIR301 `airflow.utils.db.create_session` is removed in Airflow 3.0
--> AIR301_names.py:83:1 --> AIR301_names.py:87:1
| |
82 | # airflow.utils.db 86 | # airflow.utils.db
83 | create_session 87 | create_session
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
84 | 88 |
85 | # airflow.utils.decorators 89 | # airflow.utils.decorators
| |
AIR301 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0 AIR301 `airflow.utils.decorators.apply_defaults` is removed in Airflow 3.0
--> AIR301_names.py:86:1 --> AIR301_names.py:90:1
| |
85 | # airflow.utils.decorators 89 | # airflow.utils.decorators
86 | apply_defaults 90 | apply_defaults
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
87 | 91 |
88 | # airflow.utils.file 92 | # airflow.utils.file
| |
help: `apply_defaults` is now unconditionally done and can be safely removed. help: `apply_defaults` is now unconditionally done and can be safely removed.
AIR301 `airflow.utils.file.mkdirs` is removed in Airflow 3.0 AIR301 `airflow.utils.file.mkdirs` is removed in Airflow 3.0
--> AIR301_names.py:89:1 --> AIR301_names.py:93:1
| |
88 | # airflow.utils.file 92 | # airflow.utils.file
89 | mkdirs 93 | mkdirs
| ^^^^^^ | ^^^^^^
| |
help: Use `pathlib.Path({path}).mkdir` instead help: Use `pathlib.Path({path}).mkdir` instead
AIR301 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0 AIR301 `airflow.utils.state.SHUTDOWN` is removed in Airflow 3.0
--> AIR301_names.py:93:1 --> AIR301_names.py:97:1
| |
92 | # airflow.utils.state 96 | # airflow.utils.state
93 | SHUTDOWN 97 | SHUTDOWN
| ^^^^^^^^ | ^^^^^^^^
94 | terminating_states 98 | terminating_states
| |
AIR301 `airflow.utils.state.terminating_states` is removed in Airflow 3.0 AIR301 `airflow.utils.state.terminating_states` is removed in Airflow 3.0
--> AIR301_names.py:94:1 --> AIR301_names.py:98:1
| |
92 | # airflow.utils.state 96 | # airflow.utils.state
93 | SHUTDOWN 97 | SHUTDOWN
94 | terminating_states 98 | terminating_states
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
95 | 99 |
96 | # airflow.utils.trigger_rule 100 | # airflow.utils.trigger_rule
| |
AIR301 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0 AIR301 `airflow.utils.trigger_rule.TriggerRule.DUMMY` is removed in Airflow 3.0
--> AIR301_names.py:97:1 --> AIR301_names.py:101:1
| |
96 | # airflow.utils.trigger_rule 100 | # airflow.utils.trigger_rule
97 | TriggerRule.DUMMY 101 | TriggerRule.DUMMY
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
98 | TriggerRule.NONE_FAILED_OR_SKIPPED 102 | TriggerRule.NONE_FAILED_OR_SKIPPED
| |
AIR301 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0 AIR301 `airflow.utils.trigger_rule.TriggerRule.NONE_FAILED_OR_SKIPPED` is removed in Airflow 3.0
--> AIR301_names.py:98:1
|
96 | # airflow.utils.trigger_rule
97 | TriggerRule.DUMMY
98 | TriggerRule.NONE_FAILED_OR_SKIPPED
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
AIR301 `airflow.www.auth.has_access` is removed in Airflow 3.0
--> AIR301_names.py:102:1 --> AIR301_names.py:102:1
| |
101 | # airflow.www.auth 100 | # airflow.utils.trigger_rule
102 | has_access 101 | TriggerRule.DUMMY
102 | TriggerRule.NONE_FAILED_OR_SKIPPED
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
AIR301 `airflow.www.auth.has_access` is removed in Airflow 3.0
--> AIR301_names.py:106:1
|
105 | # airflow.www.auth
106 | has_access
| ^^^^^^^^^^ | ^^^^^^^^^^
103 | has_access_dataset 107 | has_access_dataset
| |
AIR301 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0 AIR301 `airflow.www.auth.has_access_dataset` is removed in Airflow 3.0
--> AIR301_names.py:103:1 --> AIR301_names.py:107:1
| |
101 | # airflow.www.auth 105 | # airflow.www.auth
102 | has_access 106 | has_access
103 | has_access_dataset 107 | has_access_dataset
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
104 | 108 |
105 | # airflow.www.utils 109 | # airflow.www.utils
| |
AIR301 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0 AIR301 `airflow.www.utils.get_sensitive_variables_fields` is removed in Airflow 3.0
--> AIR301_names.py:106:1 --> AIR301_names.py:110:1
| |
105 | # airflow.www.utils 109 | # airflow.www.utils
106 | get_sensitive_variables_fields 110 | get_sensitive_variables_fields
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107 | should_hide_value_for_key 111 | should_hide_value_for_key
| |
AIR301 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0 AIR301 `airflow.www.utils.should_hide_value_for_key` is removed in Airflow 3.0
--> AIR301_names.py:107:1 --> AIR301_names.py:111:1
| |
105 | # airflow.www.utils 109 | # airflow.www.utils
106 | get_sensitive_variables_fields 110 | get_sensitive_variables_fields
107 | should_hide_value_for_key 111 | should_hide_value_for_key
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^
| |