This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new e9ff93af8 fix(python): fix python module/type serialize (#2688)
e9ff93af8 is described below
commit e9ff93af8cf834fa3a7ef7c575e98d5c3fc4d495
Author: Shawn Yang <[email protected]>
AuthorDate: Tue Sep 30 14:40:52 2025 +0800
fix(python): fix python module/type serialize (#2688)
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
<!-- Describe the details of this PR. -->
## Related issues
<!--
Is there any related issue? If this PR closes them you say say
fix/closes:
- #xxxx0
- #xxxx1
- Fixes #xxxx2
-->
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fory/issues/new/choose) describing the
need to do so and update the document if necessary.
Delete section if not applicable.
-->
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
<!--
When the PR has an impact on performance (if you don't know whether the
PR will have an impact on performance, you can submit the PR first, and
if it will have impact on performance, the code reviewer will explain
it), be sure to attach a benchmark data here.
Delete section if not applicable.
-->
---
python/pyfory/_registry.py | 4 +++
python/pyfory/serializer.py | 26 ++++++++++++++-
python/pyfory/tests/test_class_serializer.py | 48 ++++++++++++++++++++++++++++
python/pyfory/tests/test_serializer.py | 15 +++++++++
4 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/python/pyfory/_registry.py b/python/pyfory/_registry.py
index de64e25ee..7605c2606 100644
--- a/python/pyfory/_registry.py
+++ b/python/pyfory/_registry.py
@@ -60,6 +60,8 @@ from pyfory.serializer import (
FunctionSerializer,
ObjectSerializer,
TypeSerializer,
+ ModuleSerializer,
+ MappingProxySerializer,
MethodSerializer,
UnsupportedSerializer,
NativeFuncMethodSerializer,
@@ -216,7 +218,9 @@ class TypeResolver:
register(slice, serializer=SliceSerializer)
register(np.ndarray, serializer=NDArraySerializer)
register(array.array, serializer=DynamicPyArraySerializer)
+ register(types.MappingProxyType, serializer=MappingProxySerializer)
if not self.require_registration:
+ register(types.ModuleType, serializer=ModuleSerializer)
self._internal_py_serializer_map = {
ReduceSerializer: (self._stub_cls("__Reduce__"),
self._next_type_id()),
TypeSerializer: (self._stub_cls("__Type__"),
self._next_type_id()),
diff --git a/python/pyfory/serializer.py b/python/pyfory/serializer.py
index 984d73e47..bea983862 100644
--- a/python/pyfory/serializer.py
+++ b/python/pyfory/serializer.py
@@ -252,6 +252,31 @@ class TypeSerializer(Serializer):
return cls
+class ModuleSerializer(Serializer):
+ """Serializer for python module"""
+
+ def __init__(self, fory):
+ super().__init__(fory, types.ModuleType)
+
+ def write(self, buffer, value):
+ buffer.write_string(value.__name__)
+
+ def read(self, buffer):
+ mod = buffer.read_string()
+ return importlib.import_module(mod)
+
+
+class MappingProxySerializer(Serializer):
+ def __init__(self, fory):
+ super().__init__(fory, types.MappingProxyType)
+
+ def write(self, buffer, value):
+ self.fory.serialize_ref(buffer, dict(value))
+
+ def read(self, buffer):
+ return types.MappingProxyType(self.fory.deserialize_ref(buffer))
+
+
class PandasRangeIndexSerializer(Serializer):
__slots__ = "_cached"
@@ -1131,7 +1156,6 @@ class
FunctionSerializer(CrossLanguageCompatibleSerializer):
self.fory.serialize_ref(buffer, self_obj)
buffer.write_string(func_name)
return
- import types
# Regular function or lambda
code = func.__code__
diff --git a/python/pyfory/tests/test_class_serializer.py
b/python/pyfory/tests/test_class_serializer.py
index e77e740b1..77fe3af8c 100644
--- a/python/pyfory/tests/test_class_serializer.py
+++ b/python/pyfory/tests/test_class_serializer.py
@@ -16,6 +16,7 @@
# under the License.
from pyfory import Fory
+from dataclasses import dataclass
def test_local_class_serialization():
@@ -319,3 +320,50 @@ def test_local_class_with_multiple_inheritance():
assert instance2.combined_method() == "AB_check"
assert instance1.method_a() == "A"
assert instance2.method_b() == "B"
+
+
+@dataclass
+class Person:
+ name: str
+ age: int
+
+ def f(self, x):
+ return self.age * x
+
+ @classmethod
+ def g(cls, x):
+ return 10 * x
+
+ @staticmethod
+ def h(x):
+ return 10 * x
+
+
+def test_dataclass_serialize():
+ fory = Fory(xlang=False, ref=True, strict=False)
+
+ # serialize global class
+ @dataclass
+ class LocalPerson:
+ name: str
+ age: int
+
+ def f(self, x):
+ return self.age * x
+
+ @classmethod
+ def g(cls, x):
+ return 10 * x
+
+ @staticmethod
+ def h(x):
+ return 10 * x
+
+ for cls in [LocalPerson, LocalPerson]:
+ assert str(fory.loads(fory.dumps(cls))("Bob", 25)) == str(cls("Bob",
25))
+ # serialize global class instance method
+ assert fory.loads(fory.dumps(cls("Bob", 20).f))(10) == 200
+ # serialize global class class method
+ assert fory.loads(fory.dumps(cls.g))(10) == 100
+ # serialize global class static method
+ assert fory.loads(fory.dumps(cls.h))(10) == 100
diff --git a/python/pyfory/tests/test_serializer.py
b/python/pyfory/tests/test_serializer.py
index 39743aa2e..ee91a09a8 100644
--- a/python/pyfory/tests/test_serializer.py
+++ b/python/pyfory/tests/test_serializer.py
@@ -710,5 +710,20 @@ def test_dumps_loads():
assert obj == new_obj
+def test_module_serialize():
+ fory = Fory(xlang=False, ref=True, strict=False)
+ assert fory.loads(fory.dumps(pyfory)) is pyfory
+ from pyfory import serializer
+ from pyfory import _serialization
+
+ assert fory.loads(fory.dumps(serializer)) is serializer
+ assert fory.loads(fory.dumps(_serialization)) is _serialization
+ import threading
+
+ assert fory.loads(fory.dumps(threading)) is threading
+ # check only serialize module name
+ assert len(fory.dumps(threading)) < 20
+
+
if __name__ == "__main__":
test_string()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]