diff --git a/antarest/study/business/utils.py b/antarest/study/business/utils.py index 76671f2eec..7b30581398 100644 --- a/antarest/study/business/utils.py +++ b/antarest/study/business/utils.py @@ -15,11 +15,13 @@ from antares.study.version import StudyVersion from antarest.core.exceptions import CommandApplicationError +from antarest.core.interfaces.cache import CacheConstants from antarest.core.jwt import DEFAULT_ADMIN_USER from antarest.core.requests import RequestParameters from antarest.core.serialization import AntaresBaseModel from antarest.study.business.all_optional_meta import camel_case_model from antarest.study.model import RawStudy, Study +from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfigDTO from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.storage_service import StudyStorageService from antarest.study.storage.utils import is_managed @@ -40,12 +42,23 @@ def execute_or_add_commands( ) -> None: if isinstance(study, RawStudy): executed_commands: t.MutableSequence[ICommand] = [] + should_invalidate_cache = False for command in commands: + if not command.can_update_study_config(): + should_invalidate_cache = True result = command.apply(file_study, listener) if not result.status: raise CommandApplicationError(result.message) executed_commands.append(command) - storage_service.variant_study_service.invalidate_cache(study) + # if commands that can't update the cache are applied, we need to invalidate it. + # Otherwise, we can update it. + if should_invalidate_cache: + storage_service.variant_study_service.invalidate_cache(study) + else: + storage_service.raw_study_service.cache.put( + f"{CacheConstants.STUDY_FACTORY}/{file_study.config.study_id}", + FileStudyTreeConfigDTO.from_build_config(file_study.config).model_dump(mode="json"), + ) if not is_managed(study): # In a previous version, de-normalization was performed asynchronously. # However, this cause problems with concurrent file access, diff --git a/antarest/study/storage/variantstudy/model/command/create_area.py b/antarest/study/storage/variantstudy/model/command/create_area.py index 30cd0608a4..5fe6538fcb 100644 --- a/antarest/study/storage/variantstudy/model/command/create_area.py +++ b/antarest/study/storage/variantstudy/model/command/create_area.py @@ -317,3 +317,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py b/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py index 2e3d26e9bd..01cab8c684 100644 --- a/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py @@ -403,6 +403,10 @@ def apply_binding_constraint( study_data.tree.save(matrix_term, ["input", "bindingconstraints", matrix_id]) return CommandOutput(status=True) + @override + def can_update_study_config(self) -> bool: + return True + class CreateBindingConstraint(AbstractBindingConstraintCommand): """ diff --git a/antarest/study/storage/variantstudy/model/command/create_cluster.py b/antarest/study/storage/variantstudy/model/command/create_cluster.py index 8364ab0857..6300459a19 100644 --- a/antarest/study/storage/variantstudy/model/command/create_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/create_cluster.py @@ -102,7 +102,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu # Check if the cluster already exists in the area version = study_data.version - cluster = create_thermal_config(version, name=self.cluster_name) + cluster = create_thermal_config(version, **self.parameters) if any(cl.id == cluster.id for cl in area.thermals): return ( CommandOutput( @@ -247,3 +247,7 @@ def get_inner_matrices(self) -> t.List[str]: assert_this(isinstance(self.modulation, str)) matrices.append(strip_matrix_protocol(self.modulation)) return matrices + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/create_district.py b/antarest/study/storage/variantstudy/model/command/create_district.py index adde84a6ee..d11bce0b35 100644 --- a/antarest/study/storage/variantstudy/model/command/create_district.py +++ b/antarest/study/storage/variantstudy/model/command/create_district.py @@ -166,3 +166,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/create_link.py b/antarest/study/storage/variantstudy/model/command/create_link.py index 134491ce8c..90384dc81d 100644 --- a/antarest/study/storage/variantstudy/model/command/create_link.py +++ b/antarest/study/storage/variantstudy/model/command/create_link.py @@ -310,3 +310,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return super().get_inner_matrices() + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py b/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py index a278a1e5d6..995b4926cd 100644 --- a/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py @@ -83,7 +83,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu # Check if the cluster already exists in the area version = study_data.version - cluster = create_renewable_config(version, name=self.cluster_name) + cluster = create_renewable_config(version, **self.parameters) if any(cl.id == cluster.id for cl in area.renewables): return ( CommandOutput( @@ -187,3 +187,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/create_st_storage.py b/antarest/study/storage/variantstudy/model/command/create_st_storage.py index e247b7215c..f454333498 100644 --- a/antarest/study/storage/variantstudy/model/command/create_st_storage.py +++ b/antarest/study/storage/variantstudy/model/command/create_st_storage.py @@ -348,3 +348,7 @@ def get_inner_matrices(self) -> t.List[str]: """ matrices: t.List[str] = [strip_matrix_protocol(getattr(self, attr)) for attr in _MATRIX_NAMES] return matrices + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/create_user_resource.py b/antarest/study/storage/variantstudy/model/command/create_user_resource.py index 0afb321e54..ae5e7f4999 100644 --- a/antarest/study/storage/variantstudy/model/command/create_user_resource.py +++ b/antarest/study/storage/variantstudy/model/command/create_user_resource.py @@ -109,3 +109,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py b/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py index 9f8631b608..cdc127257e 100644 --- a/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py +++ b/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py @@ -181,3 +181,7 @@ def _build_matrix_path(matrix_path: Path) -> Path: if not real_path.exists(): (matrix_path / "series.txt.link").rename(real_path) return real_path + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/icommand.py b/antarest/study/storage/variantstudy/model/command/icommand.py index f3c998c67f..c58f8ff06a 100644 --- a/antarest/study/storage/variantstudy/model/command/icommand.py +++ b/antarest/study/storage/variantstudy/model/command/icommand.py @@ -184,6 +184,14 @@ def get_inner_matrices(self) -> t.List[str]: """ raise NotImplementedError() + @abstractmethod + def can_update_study_config(self) -> bool: + """ + Returns whether the command can update the study config or not. + We then know if we need to invalidate the cache or not after the command is used. + """ + raise NotImplementedError() + def get_command_extractor(self) -> "CommandExtractor": """ Create a new `CommandExtractor` used to revert the command changes. diff --git a/antarest/study/storage/variantstudy/model/command/remove_area.py b/antarest/study/storage/variantstudy/model/command/remove_area.py index 4d7c33e922..157625ab36 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_area.py +++ b/antarest/study/storage/variantstudy/model/command/remove_area.py @@ -310,3 +310,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py b/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py index 55dd971133..b384165532 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py @@ -107,3 +107,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_cluster.py b/antarest/study/storage/variantstudy/model/command/remove_cluster.py index 5ff1bebcae..08ddea0c1d 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/remove_cluster.py @@ -223,3 +223,7 @@ def _remove_cluster_from_binding_constraints(self, study_data: FileStudy) -> Non study_data.tree.delete(["input", "bindingconstraints", matrix_id]) study_data.tree.save(binding_constraints, url) + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_district.py b/antarest/study/storage/variantstudy/model/command/remove_district.py index 2b675aed3f..098850cb60 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_district.py +++ b/antarest/study/storage/variantstudy/model/command/remove_district.py @@ -76,3 +76,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_link.py b/antarest/study/storage/variantstudy/model/command/remove_link.py index af5d3a5321..d4d0b1b629 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_link.py +++ b/antarest/study/storage/variantstudy/model/command/remove_link.py @@ -180,3 +180,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py b/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py index 5d82f1630d..22fbf1151b 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py @@ -166,3 +166,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_st_storage.py b/antarest/study/storage/variantstudy/model/command/remove_st_storage.py index 1e230cfdfa..90e47eaa6d 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_st_storage.py +++ b/antarest/study/storage/variantstudy/model/command/remove_st_storage.py @@ -171,3 +171,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/remove_user_resource.py b/antarest/study/storage/variantstudy/model/command/remove_user_resource.py index f873ec2d10..eea506ce0b 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_user_resource.py +++ b/antarest/study/storage/variantstudy/model/command/remove_user_resource.py @@ -91,3 +91,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/replace_matrix.py b/antarest/study/storage/variantstudy/model/command/replace_matrix.py index c796c47ce2..4060d35c86 100644 --- a/antarest/study/storage/variantstudy/model/command/replace_matrix.py +++ b/antarest/study/storage/variantstudy/model/command/replace_matrix.py @@ -123,3 +123,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: def get_inner_matrices(self) -> t.List[str]: assert_this(isinstance(self.matrix, str)) return [strip_matrix_protocol(self.matrix)] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py b/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py index 6c247b4c05..8def9868ae 100644 --- a/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py @@ -234,3 +234,7 @@ def match(self, other: "ICommand", equal: bool = False) -> bool: if not equal: return self.id == other.id return super().match(other, equal) + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/update_comments.py b/antarest/study/storage/variantstudy/model/command/update_comments.py index b5300d171c..f1a01b3439 100644 --- a/antarest/study/storage/variantstudy/model/command/update_comments.py +++ b/antarest/study/storage/variantstudy/model/command/update_comments.py @@ -85,3 +85,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/update_config.py b/antarest/study/storage/variantstudy/model/command/update_config.py index ef054383f0..646ab707e0 100644 --- a/antarest/study/storage/variantstudy/model/command/update_config.py +++ b/antarest/study/storage/variantstudy/model/command/update_config.py @@ -112,3 +112,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return False diff --git a/antarest/study/storage/variantstudy/model/command/update_district.py b/antarest/study/storage/variantstudy/model/command/update_district.py index 5d0b706484..2af4b08951 100644 --- a/antarest/study/storage/variantstudy/model/command/update_district.py +++ b/antarest/study/storage/variantstudy/model/command/update_district.py @@ -134,3 +134,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/update_link.py b/antarest/study/storage/variantstudy/model/command/update_link.py index 16a13fa7e3..8766acfb68 100644 --- a/antarest/study/storage/variantstudy/model/command/update_link.py +++ b/antarest/study/storage/variantstudy/model/command/update_link.py @@ -36,6 +36,17 @@ class UpdateLink(AbstractLinkCommand): @override def _apply_config(self, study_data: FileStudyTreeConfig) -> OutputTuple: + self.parameters = self.parameters or {} + # Only updates to reflect in the config are about the filter values + if "filter-synthesis" in self.parameters or "filter-year-by-year" in self.parameters: + area_from, area_to = sorted([self.area1, self.area2]) + if "filter-synthesis" in self.parameters: + filters_synthesis = [step.strip() for step in self.parameters["filter-synthesis"].split(",")] + study_data.areas[area_from].links[area_to].filters_synthesis = filters_synthesis + if "filter-year-by-year" in self.parameters: + filters_year_by_year = [step.strip() for step in self.parameters["filter-year-by-year"].split(",")] + study_data.areas[area_from].links[area_to].filters_year = filters_year_by_year + return ( CommandOutput( status=True, @@ -84,3 +95,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return super().get_inner_matrices() + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/update_playlist.py b/antarest/study/storage/variantstudy/model/command/update_playlist.py index 3c19b9a2f4..1cfe84bf45 100644 --- a/antarest/study/storage/variantstudy/model/command/update_playlist.py +++ b/antarest/study/storage/variantstudy/model/command/update_playlist.py @@ -94,3 +94,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/antarest/study/storage/variantstudy/model/command/update_raw_file.py b/antarest/study/storage/variantstudy/model/command/update_raw_file.py index 97446dadcc..868d727509 100644 --- a/antarest/study/storage/variantstudy/model/command/update_raw_file.py +++ b/antarest/study/storage/variantstudy/model/command/update_raw_file.py @@ -96,3 +96,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: @override def get_inner_matrices(self) -> List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return False diff --git a/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py b/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py index 4328bcf1fe..dbd22464c8 100644 --- a/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py +++ b/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py @@ -126,3 +126,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: @override def get_inner_matrices(self) -> t.List[str]: return [] + + @override + def can_update_study_config(self) -> bool: + return True diff --git a/tests/storage/test_service.py b/tests/storage/test_service.py index 8359bd063f..9b782c44d1 100644 --- a/tests/storage/test_service.py +++ b/tests/storage/test_service.py @@ -82,6 +82,7 @@ study_matcher, ) from antarest.study.storage.variantstudy.business.matrix_constants_generator import GeneratorMatrixConstants +from antarest.study.storage.variantstudy.model.command.icommand import ICommand from antarest.study.storage.variantstudy.model.command_context import CommandContext from antarest.study.storage.variantstudy.model.dbmodel import VariantStudy from antarest.study.storage.variantstudy.variant_study_service import VariantStudyService @@ -1294,7 +1295,8 @@ def test_edit_study_with_command() -> None: repository=Mock(), config=Mock(), ) - command = Mock() + command = Mock(spec=ICommand) + command.can_update_study_config = Mock(return_value=False) service._create_edit_study_command = Mock(return_value=command) file_study = Mock() file_study.config.study_id = study_id diff --git a/tests/variantstudy/model/command/test_create_cluster.py b/tests/variantstudy/model/command/test_create_cluster.py index 077681bac6..f5aa740676 100644 --- a/tests/variantstudy/model/command/test_create_cluster.py +++ b/tests/variantstudy/model/command/test_create_cluster.py @@ -18,7 +18,7 @@ import pytest from pydantic import ValidationError -from antarest.study.model import STUDY_VERSION_8_8 +from antarest.study.model import STUDY_VERSION_7_2, STUDY_VERSION_8_8 from antarest.study.storage.rawstudy.model.filesystem.config.model import transform_name_to_id from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.variantstudy.business.command_reverter import CommandReverter @@ -120,7 +120,7 @@ def test_apply(self, empty_study: FileStudy, command_context: CommandContext): prepro=prepro, modulation=modulation, command_context=command_context, - study_version=STUDY_VERSION_8_8, + study_version=STUDY_VERSION_7_2, ) output = command.apply(empty_study) @@ -150,7 +150,7 @@ def test_apply(self, empty_study: FileStudy, command_context: CommandContext): prepro=prepro, modulation=modulation, command_context=command_context, - study_version=STUDY_VERSION_8_8, + study_version=STUDY_VERSION_7_2, ).apply(empty_study) assert output.status is False assert re.match( @@ -166,7 +166,7 @@ def test_apply(self, empty_study: FileStudy, command_context: CommandContext): prepro=prepro, modulation=modulation, command_context=command_context, - study_version=STUDY_VERSION_8_8, + study_version=STUDY_VERSION_7_2, ).apply(empty_study) assert output.status is False assert re.match(