From c700c16626d6aef26cb4aad5080e205c8108e0dc Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Thu, 2 May 2024 16:11:04 -0500 Subject: [PATCH 01/16] unique function names --- azure/functions/decorators/function_app.py | 34 ++++++ tests/decorators/test_function_app.py | 122 +++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 6166ae65..f6f9d2d7 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -199,6 +199,8 @@ def __str__(self): class FunctionBuilder(object): + function_bindings = {} + def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) @@ -227,6 +229,12 @@ def _validate_function(self, """ Validates the function information before building the function. + Functions with the same function name are not supported and should + fail indexing. If a function name is not defined, the default is the + method name. This also means that two functions with the same + method name will also fail indexing. + https://github.com/Azure/azure-functions-python-worker/issues/1489 + :param auth_level: Http auth level that will be set if http trigger function auth level is None. """ @@ -257,6 +265,16 @@ def _validate_function(self, parse_singular_param_to_enum(auth_level, AuthLevel)) self._function._is_http_function = True + # This dict contains the function name and its bindings for all + # functions in an app. If a previous function has the same name, + # indexing will fail here. + if self.function_bindings.get(function_name, None) is not None: + raise ValueError( + f"Function {function_name} does not have a unique" + f" function name. Please change @app.function_name() or" + f" the function method name to be unique.") + self.function_bindings[function_name] = bindings + def build(self, auth_level: Optional[AuthLevel] = None) -> Function: """ Validates and builds the function object. @@ -267,6 +285,22 @@ def build(self, auth_level: Optional[AuthLevel] = None) -> Function: self._validate_function(auth_level) return self._function + def validate_function_names(self): + """ + Functions should have unique function names. If two functions + have the same function name, the worker should fail + during indexing. + + If the function name decorator is not applied, the function + name defaults to the method name. This means that two functions + can not have the same method name as well without having unique + function names. + + Scenarios that fail / should fail indexing: + - same function name + - no function name, same method name + """ + class DecoratorApi(ABC): """Interface which contains essential decorator function building blocks diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index 2f687262..dd16873d 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -17,6 +17,7 @@ FunctionRegister, TriggerApi, ExternalHttpFunctionApp from azure.functions.decorators.http import HttpTrigger, HttpOutput, \ HttpMethod +from azure.functions.decorators.timer import TimerTrigger from azure.functions.decorators.retry_policy import RetryPolicy from test_core import DummyTrigger from tests.utils.testutils import assert_json @@ -221,6 +222,127 @@ def test_build_function_with_retry_policy_setting(self): 'strategy': 'exponential', 'max_retry_count': '2', 'minimum_interval': '1', 'maximum_interval': '5'}) + def test_unique_method_names(self): + app = FunctionApp() + + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + @app.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + functions = app.get_functions() + self.assertEqual(len(functions), 2) + + self.assertEqual(functions[0].get_function_name(), "hello") + self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello")[0], TimerTrigger) + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello2")[0], TimerTrigger) + + def test_unique_function_names(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + @app.function_name("hello2") + @app.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + functions = app.get_functions() + self.assertEqual(len(functions), 2) + + self.assertEqual(functions[0].get_function_name(), "hello") + self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello")[0], TimerTrigger) + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello2")[0], TimerTrigger) + + def test_same_method_names(self): + app = FunctionApp() + + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): # NoQA + return name + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + + def test_same_function_names(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): # NoQA + return name + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + + def test_same_function_name_different_method_name(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + + def test_same_function_and_method_name(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + class TestScaffold(unittest.TestCase): def setUp(self): From 597c3539d821f0670d1bf026a535bff53bc4c474 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Fri, 3 May 2024 11:57:39 -0500 Subject: [PATCH 02/16] added blueprint tests --- tests/decorators/test_function_app.py | 145 ++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index dd16873d..5ba666f2 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -343,6 +343,151 @@ def hello(name: str): " function name. Please change @app.function_name()" " or the function method name to be unique.") + def test_blueprint_unique_method_names(self): + app = FunctionApp() + + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + bp = Blueprint() + + @bp.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + app.register_blueprint(bp) + + functions = app.get_functions() + self.assertEqual(len(functions), 2) + + self.assertEqual(functions[0].get_function_name(), "hello") + self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello")[0], TimerTrigger) + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello2")[0], TimerTrigger) + + def test_blueprint_unique_function_names(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + bp = Blueprint() + + @bp.function_name("hello2") + @bp.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + app.register_blueprint(bp) + + functions = app.get_functions() + self.assertEqual(len(functions), 2) + + self.assertEqual(functions[0].get_function_name(), "hello") + self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello")[0], TimerTrigger) + self.assertIsInstance(app._function_builders[0].function_bindings.get( + "hello2")[0], TimerTrigger) + + def test_blueprint_same_method_names(self): + app = FunctionApp() + + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + bp = Blueprint() + + @bp.schedule(arg_name="name", schedule="10****") + def hello(name: str): # NoQA + return name + + app.register_blueprint(bp) + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + + def test_blueprint_same_function_names(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + bp = Blueprint() + + @bp.function_name("hello") + @bp.schedule(arg_name="name", schedule="10****") + def hello(name: str): # NoQA + return name + + app.register_blueprint(bp) + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + + def test_blueprint_same_function_name_different_method_name(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + bp = Blueprint() + + @bp.function_name("hello") + @bp.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + app.register_blueprint(bp) + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + + def test_blueprint_same_function_and_method_name(self): + app = FunctionApp() + + @app.function_name("hello") + @app.schedule(arg_name="name", schedule="10****") + def hello2(name: str): + return name + + bp = Blueprint() + + @bp.schedule(arg_name="name", schedule="10****") + def hello(name: str): + return name + + app.register_blueprint(bp) + + with self.assertRaises(ValueError) as err: + app.get_functions() + self.assertEqual(err.exception.args[0], + "Function hello does not have a unique" + " function name. Please change @app.function_name()" + " or the function method name to be unique.") + class TestScaffold(unittest.TestCase): def setUp(self): From 22d63f045175317d32364f5fc60960cedd34719b Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 15 May 2024 16:20:10 -0500 Subject: [PATCH 03/16] changing test function names --- tests/decorators/test_dapr.py | 16 +- tests/decorators/test_decorators.py | 158 ++++++++++---------- tests/decorators/test_function_app.py | 203 ++++++++++++++++---------- 3 files changed, 211 insertions(+), 166 deletions(-) diff --git a/tests/decorators/test_dapr.py b/tests/decorators/test_dapr.py index 522f1b54..3bfc743e 100644 --- a/tests/decorators/test_dapr.py +++ b/tests/decorators/test_dapr.py @@ -50,7 +50,7 @@ def test_dapr_binding_trigger_default_args(self): @app.dapr_binding_trigger(arg_name="req", binding_name="dummy_binding_name") - def dummy(): + def dummy1(): pass func = self._get_user_function(app) @@ -73,7 +73,7 @@ def test_dapr_topic_trigger_default_args(self): pub_sub_name="dummy_pub_sub_name", topic="dummy_topic", route="/dummy_route") - def dummy(): + def dummy2(): pass func = self._get_user_function(app) @@ -99,7 +99,7 @@ def test_dapr_state_input_binding(self): @app.dapr_state_input(arg_name="in", state_store="dummy_state_store", key="dummy_key") - def dummy(): + def dummy3(): pass func = self._get_user_function(app) @@ -125,7 +125,7 @@ def test_dapr_secret_input_binding(self): secret_store_name="dummy_secret_store_name", key="dummy_key", metadata="dummy_metadata") - def dummy(): + def dummy4(): pass func = self._get_user_function(app) @@ -151,7 +151,7 @@ def test_dapr_state_output_binding(self): @app.dapr_state_output(arg_name="out", state_store="dummy_state_store", key="dummy_key") - def dummy(): + def dummy5(): pass func = self._get_user_function(app) @@ -177,7 +177,7 @@ def test_dapr_invoke_output_binding(self): app_id="dummy_app_id", method_name="dummy_method_name", http_verb="dummy_http_verb") - def dummy(): + def dummy6(): pass func = self._get_user_function(app) @@ -203,7 +203,7 @@ def test_dapr_publish_output_binding(self): @app.dapr_publish_output(arg_name="out", pub_sub_name="dummy_pub_sub_name", topic="dummy_topic") - def dummy(): + def dummy7(): pass func = self._get_user_function(app) @@ -228,7 +228,7 @@ def test_dapr_binding_output_binding(self): @app.dapr_binding_output(arg_name="out", binding_name="dummy_binding_name", operation="dummy_operation") - def dummy(): + def dummy8(): pass func = self._get_user_function(app) diff --git a/tests/decorators/test_decorators.py b/tests/decorators/test_decorators.py index 97c50a7a..d8ddf23d 100644 --- a/tests/decorators/test_decorators.py +++ b/tests/decorators/test_decorators.py @@ -26,11 +26,11 @@ def _get_user_function(self, app): def test_route_is_function_name(self): app = self.func_app - test_func_name = "dummy_function" + test_func_name = "test_route_is_function_name" @app.function_name(test_func_name) @app.route() - def dummy_func(): + def test_route_is_function_name(): pass func = self._get_user_function(app) @@ -43,26 +43,26 @@ def test_route_is_python_function_name(self): app = self.func_app @app.route() - def dummy_func(): + def test_route_is_python_function_name(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "dummy_func") + self.assertEqual(func.get_function_name(), "test_route_is_python_function_name") self.assertTrue(isinstance(func.get_trigger(), HttpTrigger)) - self.assertTrue(func.get_trigger().route, "dummy_func") + self.assertTrue(func.get_trigger().route, "test_route_is_python_function_name") def test_route_is_custom(self): app = self.func_app - @app.function_name("dummy_function") + @app.function_name("test_route_is_custom") @app.route("dummy") def dummy_func(): pass func = self._get_user_function(app) - self.assertEqual("dummy_function", func.get_function_name()) + self.assertEqual("test_route_is_custom", func.get_function_name()) self.assertTrue(isinstance(func.get_trigger(), HttpTrigger)) self.assertTrue(func.get_trigger().route, "dummy") @@ -70,11 +70,11 @@ def test_schedule_trigger_default_args(self): app = self.func_app @app.schedule(arg_name="req", schedule="dummy_schedule") - def dummy_func(): + def test_schedule_trigger_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "dummy_func") + self.assertEqual(func.get_function_name(), "test_schedule_trigger_default_args") assert_json(self, func, { "scriptFile": "function_app.py", "bindings": [ @@ -93,7 +93,7 @@ def test_schedule_trigger_full_args(self): @app.schedule(arg_name="req", schedule="dummy_schedule", run_on_startup=False, use_monitor=False, data_type=DataType.STRING, dummy_field='dummy') - def dummy(): + def test_schedule_trigger_full_args(): pass func = self._get_user_function(app) @@ -117,11 +117,11 @@ def test_timer_trigger_default_args(self): app = self.func_app @app.timer_trigger(arg_name="req", schedule="dummy_schedule") - def dummy_func(): + def test_timer_trigger_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "dummy_func") + self.assertEqual(func.get_function_name(), "test_timer_trigger_default_args") assert_json(self, func, { "scriptFile": "function_app.py", "bindings": [ @@ -140,7 +140,7 @@ def test_timer_trigger_full_args(self): @app.timer_trigger(arg_name="req", schedule="dummy_schedule", run_on_startup=False, use_monitor=False, data_type=DataType.STRING, dummy_field='dummy') - def dummy(): + def test_timer_trigger_full_args(): pass func = self._get_user_function(app) @@ -164,7 +164,7 @@ def test_route_default_args(self): app = self.func_app @app.route() - def dummy(): + def test_route_default_args(): pass func = self._get_user_function(app) @@ -176,7 +176,7 @@ def dummy(): "direction": BindingDirection.IN, "type": HTTP_TRIGGER, "name": "req", - "route": "dummy" + "route": "test_route_default_args" }, { "direction": BindingDirection.OUT, @@ -194,7 +194,7 @@ def test_route_with_all_args(self): auth_level=AuthLevel.FUNCTION, route='dummy_route', trigger_extra_fields={"dummy_field": "dummy"}, binding_extra_fields={"dummy_field": "dummy"}) - def dummy(): + def test_route_with_all_args(): pass func = self._get_user_function(app) @@ -225,11 +225,11 @@ def test_warmup_trigger_default_args(self): app = self.func_app @app.warm_up_trigger(arg_name="req") - def dummy_func(): + def test_warmup_trigger_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "dummy_func") + self.assertEqual(func.get_function_name(), "test_warmup_trigger_default_args") assert_json(self, func, { "scriptFile": "function_app.py", "bindings": [ @@ -246,7 +246,7 @@ def test_warmup_trigger_full_args(self): @app.warm_up_trigger(arg_name="req", data_type=DataType.STRING, dummy_field='dummy') - def dummy(): + def test_warmup_trigger_full_args(): pass func = self._get_user_function(app) @@ -270,7 +270,7 @@ def test_queue_default_args(self): connection="dummy_conn") @app.queue_output(arg_name="out", queue_name="dummy_out_queue", connection="dummy_out_conn") - def dummy(): + def test_queue_default_args(): pass func = self._get_user_function(app) @@ -297,7 +297,7 @@ def test_queue_trigger(self): @app.queue_trigger(arg_name="req", queue_name="dummy_queue", connection="dummy_conn") - def dummy(): + def test_queue_trigger(): pass func = self._get_user_function(app) @@ -320,7 +320,7 @@ def test_queue_output_binding(self): connection="dummy_conn") @app.queue_output(arg_name="out", queue_name="dummy_out_queue", connection="dummy_out_conn") - def dummy(): + def test_queue_output_binding(): pass func = self._get_user_function(app) @@ -345,7 +345,7 @@ def test_queue_full_args(self): @app.queue_output(arg_name="out", queue_name="dummy_out_queue", connection="dummy_out_conn", data_type=DataType.STRING, dummy_field="dummy") - def dummy(): + def test_queue_full_args(): pass func = self._get_user_function(app) @@ -380,7 +380,7 @@ def test_service_bus_queue_default_args(self): @app.service_bus_queue_output(arg_name='res', connection='dummy_out_conn', queue_name='dummy_out_queue') - def dummy(): + def test_service_bus_queue_default_args(): pass func = self._get_user_function(app) @@ -410,7 +410,7 @@ def test_service_bus_queue_trigger(self): @app.service_bus_queue_trigger(arg_name="req", connection="dummy_conn", queue_name="dummy_queue") - def dummy(): + def test_service_bus_queue_trigger(): pass func = self._get_user_function(app) @@ -435,7 +435,7 @@ def test_service_bus_queue_output_binding(self): @app.service_bus_queue_output(arg_name='res', connection='dummy_out_conn', queue_name='dummy_out_queue') - def dummy(): + def test_service_bus_queue_output_binding(): pass func = self._get_user_function(app) @@ -468,7 +468,7 @@ def test_service_bus_queue_full_args(self): data_type=DataType.STREAM, access_rights=AccessRights.MANAGE, dummy_field="dummy") - def dummy(): + def test_service_bus_queue_full_args(): pass func = self._get_user_function(app) @@ -510,7 +510,7 @@ def test_service_bus_topic_default_args(self): @app.service_bus_topic_output(arg_name='res', connection='dummy_conn', topic_name='dummy_topic', subscription_name='dummy_sub') - def dummy(): + def test_service_bus_topic_default_args(): pass func = self._get_user_function(app) @@ -543,7 +543,7 @@ def test_service_bus_topic_trigger(self): connection='dummy_conn', topic_name='dummy_topic', subscription_name='dummy_sub') - def dummy(): + def test_service_bus_topic_trigger(): pass func = self._get_user_function(app) @@ -570,7 +570,7 @@ def test_service_bus_topic_output_binding(self): @app.service_bus_topic_output(arg_name='res', connection='dummy_conn', topic_name='dummy_topic', subscription_name='dummy_sub') - def dummy(): + def test_service_bus_topic_output_binding(): pass func = self._get_user_function(app) @@ -605,7 +605,7 @@ def test_service_bus_topic_full_args(self): data_type=DataType.STRING, access_rights=AccessRights.LISTEN, dummy_field="dummy") - def dummy(): + def test_service_bus_topic_full_args(): pass func = self._get_user_function(app) @@ -648,7 +648,7 @@ def test_event_hub_default_args(self): @app.event_hub_output(arg_name="res", event_hub_name="dummy_event_hub", connection="dummy_connection") - def dummy(): + def test_event_hub_default_args(): pass func = self._get_user_function(app) @@ -678,7 +678,7 @@ def test_event_hub_trigger(self): @app.event_hub_message_trigger(arg_name="req", connection="dummy_connection", event_hub_name="dummy_event_hub") - def dummy(): + def test_event_hub_trigger(): pass func = self._get_user_function(app) @@ -703,7 +703,7 @@ def test_event_hub_output_binding(self): @app.event_hub_output(arg_name="res", event_hub_name="dummy_event_hub", connection="dummy_connection") - def dummy(): + def test_event_hub_output_binding(): pass func = self._get_user_function(app) @@ -734,7 +734,7 @@ def test_event_hub_full_args(self): connection="dummy_connection", data_type=DataType.UNDEFINED, dummy_field="dummy") - def dummy(): + def test_event_hub_full_args(): pass func = self._get_user_function(app) @@ -810,7 +810,7 @@ def test_cosmosdb_v3_full_args(self): preferred_locations="dummy_location", data_type=DataType.STRING, dummy_field="dummy") - def dummy(): + def test_cosmosdb_v3_full_args(): pass func = self._get_user_function(app) @@ -927,7 +927,7 @@ def test_cosmosdb_full_args(self): preferred_locations="dummy_location", data_type=DataType.STRING, dummy_field="dummy") - def dummy(): + def test_cosmosdb_full_args(): pass func = self._get_user_function(app) @@ -1011,7 +1011,7 @@ def test_cosmosdb_v3_default_args(self): database_name="dummy_out_db", collection_name="dummy_out_collection", connection_string_setting="dummy_str") - def dummy(): + def test_cosmosdb_v3_default_args(): pass func = self._get_user_function(app) @@ -1061,7 +1061,7 @@ def test_cosmosdb_default_args(self): database_name="dummy_out_db", container_name="dummy_out_container", connection="dummy_str") - def dummy(): + def test_cosmosdb_default_args(): pass func = self._get_user_function(app) @@ -1104,7 +1104,7 @@ def test_cosmosdb_v3_trigger(self): database_name="dummy_db", collection_name="dummy_collection", connection_string_setting="dummy_str") - def dummy(): + def test_cosmosdb_v3_trigger(): pass func = self._get_user_function(app) @@ -1128,7 +1128,7 @@ def test_cosmosdb_trigger(self): database_name="dummy_db", container_name="dummy_container", connection="dummy_str") - def dummy(): + def test_cosmosdb_trigger(): pass func = self._get_user_function(app) @@ -1152,7 +1152,7 @@ def test_not_http_function(self): database_name="dummy_db", container_name="dummy_container", connection="dummy_str") - def dummy(): + def test_not_http_function(): pass funcs = app.get_functions() @@ -1171,7 +1171,7 @@ def test_cosmosdb_v3_input_binding(self): database_name="dummy_in_db", collection_name="dummy_in_collection", connection_string_setting="dummy_str") - def dummy(): + def test_cosmosdb_v3_input_binding(): pass func = self._get_user_function(app) @@ -1200,7 +1200,7 @@ def test_cosmosdb_input_binding(self): database_name="dummy_in_db", container_name="dummy_in_container", connection="dummy_str") - def dummy(): + def test_cosmosdb_input_binding(): pass func = self._get_user_function(app) @@ -1229,7 +1229,7 @@ def test_cosmosdb_v3_output_binding(self): database_name="dummy_out_db", collection_name="dummy_out_collection", connection_string_setting="dummy_str") - def dummy(): + def test_cosmosdb_v3_output_binding(): pass func = self._get_user_function(app) @@ -1258,7 +1258,7 @@ def test_cosmosdb_output_binding(self): database_name="dummy_out_db", container_name="dummy_out_container", connection="dummy_str") - def dummy(): + def test_cosmosdb_output_binding(): pass func = self._get_user_function(app) @@ -1284,7 +1284,7 @@ def test_multiple_triggers(self): @app.schedule(arg_name="req1", schedule="dummy_schedule") @app.schedule(arg_name="req2", schedule="dummy_schedule") - def dummy(): + def test_multiple_triggers(): pass self.assertEqual(err.exception.args[0], "A trigger was already registered to this " @@ -1299,13 +1299,13 @@ def test_no_trigger(self): with self.assertRaises(ValueError) as err: @app.queue_output(arg_name="out", queue_name="dummy_out_queue", connection="dummy_out_conn") - def dummy(): + def test_no_trigger(): pass app.get_functions() self.assertEqual(err.exception.args[0], - "Function dummy does not have a trigger. A valid " + "Function test_no_trigger does not have a trigger. A valid " "function must have one and only one trigger " "registered.") @@ -1337,7 +1337,7 @@ def test_multiple_input_bindings(self): arg_name="res", event_hub_name="dummy_event_hub", connection="dummy_connection") - def dummy(): + def test_multiple_input_bindings(): pass func = self._get_user_function(app) @@ -1464,7 +1464,7 @@ def test_blob_default_args(self): connection="dummy_conn") @app.blob_output(arg_name="out", path="dummy_out_path", connection="dummy_out_conn") - def dummy(): + def test_blob_default_args(): pass func = self._get_user_function(app) @@ -1499,7 +1499,7 @@ def test_blob_trigger(self): @app.blob_trigger(arg_name="req", path="dummy_path", data_type=DataType.STRING, connection="dummy_conn") - def dummy(): + def test_blob_trigger(): pass func = self._get_user_function(app) @@ -1526,7 +1526,7 @@ def test_blob_input_binding(self): @app.blob_input(arg_name="file", path="dummy_in_path", connection="dummy_in_conn", data_type=DataType.STRING) - def dummy(): + def test_blob_input_binding(): pass func = self._get_user_function(app) @@ -1564,7 +1564,7 @@ def test_blob_output_binding(self): @app.blob_output(arg_name="out", path="dummy_out_path", connection="dummy_out_conn", data_type=DataType.STRING) - def dummy(): + def test_blob_output_binding(): pass func = self._get_user_function(app) @@ -1600,7 +1600,7 @@ def test_custom_trigger(self): data_type=DataType.BINARY, connection="dummy_conn", path="dummy_path") - def dummy(): + def test_custom_trigger(): pass func = self._get_user_function(app) @@ -1629,7 +1629,7 @@ def test_custom_input_binding(self): path="dummy_in_path", connection="dummy_in_conn", data_type=DataType.STRING) - def dummy(): + def test_custom_input_binding(): pass func = self._get_user_function(app) @@ -1667,7 +1667,7 @@ def test_custom_output_binding(self): path="dummy_out_path", connection="dummy_out_conn", data_type=DataType.STRING) - def dummy(): + def test_custom_output_binding(): pass func = self._get_user_function(app) @@ -1696,7 +1696,7 @@ def test_custom_http_trigger(self): app = self.func_app @app.generic_trigger(arg_name="req", type=HTTP_TRIGGER) - def dummy(): + def test_custom_http_trigger(): pass func = self._get_user_function(app) @@ -1710,7 +1710,7 @@ def dummy(): "direction": BindingDirection.IN, "type": HTTP_TRIGGER, "name": "req", - "route": "dummy", + "route": "test_custom_http_trigger", "authLevel": AuthLevel.FUNCTION }) @@ -1719,7 +1719,7 @@ def test_custom_binding_with_excluded_params(self): @app.generic_trigger(arg_name="req", type=QUEUE_TRIGGER, direction=BindingDirection.INOUT) - def dummy(): + def test_custom_binding_with_excluded_params(): pass func = self._get_user_function(app) @@ -1741,7 +1741,7 @@ def test_mixed_custom_and_supported_binding(self): path="dummy_out_path", connection="dummy_out_conn", data_type=DataType.STRING) - def dummy(): + def test_mixed_custom_and_supported_binding(): pass func = self._get_user_function(app) @@ -1774,7 +1774,7 @@ def test_event_grid_default_args(self): arg_name="res", topic_endpoint_uri="dummy_topic_endpoint_uri", topic_key_setting="dummy_topic_key_setting") - def dummy(): + def test_event_grid_default_args(): pass func = self._get_user_function(app) @@ -1810,7 +1810,7 @@ def test_event_grid_full_args(self): data_type=DataType.UNDEFINED, dummy_field="dummy" ) - def dummy(): + def test_event_grid_full_args(): pass func = self._get_user_function(app) @@ -1841,7 +1841,7 @@ def test_event_grid_trigger(self): app = self.func_app @app.event_grid_trigger(arg_name="req") - def dummy(): + def test_event_grid_trigger(): pass func = self._get_user_function(app) @@ -1863,7 +1863,7 @@ def test_event_grid_output_binding(self): arg_name="res", topic_endpoint_uri="dummy_topic_endpoint_uri", topic_key_setting="dummy_topic_key_setting") - def dummy(): + def test_event_grid_output_binding(): pass func = self._get_user_function(app) @@ -1889,7 +1889,7 @@ def test_table_default_args(self): connection="dummy_out_conn", row_key="dummy_key", partition_key="dummy_partition_key") - def dummy(): + def test_table_default_args(): pass func = self._get_user_function(app) @@ -1918,7 +1918,7 @@ def dummy(): "type": HTTP_TRIGGER, "name": "req", "authLevel": AuthLevel.FUNCTION, - "route": "dummy" + "route": "test_table_default_args" }, { "direction": BindingDirection.OUT, @@ -1946,7 +1946,7 @@ def test_table_with_all_args(self): connection="dummy_out_conn", row_key="dummy_key", partition_key="dummy_partition_key") - def dummy(): + def test_table_with_all_args(): pass func = self._get_user_function(app) @@ -2004,7 +2004,7 @@ def test_table_input_binding(self): take=1, filter="dummy_filter", data_type=DataType.STRING) - def dummy(): + def test_table_input_binding(): pass func = self._get_user_function(app) @@ -2035,7 +2035,7 @@ def test_table_output_binding(self): row_key="dummy_key", partition_key="dummy_partition_key", data_type=DataType.STRING) - def dummy(): + def test_table_output_binding(): pass func = self._get_user_function(app) @@ -2067,7 +2067,7 @@ def test_sql_default_args(self): @app.sql_output(arg_name="out", command_text="dummy_table", connection_string_setting="dummy_setting") - def dummy(): + def test_sql_default_args(): pass func = self._get_user_function(app) @@ -2120,7 +2120,7 @@ def test_sql_full_args(self): connection_string_setting="dummy_setting", data_type=DataType.STRING, dummy_field="dummy") - def dummy(): + def test_sql_full_args(): pass func = self._get_user_function(app) @@ -2166,7 +2166,7 @@ def test_sql_trigger(self): @app.sql_trigger(arg_name="trigger", table_name="dummy_table", connection_string_setting="dummy_setting") - def dummy(): + def test_sql_trigger(): pass func = self._get_user_function(app) @@ -2191,7 +2191,7 @@ def test_sql_input_binding(self): @app.sql_input(arg_name="in", command_text="dummy_query", connection_string_setting="dummy_setting") - def dummy(): + def test_sql_input_binding(): pass func = self._get_user_function(app) @@ -2217,7 +2217,7 @@ def test_sql_output_binding(self): @app.sql_output(arg_name="out", command_text="dummy_table", connection_string_setting="dummy_setting") - def dummy(): + def test_sql_output_binding(): pass func = self._get_user_function(app) @@ -2251,7 +2251,7 @@ def test_function_app_full_bindings_metadata_key_order(self): connection="dummy_out_conn", row_key="dummy_key", partition_key="dummy_partition_key") - def dummy(): + def test_function_app_full_bindings_metadata_key_order(): pass self._test_function_metadata_order(app) @@ -2260,7 +2260,7 @@ def test_function_app_generic_http_trigger_metadata_key_order(self): app = self.func_app @app.generic_trigger(arg_name="req", type=HTTP_TRIGGER) - def dummy(): + def test_function_app_generic_http_trigger_metadata_key_order(): pass self._test_function_metadata_order(app) @@ -2278,11 +2278,11 @@ def test_function_app_retry_default_args(self): @app.schedule(arg_name="req", schedule="dummy_schedule") @app.retry(strategy="fixed", max_retry_count="2", delay_interval="4") - def dummy_func(): + def test_function_app_retry_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "dummy_func") + self.assertEqual(func.get_function_name(), "test_function_app_retry_default_args") self.assertEqual(func.get_setting("retry_policy").get_dict_repr(), { 'setting_name': 'retry_policy', 'strategy': 'fixed', diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index 5ba666f2..c00d9f01 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -112,30 +112,42 @@ def test_function_creation_with_binding_and_trigger(self): class TestFunctionBuilder(unittest.TestCase): - def setUp(self): - def dummy(): + + def test_function_builder_creation(self): + def test_function_builder_creation(): return "dummy" - self.dummy = dummy + self.dummy = test_function_builder_creation self.fb = FunctionBuilder(self.dummy, "dummy.py") - def test_function_builder_creation(self): self.assertTrue(callable(self.fb)) func = getattr(self.fb, "_function") self.assertEqual(self.fb._function.function_script_file, "dummy.py") self.assertEqual(func.get_user_function(), self.dummy) def test_validate_function_missing_trigger(self): + def test_validate_function_missing_trigger(): + return "dummy" + + self.dummy = test_validate_function_missing_trigger + self.fb = FunctionBuilder(self.dummy, "dummy.py") + with self.assertRaises(ValueError) as err: # self.fb.configure_function_name('dummy').build() self.fb.build() self.assertEqual(err.exception.args[0], - "Function dummy does not have a trigger. A valid " + "Function test_validate_function_missing_trigger does not have a trigger. A valid " "function must have one and only one trigger " "registered.") def test_validate_function_trigger_not_in_bindings(self): + def test_validate_function_trigger_not_in_bindings(): + return "dummy" + + self.dummy = test_validate_function_trigger_not_in_bindings + self.fb = FunctionBuilder(self.dummy, "dummy.py") + trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), data_type=DataType.UNDEFINED, auth_level=AuthLevel.ANONYMOUS, @@ -146,36 +158,54 @@ def test_validate_function_trigger_not_in_bindings(self): self.fb.build() self.assertEqual(err.exception.args[0], - f"Function dummy trigger {trigger} not present" + f"Function test_validate_function_trigger_not_in_bindings trigger {trigger} not present" f" in bindings {[]}") def test_validate_function_working(self): + def test_validate_function_working(): + return "dummy" + + self.dummy = test_validate_function_working + self.fb = FunctionBuilder(self.dummy, "dummy.py") + trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), data_type=DataType.UNDEFINED, - auth_level=AuthLevel.ANONYMOUS) + auth_level=AuthLevel.ANONYMOUS, + route='test_validate_function_working') self.fb.add_trigger(trigger) self.fb.build() def test_build_function_http_route_default(self): + def test_build_function_http_route_default(): + return "dummy" + + self.dummy = test_build_function_http_route_default + self.fb = FunctionBuilder(self.dummy, "dummy.py") + trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), data_type=DataType.UNDEFINED, auth_level=AuthLevel.ANONYMOUS) self.fb.add_trigger(trigger) func = self.fb.build() - self.assertEqual(func.get_trigger().route, "dummy") + self.assertEqual(func.get_trigger().route, "test_build_function_http_route_default") def test_build_function_with_bindings(self): + def test_build_function_with_bindings(): + return "dummy" + + self.dummy = test_build_function_with_bindings + self.fb = FunctionBuilder(self.dummy, "dummy.py") + test_trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), data_type=DataType.UNDEFINED, - auth_level=AuthLevel.ANONYMOUS, - route='dummy') + auth_level=AuthLevel.ANONYMOUS) test_input = HttpOutput(name='out', data_type=DataType.UNDEFINED) func = self.fb.add_trigger( test_trigger).add_binding(test_input).build() - self.assertEqual(func.get_function_name(), "dummy") + self.assertEqual(func.get_function_name(), "test_build_function_with_bindings") assert_json(self, func, { "scriptFile": "dummy.py", "bindings": [ @@ -185,7 +215,7 @@ def test_build_function_with_bindings(self): "direction": BindingDirection.IN, "name": "req", "dataType": DataType.UNDEFINED, - "route": "dummy", + "route": "test_build_function_with_bindings", "methods": [ HttpMethod.GET ] @@ -200,6 +230,12 @@ def test_build_function_with_bindings(self): }) def test_build_function_with_function_app_auth_level(self): + def test_build_function_with_function_app_auth_level(): + return "dummy" + + self.dummy = test_build_function_with_function_app_auth_level + self.fb = FunctionBuilder(self.dummy, "dummy.py") + trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), data_type=DataType.UNDEFINED) self.fb.add_trigger(trigger) @@ -208,11 +244,18 @@ def test_build_function_with_function_app_auth_level(self): self.assertEqual(func.get_trigger().auth_level, AuthLevel.ANONYMOUS) def test_build_function_with_retry_policy_setting(self): + def test_build_function_with_retry_policy_setting(): + return "dummy" + + self.dummy = test_build_function_with_retry_policy_setting + self.fb = FunctionBuilder(self.dummy, "dummy.py") + setting = RetryPolicy(strategy="exponential", max_retry_count="2", minimum_interval="1", maximum_interval="5") trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), data_type=DataType.UNDEFINED, - auth_level=AuthLevel.ANONYMOUS) + auth_level=AuthLevel.ANONYMOUS, + route='test_build_function_with_retry_policy_setting') self.fb.add_trigger(trigger) self.fb.add_setting(setting) func = self.fb.build() @@ -226,120 +269,120 @@ def test_unique_method_names(self): app = FunctionApp() @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_unique_method_names(name: str): return name @app.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_unique_method_names2(name: str): return name functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "hello") - self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertEqual(functions[0].get_function_name(), "test_unique_method_names") + self.assertEqual(functions[1].get_function_name(), "test_unique_method_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello")[0], TimerTrigger) + "test_unique_method_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello2")[0], TimerTrigger) + "test_unique_method_names2")[0], TimerTrigger) def test_unique_function_names(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_unique_function_names") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_unique_function_names(name: str): return name - @app.function_name("hello2") + @app.function_name("test_unique_function_names2") @app.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_unique_function_names2(name: str): return name functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "hello") - self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertEqual(functions[0].get_function_name(), "test_unique_function_names") + self.assertEqual(functions[1].get_function_name(), "test_unique_function_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello")[0], TimerTrigger) + "test_unique_function_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello2")[0], TimerTrigger) + "test_unique_function_names2")[0], TimerTrigger) def test_same_method_names(self): app = FunctionApp() @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_same_method_names(name: str): return name @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): # NoQA + def test_same_method_names(name: str): # NoQA return name with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_same_method_names does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") def test_same_function_names(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_same_function_names") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_same_function_names(name: str): return name - @app.function_name("hello") + @app.function_name("test_same_function_names") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): # NoQA + def test_same_function_names(name: str): # NoQA return name with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_same_function_names does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") def test_same_function_name_different_method_name(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_same_function_name_different_method_name") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_same_function_name_different_method_name(name: str): return name - @app.function_name("hello") + @app.function_name("test_same_function_name_different_method_name") @app.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_same_function_name_different_method_name2(name: str): return name with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_same_function_name_different_method_name does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") def test_same_function_and_method_name(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_same_function_and_method_name") @app.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_same_function_and_method_name2(name: str): return name @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_same_function_and_method_name(name: str): return name with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_same_function_and_method_name does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") @@ -347,13 +390,13 @@ def test_blueprint_unique_method_names(self): app = FunctionApp() @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_blueprint_unique_method_names(name: str): return name bp = Blueprint() @bp.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_blueprint_unique_method_names2(name: str): return name app.register_blueprint(bp) @@ -361,26 +404,26 @@ def hello2(name: str): functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "hello") - self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertEqual(functions[0].get_function_name(), "test_blueprint_unique_method_names") + self.assertEqual(functions[1].get_function_name(), "test_blueprint_unique_method_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello")[0], TimerTrigger) + "test_blueprint_unique_method_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello2")[0], TimerTrigger) + "test_blueprint_unique_method_names2")[0], TimerTrigger) def test_blueprint_unique_function_names(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_blueprint_unique_function_names") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_blueprint_unique_function_names(name: str): return name bp = Blueprint() - @bp.function_name("hello2") + @bp.function_name("test_blueprint_unique_function_names2") @bp.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_blueprint_unique_function_names2(name: str): return name app.register_blueprint(bp) @@ -388,24 +431,24 @@ def hello2(name: str): functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "hello") - self.assertEqual(functions[1].get_function_name(), "hello2") + self.assertEqual(functions[0].get_function_name(), "test_blueprint_unique_function_names") + self.assertEqual(functions[1].get_function_name(), "test_blueprint_unique_function_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello")[0], TimerTrigger) + "test_blueprint_unique_function_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( - "hello2")[0], TimerTrigger) + "test_blueprint_unique_function_names2")[0], TimerTrigger) def test_blueprint_same_method_names(self): app = FunctionApp() @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_blueprint_same_method_names(name: str): return name bp = Blueprint() @bp.schedule(arg_name="name", schedule="10****") - def hello(name: str): # NoQA + def test_blueprint_same_method_names(name: str): # NoQA return name app.register_blueprint(bp) @@ -413,23 +456,23 @@ def hello(name: str): # NoQA with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_blueprint_same_method_names does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") def test_blueprint_same_function_names(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_blueprint_same_function_names") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_blueprint_same_function_names(name: str): return name bp = Blueprint() - @bp.function_name("hello") + @bp.function_name("test_blueprint_same_function_names") @bp.schedule(arg_name="name", schedule="10****") - def hello(name: str): # NoQA + def test_blueprint_same_function_names(name: str): # NoQA return name app.register_blueprint(bp) @@ -437,23 +480,23 @@ def hello(name: str): # NoQA with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_blueprint_same_function_names does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") def test_blueprint_same_function_name_different_method_name(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_blueprint_same_function_name_different_method_name") @app.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_blueprint_same_function_name_different_method_name(name: str): return name bp = Blueprint() - @bp.function_name("hello") + @bp.function_name("test_blueprint_same_function_name_different_method_name") @bp.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_blueprint_same_function_name_different_method_name2(name: str): return name app.register_blueprint(bp) @@ -461,22 +504,22 @@ def hello2(name: str): with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_blueprint_same_function_name_different_method_name does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") def test_blueprint_same_function_and_method_name(self): app = FunctionApp() - @app.function_name("hello") + @app.function_name("test_blueprint_same_function_and_method_name") @app.schedule(arg_name="name", schedule="10****") - def hello2(name: str): + def test_blueprint_same_function_and_method_name2(name: str): return name bp = Blueprint() @bp.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_blueprint_same_function_and_method_name(name: str): return name app.register_blueprint(bp) @@ -484,7 +527,7 @@ def hello(name: str): with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function hello does not have a unique" + "Function test_blueprint_same_function_and_method_name does not have a unique" " function name. Please change @app.function_name()" " or the function method name to be unique.") @@ -513,12 +556,12 @@ def test_has_function_builders(self): def test_dummy_app_trigger(self): @self.dummy.dummy_trigger(name="dummy") - def dummy(): + def test_dummy_app_trigger(): return "dummy" self.assertEqual(len(self.dummy._function_builders), 1) func = self.dummy._function_builders[0].build() - self.assertEqual(func.get_function_name(), "dummy") + self.assertEqual(func.get_function_name(), "test_dummy_app_trigger") self.assertEqual(func.get_function_json(), '{"scriptFile": "function_app.py", "bindings": [{' '"direction": "IN", "dataType": "UNDEFINED", ' @@ -583,14 +626,16 @@ def test_add_asgi(self, add_http_app_mock): '._add_http_app') def test_add_wsgi(self, add_http_app_mock): mock_wsgi_app = object() - WsgiFunctionApp(app=mock_wsgi_app) + app = WsgiFunctionApp(app=mock_wsgi_app) add_http_app_mock.assert_called_once() self.assertIsInstance(add_http_app_mock.call_args[0][0], WsgiMiddleware) def test_add_asgi_app(self): - self._test_http_external_app(AsgiFunctionApp(app=object()), True) + asgi_app = AsgiFunctionApp(app=object()) + asgi_app.function_name("test") + self._test_http_external_app(asgi_app, True) def test_add_wsgi_app(self): self._test_http_external_app(WsgiFunctionApp(app=object()), False) From d126fec1d0dcec9356e3626f07ddf8d9cbdc24c5 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 11:02:22 -0500 Subject: [PATCH 04/16] lint --- azure/functions/decorators/function_app.py | 2 +- tests/decorators/test_decorators.py | 24 +++-- tests/decorators/test_function_app.py | 118 +++++++++++++-------- 3 files changed, 88 insertions(+), 56 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 0b5b0a6a..38361f95 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,7 +204,7 @@ def __str__(self): class FunctionBuilder(object): - function_bindings = {} + function_bindings: dict[str, str] = {} def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) diff --git a/tests/decorators/test_decorators.py b/tests/decorators/test_decorators.py index 5c1043d4..1f5ace94 100644 --- a/tests/decorators/test_decorators.py +++ b/tests/decorators/test_decorators.py @@ -49,9 +49,11 @@ def test_route_is_python_function_name(): func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "test_route_is_python_function_name") + self.assertEqual(func.get_function_name(), + "test_route_is_python_function_name") self.assertTrue(isinstance(func.get_trigger(), HttpTrigger)) - self.assertTrue(func.get_trigger().route, "test_route_is_python_function_name") + self.assertTrue(func.get_trigger().route, + "test_route_is_python_function_name") def test_route_is_custom(self): app = self.func_app @@ -75,7 +77,8 @@ def test_schedule_trigger_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "test_schedule_trigger_default_args") + self.assertEqual(func.get_function_name(), + "test_schedule_trigger_default_args") assert_json(self, func, { "scriptFile": "function_app.py", "bindings": [ @@ -122,7 +125,8 @@ def test_timer_trigger_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "test_timer_trigger_default_args") + self.assertEqual(func.get_function_name(), + "test_timer_trigger_default_args") assert_json(self, func, { "scriptFile": "function_app.py", "bindings": [ @@ -308,7 +312,8 @@ def test_warmup_trigger_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "test_warmup_trigger_default_args") + self.assertEqual(func.get_function_name(), + "test_warmup_trigger_default_args") assert_json(self, func, { "scriptFile": "function_app.py", "bindings": [ @@ -1384,9 +1389,9 @@ def test_no_trigger(): app.get_functions() self.assertEqual(err.exception.args[0], - "Function test_no_trigger does not have a trigger. A valid " - "function must have one and only one trigger " - "registered.") + "Function test_no_trigger does not have a trigger." + " A valid function must have one and only one" + " trigger registered.") def test_multiple_input_bindings(self): app = self.func_app @@ -2367,7 +2372,8 @@ def test_function_app_retry_default_args(): pass func = self._get_user_function(app) - self.assertEqual(func.get_function_name(), "test_function_app_retry_default_args") + self.assertEqual(func.get_function_name(), + "test_function_app_retry_default_args") self.assertEqual(func.get_setting("retry_policy").get_dict_repr(), { 'setting_name': 'retry_policy', 'strategy': 'fixed', diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index c00d9f01..d6b51555 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -137,9 +137,9 @@ def test_validate_function_missing_trigger(): self.fb.build() self.assertEqual(err.exception.args[0], - "Function test_validate_function_missing_trigger does not have a trigger. A valid " - "function must have one and only one trigger " - "registered.") + "Function test_validate_function_missing_trigger" + " does not have a trigger. A valid function must have" + " one and only one trigger registered.") def test_validate_function_trigger_not_in_bindings(self): def test_validate_function_trigger_not_in_bindings(): @@ -157,9 +157,11 @@ def test_validate_function_trigger_not_in_bindings(): getattr(self.fb, "_function").get_bindings().clear() self.fb.build() - self.assertEqual(err.exception.args[0], - f"Function test_validate_function_trigger_not_in_bindings trigger {trigger} not present" - f" in bindings {[]}") + self.assertEqual( + err.exception.args[0], + f"Function test_validate_function_trigger_not_in_bindings" + f" trigger {trigger} not present" + f" in bindings {[]}") def test_validate_function_working(self): def test_validate_function_working(): @@ -188,7 +190,8 @@ def test_build_function_http_route_default(): self.fb.add_trigger(trigger) func = self.fb.build() - self.assertEqual(func.get_trigger().route, "test_build_function_http_route_default") + self.assertEqual(func.get_trigger().route, + "test_build_function_http_route_default") def test_build_function_with_bindings(self): def test_build_function_with_bindings(): @@ -205,7 +208,8 @@ def test_build_function_with_bindings(): func = self.fb.add_trigger( test_trigger).add_binding(test_input).build() - self.assertEqual(func.get_function_name(), "test_build_function_with_bindings") + self.assertEqual(func.get_function_name(), + "test_build_function_with_bindings") assert_json(self, func, { "scriptFile": "dummy.py", "bindings": [ @@ -252,10 +256,11 @@ def test_build_function_with_retry_policy_setting(): setting = RetryPolicy(strategy="exponential", max_retry_count="2", minimum_interval="1", maximum_interval="5") - trigger = HttpTrigger(name='req', methods=(HttpMethod.GET,), - data_type=DataType.UNDEFINED, - auth_level=AuthLevel.ANONYMOUS, - route='test_build_function_with_retry_policy_setting') + trigger = HttpTrigger( + name='req', methods=(HttpMethod.GET,), + data_type=DataType.UNDEFINED, + auth_level=AuthLevel.ANONYMOUS, + route='test_build_function_with_retry_policy_setting') self.fb.add_trigger(trigger) self.fb.add_setting(setting) func = self.fb.build() @@ -279,8 +284,10 @@ def test_unique_method_names2(name: str): functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "test_unique_method_names") - self.assertEqual(functions[1].get_function_name(), "test_unique_method_names2") + self.assertEqual(functions[0].get_function_name(), + "test_unique_method_names") + self.assertEqual(functions[1].get_function_name(), + "test_unique_method_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( "test_unique_method_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( @@ -302,8 +309,10 @@ def test_unique_function_names2(name: str): functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "test_unique_function_names") - self.assertEqual(functions[1].get_function_name(), "test_unique_function_names2") + self.assertEqual(functions[0].get_function_name(), + "test_unique_function_names") + self.assertEqual(functions[1].get_function_name(), + "test_unique_function_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( "test_unique_function_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( @@ -323,8 +332,9 @@ def test_same_method_names(name: str): # NoQA with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function test_same_method_names does not have a unique" - " function name. Please change @app.function_name()" + "Function test_same_method_names does not have" + " a unique function name." + " Please change @app.function_name()" " or the function method name to be unique.") def test_same_function_names(self): @@ -343,8 +353,9 @@ def test_same_function_names(name: str): # NoQA with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function test_same_function_names does not have a unique" - " function name. Please change @app.function_name()" + "Function test_same_function_names does not have" + " a unique function name." + " Please change @app.function_name()" " or the function method name to be unique.") def test_same_function_name_different_method_name(self): @@ -362,10 +373,12 @@ def test_same_function_name_different_method_name2(name: str): with self.assertRaises(ValueError) as err: app.get_functions() - self.assertEqual(err.exception.args[0], - "Function test_same_function_name_different_method_name does not have a unique" - " function name. Please change @app.function_name()" - " or the function method name to be unique.") + self.assertEqual( + err.exception.args[0], + "Function test_same_function_name_different_method_name" + " does not have a unique function name." + " Please change @app.function_name()" + " or the function method name to be unique.") def test_same_function_and_method_name(self): app = FunctionApp() @@ -382,8 +395,9 @@ def test_same_function_and_method_name(name: str): with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function test_same_function_and_method_name does not have a unique" - " function name. Please change @app.function_name()" + "Function test_same_function_and_method_name" + " does not have a unique function name." + " Please change @app.function_name()" " or the function method name to be unique.") def test_blueprint_unique_method_names(self): @@ -404,8 +418,10 @@ def test_blueprint_unique_method_names2(name: str): functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "test_blueprint_unique_method_names") - self.assertEqual(functions[1].get_function_name(), "test_blueprint_unique_method_names2") + self.assertEqual(functions[0].get_function_name(), + "test_blueprint_unique_method_names") + self.assertEqual(functions[1].get_function_name(), + "test_blueprint_unique_method_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( "test_blueprint_unique_method_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( @@ -431,8 +447,10 @@ def test_blueprint_unique_function_names2(name: str): functions = app.get_functions() self.assertEqual(len(functions), 2) - self.assertEqual(functions[0].get_function_name(), "test_blueprint_unique_function_names") - self.assertEqual(functions[1].get_function_name(), "test_blueprint_unique_function_names2") + self.assertEqual(functions[0].get_function_name(), + "test_blueprint_unique_function_names") + self.assertEqual(functions[1].get_function_name(), + "test_blueprint_unique_function_names2") self.assertIsInstance(app._function_builders[0].function_bindings.get( "test_blueprint_unique_function_names")[0], TimerTrigger) self.assertIsInstance(app._function_builders[0].function_bindings.get( @@ -456,8 +474,9 @@ def test_blueprint_same_method_names(name: str): # NoQA with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function test_blueprint_same_method_names does not have a unique" - " function name. Please change @app.function_name()" + "Function test_blueprint_same_method_names" + " does not have a unique function name." + " Please change @app.function_name()" " or the function method name to be unique.") def test_blueprint_same_function_names(self): @@ -480,33 +499,38 @@ def test_blueprint_same_function_names(name: str): # NoQA with self.assertRaises(ValueError) as err: app.get_functions() self.assertEqual(err.exception.args[0], - "Function test_blueprint_same_function_names does not have a unique" - " function name. Please change @app.function_name()" - " or the function method name to be unique.") + "Function test_blueprint_same_function_names" + " does not have a unique function name. Please change" + " @app.function_name() or the function method name" + " to be unique.") def test_blueprint_same_function_name_different_method_name(self): app = FunctionApp() - @app.function_name("test_blueprint_same_function_name_different_method_name") + @app.function_name( + "test_blueprint_same_function_name_different_method_name") @app.schedule(arg_name="name", schedule="10****") def test_blueprint_same_function_name_different_method_name(name: str): return name bp = Blueprint() - @bp.function_name("test_blueprint_same_function_name_different_method_name") + @bp.function_name( + "test_blueprint_same_function_name_different_method_name") @bp.schedule(arg_name="name", schedule="10****") - def test_blueprint_same_function_name_different_method_name2(name: str): + def test_blueprint_same_function_name_different_method_name2( + name: str): return name app.register_blueprint(bp) with self.assertRaises(ValueError) as err: app.get_functions() - self.assertEqual(err.exception.args[0], - "Function test_blueprint_same_function_name_different_method_name does not have a unique" - " function name. Please change @app.function_name()" - " or the function method name to be unique.") + self.assertEqual( + err.exception.args[0], + "Function test_blueprint_same_function_name_different_method_name" + " does not have a unique function name. Please change" + " @app.function_name() or the function method name to be unique.") def test_blueprint_same_function_and_method_name(self): app = FunctionApp() @@ -526,10 +550,12 @@ def test_blueprint_same_function_and_method_name(name: str): with self.assertRaises(ValueError) as err: app.get_functions() - self.assertEqual(err.exception.args[0], - "Function test_blueprint_same_function_and_method_name does not have a unique" - " function name. Please change @app.function_name()" - " or the function method name to be unique.") + self.assertEqual( + err.exception.args[0], + "Function test_blueprint_same_function_and_method_name" + " does not have a unique function name." + " Please change @app.function_name() or the function" + " method name to be unique.") class TestScaffold(unittest.TestCase): From c8110ae04c43ffdaadc258766158b01ae4b2a8e3 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 11:12:20 -0500 Subject: [PATCH 05/16] lint --- azure/functions/decorators/function_app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 38361f95..12a20e1b 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,7 +204,7 @@ def __str__(self): class FunctionBuilder(object): - function_bindings: dict[str, str] = {} + function_bindings: dict = {} def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) From ca1e1c8a106b0fedbdad6f263280f945cdd55ac5 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 12:18:19 -0500 Subject: [PATCH 06/16] fixed test_decorator tests --- tests/decorators/test_decorators.py | 8 ++++---- tests/decorators/test_function_app.py | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/decorators/test_decorators.py b/tests/decorators/test_decorators.py index 1f5ace94..224466c3 100644 --- a/tests/decorators/test_decorators.py +++ b/tests/decorators/test_decorators.py @@ -169,7 +169,7 @@ def test_orchestration_trigger(self): app = self.func_app @app.orchestration_trigger("context") - def dummy1(context): + def test_orchestration_trigger(context): pass func = self._get_user_function(app) @@ -188,7 +188,7 @@ def test_activity_trigger(self): app = self.func_app @app.activity_trigger("arg") - def dummy2(arg): + def test_activity_trigger(arg): pass func = self._get_user_function(app) @@ -207,7 +207,7 @@ def test_entity_trigger(self): app = self.func_app @app.entity_trigger("context") - def dummy3(context): + def test_entity_trigger(context): pass func = self._get_user_function(app) @@ -227,7 +227,7 @@ def test_durable_client(self): @app.generic_trigger(arg_name="req", type=HTTP_TRIGGER) @app.durable_client_input(client_name="client") - def dummy(client): + def test_durable_client(client): pass func = self._get_user_function(app) diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index d6b51555..12d3ca99 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -321,12 +321,12 @@ def test_unique_function_names2(name: str): def test_same_method_names(self): app = FunctionApp() - @app.schedule(arg_name="name", schedule="10****") + @app.schedule(arg_name="name", schedule="10****") # NoQA def test_same_method_names(name: str): return name - @app.schedule(arg_name="name", schedule="10****") - def test_same_method_names(name: str): # NoQA + @app.schedule(arg_name="name", schedule="10****") # NoQA + def test_same_method_names(name: str): return name with self.assertRaises(ValueError) as err: @@ -340,12 +340,12 @@ def test_same_method_names(name: str): # NoQA def test_same_function_names(self): app = FunctionApp() - @app.function_name("test_same_function_names") + @app.function_name("test_same_function_names") # NoQA @app.schedule(arg_name="name", schedule="10****") def test_same_function_names(name: str): return name - @app.function_name("test_same_function_names") + @app.function_name("test_same_function_names") # NoQA @app.schedule(arg_name="name", schedule="10****") def test_same_function_names(name: str): # NoQA return name @@ -459,14 +459,14 @@ def test_blueprint_unique_function_names2(name: str): def test_blueprint_same_method_names(self): app = FunctionApp() - @app.schedule(arg_name="name", schedule="10****") + @app.schedule(arg_name="name", schedule="10****") # NoQA def test_blueprint_same_method_names(name: str): return name bp = Blueprint() - @bp.schedule(arg_name="name", schedule="10****") - def test_blueprint_same_method_names(name: str): # NoQA + @bp.schedule(arg_name="name", schedule="10****") # NoQA + def test_blueprint_same_method_names(name: str): return name app.register_blueprint(bp) @@ -482,16 +482,16 @@ def test_blueprint_same_method_names(name: str): # NoQA def test_blueprint_same_function_names(self): app = FunctionApp() - @app.function_name("test_blueprint_same_function_names") + @app.function_name("test_blueprint_same_function_names") # NoQA @app.schedule(arg_name="name", schedule="10****") def test_blueprint_same_function_names(name: str): return name bp = Blueprint() - @bp.function_name("test_blueprint_same_function_names") + @bp.function_name("test_blueprint_same_function_names") # NoQA @bp.schedule(arg_name="name", schedule="10****") - def test_blueprint_same_function_names(name: str): # NoQA + def test_blueprint_same_function_names(name: str): return name app.register_blueprint(bp) From ad5b924565758aa68db03a5361defe38fecac17e Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 12:43:02 -0500 Subject: [PATCH 07/16] fixed function_app tests --- tests/decorators/test_function_app.py | 83 +++++++++++++++------------ 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index 12d3ca99..70c878a8 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -637,35 +637,6 @@ def test_function_builder_decorated_type(self): self.assertTrue(isinstance(fb, FunctionBuilder)) self.assertEqual(fb._function.get_user_function(), self.dummy_func) - @mock.patch('azure.functions.decorators.function_app.AsgiFunctionApp' - '._add_http_app') - def test_add_asgi(self, add_http_app_mock): - mock_asgi_app = object() - AsgiFunctionApp(app=mock_asgi_app) - - add_http_app_mock.assert_called_once() - - self.assertIsInstance(add_http_app_mock.call_args[0][0], - AsgiMiddleware) - - @mock.patch('azure.functions.decorators.function_app.WsgiFunctionApp' - '._add_http_app') - def test_add_wsgi(self, add_http_app_mock): - mock_wsgi_app = object() - app = WsgiFunctionApp(app=mock_wsgi_app) - - add_http_app_mock.assert_called_once() - self.assertIsInstance(add_http_app_mock.call_args[0][0], - WsgiMiddleware) - - def test_add_asgi_app(self): - asgi_app = AsgiFunctionApp(app=object()) - asgi_app.function_name("test") - self._test_http_external_app(asgi_app, True) - - def test_add_wsgi_app(self): - self._test_http_external_app(WsgiFunctionApp(app=object()), False) - def test_register_function_app_error(self): with self.assertRaises(TypeError) as err: FunctionApp().register_functions(FunctionApp()) @@ -677,7 +648,7 @@ def test_register_blueprint(self): bp = Blueprint() @bp.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_register_blueprint(name: str): return "hello" app = FunctionApp() @@ -691,7 +662,7 @@ def test_register_app_auth_level(self): bp = Blueprint() @bp.route("name") - def hello(name: str): + def test_register_app_auth_level(name: str): return "hello" app = FunctionApp(http_auth_level=AuthLevel.ANONYMOUS) @@ -719,12 +690,12 @@ def test_set_http_type(self): @app.route("name1") @app.http_type("dummy1") - def hello(name: str): + def test_set_http_type(name: str): return "hello" @app.route("name2") @app.http_type("dummy2") - def hello2(name: str): + def test_set_http_type2(name: str): return "hello" funcs = app.get_functions() @@ -797,7 +768,7 @@ class DummyFunctionApp(FunctionRegister, TriggerApi): blueprint = Blueprint() @blueprint.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_function_register_non_http_function_app(name: str): return name app.register_blueprint(blueprint) @@ -837,7 +808,7 @@ class DummyFunctionApp(FunctionRegister, TriggerApi): app = DummyFunctionApp(auth_level=AuthLevel.ANONYMOUS) blueprint = LegacyBluePrint() - @blueprint.function_name("timer_function") + @blueprint.function_name("test_legacy_blueprints_with_function_name") @blueprint.schedule(arg_name="name", schedule="10****") def hello(name: str): return name @@ -850,7 +821,7 @@ def hello(name: str): setting = functions[0].get_setting("function_name") self.assertEqual(setting.get_settings_value("function_name"), - "timer_function") + "test_legacy_blueprints_with_function_name") def test_function_register_register_function_register_error(self): class DummyFunctionApp(FunctionRegister): @@ -871,7 +842,8 @@ class DummyFunctionApp(FunctionRegister): blueprint = Blueprint() @blueprint.schedule(arg_name="name", schedule="10****") - def hello(name: str): + def test_function_register_register_functions_from_blueprint( + name: str): return name app.register_blueprint(blueprint) @@ -884,7 +856,9 @@ def hello(name: str): self.assertEqual(trigger.type, TIMER_TRIGGER) self.assertEqual(trigger.schedule, "10****") self.assertEqual(trigger.name, "name") - self.assertEqual(functions[0].get_function_name(), "hello") + self.assertEqual( + functions[0].get_function_name(), + "test_function_register_register_functions_from_blueprint") self.assertEqual(functions[0].get_user_function()("timer"), "timer") def test_asgi_function_app_default(self): @@ -985,3 +959,36 @@ def _test_http_external_app(self, app, is_async): "type": HTTP_OUTPUT } ]}) + +class TestAddAsgi(unittest.TestCase): + @mock.patch('azure.functions.decorators.function_app.AsgiFunctionApp' + '._add_http_app') + def test_add_asgi(self, add_http_app_mock): + mock_asgi_app = object() + AsgiFunctionApp(app=mock_asgi_app) + + add_http_app_mock.assert_called_once() + + self.assertIsInstance(add_http_app_mock.call_args[0][0], + AsgiMiddleware) + +class TestAddWsgi(unittest.TestCase): + @mock.patch('azure.functions.decorators.function_app.WsgiFunctionApp' + '._add_http_app') + def test_add_wsgi(self, add_http_app_mock): + mock_wsgi_app = object() + app = WsgiFunctionApp(app=mock_wsgi_app) + + add_http_app_mock.assert_called_once() + self.assertIsInstance(add_http_app_mock.call_args[0][0], + WsgiMiddleware) + +class TestAddAsgiApp(unittest.TestCase): + def test_add_asgi_app(self): + asgi_app = AsgiFunctionApp(app=object()) + asgi_app.function_name("test") + self._test_http_external_app(asgi_app, True) + +class TestAddWsgiApp(unittest.TestCase): + def test_add_wsgi_app(self): + self._test_http_external_app(WsgiFunctionApp(app=object()), False) \ No newline at end of file From 610f392b90d4b35164f2b1620b476d0bdf7012bc Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 14:01:33 -0500 Subject: [PATCH 08/16] configurable fx name for wsgi / asgi --- azure/functions/decorators/function_app.py | 23 +++++-- tests/decorators/test_function_app.py | 80 +++++++++++----------- 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 12a20e1b..32ff7a03 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -3349,11 +3349,13 @@ class ExternalHttpFunctionApp(FunctionRegister, TriggerApi, ABC): @abc.abstractmethod def _add_http_app(self, http_middleware: Union[ - AsgiMiddleware, WsgiMiddleware]) -> None: + AsgiMiddleware, WsgiMiddleware], + function_name: Optional[str] = 'http_app_func') -> None: """Add a Wsgi or Asgi app integrated http function. :param http_middleware: :class:`WsgiMiddleware` or class:`AsgiMiddleware` instance. + :param function_name: an optional namae for the function :return: None """ @@ -3362,7 +3364,8 @@ def _add_http_app(self, class AsgiFunctionApp(ExternalHttpFunctionApp): def __init__(self, app, - http_auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION): + http_auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION, + function_name: Optional[str] = 'http_app_func'): """Constructor of :class:`AsgiFunctionApp` object. :param app: asgi app object. @@ -3372,7 +3375,7 @@ def __init__(self, app, """ super().__init__(auth_level=http_auth_level) self.middleware = AsgiMiddleware(app) - self._add_http_app(self.middleware) + self._add_http_app(self.middleware, function_name) self.startup_task_done = False def __del__(self): @@ -3381,7 +3384,8 @@ def __del__(self): def _add_http_app(self, http_middleware: Union[ - AsgiMiddleware, WsgiMiddleware]) -> None: + AsgiMiddleware, WsgiMiddleware], + function_name: Optional[str] = 'http_app_func') -> None: """Add an Asgi app integrated http function. :param http_middleware: :class:`WsgiMiddleware` @@ -3395,6 +3399,7 @@ def _add_http_app(self, asgi_middleware: AsgiMiddleware = http_middleware + @self.function_name(name=function_name) @self.http_type(http_type='asgi') @self.route(methods=(method for method in HttpMethod), auth_level=self.auth_level, @@ -3411,21 +3416,24 @@ async def http_app_func(req: HttpRequest, context: Context): class WsgiFunctionApp(ExternalHttpFunctionApp): def __init__(self, app, - http_auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION): + http_auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION, + function_name: Optional[str] = 'http_app_func'): """Constructor of :class:`WsgiFunctionApp` object. :param app: wsgi app object. """ super().__init__(auth_level=http_auth_level) - self._add_http_app(WsgiMiddleware(app)) + self._add_http_app(WsgiMiddleware(app), function_name) def _add_http_app(self, http_middleware: Union[ - AsgiMiddleware, WsgiMiddleware]) -> None: + AsgiMiddleware, WsgiMiddleware], + function_name: Optional[str] = 'http_app_func') -> None: """Add a Wsgi app integrated http function. :param http_middleware: :class:`WsgiMiddleware` or class:`AsgiMiddleware` instance. + :param function_name: an optional name for the function :return: None """ @@ -3435,6 +3443,7 @@ def _add_http_app(self, wsgi_middleware: WsgiMiddleware = http_middleware + @self.function_name(function_name) @self.http_type(http_type='wsgi') @self.route(methods=(method for method in HttpMethod), auth_level=self.auth_level, diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index 70c878a8..695e037d 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -322,11 +322,11 @@ def test_same_method_names(self): app = FunctionApp() @app.schedule(arg_name="name", schedule="10****") # NoQA - def test_same_method_names(name: str): + def test_same_method_names(name: str): # NoQA return name @app.schedule(arg_name="name", schedule="10****") # NoQA - def test_same_method_names(name: str): + def test_same_method_names(name: str): # NoQA return name with self.assertRaises(ValueError) as err: @@ -460,13 +460,13 @@ def test_blueprint_same_method_names(self): app = FunctionApp() @app.schedule(arg_name="name", schedule="10****") # NoQA - def test_blueprint_same_method_names(name: str): + def test_blueprint_same_method_names(name: str): # NoQA return name bp = Blueprint() @bp.schedule(arg_name="name", schedule="10****") # NoQA - def test_blueprint_same_method_names(name: str): + def test_blueprint_same_method_names(name: str): # NoQA return name app.register_blueprint(bp) @@ -637,6 +637,41 @@ def test_function_builder_decorated_type(self): self.assertTrue(isinstance(fb, FunctionBuilder)) self.assertEqual(fb._function.get_user_function(), self.dummy_func) + @mock.patch('azure.functions.decorators.function_app.AsgiFunctionApp' + '._add_http_app') + def test_add_asgi(self, add_http_app_mock): + mock_asgi_app = object() + AsgiFunctionApp(app=mock_asgi_app, function_name='test_add_asgi') + + add_http_app_mock.assert_called_once() + + self.assertIsInstance(add_http_app_mock.call_args[0][0], + AsgiMiddleware) + + @mock.patch('azure.functions.decorators.function_app.WsgiFunctionApp' + '._add_http_app') + def test_add_wsgi(self, add_http_app_mock): + mock_wsgi_app = object() + WsgiFunctionApp(app=mock_wsgi_app, function_name='test_add_wsgi') + + add_http_app_mock.assert_called_once() + self.assertIsInstance(add_http_app_mock.call_args[0][0], + WsgiMiddleware) + + def test_add_asgi_app(self): + self._test_http_external_app(AsgiFunctionApp( + app=object(), + function_name='test_add_asgi_app'), + True, + function_name='test_add_asgi_app') + + def test_add_wsgi_app(self): + self._test_http_external_app(WsgiFunctionApp( + app=object(), + function_name='test_add_wsgi_app'), + False, + function_name='test_add_wsgi_app') + def test_register_function_app_error(self): with self.assertRaises(TypeError) as err: FunctionApp().register_functions(FunctionApp()) @@ -918,11 +953,11 @@ def test_external_http_function_app(self): app = ExternalHttpFunctionApp(auth_level=AuthLevel.ANONYMOUS) app._add_http_app(AsgiMiddleware(object())) - def _test_http_external_app(self, app, is_async): + def _test_http_external_app(self, app, is_async, function_name): funcs = app.get_functions() self.assertEqual(len(funcs), 1) func = funcs[0] - self.assertEqual(func.get_function_name(), "http_app_func") + self.assertEqual(func.get_function_name(), function_name) raw_bindings = func.get_raw_bindings() raw_trigger = raw_bindings[0] raw_output_binding = raw_bindings[0] @@ -959,36 +994,3 @@ def _test_http_external_app(self, app, is_async): "type": HTTP_OUTPUT } ]}) - -class TestAddAsgi(unittest.TestCase): - @mock.patch('azure.functions.decorators.function_app.AsgiFunctionApp' - '._add_http_app') - def test_add_asgi(self, add_http_app_mock): - mock_asgi_app = object() - AsgiFunctionApp(app=mock_asgi_app) - - add_http_app_mock.assert_called_once() - - self.assertIsInstance(add_http_app_mock.call_args[0][0], - AsgiMiddleware) - -class TestAddWsgi(unittest.TestCase): - @mock.patch('azure.functions.decorators.function_app.WsgiFunctionApp' - '._add_http_app') - def test_add_wsgi(self, add_http_app_mock): - mock_wsgi_app = object() - app = WsgiFunctionApp(app=mock_wsgi_app) - - add_http_app_mock.assert_called_once() - self.assertIsInstance(add_http_app_mock.call_args[0][0], - WsgiMiddleware) - -class TestAddAsgiApp(unittest.TestCase): - def test_add_asgi_app(self): - asgi_app = AsgiFunctionApp(app=object()) - asgi_app.function_name("test") - self._test_http_external_app(asgi_app, True) - -class TestAddWsgiApp(unittest.TestCase): - def test_add_wsgi_app(self): - self._test_http_external_app(WsgiFunctionApp(app=object()), False) \ No newline at end of file From 0abd4b8b23cd8c63ec5b0593f8faaf8fcf31eae9 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 14:16:53 -0500 Subject: [PATCH 09/16] lint --- azure/functions/decorators/function_app.py | 35 +++++++--------------- tests/decorators/test_function_app.py | 9 +++--- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 32ff7a03..26e6be8b 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -290,22 +290,6 @@ def build(self, auth_level: Optional[AuthLevel] = None) -> Function: self._validate_function(auth_level) return self._function - def validate_function_names(self): - """ - Functions should have unique function names. If two functions - have the same function name, the worker should fail - during indexing. - - If the function name decorator is not applied, the function - name defaults to the method name. This means that two functions - can not have the same method name as well without having unique - function names. - - Scenarios that fail / should fail indexing: - - same function name - - no function name, same method name - """ - class DecoratorApi(ABC): """Interface which contains essential decorator function building blocks @@ -3350,12 +3334,12 @@ class ExternalHttpFunctionApp(FunctionRegister, TriggerApi, ABC): def _add_http_app(self, http_middleware: Union[ AsgiMiddleware, WsgiMiddleware], - function_name: Optional[str] = 'http_app_func') -> None: + function_name: str = 'http_app_func') -> None: """Add a Wsgi or Asgi app integrated http function. :param http_middleware: :class:`WsgiMiddleware` or class:`AsgiMiddleware` instance. - :param function_name: an optional namae for the function + :param function_name: name for the function :return: None """ @@ -3365,13 +3349,13 @@ def _add_http_app(self, class AsgiFunctionApp(ExternalHttpFunctionApp): def __init__(self, app, http_auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION, - function_name: Optional[str] = 'http_app_func'): + function_name: str = 'http_app_func'): """Constructor of :class:`AsgiFunctionApp` object. :param app: asgi app object. :param http_auth_level: Determines what keys, if any, need to be - present - on the request in order to invoke the function. + present on the request in order to invoke the function. + :param function_name: function name """ super().__init__(auth_level=http_auth_level) self.middleware = AsgiMiddleware(app) @@ -3385,7 +3369,7 @@ def __del__(self): def _add_http_app(self, http_middleware: Union[ AsgiMiddleware, WsgiMiddleware], - function_name: Optional[str] = 'http_app_func') -> None: + function_name: str = 'http_app_func') -> None: """Add an Asgi app integrated http function. :param http_middleware: :class:`WsgiMiddleware` @@ -3417,10 +3401,11 @@ async def http_app_func(req: HttpRequest, context: Context): class WsgiFunctionApp(ExternalHttpFunctionApp): def __init__(self, app, http_auth_level: Union[AuthLevel, str] = AuthLevel.FUNCTION, - function_name: Optional[str] = 'http_app_func'): + function_name: str = 'http_app_func'): """Constructor of :class:`WsgiFunctionApp` object. :param app: wsgi app object. + :param function_name: function name """ super().__init__(auth_level=http_auth_level) self._add_http_app(WsgiMiddleware(app), function_name) @@ -3428,12 +3413,12 @@ def __init__(self, app, def _add_http_app(self, http_middleware: Union[ AsgiMiddleware, WsgiMiddleware], - function_name: Optional[str] = 'http_app_func') -> None: + function_name: str = 'http_app_func') -> None: """Add a Wsgi app integrated http function. :param http_middleware: :class:`WsgiMiddleware` or class:`AsgiMiddleware` instance. - :param function_name: an optional name for the function + :param function_name: name for the function :return: None """ diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index 695e037d..81d26451 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -484,14 +484,14 @@ def test_blueprint_same_function_names(self): @app.function_name("test_blueprint_same_function_names") # NoQA @app.schedule(arg_name="name", schedule="10****") - def test_blueprint_same_function_names(name: str): + def test_blueprint_same_function_names(name: str): # NoQA return name bp = Blueprint() @bp.function_name("test_blueprint_same_function_names") # NoQA @bp.schedule(arg_name="name", schedule="10****") - def test_blueprint_same_function_names(name: str): + def test_blueprint_same_function_names(name: str): # NoQA return name app.register_blueprint(bp) @@ -697,7 +697,7 @@ def test_register_app_auth_level(self): bp = Blueprint() @bp.route("name") - def test_register_app_auth_level(name: str): + def test_register_app_auth_level_func(name: str): return "hello" app = FunctionApp(http_auth_level=AuthLevel.ANONYMOUS) @@ -922,7 +922,8 @@ def test_wsgi_function_app_custom(self): self.assertEqual(app.auth_level, AuthLevel.ANONYMOUS) def test_wsgi_function_app_is_http_function(self): - app = WsgiFunctionApp(app=object()) + app = WsgiFunctionApp(app=object(), + function_name='test_wsgi_function_app_is_http_function') funcs = app.get_functions() self.assertEqual(len(funcs), 1) From 4add2cdaec430cd4b6148a89dcb63f35e2c4cac2 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 14:25:40 -0500 Subject: [PATCH 10/16] last test --- tests/decorators/test_function_app.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/decorators/test_function_app.py b/tests/decorators/test_function_app.py index 81d26451..9aa219e8 100644 --- a/tests/decorators/test_function_app.py +++ b/tests/decorators/test_function_app.py @@ -697,14 +697,15 @@ def test_register_app_auth_level(self): bp = Blueprint() @bp.route("name") - def test_register_app_auth_level_func(name: str): + def test_register_app_auth_level(name: str): return "hello" app = FunctionApp(http_auth_level=AuthLevel.ANONYMOUS) app.register_blueprint(bp) - self.assertEqual(len(app.get_functions()), 1) - self.assertEqual(app.get_functions()[0].get_trigger().auth_level, + functions = app.get_functions() + self.assertEqual(len(functions), 1) + self.assertEqual(functions[0].get_trigger().auth_level, AuthLevel.ANONYMOUS) def test_default_function_http_type(self): @@ -922,8 +923,9 @@ def test_wsgi_function_app_custom(self): self.assertEqual(app.auth_level, AuthLevel.ANONYMOUS) def test_wsgi_function_app_is_http_function(self): - app = WsgiFunctionApp(app=object(), - function_name='test_wsgi_function_app_is_http_function') + app = WsgiFunctionApp( + app=object(), + function_name='test_wsgi_function_app_is_http_function') funcs = app.get_functions() self.assertEqual(len(funcs), 1) From 143a15065eef350316dc8476d453cefa7aecc288 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 29 May 2024 14:29:21 -0500 Subject: [PATCH 11/16] dapr test fx names --- tests/decorators/test_dapr.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/decorators/test_dapr.py b/tests/decorators/test_dapr.py index 3bfc743e..c87fa398 100644 --- a/tests/decorators/test_dapr.py +++ b/tests/decorators/test_dapr.py @@ -24,7 +24,7 @@ def test_dapr_service_invocation_trigger_default_args(self): @app.dapr_service_invocation_trigger(arg_name="req", method_name="dummy_method_name") - def dummy(): + def test_dapr_service_invocation_trigger_default_args(): pass func = self._get_user_function(app) @@ -50,7 +50,7 @@ def test_dapr_binding_trigger_default_args(self): @app.dapr_binding_trigger(arg_name="req", binding_name="dummy_binding_name") - def dummy1(): + def test_dapr_binding_trigger_default_args(): pass func = self._get_user_function(app) @@ -73,7 +73,7 @@ def test_dapr_topic_trigger_default_args(self): pub_sub_name="dummy_pub_sub_name", topic="dummy_topic", route="/dummy_route") - def dummy2(): + def test_dapr_topic_trigger_default_args(): pass func = self._get_user_function(app) @@ -99,7 +99,7 @@ def test_dapr_state_input_binding(self): @app.dapr_state_input(arg_name="in", state_store="dummy_state_store", key="dummy_key") - def dummy3(): + def test_dapr_state_input_binding(): pass func = self._get_user_function(app) @@ -125,7 +125,7 @@ def test_dapr_secret_input_binding(self): secret_store_name="dummy_secret_store_name", key="dummy_key", metadata="dummy_metadata") - def dummy4(): + def test_dapr_secret_input_binding(): pass func = self._get_user_function(app) @@ -151,7 +151,7 @@ def test_dapr_state_output_binding(self): @app.dapr_state_output(arg_name="out", state_store="dummy_state_store", key="dummy_key") - def dummy5(): + def test_dapr_state_output_binding(): pass func = self._get_user_function(app) @@ -177,7 +177,7 @@ def test_dapr_invoke_output_binding(self): app_id="dummy_app_id", method_name="dummy_method_name", http_verb="dummy_http_verb") - def dummy6(): + def test_dapr_invoke_output_binding(): pass func = self._get_user_function(app) @@ -203,7 +203,7 @@ def test_dapr_publish_output_binding(self): @app.dapr_publish_output(arg_name="out", pub_sub_name="dummy_pub_sub_name", topic="dummy_topic") - def dummy7(): + def test_dapr_publish_output_binding(): pass func = self._get_user_function(app) @@ -228,7 +228,7 @@ def test_dapr_binding_output_binding(self): @app.dapr_binding_output(arg_name="out", binding_name="dummy_binding_name", operation="dummy_operation") - def dummy8(): + def test_dapr_binding_output_binding(): pass func = self._get_user_function(app) From 4d087328d03e9744317e407b198096bcd0beb177 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Wed, 17 Jul 2024 13:48:29 -0500 Subject: [PATCH 12/16] feedback --- azure/functions/decorators/function_app.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 40479328..7ccc4f6d 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,10 +204,12 @@ def __str__(self): class FunctionBuilder(object): - function_bindings: dict = {} + function_bindings: Optional[Dict[Any, Any]] = None def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) + if not self.function_bindings: + self.function_bindings = {} def __call__(self, *args, **kwargs): pass @@ -273,7 +275,9 @@ def _validate_function(self, # This dict contains the function name and its bindings for all # functions in an app. If a previous function has the same name, # indexing will fail here. - if self.function_bindings.get(function_name, None) is not None: + if not self.function_bindings: + self.function_bindings = {} + if not self.function_bindings.get(function_name, None): raise ValueError( f"Function {function_name} does not have a unique" f" function name. Please change @app.function_name() or" From 8206dc43c99581dc6a6b3f8620feac110c929373 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Thu, 18 Jul 2024 10:44:52 -0500 Subject: [PATCH 13/16] missed refs --- azure/functions/decorators/function_app.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 7ccc4f6d..a4e706fc 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,12 +204,10 @@ def __str__(self): class FunctionBuilder(object): - function_bindings: Optional[Dict[Any, Any]] = None + function_bindings = {} def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) - if not self.function_bindings: - self.function_bindings = {} def __call__(self, *args, **kwargs): pass @@ -275,8 +273,6 @@ def _validate_function(self, # This dict contains the function name and its bindings for all # functions in an app. If a previous function has the same name, # indexing will fail here. - if not self.function_bindings: - self.function_bindings = {} if not self.function_bindings.get(function_name, None): raise ValueError( f"Function {function_name} does not have a unique" From 8a3b1dab5c699558f83feb4071ffe6af5366547b Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Thu, 18 Jul 2024 11:17:20 -0500 Subject: [PATCH 14/16] incorrect check --- azure/functions/decorators/function_app.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index a4e706fc..2e7b1165 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,10 +204,12 @@ def __str__(self): class FunctionBuilder(object): - function_bindings = {} + function_bindings: Optional[Dict[Any, Any]] = None def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) + if not self.function_bindings: + self.function_bindings = {} def __call__(self, *args, **kwargs): pass @@ -273,7 +275,9 @@ def _validate_function(self, # This dict contains the function name and its bindings for all # functions in an app. If a previous function has the same name, # indexing will fail here. - if not self.function_bindings.get(function_name, None): + if not self.function_bindings: + self.function_bindings = {} + if self.function_bindings.get(function_name, None): raise ValueError( f"Function {function_name} does not have a unique" f" function name. Please change @app.function_name() or" From 9da220f324ce9e7f94b879748cf6ed693b1ba104 Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Thu, 18 Jul 2024 11:38:41 -0500 Subject: [PATCH 15/16] missed reg --- azure/functions/decorators/function_app.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index 2e7b1165..f90c89fe 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,12 +204,10 @@ def __str__(self): class FunctionBuilder(object): - function_bindings: Optional[Dict[Any, Any]] = None + function_bindings = {} def __init__(self, func, function_script_file): self._function = Function(func, function_script_file) - if not self.function_bindings: - self.function_bindings = {} def __call__(self, *args, **kwargs): pass @@ -275,8 +273,6 @@ def _validate_function(self, # This dict contains the function name and its bindings for all # functions in an app. If a previous function has the same name, # indexing will fail here. - if not self.function_bindings: - self.function_bindings = {} if self.function_bindings.get(function_name, None): raise ValueError( f"Function {function_name} does not have a unique" From 7c64c3ddfe4d24535e4115eee7e1dd9bac8541bf Mon Sep 17 00:00:00 2001 From: Victoria Hall Date: Thu, 18 Jul 2024 12:55:29 -0500 Subject: [PATCH 16/16] type hint --- azure/functions/decorators/function_app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure/functions/decorators/function_app.py b/azure/functions/decorators/function_app.py index f90c89fe..14af303f 100644 --- a/azure/functions/decorators/function_app.py +++ b/azure/functions/decorators/function_app.py @@ -204,7 +204,7 @@ def __str__(self): class FunctionBuilder(object): - function_bindings = {} + function_bindings: dict = {} def __init__(self, func, function_script_file): self._function = Function(func, function_script_file)