Skip to content

Commit e22926b

Browse files
committed
Fix fork on callable
1 parent 7335985 commit e22926b

2 files changed

Lines changed: 84 additions & 7 deletions

File tree

sqlalchemy_serializer/serializer.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def is_forkable(self, value):
191191
def fork(self, key: str) -> "Serializer":
192192
"""
193193
Return new serializer for a key
194-
:return: serialized value
194+
:return: serializer
195195
"""
196196
serializer = Serializer(**self.opts._asdict())
197197
serializer.set_serialization_depth(self.serialization_depth + 1)
@@ -200,24 +200,47 @@ def fork(self, key: str) -> "Serializer":
200200
logger.debug("Fork serializer for key:%s", key)
201201
return serializer
202202

203-
def serialize(self, value):
203+
def serialize(self, value, **kwargs):
204+
"""
205+
Orchestrates the serialization process.
206+
207+
Args:
208+
value: The value to be serialized.
209+
**kwargs: Only to ensure that no key is passed
210+
since None and Ellipsis are valid keys.
211+
212+
Returns:
213+
The serialized value.
214+
"""
204215
if self.is_valid_callable(value):
205216
value = value()
206217
logger.debug("Process callable resulting type:%s", get_type(value))
207218

219+
if kwargs:
220+
if "key" in kwargs:
221+
# since None and ... are valid keys
222+
return self.serialize_with_fork(value=value, key=kwargs["key"])
223+
raise ValueError("Malformed structure of kwargs. Only `key` accepted")
224+
225+
return self.apply_callback(value=value)
226+
227+
def apply_callback(self, value):
228+
"""
229+
Apply a proper callback to serialize the value
230+
:return: serialized value
231+
:raises: IsNotSerializable
232+
"""
208233
for types, callback in self.serialize_types:
209234
if isinstance(value, types):
210235
return callback(value)
211236
raise IsNotSerializable(f"Unserializable type:{get_type(value)} value:{value}")
212237

213238
def serialize_with_fork(self, value, key):
214-
# TODO: merge this function with the serialize function
215-
# TODO: this should be performed after is_valid_callable check
216239
serializer = self
217240
if self.is_forkable(value):
218241
serializer = self.fork(key=key)
219242

220-
return serializer.serialize(value)
243+
return serializer.apply_callback(value)
221244

222245
def serialize_iter(self, value: Iterable) -> list:
223246
res = []
@@ -239,7 +262,7 @@ def serialize_dict(self, value: dict) -> dict:
239262
if self.schema.is_included(k): # TODO: Skip check if is NOT greedy
240263
logger.debug("Serialize key:%s type:%s of dict", k, get_type(v))
241264

242-
res[k] = self.serialize_with_fork(value=v, key=k)
265+
res[k] = self.serialize(value=v, key=k)
243266
else:
244267
logger.debug("Skip key:%s of dict", k)
245268
return res
@@ -261,7 +284,7 @@ def serialize_model(self, value) -> dict:
261284
get_type(v),
262285
get_type(value),
263286
)
264-
res[k] = self.serialize_with_fork(value=v, key=k)
287+
res[k] = self.serialize(value=v, key=k)
265288

266289
else:
267290
logger.debug("Skip key:%s of model:%s", k, get_type(value))
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from decimal import Decimal
2+
import pytest
3+
4+
5+
@pytest.fixture
6+
def test_dict():
7+
return {
8+
"int": 123,
9+
"float": 12.3,
10+
"decimal": Decimal("12.3"),
11+
"str": "!@#$%^",
12+
"callable": lambda: {"str": "value", "int": 1234},
13+
"list_of_dicts": [
14+
{
15+
"str": "string",
16+
"int": 1235,
17+
}
18+
],
19+
}
20+
21+
22+
def test_serializer_serialize_dict__success(get_serializer, test_dict):
23+
serializer = get_serializer()
24+
result = serializer.serialize_dict(test_dict)
25+
assert result == {
26+
"int": 123,
27+
"float": 12.3,
28+
"decimal": "12.3",
29+
"str": "!@#$%^",
30+
"callable": {"str": "value", "int": 1234},
31+
"list_of_dicts": [
32+
{
33+
"str": "string",
34+
"int": 1235,
35+
}
36+
],
37+
}
38+
39+
40+
@pytest.mark.parametrize(
41+
"only, expected",
42+
[
43+
(("int",), {"int": 123}),
44+
(("callable.int",), {"callable": {"int": 1234}}),
45+
(("list_of_dicts.int",), {"list_of_dicts": [{"int": 1235}]}),
46+
],
47+
)
48+
def test_serializer_serialize_dict__fork_success(
49+
get_serializer, test_dict, only, expected
50+
):
51+
serializer = get_serializer()
52+
serializer.schema.update(only=only)
53+
result = serializer.serialize_dict(test_dict)
54+
assert result == expected

0 commit comments

Comments
 (0)