This is an automated email from the ASF dual-hosted git repository.
potiuk 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 490b5e816b8 Consistent way of checking Airflow version in providers
(#44686)
490b5e816b8 is described below
commit 490b5e816b804f338b0eb97f240ae874d4e15810
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Dec 10 08:35:51 2024 +0100
Consistent way of checking Airflow version in providers (#44686)
This PR introduces consistent way of checking version of Airflow
by Airflow providers. So far there were about 6 different ways on
how Providers checked for Airflow version - this PR aims to unify
this approach for now and in the future - at least until minimum
version of Airflow set to 2.11 where we are likely to introduce
a simpler check via #44607. Until then all providers are going
to have `version_references.py` module copied in their sources
that they will be importing the constants from.
This PR also adds pre-commit that checks if the
``version_compat.py`` module is imported from local package copy
or maybe from another provider or test code - both causing
unneeded dependencies from the provider - to another package or
to test code respectively.
---
.pre-commit-config.yaml | 7 +
contributing-docs/08_static_code_checks.rst | 2 +
dev/breeze/doc/images/output_static-checks.svg | 148 +++++++++++----------
dev/breeze/doc/images/output_static-checks.txt | 2 +-
dev/breeze/src/airflow_breeze/pre_commit_ids.py | 1 +
.../providers/MANAGING_PROVIDERS_LIFECYCLE.rst | 25 ++++
.../amazon/aws/auth_manager/aws_auth_manager.py | 8 +-
.../providers/amazon/aws/hooks/redshift_sql.py | 8 +-
.../providers/amazon/aws/transfers/gcs_to_s3.py | 4 +-
.../airflow/providers/amazon/aws/utils/__init__.py | 16 +--
.../airflow/providers/amazon}/version_compat.py | 7 +-
.../cncf/kubernetes/cli/kubernetes_command.py | 6 +-
.../providers/cncf/kubernetes}/version_compat.py | 7 +-
.../providers/common/compat/assets/__init__.py | 7 +-
.../providers/common/compat/lineage/hook.py | 2 +-
.../providers/common/compat/standard/operators.py | 8 +-
.../providers/common/compat}/version_compat.py | 7 +-
.../providers/common/compat/version_references.py | 27 ----
.../src/airflow/providers/common/io/assets/file.py | 6 +-
.../airflow/providers/common/io}/version_compat.py | 7 +-
.../airflow/providers/common/io/xcom/backend.py | 7 +-
.../src/airflow/providers/edge/cli/edge_command.py | 4 +-
.../providers/edge/plugins/edge_executor_plugin.py | 6 +-
.../src/airflow/providers/edge}/version_compat.py | 7 +-
.../providers/edge/worker_api/routes/_v2_compat.py | 7 +-
.../providers/elasticsearch/log/es_task_handler.py | 6 +-
.../providers/elasticsearch}/version_compat.py | 7 +-
.../src/airflow/providers/google/assets/gcs.py | 8 +-
.../google/cloud/log/stackdriver_task_handler.py | 6 +-
.../airflow/providers/google}/version_compat.py | 7 +-
.../providers/openlineage/extractors/base.py | 4 +-
.../providers/openlineage/plugins/listener.py | 10 +-
.../providers/openlineage/plugins/openlineage.py | 4 +-
.../airflow/providers/openlineage/utils/utils.py | 23 +---
.../providers/openlineage}/version_compat.py | 7 +-
.../providers/opensearch/log/os_task_handler.py | 6 +-
.../providers/opensearch}/version_compat.py | 7 +-
.../src/airflow/providers/presto/hooks/presto.py | 6 +-
.../airflow/providers/presto}/version_compat.py | 7 +-
.../airflow/providers/standard/operators/python.py | 5 +-
.../src/airflow/providers/standard/provider.yaml | 1 -
.../providers/standard/sensors/date_time.py | 2 +-
.../src/airflow/providers/standard/sensors/time.py | 2 +-
.../providers/standard/sensors/time_delta.py | 2 +-
.../providers/standard/triggers/external_task.py | 2 +-
.../providers/standard/triggers/temporal.py | 2 +-
.../providers/standard/utils/version_references.py | 26 ----
.../airflow/providers/standard}/version_compat.py | 7 +-
.../src/airflow/providers/trino/hooks/trino.py | 6 +-
.../src/airflow/providers/trino}/version_compat.py | 7 +-
.../amazon/aws/operators/test_redshift_sql.py | 4 +-
.../tests/openlineage/extractors/test_base.py | 2 +-
providers/tests/standard/triggers/test_temporal.py | 3 +-
.../ci/pre_commit/check_imports_in_providers.py | 96 +++++++++++++
scripts/ci/pre_commit/common_precommit_utils.py | 21 +++
tests_common/test_utils/version_compat.py | 7 +-
56 files changed, 360 insertions(+), 279 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 49e74d453d0..65e3a0895b2 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -174,6 +174,13 @@ repos:
language: python
additional_dependencies: ['rich>=12.4.4']
require_serial: true
+ - id: check-imports-in-providers
+ name: Check imports in providers
+ entry: ./scripts/ci/pre_commit/check_imports_in_providers.py
+ language: python
+ additional_dependencies: ['rich>=12.4.4', "ruff==0.8.1"]
+ files: ^providers/src/airflow/providers/.*\.py$
+ require_serial: true
- id: update-common-sql-api-stubs
name: Check and update common.sql API stubs
entry: ./scripts/ci/pre_commit/update_common_sql_api_stubs.py
diff --git a/contributing-docs/08_static_code_checks.rst
b/contributing-docs/08_static_code_checks.rst
index 01d8f9d303e..0775c83ef06 100644
--- a/contributing-docs/08_static_code_checks.rst
+++ b/contributing-docs/08_static_code_checks.rst
@@ -182,6 +182,8 @@ require Breeze Docker image to be built locally.
+-----------------------------------------------------------+--------------------------------------------------------+---------+
| check-hooks-apply | Check if all
hooks apply to the repository | |
+-----------------------------------------------------------+--------------------------------------------------------+---------+
+| check-imports-in-providers | Check imports in
providers | |
++-----------------------------------------------------------+--------------------------------------------------------+---------+
| check-incorrect-use-of-LoggingMixin | Make sure
LoggingMixin is not used alone | |
+-----------------------------------------------------------+--------------------------------------------------------+---------+
| check-init-decorator-arguments | Sync model
__init__ and decorator arguments | |
diff --git a/dev/breeze/doc/images/output_static-checks.svg
b/dev/breeze/doc/images/output_static-checks.svg
index 4a51fad1626..8d78c5924b4 100644
--- a/dev/breeze/doc/images/output_static-checks.svg
+++ b/dev/breeze/doc/images/output_static-checks.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 2246.0"
xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 2270.4"
xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -43,7 +43,7 @@
<defs>
<clipPath id="breeze-static-checks-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="2195.0" />
+ <rect x="0" y="0" width="1463.0" height="2219.4" />
</clipPath>
<clipPath id="breeze-static-checks-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -312,9 +312,12 @@
<clipPath id="breeze-static-checks-line-88">
<rect x="0" y="2148.7" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-static-checks-line-89">
+ <rect x="0" y="2173.1" width="1464" height="24.65"/>
+ </clipPath>
</defs>
- <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="2244" rx="8"/><text
class="breeze-static-checks-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: static-checks</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="2268.4" rx="8"/><text
class="breeze-static-checks-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: static-checks</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -345,75 +348,76 @@
</text><text class="breeze-static-checks-r5" x="0" y="459.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-18)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="459.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-18)">check-executables-have-shebangs | check-extra-packages-references |              </text><text
class="breeze-static-checks-r5" x="1451.8" y="459.2" te [...]
</text><text class="breeze-static-checks-r5" x="0" y="483.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-19)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="483.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-19)">check-extras-order | check-fab-migrations | check-for-inclusive-language |       </text><text
class="breeze-static-checks-r5" x="1451.8" y="483.6" textLength="12.2"
clip-path [...]
</text><text class="breeze-static-checks-r5" x="0" y="508" textLength="12.2"
clip-path="url(#breeze-static-checks-line-20)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="508" textLength="988.2"
clip-path="url(#breeze-static-checks-line-20)">check-get-lineage-collector-providers | check-google-re2-as-dependency |         </text><text
class="breeze-static-checks-r5" x="1451.8" y="508" textLength="12.2"
clip-path="url( [...]
-</text><text class="breeze-static-checks-r5" x="0" y="532.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-21)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="532.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-21)">check-hatch-build-order | check-hooks-apply | check-incorrect-use-of-LoggingMixin</text><text
class="breeze-static-checks-r5" x="1451.8" y="532.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-21)">│< [...]
-</text><text class="breeze-static-checks-r5" x="0" y="556.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-22)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="556.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-22)">| check-init-decorator-arguments | check-integrations-list-consistent |          </text><text
class="breeze-static-checks-r5" x="1451.8" y="556.8" textLength="12.2" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="581.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-23)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="581.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-23)">check-lazy-logging | check-links-to-example-dags-do-not-use-hardcoded-versions | </text><text
class="breeze-static-checks-r5" x="1451.8" y="581.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-23)">│< [...]
-</text><text class="breeze-static-checks-r5" x="0" y="605.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-24)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="605.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-24)">check-merge-conflict | check-min-python-version | check-newsfragments-are-valid |</text><text
class="breeze-static-checks-r5" x="1451.8" y="605.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-24 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="630" textLength="12.2"
clip-path="url(#breeze-static-checks-line-25)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="630" textLength="988.2"
clip-path="url(#breeze-static-checks-line-25)">check-no-airflow-deprecation-in-providers | check-no-providers-in-core-examples |</text><text
class="breeze-static-checks-r5" x="1451.8" y="630" textLength="12.2"
clip-path="url(#breeze-static-checks-line-25)">│</text><text [...]
-</text><text class="breeze-static-checks-r5" x="0" y="654.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-26)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="654.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-26)">check-only-new-session-with-provide-session |                              
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="678.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-27)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="678.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-27)">check-persist-credentials-disabled-in-github-workflows |                         </text><text
class="bre [...]
-</text><text class="breeze-static-checks-r5" x="0" y="703.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-28)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="703.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-28)">check-pre-commit-information-consistent | check-provide-create-sessions-imports |</text><text
class="breeze-static-checks-r5" x="1451.8" y="703.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-28)">│</text [...]
-</text><text class="breeze-static-checks-r5" x="0" y="727.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-29)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="727.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-29)">check-provider-docs-valid | check-provider-yaml-valid |                          </text><
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="752" textLength="12.2"
clip-path="url(#breeze-static-checks-line-30)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="752" textLength="988.2"
clip-path="url(#breeze-static-checks-line-30)">check-providers-subpackages-init-file-exist | check-pydevd-left-in-code |        </text><text
class="breeze-static-checks-r5" x="1451.8" y="752" textLength="12.2"
clip-path="url(#bree [...]
-</text><text class="breeze-static-checks-r5" x="0" y="776.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-31)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="776.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-31)">check-revision-heads-map | check-safe-filter-usage-in-html |                     </text><text
class="breeze-static [...]
-</text><text class="breeze-static-checks-r5" x="0" y="800.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-32)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="800.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-32)">check-sql-dependency-common-data-structure |                               
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="825.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-33)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="825.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-33)">check-start-date-not-used-in-defaults | check-system-tests-present |             </text><text
class="breeze-static-checks-r5" x="1451.8" y="825.2" textLen [...]
-</text><text class="breeze-static-checks-r5" x="0" y="849.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-34)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="849.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-34)">check-system-tests-tocs | check-taskinstance-tis-attrs |                         </text><text
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="874" textLength="12.2"
clip-path="url(#breeze-static-checks-line-35)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="874" textLength="988.2"
clip-path="url(#breeze-static-checks-line-35)">check-template-context-variable-in-sync | check-template-fields-valid |          </text><text
class="breeze-static-checks-r5" x="1451.8" y="874" textLength="12.2"
clip-path= [...]
-</text><text class="breeze-static-checks-r5" x="0" y="898.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-36)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="898.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-36)">check-tests-in-the-right-folders | check-tests-unittest-testcase |               </text><text
class="breeze-static-checks-r5" x="1451.8" y="898. [...]
-</text><text class="breeze-static-checks-r5" x="0" y="922.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-37)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="922.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-37)">check-urlparse-usage-in-code | check-usage-of-re2-over-re | check-xml | codespell</text><text
class="breeze-static-checks-r5" x="1451.8" y="922.8" textLength="12.2"
clip-path="url(#breeze-static-checks-li [...]
-</text><text class="breeze-static-checks-r5" x="0" y="947.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-38)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="947.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-38)">| compile-ui-assets | compile-ui-assets-dev | compile-www-assets |               </text><text
class="breeze-static-checks-r5" x=" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="971.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-39)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="971.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-39)">compile-www-assets-dev | create-missing-init-py-files-tests | debug-statements | </text><text
class="breeze-static-checks-r5" x="1451.8" y="971.6" textLength="12.2"
clip-path="url(#breeze-static-checks-li [...]
-</text><text class="breeze-static-checks-r5" x="0" y="996" textLength="12.2"
clip-path="url(#breeze-static-checks-line-40)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="996" textLength="988.2"
clip-path="url(#breeze-static-checks-line-40)">detect-private-key | doctoc | end-of-file-fixer | fix-encoding-pragma | flynt |  </text><text
class="breeze-static-checks-r5" x="1451.8" y="996" textLength="12.2"
clip-path="url(#bree [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1020.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-41)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1020.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-41)">generate-airflow-diagrams | generate-openapi-spec | generate-pypi-readme |       </text><text
class="breeze-static-checks-r5" x="1451.8" y="1020.4" textLength="12.2" clip-p
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1044.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-42)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1044.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-42)">identity | insert-license | kubeconform | lint-chart-schema | lint-css |         </text><text
class="breeze-static-checks-r5" x="1451.8" y="10 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1069.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-43)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1069.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-43)">lint-dockerfile | lint-helm-chart | lint-json-schema | lint-markdown |           </text><text
class="breeze-static-checks-r5" x="1451.8" y="10 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1093.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-44)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1093.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-44)">lint-openapi | mixed-line-ending | mypy-airflow | mypy-dev | mypy-docs |         </text><text
class="breeze-static-checks-r5" x="1451.8" y="10 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1118" textLength="12.2"
clip-path="url(#breeze-static-checks-line-45)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1118" textLength="988.2"
clip-path="url(#breeze-static-checks-line-45)">mypy-providers | mypy-task-sdk | pretty-format-json | pylint | python-no-log-warn</text><text
class="breeze-static-checks-r5" x="1451.8" y="1118" textLength="12.2"
clip-path="url(#breeze-static-ch [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1142.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-46)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1142.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-46)">| replace-bad-characters | rst-backticks | ruff | ruff-format | shellcheck |     </text><text
class="breeze-static-checks-r5" x="1451.8" y="1142.4" textLengt [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1166.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-47)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1166.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-47)">trailing-whitespace | ts-compile-format-lint-ui | ts-compile-format-lint-www |   </text><text
class="breeze-static-checks-r5" x="1451.8" y="1166.8" textLength="12.2"
clip-path="url(#breeze-sta [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1191.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-48)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1191.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-48)">update-black-version | update-breeze-cmd-output |                            
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1215.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-49)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1215.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-49)">update-breeze-readme-config-hash | update-build-dependencies |                   </text><text
class="breeze-static-checks- [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1240" textLength="12.2"
clip-path="url(#breeze-static-checks-line-50)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1240" textLength="988.2"
clip-path="url(#breeze-static-checks-line-50)">update-chart-dependencies | update-common-sql-api-stubs | update-er-diagram |    </text><text
class="breeze-static-checks-r5" x="1451.8" y="1240" textLength="12.2"
clip-path="url(#breeze-stat [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1264.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-51)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1264.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-51)">update-extras | update-in-the-wild-to-be-sorted |                            
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1288.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-52)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1288.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-52)">update-inlined-dockerfile-scripts | update-installed-providers-to-be-sorted |    </text><text
class="breeze-static-checks-r5" x="1451.8" y="1288.8" textLength="12.2"
clip-path="url(#breeze-static-c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1313.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-53)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1313.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-53)">update-installers | update-local-yml-file | update-migration-references |        </text><text
class="breeze-static-checks-r5" x="1451.8" y="1313.2" textLength="12.2" c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1337.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-54)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1337.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-54)">update-openapi-spec-tags-to-be-sorted | update-providers-dependencies |          </text><text
class="breeze-static-checks-r5" x="1451.8" y="1337.6" textLength="12.2" c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1362" textLength="12.2"
clip-path="url(#breeze-static-checks-line-55)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1362" textLength="988.2"
clip-path="url(#breeze-static-checks-line-55)">update-providers-init-py | update-reproducible-source-date-epoch |               </text><text
class="breeze-static-checks-r5" x="1451.8" y="1362" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1386.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-56)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1386.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-56)">update-spelling-wordlist-to-be-sorted | update-supported-versions |              </text><text
class="breeze-static-checks-r5" x="1451.8" y="1386.4" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1410.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-57)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1410.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-57)">update-vendored-in-k8s-json-schema | update-version | validate-operators-init |  </text><text
class="breeze-static-checks-r5" x="1451.8" y="1410.8" textLength="12.2"
clip-path="url(#breeze-static-c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1435.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-58)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1435.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-58)">yamllint)                                     &
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1459.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-59)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1459.6" textLength="268.4"
clip-path="url(#breeze-static-checks-line-59)">--show-diff-on-failure</text><text
class="breeze-static-checks-r6" x="402.6" y="1459.6" textLength="24.4"
clip-path="url(#breeze-static-checks-line-59)">-s</text><text
class="breeze-static-checks-r1" x="451.4" y="1459.6" textLength=" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1484" textLength="12.2"
clip-path="url(#breeze-static-checks-line-60)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1484" textLength="292.8"
clip-path="url(#breeze-static-checks-line-60)">--initialize-environment</text><text
class="breeze-static-checks-r1" x="451.4" y="1484" textLength="549"
clip-path="url(#breeze-static-checks-line-60)">Initialize environment before running checks.</text><text
class=" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1508.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-61)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1508.4" textLength="353.8"
clip-path="url(#breeze-static-checks-line-61)">--max-initialization-attempts</text><text
class="breeze-static-checks-r1" x="451.4" y="1508.4" textLength="854"
clip-path="url(#breeze-static-checks-line-61)">Maximum number of attempts to initialize env
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1532.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-62)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1532.8" textLength="854"
clip-path="url(#breeze-static-checks-line-62)">(INTEGER RANGE)                                   
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1557.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-63)">│</text><text
class="breeze-static-checks-r5" x="451.4" y="1557.2" textLength="854"
clip-path="url(#breeze-static-checks-line-63)">[default: 3; 1<=x<=10]                                
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1581.6"
textLength="1464"
clip-path="url(#breeze-static-checks-line-64)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="1581.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-64)">
-</text><text class="breeze-static-checks-r5" x="0" y="1606" textLength="24.4"
clip-path="url(#breeze-static-checks-line-65)">╭─</text><text
class="breeze-static-checks-r5" x="24.4" y="1606" textLength="463.6"
clip-path="url(#breeze-static-checks-line-65)"> Selecting files to run the checks on </text><text
class="breeze-static-checks-r5" x="488" y="1606" textLength="951.6"
clip-path="url(#breeze-static-checks-line-65)">──────────────────────────────
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1630.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-66)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1630.4" textLength="73.2"
clip-path="url(#breeze-static-checks-line-66)">--file</text><text
class="breeze-static-checks-r6" x="256.2" y="1630.4" textLength="24.4"
clip-path="url(#breeze-static-checks-line-66)">-f</text><text
class="breeze-static-checks-r1" x="305" y="1630.4" textLength="427"
clip-path="url [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1654.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-67)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1654.8" textLength="134.2"
clip-path="url(#breeze-static-checks-line-67)">--all-files</text><text
class="breeze-static-checks-r6" x="256.2" y="1654.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-67)">-a</text><text
class="breeze-static-checks-r1" x="305" y="1654.8" textLength="292.8" clip-p
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1679.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-68)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1679.2" textLength="146.4"
clip-path="url(#breeze-static-checks-line-68)">--commit-ref</text><text
class="breeze-static-checks-r6" x="256.2" y="1679.2" textLength="24.4"
clip-path="url(#breeze-static-checks-line-68)">-r</text><text
class="breeze-static-checks-r1" x="305" y="1679.2" textLength="1134.6" clip
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1703.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-69)">│</text><text
class="breeze-static-checks-r1" x="305" y="1703.6" textLength="183"
clip-path="url(#breeze-static-checks-line-69)">exclusive with </text><text
class="breeze-static-checks-r4" x="488" y="1703.6" textLength="158.6"
clip-path="url(#breeze-static-checks-line-69)">--last-commit</text><text
class="breeze-static-checks-r1" x="646.6" y="1703.6" te [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1728" textLength="12.2"
clip-path="url(#breeze-static-checks-line-70)">│</text><text
class="breeze-static-checks-r7" x="305" y="1728" textLength="1134.6"
clip-path="url(#breeze-static-checks-line-70)">(TEXT)                                      
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1752.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-71)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1752.4" textLength="158.6"
clip-path="url(#breeze-static-checks-line-71)">--last-commit</text><text
class="breeze-static-checks-r6" x="256.2" y="1752.4" textLength="24.4"
clip-path="url(#breeze-static-checks-line-71)">-c</text><text
class="breeze-static-checks-r1" x="305" y="1752.4" textLength="793" clip-p [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1776.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-72)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1776.8" textLength="207.4"
clip-path="url(#breeze-static-checks-line-72)">--only-my-changes</text><text
class="breeze-static-checks-r6" x="256.2" y="1776.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-72)">-m</text><text
class="breeze-static-checks-r1" x="305" y="1776.8" textLength="1134.6" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1801.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-73)">│</text><text
class="breeze-static-checks-r1" x="305" y="1801.2" textLength="1134.6"
clip-path="url(#breeze-static-checks-line-73)">branch and HEAD of your branch.                             
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1825.6"
textLength="1464"
clip-path="url(#breeze-static-checks-line-74)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="1825.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-74)">
-</text><text class="breeze-static-checks-r5" x="0" y="1850" textLength="24.4"
clip-path="url(#breeze-static-checks-line-75)">╭─</text><text
class="breeze-static-checks-r5" x="24.4" y="1850" textLength="463.6"
clip-path="url(#breeze-static-checks-line-75)"> Building image before running checks </text><text
class="breeze-static-checks-r5" x="488" y="1850" textLength="951.6"
clip-path="url(#breeze-static-checks-line-75)">────────────────────────────────────────
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1874.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-76)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1874.4" textLength="317.2"
clip-path="url(#breeze-static-checks-line-76)">--skip-image-upgrade-check</text><text
class="breeze-static-checks-r1" x="414.8" y="1874.4" textLength="536.8"
clip-path="url(#breeze-static-checks-line-76)">Skip checking if the CI image is up 
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1898.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-77)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1898.8" textLength="158.6"
clip-path="url(#breeze-static-checks-line-77)">--force-build</text><text
class="breeze-static-checks-r1" x="414.8" y="1898.8" textLength="707.6"
clip-path="url(#breeze-static-checks-line-77)">Force image build no matter if it is determined&
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1923.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-78)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1923.2" textLength="134.2"
clip-path="url(#breeze-static-checks-line-78)">--image-tag</text><text
class="breeze-static-checks-r1" x="414.8" y="1923.2" textLength="695.4"
clip-path="url(#breeze-static-checks-line-78)">Tag of the image which is used to run the
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1947.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-79)">│</text><text
class="breeze-static-checks-r7" x="414.8" y="1947.6" textLength="963.8"
clip-path="url(#breeze-static-checks-line-79)">(TEXT)                                     
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1972" textLength="12.2"
clip-path="url(#breeze-static-checks-line-80)">│</text><text
class="breeze-static-checks-r5" x="414.8" y="1972" textLength="963.8"
clip-path="url(#breeze-static-checks-line-80)">[default: latest]                                   
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1996.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-81)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1996.4" textLength="231.8"
clip-path="url(#breeze-static-checks-line-81)">--github-repository</text><text
class="breeze-static-checks-r6" x="366" y="1996.4" textLength="24.4"
clip-path="url(#breeze-static-checks-line-81)">-g</text><text
class="breeze-static-checks-r1" x="414.8" y="1996.4" textLength="585.6 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="2020.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-82)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2020.8" textLength="109.8"
clip-path="url(#breeze-static-checks-line-82)">--builder</text><text
class="breeze-static-checks-r1" x="414.8" y="2020.8" textLength="756.4"
clip-path="url(#breeze-static-checks-line-82)">Buildx builder used to perform `docker buildx build` 
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="2045.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-83)">│</text><text
class="breeze-static-checks-r5" x="414.8" y="2045.2" textLength="756.4"
clip-path="url(#breeze-static-checks-line-83)">[default: autodetect]                                  &#
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="2069.6"
textLength="1464"
clip-path="url(#breeze-static-checks-line-84)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="2069.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-84)">
-</text><text class="breeze-static-checks-r5" x="0" y="2094" textLength="24.4"
clip-path="url(#breeze-static-checks-line-85)">╭─</text><text
class="breeze-static-checks-r5" x="24.4" y="2094" textLength="195.2"
clip-path="url(#breeze-static-checks-line-85)"> Common options </text><text
class="breeze-static-checks-r5" x="219.6" y="2094" textLength="1220"
clip-path="url(#breeze-static-checks-line-85)">────────────────────────────────────────────────────────────────────────────
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="2118.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-86)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2118.4" textLength="109.8"
clip-path="url(#breeze-static-checks-line-86)">--dry-run</text><text
class="breeze-static-checks-r6" x="158.6" y="2118.4" textLength="24.4"
clip-path="url(#breeze-static-checks-line-86)">-D</text><text
class="breeze-static-checks-r1" x="207.4" y="2118.4" textLength="719.8" clip-p
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="2142.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-87)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2142.8" textLength="109.8"
clip-path="url(#breeze-static-checks-line-87)">--verbose</text><text
class="breeze-static-checks-r6" x="158.6" y="2142.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-87)">-v</text><text
class="breeze-static-checks-r1" x="207.4" y="2142.8" textLength="585.6" clip-p
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="2167.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-88)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2167.2" textLength="73.2"
clip-path="url(#breeze-static-checks-line-88)">--help</text><text
class="breeze-static-checks-r6" x="158.6" y="2167.2" textLength="24.4"
clip-path="url(#breeze-static-checks-line-88)">-h</text><text
class="breeze-static-checks-r1" x="207.4" y="2167.2" textLength="329.4"
clip-path= [...]
-</text><text class="breeze-static-checks-r5" x="0" y="2191.6"
textLength="1464"
clip-path="url(#breeze-static-checks-line-89)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="2191.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-89)">
+</text><text class="breeze-static-checks-r5" x="0" y="532.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-21)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="532.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-21)">check-hatch-build-order | check-hooks-apply | check-imports-in-providers |       </text><text
class="breeze-static-checks-r5" x="1451.8" y="532.4" textLength="12.2"
clip-path [...]
+</text><text class="breeze-static-checks-r5" x="0" y="556.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-22)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="556.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-22)">check-incorrect-use-of-LoggingMixin | check-init-decorator-arguments |           </text><text
class="breeze-static-checks-r5" x="1451.8" y="556.8" textLength="12.2" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="581.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-23)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="581.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-23)">check-integrations-list-consistent | check-lazy-logging |                        </text><text
class [...]
+</text><text class="breeze-static-checks-r5" x="0" y="605.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-24)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="605.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-24)">check-links-to-example-dags-do-not-use-hardcoded-versions | check-merge-conflict </text><text
class="breeze-static-checks-r5" x="1451.8" y="605.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-24)">│</text [...]
+</text><text class="breeze-static-checks-r5" x="0" y="630" textLength="12.2"
clip-path="url(#breeze-static-checks-line-25)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="630" textLength="988.2"
clip-path="url(#breeze-static-checks-line-25)">| check-min-python-version | check-newsfragments-are-valid |                     </text><text
class="breeze-stati [...]
+</text><text class="breeze-static-checks-r5" x="0" y="654.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-26)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="654.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-26)">check-no-airflow-deprecation-in-providers | check-no-providers-in-core-examples |</text><text
class="breeze-static-checks-r5" x="1451.8" y="654.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-26)">│</text [...]
+</text><text class="breeze-static-checks-r5" x="0" y="678.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-27)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="678.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-27)">check-only-new-session-with-provide-session |                              
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="703.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-28)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="703.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-28)">check-persist-credentials-disabled-in-github-workflows |                         </text><text
class="bre [...]
+</text><text class="breeze-static-checks-r5" x="0" y="727.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-29)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="727.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-29)">check-pre-commit-information-consistent | check-provide-create-sessions-imports |</text><text
class="breeze-static-checks-r5" x="1451.8" y="727.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-29)">│</text [...]
+</text><text class="breeze-static-checks-r5" x="0" y="752" textLength="12.2"
clip-path="url(#breeze-static-checks-line-30)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="752" textLength="988.2"
clip-path="url(#breeze-static-checks-line-30)">check-provider-docs-valid | check-provider-yaml-valid |                          </text><text
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="776.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-31)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="776.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-31)">check-providers-subpackages-init-file-exist | check-pydevd-left-in-code |        </text><text
class="breeze-static-checks-r5" x="1451.8" y="776.4" textLength="12.2"
clip-path="url [...]
+</text><text class="breeze-static-checks-r5" x="0" y="800.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-32)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="800.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-32)">check-revision-heads-map | check-safe-filter-usage-in-html |                     </text><text
class="breeze-static [...]
+</text><text class="breeze-static-checks-r5" x="0" y="825.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-33)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="825.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-33)">check-sql-dependency-common-data-structure |                               
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="849.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-34)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="849.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-34)">check-start-date-not-used-in-defaults | check-system-tests-present |             </text><text
class="breeze-static-checks-r5" x="1451.8" y="849.6" textLen [...]
+</text><text class="breeze-static-checks-r5" x="0" y="874" textLength="12.2"
clip-path="url(#breeze-static-checks-line-35)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="874" textLength="988.2"
clip-path="url(#breeze-static-checks-line-35)">check-system-tests-tocs | check-taskinstance-tis-attrs |                         </text><text
clas [...]
+</text><text class="breeze-static-checks-r5" x="0" y="898.4" textLength="12.2"
clip-path="url(#breeze-static-checks-line-36)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="898.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-36)">check-template-context-variable-in-sync | check-template-fields-valid |          </text><text
class="breeze-static-checks-r5" x="1451.8" y="898.4" textLength="12.2" clip
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="922.8" textLength="12.2"
clip-path="url(#breeze-static-checks-line-37)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="922.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-37)">check-tests-in-the-right-folders | check-tests-unittest-testcase |               </text><text
class="breeze-static-checks-r5" x="1451.8" y="922. [...]
+</text><text class="breeze-static-checks-r5" x="0" y="947.2" textLength="12.2"
clip-path="url(#breeze-static-checks-line-38)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="947.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-38)">check-urlparse-usage-in-code | check-usage-of-re2-over-re | check-xml | codespell</text><text
class="breeze-static-checks-r5" x="1451.8" y="947.2" textLength="12.2"
clip-path="url(#breeze-static-checks-li [...]
+</text><text class="breeze-static-checks-r5" x="0" y="971.6" textLength="12.2"
clip-path="url(#breeze-static-checks-line-39)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="971.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-39)">| compile-ui-assets | compile-ui-assets-dev | compile-www-assets |               </text><text
class="breeze-static-checks-r5" x=" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="996" textLength="12.2"
clip-path="url(#breeze-static-checks-line-40)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="996" textLength="988.2"
clip-path="url(#breeze-static-checks-line-40)">compile-www-assets-dev | create-missing-init-py-files-tests | debug-statements | </text><text
class="breeze-static-checks-r5" x="1451.8" y="996" textLength="12.2"
clip-path="url(#breeze-static-checks-line-40) [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1020.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-41)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1020.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-41)">detect-private-key | doctoc | end-of-file-fixer | fix-encoding-pragma | flynt |  </text><text
class="breeze-static-checks-r5" x="1451.8" y="1020.4" textLength="12.2"
clip-path=" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1044.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-42)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1044.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-42)">generate-airflow-diagrams | generate-openapi-spec | generate-pypi-readme |       </text><text
class="breeze-static-checks-r5" x="1451.8" y="1044.8" textLength="12.2" clip-p
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1069.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-43)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1069.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-43)">identity | insert-license | kubeconform | lint-chart-schema | lint-css |         </text><text
class="breeze-static-checks-r5" x="1451.8" y="10 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1093.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-44)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1093.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-44)">lint-dockerfile | lint-helm-chart | lint-json-schema | lint-markdown |           </text><text
class="breeze-static-checks-r5" x="1451.8" y="10 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1118" textLength="12.2"
clip-path="url(#breeze-static-checks-line-45)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1118" textLength="988.2"
clip-path="url(#breeze-static-checks-line-45)">lint-openapi | mixed-line-ending | mypy-airflow | mypy-dev | mypy-docs |         </text><text
class="breeze-static-checks-r5" x="1451.8" y="1118" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1142.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-46)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1142.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-46)">mypy-providers | mypy-task-sdk | pretty-format-json | pylint | python-no-log-warn</text><text
class="breeze-static-checks-r5" x="1451.8" y="1142.4" textLength="12.2"
clip-path="url(#breeze-sta [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1166.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-47)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1166.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-47)">| replace-bad-characters | rst-backticks | ruff | ruff-format | shellcheck |     </text><text
class="breeze-static-checks-r5" x="1451.8" y="1166.8" textLengt [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1191.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-48)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1191.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-48)">trailing-whitespace | ts-compile-format-lint-ui | ts-compile-format-lint-www |   </text><text
class="breeze-static-checks-r5" x="1451.8" y="1191.2" textLength="12.2"
clip-path="url(#breeze-sta [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1215.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-49)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1215.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-49)">update-black-version | update-breeze-cmd-output |                            
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1240" textLength="12.2"
clip-path="url(#breeze-static-checks-line-50)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1240" textLength="988.2"
clip-path="url(#breeze-static-checks-line-50)">update-breeze-readme-config-hash | update-build-dependencies |                   </text><text
class="breeze-static-checks-r5" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1264.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-51)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1264.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-51)">update-chart-dependencies | update-common-sql-api-stubs | update-er-diagram |    </text><text
class="breeze-static-checks-r5" x="1451.8" y="1264.4" textLength="12.2"
clip-path="url(#breez [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1288.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-52)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1288.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-52)">update-extras | update-in-the-wild-to-be-sorted |                            
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1313.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-53)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1313.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-53)">update-inlined-dockerfile-scripts | update-installed-providers-to-be-sorted |    </text><text
class="breeze-static-checks-r5" x="1451.8" y="1313.2" textLength="12.2"
clip-path="url(#breeze-static-c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1337.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-54)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1337.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-54)">update-installers | update-local-yml-file | update-migration-references |        </text><text
class="breeze-static-checks-r5" x="1451.8" y="1337.6" textLength="12.2" c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1362" textLength="12.2"
clip-path="url(#breeze-static-checks-line-55)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1362" textLength="988.2"
clip-path="url(#breeze-static-checks-line-55)">update-openapi-spec-tags-to-be-sorted | update-providers-dependencies |          </text><text
class="breeze-static-checks-r5" x="1451.8" y="1362" textLength="12.2" clip-pa
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1386.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-56)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1386.4" textLength="988.2"
clip-path="url(#breeze-static-checks-line-56)">update-providers-init-py | update-reproducible-source-date-epoch |               </text><text
class="breeze-static-checks-r5" x="1451.8" y="13 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1410.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-57)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1410.8" textLength="988.2"
clip-path="url(#breeze-static-checks-line-57)">update-spelling-wordlist-to-be-sorted | update-supported-versions |              </text><text
class="breeze-static-checks-r5" x="1451.8" y="1410.8" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1435.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-58)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1435.2" textLength="988.2"
clip-path="url(#breeze-static-checks-line-58)">update-vendored-in-k8s-json-schema | update-version | validate-operators-init |  </text><text
class="breeze-static-checks-r5" x="1451.8" y="1435.2" textLength="12.2"
clip-path="url(#breeze-static-c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1459.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-59)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1459.6" textLength="988.2"
clip-path="url(#breeze-static-checks-line-59)">yamllint)                                     &
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1484" textLength="12.2"
clip-path="url(#breeze-static-checks-line-60)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1484" textLength="268.4"
clip-path="url(#breeze-static-checks-line-60)">--show-diff-on-failure</text><text
class="breeze-static-checks-r6" x="402.6" y="1484" textLength="24.4"
clip-path="url(#breeze-static-checks-line-60)">-s</text><text
class="breeze-static-checks-r1" x="451.4" y="1484" textLength="524.6" c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1508.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-61)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1508.4" textLength="292.8"
clip-path="url(#breeze-static-checks-line-61)">--initialize-environment</text><text
class="breeze-static-checks-r1" x="451.4" y="1508.4" textLength="549"
clip-path="url(#breeze-static-checks-line-61)">Initialize environment before running checks.</text><text
c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1532.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-62)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1532.8" textLength="353.8"
clip-path="url(#breeze-static-checks-line-62)">--max-initialization-attempts</text><text
class="breeze-static-checks-r1" x="451.4" y="1532.8" textLength="854"
clip-path="url(#breeze-static-checks-line-62)">Maximum number of attempts to initialize env
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1557.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-63)">│</text><text
class="breeze-static-checks-r7" x="451.4" y="1557.2" textLength="854"
clip-path="url(#breeze-static-checks-line-63)">(INTEGER RANGE)                                   
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1581.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-64)">│</text><text
class="breeze-static-checks-r5" x="451.4" y="1581.6" textLength="854"
clip-path="url(#breeze-static-checks-line-64)">[default: 3; 1<=x<=10]                                
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1606" textLength="1464"
clip-path="url(#breeze-static-checks-line-65)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="1606" textLength="12.2"
clip-path="url(#breeze-static-checks-line-65)">
+</text><text class="breeze-static-checks-r5" x="0" y="1630.4"
textLength="24.4" clip-path="url(#breeze-static-checks-line-66)">╭─</text><text
class="breeze-static-checks-r5" x="24.4" y="1630.4" textLength="463.6"
clip-path="url(#breeze-static-checks-line-66)"> Selecting files to run the checks on </text><text
class="breeze-static-checks-r5" x="488" y="1630.4" textLength="951.6"
clip-path="url(#breeze-static-checks-line-66)">──────────────────────── [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1654.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-67)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1654.8" textLength="73.2"
clip-path="url(#breeze-static-checks-line-67)">--file</text><text
class="breeze-static-checks-r6" x="256.2" y="1654.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-67)">-f</text><text
class="breeze-static-checks-r1" x="305" y="1654.8" textLength="427"
clip-path="url [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1679.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-68)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1679.2" textLength="134.2"
clip-path="url(#breeze-static-checks-line-68)">--all-files</text><text
class="breeze-static-checks-r6" x="256.2" y="1679.2" textLength="24.4"
clip-path="url(#breeze-static-checks-line-68)">-a</text><text
class="breeze-static-checks-r1" x="305" y="1679.2" textLength="292.8" clip-p
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1703.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-69)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1703.6" textLength="146.4"
clip-path="url(#breeze-static-checks-line-69)">--commit-ref</text><text
class="breeze-static-checks-r6" x="256.2" y="1703.6" textLength="24.4"
clip-path="url(#breeze-static-checks-line-69)">-r</text><text
class="breeze-static-checks-r1" x="305" y="1703.6" textLength="1134.6" clip
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1728" textLength="12.2"
clip-path="url(#breeze-static-checks-line-70)">│</text><text
class="breeze-static-checks-r1" x="305" y="1728" textLength="183"
clip-path="url(#breeze-static-checks-line-70)">exclusive with </text><text
class="breeze-static-checks-r4" x="488" y="1728" textLength="158.6"
clip-path="url(#breeze-static-checks-line-70)">--last-commit</text><text
class="breeze-static-checks-r1" x="646.6" y="1728" textLength [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1752.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-71)">│</text><text
class="breeze-static-checks-r7" x="305" y="1752.4" textLength="1134.6"
clip-path="url(#breeze-static-checks-line-71)">(TEXT)                                      
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1776.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-72)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1776.8" textLength="158.6"
clip-path="url(#breeze-static-checks-line-72)">--last-commit</text><text
class="breeze-static-checks-r6" x="256.2" y="1776.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-72)">-c</text><text
class="breeze-static-checks-r1" x="305" y="1776.8" textLength="793" clip-p [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1801.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-73)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1801.2" textLength="207.4"
clip-path="url(#breeze-static-checks-line-73)">--only-my-changes</text><text
class="breeze-static-checks-r6" x="256.2" y="1801.2" textLength="24.4"
clip-path="url(#breeze-static-checks-line-73)">-m</text><text
class="breeze-static-checks-r1" x="305" y="1801.2" textLength="1134.6" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1825.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-74)">│</text><text
class="breeze-static-checks-r1" x="305" y="1825.6" textLength="1134.6"
clip-path="url(#breeze-static-checks-line-74)">branch and HEAD of your branch.                             
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1850" textLength="1464"
clip-path="url(#breeze-static-checks-line-75)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="1850" textLength="12.2"
clip-path="url(#breeze-static-checks-line-75)">
+</text><text class="breeze-static-checks-r5" x="0" y="1874.4"
textLength="24.4" clip-path="url(#breeze-static-checks-line-76)">╭─</text><text
class="breeze-static-checks-r5" x="24.4" y="1874.4" textLength="463.6"
clip-path="url(#breeze-static-checks-line-76)"> Building image before running checks </text><text
class="breeze-static-checks-r5" x="488" y="1874.4" textLength="951.6"
clip-path="url(#breeze-static-checks-line-76)">──────────────────────────────────
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1898.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-77)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1898.8" textLength="317.2"
clip-path="url(#breeze-static-checks-line-77)">--skip-image-upgrade-check</text><text
class="breeze-static-checks-r1" x="414.8" y="1898.8" textLength="536.8"
clip-path="url(#breeze-static-checks-line-77)">Skip checking if the CI image is up 
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1923.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-78)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1923.2" textLength="158.6"
clip-path="url(#breeze-static-checks-line-78)">--force-build</text><text
class="breeze-static-checks-r1" x="414.8" y="1923.2" textLength="707.6"
clip-path="url(#breeze-static-checks-line-78)">Force image build no matter if it is determined&
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1947.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-79)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="1947.6" textLength="134.2"
clip-path="url(#breeze-static-checks-line-79)">--image-tag</text><text
class="breeze-static-checks-r1" x="414.8" y="1947.6" textLength="695.4"
clip-path="url(#breeze-static-checks-line-79)">Tag of the image which is used to run the
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1972" textLength="12.2"
clip-path="url(#breeze-static-checks-line-80)">│</text><text
class="breeze-static-checks-r7" x="414.8" y="1972" textLength="963.8"
clip-path="url(#breeze-static-checks-line-80)">(TEXT)                                      &#
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1996.4"
textLength="12.2" clip-path="url(#breeze-static-checks-line-81)">│</text><text
class="breeze-static-checks-r5" x="414.8" y="1996.4" textLength="963.8"
clip-path="url(#breeze-static-checks-line-81)">[default: latest]                                   
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="2020.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-82)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2020.8" textLength="231.8"
clip-path="url(#breeze-static-checks-line-82)">--github-repository</text><text
class="breeze-static-checks-r6" x="366" y="2020.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-82)">-g</text><text
class="breeze-static-checks-r1" x="414.8" y="2020.8" textLength="585.6 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="2045.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-83)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2045.2" textLength="109.8"
clip-path="url(#breeze-static-checks-line-83)">--builder</text><text
class="breeze-static-checks-r1" x="414.8" y="2045.2" textLength="756.4"
clip-path="url(#breeze-static-checks-line-83)">Buildx builder used to perform `docker buildx build` 
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="2069.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-84)">│</text><text
class="breeze-static-checks-r5" x="414.8" y="2069.6" textLength="756.4"
clip-path="url(#breeze-static-checks-line-84)">[default: autodetect]                                  &#
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="2094" textLength="1464"
clip-path="url(#breeze-static-checks-line-85)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="2094" textLength="12.2"
clip-path="url(#breeze-static-checks-line-85)">
+</text><text class="breeze-static-checks-r5" x="0" y="2118.4"
textLength="24.4" clip-path="url(#breeze-static-checks-line-86)">╭─</text><text
class="breeze-static-checks-r5" x="24.4" y="2118.4" textLength="195.2"
clip-path="url(#breeze-static-checks-line-86)"> Common options </text><text
class="breeze-static-checks-r5" x="219.6" y="2118.4" textLength="1220"
clip-path="url(#breeze-static-checks-line-86)">──────────────────────────────────────────────────────────────────────
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="2142.8"
textLength="12.2" clip-path="url(#breeze-static-checks-line-87)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2142.8" textLength="109.8"
clip-path="url(#breeze-static-checks-line-87)">--dry-run</text><text
class="breeze-static-checks-r6" x="158.6" y="2142.8" textLength="24.4"
clip-path="url(#breeze-static-checks-line-87)">-D</text><text
class="breeze-static-checks-r1" x="207.4" y="2142.8" textLength="719.8" clip-p
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="2167.2"
textLength="12.2" clip-path="url(#breeze-static-checks-line-88)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2167.2" textLength="109.8"
clip-path="url(#breeze-static-checks-line-88)">--verbose</text><text
class="breeze-static-checks-r6" x="158.6" y="2167.2" textLength="24.4"
clip-path="url(#breeze-static-checks-line-88)">-v</text><text
class="breeze-static-checks-r1" x="207.4" y="2167.2" textLength="585.6" clip-p
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="2191.6"
textLength="12.2" clip-path="url(#breeze-static-checks-line-89)">│</text><text
class="breeze-static-checks-r4" x="24.4" y="2191.6" textLength="73.2"
clip-path="url(#breeze-static-checks-line-89)">--help</text><text
class="breeze-static-checks-r6" x="158.6" y="2191.6" textLength="24.4"
clip-path="url(#breeze-static-checks-line-89)">-h</text><text
class="breeze-static-checks-r1" x="207.4" y="2191.6" textLength="329.4"
clip-path= [...]
+</text><text class="breeze-static-checks-r5" x="0" y="2216" textLength="1464"
clip-path="url(#breeze-static-checks-line-90)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-static-checks-r1" x="1464" y="2216" textLength="12.2"
clip-path="url(#breeze-static-checks-line-90)">
</text>
</g>
</g>
diff --git a/dev/breeze/doc/images/output_static-checks.txt
b/dev/breeze/doc/images/output_static-checks.txt
index 83697252d59..5eafd7bd8a7 100644
--- a/dev/breeze/doc/images/output_static-checks.txt
+++ b/dev/breeze/doc/images/output_static-checks.txt
@@ -1 +1 @@
-f9eb3d902f6df6f3bcf01be469d958e3
+1fd1ce1703cb27b2fd042f55f5aa6ddd
diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py
b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
index 657559b601f..a3b1ba37266 100644
--- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py
+++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
@@ -56,6 +56,7 @@ PRE_COMMIT_LIST = [
"check-google-re2-as-dependency",
"check-hatch-build-order",
"check-hooks-apply",
+ "check-imports-in-providers",
"check-incorrect-use-of-LoggingMixin",
"check-init-decorator-arguments",
"check-integrations-list-consistent",
diff --git a/providers/src/airflow/providers/MANAGING_PROVIDERS_LIFECYCLE.rst
b/providers/src/airflow/providers/MANAGING_PROVIDERS_LIFECYCLE.rst
index 2ad00656a5a..867f45edf9f 100644
--- a/providers/src/airflow/providers/MANAGING_PROVIDERS_LIFECYCLE.rst
+++ b/providers/src/airflow/providers/MANAGING_PROVIDERS_LIFECYCLE.rst
@@ -433,6 +433,31 @@ the compatibility checks should be updated when min
airflow version is updated.
Details on how this should be done are described in
`Provider policies
<https://github.com/apache/airflow/blob/main/dev/README_RELEASE_PROVIDER_PACKAGES.md>`_
+Conditional provider variants
+=============================
+
+Sometimes providers need to have different variants for different versions of
Airflow. This is done by:
+
+* copying ``version_compat.py`` from one of the providers that already have
conditional variants to
+ the root package of the provider you are working on
+
+* importing the ``AIRFLOW_V_X_Y_PLUS`` that you need from that imported
``version_compat.py`` file.
+
+The main reasons we are doing it in this way:
+
+* checking version >= in Python has a non-obvious problem that the pre-release
version is always considered
+ lower than the final version. This is why we are using
``AIRFLOW_V_X_Y_PLUS`` to check for the version
+ that is greater or equal to the version we are checking against - because we
want the RC candidates
+ to be considered as equal to the final version (because those RC candidates
already contain the feature
+ that is added in the final version).
+* We do not want to add dependencies to another provider (say
``common.compat``) without strong need
+* Even if the code is duplicated, it is just one ``version_compat.py`` file
that is wholly copied
+ and it is not a big deal to maintain it.
+* There is a potential risk of one provider importing the same
``AIRFLOW_V_X_Y_PLUS`` from another provider
+ (and introduce accidental dependency) or from test code (which should not
happen), but we are preventing it
+ via pre-commit check ``check-imports-in-providers`` that will fail if the
+ ``version_compat`` module is imported from another provider or from test
code.
+
Releasing pre-installed providers for the first time
====================================================
diff --git
a/providers/src/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
b/providers/src/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
index fb32a37f573..4f1e62e726f 100644
---
a/providers/src/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
+++
b/providers/src/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
@@ -39,6 +39,7 @@ from
airflow.providers.amazon.aws.auth_manager.security_manager.aws_security_man
AwsSecurityManagerOverride,
)
from airflow.providers.amazon.aws.auth_manager.views.auth import
AwsAuthManagerAuthenticationViews
+from airflow.providers.amazon.version_compat import AIRFLOW_V_2_9_PLUS
try:
from airflow.auth.managers.base_auth_manager import BaseAuthManager,
ResourceMethod
@@ -81,12 +82,7 @@ class AwsAuthManager(BaseAuthManager):
"""
def __init__(self, appbuilder: AirflowAppBuilder) -> None:
- from packaging.version import Version
-
- from airflow.version import version
-
- # TODO: remove this if block when min_airflow_version is set to higher
than 2.9.0
- if Version(version) < Version("2.9"):
+ if not AIRFLOW_V_2_9_PLUS:
raise AirflowOptionalProviderFeatureException(
"``AwsAuthManager`` is compatible with Airflow versions >=
2.9."
)
diff --git a/providers/src/airflow/providers/amazon/aws/hooks/redshift_sql.py
b/providers/src/airflow/providers/amazon/aws/hooks/redshift_sql.py
index bfdf807318a..23b9555def8 100644
--- a/providers/src/airflow/providers/amazon/aws/hooks/redshift_sql.py
+++ b/providers/src/airflow/providers/amazon/aws/hooks/redshift_sql.py
@@ -20,19 +20,15 @@ from functools import cached_property
from typing import TYPE_CHECKING
import redshift_connector
-from packaging.version import Version
from redshift_connector import Connection as RedshiftConnection
from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL
-from airflow import __version__ as AIRFLOW_VERSION
from airflow.exceptions import AirflowException
from airflow.providers.amazon.aws.hooks.base_aws import AwsBaseHook
+from airflow.providers.amazon.version_compat import AIRFLOW_V_2_10_PLUS
from airflow.providers.common.sql.hooks.sql import DbApiHook
-_IS_AIRFLOW_2_10_OR_HIGHER = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("2.10.0")
-
-
if TYPE_CHECKING:
from airflow.models.connection import Connection
from airflow.providers.openlineage.sqlparser import DatabaseInfo
@@ -265,6 +261,6 @@ class RedshiftSQLHook(DbApiHook):
def get_openlineage_default_schema(self) -> str | None:
"""Return current schema. This is usually changed with ``SEARCH_PATH``
parameter."""
- if _IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
return self.get_first("SELECT CURRENT_SCHEMA();")[0]
return super().get_openlineage_default_schema()
diff --git a/providers/src/airflow/providers/amazon/aws/transfers/gcs_to_s3.py
b/providers/src/airflow/providers/amazon/aws/transfers/gcs_to_s3.py
index c4ead1b58a7..6899f7daffc 100644
--- a/providers/src/airflow/providers/amazon/aws/transfers/gcs_to_s3.py
+++ b/providers/src/airflow/providers/amazon/aws/transfers/gcs_to_s3.py
@@ -124,9 +124,9 @@ class GCSToS3Operator(BaseOperator):
self.s3_acl_policy = s3_acl_policy
self.keep_directory_structure = keep_directory_structure
try:
- from airflow.providers.google import __version__
+ from airflow.providers.google import __version__ as
_GOOGLE_PROVIDER_VERSION
- if Version(__version__) >= Version("10.3.0"):
+ if Version(Version(_GOOGLE_PROVIDER_VERSION).base_version) >=
Version("10.3.0"):
self.__is_match_glob_supported = True
else:
self.__is_match_glob_supported = False
diff --git a/providers/src/airflow/providers/amazon/aws/utils/__init__.py
b/providers/src/airflow/providers/amazon/aws/utils/__init__.py
index 74da7001b8c..35426ab865b 100644
--- a/providers/src/airflow/providers/amazon/aws/utils/__init__.py
+++ b/providers/src/airflow/providers/amazon/aws/utils/__init__.py
@@ -31,21 +31,7 @@ log = logging.getLogger(__name__)
def trim_none_values(obj: dict):
- from packaging.version import Version
-
- from airflow.version import version
-
- if Version(version) < Version("2.7"):
- # before version 2.7, the behavior is not the same.
- # Empty dict and lists are removed from the given dict.
- return {key: val for key, val in obj.items() if val is not None}
- else:
- # once airflow 2.6 rolls out of compatibility support for provider
packages,
- # we can replace usages of this method with the core one in our code,
- # and uncomment this warning for users who may use it.
- # warnings.warn("use airflow.utils.helpers.prune_dict() instead",
- # AirflowProviderDeprecationWarning, stacklevel=2)
- return prune_dict(obj)
+ return prune_dict(obj)
def datetime_to_epoch(date_time: datetime) -> int:
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/amazon/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/amazon/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/amazon/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git
a/providers/src/airflow/providers/cncf/kubernetes/cli/kubernetes_command.py
b/providers/src/airflow/providers/cncf/kubernetes/cli/kubernetes_command.py
index 1bca856fd32..ee629cc16e9 100644
--- a/providers/src/airflow/providers/cncf/kubernetes/cli/kubernetes_command.py
+++ b/providers/src/airflow/providers/cncf/kubernetes/cli/kubernetes_command.py
@@ -25,22 +25,18 @@ from datetime import datetime, timedelta
from kubernetes import client
from kubernetes.client.api_client import ApiClient
from kubernetes.client.rest import ApiException
-from packaging.version import Version
-from airflow import __version__ as airflow_version
from airflow.models import DagRun, TaskInstance
from airflow.providers.cncf.kubernetes import pod_generator
from airflow.providers.cncf.kubernetes.executors.kubernetes_executor import
KubeConfig
from airflow.providers.cncf.kubernetes.kube_client import get_kube_client
from airflow.providers.cncf.kubernetes.kubernetes_helper_functions import
create_unique_id
from airflow.providers.cncf.kubernetes.pod_generator import PodGenerator
+from airflow.providers.cncf.kubernetes.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils import cli as cli_utils, yaml
from airflow.utils.cli import get_dag
from airflow.utils.providers_configuration_loader import
providers_configuration_loaded
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
@cli_utils.action_cli
@providers_configuration_loaded
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/cncf/kubernetes/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/cncf/kubernetes/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/cncf/kubernetes/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/common/compat/assets/__init__.py
b/providers/src/airflow/providers/common/compat/assets/__init__.py
index b237b51c39f..41e2e65621a 100644
--- a/providers/src/airflow/providers/common/compat/assets/__init__.py
+++ b/providers/src/airflow/providers/common/compat/assets/__init__.py
@@ -19,8 +19,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
-from airflow.providers.common.compat.version_references import (
- AIRFLOW_V_2_8_PLUS,
+from airflow.providers.common.compat.version_compat import (
AIRFLOW_V_2_9_PLUS,
AIRFLOW_V_2_10_PLUS,
AIRFLOW_V_3_0_PLUS,
@@ -37,11 +36,9 @@ else:
from airflow.sdk.definitions.asset import Asset, AssetAlias, AssetAll,
AssetAny
else:
# dataset is renamed to asset since Airflow 3.0
+ from airflow.auth.managers.models.resource_details import
DatasetDetails as AssetDetails
from airflow.datasets import Dataset as Asset
- if AIRFLOW_V_2_8_PLUS:
- from airflow.auth.managers.models.resource_details import
DatasetDetails as AssetDetails
-
if AIRFLOW_V_2_9_PLUS:
from airflow.datasets import (
DatasetAll as AssetAll,
diff --git a/providers/src/airflow/providers/common/compat/lineage/hook.py
b/providers/src/airflow/providers/common/compat/lineage/hook.py
index 10c22084fab..1b18723c457 100644
--- a/providers/src/airflow/providers/common/compat/lineage/hook.py
+++ b/providers/src/airflow/providers/common/compat/lineage/hook.py
@@ -16,7 +16,7 @@
# under the License.
from __future__ import annotations
-from airflow.providers.common.compat.version_references import
AIRFLOW_V_2_10_PLUS, AIRFLOW_V_3_0_PLUS
+from airflow.providers.common.compat.version_compat import
AIRFLOW_V_2_10_PLUS, AIRFLOW_V_3_0_PLUS
def _get_asset_compat_hook_lineage_collector():
diff --git
a/providers/src/airflow/providers/common/compat/standard/operators.py
b/providers/src/airflow/providers/common/compat/standard/operators.py
index 1b319e1ff9f..0e34419043f 100644
--- a/providers/src/airflow/providers/common/compat/standard/operators.py
+++ b/providers/src/airflow/providers/common/compat/standard/operators.py
@@ -19,7 +19,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
-from airflow import __version__ as AIRFLOW_VERSION
+from airflow.providers.common.compat.version_compat import AIRFLOW_V_2_10_PLUS
if TYPE_CHECKING:
from airflow.providers.standard.operators.python import (
@@ -37,17 +37,13 @@ else:
get_current_context,
)
except ModuleNotFoundError:
- from packaging.version import Version
-
- _IS_AIRFLOW_2_10_OR_HIGHER =
Version(Version(AIRFLOW_VERSION).base_version) >= Version("2.10.0")
-
from airflow.operators.python import (
PythonOperator,
ShortCircuitOperator,
get_current_context,
)
- if _IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
from airflow.operators.python import _SERIALIZERS
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/common/compat/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/common/compat/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/common/compat/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git
a/providers/src/airflow/providers/common/compat/version_references.py
b/providers/src/airflow/providers/common/compat/version_references.py
deleted file mode 100644
index ac44d73ac22..00000000000
--- a/providers/src/airflow/providers/common/compat/version_references.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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.
-
-from __future__ import annotations
-
-from packaging.version import Version
-
-from airflow import __version__ as AIRFLOW_VERSION
-
-AIRFLOW_V_3_0_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("3.0.0")
-AIRFLOW_V_2_10_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("2.10.0")
-AIRFLOW_V_2_9_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("2.9.0")
-AIRFLOW_V_2_8_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("2.8.0")
diff --git a/providers/src/airflow/providers/common/io/assets/file.py
b/providers/src/airflow/providers/common/io/assets/file.py
index 28d990d5630..73b2ef0c953 100644
--- a/providers/src/airflow/providers/common/io/assets/file.py
+++ b/providers/src/airflow/providers/common/io/assets/file.py
@@ -19,12 +19,8 @@ from __future__ import annotations
import urllib.parse
from typing import TYPE_CHECKING
-from packaging.version import Version
+from airflow.providers.common.io.version_compat import AIRFLOW_V_3_0_PLUS
-from airflow import __version__ as AIRFLOW_VERSION
-
-# TODO: Remove version check block after bumping common provider to 1.3.0
-AIRFLOW_V_3_0_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("3.0.0")
if AIRFLOW_V_3_0_PLUS:
from airflow.sdk.definitions.asset import Asset
else:
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/common/io/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/common/io/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/common/io/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/common/io/xcom/backend.py
b/providers/src/airflow/providers/common/io/xcom/backend.py
index a41ab6a917e..addde4c6c10 100644
--- a/providers/src/airflow/providers/common/io/xcom/backend.py
+++ b/providers/src/airflow/providers/common/io/xcom/backend.py
@@ -25,12 +25,11 @@ from typing import TYPE_CHECKING, Any, TypeVar
from urllib.parse import urlsplit
import fsspec.utils
-from packaging.version import Version
-from airflow import __version__ as airflow_version
from airflow.configuration import conf
from airflow.io.path import ObjectStoragePath
from airflow.models.xcom import BaseXCom
+from airflow.providers.common.io.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils.json import XComDecoder, XComEncoder
if TYPE_CHECKING:
@@ -43,10 +42,6 @@ T = TypeVar("T")
SECTION = "common.io"
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
-
def _get_compression_suffix(compression: str) -> str:
"""
Return the compression suffix for the given compression.
diff --git a/providers/src/airflow/providers/edge/cli/edge_command.py
b/providers/src/airflow/providers/edge/cli/edge_command.py
index 7f110da38ea..8e89c835252 100644
--- a/providers/src/airflow/providers/edge/cli/edge_command.py
+++ b/providers/src/airflow/providers/edge/cli/edge_command.py
@@ -30,7 +30,6 @@ from typing import TYPE_CHECKING
import psutil
from lockfile.pidlockfile import read_pid_from_pidfile,
remove_existing_pidfile, write_pid_to_pidfile
-from packaging.version import Version
from airflow import __version__ as airflow_version, settings
from airflow.cli.cli_config import ARG_PID, ARG_VERBOSE, ActionCommand, Arg
@@ -46,6 +45,7 @@ from airflow.providers.edge.cli.api_client import (
worker_set_state,
)
from airflow.providers.edge.models.edge_worker import EdgeWorkerState,
EdgeWorkerVersionException
+from airflow.providers.edge.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils import cli as cli_utils, timezone
from airflow.utils.platform import IS_WINDOWS
from airflow.utils.providers_configuration_loader import
providers_configuration_loaded
@@ -81,8 +81,6 @@ def force_use_internal_api_on_edge_worker():
os.environ["_AIRFLOW__SKIP_DATABASE_EXECUTOR_COMPATIBILITY_CHECK"] = "1"
os.environ["AIRFLOW_ENABLE_AIP_44"] = "True"
if "airflow" in sys.argv[0] and sys.argv[1:3] == ["edge", "worker"]:
- AIRFLOW_VERSION = Version(airflow_version)
- AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >=
Version("3.0.0")
if AIRFLOW_V_3_0_PLUS:
# Obvious TODO Make EdgeWorker compatible with Airflow 3 (again)
raise SystemExit(
diff --git
a/providers/src/airflow/providers/edge/plugins/edge_executor_plugin.py
b/providers/src/airflow/providers/edge/plugins/edge_executor_plugin.py
index d97176db259..19166e98a2c 100644
--- a/providers/src/airflow/providers/edge/plugins/edge_executor_plugin.py
+++ b/providers/src/airflow/providers/edge/plugins/edge_executor_plugin.py
@@ -23,15 +23,14 @@ from typing import TYPE_CHECKING, Any
from flask import Blueprint
from flask_appbuilder import BaseView, expose
-from packaging.version import Version
from sqlalchemy import select
-from airflow import __version__ as airflow_version
from airflow.auth.managers.models.resource_details import AccessView
from airflow.configuration import conf
from airflow.exceptions import AirflowConfigException
from airflow.models.taskinstance import TaskInstanceState
from airflow.plugins_manager import AirflowPlugin
+from airflow.providers.edge.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils.session import NEW_SESSION, provide_session
from airflow.utils.yaml import safe_load
from airflow.www import utils as wwwutils
@@ -42,9 +41,6 @@ from airflow.www.extensions.init_views import
_CustomErrorRequestBodyValidator,
if TYPE_CHECKING:
from sqlalchemy.orm import Session
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
def _get_airflow_2_api_endpoint() -> Blueprint:
folder = Path(__file__).parents[1].resolve() # this is
airflow/providers/edge/
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/edge/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/edge/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/edge/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git
a/providers/src/airflow/providers/edge/worker_api/routes/_v2_compat.py
b/providers/src/airflow/providers/edge/worker_api/routes/_v2_compat.py
index 553456d4108..afe4af0fbd8 100644
--- a/providers/src/airflow/providers/edge/worker_api/routes/_v2_compat.py
+++ b/providers/src/airflow/providers/edge/worker_api/routes/_v2_compat.py
@@ -18,12 +18,7 @@
from __future__ import annotations
-from packaging.version import Version
-
-from airflow import __version__ as airflow_version
-
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
+from airflow.providers.edge.version_compat import AIRFLOW_V_3_0_PLUS
if AIRFLOW_V_3_0_PLUS:
# Just re-import the types from FastAPI and Airflow Core
diff --git
a/providers/src/airflow/providers/elasticsearch/log/es_task_handler.py
b/providers/src/airflow/providers/elasticsearch/log/es_task_handler.py
index 3fb68bc24e3..241fb14aa23 100644
--- a/providers/src/airflow/providers/elasticsearch/log/es_task_handler.py
+++ b/providers/src/airflow/providers/elasticsearch/log/es_task_handler.py
@@ -31,23 +31,19 @@ from urllib.parse import quote, urlparse
import elasticsearch
import pendulum
from elasticsearch.exceptions import NotFoundError
-from packaging.version import Version
-from airflow import __version__ as airflow_version
from airflow.configuration import conf
from airflow.exceptions import AirflowException
from airflow.models.dagrun import DagRun
from airflow.providers.elasticsearch.log.es_json_formatter import
ElasticsearchJSONFormatter
from airflow.providers.elasticsearch.log.es_response import
ElasticSearchResponse, Hit
+from airflow.providers.elasticsearch.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils import timezone
from airflow.utils.log.file_task_handler import FileTaskHandler
from airflow.utils.log.logging_mixin import ExternalLoggingMixin, LoggingMixin
from airflow.utils.module_loading import import_string
from airflow.utils.session import create_session
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
if TYPE_CHECKING:
from datetime import datetime
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/elasticsearch/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/elasticsearch/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/elasticsearch/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/google/assets/gcs.py
b/providers/src/airflow/providers/google/assets/gcs.py
index 22206e3f753..1d26fe8d3da 100644
--- a/providers/src/airflow/providers/google/assets/gcs.py
+++ b/providers/src/airflow/providers/google/assets/gcs.py
@@ -19,6 +19,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from airflow.providers.google.cloud.hooks.gcs import _parse_gcs_url
+from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
if TYPE_CHECKING:
from urllib.parse import SplitResult
@@ -26,16 +27,9 @@ if TYPE_CHECKING:
from airflow.providers.common.compat.assets import Asset
from airflow.providers.common.compat.openlineage.facet import Dataset as
OpenLineageDataset
else:
- # TODO: Remove this try-exception block after bumping common provider to
1.3.0
- # This is due to common provider AssetDetails import error handling
try:
from airflow.providers.common.compat.assets import Asset
except ImportError:
- from packaging.version import Version
-
- from airflow import __version__ as AIRFLOW_VERSION
-
- AIRFLOW_V_3_0_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("3.0.0")
if AIRFLOW_V_3_0_PLUS:
from airflow.sdk.definitions.asset import Asset
else:
diff --git
a/providers/src/airflow/providers/google/cloud/log/stackdriver_task_handler.py
b/providers/src/airflow/providers/google/cloud/log/stackdriver_task_handler.py
index b26696d290e..9ade3b812f0 100644
---
a/providers/src/airflow/providers/google/cloud/log/stackdriver_task_handler.py
+++
b/providers/src/airflow/providers/google/cloud/log/stackdriver_task_handler.py
@@ -30,18 +30,14 @@ from google.cloud.logging import Resource
from google.cloud.logging.handlers.transports import
BackgroundThreadTransport, Transport
from google.cloud.logging_v2.services.logging_service_v2 import
LoggingServiceV2Client
from google.cloud.logging_v2.types import ListLogEntriesRequest,
ListLogEntriesResponse
-from packaging.version import Version
-from airflow import __version__ as airflow_version
from airflow.exceptions import RemovedInAirflow3Warning
from airflow.providers.google.cloud.utils.credentials_provider import
get_credentials_and_project_id
from airflow.providers.google.common.consts import CLIENT_INFO
+from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils.log.trigger_handler import ctx_indiv_trigger
from airflow.utils.types import NOTSET, ArgNotSet
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
if TYPE_CHECKING:
from google.auth.credentials import Credentials
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/google/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/google/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/google/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/openlineage/extractors/base.py
b/providers/src/airflow/providers/openlineage/extractors/base.py
index ceb10ff8b1d..2b85825d8c6 100644
--- a/providers/src/airflow/providers/openlineage/extractors/base.py
+++ b/providers/src/airflow/providers/openlineage/extractors/base.py
@@ -29,7 +29,7 @@ with warnings.catch_warnings():
from openlineage.client.facet import BaseFacet as BaseFacet_V1
from openlineage.client.facet_v2 import JobFacet, RunFacet
-from airflow.providers.openlineage.utils.utils import IS_AIRFLOW_2_10_OR_HIGHER
+from airflow.providers.openlineage.utils.utils import AIRFLOW_V_2_10_PLUS
from airflow.utils.log.logging_mixin import LoggingMixin
from airflow.utils.state import TaskInstanceState
@@ -117,7 +117,7 @@ class DefaultExtractor(BaseExtractor):
def extract_on_complete(self, task_instance) -> OperatorLineage | None:
failed_states = [TaskInstanceState.FAILED,
TaskInstanceState.UP_FOR_RETRY]
- if not IS_AIRFLOW_2_10_OR_HIGHER: # todo: remove when min airflow
version >= 2.10.0
+ if not AIRFLOW_V_2_10_PLUS: # todo: remove when min airflow version
>= 2.10.0
# Before fix (#41053) implemented in Airflow 2.10 TaskInstance's
state was still RUNNING when
# being passed to listener's on_failure method. Since
`extract_on_complete()` is only called
# after task completion, RUNNING state means that we are dealing
with FAILED task in < 2.10
diff --git a/providers/src/airflow/providers/openlineage/plugins/listener.py
b/providers/src/airflow/providers/openlineage/plugins/listener.py
index 7f0073d8f95..aefd534f155 100644
--- a/providers/src/airflow/providers/openlineage/plugins/listener.py
+++ b/providers/src/airflow/providers/openlineage/plugins/listener.py
@@ -32,7 +32,7 @@ from airflow.providers.openlineage import conf
from airflow.providers.openlineage.extractors import ExtractorManager
from airflow.providers.openlineage.plugins.adapter import OpenLineageAdapter,
RunState
from airflow.providers.openlineage.utils.utils import (
- IS_AIRFLOW_2_10_OR_HIGHER,
+ AIRFLOW_V_2_10_PLUS,
get_airflow_dag_run_facet,
get_airflow_debug_facet,
get_airflow_job_facet,
@@ -61,7 +61,7 @@ _openlineage_listener: OpenLineageListener | None = None
def _get_try_number_success(val):
# todo: remove when min airflow version >= 2.10.0
- if IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
return val.try_number
return val.try_number - 1
@@ -273,7 +273,7 @@ class OpenLineageListener:
self._execute(on_success, "on_success", use_fork=True)
- if IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
@hookimpl
def on_task_instance_failed(
@@ -496,7 +496,7 @@ class OpenLineageListener:
self.log.debug("Executor have not started before
`on_dag_run_success`")
return
- if IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
task_ids = DagRun._get_partial_task_ids(dag_run.dag)
else:
task_ids = dag_run.dag.task_ids if dag_run.dag and
dag_run.dag.partial else None
@@ -529,7 +529,7 @@ class OpenLineageListener:
self.log.debug("Executor have not started before
`on_dag_run_failed`")
return
- if IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
task_ids = DagRun._get_partial_task_ids(dag_run.dag)
else:
task_ids = dag_run.dag.task_ids if dag_run.dag and
dag_run.dag.partial else None
diff --git a/providers/src/airflow/providers/openlineage/plugins/openlineage.py
b/providers/src/airflow/providers/openlineage/plugins/openlineage.py
index ce70f3a52a9..36c26657546 100644
--- a/providers/src/airflow/providers/openlineage/plugins/openlineage.py
+++ b/providers/src/airflow/providers/openlineage/plugins/openlineage.py
@@ -25,7 +25,7 @@ from airflow.providers.openlineage.plugins.macros import (
lineage_parent_id,
lineage_run_id,
)
-from airflow.providers.openlineage.utils.utils import IS_AIRFLOW_2_10_OR_HIGHER
+from airflow.providers.openlineage.version_compat import AIRFLOW_V_2_10_PLUS
class OpenLineageProviderPlugin(AirflowPlugin):
@@ -40,7 +40,7 @@ class OpenLineageProviderPlugin(AirflowPlugin):
if not conf.is_disabled():
macros = [lineage_job_namespace, lineage_job_name, lineage_run_id,
lineage_parent_id]
listeners = [get_openlineage_listener()]
- if IS_AIRFLOW_2_10_OR_HIGHER:
+ if AIRFLOW_V_2_10_PLUS:
from airflow.lineage.hook import HookLineageReader
hook_lineage_readers = [HookLineageReader]
diff --git a/providers/src/airflow/providers/openlineage/utils/utils.py
b/providers/src/airflow/providers/openlineage/utils/utils.py
index 8f9b00741ea..4408a833fba 100644
--- a/providers/src/airflow/providers/openlineage/utils/utils.py
+++ b/providers/src/airflow/providers/openlineage/utils/utils.py
@@ -27,14 +27,16 @@ from typing import TYPE_CHECKING, Any, Callable
import attrs
from openlineage.client.utils import RedactMixin
-from packaging.version import Version
from sqlalchemy import exists
from airflow import __version__ as AIRFLOW_VERSION
# TODO: move this maybe to Airflow's logic?
from airflow.models import DAG, BaseOperator, DagRun, MappedOperator,
TaskReschedule
-from airflow.providers.openlineage import __version__ as
OPENLINEAGE_PROVIDER_VERSION, conf
+from airflow.providers.openlineage import (
+ __version__ as OPENLINEAGE_PROVIDER_VERSION,
+ conf,
+)
from airflow.providers.openlineage.plugins.facets import (
AirflowDagRunFacet,
AirflowDebugRunFacet,
@@ -49,6 +51,7 @@ from airflow.providers.openlineage.utils.selective_enable
import (
is_dag_lineage_enabled,
is_task_lineage_enabled,
)
+from airflow.providers.openlineage.version_compat import AIRFLOW_V_2_10_PLUS,
AIRFLOW_V_3_0_PLUS
from airflow.sensors.base import BaseSensorOperator
from airflow.serialization.serialized_objects import SerializedBaseOperator
from airflow.utils.context import AirflowContextDeprecationWarning
@@ -69,16 +72,9 @@ if TYPE_CHECKING:
from airflow.providers.common.compat.assets import Asset
from airflow.utils.state import DagRunState, TaskInstanceState
else:
- # TODO: Remove this try-exception block after bumping common provider to
1.3.0
- # This is due to common provider AssetDetails import error handling
try:
from airflow.providers.common.compat.assets import Asset
except ImportError:
- from packaging.version import Version
-
- from airflow import __version__ as AIRFLOW_VERSION
-
- AIRFLOW_V_3_0_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("3.0.0")
if AIRFLOW_V_3_0_PLUS:
from airflow.sdk.definitions.asset import Asset
else:
@@ -87,7 +83,6 @@ else:
log = logging.getLogger(__name__)
_NOMINAL_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
-IS_AIRFLOW_2_10_OR_HIGHER = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("2.10.0")
def try_import_from_string(string: str) -> Any:
@@ -716,7 +711,7 @@ def get_filtered_unknown_operator_keys(operator:
BaseOperator) -> dict:
def should_use_external_connection(hook) -> bool:
# If we're at Airflow 2.10, the execution is process-isolated, so we can
safely run those again.
- if not IS_AIRFLOW_2_10_OR_HIGHER:
+ if not AIRFLOW_V_2_10_PLUS:
return hook.__class__.__name__ not in [
"SnowflakeHook",
"SnowflakeSqlApiHook",
@@ -732,12 +727,6 @@ def translate_airflow_asset(asset: Asset, lineage_context)
-> OpenLineageDataset
This function returns None if no URI normalizer is defined, no asset
converter is found or
some core Airflow changes are missing and ImportError is raised.
"""
- # TODO: Remove version check block after bumping common provider to 1.3.0
- from packaging.version import Version
-
- from airflow import __version__ as AIRFLOW_VERSION
-
- AIRFLOW_V_3_0_PLUS = Version(Version(AIRFLOW_VERSION).base_version) >=
Version("3.0.0")
if AIRFLOW_V_3_0_PLUS:
from airflow.sdk.definitions.asset import _get_normalized_scheme
else:
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/openlineage/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/openlineage/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/openlineage/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/opensearch/log/os_task_handler.py
b/providers/src/airflow/providers/opensearch/log/os_task_handler.py
index 7bbaecb1159..8e784076c5f 100644
--- a/providers/src/airflow/providers/opensearch/log/os_task_handler.py
+++ b/providers/src/airflow/providers/opensearch/log/os_task_handler.py
@@ -29,23 +29,19 @@ from typing import TYPE_CHECKING, Any, Callable, Literal
import pendulum
from opensearchpy import OpenSearch
from opensearchpy.exceptions import NotFoundError
-from packaging.version import Version
-from airflow import __version__ as airflow_version
from airflow.configuration import conf
from airflow.exceptions import AirflowException
from airflow.models import DagRun
from airflow.providers.opensearch.log.os_json_formatter import
OpensearchJSONFormatter
from airflow.providers.opensearch.log.os_response import Hit,
OpensearchResponse
+from airflow.providers.opensearch.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils import timezone
from airflow.utils.log.file_task_handler import FileTaskHandler
from airflow.utils.log.logging_mixin import ExternalLoggingMixin, LoggingMixin
from airflow.utils.module_loading import import_string
from airflow.utils.session import create_session
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
if TYPE_CHECKING:
from airflow.models.taskinstance import TaskInstance, TaskInstanceKey
USE_PER_RUN_LOG_ID = hasattr(DagRun, "get_log_template")
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/opensearch/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/opensearch/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/opensearch/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/presto/hooks/presto.py
b/providers/src/airflow/providers/presto/hooks/presto.py
index c78361f73eb..7d98a3ad872 100644
--- a/providers/src/airflow/providers/presto/hooks/presto.py
+++ b/providers/src/airflow/providers/presto/hooks/presto.py
@@ -23,19 +23,15 @@ from collections.abc import Iterable, Mapping
from typing import TYPE_CHECKING, Any, TypeVar
import prestodb
-from packaging.version import Version
from prestodb.exceptions import DatabaseError
from prestodb.transaction import IsolationLevel
-from airflow import __version__ as airflow_version
from airflow.configuration import conf
from airflow.exceptions import AirflowException
from airflow.providers.common.sql.hooks.sql import DbApiHook
+from airflow.providers.presto.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils.operator_helpers import AIRFLOW_VAR_NAME_FORMAT_MAPPING,
DEFAULT_FORMAT_PREFIX
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
if TYPE_CHECKING:
from airflow.models import Connection
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/presto/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/presto/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/presto/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/standard/operators/python.py
b/providers/src/airflow/providers/standard/operators/python.py
index 83e61820514..ce1447769e1 100644
--- a/providers/src/airflow/providers/standard/operators/python.py
+++ b/providers/src/airflow/providers/standard/operators/python.py
@@ -47,7 +47,10 @@ from airflow.models.taskinstance import _CURRENT_CONTEXT
from airflow.models.variable import Variable
from airflow.operators.branch import BranchMixIn
from airflow.providers.standard.utils.python_virtualenv import
prepare_virtualenv, write_python_script
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_2_10_PLUS, AIRFLOW_V_3_0_PLUS
+from airflow.providers.standard.version_compat import (
+ AIRFLOW_V_2_10_PLUS,
+ AIRFLOW_V_3_0_PLUS,
+)
from airflow.typing_compat import Literal
from airflow.utils import hashlib_wrapper
from airflow.utils.context import context_copy_partial, context_merge
diff --git a/providers/src/airflow/providers/standard/provider.yaml
b/providers/src/airflow/providers/standard/provider.yaml
index 6e5d7ba9e73..661f3f4f855 100644
--- a/providers/src/airflow/providers/standard/provider.yaml
+++ b/providers/src/airflow/providers/standard/provider.yaml
@@ -22,7 +22,6 @@ description: |
Airflow Standard Provider
state: ready
source-date-epoch: 1732434919
-
# note that those versions are maintained by release manager - do not update
them manually
versions:
- 0.0.2
diff --git a/providers/src/airflow/providers/standard/sensors/date_time.py
b/providers/src/airflow/providers/standard/sensors/date_time.py
index 65ca95da5cc..050c36239b2 100644
--- a/providers/src/airflow/providers/standard/sensors/date_time.py
+++ b/providers/src/airflow/providers/standard/sensors/date_time.py
@@ -23,7 +23,7 @@ from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, NoReturn
from airflow.providers.standard.triggers.temporal import DateTimeTrigger
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_3_0_PLUS
+from airflow.providers.standard.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.sensors.base import BaseSensorOperator
try:
diff --git a/providers/src/airflow/providers/standard/sensors/time.py
b/providers/src/airflow/providers/standard/sensors/time.py
index 6443f2a344a..273fda9d362 100644
--- a/providers/src/airflow/providers/standard/sensors/time.py
+++ b/providers/src/airflow/providers/standard/sensors/time.py
@@ -22,7 +22,7 @@ from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, NoReturn
from airflow.providers.standard.triggers.temporal import DateTimeTrigger
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_2_10_PLUS
+from airflow.providers.standard.version_compat import AIRFLOW_V_2_10_PLUS
from airflow.sensors.base import BaseSensorOperator
try:
diff --git a/providers/src/airflow/providers/standard/sensors/time_delta.py
b/providers/src/airflow/providers/standard/sensors/time_delta.py
index 8e0f26ac249..6b09a361efa 100644
--- a/providers/src/airflow/providers/standard/sensors/time_delta.py
+++ b/providers/src/airflow/providers/standard/sensors/time_delta.py
@@ -26,7 +26,7 @@ from packaging.version import Version
from airflow.configuration import conf
from airflow.exceptions import AirflowSkipException
from airflow.providers.standard.triggers.temporal import DateTimeTrigger,
TimeDeltaTrigger
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_3_0_PLUS
+from airflow.providers.standard.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.sensors.base import BaseSensorOperator
from airflow.utils import timezone
diff --git a/providers/src/airflow/providers/standard/triggers/external_task.py
b/providers/src/airflow/providers/standard/triggers/external_task.py
index ff99caf668d..a54729fa690 100644
--- a/providers/src/airflow/providers/standard/triggers/external_task.py
+++ b/providers/src/airflow/providers/standard/triggers/external_task.py
@@ -25,7 +25,7 @@ from sqlalchemy import func
from airflow.models import DagRun
from airflow.providers.standard.utils.sensor_helper import _get_count
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_3_0_PLUS
+from airflow.providers.standard.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.triggers.base import BaseTrigger, TriggerEvent
from airflow.utils.session import NEW_SESSION, provide_session
diff --git a/providers/src/airflow/providers/standard/triggers/temporal.py
b/providers/src/airflow/providers/standard/triggers/temporal.py
index 032af6186d2..12834509b51 100644
--- a/providers/src/airflow/providers/standard/triggers/temporal.py
+++ b/providers/src/airflow/providers/standard/triggers/temporal.py
@@ -24,7 +24,7 @@ from typing import Any
import pendulum
from airflow.exceptions import AirflowException
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_2_10_PLUS
+from airflow.providers.standard.version_compat import AIRFLOW_V_2_10_PLUS
from airflow.triggers.base import BaseTrigger, TriggerEvent
from airflow.utils import timezone
diff --git
a/providers/src/airflow/providers/standard/utils/version_references.py
b/providers/src/airflow/providers/standard/utils/version_references.py
deleted file mode 100644
index 47fc7a1e800..00000000000
--- a/providers/src/airflow/providers/standard/utils/version_references.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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.
-from __future__ import annotations
-
-from packaging.version import Version
-
-from airflow import __version__ as airflow_version
-
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_2_10_PLUS = Version(AIRFLOW_VERSION.base_version) >=
Version("2.10.0")
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/standard/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/standard/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/standard/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/src/airflow/providers/trino/hooks/trino.py
b/providers/src/airflow/providers/trino/hooks/trino.py
index 129f1288e4d..3e10d21051a 100644
--- a/providers/src/airflow/providers/trino/hooks/trino.py
+++ b/providers/src/airflow/providers/trino/hooks/trino.py
@@ -24,20 +24,16 @@ from pathlib import Path
from typing import TYPE_CHECKING, Any, TypeVar
import trino
-from packaging.version import Version
from trino.exceptions import DatabaseError
from trino.transaction import IsolationLevel
-from airflow import __version__ as airflow_version
from airflow.configuration import conf
from airflow.exceptions import AirflowException
from airflow.providers.common.sql.hooks.sql import DbApiHook
+from airflow.providers.trino.version_compat import AIRFLOW_V_3_0_PLUS
from airflow.utils.helpers import exactly_one
from airflow.utils.operator_helpers import AIRFLOW_VAR_NAME_FORMAT_MAPPING,
DEFAULT_FORMAT_PREFIX
-AIRFLOW_VERSION = Version(airflow_version)
-AIRFLOW_V_3_0_PLUS = Version(AIRFLOW_VERSION.base_version) >= Version("3.0.0")
-
if TYPE_CHECKING:
from airflow.models import Connection
diff --git a/tests_common/test_utils/version_compat.py
b/providers/src/airflow/providers/trino/version_compat.py
similarity index 77%
copy from tests_common/test_utils/version_compat.py
copy to providers/src/airflow/providers/trino/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/providers/src/airflow/providers/trino/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations
diff --git a/providers/tests/amazon/aws/operators/test_redshift_sql.py
b/providers/tests/amazon/aws/operators/test_redshift_sql.py
index d415f19ed4e..1b124ee2028 100644
--- a/providers/tests/amazon/aws/operators/test_redshift_sql.py
+++ b/providers/tests/amazon/aws/operators/test_redshift_sql.py
@@ -79,10 +79,10 @@ class TestRedshiftSQLOpenLineage:
],
)
@patch(
-
"airflow.providers.amazon.aws.hooks.redshift_sql._IS_AIRFLOW_2_10_OR_HIGHER",
+ "airflow.providers.amazon.aws.hooks.redshift_sql.AIRFLOW_V_2_10_PLUS",
new_callable=PropertyMock,
)
-
@patch("airflow.providers.openlineage.utils.utils.IS_AIRFLOW_2_10_OR_HIGHER",
new_callable=PropertyMock)
+ @patch("airflow.providers.openlineage.utils.utils.AIRFLOW_V_2_10_PLUS",
new_callable=PropertyMock)
@patch("airflow.providers.amazon.aws.hooks.base_aws.AwsBaseHook.conn")
def test_execute_openlineage_events(
self,
diff --git a/providers/tests/openlineage/extractors/test_base.py
b/providers/tests/openlineage/extractors/test_base.py
index aa1a2467a83..d2122e418be 100644
--- a/providers/tests/openlineage/extractors/test_base.py
+++ b/providers/tests/openlineage/extractors/test_base.py
@@ -260,7 +260,7 @@ def test_extract_on_failure(task_state,
is_airflow_2_10_or_higher, should_call_o
extractor = DefaultExtractor(operator=operator)
with mock.patch(
-
"airflow.providers.openlineage.extractors.base.IS_AIRFLOW_2_10_OR_HIGHER",
is_airflow_2_10_or_higher
+ "airflow.providers.openlineage.extractors.base.AIRFLOW_V_2_10_PLUS",
is_airflow_2_10_or_higher
):
result = extractor.extract_on_complete(task_instance)
diff --git a/providers/tests/standard/triggers/test_temporal.py
b/providers/tests/standard/triggers/test_temporal.py
index 7271d43f5d0..91e27298c50 100644
--- a/providers/tests/standard/triggers/test_temporal.py
+++ b/providers/tests/standard/triggers/test_temporal.py
@@ -24,12 +24,13 @@ import pendulum
import pytest
from airflow.providers.standard.triggers.temporal import DateTimeTrigger,
TimeDeltaTrigger
-from airflow.providers.standard.utils.version_references import
AIRFLOW_V_2_10_PLUS
from airflow.triggers.base import TriggerEvent
from airflow.utils import timezone
from airflow.utils.state import TaskInstanceState
from airflow.utils.timezone import utcnow
+from tests_common.test_utils.version_compat import AIRFLOW_V_2_10_PLUS
+
def test_input_validation():
"""
diff --git a/scripts/ci/pre_commit/check_imports_in_providers.py
b/scripts/ci/pre_commit/check_imports_in_providers.py
new file mode 100755
index 00000000000..2934b6402ed
--- /dev/null
+++ b/scripts/ci/pre_commit/check_imports_in_providers.py
@@ -0,0 +1,96 @@
+#!/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.
+from __future__ import annotations
+
+import json
+import os.path
+import subprocess
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).parent.resolve()))
+from common_precommit_utils import (
+ AIRFLOW_SOURCES_ROOT_PATH,
+ console,
+ get_provider_dir,
+ get_provider_from_path,
+)
+
+errors_found = False
+
+
+def check_imports(folders_to_check: list[Path]):
+ global errors_found
+ import_tree_str = subprocess.check_output(
+ [
+ "ruff",
+ "analyze",
+ "graph",
+ *[folder_to_check.as_posix() for folder_to_check in
folders_to_check],
+ ]
+ )
+ import_tree = json.loads(import_tree_str)
+ # Uncomment these if you want to debug strange dependencies and see if
ruff gets it right
+ # console.print("Dependencies discovered by ruff:")
+ # console.print(import_tree)
+
+ for importing_file in sys.argv[1:]:
+ if not importing_file.startswith("providers/"):
+ console.print(f"[yellow]Skipping non-provider file:
{importing_file}")
+ continue
+ imported_files = import_tree.get(importing_file, None)
+ if imported_files is None:
+ if importing_file != "providers/src/airflow/providers/__init__.py":
+ # providers/__init__.py should be ignored
+ console.print(f"[red]The file {importing_file} is not
discovered by ruff analyze!")
+ errors_found = True
+ continue
+ for imported_file in imported_files:
+ if imported_file.endswith("/version_compat.py"):
+ # Note - this will check also imports from other places - not
only from providers
+ # Which means that import from tests_common, and airflow will
be also banned
+ common_path = os.path.commonpath([importing_file,
imported_file])
+ imported_file_parent_dir =
Path(imported_file).parent.as_posix()
+ if common_path != imported_file_parent_dir:
+ provider_id = get_provider_from_path(Path(importing_file))
+ provider_dir = get_provider_dir(provider_id)
+ console.print(
+ f"\n[red]Invalid import of `version_compat` module in
provider {provider_id} in:\n"
+ )
+ console.print(f"[yellow]{importing_file}")
+ console.print(
+ f"\n[bright_blue]The AIRFLOW_V_X_Y_PLUS import should
be "
+ f"from the {provider_id} provider root directory
({provider_dir}), but it is currently from:"
+ )
+ console.print(f"\n[yellow]{imported_file}\n")
+ console.print(
+ f"1. Copy `version_compat`.py to
`{provider_dir}/version_compat.py` if not there.\n"
+ f"2. Import the version constants you need as:\n\n"
+ f"[yellow]from
airflow.providers.{provider_id}.version_compat import ...[/]\n"
+ f"\n"
+ )
+ errors_found = True
+
+
+check_imports([AIRFLOW_SOURCES_ROOT_PATH / "providers" / "src",
AIRFLOW_SOURCES_ROOT_PATH / "tests_common"])
+
+if errors_found:
+ console.print("\n[red]Errors found in imports![/]\n")
+ sys.exit(1)
+else:
+ console.print("\n[green]All version_compat imports are correct![/]\n")
diff --git a/scripts/ci/pre_commit/common_precommit_utils.py
b/scripts/ci/pre_commit/common_precommit_utils.py
index b8d29410db4..e6ba1547be0 100644
--- a/scripts/ci/pre_commit/common_precommit_utils.py
+++ b/scripts/ci/pre_commit/common_precommit_utils.py
@@ -231,3 +231,24 @@ def validate_cmd_result(cmd_result,
include_ci_env_check=False):
"run `breeze ci-image build --python 3.9` and try again."
)
sys.exit(cmd_result.returncode)
+
+
+def get_provider_from_path(file_path: Path) -> str | None:
+ """
+ Get the provider name from the path of the file it belongs to.
+ """
+ for parent in file_path.parents:
+ if (parent / "provider.yaml").exists():
+ for providers_candidate in parent.parents:
+ if providers_candidate.name == "providers":
+ return
parent.relative_to(providers_candidate).as_posix().replace("/", ".")
+ else:
+ return None
+ return None
+
+
+def get_provider_dir(provider_id: str) -> Path:
+ """
+ Get the provider directory from the provider =id.
+ """
+ return Path("providers") / "src" / "airflow" / "providers" /
provider_id.replace(".", os.sep)
diff --git a/tests_common/test_utils/version_compat.py
b/tests_common/test_utils/version_compat.py
index fd48d6863d3..5c9afb34ac7 100644
--- a/tests_common/test_utils/version_compat.py
+++ b/tests_common/test_utils/version_compat.py
@@ -14,7 +14,12 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-
+#
+# NOTE! THIS FILE IS COPIED MANUALLY IN OTHER PROVIDERS DELIBERATELY TO AVOID
ADDING UNNECESSARY
+# DEPENDENCIES BETWEEN PROVIDERS. IF YOU WANT TO ADD CONDITIONAL CODE IN YOUR
PROVIDER THAT DEPENDS
+# ON AIRFLOW VERSION, PLEASE COPY THIS FILE TO THE ROOT PACKAGE OF YOUR
PROVIDER AND IMPORT
+# THOSE CONSTANTS FROM IT RATHER THAN IMPORTING THEM FROM ANOTHER PROVIDER OR
TEST CODE
+#
from __future__ import annotations