diff --git a/.vscode/settings.json b/.vscode/settings.json index 4efc47061..bb92a125e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,5 +21,4 @@ "python.testing.cwd": "${workspaceFolder}/code", "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, - "pylint.path" : [ "${interpreter}", "-m", "pylint" ] } diff --git a/code/backend/batch/utilities/helpers/config/config_helper.py b/code/backend/batch/utilities/helpers/config/config_helper.py index 5bc1e0563..9d03bc1fd 100644 --- a/code/backend/batch/utilities/helpers/config/config_helper.py +++ b/code/backend/batch/utilities/helpers/config/config_helper.py @@ -1,6 +1,7 @@ import os import json import logging +import functools from string import Template from ..azure_blob_storage_client import AzureBlobStorageClient @@ -164,6 +165,7 @@ def _set_new_config_properties(config: dict, default_config: dict): ] @staticmethod + @functools.cache def get_active_config_or_default(): env_helper = EnvHelper() config = ConfigHelper.get_default_config() @@ -191,6 +193,7 @@ def save_config_as_active(config): CONFIG_FILE_NAME, content_type="application/json", ) + ConfigHelper.get_active_config_or_default.cache_clear() @staticmethod def validate_config(config: dict): @@ -214,8 +217,8 @@ def get_default_config(): config_file_path = os.path.join(os.path.dirname(__file__), "default.json") - with open(config_file_path) as f: - logger.info(f"Loading default config from {config_file_path}") + with open(config_file_path, encoding="utf-8") as f: + logger.info("Loading default config from %s", config_file_path) ConfigHelper._default_config = json.loads( Template(f.read()).substitute( ORCHESTRATION_STRATEGY=env_helper.ORCHESTRATION_STRATEGY @@ -229,6 +232,7 @@ def get_default_config(): @staticmethod def clear_config(): ConfigHelper._default_config = None + ConfigHelper.get_active_config_or_default.cache_clear() @staticmethod def _append_advanced_image_processors(): diff --git a/code/backend/pages/04_Configuration.py b/code/backend/pages/04_Configuration.py index dd76f8c8d..5f31bb9e5 100644 --- a/code/backend/pages/04_Configuration.py +++ b/code/backend/pages/04_Configuration.py @@ -1,9 +1,9 @@ -import streamlit as st -import json -import jsonschema import os -import traceback import sys +import traceback +import json +import jsonschema +import streamlit as st from batch.utilities.helpers.env_helper import EnvHelper from batch.utilities.helpers.config.config_helper import ConfigHelper from azure.core.exceptions import ResourceNotFoundError @@ -18,14 +18,14 @@ menu_items=None, ) -mod_page_style = """ +MOD_PAGE_STYLE = """ """ -st.markdown(mod_page_style, unsafe_allow_html=True) +st.markdown(MOD_PAGE_STYLE, unsafe_allow_html=True) config = ConfigHelper.get_active_config_or_default() @@ -379,9 +379,11 @@ def validate_documents(): ), } ConfigHelper.save_config_as_active(current_config) - st.success("Configuration saved successfully!") + st.success( + "Configuration saved successfully! Please restart the chat service for these changes to take effect." + ) - with st.popover(":red[Reset confiiguration to defaults]"): + with st.popover(":red[Reset configuration to defaults]"): st.write( "**Resetting the configuration cannot be reversed, proceed with caution!**" ) diff --git a/code/tests/functional/tests/backend_api/default/conftest.py b/code/tests/functional/tests/backend_api/default/conftest.py index 27f4dadd5..4c8aac922 100644 --- a/code/tests/functional/tests/backend_api/default/conftest.py +++ b/code/tests/functional/tests/backend_api/default/conftest.py @@ -48,3 +48,11 @@ def manage_app(app_port: int, app_config: AppConfig): app_config.remove_from_environment() EnvHelper.clear_instance() ConfigHelper.clear_config() + + +@pytest.fixture(autouse=True) +def reset_default_config(): + """ + Reset the default config after each test + """ + ConfigHelper.clear_config() diff --git a/code/tests/utilities/helpers/test_config_helper.py b/code/tests/utilities/helpers/test_config_helper.py index 7be1a05d6..4bd4568f7 100644 --- a/code/tests/utilities/helpers/test_config_helper.py +++ b/code/tests/utilities/helpers/test_config_helper.py @@ -133,19 +133,33 @@ def env_helper_mock(): env_helper.LOAD_CONFIG_FROM_BLOB_STORAGE = True env_helper.USE_ADVANCED_IMAGE_PROCESSING = False - yield env_helper + yield mock @pytest.fixture(autouse=True) def reset_default_config(): ConfigHelper._default_config = None + ConfigHelper.get_active_config_or_default.cache_clear() yield ConfigHelper._default_config = None + ConfigHelper.get_active_config_or_default.cache_clear() + + +def test_active_config_or_default_is_cached(env_helper_mock: MagicMock): + # when + active_config_one = ConfigHelper.get_active_config_or_default() + active_config_two = ConfigHelper.get_active_config_or_default() + + # then + assert active_config_one is active_config_two + + # We should have called EnvHelper three times for each call to get_active_config_or_default + assert env_helper_mock.call_count == 3 def test_default_config(env_helper_mock: MagicMock): # when - env_helper_mock.ORCHESTRATION_STRATEGY = "mock-strategy" + env_helper_mock.return_value.ORCHESTRATION_STRATEGY = "mock-strategy" default_config = ConfigHelper.get_default_config() # then @@ -163,7 +177,7 @@ def test_default_config_is_cached(): def test_default_config_when_use_advanced_image_processing(env_helper_mock): # given - env_helper_mock.USE_ADVANCED_IMAGE_PROCESSING = True + env_helper_mock.return_value.USE_ADVANCED_IMAGE_PROCESSING = True # when config = ConfigHelper.get_default_config() @@ -384,7 +398,7 @@ def test_get_available_document_types_when_advanced_image_processing_enabled( config: Config, env_helper_mock: MagicMock ): # given - env_helper_mock.USE_ADVANCED_IMAGE_PROCESSING = True + env_helper_mock.return_value.USE_ADVANCED_IMAGE_PROCESSING = True # when document_types = config.get_available_document_types()