diff --git a/airflow-core/docs/howto/custom-view-plugin.rst b/airflow-core/docs/howto/custom-view-plugin.rst index 3520de1a652ec..024c32f96132d 100644 --- a/airflow-core/docs/howto/custom-view-plugin.rst +++ b/airflow-core/docs/howto/custom-view-plugin.rst @@ -118,7 +118,7 @@ Create an Airflow plugin that serves your React application: from pathlib import Path from fastapi import FastAPI - from starlette.staticfiles import StaticFiles + from fastapi.staticfiles import StaticFiles import mimetypes from airflow.plugins_manager import AirflowPlugin diff --git a/airflow-core/src/airflow/api_fastapi/app.py b/airflow-core/src/airflow/api_fastapi/app.py index e2b4373302477..30d151c0db7f3 100644 --- a/airflow-core/src/airflow/api_fastapi/app.py +++ b/airflow-core/src/airflow/api_fastapi/app.py @@ -23,7 +23,7 @@ from urllib.parse import urlsplit from fastapi import FastAPI -from starlette.routing import Mount +from fastapi.routing import Mount from airflow.api_fastapi.common.dagbag import create_dag_bag from airflow.api_fastapi.core_api.app import ( diff --git a/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py b/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py index 372aecf603525..2233de8e0b5b6 100644 --- a/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py +++ b/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py @@ -18,7 +18,7 @@ from __future__ import annotations from fastapi import Depends, Request, status -from starlette.responses import RedirectResponse +from fastapi.responses import RedirectResponse from airflow.api_fastapi.auth.managers.base_auth_manager import COOKIE_NAME_JWT_TOKEN from airflow.api_fastapi.auth.managers.simple.datamodels.login import LoginBody, LoginResponse diff --git a/airflow-core/src/airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py b/airflow-core/src/airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py index 6218b48296b71..c07b4e3eb74da 100644 --- a/airflow-core/src/airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py +++ b/airflow-core/src/airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py @@ -28,11 +28,10 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, TextIO -from fastapi import FastAPI -from starlette.requests import Request -from starlette.responses import HTMLResponse -from starlette.staticfiles import StaticFiles -from starlette.templating import Jinja2Templates +from fastapi import FastAPI, Request +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates from termcolor import colored from airflow.api_fastapi.app import AUTH_MANAGER_FASTAPI_APP_PREFIX diff --git a/airflow-core/src/airflow/api_fastapi/compat.py b/airflow-core/src/airflow/api_fastapi/compat.py index 06d8822bf9542..75e2e79d63732 100644 --- a/airflow-core/src/airflow/api_fastapi/compat.py +++ b/airflow-core/src/airflow/api_fastapi/compat.py @@ -16,11 +16,21 @@ # under the License. from __future__ import annotations +from fastapi import status + +# HTTP_422_UNPROCESSABLE_CONTENT was added in Starlette 0.48.0, replacing HTTP_422_UNPROCESSABLE_ENTITY +# to align with RFC 9110 (HTTP Semantics). +# +# FastAPI 0.128.0 (our minimum version) requires starlette>=0.40.0. With "Low dep tests" +# (uv sync --resolution lowest-direct), starlette 0.40.0 is installed, which only has +# HTTP_422_UNPROCESSABLE_ENTITY. So we need this fallback for backward compatibility. +# +# Refs: +# - https://www.starlette.io/release-notes/ +# - https://www.rfc-editor.org/rfc/rfc9110#status.422 try: - from starlette.status import HTTP_422_UNPROCESSABLE_CONTENT -except ImportError: - from starlette.status import ( # type: ignore[no-redef] - HTTP_422_UNPROCESSABLE_ENTITY as HTTP_422_UNPROCESSABLE_CONTENT, - ) + HTTP_422_UNPROCESSABLE_CONTENT = status.HTTP_422_UNPROCESSABLE_CONTENT +except AttributeError: + HTTP_422_UNPROCESSABLE_CONTENT = status.HTTP_422_UNPROCESSABLE_ENTITY # type: ignore[attr-defined] __all__ = ["HTTP_422_UNPROCESSABLE_CONTENT"] diff --git a/airflow-core/src/airflow/api_fastapi/core_api/app.py b/airflow-core/src/airflow/api_fastapi/core_api/app.py index b53a178027825..fdc58592710c5 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/app.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/app.py @@ -22,13 +22,12 @@ import warnings from pathlib import Path -from fastapi import FastAPI +from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware -from starlette.requests import Request -from starlette.responses import HTMLResponse, JSONResponse -from starlette.staticfiles import StaticFiles -from starlette.templating import Jinja2Templates +from fastapi.responses import HTMLResponse, JSONResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates from airflow.api_fastapi.auth.tokens import get_signing_key from airflow.configuration import conf diff --git a/providers/amazon/src/airflow/providers/amazon/aws/auth_manager/routes/login.py b/providers/amazon/src/airflow/providers/amazon/aws/auth_manager/routes/login.py index 6c43f70fe4c6c..2c65d5ad236a1 100644 --- a/providers/amazon/src/airflow/providers/amazon/aws/auth_manager/routes/login.py +++ b/providers/amazon/src/airflow/providers/amazon/aws/auth_manager/routes/login.py @@ -21,9 +21,8 @@ from typing import Any import anyio -from fastapi import HTTPException, Request -from starlette import status -from starlette.responses import RedirectResponse +from fastapi import HTTPException, Request, status +from fastapi.responses import RedirectResponse from airflow.api_fastapi.app import ( AUTH_MANAGER_FASTAPI_APP_PREFIX, diff --git a/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/routes/login.py b/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/routes/login.py index 7ae20e1a23a97..afd7b230d1cad 100644 --- a/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/routes/login.py +++ b/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/routes/login.py @@ -18,10 +18,8 @@ from typing import Any -from fastapi import Body -from starlette import status -from starlette.requests import Request # noqa: TC002 -from starlette.responses import RedirectResponse +from fastapi import Body, Request, status +from fastapi.responses import RedirectResponse from airflow.api_fastapi.app import get_auth_manager from airflow.api_fastapi.auth.managers.base_auth_manager import COOKIE_NAME_JWT_TOKEN diff --git a/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/services/login.py b/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/services/login.py index c6d9dc3ff0dda..b61e201fb076d 100644 --- a/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/services/login.py +++ b/providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/services/login.py @@ -18,8 +18,7 @@ from typing import Any -from starlette import status -from starlette.exceptions import HTTPException +from fastapi import HTTPException, status from airflow.configuration import conf from airflow.providers.fab.auth_manager.api_fastapi.datamodels.login import LoginResponse diff --git a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py index c5486bcdc19e1..b89fd72f9cde4 100644 --- a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py +++ b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py @@ -24,11 +24,11 @@ from connexion import FlaskApi from fastapi import FastAPI +from fastapi.middleware.wsgi import WSGIMiddleware from flask import Blueprint, current_app, g from flask_appbuilder.const import AUTH_LDAP from sqlalchemy import select from sqlalchemy.orm import Session, joinedload -from starlette.middleware.wsgi import WSGIMiddleware from airflow.api_fastapi.app import AUTH_MANAGER_FASTAPI_APP_PREFIX from airflow.api_fastapi.auth.managers.base_auth_manager import BaseAuthManager diff --git a/providers/fab/tests/unit/fab/auth_manager/api_fastapi/services/test_login.py b/providers/fab/tests/unit/fab/auth_manager/api_fastapi/services/test_login.py index 85c4758f01098..7655d175490ff 100644 --- a/providers/fab/tests/unit/fab/auth_manager/api_fastapi/services/test_login.py +++ b/providers/fab/tests/unit/fab/auth_manager/api_fastapi/services/test_login.py @@ -20,7 +20,7 @@ from unittest.mock import ANY, MagicMock, patch import pytest -from starlette.exceptions import HTTPException +from fastapi import HTTPException from airflow.providers.fab.auth_manager.api_fastapi.services.login import FABAuthManagerLogin diff --git a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/login.py b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/login.py index a9a402c2c6aa7..2cc3a83aa9614 100644 --- a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/login.py +++ b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/login.py @@ -21,7 +21,7 @@ from typing import Annotated, cast from fastapi import Depends, Request -from starlette.responses import HTMLResponse, RedirectResponse +from fastapi.responses import HTMLResponse, RedirectResponse from airflow.api_fastapi.app import get_auth_manager from airflow.api_fastapi.auth.managers.base_auth_manager import COOKIE_NAME_JWT_TOKEN diff --git a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/token.py b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/token.py index 4514531c6484c..e1cd9cc4b12de 100644 --- a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/token.py +++ b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/routes/token.py @@ -19,7 +19,7 @@ import logging -from starlette import status +from fastapi import status from airflow.api_fastapi.common.router import AirflowRouter from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc diff --git a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/services/token.py b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/services/token.py index f1d4a180de18b..2b9844f3d0448 100644 --- a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/services/token.py +++ b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/services/token.py @@ -17,9 +17,8 @@ from __future__ import annotations -from fastapi import HTTPException +from fastapi import HTTPException, status from keycloak import KeycloakAuthenticationError -from starlette import status from airflow.api_fastapi.app import get_auth_manager from airflow.providers.common.compat.sdk import conf