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

jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 7bd8ea68215 Cleanup leftovers from api connexion (#47490)
7bd8ea68215 is described below

commit 7bd8ea68215a107d8b31a00b5d4e3d6054c581dc
Author: Jens Scheffler <[email protected]>
AuthorDate: Fri Mar 7 20:44:52 2025 +0100

    Cleanup leftovers from api connexion (#47490)
    
    * Cleanup leftovers frmo API Connexion
    
    * Cleanup leftovers frmo API Connexion, wipe all leftovers
    
    * Fix selective checks
    
    * Add missing dependecy of connexion to FAB provider
    
    * Clean another CODEOWNER leftover
    
    * Revert exceptions about project tests missing
---
 .github/CODEOWNERS                                 |  2 -
 LICENSE                                            |  1 -
 airflow/api_connexion/__init__.py                  | 16 ----
 airflow/api_connexion/schemas/__init__.py          | 16 ----
 airflow/api_connexion/schemas/dag_schema.py        | 86 ----------------------
 .../cli/commands/remote_commands/dag_command.py    | 78 ++++++++++++++++++--
 airflow/config_templates/config.yml                |  2 +-
 contributing-docs/testing/unit_tests.rst           |  2 +-
 dev/README_RELEASE_AIRFLOW.md                      |  6 +-
 dev/README_RELEASE_PYTHON_CLIENT.md                |  2 +-
 dev/airflow-github                                 |  2 +-
 .../src/airflow_breeze/utils/selective_checks.py   | 32 --------
 dev/breeze/tests/test_selective_checks.py          |  4 -
 generated/dep_tree.txt                             | 49 ------------
 generated/dependency_depth.json                    |  1 -
 generated/provider_dependencies.json               |  1 +
 hatch_build.py                                     | 11 +--
 providers/fab/README.rst                           |  1 +
 providers/fab/pyproject.toml                       |  1 +
 .../src/airflow/providers/fab/get_provider_info.py |  1 +
 pyproject.toml                                     |  6 --
 .../ci/pre_commit/check_tests_in_right_folders.py  |  1 -
 scripts/cov/restapi_coverage.py                    | 11 +--
 .../commands/remote_commands/test_dag_command.py   |  5 +-
 24 files changed, 88 insertions(+), 249 deletions(-)

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2bd3181c08f..df42a71b9b7 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -29,9 +29,7 @@
 /airflow/ui/ @bbovenzi @pierrejeambrun @ryanahamilton @jscheffl
 
 # Security/Permissions
-/airflow/api_connexion/security.py @vincbeck
 /airflow/security/permissions.py @vincbeck
-/airflow/www/security.py @vincbeck
 
 # Calendar/Timetables
 /airflow/timetables/ @uranusjr
diff --git a/LICENSE b/LICENSE
index 405dcfe69d7..25c727ac6e9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -220,7 +220,6 @@ at 3rd-party-licenses/LICENSE-[project].txt.
     (ALv2 License) hue v4.3.0 (https://github.com/cloudera/hue/)
     (ALv2 License) jqclock v2.3.0 
(https://github.com/JohnRDOrazio/jQuery-Clock-Plugin)
     (ALv2 License) bootstrap3-typeahead v4.0.2 
(https://github.com/bassjobsen/Bootstrap-3-Typeahead)
-    (ALv2 License) connexion v2.7.0 (https://github.com/zalando/connexion)
 
 ========================================================================
 MIT licenses
diff --git a/airflow/api_connexion/__init__.py 
b/airflow/api_connexion/__init__.py
deleted file mode 100644
index 13a83393a91..00000000000
--- a/airflow/api_connexion/__init__.py
+++ /dev/null
@@ -1,16 +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.
diff --git a/airflow/api_connexion/schemas/__init__.py 
b/airflow/api_connexion/schemas/__init__.py
deleted file mode 100644
index 13a83393a91..00000000000
--- a/airflow/api_connexion/schemas/__init__.py
+++ /dev/null
@@ -1,16 +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.
diff --git a/airflow/api_connexion/schemas/dag_schema.py 
b/airflow/api_connexion/schemas/dag_schema.py
deleted file mode 100644
index a164dec6f7e..00000000000
--- a/airflow/api_connexion/schemas/dag_schema.py
+++ /dev/null
@@ -1,86 +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 itsdangerous import URLSafeSerializer
-from marshmallow import fields
-from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field
-
-from airflow.configuration import conf
-from airflow.models.dag import DagModel, DagTag
-
-
-class DagTagSchema(SQLAlchemySchema):
-    """Dag Tag schema."""
-
-    class Meta:
-        """Meta."""
-
-        model = DagTag
-
-    name = auto_field()
-
-
-class DAGSchema(SQLAlchemySchema):
-    """DAG schema."""
-
-    class Meta:
-        """Meta."""
-
-        model = DagModel
-
-    dag_id = auto_field(dump_only=True)
-    dag_display_name = fields.String(attribute="dag_display_name", 
dump_only=True)
-    bundle_name = auto_field(dump_only=True)
-    bundle_version = auto_field(dump_only=True)
-    is_paused = auto_field()
-    is_active = auto_field(dump_only=True)
-    last_parsed_time = auto_field(dump_only=True)
-    last_expired = auto_field(dump_only=True)
-    default_view = auto_field(dump_only=True)
-    fileloc = auto_field(dump_only=True)
-    file_token = fields.Method("get_token", dump_only=True)
-    owners = fields.Method("get_owners", dump_only=True)
-    description = auto_field(dump_only=True)
-    timetable_summary = auto_field(dump_only=True)
-    timetable_description = auto_field(dump_only=True)
-    tags = fields.List(fields.Nested(DagTagSchema), dump_only=True)
-    max_active_tasks = auto_field(dump_only=True)
-    max_active_runs = auto_field(dump_only=True)
-    max_consecutive_failed_dag_runs = auto_field(dump_only=True)
-    has_task_concurrency_limits = auto_field(dump_only=True)
-    has_import_errors = auto_field(dump_only=True)
-    next_dagrun = auto_field(dump_only=True)
-    next_dagrun_data_interval_start = auto_field(dump_only=True)
-    next_dagrun_data_interval_end = auto_field(dump_only=True)
-    next_dagrun_create_after = auto_field(dump_only=True)
-
-    @staticmethod
-    def get_owners(obj: DagModel):
-        """Convert owners attribute to DAG representation."""
-        if not getattr(obj, "owners", None):
-            return []
-        return obj.owners.split(",")
-
-    @staticmethod
-    def get_token(obj: DagModel):
-        """Return file token."""
-        serializer = URLSafeSerializer(conf.get_mandatory_value("webserver", 
"secret_key"))
-        return serializer.dumps(obj.fileloc)
-
-
-dag_schema = DAGSchema()
diff --git a/airflow/cli/commands/remote_commands/dag_command.py 
b/airflow/cli/commands/remote_commands/dag_command.py
index a2ec030a09f..7f36217a27c 100644
--- a/airflow/cli/commands/remote_commands/dag_command.py
+++ b/airflow/cli/commands/remote_commands/dag_command.py
@@ -29,16 +29,19 @@ import subprocess
 import sys
 from typing import TYPE_CHECKING
 
+from itsdangerous import URLSafeSerializer
+from marshmallow import fields
+from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field
 from sqlalchemy import func, select
 
 from airflow.api.client import get_current_api_client
-from airflow.api_connexion.schemas.dag_schema import dag_schema
 from airflow.cli.simple_table import AirflowConsole
 from airflow.cli.utils import fetch_dag_run_from_run_id_or_logical_date_string
+from airflow.configuration import conf
 from airflow.dag_processing.bundles.manager import DagBundlesManager
 from airflow.exceptions import AirflowException
 from airflow.jobs.job import Job
-from airflow.models import DagBag, DagModel, DagRun, TaskInstance
+from airflow.models import DagBag, DagModel, DagRun, DagTag, TaskInstance
 from airflow.models.errors import ParseImportError
 from airflow.models.serialized_dag import SerializedDagModel
 from airflow.sdk.definitions._internal.dag_parsing_context import 
_airflow_parsing_context_manager
@@ -59,6 +62,66 @@ if TYPE_CHECKING:
 log = logging.getLogger(__name__)
 
 
+# TODO: To clean up api_connexion, we need to move the below 2 classes to this 
file until migrated to FastAPI
+class DagTagSchema(SQLAlchemySchema):
+    """Dag Tag schema."""
+
+    class Meta:
+        """Meta."""
+
+        model = DagTag
+
+    name = auto_field()
+
+
+class DAGSchema(SQLAlchemySchema):
+    """DAG schema."""
+
+    class Meta:
+        """Meta."""
+
+        model = DagModel
+
+    dag_id = auto_field(dump_only=True)
+    dag_display_name = fields.String(attribute="dag_display_name", 
dump_only=True)
+    bundle_name = auto_field(dump_only=True)
+    bundle_version = auto_field(dump_only=True)
+    is_paused = auto_field()
+    is_active = auto_field(dump_only=True)
+    last_parsed_time = auto_field(dump_only=True)
+    last_expired = auto_field(dump_only=True)
+    default_view = auto_field(dump_only=True)
+    fileloc = auto_field(dump_only=True)
+    file_token = fields.Method("get_token", dump_only=True)
+    owners = fields.Method("get_owners", dump_only=True)
+    description = auto_field(dump_only=True)
+    timetable_summary = auto_field(dump_only=True)
+    timetable_description = auto_field(dump_only=True)
+    tags = fields.List(fields.Nested(DagTagSchema), dump_only=True)
+    max_active_tasks = auto_field(dump_only=True)
+    max_active_runs = auto_field(dump_only=True)
+    max_consecutive_failed_dag_runs = auto_field(dump_only=True)
+    has_task_concurrency_limits = auto_field(dump_only=True)
+    has_import_errors = auto_field(dump_only=True)
+    next_dagrun = auto_field(dump_only=True)
+    next_dagrun_data_interval_start = auto_field(dump_only=True)
+    next_dagrun_data_interval_end = auto_field(dump_only=True)
+    next_dagrun_create_after = auto_field(dump_only=True)
+
+    @staticmethod
+    def get_owners(obj: DagModel):
+        """Convert owners attribute to DAG representation."""
+        if not getattr(obj, "owners", None):
+            return []
+        return obj.owners.split(",")
+
+    @staticmethod
+    def get_token(obj: DagModel):
+        """Return file token."""
+        serializer = URLSafeSerializer(conf.get_mandatory_value("webserver", 
"secret_key"))
+        return serializer.dumps(obj.fileloc)
+
+
 @cli_utils.action_cli
 @providers_configuration_loaded
 def dag_trigger(args) -> None:
@@ -329,15 +392,16 @@ def dag_next_execution(args) -> None:
 def dag_list_dags(args, session: Session = NEW_SESSION) -> None:
     """Display dags with or without stats at the command line."""
     cols = args.columns if args.columns else []
-    invalid_cols = [c for c in cols if c not in dag_schema.fields]
-    valid_cols = [c for c in cols if c in dag_schema.fields]
+    dag_schema_fields = DAGSchema().fields
+    invalid_cols = [c for c in cols if c not in dag_schema_fields]
+    valid_cols = [c for c in cols if c in dag_schema_fields]
 
     if invalid_cols:
         from rich import print as rich_print
 
         rich_print(
             f"[red][bold]Error:[/bold] Ignoring the following invalid columns: 
{invalid_cols}.  "
-            f"List of valid columns: {list(dag_schema.fields.keys())}",
+            f"List of valid columns: {list(dag_schema_fields.keys())}",
             file=sys.stderr,
         )
 
@@ -363,7 +427,7 @@ def dag_list_dags(args, session: Session = NEW_SESSION) -> 
None:
     def get_dag_detail(dag: DAG) -> dict:
         dag_model = DagModel.get_dagmodel(dag.dag_id, session=session)
         if dag_model:
-            dag_detail = dag_schema.dump(dag_model)
+            dag_detail = DAGSchema().dump(dag_model)
         else:
             dag_detail = _get_dagbag_dag_details(dag)
         return {col: dag_detail[col] for col in valid_cols}
@@ -395,7 +459,7 @@ def dag_details(args, session: Session = NEW_SESSION):
     dag = DagModel.get_dagmodel(args.dag_id, session=session)
     if not dag:
         raise SystemExit(f"DAG: {args.dag_id} does not exist in 'dag' table")
-    dag_detail = dag_schema.dump(dag)
+    dag_detail = DAGSchema().dump(dag)
 
     if args.output in ["table", "plain"]:
         data = [{"property_name": key, "property_value": value} for key, value 
in dag_detail.items()]
diff --git a/airflow/config_templates/config.yml 
b/airflow/config_templates/config.yml
index d70e244b180..f4691a67949 100644
--- a/airflow/config_templates/config.yml
+++ b/airflow/config_templates/config.yml
@@ -924,7 +924,7 @@ logging:
         consoles\.
       version_added: 2.0.0
       type: string
-      example: "connexion,sqlalchemy"
+      example: "fastapi,sqlalchemy"
       default: ""
     worker_log_server_port:
       description: |
diff --git a/contributing-docs/testing/unit_tests.rst 
b/contributing-docs/testing/unit_tests.rst
index f34002886b4..73ed4d58558 100644
--- a/contributing-docs/testing/unit_tests.rst
+++ b/contributing-docs/testing/unit_tests.rst
@@ -95,7 +95,7 @@ test types you want to use in various ``breeze testing`` 
sub-commands in three w
 Those test types are defined:
 
 * ``Always`` - those are tests that should be always executed (always 
sub-folder)
-* ``API`` - Tests for the Airflow API (api, api_connexion, api_internal, 
api_fastapi sub-folders)
+* ``API`` - Tests for the Airflow API (api, api_internal, api_fastapi 
sub-folders)
 * ``CLI`` - Tests for the Airflow CLI (cli folder)
 * ``Core`` - for the core Airflow functionality (core, executors, jobs, 
models, ti_deps, utils sub-folders)
 * ``Operators`` - tests for the operators (operators folder)
diff --git a/dev/README_RELEASE_AIRFLOW.md b/dev/README_RELEASE_AIRFLOW.md
index 43140b1dd34..35549a55b43 100644
--- a/dev/README_RELEASE_AIRFLOW.md
+++ b/dev/README_RELEASE_AIRFLOW.md
@@ -261,7 +261,7 @@ pipx install -e ./dev/breeze
     git reset --hard origin/v${VERSION_BRANCH}-test
     ```
 
-- Set your version in `airflow/__init__.py`, 
`airflow/api_connexion/openapi/v1.yaml` (without the RC tag).
+- Set your version in `airflow/__init__.py` (without the RC tag).
 - Run `git commit` without a message to update versions in `docs`.
 - Add supported Airflow version to 
`./scripts/ci/pre_commit/supported_versions.py` and let pre-commit do the job 
again.
 - Replace the versions in `README.md` about installation and verify that 
installation instructions work fine.
@@ -1039,7 +1039,7 @@ EOF
 This includes:
 
 - Modify `./scripts/ci/pre_commit/supported_versions.py` and let pre-commit do 
the job.
-- For major/minor release, update version in `airflow/__init__.py`, 
`docs/docker-stack/` and `airflow/api_connexion/openapi/v1.yaml` to the next 
likely minor version release.
+- For major/minor release, update version in `airflow/__init__.py` and 
`docs/docker-stack/` to the next likely minor version release.
 - Sync `RELEASE_NOTES.rst` (including deleting relevant `newsfragments`) and 
`README.md` changes.
 - Updating `Dockerfile` with the new version.
 - Updating `airflow_bug_report.yml` issue template in 
`.github/ISSUE_TEMPLATE/` with the new version.
@@ -1081,7 +1081,7 @@ Clients can be found here:
 ### API Clients versioning policy
 
 Clients and Core versioning are completely decoupled. Clients also follow 
SemVer and are updated when core introduce changes relevant to the clients.
-Most of the time, if the [openapi 
specification](https://github.com/apache/airflow/blob/main/airflow/api_connexion/openapi/v1.yaml)
 has
+Most of the time, if the [openapi 
specification](https://github.com/apache/airflow/blob/main/clients/python/openapi_v1.yaml)
 has
 changed, clients need to be released.
 
 To determine if you should release API clients, you can run from the airflow 
repository:
diff --git a/dev/README_RELEASE_PYTHON_CLIENT.md 
b/dev/README_RELEASE_PYTHON_CLIENT.md
index 77b2266affa..a6c6460d7fe 100644
--- a/dev/README_RELEASE_PYTHON_CLIENT.md
+++ b/dev/README_RELEASE_PYTHON_CLIENT.md
@@ -92,7 +92,7 @@ echo "${VERSION}" > clients/python/version.txt
 
 ```shell script
 cd ${AIRFLOW_REPO_ROOT}
-git log 2.8.0..HEAD --pretty=oneline -- airflow/api_connexion/openapi/v1.yaml
+git log 2.8.0..HEAD --pretty=oneline -- clients/python/openapi_v1.yaml
 ```
 
 - Update CHANGELOG.md with the details.
diff --git a/dev/airflow-github b/dev/airflow-github
index 2d1567948d3..0963c4a2224 100755
--- a/dev/airflow-github
+++ b/dev/airflow-github
@@ -408,7 +408,7 @@ def api_clients_policy(previous_version, target_version):
         repo,
         previous_version,
         target_version,
-        files=[f"{repo.working_dir}/airflow/api_connexion/openapi/v1.yaml"],
+        files=[f"{repo.working_dir}/clients/python/openapi_v1.yaml"],
     )
 
     clients_need_release = False
diff --git a/dev/breeze/src/airflow_breeze/utils/selective_checks.py 
b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
index 7d7be448088..006d56fedc1 100644
--- a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
+++ b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
@@ -80,8 +80,6 @@ FORCE_PIP_LABEL = "force pip"
 FULL_TESTS_NEEDED_LABEL = "full tests needed"
 INCLUDE_SUCCESS_OUTPUTS_LABEL = "include success outputs"
 LATEST_VERSIONS_ONLY_LABEL = "latest versions only"
-LEGACY_UI_LABEL = "legacy ui"
-LEGACY_API_LABEL = "legacy api"
 LOG_WITHOUT_MOCK_IN_TESTS_EXCEPTION_LABEL = "log exception"
 NON_COMMITTER_BUILD_LABEL = "non committer build"
 UPGRADE_TO_NEWER_DEPENDENCIES_LABEL = "upgrade to newer dependencies"
@@ -102,7 +100,6 @@ class FileGroupForCi(Enum):
     ALWAYS_TESTS_FILES = "always_test_files"
     API_FILES = "api_files"
     API_CODEGEN_FILES = "api_codegen_files"
-    LEGACY_API_FILES = "legacy_api_files"
     HELM_FILES = "helm_files"
     DEPENDENCY_FILES = "dependency_files"
     DOC_FILES = "doc_files"
@@ -171,9 +168,6 @@ CI_FILE_GROUP_MATCHES = HashableDict(
             r"^airflow/api_fastapi/core_api/openapi/v1-generated\.yaml",
             r"^clients/gen",
         ],
-        FileGroupForCi.LEGACY_API_FILES: [
-            r"^airflow/api_connexion/",
-        ],
         FileGroupForCi.HELM_FILES: [
             r"^chart",
             r"^airflow/kubernetes",
@@ -288,10 +282,8 @@ TEST_TYPE_MATCHES = HashableDict(
     {
         SelectiveCoreTestType.API: [
             r"^airflow/api/",
-            r"^airflow/api_connexion/",
             r"^airflow/api_fastapi/",
             r"^tests/api/",
-            r"^tests/api_connexion/",
             r"^tests/api_fastapi/",
         ],
         SelectiveCoreTestType.CLI: [
@@ -1510,30 +1502,6 @@ class SelectiveChecks:
             and self._github_repository == APACHE_AIRFLOW_GITHUB_REPOSITORY
         ) or CANARY_LABEL in self._pr_labels
 
-    @cached_property
-    def is_legacy_ui_api_labeled(self) -> bool:
-        # Selective check for legacy UI/API updates.
-        # It is to ping the maintainer to add the label and make them aware of 
the changes.
-        if self._is_canary_run() or self._github_event not in (
-            GithubEvents.PULL_REQUEST,
-            GithubEvents.PULL_REQUEST_TARGET,
-        ):
-            return False
-
-        if (
-            self._matching_files(
-                FileGroupForCi.LEGACY_API_FILES, CI_FILE_GROUP_MATCHES, 
CI_FILE_GROUP_EXCLUDES
-            )
-            and LEGACY_API_LABEL not in self._pr_labels
-        ):
-            get_console().print(
-                f"[error]Please ask maintainer to assign "
-                f"the '{LEGACY_API_LABEL}' label to the PR in order to 
continue"
-            )
-            sys.exit(1)
-        else:
-            return True
-
     @classmethod
     def _find_caplog_in_def(cls, added_lines):
         """
diff --git a/dev/breeze/tests/test_selective_checks.py 
b/dev/breeze/tests/test_selective_checks.py
index 250434548a9..419e3394982 100644
--- a/dev/breeze/tests/test_selective_checks.py
+++ b/dev/breeze/tests/test_selective_checks.py
@@ -51,10 +51,6 @@ LIST_OF_ALL_PROVIDER_TESTS = " ".join(
 # commit that is neutral - allows to keep pyproject.toml-changing PRS neutral 
for unit tests
 NEUTRAL_COMMIT = "938f0c1f3cc4cbe867123ee8aa9f290f9f18100a"
 
-# for is_legacy_ui_api_labeled tests
-LEGACY_UI_LABEL = "legacy ui"
-LEGACY_API_LABEL = "legacy api"
-
 # Use me if you are adding test for the changed files that includes caplog
 LOG_WITHOUT_MOCK_IN_TESTS_EXCEPTION_LABEL = "log exception"
 
diff --git a/generated/dep_tree.txt b/generated/dep_tree.txt
index a2c2f59f5b8..2d117e37416 100644
--- a/generated/dep_tree.txt
+++ b/generated/dep_tree.txt
@@ -27,55 +27,6 @@ apache-airflow v3.0.0.dev0
 ├── blinker v1.8.2
 ├── colorlog v6.8.2
 ├── configupdater v3.2
-├── connexion[flask] v2.14.2
-│   ├── clickclick v20.10.2
-│   │   ├── click v8.1.7
-│   │   └── pyyaml v6.0.2
-│   ├── flask v2.2.5
-│   │   ├── click v8.1.7
-│   │   ├── importlib-metadata v8.4.0
-│   │   │   └── zipp v3.20.1
-│   │   ├── itsdangerous v2.2.0
-│   │   ├── jinja2 v3.1.4
-│   │   │   └── markupsafe v2.1.5
-│   │   └── werkzeug v2.2.3
-│   │       └── markupsafe v2.1.5
-│   ├── inflection v0.5.1
-│   ├── itsdangerous v2.2.0
-│   ├── jsonschema v4.23.0
-│   │   ├── attrs v24.2.0
-│   │   ├── importlib-resources v6.4.4
-│   │   │   └── zipp v3.20.1
-│   │   ├── jsonschema-specifications v2023.12.1
-│   │   │   ├── importlib-resources v6.4.4
-│   │   │   │   └── zipp v3.20.1
-│   │   │   └── referencing v0.35.1
-│   │   │       ├── attrs v24.2.0
-│   │   │       └── rpds-py v0.20.0
-│   │   ├── pkgutil-resolve-name v1.3.10
-│   │   ├── referencing v0.35.1
-│   │   │   ├── attrs v24.2.0
-│   │   │   └── rpds-py v0.20.0
-│   │   └── rpds-py v0.20.0
-│   ├── packaging v24.1
-│   ├── pyyaml v6.0.2
-│   ├── requests v2.32.3
-│   │   ├── certifi v2024.8.30
-│   │   ├── charset-normalizer v3.3.2
-│   │   ├── idna v3.8
-│   │   └── urllib3 v2.2.2
-│   ├── werkzeug v2.2.3
-│   │   └── markupsafe v2.1.5
-│   ├── flask v2.2.5 (extra: flask)
-│   │   ├── click v8.1.7
-│   │   ├── importlib-metadata v8.4.0
-│   │   │   └── zipp v3.20.1
-│   │   ├── itsdangerous v2.2.0
-│   │   ├── jinja2 v3.1.4
-│   │   │   └── markupsafe v2.1.5
-│   │   └── werkzeug v2.2.3
-│   │       └── markupsafe v2.1.5
-│   └── itsdangerous v2.2.0 (extra: flask)
 ├── cron-descriptor v1.4.5
 ├── croniter v3.0.3
 │   ├── python-dateutil v2.9.0.post0
diff --git a/generated/dependency_depth.json b/generated/dependency_depth.json
index 593e791ae09..7d1c40327e7 100644
--- a/generated/dependency_depth.json
+++ b/generated/dependency_depth.json
@@ -23,7 +23,6 @@
     "blinker": 1,
     "colorlog": 1,
     "configupdater": 1,
-    "connexion[flask]": 1,
     "clickclick": 2,
     "click": 3,
     "pyyaml": 3,
diff --git a/generated/provider_dependencies.json 
b/generated/provider_dependencies.json
index ae9fa645742..44e1a4e70ea 100644
--- a/generated/provider_dependencies.json
+++ b/generated/provider_dependencies.json
@@ -591,6 +591,7 @@
     "deps": [
       "apache-airflow-providers-common-compat>=1.2.1",
       "apache-airflow>=3.0.0.dev0",
+      "connexion[flask]>=2.14.2,<3.0",
       "flask-appbuilder==4.5.3",
       "flask-login>=0.6.2",
       "flask>=2.2,<2.3",
diff --git a/hatch_build.py b/hatch_build.py
index 0a0e784f08b..5bdf7ae9718 100644
--- a/hatch_build.py
+++ b/hatch_build.py
@@ -197,13 +197,6 @@ DEPENDENCIES = [
     "blinker>=1.6.2",
     "colorlog>=6.8.2",
     "configupdater>=3.1.1",
-    # `airflow/www/extensions/init_views` imports 
`connexion.decorators.validation.RequestBodyValidator`
-    # connexion v3 has refactored the entire module to middleware, see: 
/spec-first/connexion/issues/1525
-    # Specifically, RequestBodyValidator was removed in: 
/spec-first/connexion/pull/1595
-    # The usage was added in #30596, seemingly only to override and improve 
the default error message.
-    # Either revert that change or find another way, preferably without using 
connexion internals.
-    # This limit can be removed after 
https://github.com/apache/airflow/issues/35234 is fixed
-    "connexion[flask]>=2.14.2,<3.0",
     "cron-descriptor>=1.2.24",
     "croniter>=2.0.2",
     "cryptography>=41.0.0",
@@ -279,8 +272,8 @@ DEPENDENCIES = [
     # Does not work with it Tracked in 
https://github.com/fsspec/universal_pathlib/issues/276
     "universal-pathlib>=0.2.2,!=0.2.4",
     "uuid6>=2024.7.10",
-    # Werkzug 3 breaks Flask-Login 0.6.2, also connexion needs to be updated 
to >= 3.0
-    # we should remove this limitation when FAB supports Flask 2.3 and we 
migrate connexion to 3+
+    # Werkzug 3 breaks Flask-Login 0.6.2
+    # we should remove this limitation when FAB supports Flask 2.3
     "werkzeug>=2.0,<3",
 ]
 
diff --git a/providers/fab/README.rst b/providers/fab/README.rst
index 772dce9a8f3..859bd8fc8ba 100644
--- a/providers/fab/README.rst
+++ b/providers/fab/README.rst
@@ -58,6 +58,7 @@ PIP package                                 Version required
 ``flask``                                   ``>=2.2,<2.3``
 ``flask-appbuilder``                        ``==4.5.3``
 ``flask-login``                             ``>=0.6.2``
+``connexion[flask]``                        ``>=2.14.2,<3.0``
 ``jmespath``                                ``>=0.7.0``
 ==========================================  ==================
 
diff --git a/providers/fab/pyproject.toml b/providers/fab/pyproject.toml
index bf693eb033c..9f5cde67783 100644
--- a/providers/fab/pyproject.toml
+++ b/providers/fab/pyproject.toml
@@ -67,6 +67,7 @@ dependencies = [
     # In particular, make sure any breaking changes, for example any new 
methods, are accounted for.
     "flask-appbuilder==4.5.3",
     "flask-login>=0.6.2",
+    "connexion[flask]>=2.14.2,<3.0",
     "jmespath>=0.7.0",
 ]
 
diff --git a/providers/fab/src/airflow/providers/fab/get_provider_info.py 
b/providers/fab/src/airflow/providers/fab/get_provider_info.py
index efe4452fe2e..fa183c9aa29 100644
--- a/providers/fab/src/airflow/providers/fab/get_provider_info.py
+++ b/providers/fab/src/airflow/providers/fab/get_provider_info.py
@@ -82,6 +82,7 @@ def get_provider_info():
             "flask>=2.2,<2.3",
             "flask-appbuilder==4.5.3",
             "flask-login>=0.6.2",
+            "connexion[flask]>=2.14.2,<3.0",
             "jmespath>=0.7.0",
         ],
         "optional-dependencies": {"kerberos": ["kerberos>=1.3.0"]},
diff --git a/pyproject.toml b/pyproject.toml
index a6bb054bd3d..c8a3c37b2e3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -506,12 +506,6 @@ filterwarnings = [
     "ignore::DeprecationWarning:flask_sqlalchemy",
     # https://github.com/dpgaspar/Flask-AppBuilder/pull/1903
     "ignore::DeprecationWarning:apispec.utils",
-    # Connexion 2 use different deprecated objects, this should be resolved 
into Connexion 3
-    # https://github.com/spec-first/connexion/pull/1536
-    'ignore::DeprecationWarning:connexion.spec',
-    'ignore:jsonschema\.RefResolver:DeprecationWarning:connexion.json_schema',
-    
'ignore:jsonschema\.exceptions\.RefResolutionError:DeprecationWarning:connexion.json_schema',
-    'ignore:Accessing 
jsonschema\.draft4_format_checker:DeprecationWarning:connexion.decorators.validation',
 ]
 # We cannot add warnings from the airflow package into `filterwarnings`,
 # because it invokes import airflow before we set up test environment which 
breaks the tests.
diff --git a/scripts/ci/pre_commit/check_tests_in_right_folders.py 
b/scripts/ci/pre_commit/check_tests_in_right_folders.py
index a04400e1c0c..48665d1f901 100755
--- a/scripts/ci/pre_commit/check_tests_in_right_folders.py
+++ b/scripts/ci/pre_commit/check_tests_in_right_folders.py
@@ -31,7 +31,6 @@ POSSIBLE_TEST_FOLDERS = [
     "_internals",
     "always",
     "api",
-    "api_connexion",
     "api_internal",
     "api_fastapi",
     "assets",
diff --git a/scripts/cov/restapi_coverage.py b/scripts/cov/restapi_coverage.py
index 52728c4b7d8..f87ce9880c5 100644
--- a/scripts/cov/restapi_coverage.py
+++ b/scripts/cov/restapi_coverage.py
@@ -23,16 +23,9 @@ from cov_runner import run_tests
 
 sys.path.insert(0, str(Path(__file__).parent.resolve()))
 
-source_files = ["airflow/api_connexion"]
+source_files = ["airflow/api_fastapi"]
 
-files_not_fully_covered = [
-    "airflow/api_connexion/endpoints/forward_to_fab_endpoint.py",
-    "airflow/api_connexion/endpoints/task_instance_endpoint.py",
-    "airflow/api_connexion/exceptions.py",
-    "airflow/api_connexion/schemas/common_schema.py",
-    "airflow/api_connexion/security.py",
-    "airflow/api_connexion/types.py",
-]
+files_not_fully_covered: list[str] = []
 
 if __name__ == "__main__":
     args = ["-qq"] + source_files
diff --git a/tests/cli/commands/remote_commands/test_dag_command.py 
b/tests/cli/commands/remote_commands/test_dag_command.py
index 5a5e16e0504..c509aa009fc 100644
--- a/tests/cli/commands/remote_commands/test_dag_command.py
+++ b/tests/cli/commands/remote_commands/test_dag_command.py
@@ -32,7 +32,6 @@ import time_machine
 from sqlalchemy import select
 
 from airflow import settings
-from airflow.api_connexion.schemas.dag_schema import DAGSchema, dag_schema
 from airflow.cli import cli_parser
 from airflow.cli.commands.remote_commands import dag_command
 from airflow.decorators import task
@@ -237,7 +236,7 @@ class TestCliDags:
             dag_command.dag_details(args)
             out = temp_stdout.getvalue()
 
-        dag_detail_fields = DAGSchema().fields.keys()
+        dag_detail_fields = dag_command.DAGSchema().fields.keys()
 
         # Check if DAG Details field are present
         for field in dag_detail_fields:
@@ -311,7 +310,7 @@ class TestCliDags:
 
     @conf_vars({("core", "load_examples"): "true"})
     def test_dagbag_dag_col(self):
-        valid_cols = [c for c in dag_schema.fields]
+        valid_cols = [c for c in dag_command.DAGSchema().fields]
         dagbag = DagBag(include_examples=True)
         dag_details = 
dag_command._get_dagbag_dag_details(dagbag.get_dag("tutorial_dag"))
         assert list(dag_details.keys()) == valid_cols

Reply via email to