This is an automated email from the ASF dual-hosted git repository.

uranusjr 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 7b5b3470c1 Add pre-commit hook to check session default value (#28007)
7b5b3470c1 is described below

commit 7b5b3470c13dedbd699e0335548bdba7083cb29e
Author: Tzu-ping Chung <[email protected]>
AuthorDate: Mon Dec 19 17:38:55 2022 +0800

    Add pre-commit hook to check session default value (#28007)
---
 .pre-commit-config.yaml                            |   6 +
 CONTRIBUTING.rst                                   |   7 +-
 STATIC_CODE_CHECKS.rst                             |   2 +
 airflow/api/client/api_client.py                   |   2 +-
 airflow/api/common/mark_tasks.py                   |   4 +-
 airflow/jobs/backfill_job.py                       |   8 +-
 airflow/jobs/base_job.py                           |   3 +-
 airflow/models/taskinstance.py                     |  12 +-
 airflow/models/xcom_arg.py                         |   1 +
 airflow/sentry.py                                  |   6 +-
 airflow/utils/db_cleanup.py                        |   2 +-
 airflow/www/extensions/init_appbuilder.py          |   6 +-
 airflow/www/security.py                            |   4 +-
 airflow/www/utils.py                               |   3 +-
 airflow/www/views.py                               |   2 +-
 dev/breeze/src/airflow_breeze/pre_commit_ids.py    |   1 +
 images/breeze/output-commands-hash.txt             |   2 +-
 images/breeze/output_static-checks.svg             | 114 ++++++++++---------
 .../pre_commit_new_session_in_provide_session.py   | 125 +++++++++++++++++++++
 19 files changed, 232 insertions(+), 78 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8b3f4c732d..1a67aaf66a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -447,6 +447,12 @@ repos:
         pass_filenames: true
         files: \.py$
         exclude: ^tests/|^airflow/_vendor/|^docs/
+      - id: check-only-new-session-with-provide-session
+        name: Check NEW_SESSION is only used with @provide_session
+        language: python
+        entry: 
./scripts/ci/pre_commit/pre_commit_new_session_in_provide_session.py
+        pass_filenames: true
+        files: ^airflow/.+\.py$
       - id: check-for-inclusive-language
         language: pygrep
         name: Check for language that we do not accept as community
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index a5e00305c1..96f491b4fc 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -938,13 +938,16 @@ To make this easier, there is the ``create_session`` 
helper:
     from airflow.utils.session import create_session
 
 
-    def my_call(*args, session: Session):
+    def my_call(x, y, *, session: Session):
         ...
         # You MUST not commit the session here.
 
 
     with create_session() as session:
-        my_call(*args, session=session)
+        my_call(x, y, session=session)
+
+.. warning::
+  **DO NOT** add a default to the ``session`` argument **unless** 
``@provide_session`` is used.
 
 If this function is designed to be called by "end-users" (i.e. DAG authors) 
then using the ``@provide_session`` wrapper is okay:
 
diff --git a/STATIC_CODE_CHECKS.rst b/STATIC_CODE_CHECKS.rst
index e6491f727b..b562443000 100644
--- a/STATIC_CODE_CHECKS.rst
+++ b/STATIC_CODE_CHECKS.rst
@@ -191,6 +191,8 @@ require Breeze Docker image to be build locally.
 
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
 | check-no-relative-imports                                 | No relative 
imports                                              |         |
 
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
+| check-only-new-session-with-provide-session               | Check 
NEW_SESSION is only used with @provide_session             |         |
++-----------------------------------------------------------+------------------------------------------------------------------+---------+
 | check-persist-credentials-disabled-in-github-workflows    | Check that 
workflow files have persist-credentials disabled      |         |
 
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
 | check-pre-commit-information-consistent                   | Update 
information re pre-commit hooks and verify ids and names  |         |
diff --git a/airflow/api/client/api_client.py b/airflow/api/client/api_client.py
index 8d1c26065b..222c0f142d 100644
--- a/airflow/api/client/api_client.py
+++ b/airflow/api/client/api_client.py
@@ -24,7 +24,7 @@ import httpx
 class Client:
     """Base API client for all API clients."""
 
-    def __init__(self, api_base_url, auth=None, session=None):
+    def __init__(self, api_base_url, auth=None, session: httpx.Client | None = 
None):
         self._api_base_url = api_base_url
         self._session: httpx.Client = session or httpx.Client()
         if auth:
diff --git a/airflow/api/common/mark_tasks.py b/airflow/api/common/mark_tasks.py
index 46b912790b..2b88589e9f 100644
--- a/airflow/api/common/mark_tasks.py
+++ b/airflow/api/common/mark_tasks.py
@@ -350,7 +350,7 @@ def get_run_ids(dag: DAG, run_id: str, future: bool, past: 
bool, session: SASess
     return run_ids
 
 
-def _set_dag_run_state(dag_id: str, run_id: str, state: DagRunState, session: 
SASession = NEW_SESSION):
+def _set_dag_run_state(dag_id: str, run_id: str, state: DagRunState, session: 
SASession):
     """
     Set dag run state in the DB.
 
@@ -500,7 +500,7 @@ def __set_dag_run_state_to_running_or_queued(
     execution_date: datetime | None = None,
     run_id: str | None = None,
     commit: bool = False,
-    session: SASession = NEW_SESSION,
+    session: SASession,
 ) -> list[TaskInstance]:
     """
     Set the dag run for a specific execution date to running.
diff --git a/airflow/jobs/backfill_job.py b/airflow/jobs/backfill_job.py
index f8f99422a2..3924d0867e 100644
--- a/airflow/jobs/backfill_job.py
+++ b/airflow/jobs/backfill_job.py
@@ -165,7 +165,7 @@ class BackfillJob(BaseJob):
         self.disable_retry = disable_retry
         super().__init__(*args, **kwargs)
 
-    def _update_counters(self, ti_status, session=None):
+    def _update_counters(self, ti_status, session):
         """
         Updates the counters per state of the tasks that were running.
 
@@ -407,14 +407,14 @@ class BackfillJob(BaseJob):
 
         self.log.debug("Finished dag run loop iteration. Remaining tasks %s", 
ti_status.to_run.values())
 
-    @provide_session
     def _process_backfill_task_instances(
         self,
         ti_status,
         executor,
         pickle_id,
         start_date=None,
-        session=None,
+        *,
+        session: Session,
     ) -> list:
         """
         Process a set of task instances from a set of DAG runs.
@@ -441,7 +441,7 @@ class BackfillJob(BaseJob):
             # or leaf to root, as otherwise tasks might be
             # determined deadlocked while they are actually
             # waiting for their upstream to finish
-            def _per_task_process(key, ti: TaskInstance, session=None):
+            def _per_task_process(key, ti: TaskInstance, session):
                 ti.refresh_from_db(lock_for_update=True, session=session)
 
                 task = self.dag.get_task(ti.task_id, include_subdags=True)
diff --git a/airflow/jobs/base_job.py b/airflow/jobs/base_job.py
index 673f035533..580b5a36ed 100644
--- a/airflow/jobs/base_job.py
+++ b/airflow/jobs/base_job.py
@@ -175,7 +175,8 @@ class BaseJob(Base, LoggingMixin):
     def on_kill(self):
         """Will be called when an external kill command is received."""
 
-    def heartbeat_callback(self, session=None):
+    @provide_session
+    def heartbeat_callback(self, session=None) -> None:
         """Callback that is called during heartbeat. This method should be 
overwritten."""
 
     def heartbeat(self, only_if_necessary: bool = False):
diff --git a/airflow/models/taskinstance.py b/airflow/models/taskinstance.py
index 945e6b00a8..62040b1a67 100644
--- a/airflow/models/taskinstance.py
+++ b/airflow/models/taskinstance.py
@@ -1852,7 +1852,9 @@ class TaskInstance(Base, LoggingMixin):
         return self.task.retries and self.try_number <= self.max_tries
 
     def get_template_context(
-        self, session: Session = NEW_SESSION, ignore_param_exceptions: bool = 
True
+        self,
+        session: Session | None = None,
+        ignore_param_exceptions: bool = True,
     ) -> Context:
         """Return TI Context"""
         # Do not use provide_session here -- it expunges everything on exit!
@@ -1976,9 +1978,13 @@ class TaskInstance(Base, LoggingMixin):
             return prev_ds.replace("-", "")
 
         def get_triggering_events() -> dict[str, list[DatasetEvent]]:
+            if TYPE_CHECKING:
+                assert session is not None
+
+            # The dag_run may not be attached to the session anymore since the
+            # code base is over-zealous with use of session.expunge_all().
+            # Re-attach it if we get called.
             nonlocal dag_run
-            # The dag_run may not be attached to the session anymore (code 
base is over-zealous with use of
-            # `session.expunge_all()`) so re-attach it if we get called
             if dag_run not in session:
                 dag_run = session.merge(dag_run, load=False)
 
diff --git a/airflow/models/xcom_arg.py b/airflow/models/xcom_arg.py
index d2b80474a9..133fd4280b 100644
--- a/airflow/models/xcom_arg.py
+++ b/airflow/models/xcom_arg.py
@@ -189,6 +189,7 @@ class XComArg(ResolveMixin, DependencyMixin):
         """
         raise NotImplementedError()
 
+    @provide_session
     def resolve(self, context: Context, session: Session = NEW_SESSION) -> Any:
         """Pull XCom value.
 
diff --git a/airflow/sentry.py b/airflow/sentry.py
index ed223fcccf..e76fe1db1b 100644
--- a/airflow/sentry.py
+++ b/airflow/sentry.py
@@ -20,11 +20,15 @@ from __future__ import annotations
 
 import logging
 from functools import wraps
+from typing import TYPE_CHECKING
 
 from airflow.configuration import conf
 from airflow.utils.session import find_session_idx, provide_session
 from airflow.utils.state import State
 
+if TYPE_CHECKING:
+    from sqlalchemy.orm import Session
+
 log = logging.getLogger(__name__)
 
 
@@ -36,7 +40,7 @@ class DummySentry:
         """Blank function for tagging."""
 
     @classmethod
-    def add_breadcrumbs(cls, task_instance, session=None):
+    def add_breadcrumbs(cls, task_instance, session: Session | None = None):
         """Blank function for breadcrumbs."""
 
     @classmethod
diff --git a/airflow/utils/db_cleanup.py b/airflow/utils/db_cleanup.py
index e03d1a28b0..51bfbb7963 100644
--- a/airflow/utils/db_cleanup.py
+++ b/airflow/utils/db_cleanup.py
@@ -245,7 +245,7 @@ def _cleanup_table(
     dry_run=True,
     verbose=False,
     skip_archive=False,
-    session=None,
+    session,
     **kwargs,
 ):
     print()
diff --git a/airflow/www/extensions/init_appbuilder.py 
b/airflow/www/extensions/init_appbuilder.py
index 0aa44e2dfe..acd12b319f 100644
--- a/airflow/www/extensions/init_appbuilder.py
+++ b/airflow/www/extensions/init_appbuilder.py
@@ -100,9 +100,9 @@ class AirflowAppBuilder:
     # Babel Manager Class
     bm = None
     # dict with addon name has key and intantiated class has value
-    addon_managers = None
+    addon_managers: dict
     # temporary list that hold addon_managers config key
-    _addon_managers = None
+    _addon_managers: list
 
     menu = None
     indexview = None
@@ -115,7 +115,7 @@ class AirflowAppBuilder:
     def __init__(
         self,
         app=None,
-        session=None,
+        session: Session | None = None,
         menu=None,
         indexview=None,
         base_template="airflow/main.html",
diff --git a/airflow/www/security.py b/airflow/www/security.py
index ce75970b14..bd4c34c9bd 100644
--- a/airflow/www/security.py
+++ b/airflow/www/security.py
@@ -22,7 +22,7 @@ from typing import Sequence
 
 from flask import g
 from sqlalchemy import or_
-from sqlalchemy.orm import joinedload
+from sqlalchemy.orm import Session, joinedload
 
 from airflow.exceptions import AirflowException, RemovedInAirflow3Warning
 from airflow.models import DagBag, DagModel
@@ -724,7 +724,7 @@ class AirflowSecurityManager(SecurityManager, LoggingMixin):
 class ApplessAirflowSecurityManager(AirflowSecurityManager):
     """Security Manager that doesn't need the whole flask app"""
 
-    def __init__(self, session=None):
+    def __init__(self, session: Session | None = None):
         self.session = session
 
     @property
diff --git a/airflow/www/utils.py b/airflow/www/utils.py
index 23c312bbdb..31e41d71ed 100644
--- a/airflow/www/utils.py
+++ b/airflow/www/utils.py
@@ -53,6 +53,7 @@ from airflow.www.widgets import AirflowDateTimePickerWidget
 
 if TYPE_CHECKING:
     from sqlalchemy.orm.query import Query
+    from sqlalchemy.orm.session import Session
     from sqlalchemy.sql.operators import ColumnOperators
 
 
@@ -713,7 +714,7 @@ class CustomSQLAInterface(SQLAInterface):
 
     """
 
-    def __init__(self, obj, session=None):
+    def __init__(self, obj, session: Session | None = None):
         super().__init__(obj, session=session)
 
         def clean_column_names():
diff --git a/airflow/www/views.py b/airflow/www/views.py
index baf806b5f5..549db3a291 100644
--- a/airflow/www/views.py
+++ b/airflow/www/views.py
@@ -2110,7 +2110,7 @@ class Airflow(AirflowBaseView):
         recursive: bool = False,
         confirmed: bool = False,
         only_failed: bool = False,
-        session: Session = NEW_SESSION,
+        session: Session,
     ):
         if confirmed:
             count = dag.clear(
diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py 
b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
index fc6a9c445f..32bd376e69 100644
--- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py
+++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
@@ -52,6 +52,7 @@ PRE_COMMIT_LIST = [
     "check-newsfragments-are-valid",
     "check-no-providers-in-core-examples",
     "check-no-relative-imports",
+    "check-only-new-session-with-provide-session",
     "check-persist-credentials-disabled-in-github-workflows",
     "check-pre-commit-information-consistent",
     "check-provide-create-sessions-imports",
diff --git a/images/breeze/output-commands-hash.txt 
b/images/breeze/output-commands-hash.txt
index 783e4d894e..c500e49fad 100644
--- a/images/breeze/output-commands-hash.txt
+++ b/images/breeze/output-commands-hash.txt
@@ -51,7 +51,7 @@ setup:version:123b462a421884dc2320ffc5e54b2478
 setup:fbabee281b69f818091d780b24bd815a
 shell:76e0f530b7af514a2aad3032b6516c46
 start-airflow:06d4aeb5f1b65f6b975f3f915558d0b3
-static-checks:f45ad432bdc47a2256fdb0277b19d816
+static-checks:6693433065e2091cd1508d8a23ed00fe
 stop:8969537ccdd799f692ccb8600a7bbed6
 testing:docker-compose-tests:b86c044b24138af0659a05ed6331576c
 testing:helm-tests:94a442e7f3f63b34c4831a84d165690a
diff --git a/images/breeze/output_static-checks.svg 
b/images/breeze/output_static-checks.svg
index 0418a91abd..b29ddcc784 100644
--- a/images/breeze/output_static-checks.svg
+++ b/images/breeze/output_static-checks.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1367.6" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 1392.0" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -35,15 +35,15 @@
     .breeze-static-checks-r1 { fill: #c5c8c6;font-weight: bold }
 .breeze-static-checks-r2 { fill: #c5c8c6 }
 .breeze-static-checks-r3 { fill: #d0b344;font-weight: bold }
-.breeze-static-checks-r4 { fill: #68a0b3;font-weight: bold }
-.breeze-static-checks-r5 { fill: #868887 }
+.breeze-static-checks-r4 { fill: #868887 }
+.breeze-static-checks-r5 { fill: #68a0b3;font-weight: bold }
 .breeze-static-checks-r6 { fill: #98a84b;font-weight: bold }
 .breeze-static-checks-r7 { fill: #8d7b39 }
     </style>
 
     <defs>
     <clipPath id="breeze-static-checks-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="1316.6" />
+      <rect x="0" y="0" width="1463.0" height="1341.0" />
     </clipPath>
     <clipPath id="breeze-static-checks-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -204,9 +204,12 @@
 <clipPath id="breeze-static-checks-line-52">
     <rect x="0" y="1270.3" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-static-checks-line-53">
+    <rect x="0" y="1294.7" 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="1365.6" rx="8"/><text 
class="breeze-static-checks-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;static-checks</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1390" rx="8"/><text 
class="breeze-static-checks-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;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"/>
@@ -217,59 +220,60 @@
     
     <g class="breeze-static-checks-matrix">
     <text class="breeze-static-checks-r2" x="1464" y="20" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-0)">
-</text><text class="breeze-static-checks-r3" x="12.2" y="44.4" 
textLength="85.4" 
clip-path="url(#breeze-static-checks-line-1)">Usage:&#160;</text><text 
class="breeze-static-checks-r1" x="97.6" y="44.4" textLength="268.4" 
clip-path="url(#breeze-static-checks-line-1)">breeze&#160;static-checks&#160;[</text><text
 class="breeze-static-checks-r4" x="366" y="44.4" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-1)">OPTIONS</text><text 
class="breeze-static-checks-r1" x="451.4" y="44 [...]
+</text><text class="breeze-static-checks-r3" x="12.2" y="44.4" 
textLength="85.4" 
clip-path="url(#breeze-static-checks-line-1)">Usage:&#160;</text><text 
class="breeze-static-checks-r1" x="97.6" y="44.4" textLength="610" 
clip-path="url(#breeze-static-checks-line-1)">breeze&#160;static-checks&#160;[OPTIONS]&#160;[PRECOMMIT_ARGS]...</text><text
 class="breeze-static-checks-r2" x="1464" y="44.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-1)">
 </text><text class="breeze-static-checks-r2" x="1464" y="68.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-2)">
 </text><text class="breeze-static-checks-r2" x="12.2" y="93.2" 
textLength="219.6" 
clip-path="url(#breeze-static-checks-line-3)">Run&#160;static&#160;checks.</text><text
 class="breeze-static-checks-r2" x="1464" y="93.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-3)">
 </text><text class="breeze-static-checks-r2" x="1464" y="117.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-4)">
-</text><text class="breeze-static-checks-r5" x="0" y="142" textLength="24.4" 
clip-path="url(#breeze-static-checks-line-5)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="142" textLength="219.6" 
clip-path="url(#breeze-static-checks-line-5)">&#160;Pre-commit&#160;flags&#160;</text><text
 class="breeze-static-checks-r5" x="244" y="142" textLength="1195.6" 
clip-path="url(#breeze-static-checks-line-5)">────────────────────────────────────────────────────────────────────────────────
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="166.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-6)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="166.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-6)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="166.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-6)">-type</text><text 
class="breeze-static-checks-r6" x="317.2" y="166.4" textLength="24.4" 
clip-path="url(#breeze- [...]
-</text><text class="breeze-static-checks-r5" x="0" y="190.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-7)">│</text><text 
class="breeze-static-checks-r7" x="366" y="190.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-7)">(all&#160;|&#160;black&#160;|&#160;blacken-docs&#160;|&#160;check-airflow-config-yaml-consistent&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="215.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-8)">│</text><text 
class="breeze-static-checks-r7" x="366" y="215.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-8)">check-airflow-provider-compatibility&#160;|&#160;check-apache-license-rat&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class= [...]
-</text><text class="breeze-static-checks-r5" x="0" y="239.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-9)">│</text><text 
class="breeze-static-checks-r7" x="366" y="239.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-9)">check-base-operator-partial-arguments&#160;|&#160;check-base-operator-usage&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-st [...]
-</text><text class="breeze-static-checks-r5" x="0" y="264" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-10)">│</text><text 
class="breeze-static-checks-r7" x="366" y="264" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-10)">check-boring-cyborg-configuration&#160;|&#160;check-breeze-top-dependencies-limited&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="264" textLen [...]
-</text><text class="breeze-static-checks-r5" x="0" y="288.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-11)">│</text><text 
class="breeze-static-checks-r7" x="366" y="288.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-11)">check-builtin-literals&#160;|&#160;check-changelog-has-no-duplicates&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="312.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-12)">│</text><text 
class="breeze-static-checks-r7" x="366" y="312.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-12)">check-core-deprecation-classes&#160;|&#160;check-daysago-import-from-utils&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="br [...]
-</text><text class="breeze-static-checks-r5" x="0" y="337.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-13)">│</text><text 
class="breeze-static-checks-r7" x="366" y="337.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-13)">check-decorated-operator-implements-custom-name&#160;|&#160;check-docstring-param-types&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="337.2" textLength="12.2" cli 
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="361.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-14)">│</text><text 
class="breeze-static-checks-r7" x="366" y="361.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-14)">check-example-dags-urls&#160;|&#160;check-executables-have-shebangs&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="386" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-15)">│</text><text 
class="breeze-static-checks-r7" x="366" y="386" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-15)">check-extra-packages-references&#160;|&#160;check-extras-order&#160;|&#160;check-for-inclusive-language&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="386" textLength="12.2" 
clip-path="url(#breeze-static [...]
-</text><text class="breeze-static-checks-r5" x="0" y="410.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-16)">│</text><text 
class="breeze-static-checks-r7" x="366" y="410.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-16)">check-hooks-apply&#160;|&#160;check-incorrect-use-of-LoggingMixin&#160;|&#160;check-init-decorator-arguments</text><text
 class="breeze-static-checks-r5" x="1451.8" y="410.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-1 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="434.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-17)">│</text><text 
class="breeze-static-checks-r7" x="366" y="434.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-17)">|&#160;check-lazy-logging&#160;|&#160;check-links-to-example-dags-do-not-use-hardcoded-versions&#160;|&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="434.8" textLength="12.2" 
clip-path="ur [...]
-</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="366" y="459.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-18)">check-merge-conflict&#160;|&#160;check-newsfragments-are-valid&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</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="366" y="483.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-19)">check-no-providers-in-core-examples&#160;|&#160;check-no-relative-imports&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 clas [...]
-</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="366" y="508" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-20)">check-persist-credentials-disabled-in-github-workflows&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</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="366" y="532.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-21)">check-pre-commit-information-consistent&#160;|&#160;check-provide-create-sessions-imports&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="532.4" textLength="12.2" 
clip-path="ur [...]
-</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="366" y="556.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-22)">check-provider-yaml-valid&#160;|&#160;check-providers-init-file-missing&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text>
 [...]
-</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="366" y="581.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-23)">check-providers-subpackages-init-file-exist&#160;|&#160;check-pydevd-left-in-code&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y [...]
-</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="366" y="605.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-24)">check-revision-heads-map&#160;|&#160;check-safe-filter-usage-in-html&#160;|&#160;check-setup-order&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="605.6" textLength="12.2 [...]
-</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="366" y="630" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-25)">check-start-date-not-used-in-defaults&#160;|&#160;check-system-tests-present&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-ch [...]
-</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="366" y="654.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-26)">check-system-tests-tocs&#160;|&#160;check-xml&#160;|&#160;codespell&#160;|&#160;compile-www-assets&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="br [...]
-</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="366" y="678.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-27)">compile-www-assets-dev&#160;|&#160;create-missing-init-py-files-tests&#160;|&#160;debug-statements&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="678.8" textLength="12.2 [...]
-</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="366" y="703.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-28)">detect-private-key&#160;|&#160;doctoc&#160;|&#160;end-of-file-fixer&#160;|&#160;fix-encoding-pragma&#160;|&#160;flynt&#160;|&#160;identity</text><text
 class="breeze-static-checks-r5" x="1451.8" y="703.2" textLength="12.2" 
clip-path="ur [...]
-</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="366" y="727.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-29)">|&#160;insert-license&#160;|&#160;isort&#160;|&#160;lint-chart-schema&#160;|&#160;lint-css&#160;|&#160;lint-dockerfile&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-stati [...]
-</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="366" y="752" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-30)">lint-helm-chart&#160;|&#160;lint-json-schema&#160;|&#160;lint-markdown&#160;|&#160;lint-openapi&#160;|&#160;mixed-line-ending&#160;|&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="752" textLength="12.2" 
clip-path="url(#bre [...]
-</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="366" y="776.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-31)">pretty-format-json&#160;|&#160;pydocstyle&#160;|&#160;python-no-log-warn&#160;|&#160;pyupgrade&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</
 [...]
-</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="366" y="800.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-32)">replace-bad-characters&#160;|&#160;rst-backticks&#160;|&#160;run-flake8&#160;|&#160;run-mypy&#160;|&#160;run-shellcheck&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="800.8" t [...]
-</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="366" y="825.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-33)">static-check-autoflake&#160;|&#160;trailing-whitespace&#160;|&#160;ts-compile-and-lint-javascript&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="825.2" textLength= [...]
-</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="366" y="849.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-34)">update-breeze-cmd-output&#160;|&#160;update-breeze-readme-config-hash&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
-</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="366" y="874" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-35)">update-common-sql-api-stubs&#160;|&#160;update-er-diagram&#160;|&#160;update-extras&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><tex
 [...]
-</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="366" y="898.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-36)">update-in-the-wild-to-be-sorted&#160;|&#160;update-inlined-dockerfile-scripts&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-che [...]
-</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="366" y="922.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-37)">update-local-yml-file&#160;|&#160;update-migration-references&#160;|&#160;update-providers-dependencies&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="922.8" textLength="12.2" 
clip-path="url(#breeze- [...]
-</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="366" y="947.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-38)">update-spelling-wordlist-to-be-sorted&#160;|&#160;update-supported-versions&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze- [...]
-</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="366" y="971.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-39)">update-vendored-in-k8s-json-schema&#160;|&#160;update-version&#160;|&#160;yamllint&#160;|&#160;yesqa)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-stati [...]
-</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-r4" x="24.4" y="996" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-40)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="996" textLength="61" 
clip-path="url(#breeze-static-checks-line-40)">-file</text><text 
class="breeze-static-checks-r6" x="317.2" y="996" textLength="24.4" 
clip-path="url(#breeze-stati [...]
-</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-r4" x="24.4" y="1020.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-41)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1020.4" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-41)">-all</text><text 
class="breeze-static-checks-r4" x="85.4" y="1020.4" textLength="73.2" 
clip-path="url(# [...]
-</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-r4" x="24.4" y="1044.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-42)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1044.8" textLength="61" 
clip-path="url(#breeze-static-checks-line-42)">-show</text><text 
class="breeze-static-checks-r4" x="97.6" y="1044.8" textLength="195.2" 
clip-path="url(# [...]
-</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-r4" x="24.4" y="1069.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-43)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1069.2" textLength="61" 
clip-path="url(#breeze-static-checks-line-43)">-last</text><text 
class="breeze-static-checks-r4" x="97.6" y="1069.2" textLength="85.4" 
clip-path="url(#b [...]
-</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-r4" x="24.4" y="1093.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-44)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1093.6" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-44)">-commit</text><text 
class="breeze-static-checks-r4" x="122" y="1093.6" textLength="48.8" 
clip-path="url [...]
-</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-r2" x="366" y="1118" textLength="292.8" 
clip-path="url(#breeze-static-checks-line-45)">Mutually&#160;exclusive&#160;with&#160;</text><text
 class="breeze-static-checks-r4" x="658.8" y="1118" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-45)">-</text><text 
class="breeze-static-checks-r4" x="671" y="1118" textLen [...]
-</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="366" y="1142.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-46)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160
 [...]
-</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-r4" x="24.4" y="1166.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-47)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1166.8" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-47)">-github</text><text 
class="breeze-static-checks-r4" x="122" y="1166.8" textLength="134.2" 
clip-path="ur [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1191.2" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-48)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r2" x="1464" y="1191.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-48)">
-</text><text class="breeze-static-checks-r5" x="0" y="1215.6" 
textLength="24.4" clip-path="url(#breeze-static-checks-line-49)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1215.6" textLength="195.2" 
clip-path="url(#breeze-static-checks-line-49)">&#160;Common&#160;options&#160;</text><text
 class="breeze-static-checks-r5" x="219.6" y="1215.6" textLength="1220" 
clip-path="url(#breeze-static-checks-line-49)">──────────────────────────────────────────────────────────────────────
 [...]
-</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-r4" x="24.4" y="1240" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-50)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1240" textLength="97.6" 
clip-path="url(#breeze-static-checks-line-50)">-verbose</text><text 
class="breeze-static-checks-r6" x="158.6" y="1240" textLength="24.4" 
clip-path="url(#bre [...]
-</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-r4" x="24.4" y="1264.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-51)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1264.4" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-51)">-dry</text><text 
class="breeze-static-checks-r4" x="85.4" y="1264.4" textLength="48.8" 
clip-path="url(# [...]
-</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-r4" x="24.4" y="1288.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-52)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1288.8" textLength="61" 
clip-path="url(#breeze-static-checks-line-52)">-help</text><text 
class="breeze-static-checks-r6" x="158.6" y="1288.8" textLength="24.4" 
clip-path="url(# [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1313.2" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-53)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r2" x="1464" y="1313.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-53)">
+</text><text class="breeze-static-checks-r4" x="0" y="142" textLength="24.4" 
clip-path="url(#breeze-static-checks-line-5)">╭─</text><text 
class="breeze-static-checks-r4" x="24.4" y="142" textLength="219.6" 
clip-path="url(#breeze-static-checks-line-5)">&#160;Pre-commit&#160;flags&#160;</text><text
 class="breeze-static-checks-r4" x="244" y="142" textLength="1195.6" 
clip-path="url(#breeze-static-checks-line-5)">────────────────────────────────────────────────────────────────────────────────
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="166.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-6)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="166.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-6)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="166.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-6)">-type</text><text 
class="breeze-static-checks-r6" x="317.2" y="166.4" textLength="24.4" 
clip-path="url(#breeze- [...]
+</text><text class="breeze-static-checks-r4" x="0" y="190.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-7)">│</text><text 
class="breeze-static-checks-r7" x="366" y="190.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-7)">(all&#160;|&#160;black&#160;|&#160;blacken-docs&#160;|&#160;check-airflow-config-yaml-consistent&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 c [...]
+</text><text class="breeze-static-checks-r4" x="0" y="215.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-8)">│</text><text 
class="breeze-static-checks-r7" x="366" y="215.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-8)">check-airflow-provider-compatibility&#160;|&#160;check-apache-license-rat&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class= [...]
+</text><text class="breeze-static-checks-r4" x="0" y="239.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-9)">│</text><text 
class="breeze-static-checks-r7" x="366" y="239.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-9)">check-base-operator-partial-arguments&#160;|&#160;check-base-operator-usage&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-st [...]
+</text><text class="breeze-static-checks-r4" x="0" y="264" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-10)">│</text><text 
class="breeze-static-checks-r7" x="366" y="264" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-10)">check-boring-cyborg-configuration&#160;|&#160;check-breeze-top-dependencies-limited&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="264" textLen [...]
+</text><text class="breeze-static-checks-r4" x="0" y="288.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-11)">│</text><text 
class="breeze-static-checks-r7" x="366" y="288.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-11)">check-builtin-literals&#160;|&#160;check-changelog-has-no-duplicates&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="312.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-12)">│</text><text 
class="breeze-static-checks-r7" x="366" y="312.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-12)">check-core-deprecation-classes&#160;|&#160;check-daysago-import-from-utils&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="br [...]
+</text><text class="breeze-static-checks-r4" x="0" y="337.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-13)">│</text><text 
class="breeze-static-checks-r7" x="366" y="337.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-13)">check-decorated-operator-implements-custom-name&#160;|&#160;check-docstring-param-types&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="337.2" textLength="12.2" cli 
[...]
+</text><text class="breeze-static-checks-r4" x="0" y="361.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-14)">│</text><text 
class="breeze-static-checks-r7" x="366" y="361.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-14)">check-example-dags-urls&#160;|&#160;check-executables-have-shebangs&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="386" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-15)">│</text><text 
class="breeze-static-checks-r7" x="366" y="386" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-15)">check-extra-packages-references&#160;|&#160;check-extras-order&#160;|&#160;check-for-inclusive-language&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="386" textLength="12.2" 
clip-path="url(#breeze-static [...]
+</text><text class="breeze-static-checks-r4" x="0" y="410.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-16)">│</text><text 
class="breeze-static-checks-r7" x="366" y="410.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-16)">check-hooks-apply&#160;|&#160;check-incorrect-use-of-LoggingMixin&#160;|&#160;check-init-decorator-arguments</text><text
 class="breeze-static-checks-r4" x="1451.8" y="410.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-1 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="434.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-17)">│</text><text 
class="breeze-static-checks-r7" x="366" y="434.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-17)">|&#160;check-lazy-logging&#160;|&#160;check-links-to-example-dags-do-not-use-hardcoded-versions&#160;|&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="434.8" textLength="12.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r4" x="0" y="459.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-18)">│</text><text 
class="breeze-static-checks-r7" x="366" y="459.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-18)">check-merge-conflict&#160;|&#160;check-newsfragments-are-valid&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="483.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-19)">│</text><text 
class="breeze-static-checks-r7" x="366" y="483.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-19)">check-no-providers-in-core-examples&#160;|&#160;check-no-relative-imports&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 clas [...]
+</text><text class="breeze-static-checks-r4" x="0" y="508" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-20)">│</text><text 
class="breeze-static-checks-r7" x="366" y="508" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-20)">check-only-new-session-with-provide-session&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="532.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-21)">│</text><text 
class="breeze-static-checks-r7" x="366" y="532.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-21)">check-persist-credentials-disabled-in-github-workflows&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="556.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-22)">│</text><text 
class="breeze-static-checks-r7" x="366" y="556.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-22)">check-pre-commit-information-consistent&#160;|&#160;check-provide-create-sessions-imports&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="556.8" textLength="12.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r4" x="0" y="581.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-23)">│</text><text 
class="breeze-static-checks-r7" x="366" y="581.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-23)">check-provider-yaml-valid&#160;|&#160;check-providers-init-file-missing&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text>
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="605.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-24)">│</text><text 
class="breeze-static-checks-r7" x="366" y="605.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-24)">check-providers-subpackages-init-file-exist&#160;|&#160;check-pydevd-left-in-code&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y [...]
+</text><text class="breeze-static-checks-r4" x="0" y="630" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-25)">│</text><text 
class="breeze-static-checks-r7" x="366" y="630" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-25)">check-revision-heads-map&#160;|&#160;check-safe-filter-usage-in-html&#160;|&#160;check-setup-order&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="630" textLength="12.2" clip [...]
+</text><text class="breeze-static-checks-r4" x="0" y="654.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-26)">│</text><text 
class="breeze-static-checks-r7" x="366" y="654.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-26)">check-start-date-not-used-in-defaults&#160;|&#160;check-system-tests-present&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-stati [...]
+</text><text class="breeze-static-checks-r4" x="0" y="678.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-27)">│</text><text 
class="breeze-static-checks-r7" x="366" y="678.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-27)">check-system-tests-tocs&#160;|&#160;check-xml&#160;|&#160;codespell&#160;|&#160;compile-www-assets&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="br [...]
+</text><text class="breeze-static-checks-r4" x="0" y="703.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-28)">│</text><text 
class="breeze-static-checks-r7" x="366" y="703.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-28)">compile-www-assets-dev&#160;|&#160;create-missing-init-py-files-tests&#160;|&#160;debug-statements&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="703.2" textLength="12.2 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="727.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-29)">│</text><text 
class="breeze-static-checks-r7" x="366" y="727.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-29)">detect-private-key&#160;|&#160;doctoc&#160;|&#160;end-of-file-fixer&#160;|&#160;fix-encoding-pragma&#160;|&#160;flynt&#160;|&#160;identity</text><text
 class="breeze-static-checks-r4" x="1451.8" y="727.6" textLength="12.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r4" x="0" y="752" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-30)">│</text><text 
class="breeze-static-checks-r7" x="366" y="752" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-30)">|&#160;insert-license&#160;|&#160;isort&#160;|&#160;lint-chart-schema&#160;|&#160;lint-css&#160;|&#160;lint-dockerfile&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-ch [...]
+</text><text class="breeze-static-checks-r4" x="0" y="776.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-31)">│</text><text 
class="breeze-static-checks-r7" x="366" y="776.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-31)">lint-helm-chart&#160;|&#160;lint-json-schema&#160;|&#160;lint-markdown&#160;|&#160;lint-openapi&#160;|&#160;mixed-line-ending&#160;|&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="776.4" textLength="12.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r4" x="0" y="800.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-32)">│</text><text 
class="breeze-static-checks-r7" x="366" y="800.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-32)">pretty-format-json&#160;|&#160;pydocstyle&#160;|&#160;python-no-log-warn&#160;|&#160;pyupgrade&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="825.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-33)">│</text><text 
class="breeze-static-checks-r7" x="366" y="825.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-33)">replace-bad-characters&#160;|&#160;rst-backticks&#160;|&#160;run-flake8&#160;|&#160;run-mypy&#160;|&#160;run-shellcheck&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="825.2" t [...]
+</text><text class="breeze-static-checks-r4" x="0" y="849.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-34)">│</text><text 
class="breeze-static-checks-r7" x="366" y="849.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-34)">static-check-autoflake&#160;|&#160;trailing-whitespace&#160;|&#160;ts-compile-and-lint-javascript&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="849.6" textLength= [...]
+</text><text class="breeze-static-checks-r4" x="0" y="874" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-35)">│</text><text 
class="breeze-static-checks-r7" x="366" y="874" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-35)">update-breeze-cmd-output&#160;|&#160;update-breeze-readme-config-hash&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="898.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-36)">│</text><text 
class="breeze-static-checks-r7" x="366" y="898.4" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-36)">update-common-sql-api-stubs&#160;|&#160;update-er-diagram&#160;|&#160;update-extras&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text>
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="922.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-37)">│</text><text 
class="breeze-static-checks-r7" x="366" y="922.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-37)">update-in-the-wild-to-be-sorted&#160;|&#160;update-inlined-dockerfile-scripts&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-che [...]
+</text><text class="breeze-static-checks-r4" x="0" y="947.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-38)">│</text><text 
class="breeze-static-checks-r7" x="366" y="947.2" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-38)">update-local-yml-file&#160;|&#160;update-migration-references&#160;|&#160;update-providers-dependencies&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r4" x="1451.8" y="947.2" textLength="12.2" 
clip-path="url(#breeze- [...]
+</text><text class="breeze-static-checks-r4" x="0" y="971.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-39)">│</text><text 
class="breeze-static-checks-r7" x="366" y="971.6" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-39)">update-spelling-wordlist-to-be-sorted&#160;|&#160;update-supported-versions&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze- [...]
+</text><text class="breeze-static-checks-r4" x="0" y="996" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-40)">│</text><text 
class="breeze-static-checks-r7" x="366" y="996" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-40)">update-vendored-in-k8s-json-schema&#160;|&#160;update-version&#160;|&#160;yamllint&#160;|&#160;yesqa)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-ch [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1020.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-41)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1020.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-41)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1020.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-41)">-file</text><text 
class="breeze-static-checks-r6" x="317.2" y="1020.4" textLength="24.4" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1044.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-42)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1044.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-42)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1044.8" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-42)">-all</text><text 
class="breeze-static-checks-r5" x="85.4" y="1044.8" textLength="73.2" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1069.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-43)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1069.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-43)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1069.2" textLength="61" 
clip-path="url(#breeze-static-checks-line-43)">-show</text><text 
class="breeze-static-checks-r5" x="97.6" y="1069.2" textLength="195.2" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1093.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-44)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1093.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-44)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1093.6" textLength="61" 
clip-path="url(#breeze-static-checks-line-44)">-last</text><text 
class="breeze-static-checks-r5" x="97.6" y="1093.6" textLength="85.4" 
clip-path="url(#b [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1118" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-45)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1118" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-45)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1118" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-45)">-commit</text><text 
class="breeze-static-checks-r5" x="122" y="1118" textLength="48.8" 
clip-path="url(#breeze [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1142.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-46)">│</text><text 
class="breeze-static-checks-r2" x="366" y="1142.4" textLength="292.8" 
clip-path="url(#breeze-static-checks-line-46)">Mutually&#160;exclusive&#160;with&#160;</text><text
 class="breeze-static-checks-r5" x="658.8" y="1142.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-46)">-</text><text 
class="breeze-static-checks-r5" x="671" y="1142.4" [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1166.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-47)">│</text><text 
class="breeze-static-checks-r7" x="366" y="1166.8" textLength="1073.6" 
clip-path="url(#breeze-static-checks-line-47)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1191.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-48)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1191.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-48)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1191.2" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-48)">-github</text><text 
class="breeze-static-checks-r5" x="122" y="1191.2" textLength="134.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1215.6" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-49)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r2" x="1464" y="1215.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-49)">
+</text><text class="breeze-static-checks-r4" x="0" y="1240" textLength="24.4" 
clip-path="url(#breeze-static-checks-line-50)">╭─</text><text 
class="breeze-static-checks-r4" x="24.4" y="1240" textLength="195.2" 
clip-path="url(#breeze-static-checks-line-50)">&#160;Common&#160;options&#160;</text><text
 class="breeze-static-checks-r4" x="219.6" y="1240" textLength="1220" 
clip-path="url(#breeze-static-checks-line-50)">────────────────────────────────────────────────────────────────────────────
 [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1264.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-51)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1264.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-51)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1264.4" textLength="97.6" 
clip-path="url(#breeze-static-checks-line-51)">-verbose</text><text 
class="breeze-static-checks-r6" x="158.6" y="1264.4" textLength="24.4" 
clip-path=" [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1288.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-52)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1288.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-52)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1288.8" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-52)">-dry</text><text 
class="breeze-static-checks-r5" x="85.4" y="1288.8" textLength="48.8" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1313.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-53)">│</text><text 
class="breeze-static-checks-r5" x="24.4" y="1313.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-53)">-</text><text 
class="breeze-static-checks-r5" x="36.6" y="1313.2" textLength="61" 
clip-path="url(#breeze-static-checks-line-53)">-help</text><text 
class="breeze-static-checks-r6" x="158.6" y="1313.2" textLength="24.4" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r4" x="0" y="1337.6" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-54)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r2" x="1464" y="1337.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-54)">
 </text>
     </g>
     </g>
diff --git a/scripts/ci/pre_commit/pre_commit_new_session_in_provide_session.py 
b/scripts/ci/pre_commit/pre_commit_new_session_in_provide_session.py
new file mode 100755
index 0000000000..47b782fe12
--- /dev/null
+++ b/scripts/ci/pre_commit/pre_commit_new_session_in_provide_session.py
@@ -0,0 +1,125 @@
+#!/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 ast
+import enum
+import itertools
+import pathlib
+import sys
+import typing
+
+
+class _SessionArgument(typing.NamedTuple):
+    argument: ast.arg
+    default: ast.expr | None
+
+
+def _get_session_arg_and_default(args: ast.arguments) -> _SessionArgument | 
None:
+    arguments = reversed([*args.args, *args.kwonlyargs])
+    defaults = reversed([*args.defaults, *args.kw_defaults])
+    for argument, default in itertools.zip_longest(arguments, defaults, 
fillvalue=None):
+        if argument is None:
+            continue  # Impossible since a function can't have more defaults 
than arguments.
+        if argument.arg != "session":
+            continue
+        return _SessionArgument(argument, default)
+    return None
+
+
+class _SessionDefault(enum.Enum):
+    none = "none"
+    new_session = "new_session"
+
+
+def _is_new_session_or_none(value: ast.expr) -> _SessionDefault | None:
+    """Whether an expression is NEW_SESSION.
+
+    Old code written before the introduction of NEW_SESSION (and even some new
+    if the contributor wasn't made aware of the addition) generally uses None
+    as the default value, so we add that to the check as well.
+    """
+    if isinstance(value, ast.Constant) and value.value is None:
+        return _SessionDefault.none
+    if isinstance(value, ast.Name) and value.id == "NEW_SESSION":
+        return _SessionDefault.new_session
+    # It's possible to do FOO = NEW_SESSION and reference FOO to work around
+    # this check, but let's rely on reviewers to catch this kind of 
shenanigans.
+    return None
+
+
+_ALLOWED_DECORATOR_NAMES = ("overload", "provide_session", "abstractmethod")
+
+
+def _is_decorated_correctly(nodes: list[ast.expr]) -> bool:
+    """Whether expected decorators are provided.
+
+    Three decorators would allow NEW_SESSION usages:
+
+    * ``@provide_session``: The canonical case.
+    * ``@overload``: A typing overload and not something to actually execute.
+    * ``@abstractmethod``: This will be overridden in a subclass anyway.
+    """
+    # This only accepts those decorators literally. Should be enough?
+    return any(isinstance(node, ast.Name) and node.id in 
_ALLOWED_DECORATOR_NAMES for node in nodes)
+
+
+def _annotation_has_none(value: ast.expr | None) -> bool:
+    if value is None:
+        return False
+    if isinstance(value, ast.Constant) and value.value is None:
+        return True
+    if isinstance(value, ast.BinOp) and isinstance(value.op, ast.BitOr):  # 
Type union.
+        return _annotation_has_none(value.left) or 
_annotation_has_none(value.right)
+    return False
+
+
+def _iter_incorrect_new_session_usages(path: pathlib.Path) -> 
typing.Iterator[ast.FunctionDef]:
+    """Check NEW_SESSION usages outside functions decorated with 
provide_session."""
+    for node in ast.walk(ast.parse(path.read_text("utf-8"), str(path))):
+        if not isinstance(node, ast.FunctionDef):
+            continue
+        session = _get_session_arg_and_default(node.args)
+        if session is None or session.default is None:
+            continue  # No session argument or the argument has no default, 
we're good.
+        if _is_decorated_correctly(node.decorator_list):
+            continue  # Has @provide_session so the default is expected.
+        default_kind = _is_new_session_or_none(session.default)
+        if default_kind is None:
+            continue  # Default value is not NEW_SESSION or None.
+        if default_kind == _SessionDefault.none and 
_annotation_has_none(session.argument.annotation):
+            continue  # None is OK if the argument is explicitly typed as None.
+        yield node
+
+
+def main(argv: list[str]) -> int:
+    paths = (pathlib.Path(filename) for filename in argv[1:])
+    errors = [(path, error) for path in paths for error in 
_iter_incorrect_new_session_usages(path)]
+    if errors:
+        print("Incorrect @provide_session and NEW_SESSION usages:", end="\n\n")
+        for path, error in errors:
+            print(f"{path}:{error.lineno}")
+            print(f"\tdef {error.name}(...", end="\n\n")
+        print("Only function decorated with @provide_session should use 
'session: Session = NEW_SESSION'.")
+        print("See: 
https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#database-session-handling";)
+    return len(errors)
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))

Reply via email to