From 6a97e65c4996789366f655504d99a2d75b542bd3 Mon Sep 17 00:00:00 2001 From: Maksym Kovalchuk Date: Thu, 10 Apr 2025 17:20:01 +0300 Subject: [PATCH 1/2] [show][config][plugin] add processing of ModuleNotFoundError with warning log message instead of default error message Avoid excess error messages for cases of race conditions when plugin was removed right before the stage of its loading Signed-off-by: Maksym Kovalchuk --- utilities_common/util_base.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utilities_common/util_base.py b/utilities_common/util_base.py index 98fc230629..c6053392ca 100644 --- a/utilities_common/util_base.py +++ b/utilities_common/util_base.py @@ -29,6 +29,12 @@ def iter_namespace(ns_pkg): log.log_debug('importing plugin: {}'.format(module_name)) try: module = importlib.import_module(module_name) + + except ModuleNotFoundError as err: + log.log_warning('failed to import plugin {}: {}'.format(module_name, err), + also_print_to_console=True) + continue + except Exception as err: log.log_error('failed to import plugin {}: {}'.format(module_name, err), also_print_to_console=True) From 1793c048ceb81fd09d9d8207d693a11557291125 Mon Sep 17 00:00:00 2001 From: Maksym Kovalchuk Date: Thu, 10 Apr 2025 17:22:57 +0300 Subject: [PATCH 2/2] Add test coverage for new type of exception Signed-off-by: Maksym Kovalchuk --- tests/test_util_base.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/test_util_base.py diff --git a/tests/test_util_base.py b/tests/test_util_base.py new file mode 100644 index 0000000000..4ccdadeee0 --- /dev/null +++ b/tests/test_util_base.py @@ -0,0 +1,31 @@ +from unittest.mock import patch, MagicMock +from utilities_common.util_base import UtilHelper + + +@patch("pkgutil.iter_modules") +@patch("utilities_common.util_base.log.log_error") +@patch("utilities_common.util_base.log.log_warning") +def test_load_plugins_exceptions_logs(mock_log_warning, mock_log_error, mock_iter_modules): + NON_EXISTENT_MODULE_NAME = "non-existent-module" + FAILED_TO_IMPORT_MESSAGE = f"failed to import plugin {NON_EXISTENT_MODULE_NAME}" + COMMON_EXCEPTION_MESSAGE = "Common exception" + + mock_iter_modules.return_value = [(None, NON_EXISTENT_MODULE_NAME, False)] + plugins_namespace = MagicMock() + plugins_namespace.__path__ = "some_path" + plugins_namespace.__name__ = "some_name" + + # Assetion for ModuleNotFoundError + list(UtilHelper().load_plugins(plugins_namespace)) + mock_log_warning.assert_called_once_with( + f"{FAILED_TO_IMPORT_MESSAGE}: No module named '{NON_EXISTENT_MODULE_NAME}'", + also_print_to_console=True + ) + + # Assertion for Exception + with patch("importlib.import_module", side_effect=Exception(COMMON_EXCEPTION_MESSAGE)): + list(UtilHelper().load_plugins(plugins_namespace)) + mock_log_error.assert_called_once_with( + f"{FAILED_TO_IMPORT_MESSAGE}: {COMMON_EXCEPTION_MESSAGE}", + also_print_to_console=True + )