This is an automated email from the ASF dual-hosted git repository.
amoghdesai 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 ee5e21bb8a2 Support uuid ser/deser in serde (#59783)
ee5e21bb8a2 is described below
commit ee5e21bb8a286addf4571b45e19d8d30cb24f8dc
Author: Amogh Desai <[email protected]>
AuthorDate: Wed Dec 24 19:54:41 2025 +0530
Support uuid ser/deser in serde (#59783)
---
task-sdk/src/airflow/sdk/serde/serializers/uuid.py | 50 ++++++++++++++++++++++
task-sdk/tests/task_sdk/serde/test_serializers.py | 14 ++++++
2 files changed, 64 insertions(+)
diff --git a/task-sdk/src/airflow/sdk/serde/serializers/uuid.py
b/task-sdk/src/airflow/sdk/serde/serializers/uuid.py
new file mode 100644
index 00000000000..b1cdd4e5581
--- /dev/null
+++ b/task-sdk/src/airflow/sdk/serde/serializers/uuid.py
@@ -0,0 +1,50 @@
+# 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 typing import TYPE_CHECKING
+
+from airflow.sdk.module_loading import qualname
+
+if TYPE_CHECKING:
+ import uuid
+
+ from airflow.sdk.serde import U
+
+__version__ = 1
+
+serializers = ["uuid.UUID"]
+deserializers = serializers
+
+
+def serialize(o: object) -> tuple[U, str, int, bool]:
+ """Serialize a UUID object to a string representation."""
+ import uuid
+
+ if isinstance(o, uuid.UUID):
+ return str(o), qualname(o), __version__, True
+ return "", "", 0, False
+
+
+def deserialize(cls: type, version: int, data: str) -> uuid.UUID:
+ """Deserialize a string back to a UUID object."""
+ import uuid
+
+ if cls is uuid.UUID and isinstance(data, str):
+ return uuid.UUID(data)
+ raise TypeError(f"cannot deserialize {qualname(cls)} from {type(data)}")
diff --git a/task-sdk/tests/task_sdk/serde/test_serializers.py
b/task-sdk/tests/task_sdk/serde/test_serializers.py
index 58a9e701866..f8a57caa50f 100644
--- a/task-sdk/tests/task_sdk/serde/test_serializers.py
+++ b/task-sdk/tests/task_sdk/serde/test_serializers.py
@@ -18,6 +18,7 @@ from __future__ import annotations
import datetime
import decimal
+import uuid
from importlib import metadata
from typing import ClassVar
from unittest.mock import patch
@@ -661,3 +662,16 @@ class TestSerializers:
bad = {CLASSNAME: "", VERSION: 1, DATA: {}}
with pytest.raises(TypeError, match="classname cannot be empty"):
deserialize(bad)
+
+ @pytest.mark.parametrize(
+ "uuid_value",
+ [
+ pytest.param(uuid.uuid4(), id="uuid4"),
+ pytest.param(uuid.uuid1(), id="uuid1"),
+ ],
+ )
+ def test_uuid_roundtrip(self, uuid_value):
+ serialized = serialize(uuid_value)
+ deserialized = deserialize(serialized)
+ assert isinstance(deserialized, uuid.UUID)
+ assert uuid_value == deserialized