From 37d07da9d55b377d59f3d3ad695550e3afe8d691 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Tue, 7 Jun 2022 14:53:18 -0500 Subject: [PATCH 01/11] Enabled dependency isolation by default --- azure_functions_worker/constants.py | 3 +- azure_functions_worker/loader.py | 3 +- azure_functions_worker/utils/dependency.py | 32 +++++-------------- .../function_app.py | 0 4 files changed, 11 insertions(+), 27 deletions(-) create mode 100644 tests/endtoend/dependency_isolation_functions/dependency_isolation_stein/function_app.py diff --git a/azure_functions_worker/constants.py b/azure_functions_worker/constants.py index c78e8c1b8..d623e9d93 100644 --- a/azure_functions_worker/constants.py +++ b/azure_functions_worker/constants.py @@ -43,8 +43,7 @@ PYTHON_THREADPOOL_THREAD_COUNT_MAX = sys.maxsize PYTHON_THREADPOOL_THREAD_COUNT_MAX_37 = 32 -PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT = False -PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 = False +PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT = True PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT = False PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT_39 = True diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py index e5120a2b9..a5db97aba 100644 --- a/azure_functions_worker/loader.py +++ b/azure_functions_worker/loader.py @@ -147,7 +147,8 @@ def index_function_app(function_path: str) -> List[Function]: app: Optional[FunctionApp] = None for i in imported_module.__dir__(): - if isinstance(getattr(imported_module, i, None), FunctionApp): + if type(getattr(imported_module, i, + None)).__name__ == FunctionApp.__name__: if not app: app = getattr(imported_module, i, None) else: diff --git a/azure_functions_worker/utils/dependency.py b/azure_functions_worker/utils/dependency.py index 8fee4c4c5..d99495597 100644 --- a/azure_functions_worker/utils/dependency.py +++ b/azure_functions_worker/utils/dependency.py @@ -1,21 +1,19 @@ -from azure_functions_worker.utils.common import is_true_like -from typing import List, Optional -from types import ModuleType import importlib import inspect import os import re import sys +from types import ModuleType +from typing import List, Optional -from ..logging import logger +from azure_functions_worker.utils.common import is_true_like from ..constants import ( AZURE_WEBJOBS_SCRIPT_ROOT, CONTAINER_NAME, PYTHON_ISOLATE_WORKER_DEPENDENCIES, - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT, - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 + PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT ) -from ..utils.common import is_python_version +from ..logging import logger from ..utils.wrappers import enable_feature_by @@ -75,12 +73,7 @@ def is_in_linux_consumption(cls): @classmethod @enable_feature_by( flag=PYTHON_ISOLATE_WORKER_DEPENDENCIES, - flag_default=( - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 if - is_python_version('3.10') else - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT - ) - ) + flag_default=PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT) def use_worker_dependencies(cls): """Switch the sys.path and ensure the worker imports are loaded from Worker's dependenciess. @@ -106,12 +99,7 @@ def use_worker_dependencies(cls): @classmethod @enable_feature_by( flag=PYTHON_ISOLATE_WORKER_DEPENDENCIES, - flag_default=( - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 if - is_python_version('3.10') else - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT - ) - ) + flag_default=PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT) def prioritize_customer_dependencies(cls, cx_working_dir=None): """Switch the sys.path and ensure the customer's code import are loaded from CX's deppendencies. @@ -180,11 +168,7 @@ def reload_customer_libraries(cls, cx_working_dir: str): """ use_new_env = os.getenv(PYTHON_ISOLATE_WORKER_DEPENDENCIES) if use_new_env is None: - use_new = ( - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 if - is_python_version('3.10') else - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT - ) + use_new = PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT else: use_new = is_true_like(use_new_env) diff --git a/tests/endtoend/dependency_isolation_functions/dependency_isolation_stein/function_app.py b/tests/endtoend/dependency_isolation_functions/dependency_isolation_stein/function_app.py new file mode 100644 index 000000000..e69de29bb From 450fe63c0aa4d0c67ce1d6b5bb0a075abca70b81 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Wed, 8 Jun 2022 14:49:26 -0500 Subject: [PATCH 02/11] Unit test fixes --- tests/unittests/test_rpc_messages.py | 8 +-- tests/unittests/test_utilities_dependency.py | 70 +------------------- 2 files changed, 4 insertions(+), 74 deletions(-) diff --git a/tests/unittests/test_rpc_messages.py b/tests/unittests/test_rpc_messages.py index 4d5057540..3cc246cf7 100644 --- a/tests/unittests/test_rpc_messages.py +++ b/tests/unittests/test_rpc_messages.py @@ -127,13 +127,7 @@ def test_failed_azure_namespace_import(self): @unittest.skipIf(sys.platform == 'win32', 'Linux .sh script only works on Linux') - @unittest.skipIf( - is_python_version('3.10'), - 'In Python 3.10, isolate worker dependencies is turned on by default.' - ' Reloading all customer dependencies on specialization is a must.' - ' This partially reloading namespace feature is no longer needed.' - ) def test_successful_azure_namespace_import(self): self._verify_azure_namespace_import( 'true', - 'module_b is imported') + 'module_b fails to import') diff --git a/tests/unittests/test_utilities_dependency.py b/tests/unittests/test_utilities_dependency.py index 454007806..c8cde1485 100644 --- a/tests/unittests/test_utilities_dependency.py +++ b/tests/unittests/test_utilities_dependency.py @@ -229,7 +229,7 @@ def test_add_to_sys_path_no_duplication(self): def test_add_to_sys_path_import_module(self): DependencyManager._add_to_sys_path(self._customer_deps_path, True) - import common_module # NoQA + import common_module # NoQA self.assertEqual( common_module.package_location, os.path.join(self._customer_deps_path, 'common_module') @@ -240,7 +240,7 @@ def test_add_to_sys_path_import_namespace_path(self): into sys.path """ DependencyManager._add_to_sys_path(self._customer_deps_path, True) - import common_namespace # NoQA + import common_namespace # NoQA self.assertEqual(len(common_namespace.__path__), 1) self.assertEqual( common_namespace.__path__[0], @@ -517,7 +517,7 @@ def test_clear_path_importer_cache_and_modules_retain_namespace(self): sys.path.insert(0, self._worker_deps_path) # Ensure new import is from _worker_deps_path - import common_module as worker_mod # NoQA + import common_module as worker_mod # NoQA self.assertIn('common_module', sys.modules) self.assertEqual( worker_mod.package_location, @@ -555,39 +555,6 @@ def test_use_worker_dependencies_disable(self): with self.assertRaises(ImportError): import common_module # NoQA - @unittest.skipUnless( - sys.version_info.major == 3 and sys.version_info.minor != 10, - 'Test only available for Python 3.6, 3.7, 3.8 or 3.9' - ) - def test_use_worker_dependencies_default_python_36_37_38_39(self): - # Feature should be disabled in Python 3.6, 3.7, 3.8 and 3.9 - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # The common_module cannot be imported since feature is disabled - DependencyManager.use_worker_dependencies() - with self.assertRaises(ImportError): - import common_module # NoQA - - @unittest.skip('Skipping since PYTHON_ISOLATE_WORKER_DEPENDENCIES is ' - 'disabled by default') - def test_use_worker_dependencies_default_python_310(self): - # Feature should be enabled in Python 3.10 by default - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # Ensure the common_module is imported from _worker_deps_path - DependencyManager.use_worker_dependencies() - import common_module # NoQA - self.assertEqual( - common_module.package_location, - os.path.join(self._worker_deps_path, 'common_module') - ) - def test_prioritize_customer_dependencies(self): # Setup app settings os.environ['PYTHON_ISOLATE_WORKER_DEPENDENCIES'] = 'true' @@ -626,37 +593,6 @@ def test_prioritize_customer_dependencies_disable(self): with self.assertRaises(ImportError): import common_module # NoQA - @unittest.skipIf(is_python_version('3.10'), - 'Test not available for python 3.10') - def test_prioritize_customer_dependencies_default_python_36_37_38_39(self): - # Feature should be disabled in Python 3.6, 3.7, 3.8 and 3.9 - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # Ensure the common_module is imported from _customer_deps_path - DependencyManager.prioritize_customer_dependencies() - with self.assertRaises(ImportError): - import common_module # NoQA - - @unittest.skip('Skipping since PYTHON_ISOLATE_WORKER_DEPENDENCIES is ' - 'disabled by default') - def test_prioritize_customer_dependencies_default_python_310(self): - # Feature should be enabled in Python 3.10 by default - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # Ensure the common_module is imported from _customer_deps_path - DependencyManager.prioritize_customer_dependencies() - import common_module # NoQA - self.assertEqual( - common_module.package_location, - os.path.join(self._customer_deps_path, 'common_module') - ) - def test_prioritize_customer_dependencies_from_working_directory(self): self._initialize_scenario() From d9f9ef6c1de66bc1aa9d76931c7316d48694de7c Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Wed, 8 Jun 2022 18:03:05 -0500 Subject: [PATCH 03/11] Fixed flake8 tests --- tests/unittests/test_rpc_messages.py | 1 - tests/unittests/test_utilities_dependency.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unittests/test_rpc_messages.py b/tests/unittests/test_rpc_messages.py index 3cc246cf7..54cd188ce 100644 --- a/tests/unittests/test_rpc_messages.py +++ b/tests/unittests/test_rpc_messages.py @@ -8,7 +8,6 @@ import unittest from azure_functions_worker import protos, testutils -from azure_functions_worker.utils.common import is_python_version class TestGRPC(testutils.AsyncTestCase): diff --git a/tests/unittests/test_utilities_dependency.py b/tests/unittests/test_utilities_dependency.py index c8cde1485..ad456595e 100644 --- a/tests/unittests/test_utilities_dependency.py +++ b/tests/unittests/test_utilities_dependency.py @@ -1,13 +1,12 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +import importlib.util import os import sys -import importlib.util import unittest from unittest.mock import patch from azure_functions_worker import testutils -from azure_functions_worker.utils.common import is_python_version from azure_functions_worker.utils.dependency import DependencyManager From c8a50fbe92f7969d4dc8251896e546d0a9261e8f Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Tue, 7 Jun 2022 14:53:18 -0500 Subject: [PATCH 04/11] Enabled dependency isolation by default --- azure_functions_worker/constants.py | 3 +- azure_functions_worker/loader.py | 3 +- azure_functions_worker/utils/dependency.py | 32 +++++-------------- .../function_app.py | 0 4 files changed, 11 insertions(+), 27 deletions(-) create mode 100644 tests/endtoend/dependency_isolation_functions/dependency_isolation_stein/function_app.py diff --git a/azure_functions_worker/constants.py b/azure_functions_worker/constants.py index c78e8c1b8..d623e9d93 100644 --- a/azure_functions_worker/constants.py +++ b/azure_functions_worker/constants.py @@ -43,8 +43,7 @@ PYTHON_THREADPOOL_THREAD_COUNT_MAX = sys.maxsize PYTHON_THREADPOOL_THREAD_COUNT_MAX_37 = 32 -PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT = False -PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 = False +PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT = True PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT = False PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT_39 = True diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py index e5120a2b9..a5db97aba 100644 --- a/azure_functions_worker/loader.py +++ b/azure_functions_worker/loader.py @@ -147,7 +147,8 @@ def index_function_app(function_path: str) -> List[Function]: app: Optional[FunctionApp] = None for i in imported_module.__dir__(): - if isinstance(getattr(imported_module, i, None), FunctionApp): + if type(getattr(imported_module, i, + None)).__name__ == FunctionApp.__name__: if not app: app = getattr(imported_module, i, None) else: diff --git a/azure_functions_worker/utils/dependency.py b/azure_functions_worker/utils/dependency.py index 8fee4c4c5..d99495597 100644 --- a/azure_functions_worker/utils/dependency.py +++ b/azure_functions_worker/utils/dependency.py @@ -1,21 +1,19 @@ -from azure_functions_worker.utils.common import is_true_like -from typing import List, Optional -from types import ModuleType import importlib import inspect import os import re import sys +from types import ModuleType +from typing import List, Optional -from ..logging import logger +from azure_functions_worker.utils.common import is_true_like from ..constants import ( AZURE_WEBJOBS_SCRIPT_ROOT, CONTAINER_NAME, PYTHON_ISOLATE_WORKER_DEPENDENCIES, - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT, - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 + PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT ) -from ..utils.common import is_python_version +from ..logging import logger from ..utils.wrappers import enable_feature_by @@ -75,12 +73,7 @@ def is_in_linux_consumption(cls): @classmethod @enable_feature_by( flag=PYTHON_ISOLATE_WORKER_DEPENDENCIES, - flag_default=( - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 if - is_python_version('3.10') else - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT - ) - ) + flag_default=PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT) def use_worker_dependencies(cls): """Switch the sys.path and ensure the worker imports are loaded from Worker's dependenciess. @@ -106,12 +99,7 @@ def use_worker_dependencies(cls): @classmethod @enable_feature_by( flag=PYTHON_ISOLATE_WORKER_DEPENDENCIES, - flag_default=( - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 if - is_python_version('3.10') else - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT - ) - ) + flag_default=PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT) def prioritize_customer_dependencies(cls, cx_working_dir=None): """Switch the sys.path and ensure the customer's code import are loaded from CX's deppendencies. @@ -180,11 +168,7 @@ def reload_customer_libraries(cls, cx_working_dir: str): """ use_new_env = os.getenv(PYTHON_ISOLATE_WORKER_DEPENDENCIES) if use_new_env is None: - use_new = ( - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_310 if - is_python_version('3.10') else - PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT - ) + use_new = PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT else: use_new = is_true_like(use_new_env) diff --git a/tests/endtoend/dependency_isolation_functions/dependency_isolation_stein/function_app.py b/tests/endtoend/dependency_isolation_functions/dependency_isolation_stein/function_app.py new file mode 100644 index 000000000..e69de29bb From c5620d26ef722cd0f6136fca6e0d6ebbcb7c36a0 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Wed, 8 Jun 2022 14:49:26 -0500 Subject: [PATCH 05/11] Unit test fixes --- tests/unittests/test_rpc_messages.py | 8 +-- tests/unittests/test_utilities_dependency.py | 70 +------------------- 2 files changed, 4 insertions(+), 74 deletions(-) diff --git a/tests/unittests/test_rpc_messages.py b/tests/unittests/test_rpc_messages.py index 4d5057540..3cc246cf7 100644 --- a/tests/unittests/test_rpc_messages.py +++ b/tests/unittests/test_rpc_messages.py @@ -127,13 +127,7 @@ def test_failed_azure_namespace_import(self): @unittest.skipIf(sys.platform == 'win32', 'Linux .sh script only works on Linux') - @unittest.skipIf( - is_python_version('3.10'), - 'In Python 3.10, isolate worker dependencies is turned on by default.' - ' Reloading all customer dependencies on specialization is a must.' - ' This partially reloading namespace feature is no longer needed.' - ) def test_successful_azure_namespace_import(self): self._verify_azure_namespace_import( 'true', - 'module_b is imported') + 'module_b fails to import') diff --git a/tests/unittests/test_utilities_dependency.py b/tests/unittests/test_utilities_dependency.py index 454007806..c8cde1485 100644 --- a/tests/unittests/test_utilities_dependency.py +++ b/tests/unittests/test_utilities_dependency.py @@ -229,7 +229,7 @@ def test_add_to_sys_path_no_duplication(self): def test_add_to_sys_path_import_module(self): DependencyManager._add_to_sys_path(self._customer_deps_path, True) - import common_module # NoQA + import common_module # NoQA self.assertEqual( common_module.package_location, os.path.join(self._customer_deps_path, 'common_module') @@ -240,7 +240,7 @@ def test_add_to_sys_path_import_namespace_path(self): into sys.path """ DependencyManager._add_to_sys_path(self._customer_deps_path, True) - import common_namespace # NoQA + import common_namespace # NoQA self.assertEqual(len(common_namespace.__path__), 1) self.assertEqual( common_namespace.__path__[0], @@ -517,7 +517,7 @@ def test_clear_path_importer_cache_and_modules_retain_namespace(self): sys.path.insert(0, self._worker_deps_path) # Ensure new import is from _worker_deps_path - import common_module as worker_mod # NoQA + import common_module as worker_mod # NoQA self.assertIn('common_module', sys.modules) self.assertEqual( worker_mod.package_location, @@ -555,39 +555,6 @@ def test_use_worker_dependencies_disable(self): with self.assertRaises(ImportError): import common_module # NoQA - @unittest.skipUnless( - sys.version_info.major == 3 and sys.version_info.minor != 10, - 'Test only available for Python 3.6, 3.7, 3.8 or 3.9' - ) - def test_use_worker_dependencies_default_python_36_37_38_39(self): - # Feature should be disabled in Python 3.6, 3.7, 3.8 and 3.9 - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # The common_module cannot be imported since feature is disabled - DependencyManager.use_worker_dependencies() - with self.assertRaises(ImportError): - import common_module # NoQA - - @unittest.skip('Skipping since PYTHON_ISOLATE_WORKER_DEPENDENCIES is ' - 'disabled by default') - def test_use_worker_dependencies_default_python_310(self): - # Feature should be enabled in Python 3.10 by default - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # Ensure the common_module is imported from _worker_deps_path - DependencyManager.use_worker_dependencies() - import common_module # NoQA - self.assertEqual( - common_module.package_location, - os.path.join(self._worker_deps_path, 'common_module') - ) - def test_prioritize_customer_dependencies(self): # Setup app settings os.environ['PYTHON_ISOLATE_WORKER_DEPENDENCIES'] = 'true' @@ -626,37 +593,6 @@ def test_prioritize_customer_dependencies_disable(self): with self.assertRaises(ImportError): import common_module # NoQA - @unittest.skipIf(is_python_version('3.10'), - 'Test not available for python 3.10') - def test_prioritize_customer_dependencies_default_python_36_37_38_39(self): - # Feature should be disabled in Python 3.6, 3.7, 3.8 and 3.9 - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # Ensure the common_module is imported from _customer_deps_path - DependencyManager.prioritize_customer_dependencies() - with self.assertRaises(ImportError): - import common_module # NoQA - - @unittest.skip('Skipping since PYTHON_ISOLATE_WORKER_DEPENDENCIES is ' - 'disabled by default') - def test_prioritize_customer_dependencies_default_python_310(self): - # Feature should be enabled in Python 3.10 by default - # Setup paths - DependencyManager.worker_deps_path = self._worker_deps_path - DependencyManager.cx_deps_path = self._customer_deps_path - DependencyManager.cx_working_dir = self._customer_func_path - - # Ensure the common_module is imported from _customer_deps_path - DependencyManager.prioritize_customer_dependencies() - import common_module # NoQA - self.assertEqual( - common_module.package_location, - os.path.join(self._customer_deps_path, 'common_module') - ) - def test_prioritize_customer_dependencies_from_working_directory(self): self._initialize_scenario() From 1da42b3b342a4b403feb092d3dfde11d5e2c28eb Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Wed, 8 Jun 2022 18:03:05 -0500 Subject: [PATCH 06/11] Fixed flake8 tests --- tests/unittests/test_rpc_messages.py | 1 - tests/unittests/test_utilities_dependency.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unittests/test_rpc_messages.py b/tests/unittests/test_rpc_messages.py index 3cc246cf7..54cd188ce 100644 --- a/tests/unittests/test_rpc_messages.py +++ b/tests/unittests/test_rpc_messages.py @@ -8,7 +8,6 @@ import unittest from azure_functions_worker import protos, testutils -from azure_functions_worker.utils.common import is_python_version class TestGRPC(testutils.AsyncTestCase): diff --git a/tests/unittests/test_utilities_dependency.py b/tests/unittests/test_utilities_dependency.py index c8cde1485..ad456595e 100644 --- a/tests/unittests/test_utilities_dependency.py +++ b/tests/unittests/test_utilities_dependency.py @@ -1,13 +1,12 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +import importlib.util import os import sys -import importlib.util import unittest from unittest.mock import patch from azure_functions_worker import testutils -from azure_functions_worker.utils.common import is_python_version from azure_functions_worker.utils.dependency import DependencyManager From 1af2e2dd54de31d3ac3d3beb6d9efd75e52e8925 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Wed, 15 Jun 2022 13:50:55 -0500 Subject: [PATCH 07/11] Reverted loader.py change --- azure_functions_worker/loader.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py index cdaf0f0f5..36787e651 100644 --- a/azure_functions_worker/loader.py +++ b/azure_functions_worker/loader.py @@ -146,8 +146,7 @@ def index_function_app(function_path: str): from azure.functions import FunctionApp app: Optional[FunctionApp] = None for i in imported_module.__dir__(): - if type(getattr(imported_module, i, - None)).__name__ == FunctionApp.__name__: + if isinstance(getattr(imported_module, i, None), FunctionApp): if not app: app = getattr(imported_module, i, None) else: From 5244055b0623fa330c550e8e2cda32f1e177a639 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Thu, 16 Jun 2022 10:40:36 -0500 Subject: [PATCH 08/11] Added unit tests --- tests/unittests/test_utilities_dependency.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/unittests/test_utilities_dependency.py b/tests/unittests/test_utilities_dependency.py index ad456595e..05e83f025 100644 --- a/tests/unittests/test_utilities_dependency.py +++ b/tests/unittests/test_utilities_dependency.py @@ -608,6 +608,19 @@ def test_prioritize_customer_dependencies_from_working_directory(self): os.path.join(self._customer_func_path, 'func_specific_module') ) + def test_reload_customer_libraries(self): + os.environ['PYTHON_ISOLATE_WORKER_DEPENDENCIES'] = 'true' + # Setup paths + DependencyManager.worker_deps_path = self._worker_deps_path + DependencyManager.cx_deps_path = self._customer_deps_path + DependencyManager.cx_working_dir = self._customer_func_path + + DependencyManager.reload_customer_libraries(self._customer_deps_path) + import common_module # NoQA + self.assertEqual( + common_module.package_location, + os.path.join(self._customer_deps_path, 'common_module')) + def test_remove_module_cache(self): # First import the common_module and create a sys.modules cache sys.path.append(self._customer_deps_path) From 4bd58a561f125e5323d40587bbd3305b20a0bb70 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Fri, 17 Jun 2022 12:31:06 -0500 Subject: [PATCH 09/11] Added unit tests --- tests/unittests/test_utilities_dependency.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/unittests/test_utilities_dependency.py b/tests/unittests/test_utilities_dependency.py index 05e83f025..51cace317 100644 --- a/tests/unittests/test_utilities_dependency.py +++ b/tests/unittests/test_utilities_dependency.py @@ -608,7 +608,7 @@ def test_prioritize_customer_dependencies_from_working_directory(self): os.path.join(self._customer_func_path, 'func_specific_module') ) - def test_reload_customer_libraries(self): + def test_reload_customer_libraries_dependency_isolation_true(self): os.environ['PYTHON_ISOLATE_WORKER_DEPENDENCIES'] = 'true' # Setup paths DependencyManager.worker_deps_path = self._worker_deps_path @@ -621,6 +621,23 @@ def test_reload_customer_libraries(self): common_module.package_location, os.path.join(self._customer_deps_path, 'common_module')) + def test_reload_customer_libraries_dependency_isolation_false(self): + os.environ['PYTHON_ISOLATE_WORKER_DEPENDENCIES'] = 'false' + # Setup paths + DependencyManager.worker_deps_path = self._worker_deps_path + DependencyManager.cx_deps_path = self._customer_deps_path + DependencyManager.cx_working_dir = self._customer_func_path + + DependencyManager._add_to_sys_path(self._worker_deps_path, True) + import azure.functions # NoQA + + DependencyManager._add_to_sys_path(self._customer_deps_path, True) + DependencyManager.reload_customer_libraries(self._customer_deps_path) + # Checking if azure.functions gets reloaded + self.assertIn( + os.path.join(self._customer_deps_path, 'azure', 'functions'), + sys.modules['azure.functions'].__path__) + def test_remove_module_cache(self): # First import the common_module and create a sys.modules cache sys.path.append(self._customer_deps_path) From a07642263e1c2fa0516f6dd9602a92421082d428 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Mon, 20 Jun 2022 10:52:02 -0500 Subject: [PATCH 10/11] Reverted loader.py change --- azure_functions_worker/loader.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py index cdaf0f0f5..36787e651 100644 --- a/azure_functions_worker/loader.py +++ b/azure_functions_worker/loader.py @@ -146,8 +146,7 @@ def index_function_app(function_path: str): from azure.functions import FunctionApp app: Optional[FunctionApp] = None for i in imported_module.__dir__(): - if type(getattr(imported_module, i, - None)).__name__ == FunctionApp.__name__: + if isinstance(getattr(imported_module, i, None), FunctionApp): if not app: app = getattr(imported_module, i, None) else: From bab4d2d65b734a0f244ca6986a4b39b18a1d5387 Mon Sep 17 00:00:00 2001 From: Gavin Aguiar Date: Tue, 21 Jun 2022 18:48:11 -0500 Subject: [PATCH 11/11] Added copyright comment --- azure_functions_worker/utils/dependency.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure_functions_worker/utils/dependency.py b/azure_functions_worker/utils/dependency.py index d99495597..eb3ab028c 100644 --- a/azure_functions_worker/utils/dependency.py +++ b/azure_functions_worker/utils/dependency.py @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. import importlib import inspect import os