This is an automated email from the ASF dual-hosted git repository.
jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 6f56aa1fe0a build(prek-hook): Check whether new "raise
AirflowException" is added (#55416)
6f56aa1fe0a is described below
commit 6f56aa1fe0a65a8bceea7c827fb3a13087f558a5
Author: Wei Lee <[email protected]>
AuthorDate: Fri Apr 10 03:20:12 2026 +0800
build(prek-hook): Check whether new "raise AirflowException" is added
(#55416)
* build(prek-hook): Check whether new "raise AirflowException" is added
* feat: add white list
* refactor: simplify the record to use count instead of raw content
* fixup! refactor: simplify the record to use count instead of raw content
* refactor: filter python files that matters
* fixup! refactor: filter python files that matters
---
.pre-commit-config.yaml | 6 +
.../ci/prek/check_new_airflow_exception_usage.py | 265 +++++++++++++
scripts/ci/prek/known_airflow_exceptions.txt | 433 +++++++++++++++++++++
3 files changed, 704 insertions(+)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 52f9d2f85e8..df62237b6f3 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -977,6 +977,12 @@ repos:
language: python
pass_filenames: true
files: \.py$
+ - id: check-no-new-airflow-exceptions
+ name: Check that no new raise AirflowException usages are added
+ entry: ./scripts/ci/prek/check_new_airflow_exception_usage.py
+ language: python
+ pass_filenames: true
+ files: ^(airflow-core|airflow-ctl|task-sdk|providers|shared)/.*\.py$
- id: bandit
name: bandit
description: "Bandit is a tool for finding common security issues in
Python code"
diff --git a/scripts/ci/prek/check_new_airflow_exception_usage.py
b/scripts/ci/prek/check_new_airflow_exception_usage.py
new file mode 100755
index 00000000000..133a8ef07fd
--- /dev/null
+++ b/scripts/ci/prek/check_new_airflow_exception_usage.py
@@ -0,0 +1,265 @@
+#!/usr/bin/env python
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# /// script
+# requires-python = ">=3.10"
+# dependencies = [
+# "rich>=13.0.0",
+# ]
+# ///
+"""Check that no new ``raise AirflowException`` usages are introduced.
+
+All *existing* usages are recorded in ``known_airflow_exceptions.txt`` next to
+this script as ``relative/path::N`` entries (one per file), where ``N`` is the
+maximum number of ``raise AirflowException`` occurrences allowed in that file.
+A file whose current count exceeds the recorded limit is treated as a violation
+– use a dedicated exception class instead.
+
+Modes
+-----
+Default (files passed by prek/pre-commit):
+ Check only the supplied files; fail if any file's count exceeds the limit.
+ When a file's count has *decreased*, the allowlist entry is tightened
+ automatically and the hook exits with a non-zero code so that pre-commit
+ reports the modified allowlist — just stage
+ ``scripts/ci/prek/known_airflow_exceptions.txt`` and re-run.
+
+``--all-files``:
+ Walk the whole repository and check every ``.py`` file.
+
+``--cleanup``:
+ Remove entries for files that no longer exist. Safe to run at any time;
+ does not add new entries or raise limits.
+
+``--generate``:
+ Scan the whole repository and *rebuild* the allowlist from scratch.
+ Intended for the initial setup or after a large-scale clean-up sprint.
+"""
+
+from __future__ import annotations
+
+import argparse
+import re
+from pathlib import Path
+
+from rich.console import Console
+from rich.panel import Panel
+
+console = Console()
+
+REPO_ROOT = Path(__file__).parents[3]
+
+# Match lines that actually raise AirflowException. Comment filtering is done
+# in _raise_lines() by skipping lines whose stripped form starts with "#".
+_RAISE_RE = re.compile(r"raise\s+AirflowException\b")
+
+
+class AllowlistManager:
+ def __init__(self, allowlist_file: Path) -> None:
+ self.allowlist_file = allowlist_file
+
+ def load(self) -> dict[str, int]:
+ """Return mapping of ``relative_path -> allowed_count``."""
+ if not self.allowlist_file.exists():
+ return {}
+
+ result: dict[str, int] = {}
+ for raw_line in self.allowlist_file.read_text().splitlines():
+ if not (stripped := raw_line.strip()):
+ continue
+
+ rel_str, _, count_str = stripped.rpartition("::")
+ if not rel_str or not count_str:
+ continue
+
+ try:
+ result[rel_str] = int(count_str)
+ except ValueError:
+ continue
+
+ return result
+
+ def save(self, counts: dict[str, int]) -> None:
+ lines = [f"{rel}::{count}" for rel, count in sorted(counts.items())]
+ self.allowlist_file.write_text("\n".join(lines) + "\n")
+
+ def generate(self) -> int:
+ console.print(f"Scanning [cyan]{REPO_ROOT}[/cyan] for raise
AirflowException …")
+ counts: dict[str, int] = {}
+ for path in _iter_python_files():
+ n = len(_raise_lines(path))
+ if n > 0:
+ counts[str(path.relative_to(REPO_ROOT))] = n
+
+ self.save(counts)
+ total = sum(counts.values())
+ console.print(
+ f"[green]✓ Generated[/green]
[cyan]{self.allowlist_file.relative_to(REPO_ROOT)}[/cyan] "
+ f"with [bold]{len(counts)}[/bold] files / [bold]{total}[/bold]
occurrences."
+ )
+ return 0
+
+ def cleanup(self) -> int:
+ allowlist = self.load()
+ if not allowlist:
+ console.print("[yellow]Allowlist is empty – nothing to clean
up.[/yellow]")
+ return 0
+
+ stale: list[str] = [rel for rel in allowlist if not (REPO_ROOT /
rel).exists()]
+ if stale:
+ console.print(
+ f"[yellow]Removing {len(stale)} stale entr{'y' if len(stale)
== 1 else 'ies'}:[/yellow]"
+ )
+ for s in sorted(stale):
+ console.print(f" [dim]-[/dim] {s}")
+ for s in stale:
+ del allowlist[s]
+ self.save(allowlist)
+ console.print(
+ f"\n[green]Updated[/green]
[cyan]{self.allowlist_file.relative_to(REPO_ROOT)}[/cyan]"
+ )
+ else:
+ console.print("[green]✓ No stale entries found.[/green]")
+ return 0
+
+
+def _raise_lines(path: Path) -> list[str]:
+ """Return stripped raise-lines from *path* that match the pattern."""
+ try:
+ text = path.read_text(encoding="utf-8", errors="replace")
+ except OSError:
+ return []
+
+ result = []
+ for raw_line in text.splitlines():
+ stripped = raw_line.strip()
+ # Skip comment lines
+ if stripped.startswith("#"):
+ continue
+ if _RAISE_RE.search(raw_line):
+ result.append(stripped)
+ return result
+
+
+def _iter_python_files() -> list[Path]:
+ return [
+ p.resolve() for p in REPO_ROOT.rglob("*.py") if ".tox" not in p.parts
and "__pycache__" not in p.parts
+ ]
+
+
+def _check_airflow_exception_usage(
+ files: list[Path], allowlist: dict[str, int], manager: AllowlistManager
+) -> int:
+ violations: list[tuple[Path, int, int]] = []
+ tightened: list[tuple[str, int, int]] = [] # (rel, old_count, new_count)
+
+ for path in files:
+ if not path.exists() or path.suffix != ".py":
+ continue
+ actual = len(_raise_lines(path))
+ rel = str(path.relative_to(REPO_ROOT))
+ allowed = allowlist.get(rel, 0)
+ if actual > allowed:
+ violations.append((path, actual, allowed))
+ elif actual < allowed:
+ # Usage was reduced — tighten the allowlist entry so it can't
creep back up.
+ if actual == 0:
+ del allowlist[rel]
+ else:
+ allowlist[rel] = actual
+ tightened.append((rel, allowed, actual))
+
+ if tightened:
+ manager.save(allowlist)
+ console.print(
+ f"[green]✓ Tightened {len(tightened)} entr{'y' if len(tightened)
== 1 else 'ies'} "
+ f"in
[cyan]{manager.allowlist_file.relative_to(REPO_ROOT)}[/cyan][/green] "
+ "(stage the updated file):"
+ )
+ for rel, old, new in tightened:
+ console.print(f" [cyan]{rel}[/cyan] {old} → {new}")
+
+ if violations:
+ console.print(
+ Panel.fit(
+ "New [bold]raise AirflowException[/bold] usage detected.\n"
+ "Define a dedicated exception class or use an existing
specific exception.\n"
+ "If this usage is intentional and pre-existing, run:\n\n"
+ " [cyan]uv run
./scripts/ci/prek/check_new_airflow_exception_usage.py --generate[/cyan]\n\n"
+ "to regenerate the allowlist, then commit the updated\n"
+ "[cyan]scripts/ci/prek/known_airflow_exceptions.txt[/cyan].",
+ title="[red]❌ Check failed[/red]",
+ border_style="red",
+ )
+ )
+ for path, actual, allowed in violations:
+ console.print(f" [cyan]{path.relative_to(REPO_ROOT)}[/cyan]
count={actual} (allowed={allowed})")
+ return 1
+
+ # Return 1 when the allowlist was tightened so pre-commit reports the file
as modified
+ # and prompts the user to stage the updated allowlist.
+ return 1 if tightened else 0
+
+
+def main(argv: list[str] | None = None) -> int:
+ parser = argparse.ArgumentParser(
+ description="Prevent new `raise AirflowException` usages.",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog=__doc__,
+ )
+ parser.add_argument("files", nargs="*", metavar="FILE", help="Files to
check (provided by prek)")
+ parser.add_argument(
+ "--all-files",
+ action="store_true",
+ help="Check every Python file in the repository",
+ )
+ parser.add_argument(
+ "--cleanup",
+ action="store_true",
+ help="Remove stale entries from the allowlist and exit",
+ )
+ parser.add_argument(
+ "--generate",
+ action="store_true",
+ help="Regenerate the allowlist from the current codebase and exit",
+ )
+ args = parser.parse_args(argv)
+
+ manager = AllowlistManager(Path(__file__).parent /
"known_airflow_exceptions.txt")
+
+ if args.generate:
+ return manager.generate()
+
+ if args.cleanup:
+ return manager.cleanup()
+
+ allowlist = manager.load()
+
+ if args.all_files:
+ return _check_airflow_exception_usage(_iter_python_files(), allowlist,
manager)
+
+ if not args.files:
+ console.print(
+ "[yellow]No files provided. Pass filenames or use --all-files to
scan the whole repo.[/yellow]"
+ )
+ return 0
+
+ return _check_airflow_exception_usage([Path(f).resolve() for f in
args.files], allowlist, manager)
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/scripts/ci/prek/known_airflow_exceptions.txt
b/scripts/ci/prek/known_airflow_exceptions.txt
new file mode 100644
index 00000000000..76e3994c549
--- /dev/null
+++ b/scripts/ci/prek/known_airflow_exceptions.txt
@@ -0,0 +1,433 @@
+airflow-core/src/airflow/api/common/delete_dag.py::1
+airflow-core/src/airflow/api_fastapi/core_api/app.py::1
+airflow-core/src/airflow/cli/cli_parser.py::1
+airflow-core/src/airflow/cli/commands/dag_command.py::3
+airflow-core/src/airflow/cli/commands/db_command.py::1
+airflow-core/src/airflow/config_templates/airflow_local_settings.py::1
+airflow-core/src/airflow/dag_processing/dagbag.py::1
+airflow-core/src/airflow/jobs/base_job_runner.py::1
+airflow-core/src/airflow/jobs/job.py::1
+airflow-core/src/airflow/models/connection.py::6
+airflow-core/src/airflow/models/crypto.py::1
+airflow-core/src/airflow/models/dagrun.py::2
+airflow-core/src/airflow/models/pool.py::2
+airflow-core/src/airflow/secrets/local_filesystem.py::4
+airflow-core/src/airflow/serialization/definitions/dag.py::1
+airflow-core/src/airflow/serialization/json_schema.py::1
+airflow-core/src/airflow/serialization/serialized_objects.py::2
+airflow-core/src/airflow/ti_deps/deps/valid_state_dep.py::1
+airflow-core/src/airflow/utils/cli.py::4
+airflow-core/src/airflow/utils/db.py::1
+airflow-core/src/airflow/utils/db_cleanup.py::1
+airflow-core/src/airflow/utils/db_manager.py::3
+airflow-core/src/airflow/utils/dot_renderer.py::3
+airflow-core/src/airflow/utils/helpers.py::4
+airflow-core/src/airflow/utils/process_utils.py::1
+airflow-core/tests/unit/models/test_dag.py::1
+airflow-core/tests/unit/models/test_taskinstance.py::3
+airflow-core/tests/unit/utils/test_process_utils.py::1
+devel-common/src/tests_common/test_utils/azure_system_helpers.py::3
+devel-common/src/tests_common/test_utils/logging_command_executor.py::1
+devel-common/src/tests_common/test_utils/salesforce_system_helpers.py::2
+devel-common/src/tests_common/test_utils/sftp_system_helpers.py::1
+devel-common/src/tests_common/test_utils/watcher.py::1
+providers/airbyte/src/airflow/providers/airbyte/hooks/airbyte.py::8
+providers/airbyte/src/airflow/providers/airbyte/operators/airbyte.py::4
+providers/airbyte/src/airflow/providers/airbyte/sensors/airbyte.py::6
+providers/alibaba/src/airflow/providers/alibaba/cloud/hooks/analyticdb_spark.py::6
+providers/alibaba/src/airflow/providers/alibaba/cloud/hooks/oss.py::11
+providers/alibaba/src/airflow/providers/alibaba/cloud/operators/analyticdb_spark.py::1
+providers/alibaba/src/airflow/providers/alibaba/cloud/sensors/oss_key.py::2
+providers/amazon/src/airflow/providers/amazon/aws/auth_manager/avp/facade.py::3
+providers/amazon/src/airflow/providers/amazon/aws/bundles/s3.py::5
+providers/amazon/src/airflow/providers/amazon/aws/executors/aws_lambda/lambda_executor.py::2
+providers/amazon/src/airflow/providers/amazon/aws/executors/batch/batch_executor.py::1
+providers/amazon/src/airflow/providers/amazon/aws/executors/ecs/ecs_executor.py::1
+providers/amazon/src/airflow/providers/amazon/aws/hooks/athena_sql.py::1
+providers/amazon/src/airflow/providers/amazon/aws/hooks/base_aws.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/batch_client.py::7
+providers/amazon/src/airflow/providers/amazon/aws/hooks/batch_waiters.py::1
+providers/amazon/src/airflow/providers/amazon/aws/hooks/chime.py::5
+providers/amazon/src/airflow/providers/amazon/aws/hooks/comprehend.py::1
+providers/amazon/src/airflow/providers/amazon/aws/hooks/datasync.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/dynamodb.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/ec2.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/elasticache_replication_group.py::1
+providers/amazon/src/airflow/providers/amazon/aws/hooks/emr.py::5
+providers/amazon/src/airflow/providers/amazon/aws/hooks/glue.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/glue_catalog.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/quicksight.py::4
+providers/amazon/src/airflow/providers/amazon/aws/hooks/rds.py::7
+providers/amazon/src/airflow/providers/amazon/aws/hooks/redshift_sql.py::3
+providers/amazon/src/airflow/providers/amazon/aws/hooks/s3.py::2
+providers/amazon/src/airflow/providers/amazon/aws/hooks/sagemaker.py::10
+providers/amazon/src/airflow/providers/amazon/aws/hooks/sagemaker_unified_studio.py::3
+providers/amazon/src/airflow/providers/amazon/aws/links/emr.py::2
+providers/amazon/src/airflow/providers/amazon/aws/operators/appflow.py::3
+providers/amazon/src/airflow/providers/amazon/aws/operators/athena.py::3
+providers/amazon/src/airflow/providers/amazon/aws/operators/batch.py::7
+providers/amazon/src/airflow/providers/amazon/aws/operators/bedrock.py::6
+providers/amazon/src/airflow/providers/amazon/aws/operators/comprehend.py::2
+providers/amazon/src/airflow/providers/amazon/aws/operators/datasync.py::10
+providers/amazon/src/airflow/providers/amazon/aws/operators/dms.py::6
+providers/amazon/src/airflow/providers/amazon/aws/operators/ec2.py::1
+providers/amazon/src/airflow/providers/amazon/aws/operators/ecs.py::7
+providers/amazon/src/airflow/providers/amazon/aws/operators/eks.py::12
+providers/amazon/src/airflow/providers/amazon/aws/operators/emr.py::24
+providers/amazon/src/airflow/providers/amazon/aws/operators/eventbridge.py::1
+providers/amazon/src/airflow/providers/amazon/aws/operators/glue.py::6
+providers/amazon/src/airflow/providers/amazon/aws/operators/glue_crawler.py::1
+providers/amazon/src/airflow/providers/amazon/aws/operators/glue_databrew.py::1
+providers/amazon/src/airflow/providers/amazon/aws/operators/kinesis_analytics.py::5
+providers/amazon/src/airflow/providers/amazon/aws/operators/lambda_function.py::1
+providers/amazon/src/airflow/providers/amazon/aws/operators/mwaa.py::1
+providers/amazon/src/airflow/providers/amazon/aws/operators/neptune.py::4
+providers/amazon/src/airflow/providers/amazon/aws/operators/rds.py::4
+providers/amazon/src/airflow/providers/amazon/aws/operators/redshift_cluster.py::9
+providers/amazon/src/airflow/providers/amazon/aws/operators/redshift_data.py::2
+providers/amazon/src/airflow/providers/amazon/aws/operators/s3.py::5
+providers/amazon/src/airflow/providers/amazon/aws/operators/sagemaker.py::22
+providers/amazon/src/airflow/providers/amazon/aws/operators/sagemaker_unified_studio.py::2
+providers/amazon/src/airflow/providers/amazon/aws/operators/step_function.py::2
+providers/amazon/src/airflow/providers/amazon/aws/sensors/athena.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/batch.py::6
+providers/amazon/src/airflow/providers/amazon/aws/sensors/bedrock.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/comprehend.py::2
+providers/amazon/src/airflow/providers/amazon/aws/sensors/dms.py::2
+providers/amazon/src/airflow/providers/amazon/aws/sensors/ec2.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/ecs.py::2
+providers/amazon/src/airflow/providers/amazon/aws/sensors/eks.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/emr.py::10
+providers/amazon/src/airflow/providers/amazon/aws/sensors/glacier.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/glue.py::6
+providers/amazon/src/airflow/providers/amazon/aws/sensors/glue_catalog_partition.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/glue_crawler.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/kinesis_analytics.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/lambda_function.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/mwaa.py::4
+providers/amazon/src/airflow/providers/amazon/aws/sensors/opensearch_serverless.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/quicksight.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/rds.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/redshift_cluster.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/s3.py::3
+providers/amazon/src/airflow/providers/amazon/aws/sensors/sagemaker.py::8
+providers/amazon/src/airflow/providers/amazon/aws/sensors/sagemaker_unified_studio.py::1
+providers/amazon/src/airflow/providers/amazon/aws/sensors/sqs.py::2
+providers/amazon/src/airflow/providers/amazon/aws/sensors/step_function.py::1
+providers/amazon/src/airflow/providers/amazon/aws/transfers/gcs_to_s3.py::1
+providers/amazon/src/airflow/providers/amazon/aws/transfers/redshift_to_s3.py::1
+providers/amazon/src/airflow/providers/amazon/aws/transfers/s3_to_dynamodb.py::3
+providers/amazon/src/airflow/providers/amazon/aws/transfers/s3_to_redshift.py::3
+providers/amazon/src/airflow/providers/amazon/aws/transfers/s3_to_sql.py::1
+providers/amazon/src/airflow/providers/amazon/aws/transfers/sql_to_s3.py::4
+providers/amazon/src/airflow/providers/amazon/aws/triggers/ecs.py::1
+providers/amazon/src/airflow/providers/amazon/aws/triggers/sagemaker.py::1
+providers/amazon/src/airflow/providers/amazon/aws/triggers/sqs.py::1
+providers/amazon/src/airflow/providers/amazon/aws/utils/__init__.py::1
+providers/amazon/src/airflow/providers/amazon/aws/utils/connection_wrapper.py::2
+providers/amazon/src/airflow/providers/amazon/aws/utils/waiter.py::1
+providers/amazon/src/airflow/providers/amazon/aws/utils/waiter_with_logging.py::6
+providers/amazon/tests/unit/amazon/aws/operators/test_ecs.py::1
+providers/apache/beam/src/airflow/providers/apache/beam/hooks/beam.py::8
+providers/apache/beam/src/airflow/providers/apache/beam/operators/beam.py::4
+providers/apache/druid/src/airflow/providers/apache/druid/hooks/druid.py::4
+providers/apache/flink/src/airflow/providers/apache/flink/sensors/flink_kubernetes.py::1
+providers/apache/hive/src/airflow/providers/apache/hive/hooks/hive.py::9
+providers/apache/hive/src/airflow/providers/apache/hive/operators/hive_stats.py::1
+providers/apache/hive/src/airflow/providers/apache/hive/transfers/s3_to_hive.py::6
+providers/apache/kafka/src/airflow/providers/apache/kafka/operators/consume.py::2
+providers/apache/kafka/src/airflow/providers/apache/kafka/operators/produce.py::1
+providers/apache/kafka/src/airflow/providers/apache/kafka/triggers/await_message.py::1
+providers/apache/kylin/src/airflow/providers/apache/kylin/hooks/kylin.py::1
+providers/apache/kylin/src/airflow/providers/apache/kylin/operators/kylin_cube.py::5
+providers/apache/livy/src/airflow/providers/apache/livy/hooks/livy.py::7
+providers/apache/livy/src/airflow/providers/apache/livy/operators/livy.py::3
+providers/apache/pig/src/airflow/providers/apache/pig/hooks/pig.py::1
+providers/apache/pinot/src/airflow/providers/apache/pinot/hooks/pinot.py::1
+providers/apache/spark/src/airflow/providers/apache/spark/hooks/spark_sql.py::2
+providers/apache/spark/src/airflow/providers/apache/spark/hooks/spark_submit.py::11
+providers/arangodb/src/airflow/providers/arangodb/hooks/arangodb.py::9
+providers/arangodb/src/airflow/providers/arangodb/operators/arangodb.py::1
+providers/atlassian/jira/src/airflow/providers/atlassian/jira/hooks/jira.py::1
+providers/celery/src/airflow/providers/celery/executors/celery_executor_utils.py::2
+providers/celery/src/airflow/providers/celery/executors/default_celery.py::5
+providers/celery/tests/integration/celery/test_celery_executor.py::2
+providers/cloudant/src/airflow/providers/cloudant/hooks/cloudant.py::2
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/backcompat/backwards_compat_converters.py::3
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/executors/kubernetes_executor_utils.py::2
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/hooks/kubernetes.py::5
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/custom_object_launcher.py::4
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/job.py::5
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/kueue.py::2
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/pod.py::3
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/resource.py::3
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/spark_kubernetes.py::1
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/resource_convert/env_variable.py::1
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/secrets/kubernetes_secrets_backend.py::1
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/sensors/spark_kubernetes.py::1
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/template_rendering.py::1
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/triggers/pod.py::2
+providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/pod_manager.py::2
+providers/common/sql/src/airflow/providers/common/sql/hooks/sql.py::1
+providers/common/sql/src/airflow/providers/common/sql/operators/generic_transfer.py::1
+providers/common/sql/src/airflow/providers/common/sql/operators/sql.py::7
+providers/common/sql/src/airflow/providers/common/sql/sensors/sql.py::6
+providers/common/sql/src/airflow/providers/common/sql/triggers/sql.py::1
+providers/databricks/src/airflow/providers/databricks/hooks/databricks.py::8
+providers/databricks/src/airflow/providers/databricks/hooks/databricks_base.py::46
+providers/databricks/src/airflow/providers/databricks/hooks/databricks_sql.py::2
+providers/databricks/src/airflow/providers/databricks/operators/databricks.py::10
+providers/databricks/src/airflow/providers/databricks/operators/databricks_repos.py::12
+providers/databricks/src/airflow/providers/databricks/operators/databricks_sql.py::8
+providers/databricks/src/airflow/providers/databricks/operators/databricks_workflow.py::4
+providers/databricks/src/airflow/providers/databricks/plugins/databricks_workflow.py::7
+providers/databricks/src/airflow/providers/databricks/sensors/databricks.py::4
+providers/databricks/src/airflow/providers/databricks/sensors/databricks_partition.py::4
+providers/databricks/src/airflow/providers/databricks/sensors/databricks_sql.py::1
+providers/databricks/src/airflow/providers/databricks/utils/databricks.py::3
+providers/databricks/src/airflow/providers/databricks/utils/mixins.py::5
+providers/databricks/tests/unit/databricks/hooks/test_databricks_base.py::1
+providers/datadog/src/airflow/providers/datadog/hooks/datadog.py::2
+providers/datadog/src/airflow/providers/datadog/sensors/datadog.py::1
+providers/dbt/cloud/src/airflow/providers/dbt/cloud/hooks/dbt.py::3
+providers/dbt/cloud/src/airflow/providers/dbt/cloud/operators/dbt.py::1
+providers/dbt/cloud/src/airflow/providers/dbt/cloud/sensors/dbt.py::1
+providers/dingding/src/airflow/providers/dingding/hooks/dingding.py::2
+providers/discord/src/airflow/providers/discord/operators/discord_webhook.py::1
+providers/docker/src/airflow/providers/docker/decorators/docker.py::1
+providers/docker/src/airflow/providers/docker/hooks/docker.py::3
+providers/docker/src/airflow/providers/docker/operators/docker_swarm.py::2
+providers/edge3/src/airflow/providers/edge3/example_dags/win_test.py::3
+providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py::3
+providers/fab/src/airflow/providers/fab/auth_manager/models/db.py::1
+providers/fab/src/airflow/providers/fab/www/extensions/init_security.py::1
+providers/facebook/src/airflow/providers/facebook/ads/hooks/ads.py::2
+providers/git/src/airflow/providers/git/bundles/git.py::5
+providers/git/src/airflow/providers/git/hooks/git.py::1
+providers/github/src/airflow/providers/github/operators/github.py::2
+providers/github/src/airflow/providers/github/sensors/github.py::3
+providers/github/tests/system/github/example_github.py::2
+providers/google/src/airflow/providers/google/ads/hooks/ads.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/alloy_db.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/bigquery.py::14
+providers/google/src/airflow/providers/google/cloud/hooks/bigtable.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_batch.py::5
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_build.py::3
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_composer.py::5
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_memorystore.py::5
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_run.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_sql.py::32
+providers/google/src/airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py::5
+providers/google/src/airflow/providers/google/cloud/hooks/compute.py::6
+providers/google/src/airflow/providers/google/cloud/hooks/compute_ssh.py::6
+providers/google/src/airflow/providers/google/cloud/hooks/dataflow.py::13
+providers/google/src/airflow/providers/google/cloud/hooks/dataform.py::4
+providers/google/src/airflow/providers/google/cloud/hooks/dataplex.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/dataproc.py::5
+providers/google/src/airflow/providers/google/cloud/hooks/dataproc_metastore.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/dlp.py::32
+providers/google/src/airflow/providers/google/cloud/hooks/functions.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/gcs.py::8
+providers/google/src/airflow/providers/google/cloud/hooks/gdm.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/kubernetes_engine.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/looker.py::8
+providers/google/src/airflow/providers/google/cloud/hooks/managed_kafka.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/mlengine.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/spanner.py::5
+providers/google/src/airflow/providers/google/cloud/hooks/stackdriver.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/tasks.py::3
+providers/google/src/airflow/providers/google/cloud/hooks/translate.py::3
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py::3
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py::8
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/feature_store.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/model_service.py::2
+providers/google/src/airflow/providers/google/cloud/hooks/vertex_ai/pipeline_job.py::1
+providers/google/src/airflow/providers/google/cloud/hooks/vision.py::5
+providers/google/src/airflow/providers/google/cloud/operators/alloy_db.py::16
+providers/google/src/airflow/providers/google/cloud/operators/bigquery.py::18
+providers/google/src/airflow/providers/google/cloud/operators/bigquery_dts.py::2
+providers/google/src/airflow/providers/google/cloud/operators/bigtable.py::5
+providers/google/src/airflow/providers/google/cloud/operators/cloud_batch.py::4
+providers/google/src/airflow/providers/google/cloud/operators/cloud_build.py::4
+providers/google/src/airflow/providers/google/cloud/operators/cloud_composer.py::6
+providers/google/src/airflow/providers/google/cloud/operators/cloud_logging_sink.py::2
+providers/google/src/airflow/providers/google/cloud/operators/cloud_run.py::9
+providers/google/src/airflow/providers/google/cloud/operators/cloud_sql.py::15
+providers/google/src/airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py::16
+providers/google/src/airflow/providers/google/cloud/operators/compute.py::19
+providers/google/src/airflow/providers/google/cloud/operators/dataflow.py::16
+providers/google/src/airflow/providers/google/cloud/operators/datafusion.py::2
+providers/google/src/airflow/providers/google/cloud/operators/dataplex.py::54
+providers/google/src/airflow/providers/google/cloud/operators/dataproc.py::32
+providers/google/src/airflow/providers/google/cloud/operators/dataproc_metastore.py::2
+providers/google/src/airflow/providers/google/cloud/operators/datastore.py::2
+providers/google/src/airflow/providers/google/cloud/operators/functions.py::6
+providers/google/src/airflow/providers/google/cloud/operators/gcs.py::2
+providers/google/src/airflow/providers/google/cloud/operators/gen_ai.py::20
+providers/google/src/airflow/providers/google/cloud/operators/kubernetes_engine.py::13
+providers/google/src/airflow/providers/google/cloud/operators/looker.py::1
+providers/google/src/airflow/providers/google/cloud/operators/managed_kafka.py::15
+providers/google/src/airflow/providers/google/cloud/operators/pubsub.py::1
+providers/google/src/airflow/providers/google/cloud/operators/spanner.py::19
+providers/google/src/airflow/providers/google/cloud/operators/speech_to_text.py::2
+providers/google/src/airflow/providers/google/cloud/operators/text_to_speech.py::1
+providers/google/src/airflow/providers/google/cloud/operators/translate.py::9
+providers/google/src/airflow/providers/google/cloud/operators/translate_speech.py::2
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py::1
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/custom_job.py::1
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/dataset.py::1
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/experiment_service.py::6
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/feature_store.py::2
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py::1
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/pipeline_job.py::1
+providers/google/src/airflow/providers/google/cloud/operators/vertex_ai/ray.py::6
+providers/google/src/airflow/providers/google/cloud/secrets/secret_manager.py::1
+providers/google/src/airflow/providers/google/cloud/sensors/bigquery.py::4
+providers/google/src/airflow/providers/google/cloud/sensors/bigquery_dts.py::1
+providers/google/src/airflow/providers/google/cloud/sensors/cloud_composer.py::4
+providers/google/src/airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py::1
+providers/google/src/airflow/providers/google/cloud/sensors/dataflow.py::8
+providers/google/src/airflow/providers/google/cloud/sensors/dataform.py::3
+providers/google/src/airflow/providers/google/cloud/sensors/datafusion.py::2
+providers/google/src/airflow/providers/google/cloud/sensors/dataplex.py::7
+providers/google/src/airflow/providers/google/cloud/sensors/dataproc.py::6
+providers/google/src/airflow/providers/google/cloud/sensors/dataproc_metastore.py::2
+providers/google/src/airflow/providers/google/cloud/sensors/gcs.py::7
+providers/google/src/airflow/providers/google/cloud/sensors/looker.py::4
+providers/google/src/airflow/providers/google/cloud/sensors/pubsub.py::1
+providers/google/src/airflow/providers/google/cloud/sensors/vertex_ai/feature_store.py::2
+providers/google/src/airflow/providers/google/cloud/sensors/workflows.py::1
+providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py::1
+providers/google/src/airflow/providers/google/cloud/transfers/bigquery_to_gcs.py::5
+providers/google/src/airflow/providers/google/cloud/transfers/cassandra_to_gcs.py::3
+providers/google/src/airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py::2
+providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_bigquery.py::7
+providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_gcs.py::6
+providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_local.py::1
+providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_sftp.py::1
+providers/google/src/airflow/providers/google/cloud/transfers/s3_to_gcs.py::2
+providers/google/src/airflow/providers/google/cloud/transfers/sftp_to_gcs.py::1
+providers/google/src/airflow/providers/google/cloud/triggers/bigquery.py::2
+providers/google/src/airflow/providers/google/cloud/triggers/cloud_composer.py::3
+providers/google/src/airflow/providers/google/cloud/triggers/cloud_run.py::1
+providers/google/src/airflow/providers/google/cloud/triggers/dataproc.py::5
+providers/google/src/airflow/providers/google/cloud/triggers/kubernetes_engine.py::1
+providers/google/src/airflow/providers/google/cloud/utils/credentials_provider.py::17
+providers/google/src/airflow/providers/google/common/hooks/base_google.py::7
+providers/google/src/airflow/providers/google/common/hooks/operation_helpers.py::2
+providers/google/src/airflow/providers/google/firebase/hooks/firestore.py::1
+providers/google/src/airflow/providers/google/firebase/operators/firestore.py::1
+providers/google/src/airflow/providers/google/leveldb/hooks/leveldb.py::4
+providers/google/src/airflow/providers/google/marketing_platform/hooks/campaign_manager.py::2
+providers/google/src/airflow/providers/google/marketing_platform/hooks/search_ads.py::1
+providers/google/src/airflow/providers/google/marketing_platform/operators/bid_manager.py::3
+providers/google/src/airflow/providers/google/marketing_platform/operators/campaign_manager.py::2
+providers/google/src/airflow/providers/google/marketing_platform/sensors/display_video.py::1
+providers/google/src/airflow/providers/google/suite/hooks/calendar.py::1
+providers/google/src/airflow/providers/google/suite/hooks/sheets.py::1
+providers/google/src/airflow/providers/google/suite/transfers/gcs_to_gdrive.py::1
+providers/google/tests/system/google/cloud/cloud_build/example_cloud_build_trigger.py::1
+providers/google/tests/system/google/cloud/composer/example_cloud_composer.py::1
+providers/google/tests/system/google/cloud/dataflow/example_dataflow_native_python_async.py::1
+providers/google/tests/system/google/cloud/dataflow/example_dataflow_sensors_deferrable.py::1
+providers/google/tests/unit/google/cloud/hooks/test_bigquery.py::1
+providers/google/tests/unit/google/cloud/operators/test_dataflow.py::1
+providers/google/tests/unit/google/cloud/utils/gcp_authenticator.py::2
+providers/http/src/airflow/providers/http/hooks/http.py::2
+providers/http/src/airflow/providers/http/operators/http.py::2
+providers/http/src/airflow/providers/http/triggers/http.py::1
+providers/http/tests/unit/http/sensors/test_http.py::2
+providers/imap/src/airflow/providers/imap/hooks/imap.py::1
+providers/jdbc/src/airflow/providers/jdbc/hooks/jdbc.py::2
+providers/jenkins/src/airflow/providers/jenkins/operators/jenkins_job_trigger.py::4
+providers/jenkins/src/airflow/providers/jenkins/sensors/jenkins.py::1
+providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py::4
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/adx.py::4
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/base_azure.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/batch.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/container_instance.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/cosmos.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/data_factory.py::26
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/data_lake.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/msgraph.py::3
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/wasb.py::2
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/operators/batch.py::10
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/operators/container_instances.py::10
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/operators/data_factory.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/operators/msgraph.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/operators/powerbi.py::4
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/operators/synapse.py::2
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/sensors/data_factory.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/sensors/msgraph.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/sensors/wasb.py::4
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/local_to_adls.py::1
+providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/sftp_to_wasb.py::1
+providers/microsoft/azure/tests/unit/microsoft/azure/hooks/test_asb.py::3
+providers/microsoft/azure/tests/unit/microsoft/azure/operators/test_asb.py::3
+providers/microsoft/psrp/src/airflow/providers/microsoft/psrp/hooks/psrp.py::2
+providers/microsoft/psrp/src/airflow/providers/microsoft/psrp/operators/psrp.py::3
+providers/microsoft/winrm/src/airflow/providers/microsoft/winrm/hooks/winrm.py::5
+providers/microsoft/winrm/src/airflow/providers/microsoft/winrm/operators/winrm.py::7
+providers/neo4j/src/airflow/providers/neo4j/sensors/neo4j.py::5
+providers/openfaas/src/airflow/providers/openfaas/hooks/openfaas.py::4
+providers/opensearch/src/airflow/providers/opensearch/hooks/opensearch.py::1
+providers/opensearch/src/airflow/providers/opensearch/log/os_task_handler.py::1
+providers/opensearch/src/airflow/providers/opensearch/operators/opensearch.py::9
+providers/pagerduty/src/airflow/providers/pagerduty/hooks/pagerduty.py::1
+providers/pagerduty/src/airflow/providers/pagerduty/hooks/pagerduty_events.py::2
+providers/postgres/src/airflow/providers/postgres/hooks/postgres.py::2
+providers/presto/src/airflow/providers/presto/hooks/presto.py::1
+providers/samba/src/airflow/providers/samba/transfers/gcs_to_samba.py::1
+providers/segment/src/airflow/providers/segment/hooks/segment.py::2
+providers/sftp/src/airflow/providers/sftp/hooks/sftp.py::6
+providers/sftp/src/airflow/providers/sftp/operators/sftp.py::2
+providers/sftp/src/airflow/providers/sftp/sensors/sftp.py::4
+providers/singularity/src/airflow/providers/singularity/operators/singularity.py::2
+providers/slack/src/airflow/providers/slack/hooks/slack.py::1
+providers/slack/src/airflow/providers/slack/hooks/slack_webhook.py::2
+providers/slack/src/airflow/providers/slack/transfers/base_sql_to_slack.py::1
+providers/slack/src/airflow/providers/slack/transfers/sql_to_slack.py::1
+providers/slack/src/airflow/providers/slack/transfers/sql_to_slack_webhook.py::3
+providers/smtp/src/airflow/providers/smtp/hooks/smtp.py::16
+providers/smtp/src/airflow/providers/smtp/operators/smtp.py::3
+providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake.py::1
+providers/snowflake/src/airflow/providers/snowflake/hooks/snowflake_sql_api.py::3
+providers/snowflake/src/airflow/providers/snowflake/operators/snowflake.py::3
+providers/snowflake/tests/unit/snowflake/operators/test_snowflake.py::1
+providers/ssh/src/airflow/providers/ssh/hooks/ssh.py::5
+providers/ssh/src/airflow/providers/ssh/operators/ssh.py::3
+providers/ssh/src/airflow/providers/ssh/operators/ssh_remote_job.py::7
+providers/standard/src/airflow/providers/standard/operators/bash.py::3
+providers/standard/src/airflow/providers/standard/operators/datetime.py::1
+providers/standard/src/airflow/providers/standard/operators/python.py::8
+providers/standard/src/airflow/providers/standard/operators/trigger_dagrun.py::6
+providers/standard/src/airflow/providers/standard/sensors/filesystem.py::1
+providers/standard/src/airflow/providers/standard/utils/skipmixin.py::3
+providers/standard/tests/unit/standard/operators/test_python.py::1
+providers/standard/tests/unit/standard/sensors/test_external_task_sensor.py::1
+providers/tableau/src/airflow/providers/tableau/hooks/tableau.py::1
+providers/tableau/src/airflow/providers/tableau/operators/tableau.py::3
+providers/telegram/src/airflow/providers/telegram/hooks/telegram.py::6
+providers/telegram/src/airflow/providers/telegram/operators/telegram.py::2
+providers/teradata/src/airflow/providers/teradata/hooks/bteq.py::10
+providers/teradata/src/airflow/providers/teradata/hooks/ttu.py::1
+providers/teradata/src/airflow/providers/teradata/operators/teradata_compute_cluster.py::9
+providers/teradata/src/airflow/providers/teradata/triggers/teradata_compute_cluster.py::1
+providers/teradata/src/airflow/providers/teradata/utils/bteq_util.py::2
+providers/trino/src/airflow/providers/trino/hooks/trino.py::1
+providers/vespa/src/airflow/providers/vespa/operators/vespa_ingest.py::1
+providers/ydb/src/airflow/providers/ydb/hooks/ydb.py::1
+providers/ydb/src/airflow/providers/ydb/operators/ydb.py::1
+scripts/ci/prek/check_new_airflow_exception_usage.py::5
+task-sdk/src/airflow/sdk/bases/sensor.py::1
+task-sdk/src/airflow/sdk/bases/skipmixin.py::3
+task-sdk/src/airflow/sdk/crypto.py::1
+task-sdk/src/airflow/sdk/definitions/_internal/setup_teardown.py::1
+task-sdk/src/airflow/sdk/definitions/connection.py::4
+task-sdk/src/airflow/sdk/definitions/decorators/setup_teardown.py::4
+task-sdk/src/airflow/sdk/definitions/xcom_arg.py::1
+task-sdk/src/airflow/sdk/execution_time/task_runner.py::1
+task-sdk/tests/task_sdk/bases/test_sensor.py::1
+task-sdk/tests/task_sdk/execution_time/test_task_runner.py::2