Skip to content

Commit bf214ea

Browse files
committed
add full DurableClientConverter class
1 parent 6de1aa0 commit bf214ea

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

azure/functions/durable_functions.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,62 @@ class DurableClientConverter(meta.InConverter,
133133
@classmethod
134134
def has_implicit_output(cls) -> bool:
135135
return False
136+
137+
@classmethod
138+
def has_trigger_support(cls) -> bool:
139+
return False
140+
141+
@classmethod
142+
def check_input_type_annotation(cls, pytype: type) -> bool:
143+
return issubclass(pytype, (str, bytes))
144+
145+
@classmethod
146+
def check_output_type_annotation(cls, pytype: type) -> bool:
147+
return issubclass(pytype, (str, bytes, bytearray))
148+
149+
@classmethod
150+
def encode(cls, obj: typing.Any, *,
151+
expected_type: typing.Optional[type]) -> meta.Datum:
152+
if isinstance(obj, str):
153+
return meta.Datum(type='string', value=obj)
154+
155+
elif isinstance(obj, (bytes, bytearray)):
156+
return meta.Datum(type='bytes', value=bytes(obj))
157+
elif obj is None:
158+
return meta.Datum(type=None, value=obj)
159+
elif isinstance(obj, dict):
160+
return meta.Datum(type='dict', value=obj)
161+
elif isinstance(obj, list):
162+
return meta.Datum(type='list', value=obj)
163+
elif isinstance(obj, int):
164+
return meta.Datum(type='int', value=obj)
165+
elif isinstance(obj, float):
166+
return meta.Datum(type='double', value=obj)
167+
elif isinstance(obj, bool):
168+
return meta.Datum(type='bool', value=obj)
169+
else:
170+
raise NotImplementedError
171+
172+
@classmethod
173+
def decode(cls, data: meta.Datum, *, trigger_metadata) -> typing.Any:
174+
# Enabling support for Dapr bindings
175+
# https://github.com/Azure/azure-functions-python-worker/issues/1316
176+
if data is None:
177+
return None
178+
data_type = data.type
179+
180+
if data_type == 'string':
181+
result = data.value
182+
elif data_type == 'bytes':
183+
result = data.value
184+
elif data_type == 'json':
185+
result = data.value
186+
elif data_type is None:
187+
result = None
188+
else:
189+
raise ValueError(
190+
'unexpected type of data received for the "generic" binding ',
191+
repr(data_type)
192+
)
193+
194+
return result

tests/test_durable_functions.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,77 @@ def test_enitity_trigger_converter_encode(self):
270270

271271
self.assertEqual(result.type, "json")
272272
self.assertEqual(result.python_value, {'dummy_key': 'dummy_value'})
273+
274+
def test_durable_client_converter_has_trigger_support(self):
275+
self.assertFalse(DurableClientConverter.has_trigger_support())
276+
277+
def test_durable_client_converter_check_input_type_annotation(self):
278+
self.assertTrue(DurableClientConverter.check_input_type_annotation(str))
279+
self.assertTrue(DurableClientConverter.check_input_type_annotation(bytes))
280+
self.assertFalse(DurableClientConverter.check_input_type_annotation(int))
281+
282+
def test_durable_client_converter_check_output_type_annotation(self):
283+
self.assertTrue(DurableClientConverter.check_output_type_annotation(str))
284+
self.assertTrue(DurableClientConverter.check_output_type_annotation(bytes))
285+
self.assertTrue(DurableClientConverter.check_output_type_annotation(bytearray))
286+
self.assertFalse(DurableClientConverter.check_output_type_annotation(int))
287+
288+
def test_durable_client_converter_encode(self):
289+
datum = DurableClientConverter.encode("hello")
290+
self.assertEqual(datum.type, "string")
291+
self.assertEqual(datum.value, "hello")
292+
293+
datum = DurableClientConverter.encode(b"data")
294+
self.assertEqual(datum.type, "bytes")
295+
self.assertEqual(datum.value, b"data")
296+
297+
datum = DurableClientConverter.encode(None)
298+
self.assertIsNone(datum.type)
299+
self.assertIsNone(datum.value)
300+
301+
datum = DurableClientConverter.encode({"a": 1})
302+
self.assertEqual(datum.type, "dict")
303+
self.assertEqual(datum.value, {"a": 1})
304+
305+
datum = DurableClientConverter.encode([1, 2])
306+
self.assertEqual(datum.type, "list")
307+
self.assertEqual(datum.value, [1, 2])
308+
309+
datum = DurableClientConverter.encode(42)
310+
self.assertEqual(datum.type, "int")
311+
self.assertEqual(datum.value, 42)
312+
313+
datum = DurableClientConverter.encode(3.14)
314+
self.assertEqual(datum.type, "double")
315+
self.assertEqual(datum.value, 3.14)
316+
317+
datum = DurableClientConverter.encode(True)
318+
self.assertEqual(datum.type, "bool")
319+
self.assertTrue(datum.value)
320+
321+
with self.assertRaises(NotImplementedError):
322+
DurableClientConverter.encode(set([1, 2]))
323+
324+
def test_durable_client_converter_decode(self):
325+
data = Datum(type="string", value="abc")
326+
result = DurableClientConverter.decode(data, trigger_metadata=None)
327+
self.assertEqual(result, "abc")
328+
329+
data = Datum(type="bytes", value=b"123")
330+
result = DurableClientConverter.decode(data, trigger_metadata=None)
331+
self.assertEqual(result, b"123")
332+
333+
data = Datum(type="json", value={"key": "val"})
334+
result = DurableClientConverter.decode(data, trigger_metadata=None)
335+
self.assertEqual(result, {"key": "val"})
336+
337+
data = Datum(type=None, value=None)
338+
result = DurableClientConverter.decode(data, trigger_metadata=None)
339+
self.assertIsNone(result)
340+
341+
result = DurableClientConverter.decode(None, trigger_metadata=None)
342+
self.assertIsNone(result)
343+
344+
data = Datum(type="weird", value="???")
345+
with self.assertRaises(ValueError):
346+
DurableClientConverter.decode(data, trigger_metadata=None)

0 commit comments

Comments
 (0)