Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions azure/functions/durable_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,60 @@ class DurableClientConverter(meta.InConverter,
@classmethod
def has_implicit_output(cls) -> bool:
return False

@classmethod
def has_trigger_support(cls) -> bool:
return False

@classmethod
def check_input_type_annotation(cls, pytype: type) -> bool:
return issubclass(pytype, (str, bytes))

@classmethod
def check_output_type_annotation(cls, pytype: type) -> bool:
return issubclass(pytype, (str, bytes, bytearray))

@classmethod
def encode(cls, obj: typing.Any, *,
expected_type: typing.Optional[type]) -> meta.Datum:
if isinstance(obj, str):
return meta.Datum(type='string', value=obj)

elif isinstance(obj, (bytes, bytearray)):
return meta.Datum(type='bytes', value=bytes(obj))
elif obj is None:
return meta.Datum(type=None, value=obj)
elif isinstance(obj, dict):
return meta.Datum(type='dict', value=obj)
elif isinstance(obj, list):
return meta.Datum(type='list', value=obj)
elif isinstance(obj, bool):
return meta.Datum(type='bool', value=obj)
elif isinstance(obj, int):
return meta.Datum(type='int', value=obj)
elif isinstance(obj, float):
return meta.Datum(type='double', value=obj)
else:
raise NotImplementedError

@classmethod
def decode(cls, data: meta.Datum, *, trigger_metadata) -> typing.Any:
if data is None:
return None
data_type = data.type

if data_type == 'string':
result = data.value
elif data_type == 'bytes':
result = data.value
elif data_type == 'json':
result = data.value
elif data_type is None:
result = None
else:
raise ValueError(
'unexpected type of data received for the "generic" binding ',
repr(data_type)
)

return result
74 changes: 74 additions & 0 deletions tests/test_durable_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,77 @@ def test_enitity_trigger_converter_encode(self):

self.assertEqual(result.type, "json")
self.assertEqual(result.python_value, {'dummy_key': 'dummy_value'})

def test_durable_client_converter_has_trigger_support(self):
self.assertFalse(DurableClientConverter.has_trigger_support())

def test_durable_client_converter_check_input_type_annotation(self):
self.assertTrue(DurableClientConverter.check_input_type_annotation(str))
self.assertTrue(DurableClientConverter.check_input_type_annotation(bytes))
self.assertFalse(DurableClientConverter.check_input_type_annotation(int))

def test_durable_client_converter_check_output_type_annotation(self):
self.assertTrue(DurableClientConverter.check_output_type_annotation(str))
self.assertTrue(DurableClientConverter.check_output_type_annotation(bytes))
self.assertTrue(DurableClientConverter.check_output_type_annotation(bytearray))
self.assertFalse(DurableClientConverter.check_output_type_annotation(int))

def test_durable_client_converter_encode(self):
datum = DurableClientConverter.encode(obj="hello", expected_type=str)
self.assertEqual(datum.type, "string")
self.assertEqual(datum.value, "hello")

datum = DurableClientConverter.encode(obj=b"data", expected_type=bytes)
self.assertEqual(datum.type, "bytes")
self.assertEqual(datum.value, b"data")

datum = DurableClientConverter.encode(obj=None, expected_type=None)
self.assertIsNone(datum.type)
self.assertIsNone(datum.value)

datum = DurableClientConverter.encode(obj={"a": 1}, expected_type=dict)
self.assertEqual(datum.type, "dict")
self.assertEqual(datum.value, {"a": 1})

datum = DurableClientConverter.encode(obj=[1, 2], expected_type=list)
self.assertEqual(datum.type, "list")
self.assertEqual(datum.value, [1, 2])

datum = DurableClientConverter.encode(obj=42, expected_type=int)
self.assertEqual(datum.type, "int")
self.assertEqual(datum.value, 42)

datum = DurableClientConverter.encode(obj=3.14, expected_type=float)
self.assertEqual(datum.type, "double")
self.assertEqual(datum.value, 3.14)

datum = DurableClientConverter.encode(obj=True, expected_type=bool)
self.assertEqual(datum.type, "bool")
self.assertTrue(datum.value)

with self.assertRaises(NotImplementedError):
DurableClientConverter.encode(obj=set([1, 2]), expected_type=set)

def test_durable_client_converter_decode(self):
data = Datum(type="string", value="abc")
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
self.assertEqual(result, "abc")

data = Datum(type="bytes", value=b"123")
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
self.assertEqual(result, b"123")

data = Datum(type="json", value={"key": "val"})
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
self.assertEqual(result, {"key": "val"})

data = Datum(type=None, value=None)
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
self.assertIsNone(result)

result = DurableClientConverter.decode(data=None, trigger_metadata=None)
self.assertIsNone(result)

data = Datum(type="weird", value="???")
with self.assertRaises(ValueError):
DurableClientConverter.decode(data=data, trigger_metadata=None)