Skip to content

Commit 1059e5c

Browse files
committed
Merge branch 'hallvictoria/simplified-mcp-decorator' of https://github.com/Azure/azure-functions-python-library into hallvictoria/simplified-mcp-decorator
2 parents 68ddad8 + 1a7a15d commit 1059e5c

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

azure/functions/durable_functions.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,60 @@ 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, bool):
164+
return meta.Datum(type='bool', value=obj)
165+
elif isinstance(obj, int):
166+
return meta.Datum(type='int', value=obj)
167+
elif isinstance(obj, float):
168+
return meta.Datum(type='double', value=obj)
169+
else:
170+
raise NotImplementedError
171+
172+
@classmethod
173+
def decode(cls, data: meta.Datum, *, trigger_metadata) -> typing.Any:
174+
if data is None:
175+
return None
176+
data_type = data.type
177+
178+
if data_type == 'string':
179+
result = data.value
180+
elif data_type == 'bytes':
181+
result = data.value
182+
elif data_type == 'json':
183+
result = data.value
184+
elif data_type is None:
185+
result = None
186+
else:
187+
raise ValueError(
188+
'unexpected type of data received for the "generic" binding ',
189+
repr(data_type)
190+
)
191+
192+
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(obj="hello", expected_type=str)
290+
self.assertEqual(datum.type, "string")
291+
self.assertEqual(datum.value, "hello")
292+
293+
datum = DurableClientConverter.encode(obj=b"data", expected_type=bytes)
294+
self.assertEqual(datum.type, "bytes")
295+
self.assertEqual(datum.value, b"data")
296+
297+
datum = DurableClientConverter.encode(obj=None, expected_type=None)
298+
self.assertIsNone(datum.type)
299+
self.assertIsNone(datum.value)
300+
301+
datum = DurableClientConverter.encode(obj={"a": 1}, expected_type=dict)
302+
self.assertEqual(datum.type, "dict")
303+
self.assertEqual(datum.value, {"a": 1})
304+
305+
datum = DurableClientConverter.encode(obj=[1, 2], expected_type=list)
306+
self.assertEqual(datum.type, "list")
307+
self.assertEqual(datum.value, [1, 2])
308+
309+
datum = DurableClientConverter.encode(obj=42, expected_type=int)
310+
self.assertEqual(datum.type, "int")
311+
self.assertEqual(datum.value, 42)
312+
313+
datum = DurableClientConverter.encode(obj=3.14, expected_type=float)
314+
self.assertEqual(datum.type, "double")
315+
self.assertEqual(datum.value, 3.14)
316+
317+
datum = DurableClientConverter.encode(obj=True, expected_type=bool)
318+
self.assertEqual(datum.type, "bool")
319+
self.assertTrue(datum.value)
320+
321+
with self.assertRaises(NotImplementedError):
322+
DurableClientConverter.encode(obj=set([1, 2]), expected_type=set)
323+
324+
def test_durable_client_converter_decode(self):
325+
data = Datum(type="string", value="abc")
326+
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
327+
self.assertEqual(result, "abc")
328+
329+
data = Datum(type="bytes", value=b"123")
330+
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
331+
self.assertEqual(result, b"123")
332+
333+
data = Datum(type="json", value={"key": "val"})
334+
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
335+
self.assertEqual(result, {"key": "val"})
336+
337+
data = Datum(type=None, value=None)
338+
result = DurableClientConverter.decode(data=data, trigger_metadata=None)
339+
self.assertIsNone(result)
340+
341+
result = DurableClientConverter.decode(data=None, trigger_metadata=None)
342+
self.assertIsNone(result)
343+
344+
data = Datum(type="weird", value="???")
345+
with self.assertRaises(ValueError):
346+
DurableClientConverter.decode(data=data, trigger_metadata=None)

0 commit comments

Comments
 (0)