Skip to content

Commit 60042c2

Browse files
authored
Support dataclasses serde (#74)
This commit adds an optional dependency to help with dataclass serialization. To use that one need to `pip install sdk_python[serde]`.
1 parent 76b5863 commit 60042c2

File tree

3 files changed

+42
-3
lines changed

3 files changed

+42
-3
lines changed

examples/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
hypercorn
22
restate_sdk
33
pydantic
4+
dacite

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ authors = [
1717
test = ["pytest", "hypercorn"]
1818
lint = ["mypy", "pylint"]
1919
harness = ["testcontainers", "hypercorn", "httpx"]
20+
serde = ["dacite", "pydantic"]
2021

2122
[build-system]
2223
requires = ["maturin>=1.6,<2.0"]

python/restate/serde.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import json
1414
import typing
1515

16+
from dataclasses import asdict, is_dataclass
17+
1618
def try_import_pydantic_base_model():
1719
"""
1820
Try to import PydanticBaseModel from Pydantic.
@@ -26,7 +28,39 @@ class Dummy: # pylint: disable=too-few-public-methods
2628

2729
return Dummy
2830

31+
def try_import_from_dacite():
32+
"""
33+
Try to import from_dict from dacite.
34+
"""
35+
try:
36+
from dacite import from_dict # type: ignore # pylint: disable=import-outside-toplevel
37+
38+
return asdict, from_dict
39+
40+
except ImportError:
41+
42+
def to_dict(obj):
43+
"""a dummy function when dacite is not available"""
44+
raise RuntimeError("Trying to deserialize into a @dataclass." \
45+
"Please add the optional dependencies needed." \
46+
"use pip install restate-sdk[serde] "
47+
"or" \
48+
" pip install restate-sdk[all] to install all dependencies.")
49+
50+
51+
def from_dict(a,b): # pylint: disable=too-few-public-methods,unused-argument
52+
"""a dummy function when dacite is not available"""
53+
54+
raise RuntimeError("Trying to deserialize into a @dataclass." \
55+
"Please add the optional dependencies needed." \
56+
"use pip install restate-sdk[serde] "
57+
"or" \
58+
" pip install restate-sdk[all] to install all dependencies.")
59+
60+
return to_dict, from_dict
61+
2962
PydanticBaseModel = try_import_pydantic_base_model()
63+
DaciteToDict, DaciteFromDict = try_import_from_dacite()
3064

3165
T = typing.TypeVar('T')
3266
I = typing.TypeVar('I')
@@ -170,6 +204,9 @@ def deserialize(self, buf: bytes) -> typing.Optional[I]:
170204
return None
171205
if is_pydantic(self.type_hint):
172206
return self.type_hint.model_validate_json(buf) # type: ignore
207+
if is_dataclass(self.type_hint):
208+
data = json.loads(buf)
209+
return DaciteFromDict(self.type_hint, data)
173210
return json.loads(buf)
174211

175212
def serialize(self, obj: typing.Optional[I]) -> bytes:
@@ -183,13 +220,13 @@ def serialize(self, obj: typing.Optional[I]) -> bytes:
183220
Returns:
184221
bytes: The serialized byte array.
185222
"""
186-
187223
if obj is None:
188224
return bytes()
189-
190225
if is_pydantic(self.type_hint):
191226
return obj.model_dump_json().encode("utf-8") # type: ignore[attr-defined]
192-
227+
if is_dataclass(obj):
228+
data = DaciteToDict(obj) # type: ignore
229+
return json.dumps(data).encode("utf-8")
193230
return json.dumps(obj).encode("utf-8")
194231

195232

0 commit comments

Comments
 (0)