From 4973fe09fec1843330cef15477fe122f35c8278e Mon Sep 17 00:00:00 2001 From: vargastat Date: Wed, 4 Dec 2024 13:03:12 +0100 Subject: [PATCH] conflits resolved --- src/antares/model/study.py | 23 ++++- .../api_services/binding_constraint_api.py | 2 - .../binding_constraint_local.py | 86 +++++++++++++++---- .../services/local_services/test_study.py | 14 +-- 4 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/antares/model/study.py b/src/antares/model/study.py index b105ff63..df35c1d0 100644 --- a/src/antares/model/study.py +++ b/src/antares/model/study.py @@ -205,6 +205,7 @@ def __init__( self._settings = DefaultStudySettings.model_validate(settings if settings is not None else StudySettings()) self._areas: Dict[str, Area] = dict() self._links: Dict[str, Link] = dict() + self._binding_constraints: Dict[str, BindingConstraint] = dict() @property def service(self) -> BaseStudyService: @@ -229,7 +230,7 @@ def get_settings(self) -> DefaultStudySettings: return self._settings def get_binding_constraints(self) -> MappingProxyType[str, BindingConstraint]: - return MappingProxyType(self._binding_constraints_service.binding_constraints) + return MappingProxyType(self._binding_constraints) def create_area( self, area_name: str, *, properties: Optional[AreaProperties] = None, ui: Optional[AreaUi] = None @@ -269,9 +270,25 @@ def create_binding_constraint( equal_term_matrix: Optional[pd.DataFrame] = None, greater_term_matrix: Optional[pd.DataFrame] = None, ) -> BindingConstraint: - return self._binding_constraints_service.create_binding_constraint( + """ + Create a new binding constraint and store it. + + Args: + name (str): The name of the binding constraint. + properties (Optional[BindingConstraintProperties]): Optional properties for the constraint. + terms (Optional[List[ConstraintTerm]]): Optional list of terms for the constraint. + less_term_matrix (Optional[pd.DataFrame]): Optional less-than term matrix. + equal_term_matrix (Optional[pd.DataFrame]): Optional equality term matrix. + greater_term_matrix (Optional[pd.DataFrame]): Optional greater-than term matrix. + + Returns: + BindingConstraint: The created binding constraint. + """ + binding_constraint = self._binding_constraints_service.create_binding_constraint( name, properties, terms, less_term_matrix, equal_term_matrix, greater_term_matrix ) + self._binding_constraints[binding_constraint.name] = binding_constraint + return binding_constraint def update_settings(self, settings: StudySettings) -> None: new_settings = self._study_service.update_study_settings(settings) @@ -280,7 +297,7 @@ def update_settings(self, settings: StudySettings) -> None: def delete_binding_constraint(self, constraint: BindingConstraint) -> None: self._study_service.delete_binding_constraint(constraint) - self._binding_constraints_service.binding_constraints.pop(constraint.id) + self._binding_constraints.pop(constraint.id) def delete(self, children: bool = False) -> None: self._study_service.delete(children) diff --git a/src/antares/service/api_services/binding_constraint_api.py b/src/antares/service/api_services/binding_constraint_api.py index 167ef364..3646143c 100644 --- a/src/antares/service/api_services/binding_constraint_api.py +++ b/src/antares/service/api_services/binding_constraint_api.py @@ -43,7 +43,6 @@ def __init__(self, config: APIconf, study_id: str) -> None: self.study_id = study_id self._wrapper = RequestWrapper(self.api_config.set_up_api_conf()) self._base_url = f"{self.api_config.get_host()}/api/v1" - self.binding_constraints = {} def create_binding_constraint( self, @@ -105,7 +104,6 @@ def create_binding_constraint( raise BindingConstraintCreationError(name, e.message) from e constraint = BindingConstraint(name, self, bc_properties, bc_terms) - self.binding_constraints[constraint.id] = constraint return constraint diff --git a/src/antares/service/local_services/binding_constraint_local.py b/src/antares/service/local_services/binding_constraint_local.py index d8eee345..12a8b027 100644 --- a/src/antares/service/local_services/binding_constraint_local.py +++ b/src/antares/service/local_services/binding_constraint_local.py @@ -9,7 +9,6 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. - from typing import Any, Optional import numpy as np @@ -22,6 +21,7 @@ BindingConstraintFrequency, BindingConstraintOperator, BindingConstraintProperties, + BindingConstraintPropertiesLocal, ConstraintMatrixName, ConstraintTerm, ) @@ -37,7 +37,6 @@ def __init__(self, config: LocalConfiguration, study_name: str, **kwargs: Any) - self.config = config self.study_name = study_name self.ini_file = IniFile(self.config.study_path, IniFileTypes.BINDING_CONSTRAINTS_INI) - self.binding_constraints = {} def create_binding_constraint( self, @@ -54,17 +53,10 @@ def create_binding_constraint( properties=properties, terms=terms, ) - if constraint.id in self.binding_constraints: - raise BindingConstraintCreationError( - constraint_name=name, message=f"A binding constraint with the name '{name}' already exists." - ) constraint.properties = constraint.local_properties.yield_binding_constraint_properties() - # Add binding constraints - self.binding_constraints[constraint.id] = constraint - self._write_binding_constraint_ini() + self._write_binding_constraint_ini(constraint.properties, name, name, terms) - # Add constraint time series self._store_time_series(constraint, less_term_matrix, equal_term_matrix, greater_term_matrix) return constraint @@ -103,20 +95,76 @@ def _check_if_empty_ts(time_step: BindingConstraintFrequency, time_series: Optio time_series_length = (365 * 24 + 24) if time_step == BindingConstraintFrequency.HOURLY else 366 return time_series if time_series is not None else pd.DataFrame(np.zeros([time_series_length, 1])) - def _write_binding_constraint_ini(self) -> None: - binding_constraints_ini_content = { - idx: idx_constraint.local_properties.list_ini_fields - for idx, idx_constraint in enumerate(self.binding_constraints.values()) - } - self.ini_file.ini_dict = binding_constraints_ini_content + def _write_binding_constraint_ini( + self, + properties: BindingConstraintProperties, + constraint_name: str, + constraint_id: str, + terms: Optional[list[ConstraintTerm]] = None, + ) -> None: + """ + Write a single binding constraint to the INI file, reconstructing a full BindingConstraintPropertiesLocal instance. + + Args: + properties (BindingConstraintProperties): Basic properties of the binding constraint. + constraint_name (str): The name of the constraint. + constraint_id (str): The ID of the constraint. + terms (dict[str, ConstraintTerm], optional): Terms applying to the binding constraint. Defaults to None. + Raises: + BindingConstraintCreationError: If a binding constraint with the same name already exists in the INI file. + """ + + current_ini_content = self.ini_file.ini_dict or {} + + if constraint_name in current_ini_content: + if terms in [None, {}]: + raise BindingConstraintCreationError( + constraint_name=constraint_name, + message=f"A binding constraint with the name {constraint_name} already exists with terms.", + ) + + terms_dict = {term.id: term for term in terms} if terms else {} + + full_properties = BindingConstraintPropertiesLocal( + constraint_name=constraint_name, constraint_id=constraint_id, terms=terms_dict, **properties.model_dump() + ) + + current_ini_content = self.ini_file.ini_dict or {} + + current_ini_content[full_properties.constraint_name] = full_properties.list_ini_fields + + self.ini_file.ini_dict = current_ini_content + self.ini_file.write_ini_file() def add_constraint_terms(self, constraint: BindingConstraint, terms: list[ConstraintTerm]) -> list[ConstraintTerm]: - new_terms = constraint.local_properties.terms | { - term.id: term for term in terms if term.id not in constraint.get_terms() + """ + Add terms to a binding constraint and update the INI file. + + Args: + constraint (BindingConstraint): The binding constraint to update. + terms (list[ConstraintTerm]): A list of new terms to add. + + Returns: + list[ConstraintTerm]: The updated list of terms. + """ + + new_terms = { + **constraint.local_properties.terms, # Existing terms + **{term.id: term for term in terms if term.id not in constraint.get_terms()}, # New terms } + constraint.local_properties.terms = new_terms - self._write_binding_constraint_ini() + + list(new_terms.values()) + + self._write_binding_constraint_ini( + properties=constraint.properties, + constraint_name=constraint.name, + constraint_id=constraint.id, + terms=list(new_terms.values()), + ) + return list(new_terms.values()) def delete_binding_constraint_term(self, constraint_id: str, term_id: str) -> None: diff --git a/tests/antares/services/local_services/test_study.py b/tests/antares/services/local_services/test_study.py index 846312cd..4d78cdfc 100644 --- a/tests/antares/services/local_services/test_study.py +++ b/tests/antares/services/local_services/test_study.py @@ -1498,7 +1498,7 @@ def test_creating_duplicate_area_name_errors(self, local_study_w_areas): # Then with pytest.raises( AreaCreationError, - match=f"Could not create the area {area_to_create}: There is already an area '{area_to_create}' in the study '{local_study_w_areas.name}'", + match=f"Could not create the area {area_to_create}: There is already an area '{area_to_create}' in the study '{local_study_w_areas.name}", ): local_study_w_areas.create_area(area_to_create) @@ -2071,7 +2071,7 @@ def test_duplicate_name_errors(self, local_study_with_constraint): # Then with pytest.raises( BindingConstraintCreationError, - match=f"Could not create the binding constraint {binding_constraint_name}: A binding constraint with the name '{binding_constraint_name}' already exists.", + match=f"Could not create the binding constraint {binding_constraint_name}: A binding constraint with the name {binding_constraint_name} already exists.", ): local_study_with_constraint.create_binding_constraint(name=binding_constraint_name) @@ -2099,7 +2099,7 @@ def test_constraints_ini_have_correct_default_content( self, local_study_with_constraint, test_constraint, default_constraint_properties ): # Given - expected_ini_contents = """[0] + expected_ini_contents = """[test constraint] name = test constraint id = test constraint enabled = true @@ -2133,7 +2133,7 @@ def test_constraints_and_ini_have_custom_properties(self, local_study_with_const filter_synthesis="monthly", group="test group", ) - expected_ini_content = """[0] + expected_ini_content = """[test constraint] name = test constraint id = test constraint enabled = true @@ -2143,7 +2143,7 @@ def test_constraints_and_ini_have_custom_properties(self, local_study_with_const filter-synthesis = hourly group = default -[1] +[test constraint two] name = test constraint two id = test constraint two enabled = false @@ -2176,7 +2176,7 @@ def test_constraint_can_add_term(self, test_constraint): def test_constraint_term_and_ini_have_correct_defaults(self, local_study_with_constraint, test_constraint): # Given - expected_ini_contents = """[0] + expected_ini_contents = """[test constraint] name = test constraint id = test constraint enabled = true @@ -2200,7 +2200,7 @@ def test_constraint_term_with_offset_and_ini_have_correct_values( self, local_study_with_constraint, test_constraint ): # Given - expected_ini_contents = """[0] + expected_ini_contents = """[test constraint] name = test constraint id = test constraint enabled = true