This is an automated email from the ASF dual-hosted git repository.
ash 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 d1b80e4bd9f (Re)move old dependencies from the old FAB UI (#48007)
d1b80e4bd9f is described below
commit d1b80e4bd9f78d9bdd0f4c300ea9d91100ccfe9c
Author: Ash Berlin-Taylor <[email protected]>
AuthorDate: Mon Mar 24 14:42:19 2025 +0000
(Re)move old dependencies from the old FAB UI (#48007)
Some of these deps, like python-nvd3 or markdown-it-py, are simply not used
anymore, while others are still used and the dep has been moved to the fab
provider where it is actually used.
---
RELEASE_NOTES.rst | 6 ++
airflow-core/pyproject.toml | 22 -------
airflow-core/src/airflow/utils/json.py | 67 +---------------------
airflow-core/tests/unit/utils/test_json.py | 25 --------
generated/provider_dependencies.json | 8 ++-
.../src/airflow/providers/amazon/aws/hooks/eks.py | 9 +--
.../providers/amazon/aws/operators/sagemaker.py | 3 +-
providers/fab/README.rst | 6 +-
providers/fab/pyproject.toml | 16 +++++-
.../src/airflow/providers/fab/get_provider_info.py | 6 +-
reproducible_build.yaml | 4 +-
11 files changed, 44 insertions(+), 128 deletions(-)
diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst
index 780e33ee8e4..756da7050db 100644
--- a/RELEASE_NOTES.rst
+++ b/RELEASE_NOTES.rst
@@ -14277,3 +14277,9 @@ Airflow 1.7.1 (2016-05-19)
- Use GSSAPI instead of KERBEROS and provide backwards compatibility
- ISSUE-1123 Use impyla instead of pyhs2
- Set celery_executor to use queue name as exchange
+
+
+.. spelling::
+
+ nvd
+ lineChart
diff --git a/airflow-core/pyproject.toml b/airflow-core/pyproject.toml
index 3ea64a6fe68..d3e46ce4106 100644
--- a/airflow-core/pyproject.toml
+++ b/airflow-core/pyproject.toml
@@ -69,12 +69,8 @@ dependencies = [
"argcomplete>=1.10",
"asgiref>=2.3.0",
"attrs>=22.1.0, !=25.2.0",
- # Blinker use for signals in Flask, this is an optional dependency in
Flask 2.2 and lower.
- # In Flask 2.3 it becomes a mandatory dependency, and flask signals are
always available.
- "blinker>=1.6.2",
"cadwyn>=5.1.3",
"colorlog>=6.8.2",
- "configupdater>=3.1.1",
"cron-descriptor>=1.2.24",
"croniter>=2.0.2",
"cryptography>=41.0.0",
@@ -86,15 +82,6 @@ dependencies = [
# 0.115.10 fastapi was a bad release that broke our API's and static
checks.
# Related fastapi issue here:
https://github.com/fastapi/fastapi/discussions/13431
"fastapi[standard]>=0.112.4,!=0.115.10",
- "flask-caching>=2.0.0",
- # Flask-Session 0.6 add new arguments into the SqlAlchemySessionInterface
constructor as well as
- # all parameters now are mandatory which make
AirflowDatabaseSessionInterface incompatible with this version.
- "flask-session>=0.4.0,<0.6",
- "flask-wtf>=1.1.0",
- # Flask 2.3 is scheduled to introduce a number of deprecation removals -
some of them might be breaking
- # for our dependencies - notably `_app_ctx_stack` and `_request_ctx_stack`
removals.
- # We should remove the limitation after 2.3 is released and our
dependencies are updated to handle it
- "flask>=2.2.1,<2.3",
"fsspec>=2023.10.0",
"gitpython>=3.1.40",
"gunicorn>=20.1.0",
@@ -107,10 +94,7 @@ dependencies = [
"libcst >=1.1.0",
"linkify-it-py>=2.0.0",
"lockfile>=0.12.2",
- "markdown-it-py>=2.1.0",
- "markupsafe>=1.1.1",
"marshmallow-oneofschema>=2.0.1",
- "mdit-py-plugins>=0.3.0",
"methodtools>=0.4.7",
"opentelemetry-api>=1.24.0",
"opentelemetry-exporter-otlp>=1.24.0",
@@ -127,12 +111,9 @@ dependencies = [
"pyjwt>=2.10.0",
"python-daemon>=3.0.0",
"python-dateutil>=2.7.0",
- "python-nvd3>=0.15.0",
"python-slugify>=5.0",
# Requests 3 if it will be released, will be heavily breaking.
"requests>=2.27.0,<3",
- "requests-toolbelt>=1.0.0",
- "rfc3339-validator>=0.1.4",
"rich-argparse>=1.0.0",
"rich>=13.1.0",
"setproctitle>=1.3.3",
@@ -151,9 +132,6 @@ 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
- # we should remove this limitation when FAB supports Flask 2.3
- "werkzeug>=2.0,<4",
]
diff --git a/airflow-core/src/airflow/utils/json.py
b/airflow-core/src/airflow/utils/json.py
index a8846282899..e7af172226f 100644
--- a/airflow-core/src/airflow/utils/json.py
+++ b/airflow-core/src/airflow/utils/json.py
@@ -18,70 +18,9 @@
from __future__ import annotations
import json
-from datetime import date, datetime
-from decimal import Decimal
from typing import Any
-from flask.json.provider import JSONProvider
-
-from airflow.serialization.serde import CLASSNAME, DATA, SCHEMA_ID,
deserialize, serialize
-from airflow.utils.timezone import convert_to_utc, is_naive
-
-
-class AirflowJsonProvider(JSONProvider):
- """JSON Provider for Flask app to use WebEncoder."""
-
- ensure_ascii: bool = True
- sort_keys: bool = True
-
- def dumps(self, obj, **kwargs):
- kwargs.setdefault("ensure_ascii", self.ensure_ascii)
- kwargs.setdefault("sort_keys", self.sort_keys)
- return json.dumps(obj, **kwargs, cls=WebEncoder)
-
- def loads(self, s: str | bytes, **kwargs):
- return json.loads(s, **kwargs)
-
-
-class WebEncoder(json.JSONEncoder):
- """
- This encodes values into a web understandable format. There is no
deserializer.
-
- This parses datetime, dates, Decimal and bytes. In order to parse the
custom
- classes and the other types, and since it's just to show the result in the
UI,
- we return repr(object) for everything else.
- """
-
- def default(self, o: Any) -> Any:
- if isinstance(o, datetime):
- if is_naive(o):
- o = convert_to_utc(o)
- return o.isoformat()
-
- if isinstance(o, date):
- return o.strftime("%Y-%m-%d")
-
- if isinstance(o, Decimal):
- data = serialize(o)
- if isinstance(data, dict) and DATA in data:
- return data[DATA]
- if isinstance(o, bytes):
- try:
- return o.decode("unicode_escape")
- except UnicodeDecodeError:
- return repr(o)
- try:
- data = serialize(o)
- if isinstance(data, dict) and CLASSNAME in data:
- # this is here for backwards compatibility
- if (
- data[CLASSNAME].startswith("numpy")
- or data[CLASSNAME] ==
"kubernetes.client.models.v1_pod.V1Pod"
- ):
- return data[DATA]
- return data
- except TypeError:
- return repr(o)
+from airflow.serialization.serde import CLASSNAME, SCHEMA_ID, deserialize,
serialize
class XComEncoder(json.JSONEncoder):
@@ -121,7 +60,3 @@ class XComDecoder(json.JSONDecoder):
def orm_object_hook(dct: dict) -> object:
"""Create a readable representation of a serialized object."""
return deserialize(dct, False)
-
-
-# backwards compatibility
-AirflowJsonEncoder = WebEncoder
diff --git a/airflow-core/tests/unit/utils/test_json.py
b/airflow-core/tests/unit/utils/test_json.py
index d5d0cdb32e8..2148830bd43 100644
--- a/airflow-core/tests/unit/utils/test_json.py
+++ b/airflow-core/tests/unit/utils/test_json.py
@@ -19,11 +19,8 @@ from __future__ import annotations
import json
from dataclasses import dataclass
-from datetime import date, datetime
from typing import ClassVar
-import numpy as np
-import pendulum
import pytest
from airflow.sdk.definitions.asset import Asset
@@ -55,28 +52,6 @@ class U:
x: int
-class TestWebEncoder:
- def test_encode_datetime(self):
- obj = datetime.strptime("2017-05-21 00:00:00", "%Y-%m-%d %H:%M:%S")
- assert json.dumps(obj, cls=utils_json.WebEncoder) ==
'"2017-05-21T00:00:00+00:00"'
-
- def test_encode_pendulum(self):
- obj = pendulum.datetime(2017, 5, 21, tz="Asia/Kolkata")
- assert json.dumps(obj, cls=utils_json.WebEncoder) ==
'"2017-05-21T00:00:00+05:30"'
-
- def test_encode_date(self):
- assert json.dumps(date(2017, 5, 21), cls=utils_json.WebEncoder) ==
'"2017-05-21"'
-
- def test_encode_numpy_int(self):
- assert json.dumps(np.int32(5), cls=utils_json.WebEncoder) == "5"
-
- def test_encode_numpy_bool(self):
- assert json.dumps(np.bool_(True), cls=utils_json.WebEncoder) == "true"
-
- def test_encode_numpy_float(self):
- assert json.dumps(np.float16(3.76953125), cls=utils_json.WebEncoder)
== "3.76953125"
-
-
class TestXComEncoder:
def test_encode_raises(self):
with pytest.raises(TypeError, match="^.*is not JSON serializable$"):
diff --git a/generated/provider_dependencies.json
b/generated/provider_dependencies.json
index 95e149de682..5f765c9f10e 100644
--- a/generated/provider_dependencies.json
+++ b/generated/provider_dependencies.json
@@ -594,11 +594,15 @@
"deps": [
"apache-airflow-providers-common-compat>=1.2.1",
"apache-airflow>=3.0.0.dev0",
+ "blinker>=1.6.2",
"connexion[flask]>=2.14.2,<3.0",
"flask-appbuilder==4.5.3",
"flask-login>=0.6.2",
- "flask>=2.2,<2.3",
- "jmespath>=0.7.0"
+ "flask-session>=0.4.0,<0.6",
+ "flask-wtf>=1.1.0",
+ "flask>=2.2.1,<2.3",
+ "jmespath>=0.7.0",
+ "werkzeug>=2.2,<4"
],
"devel-deps": [
"kerberos>=1.3.0"
diff --git a/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
b/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
index 421e66b606a..60d3b5bb7a0 100644
--- a/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
+++ b/providers/amazon/src/airflow/providers/amazon/aws/hooks/eks.py
@@ -35,7 +35,6 @@ from botocore.signers import RequestSigner
from airflow.providers.amazon.aws.hooks.base_aws import AwsBaseHook
from airflow.providers.amazon.aws.hooks.sts import StsHook
from airflow.utils import yaml
-from airflow.utils.json import AirflowJsonEncoder
DEFAULT_PAGINATION_TOKEN = ""
STS_TOKEN_EXPIRES_IN = 60
@@ -315,7 +314,7 @@ class EksHook(AwsBaseHook):
)
if verbose:
cluster_data = response.get("cluster")
- self.log.info("Amazon EKS cluster details: %s",
json.dumps(cluster_data, cls=AirflowJsonEncoder))
+ self.log.info("Amazon EKS cluster details: %s",
json.dumps(cluster_data, default=repr))
return response
def describe_nodegroup(self, clusterName: str, nodegroupName: str,
verbose: bool = False) -> dict:
@@ -343,7 +342,7 @@ class EksHook(AwsBaseHook):
nodegroup_data = response.get("nodegroup")
self.log.info(
"Amazon EKS managed node group details: %s",
- json.dumps(nodegroup_data, cls=AirflowJsonEncoder),
+ json.dumps(nodegroup_data, default=repr),
)
return response
@@ -374,9 +373,7 @@ class EksHook(AwsBaseHook):
)
if verbose:
fargate_profile_data = response.get("fargateProfile")
- self.log.info(
- "AWS Fargate profile details: %s",
json.dumps(fargate_profile_data, cls=AirflowJsonEncoder)
- )
+ self.log.info("AWS Fargate profile details: %s",
json.dumps(fargate_profile_data, default=repr))
return response
def get_cluster_state(self, clusterName: str) -> ClusterStates:
diff --git
a/providers/amazon/src/airflow/providers/amazon/aws/operators/sagemaker.py
b/providers/amazon/src/airflow/providers/amazon/aws/operators/sagemaker.py
index dc68f13bb36..c3d74acd7bf 100644
--- a/providers/amazon/src/airflow/providers/amazon/aws/operators/sagemaker.py
+++ b/providers/amazon/src/airflow/providers/amazon/aws/operators/sagemaker.py
@@ -44,7 +44,6 @@ from airflow.providers.amazon.aws.utils import
trim_none_values, validate_execut
from airflow.providers.amazon.aws.utils.sagemaker import ApprovalStatus
from airflow.providers.amazon.aws.utils.tags import format_tags
from airflow.utils.helpers import prune_dict
-from airflow.utils.json import AirflowJsonEncoder
if TYPE_CHECKING:
from airflow.providers.common.compat.openlineage.facet import Dataset
@@ -56,7 +55,7 @@ CHECK_INTERVAL_SECOND: int = 30
def serialize(result: dict) -> dict:
- return json.loads(json.dumps(result, cls=AirflowJsonEncoder))
+ return json.loads(json.dumps(result, default=repr))
class SageMakerBaseOperator(BaseOperator):
diff --git a/providers/fab/README.rst b/providers/fab/README.rst
index f04c442fd10..f54d341f885 100644
--- a/providers/fab/README.rst
+++ b/providers/fab/README.rst
@@ -55,11 +55,15 @@ PIP package Version required
========================================== ==================
``apache-airflow`` ``>=3.0.0.dev0``
``apache-airflow-providers-common-compat`` ``>=1.2.1``
-``flask`` ``>=2.2,<2.3``
+``blinker`` ``>=1.6.2``
+``flask`` ``>=2.2.1,<2.3``
``flask-appbuilder`` ``==4.5.3``
``flask-login`` ``>=0.6.2``
+``flask-session`` ``>=0.4.0,<0.6``
+``flask-wtf`` ``>=1.1.0``
``connexion[flask]`` ``>=2.14.2,<3.0``
``jmespath`` ``>=0.7.0``
+``werkzeug`` ``>=2.2,<4``
========================================== ==================
Cross provider package dependencies
diff --git a/providers/fab/pyproject.toml b/providers/fab/pyproject.toml
index 78f03450f38..8c97d3fc9ce 100644
--- a/providers/fab/pyproject.toml
+++ b/providers/fab/pyproject.toml
@@ -59,7 +59,13 @@ requires-python = "~=3.9"
dependencies = [
"apache-airflow>=3.0.0.dev0",
"apache-airflow-providers-common-compat>=1.2.1",
- "flask>=2.2,<2.3",
+ # Blinker use for signals in Flask, this is an optional dependency in
Flask 2.2 and lower.
+ # In Flask 2.3 it becomes a mandatory dependency, and flask signals are
always available.
+ "blinker>=1.6.2",
+ # Flask 2.3 is scheduled to introduce a number of deprecation removals -
some of them might be breaking
+ # for our dependencies - notably `_app_ctx_stack` and `_request_ctx_stack`
removals.
+ # We should remove the limitation after 2.3 is released and our
dependencies are updated to handle it
+ "flask>=2.2.1,<2.3",
# We are tightly coupled with FAB version as we vendored-in part of FAB
code related to security manager
# This is done as part of preparation to removing FAB as dependency, but
we are not ready for it yet
# Every time we update FAB version here, please make sure that you review
the classes and models in
@@ -67,8 +73,16 @@ 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",
+ # Flask-Session 0.6 add new arguments into the SqlAlchemySessionInterface
constructor as well as
+ # all parameters now are mandatory which make
AirflowDatabaseSessionInterface incompatible with this version.
+ "flask-session>=0.4.0,<0.6",
+ "flask-wtf>=1.1.0",
"connexion[flask]>=2.14.2,<3.0",
"jmespath>=0.7.0",
+ # Werkzug 3 breaks Flask-Login 0.6.2
+ # we should remove this limitation when FAB supports Flask 2.3
+ "werkzeug>=2.2,<4",
+
]
# The optional dependencies should be modified in place in the generated file
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 026a8325f03..a6dc998cfc4 100644
--- a/providers/fab/src/airflow/providers/fab/get_provider_info.py
+++ b/providers/fab/src/airflow/providers/fab/get_provider_info.py
@@ -86,11 +86,15 @@ def get_provider_info():
"dependencies": [
"apache-airflow>=3.0.0.dev0",
"apache-airflow-providers-common-compat>=1.2.1",
- "flask>=2.2,<2.3",
+ "blinker>=1.6.2",
+ "flask>=2.2.1,<2.3",
"flask-appbuilder==4.5.3",
"flask-login>=0.6.2",
+ "flask-session>=0.4.0,<0.6",
+ "flask-wtf>=1.1.0",
"connexion[flask]>=2.14.2,<3.0",
"jmespath>=0.7.0",
+ "werkzeug>=2.2,<4",
],
"optional-dependencies": {"kerberos": ["kerberos>=1.3.0"]},
"devel-dependencies": ["kerberos>=1.3.0"],
diff --git a/reproducible_build.yaml b/reproducible_build.yaml
index 00ac3b9fa5e..dfe504f7ddd 100644
--- a/reproducible_build.yaml
+++ b/reproducible_build.yaml
@@ -1,2 +1,2 @@
-release-notes-hash: 8c02811625ac7262d5ce34eb4cd7c5b0
-source-date-epoch: 1742481556
+release-notes-hash: 0aba23cb51bcf2ed752e8591c8f11e0f
+source-date-epoch: 1742823847