From 839bfbbc2fb5836cba80fd7aeaf5cffe555abe7c Mon Sep 17 00:00:00 2001 From: wangbill Date: Mon, 23 Sep 2024 10:55:22 -0700 Subject: [PATCH 01/10] chore: allow-forked-pr-to-run-labeler (#245) --- .github/workflows/label.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 29fe3b65..3274d56a 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -1,6 +1,6 @@ name: "Pull Request Labeler" on: - pull_request: + pull_request_target: paths: - '**/__init__.py' jobs: From 87cd09230fc9f35e90857025fcfb124271c9e48f Mon Sep 17 00:00:00 2001 From: hallvictoria <59299039+hallvictoria@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:12:56 -0500 Subject: [PATCH 02/10] build: update Python Library Version to 1.21.0 (#246) Co-authored-by: AzureFunctionsPython --- azure/functions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/__init__.py b/azure/functions/__init__.py index 7de175dd..86565e37 100644 --- a/azure/functions/__init__.py +++ b/azure/functions/__init__.py @@ -98,4 +98,4 @@ 'BlobSource' ) -__version__ = '1.21.0b3' +__version__ = '1.21.0' From 4307c75430f36148d8e812113aaeab93fa218596 Mon Sep 17 00:00:00 2001 From: guptaheena <150243077+guptaheena@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:04:04 +0530 Subject: [PATCH 03/10] feat: Add MySql Binding Support V1 (#243) * mysql binding support * fix linting * Update __init__.py * fix indentation --------- Co-authored-by: wangbill Co-authored-by: Gavin Aguiar <80794152+gavin-aguiar@users.noreply.github.com> --- azure/functions/__init__.py | 4 + azure/functions/_mysql.py | 71 +++++++++ azure/functions/mysql.py | 78 ++++++++++ tests/test_mysql.py | 293 ++++++++++++++++++++++++++++++++++++ 4 files changed, 446 insertions(+) create mode 100644 azure/functions/_mysql.py create mode 100644 azure/functions/mysql.py create mode 100644 tests/test_mysql.py diff --git a/azure/functions/__init__.py b/azure/functions/__init__.py index 86565e37..eee6c1c9 100644 --- a/azure/functions/__init__.py +++ b/azure/functions/__init__.py @@ -23,6 +23,7 @@ from ._queue import QueueMessage from ._servicebus import ServiceBusMessage from ._sql import SqlRow, SqlRowList +from ._mysql import MySqlRow, MySqlRowList # Import binding implementations to register them from . import blob # NoQA @@ -37,6 +38,7 @@ from . import durable_functions # NoQA from . import sql # NoQA from . import warmup # NoQA +from . import mysql # NoQA __all__ = ( @@ -67,6 +69,8 @@ 'SqlRowList', 'TimerRequest', 'WarmUpContext', + 'MySqlRow', + 'MySqlRowList', # Middlewares 'WsgiMiddleware', diff --git a/azure/functions/_mysql.py b/azure/functions/_mysql.py new file mode 100644 index 00000000..9c7515d9 --- /dev/null +++ b/azure/functions/_mysql.py @@ -0,0 +1,71 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +import abc +import collections +import json + + +class BaseMySqlRow(abc.ABC): + + @classmethod + @abc.abstractmethod + def from_json(cls, json_data: str) -> 'BaseMySqlRow': + raise NotImplementedError + + @classmethod + @abc.abstractmethod + def from_dict(cls, dct: dict) -> 'BaseMySqlRow': + raise NotImplementedError + + @abc.abstractmethod + def __getitem__(self, key): + raise NotImplementedError + + @abc.abstractmethod + def __setitem__(self, key, value): + raise NotImplementedError + + @abc.abstractmethod + def to_json(self) -> str: + raise NotImplementedError + + +class BaseMySqlRowList(abc.ABC): + pass + + +class MySqlRow(BaseMySqlRow, collections.UserDict): + """A MySql Row. + + MySqlRow objects are ''UserDict'' subclasses and behave like dicts. + """ + + @classmethod + def from_json(cls, json_data: str) -> 'BaseMySqlRow': + """Create a MySqlRow from a JSON string.""" + return cls.from_dict(json.loads(json_data)) + + @classmethod + def from_dict(cls, dct: dict) -> 'BaseMySqlRow': + """Create a MySqlRow from a dict object""" + return cls({k: v for k, v in dct.items()}) + + def to_json(self) -> str: + """Return the JSON representation of the MySqlRow""" + return json.dumps(dict(self)) + + def __getitem__(self, key): + return collections.UserDict.__getitem__(self, key) + + def __setitem__(self, key, value): + return collections.UserDict.__setitem__(self, key, value) + + def __repr__(self) -> str: + return ( + f'' + ) + + +class MySqlRowList(BaseMySqlRowList, collections.UserList): + "A ''UserList'' subclass containing a list of :class:'~MySqlRow' objects" + pass diff --git a/azure/functions/mysql.py b/azure/functions/mysql.py new file mode 100644 index 00000000..06a04a56 --- /dev/null +++ b/azure/functions/mysql.py @@ -0,0 +1,78 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import collections.abc +import json +import typing + +from azure.functions import _mysql as mysql + +from . import meta + + +class MySqlConverter(meta.InConverter, meta.OutConverter, + binding='mysql'): + + @classmethod + def check_input_type_annotation(cls, pytype: type) -> bool: + return issubclass(pytype, mysql.BaseMySqlRowList) + + @classmethod + def check_output_type_annotation(cls, pytype: type) -> bool: + return issubclass(pytype, (mysql.BaseMySqlRowList, mysql.BaseMySqlRow)) + + @classmethod + def decode(cls, + data: meta.Datum, + *, + trigger_metadata) -> typing.Optional[mysql.MySqlRowList]: + if data is None or data.type is None: + return None + + data_type = data.type + + if data_type in ['string', 'json']: + body = data.value + + elif data_type == 'bytes': + body = data.value.decode('utf-8') + + else: + raise NotImplementedError( + f'Unsupported payload type: {data_type}') + + rows = json.loads(body) + if not isinstance(rows, list): + rows = [rows] + + return mysql.MySqlRowList( + (None if row is None else mysql.MySqlRow.from_dict(row)) + for row in rows) + + @classmethod + def encode(cls, obj: typing.Any, *, + expected_type: typing.Optional[type]) -> meta.Datum: + if isinstance(obj, mysql.MySqlRow): + data = mysql.MySqlRowList([obj]) + + elif isinstance(obj, mysql.MySqlRowList): + data = obj + + elif isinstance(obj, collections.abc.Iterable): + data = mysql.MySqlRowList() + + for row in obj: + if not isinstance(row, mysql.MySqlRow): + raise NotImplementedError( + f'Unsupported list type: {type(obj)}, \ + lists must contain MySqlRow objects') + else: + data.append(row) + + else: + raise NotImplementedError(f'Unsupported type: {type(obj)}') + + return meta.Datum( + type='json', + value=json.dumps([dict(d) for d in data]) + ) diff --git a/tests/test_mysql.py b/tests/test_mysql.py new file mode 100644 index 00000000..514c066a --- /dev/null +++ b/tests/test_mysql.py @@ -0,0 +1,293 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import json +import unittest + +import azure.functions as func +import azure.functions.mysql as mysql +from azure.functions.meta import Datum + + +class TestMySql(unittest.TestCase): + def test_mysql_decode_none(self): + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=None, trigger_metadata=None) + self.assertIsNone(result) + + def test_mysql_decode_string(self): + datum: Datum = Datum(""" + { + "id": "1", + "name": "test" + } + """, "string") + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + self.assertIsNotNone(result, + 'MySqlRowList should be non-None') + self.assertEqual(len(result), + 1, + 'MySqlRowList should have exactly 1 item') + self.assertEqual(result[0]['id'], + '1', + 'MySqlRow item should have id 1') + self.assertEqual(result[0]['name'], + 'test', + 'MySqlRow item should have name test') + + def test_mysql_decode_bytes(self): + datum: Datum = Datum(""" + { + "id": "1", + "name": "test" + } + """.encode(), "bytes") + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + self.assertIsNotNone(result, + 'MySqlRowList should be non-None') + self.assertEqual(len(result), + 1, + 'MySqlRowList should have exactly 1 item') + self.assertEqual(result[0]['id'], + '1', + 'MySqlRow item should have id 1') + self.assertEqual(result[0]['name'], + 'test', + 'MySqlRow item should have name test') + + def test_mysql_decode_json(self): + datum: Datum = Datum(""" + { + "id": "1", + "name": "test" + } + """, "json") + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + self.assertIsNotNone(result, + 'MySqlRowList should be non-None') + self.assertEqual(len(result), + 1, + 'MySqlRowList should have exactly 1 item') + self.assertEqual(result[0]['id'], + '1', + 'MySqlRow item should have id 1') + self.assertEqual(result[0]['name'], + 'test', + 'MySqlRow item should have name test') + + def test_mysql_decode_json_name_is_null(self): + datum: Datum = Datum(""" + { + "id": "1", + "name": null + } + """, "json") + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + self.assertIsNotNone(result, + 'MySqlRowList itself should be non-None') + self.assertEqual(len(result), + 1, + 'MySqlRowList should have exactly 1 item') + self.assertEqual(result[0]['name'], + None, + 'Item in MySqlRowList should be None') + + def test_mysql_decode_json_multiple_entries(self): + datum: Datum = Datum(""" + [ + { + "id": "1", + "name": "test1" + }, + { + "id": "2", + "name": "test2" + } + ] + """, "json") + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + self.assertIsNotNone(result) + self.assertEqual(len(result), + 2, + 'MySqlRowList should have exactly 2 items') + self.assertEqual(result[0]['id'], + '1', + 'First MySqlRowList item should have id 1') + self.assertEqual(result[0]['name'], + 'test1', + 'First MySqlRowList item should have name test1') + self.assertEqual(result[1]['id'], + '2', + 'First MySqlRowList item should have id 2') + self.assertEqual(result[1]['name'], + 'test2', + 'Second MySqlRowList item should have name test2') + + def test_mysql_decode_json_multiple_nulls(self): + datum: Datum = Datum("[null]", "json") + result: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + self.assertIsNotNone(result) + self.assertEqual(len(result), + 1, + 'MySqlRowList should have exactly 1 item') + self.assertEqual(result[0], + None, + 'MySqlRow item should be None') + + def test_mysql_encode_mysqlrow(self): + mysqlRow = func.MySqlRow.from_json(""" + { + "id": "1", + "name": "test" + } + """) + datum = mysql.MySqlConverter.encode(obj=mysqlRow, expected_type=None) + self.assertEqual(datum.type, + 'json', + 'Datum type should be JSON') + self.assertEqual(len(datum.python_value), + 1, + 'Encoded value should be list of length 1') + self.assertEqual(datum.python_value[0]['id'], + '1', + 'id should be 1') + self.assertEqual(datum.python_value[0]['name'], + 'test', + 'name should be test') + + def test_mysql_encode_mysqlrowlist(self): + datum: Datum = Datum(""" + { + "id": "1", + "name": "test" + } + """, "json") + mysqlRowList: func.MySqlRowList = mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + datum = mysql.MySqlConverter.encode( + obj=mysqlRowList, expected_type=None) + self.assertEqual(datum.type, + 'json', + 'Datum type should be JSON') + self.assertEqual(len(datum.python_value), + 1, + 'Encoded value should be list of length 1') + self.assertEqual(datum.python_value[0]['id'], + '1', + 'id should be 1') + self.assertEqual(datum.python_value[0]['name'], + 'test', + 'name should be test') + + def test_mysql_encode_list_of_mysqlrows(self): + mysqlRows = [ + func.MySqlRow.from_json(""" + { + "id": "1", + "name": "test" + } + """), + func.MySqlRow.from_json(""" + { + "id": "2", + "name": "test2" + } + """) + ] + datum = mysql.MySqlConverter.encode(obj=mysqlRows, expected_type=None) + self.assertEqual(datum.type, + 'json', + 'Datum type should be JSON') + self.assertEqual(len(datum.python_value), + 2, + 'Encoded value should be list of length 2') + self.assertEqual(datum.python_value[0]['id'], + '1', + 'id should be 1') + self.assertEqual(datum.python_value[0]['name'], + 'test', + 'name should be test') + self.assertEqual(datum.python_value[1]['id'], + '2', + 'id should be 2') + self.assertEqual(datum.python_value[1]['name'], + 'test2', + 'name should be test2') + + def test_mysql_encode_list_of_str_raises(self): + strList = [ + """ + { + "id": "1", + "name": "test" + } + """ + ] + self.assertRaises(NotImplementedError, + mysql.MySqlConverter.encode, + obj=strList, + expected_type=None) + + def test_mysql_encode_list_of_mysqlrowlist_raises(self): + datum: Datum = Datum(""" + { + "id": "1", + "name": "test" + } + """, "json") + mysqlRowListList = [ + mysql.MySqlConverter.decode( + data=datum, trigger_metadata=None) + ] + self.assertRaises(NotImplementedError, + mysql.MySqlConverter.encode, + obj=mysqlRowListList, + expected_type=None) + + def test_mysql_input_type(self): + check_input_type = mysql.MySqlConverter.check_input_type_annotation + self.assertTrue(check_input_type(func.MySqlRowList), + 'MySqlRowList should be accepted') + self.assertFalse(check_input_type(func.MySqlRow), + 'MySqlRow should not be accepted') + self.assertFalse(check_input_type(str), + 'str should not be accepted') + + def test_mysql_output_type(self): + check_output_type = mysql.MySqlConverter.check_output_type_annotation + self.assertTrue(check_output_type(func.MySqlRowList), + 'MySqlRowList should be accepted') + self.assertTrue(check_output_type(func.MySqlRow), + 'MySqlRow should be accepted') + self.assertFalse(check_output_type(str), + 'str should not be accepted') + + def test_mysqlrow_json(self): + # Parse MySqlRow from JSON + mysqlRow = func.MySqlRow.from_json(""" + { + "id": "1", + "name": "test" + } + """) + self.assertEqual(mysqlRow['id'], + '1', + 'Parsed MySqlRow id should be 1') + self.assertEqual(mysqlRow['name'], + 'test', + 'Parsed MySqlRow name should be test') + + # Parse JSON from MySqlRow + mysqlRowJson = json.loads(func.MySqlRow.to_json(mysqlRow)) + self.assertEqual(mysqlRowJson['id'], + '1', + 'Parsed JSON id should be 1') + self.assertEqual(mysqlRowJson['name'], + 'test', + 'Parsed JSON name should be test') From 3f8e43ce44d698a1127cb58d2e27f825fd944937 Mon Sep 17 00:00:00 2001 From: hallvictoria <59299039+hallvictoria@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:38:30 -0500 Subject: [PATCH 04/10] cherry pick changes (#249) Co-authored-by: Victoria Hall --- azure/functions/decorators/blob.py | 2 +- tests/decorators/test_blob.py | 6 +++--- tests/decorators/test_decorators.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/azure/functions/decorators/blob.py b/azure/functions/decorators/blob.py index 1a2d4122..bd2861fa 100644 --- a/azure/functions/decorators/blob.py +++ b/azure/functions/decorators/blob.py @@ -17,7 +17,7 @@ def __init__(self, **kwargs): self.path = path self.connection = connection - self.source = source + self.source = source.value if source else None super().__init__(name=name, data_type=data_type) @staticmethod diff --git a/tests/decorators/test_blob.py b/tests/decorators/test_blob.py index f8712b9f..43926591 100644 --- a/tests/decorators/test_blob.py +++ b/tests/decorators/test_blob.py @@ -42,7 +42,7 @@ def test_blob_trigger_creation_with_default_specified_source(self): "name": "req", "dataType": DataType.UNDEFINED, "path": "dummy_path", - 'source': BlobSource.LOGS_AND_CONTAINER_SCAN, + 'source': 'LogsAndContainerScan', "connection": "dummy_connection" }) @@ -62,7 +62,7 @@ def test_blob_trigger_creation_with_source_as_string(self): "name": "req", "dataType": DataType.UNDEFINED, "path": "dummy_path", - 'source': BlobSource.EVENT_GRID, + 'source': 'EventGrid', "connection": "dummy_connection" }) @@ -82,7 +82,7 @@ def test_blob_trigger_creation_with_source_as_enum(self): "name": "req", "dataType": DataType.UNDEFINED, "path": "dummy_path", - 'source': BlobSource.EVENT_GRID, + 'source': 'EventGrid', "connection": "dummy_connection" }) diff --git a/tests/decorators/test_decorators.py b/tests/decorators/test_decorators.py index 82973ba3..acdd5ccd 100644 --- a/tests/decorators/test_decorators.py +++ b/tests/decorators/test_decorators.py @@ -1628,7 +1628,7 @@ def test_blob_input_binding(): "type": BLOB_TRIGGER, "name": "req", "path": "dummy_path", - "source": BlobSource.EVENT_GRID, + "source": 'EventGrid', "connection": "dummy_conn" }) From 52a5bbe85785c10caab8cbfdf5590d2d93ff7eeb Mon Sep 17 00:00:00 2001 From: AzureFunctionsPython Date: Mon, 30 Sep 2024 19:42:03 +0000 Subject: [PATCH 05/10] build: update Python Library Version to 1.21.1 --- azure/functions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/__init__.py b/azure/functions/__init__.py index 86565e37..e7add804 100644 --- a/azure/functions/__init__.py +++ b/azure/functions/__init__.py @@ -98,4 +98,4 @@ 'BlobSource' ) -__version__ = '1.21.0' +__version__ = '1.21.1' From 6356f6f76cc8bce39a7f9eb1ade9306e48a1f509 Mon Sep 17 00:00:00 2001 From: hallvictoria <59299039+hallvictoria@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:13:28 -0500 Subject: [PATCH 06/10] build: update Python Library Version to 1.22.0b1 (#251) Co-authored-by: AzureFunctionsPython --- azure/functions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/__init__.py b/azure/functions/__init__.py index 2fa4a543..ee945e9d 100644 --- a/azure/functions/__init__.py +++ b/azure/functions/__init__.py @@ -102,4 +102,4 @@ 'BlobSource' ) -__version__ = '1.21.1' +__version__ = '1.22.0b1' From a4c07f6a9c24bb0c31bed6e42eec207539e6accd Mon Sep 17 00:00:00 2001 From: Manvir Kaur <67894494+manvkaur@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:34:12 +0100 Subject: [PATCH 07/10] fix: assistant_post_input and assistant_query_input decorator params updated to configure custom table storage (#244) * update assistant decortators for table storage optional params * update functionapp and tests * remove underscores * fix casing * correct typo * resolve linting issues * fix linting issues in two more files * update default collection name to ChatState --- azure/functions/decorators/function_app.py | 26 ++++++++++++++++++---- azure/functions/decorators/openai.py | 8 +++++++ tests/decorators/test_openai.py | 8 +++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 773bf5da..1378b2cb 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -80,8 +80,8 @@ def __str__(self): return self.get_function_json() def __call__(self, *args, **kwargs): - """This would allow the Function object to be directly callable and runnable - directly using the interpreter locally. + """This would allow the Function object to be directly callable + and runnable directly using the interpreter locally. Example: @app.route(route="http_trigger") @@ -332,8 +332,8 @@ def decorator(): return wrap def _get_durable_blueprint(self): - """Attempt to import the Durable Functions SDK from which DF decorators are - implemented. + """Attempt to import the Durable Functions SDK from which DF + decorators are implemented. """ try: @@ -3266,6 +3266,8 @@ def assistant_query_input(self, arg_name: str, id: str, timestamp_utc: str, + chat_storage_connection_setting: Optional[str] = "AzureWebJobsStorage", # noqa: E501 + collection_name: Optional[str] = "ChatState", # noqa: E501 data_type: Optional[ Union[DataType, str]] = None, **kwargs) \ @@ -3278,6 +3280,11 @@ def assistant_query_input(self, :param timestamp_utc: the timestamp of the earliest message in the chat history to fetch. The timestamp should be in ISO 8601 format - for example, 2023-08-01T00:00:00Z. + :param chat_storage_connection_setting: The configuration section name + for the table settings for assistant chat storage. The default value is + "AzureWebJobsStorage". + :param collection_name: The table collection name for assistant chat + storage. The default value is "ChatState". :param id: The ID of the Assistant to query. :param data_type: Defines how Functions runtime should treat the parameter value @@ -3295,6 +3302,8 @@ def decorator(): name=arg_name, id=id, timestamp_utc=timestamp_utc, + chat_storage_connection_setting=chat_storage_connection_setting, # noqa: E501 + collection_name=collection_name, data_type=parse_singular_param_to_enum(data_type, DataType), **kwargs)) @@ -3308,6 +3317,8 @@ def assistant_post_input(self, arg_name: str, id: str, user_message: str, model: Optional[str] = None, + chat_storage_connection_setting: Optional[str] = "AzureWebJobsStorage", # noqa: E501 + collection_name: Optional[str] = "ChatState", # noqa: E501 data_type: Optional[ Union[DataType, str]] = None, **kwargs) \ @@ -3321,6 +3332,11 @@ def assistant_post_input(self, arg_name: str, :param user_message: The user message that user has entered for assistant to respond to. :param model: The OpenAI chat model to use. + :param chat_storage_connection_setting: The configuration section name + for the table settings for assistant chat storage. The default value is + "AzureWebJobsStorage". + :param collection_name: The table collection name for assistant chat + storage. The default value is "ChatState". :param data_type: Defines how Functions runtime should treat the parameter value :param kwargs: Keyword arguments for specifying additional binding @@ -3338,6 +3354,8 @@ def decorator(): id=id, user_message=user_message, model=model, + chat_storage_connection_setting=chat_storage_connection_setting, # noqa: E501 + collection_name=collection_name, data_type=parse_singular_param_to_enum(data_type, DataType), **kwargs)) diff --git a/azure/functions/decorators/openai.py b/azure/functions/decorators/openai.py index df459c1c..2563a78e 100644 --- a/azure/functions/decorators/openai.py +++ b/azure/functions/decorators/openai.py @@ -77,10 +77,14 @@ def __init__(self, name: str, id: str, timestamp_utc: str, + chat_storage_connection_setting: Optional[str] = "AzureWebJobsStorage", # noqa: E501 + collection_name: Optional[str] = "ChatState", data_type: Optional[DataType] = None, **kwargs): self.id = id self.timestamp_utc = timestamp_utc + self.chat_storage_connection_setting = chat_storage_connection_setting + self.collection_name = collection_name super().__init__(name=name, data_type=data_type) @@ -165,12 +169,16 @@ def __init__(self, name: str, id: str, user_message: str, model: Optional[str] = None, + chat_storage_connection_setting: Optional[str] = "AzureWebJobsStorage", # noqa: E501 + collection_name: Optional[str] = "ChatState", data_type: Optional[DataType] = None, **kwargs): self.name = name self.id = id self.user_message = user_message self.model = model + self.chat_storage_connection_setting = chat_storage_connection_setting + self.collection_name = collection_name super().__init__(name=name, data_type=data_type) diff --git a/tests/decorators/test_openai.py b/tests/decorators/test_openai.py index f2ebdaca..c2009c72 100644 --- a/tests/decorators/test_openai.py +++ b/tests/decorators/test_openai.py @@ -57,6 +57,8 @@ def test_text_completion_input_valid_creation(self): def test_assistant_query_input_valid_creation(self): input = AssistantQueryInput(name="test", timestamp_utc="timestamp_utc", + chat_storage_connection_setting="AzureWebJobsStorage", # noqa: E501 + collection_name="ChatState", data_type=DataType.UNDEFINED, id="test_id", type="assistantQueryInput", @@ -66,6 +68,8 @@ def test_assistant_query_input_valid_creation(self): self.assertEqual(input.get_dict_repr(), {"name": "test", "timestampUtc": "timestamp_utc", + "chatStorageConnectionSetting": "AzureWebJobsStorage", # noqa: E501 + "collectionName": "ChatState", "dataType": DataType.UNDEFINED, "direction": BindingDirection.IN, "type": "assistantQuery", @@ -111,6 +115,8 @@ def test_assistant_post_input_valid_creation(self): input = AssistantPostInput(name="test", id="test_id", model="test_model", + chat_storage_connection_setting="AzureWebJobsStorage", # noqa: E501 + collection_name="ChatState", user_message="test_message", data_type=DataType.UNDEFINED, dummy_field="dummy") @@ -120,6 +126,8 @@ def test_assistant_post_input_valid_creation(self): {"name": "test", "id": "test_id", "model": "test_model", + "chatStorageConnectionSetting": "AzureWebJobsStorage", # noqa: E501 + "collectionName": "ChatState", "userMessage": "test_message", "dataType": DataType.UNDEFINED, "direction": BindingDirection.IN, From c0e174871d2ccefa37759af8d06c51678b0c6857 Mon Sep 17 00:00:00 2001 From: hallvictoria <59299039+hallvictoria@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:32:55 -0500 Subject: [PATCH 08/10] build: update Python Library Version to 1.22.0b2 (#253) Co-authored-by: AzureFunctionsPython --- azure/functions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/__init__.py b/azure/functions/__init__.py index ee945e9d..053d788a 100644 --- a/azure/functions/__init__.py +++ b/azure/functions/__init__.py @@ -102,4 +102,4 @@ 'BlobSource' ) -__version__ = '1.22.0b1' +__version__ = '1.22.0b2' From 5f656ad03acffe6510808826e85572303c05bfce Mon Sep 17 00:00:00 2001 From: hallvictoria <59299039+hallvictoria@users.noreply.github.com> Date: Wed, 9 Oct 2024 12:18:43 -0500 Subject: [PATCH 09/10] fix: allow source to be string and enum (#256) * allowing both BlobSource and string source values * add test * using isinstance, removed extra if check * mypy fix --------- Co-authored-by: Victoria Hall --- azure/functions/decorators/blob.py | 5 ++++- tests/decorators/test_blob.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/azure/functions/decorators/blob.py b/azure/functions/decorators/blob.py index bd2861fa..9ed4ce2f 100644 --- a/azure/functions/decorators/blob.py +++ b/azure/functions/decorators/blob.py @@ -17,7 +17,10 @@ def __init__(self, **kwargs): self.path = path self.connection = connection - self.source = source.value if source else None + if isinstance(source, BlobSource): + self.source = source.value + else: + self.source = source # type: ignore super().__init__(name=name, data_type=data_type) @staticmethod diff --git a/tests/decorators/test_blob.py b/tests/decorators/test_blob.py index 43926591..bad8f99b 100644 --- a/tests/decorators/test_blob.py +++ b/tests/decorators/test_blob.py @@ -50,7 +50,7 @@ def test_blob_trigger_creation_with_source_as_string(self): trigger = BlobTrigger(name="req", path="dummy_path", connection="dummy_connection", - source=BlobSource.EVENT_GRID, + source="EventGrid", data_type=DataType.UNDEFINED, dummy_field="dummy") From 7683200f0caa91193284f041bf0202af4cd140c0 Mon Sep 17 00:00:00 2001 From: hallvictoria <59299039+hallvictoria@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:25:31 -0500 Subject: [PATCH 10/10] build: update Python Library Version to 1.22.0b3 (#262) Co-authored-by: AzureFunctionsPython --- azure/functions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/__init__.py b/azure/functions/__init__.py index 053d788a..22978fa5 100644 --- a/azure/functions/__init__.py +++ b/azure/functions/__init__.py @@ -102,4 +102,4 @@ 'BlobSource' ) -__version__ = '1.22.0b2' +__version__ = '1.22.0b3'