diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py
index 36787e65..a5ec98f3 100644
--- a/azure_functions_worker/loader.py
+++ b/azure_functions_worker/loader.py
@@ -143,18 +143,19 @@ def index_function_app(function_path: str):
module_name = pathlib.Path(function_path).stem
imported_module = importlib.import_module(module_name)
- from azure.functions import FunctionApp
- app: Optional[FunctionApp] = None
+ from azure.functions import FunctionRegister
+ app: Optional[FunctionRegister] = None
for i in imported_module.__dir__():
- if isinstance(getattr(imported_module, i, None), FunctionApp):
+ if isinstance(getattr(imported_module, i, None), FunctionRegister):
if not app:
app = getattr(imported_module, i, None)
else:
raise ValueError(
- "Multiple instances of FunctionApp are defined")
+ f"More than one {app.__class__.__name__} or other top "
+ f"level function app instances are defined.")
if not app:
- raise ValueError("Could not find instance of FunctionApp in "
+ raise ValueError("Could not find top level function app instances in "
f"{SCRIPT_FILE_NAME}.")
return app.get_functions()
diff --git a/setup.py b/setup.py
index ab16cd39..0ffe06ec 100644
--- a/setup.py
+++ b/setup.py
@@ -105,7 +105,7 @@ INSTALL_REQUIRES = [
"grpcio~=1.43.0",
"grpcio-tools~=1.43.0",
"protobuf~=3.19.3",
- 'azure-functions==1.11.3b2',
+ "azure-functions==1.11.3b2",
"python-dateutil~=2.8.2"
]
diff --git a/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py
new file mode 100644
index 00000000..78504939
--- /dev/null
+++ b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py
@@ -0,0 +1,31 @@
+import logging
+
+import azure.functions as func
+
+bp = func.Blueprint()
+
+
+@bp.route(route="default_template")
+def default_template(req: func.HttpRequest) -> func.HttpResponse:
+ logging.info('Python HTTP trigger function processed a request.')
+
+ name = req.params.get('name')
+ if not name:
+ try:
+ req_body = req.get_json()
+ except ValueError:
+ pass
+ else:
+ name = req_body.get('name')
+
+ if name:
+ return func.HttpResponse(
+ f"Hello, {name}. This HTTP triggered function "
+ f"executed successfully.")
+ else:
+ return func.HttpResponse(
+ "This HTTP triggered function executed successfully. "
+ "Pass a name in the query string or in the request body for a"
+ " personalized response.",
+ status_code=200
+ )
diff --git a/tests/endtoend/blueprint_functions/functions_in_blueprint_only/function_app.py b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/function_app.py
new file mode 100644
index 00000000..fb045265
--- /dev/null
+++ b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/function_app.py
@@ -0,0 +1,6 @@
+import azure.functions as func
+from blueprint import bp
+
+app = func.FunctionApp()
+
+app.register_functions(bp)
diff --git a/tests/endtoend/blueprint_functions/functions_in_both_blueprint_functionapp/blueprint.py b/tests/endtoend/blueprint_functions/functions_in_both_blueprint_functionapp/blueprint.py
new file mode 100644
index 00000000..78504939
--- /dev/null
+++ b/tests/endtoend/blueprint_functions/functions_in_both_blueprint_functionapp/blueprint.py
@@ -0,0 +1,31 @@
+import logging
+
+import azure.functions as func
+
+bp = func.Blueprint()
+
+
+@bp.route(route="default_template")
+def default_template(req: func.HttpRequest) -> func.HttpResponse:
+ logging.info('Python HTTP trigger function processed a request.')
+
+ name = req.params.get('name')
+ if not name:
+ try:
+ req_body = req.get_json()
+ except ValueError:
+ pass
+ else:
+ name = req_body.get('name')
+
+ if name:
+ return func.HttpResponse(
+ f"Hello, {name}. This HTTP triggered function "
+ f"executed successfully.")
+ else:
+ return func.HttpResponse(
+ "This HTTP triggered function executed successfully. "
+ "Pass a name in the query string or in the request body for a"
+ " personalized response.",
+ status_code=200
+ )
diff --git a/tests/endtoend/blueprint_functions/functions_in_both_blueprint_functionapp/function_app.py b/tests/endtoend/blueprint_functions/functions_in_both_blueprint_functionapp/function_app.py
new file mode 100644
index 00000000..4347b0c7
--- /dev/null
+++ b/tests/endtoend/blueprint_functions/functions_in_both_blueprint_functionapp/function_app.py
@@ -0,0 +1,13 @@
+import azure.functions as func
+
+from blueprint import bp
+
+app = func.FunctionApp()
+
+app.register_blueprint(bp)
+
+
+@app.route(route="return_http")
+def return_http(req: func.HttpRequest):
+ return func.HttpResponse('
Hello World™
',
+ mimetype='text/html')
diff --git a/tests/endtoend/blueprint_functions/multiple_function_registers/function_app.py b/tests/endtoend/blueprint_functions/multiple_function_registers/function_app.py
new file mode 100644
index 00000000..4277df8d
--- /dev/null
+++ b/tests/endtoend/blueprint_functions/multiple_function_registers/function_app.py
@@ -0,0 +1,12 @@
+import azure.functions as func
+
+app = func.FunctionApp()
+
+
+@app.route(route="return_http")
+def return_http(req: func.HttpRequest):
+ return func.HttpResponse('Hello World™
',
+ mimetype='text/html')
+
+
+asgi_app = func.AsgiFunctionApp()
diff --git a/tests/endtoend/blueprint_functions/only_blueprint/function_app.py b/tests/endtoend/blueprint_functions/only_blueprint/function_app.py
new file mode 100644
index 00000000..78504939
--- /dev/null
+++ b/tests/endtoend/blueprint_functions/only_blueprint/function_app.py
@@ -0,0 +1,31 @@
+import logging
+
+import azure.functions as func
+
+bp = func.Blueprint()
+
+
+@bp.route(route="default_template")
+def default_template(req: func.HttpRequest) -> func.HttpResponse:
+ logging.info('Python HTTP trigger function processed a request.')
+
+ name = req.params.get('name')
+ if not name:
+ try:
+ req_body = req.get_json()
+ except ValueError:
+ pass
+ else:
+ name = req_body.get('name')
+
+ if name:
+ return func.HttpResponse(
+ f"Hello, {name}. This HTTP triggered function "
+ f"executed successfully.")
+ else:
+ return func.HttpResponse(
+ "This HTTP triggered function executed successfully. "
+ "Pass a name in the query string or in the request body for a"
+ " personalized response.",
+ status_code=200
+ )
diff --git a/tests/endtoend/test_blueprint_functions.py b/tests/endtoend/test_blueprint_functions.py
new file mode 100644
index 00000000..bb73fd91
--- /dev/null
+++ b/tests/endtoend/test_blueprint_functions.py
@@ -0,0 +1,59 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+from azure_functions_worker import testutils
+
+
+class TestFunctionInBluePrintOnly(testutils.WebHostTestCase):
+ @classmethod
+ def get_script_dir(cls):
+ return testutils.E2E_TESTS_FOLDER / 'blueprint_functions' / \
+ 'functions_in_blueprint_only'
+
+ @testutils.retryable_test(3, 5)
+ def test_function_in_blueprint_only(self):
+ r = self.webhost.request('GET', 'default_template')
+ self.assertTrue(r.ok)
+
+
+class TestFunctionsInBothBlueprintAndFuncApp(testutils.WebHostTestCase):
+ @classmethod
+ def get_script_dir(cls):
+ return testutils.E2E_TESTS_FOLDER / 'blueprint_functions' / \
+ 'functions_in_both_blueprint_functionapp'
+
+ @testutils.retryable_test(3, 5)
+ def test_functions_in_both_blueprint_functionapp(self):
+ r = self.webhost.request('GET', 'default_template')
+ self.assertTrue(r.ok)
+
+ r = self.webhost.request('GET', 'return_http')
+ self.assertTrue(r.ok)
+
+
+class TestMultipleFunctionRegisters(testutils.WebHostTestCase):
+ @classmethod
+ def get_script_dir(cls):
+ return testutils.E2E_TESTS_FOLDER / 'blueprint_functions' / \
+ 'multiple_function_registers'
+
+ @testutils.retryable_test(3, 5)
+ def test_function_in_blueprint_only(self):
+ r = self.webhost.request('GET', 'return_http')
+ self.assertEqual(r.status_code, 404)
+
+
+class TestOnlyBlueprint(testutils.WebHostTestCase):
+ @classmethod
+ def get_script_dir(cls):
+ return testutils.E2E_TESTS_FOLDER / 'blueprint_functions' / \
+ 'only_blueprint'
+
+ @testutils.retryable_test(3, 5)
+ def test_only_blueprint(self):
+ """Test if the default template of Http trigger in Python
+ Function app
+ will return OK
+ """
+ r = self.webhost.request('GET', 'default_template')
+ self.assertEqual(r.status_code, 404)
diff --git a/tests/endtoend/third_party_http_functions/stein/asgi_function/function_app.py b/tests/endtoend/third_party_http_functions/stein/asgi_function/function_app.py
index 0654b349..c5570be6 100644
--- a/tests/endtoend/third_party_http_functions/stein/asgi_function/function_app.py
+++ b/tests/endtoend/third_party_http_functions/stein/asgi_function/function_app.py
@@ -37,5 +37,5 @@ async def raise_http_exception():
raise HTTPException(status_code=404, detail="Item not found")
-app = func.FunctionApp(asgi_app=fast_app,
- http_auth_level=func.AuthLevel.ANONYMOUS)
+app = func.AsgiFunctionApp(app=fast_app,
+ http_auth_level=func.AuthLevel.ANONYMOUS)
diff --git a/tests/endtoend/third_party_http_functions/stein/wsgi_function/function_app.py b/tests/endtoend/third_party_http_functions/stein/wsgi_function/function_app.py
index 267fb85e..264a67a0 100644
--- a/tests/endtoend/third_party_http_functions/stein/wsgi_function/function_app.py
+++ b/tests/endtoend/third_party_http_functions/stein/wsgi_function/function_app.py
@@ -32,5 +32,5 @@ def raise_http_exception():
return {"detail": "Item not found"}, 404
-app = func.FunctionApp(wsgi_app=flask_app.wsgi_app,
- http_auth_level=func.AuthLevel.ANONYMOUS)
+app = func.WsgiFunctionApp(app=flask_app.wsgi_app,
+ http_auth_level=func.AuthLevel.ANONYMOUS)
diff --git a/tests/unittests/third_party_http_functions/stein/asgi_function/function_app.py b/tests/unittests/third_party_http_functions/stein/asgi_function/function_app.py
index 7ac32678..3248f25f 100644
--- a/tests/unittests/third_party_http_functions/stein/asgi_function/function_app.py
+++ b/tests/unittests/third_party_http_functions/stein/asgi_function/function_app.py
@@ -172,5 +172,5 @@ async def unhandled_unserializable_error():
raise UnserializableException('foo')
-app = func.FunctionApp(asgi_app=fast_app,
- http_auth_level=func.AuthLevel.ANONYMOUS)
+app = func.AsgiFunctionApp(app=fast_app,
+ http_auth_level=func.AuthLevel.ANONYMOUS)
diff --git a/tests/unittests/third_party_http_functions/stein/wsgi_function/function_app.py b/tests/unittests/third_party_http_functions/stein/wsgi_function/function_app.py
index dbd2c311..d08b3dc6 100644
--- a/tests/unittests/third_party_http_functions/stein/wsgi_function/function_app.py
+++ b/tests/unittests/third_party_http_functions/stein/wsgi_function/function_app.py
@@ -99,5 +99,5 @@ def unhandled_unserializable_error():
raise UnserializableException('foo')
-app = func.FunctionApp(wsgi_app=flask_app.wsgi_app,
- http_auth_level=func.AuthLevel.ANONYMOUS)
+app = func.WsgiFunctionApp(app=flask_app.wsgi_app,
+ http_auth_level=func.AuthLevel.ANONYMOUS)