This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new dfb6a89df79 Vendor-in json-merge-patch and add `--no-dev` to direct uv
tool install (#48210)
dfb6a89df79 is described below
commit dfb6a89df7906421309ab6275aef76775e51d2db
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Mar 25 12:49:32 2025 +0100
Vendor-in json-merge-patch and add `--no-dev` to direct uv tool install
(#48210)
The setuptools 78.0.1 started to fail old packages that had dash
metadata keys and had only .sdist installation. This caused failures
of three of our dependencies:
* json-merge-patch
* pykylin
* pyspark
The `josn-merge-patch` is a library released in 2017 (v 0.2) that implements
the [RFC7386](https://datatracker.ietf.org/doc/html/rfc7386) standard
of patching json. It has been used in only one place in our repo
in google provider, in order to merge json patches (well - obvious :).
Seems like the best approach is to vendor-in the code (70 lines or so)
rather than rely on 2017-released package
The change also revealed that in pre-commit we could use `--no-dev`
flag to skip installing development dependencies, because
we only care about the codegen deps.
---
.pre-commit-config.yaml | 5 +-
generated/provider_dependencies.json | 1 -
providers/google/README.rst | 1 -
providers/google/pyproject.toml | 1 -
.../google/3rd-party-licenses/LICENSES.txt | 14 ++++
.../providers/google/3rd-party-licenses/NOTICE | 15 ++++
.../airflow/providers/google/_vendor/__init__.py | 0
.../providers/google/_vendor/json_merge_patch.py | 91 ++++++++++++++++++++++
.../providers/google/cloud/operators/compute.py | 2 +-
.../airflow/providers/google/get_provider_info.py | 1 -
pyproject.toml | 1 +
11 files changed, 124 insertions(+), 8 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 54ae2510b38..85e23c4da1f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -96,7 +96,7 @@ repos:
- --fuzzy-match-generates-todo
- id: insert-license
name: Add license for all Python files
- exclude: ^\.github/.*$
+ exclude: ^\.github/.*$|^.*/_vendor/.*$
files: \.py$|\.pyi$
args:
- --comment-style
@@ -1369,11 +1369,10 @@ repos:
- id: generate-tasksdk-datamodels
name: Generate Datamodels for TaskSDK client
language: python
- entry: uv run -p 3.12 --no-progress --active --group codegen --project
apache-airflow-task-sdk --directory task-sdk -s dev/generate_task_sdk_models.py
+ entry: uv run -p 3.12 --no-dev --no-progress --active --group codegen
--project apache-airflow-task-sdk --directory task-sdk -s
dev/generate_task_sdk_models.py
pass_filenames: false
files: ^airflow-core/src/airflow/api_fastapi/execution_api/.*\.py$
require_serial: true
- additional_dependencies: ['rich>=12.4.4']
- id: update-er-diagram
name: Update ER diagram
language: python
diff --git a/generated/provider_dependencies.json
b/generated/provider_dependencies.json
index 3f2d5128355..0474ffdaa2a 100644
--- a/generated/provider_dependencies.json
+++ b/generated/provider_dependencies.json
@@ -710,7 +710,6 @@
"grpcio-gcp>=0.2.2",
"httpx>=0.25.0",
"immutabledict>=4.2.0",
- "json-merge-patch>=0.2",
"looker-sdk>=22.4.0,!=24.18.0",
"pandas-gbq>=0.7.0",
"pandas>=2.1.2,<2.2",
diff --git a/providers/google/README.rst b/providers/google/README.rst
index e485ab507cb..a403613d837 100644
--- a/providers/google/README.rst
+++ b/providers/google/README.rst
@@ -116,7 +116,6 @@ PIP package Version required
``google-cloud-batch`` ``>=0.13.0``
``grpcio-gcp`` ``>=0.2.2``
``httpx`` ``>=0.25.0``
-``json-merge-patch`` ``>=0.2``
``looker-sdk`` ``>=22.4.0,!=24.18.0``
``pandas-gbq`` ``>=0.7.0``
``pandas`` ``>=2.1.2,<2.2``
diff --git a/providers/google/pyproject.toml b/providers/google/pyproject.toml
index 597e585a7db..43ab5dffacb 100644
--- a/providers/google/pyproject.toml
+++ b/providers/google/pyproject.toml
@@ -119,7 +119,6 @@ dependencies = [
"google-cloud-batch>=0.13.0",
"grpcio-gcp>=0.2.2",
"httpx>=0.25.0",
- "json-merge-patch>=0.2",
# looker-sdk 24.18.0 has issues in import looker_sdk.rtl, No module named
looker_sdk.rtl
# See https://github.com/looker-open-source/sdk-codegen/issues/1518
"looker-sdk>=22.4.0,!=24.18.0",
diff --git
a/providers/google/src/airflow/providers/google/3rd-party-licenses/LICENSES.txt
b/providers/google/src/airflow/providers/google/3rd-party-licenses/LICENSES.txt
new file mode 100644
index 00000000000..3ea6a4c7a40
--- /dev/null
+++
b/providers/google/src/airflow/providers/google/3rd-party-licenses/LICENSES.txt
@@ -0,0 +1,14 @@
+BSD 3-Clause "New" or "Revised" License
+
+Copyright (c) 2015, Open Data Services Coop
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROF [...]
diff --git
a/providers/google/src/airflow/providers/google/3rd-party-licenses/NOTICE
b/providers/google/src/airflow/providers/google/3rd-party-licenses/NOTICE
new file mode 100644
index 00000000000..a045ba56e58
--- /dev/null
+++ b/providers/google/src/airflow/providers/google/3rd-party-licenses/NOTICE
@@ -0,0 +1,15 @@
+Apache Airflow
+Copyright 2016-2025 The Apache Software Foundation
+
+This product includes software developed at The Apache Software
+Foundation (http://www.apache.org/).
+
+=======================================================================
+
+json-merge-patch:
+-----------------
+
+This product contains a modified portion of 'json-merge-patch' developed by
Open Data Services Coop
+https://github.com/OpenDataServices/json-merge-patch).
+
+Copyright (c) 2015, Open Data Services Coop
diff --git a/providers/google/src/airflow/providers/google/_vendor/__init__.py
b/providers/google/src/airflow/providers/google/_vendor/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git
a/providers/google/src/airflow/providers/google/_vendor/json_merge_patch.py
b/providers/google/src/airflow/providers/google/_vendor/json_merge_patch.py
new file mode 100644
index 00000000000..3d653d8c815
--- /dev/null
+++ b/providers/google/src/airflow/providers/google/_vendor/json_merge_patch.py
@@ -0,0 +1,91 @@
+# BSD 3-Clause "New" or "Revised" License
+#
+# Copyright (c) 2015, Open Data Services Coop
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PR [...]
+
+from collections import OrderedDict
+import sys
+
+def merge(*objs, **kw):
+ result = objs[0]
+ for obj in objs[1:]:
+ result = merge_obj(result, obj, kw.get('position'))
+ return result
+
+def move_to_start(result, key):
+ result_copy = result.copy()
+ result.clear()
+ result[key] = result_copy.pop(key)
+ result.update(result_copy)
+
+def merge_obj(result, obj, position=None):
+ if not isinstance(result, dict):
+ result = OrderedDict() if position else {}
+
+ if not isinstance(obj, dict):
+ return obj
+
+ if position:
+ if position not in ('first', 'last'):
+ raise ValueError("position can either be first or last")
+ if not isinstance(result, OrderedDict) or not isinstance(obj,
OrderedDict):
+ raise ValueError("If using position all dicts need to be
OrderedDicts")
+
+ for key, value in obj.items():
+ if isinstance(value, dict):
+ target = result.get(key)
+ if isinstance(target, dict):
+ merge_obj(target, value, position)
+ continue
+ result[key] = OrderedDict() if position else {}
+ if position and position == 'first':
+ if sys.version_info >= (3, 2):
+ result.move_to_end(key, False)
+ else:
+ move_to_start(result, key)
+ merge_obj(result[key], value, position)
+ continue
+ if value is None:
+ result.pop(key, None)
+ continue
+ if key not in result and position == 'first':
+ result[key] = value
+ if sys.version_info >= (3, 2):
+ result.move_to_end(key, False)
+ else:
+ move_to_start(result, key)
+ else:
+ result[key] = value
+
+ return result
+
+def create_patch(source, target):
+ return create_patch_obj(source, target)
+
+def create_patch_obj(source, target):
+ if not isinstance(target, dict) or not isinstance(source, dict):
+ return target
+
+ result = {}
+
+ for key in set(source.keys()) - set(target.keys()):
+ result[key] = None
+
+ for key, value in target.items():
+ if key not in source:
+ result[key] = value
+ continue
+ if value == source[key]:
+ continue
+ result[key] = create_patch_obj(source[key], value)
+ return result
diff --git
a/providers/google/src/airflow/providers/google/cloud/operators/compute.py
b/providers/google/src/airflow/providers/google/cloud/operators/compute.py
index b43305c13af..e797e193c3b 100644
--- a/providers/google/src/airflow/providers/google/cloud/operators/compute.py
+++ b/providers/google/src/airflow/providers/google/cloud/operators/compute.py
@@ -25,9 +25,9 @@ from typing import TYPE_CHECKING, Any
from google.api_core import exceptions
from google.cloud.compute_v1.types import Instance, InstanceGroupManager,
InstanceTemplate
-from json_merge_patch import merge
from airflow.exceptions import AirflowException
+from airflow.providers.google._vendor.json_merge_patch import merge
from airflow.providers.google.cloud.hooks.compute import ComputeEngineHook
from airflow.providers.google.cloud.links.compute import (
ComputeInstanceDetailsLink,
diff --git a/providers/google/src/airflow/providers/google/get_provider_info.py
b/providers/google/src/airflow/providers/google/get_provider_info.py
index 29e5899f1d4..7d3b3d3eb0f 100644
--- a/providers/google/src/airflow/providers/google/get_provider_info.py
+++ b/providers/google/src/airflow/providers/google/get_provider_info.py
@@ -1640,7 +1640,6 @@ def get_provider_info():
"google-cloud-batch>=0.13.0",
"grpcio-gcp>=0.2.2",
"httpx>=0.25.0",
- "json-merge-patch>=0.2",
"looker-sdk>=22.4.0,!=24.18.0",
"pandas-gbq>=0.7.0",
"pandas>=2.1.2,<2.2",
diff --git a/pyproject.toml b/pyproject.toml
index e3e8c6ab996..b65603ce7bf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -797,6 +797,7 @@ dev = [
required-version = ">=0.6.3"
no-build-isolation-package = ["sphinx-redoc"]
+
[tool.uv.sources]
# These names must match the names as defined in the pyproject.toml of the
workspace items,
# *not* the workspace folder paths