From 74cd145024c49334ae3634178f115a1bef41c1fb Mon Sep 17 00:00:00 2001 From: vargastat Date: Wed, 11 Dec 2024 15:45:40 +0100 Subject: [PATCH 1/4] id for Link added --- src/antares/model/link.py | 13 ++++--- src/antares/model/study.py | 13 ++++--- src/antares/service/api_services/link_api.py | 18 ++++----- .../service/local_services/link_local.py | 1 - .../services/api_services/test_link_api.py | 4 +- .../services/api_services/test_study_api.py | 39 +++++-------------- .../services/local_services/test_study.py | 4 +- tests/integration/test_web_client.py | 10 ++--- 8 files changed, 42 insertions(+), 60 deletions(-) diff --git a/src/antares/model/link.py b/src/antares/model/link.py index d4305dea..bb60a9fd 100644 --- a/src/antares/model/link.py +++ b/src/antares/model/link.py @@ -20,6 +20,7 @@ from antares.model.commons import FilterOption, sort_filter_values from antares.tools.alias_generators import to_kebab from antares.tools.all_optional_meta import all_optional_model +from antares.tools.contents_tool import transform_name_to_id class TransmissionCapacities(Enum): @@ -145,16 +146,16 @@ def __init__( # type: ignore # TODO: Find a way to avoid circular imports self._ui = ui or LinkUi() @property - def name(self) -> str: - return self._area_from + " / " + self._area_to + def id(self) -> str: + return self.area_from_id + " / " + self.area_to_id @property - def area_from(self) -> str: - return self._area_from + def area_from_id(self) -> str: + return transform_name_to_id(self._area_from) @property - def area_to(self) -> str: - return self._area_to + def area_to_id(self) -> str: + return transform_name_to_id(self._area_to) @property def properties(self) -> LinkProperties: diff --git a/src/antares/model/study.py b/src/antares/model/study.py index 03e7f13a..e082424d 100644 --- a/src/antares/model/study.py +++ b/src/antares/model/study.py @@ -268,23 +268,24 @@ def create_link( properties: Optional[LinkProperties] = None, ui: Optional[LinkUi] = None, ) -> Link: + sorted_areas = sorted([area_from, area_to]) + area_from, area_to = sorted_areas + missing_areas = [area for area in [area_from, area_to] if area not in self._areas] if missing_areas: raise LinkCreationError(area_from, area_to, f"{', '.join(missing_areas)} does not exist") - existing_link = next( - (link for link in self._links.values() if link.area_from == area_from and link.area_to == area_to), None - ) - if existing_link: + temp_link = Link(area_from, area_to, link_service=None) + if temp_link.id in self._links: raise LinkCreationError(area_from, area_to, f"A link from {area_from} to {area_to} already exists") link = self._link_service.create_link(area_from, area_to, properties, ui) - self._links[link.name] = link + self._links[link.id] = link return link def delete_link(self, link: Link) -> None: self._link_service.delete_link(link) - self._links.pop(link.name) + self._links.pop(link.id) def create_binding_constraint( self, diff --git a/src/antares/service/api_services/link_api.py b/src/antares/service/api_services/link_api.py index 2146d300..ae2d1568 100644 --- a/src/antares/service/api_services/link_api.py +++ b/src/antares/service/api_services/link_api.py @@ -97,18 +97,18 @@ def create_link( return Link(area_from, area_to, self, created_properties, ui) def delete_link(self, link: Link) -> None: - area_from_id = link.area_from - area_to_id = link.area_to + area_from_id = link.area_from_id + area_to_id = link.area_to_id url = f"{self._base_url}/studies/{self.study_id}/links/{area_from_id}/{area_to_id}" try: self._wrapper.delete(url) except APIError as e: - raise LinkDeletionError(link.name, e.message) from e + raise LinkDeletionError(link.id, e.message) from e def update_link_properties(self, link: Link, properties: LinkProperties) -> LinkProperties: # todo: change this code when AntaresWeb will have a real endpoint - area1_id = link.area_from - area2_id = link.area_to + area1_id = link.area_from_id + area2_id = link.area_to_id raw_url = f"{self._base_url}/studies/{self.study_id}/raw?path=input/links/{area1_id}/properties/{area2_id}" try: new_properties = properties.model_dump(mode="json", by_alias=True, exclude_none=True) @@ -134,14 +134,14 @@ def update_link_properties(self, link: Link, properties: LinkProperties) -> Link link_properties = LinkProperties.model_validate(json_response) except APIError as e: - raise LinkPropertiesUpdateError(link.name, e.message) from e + raise LinkPropertiesUpdateError(link.id, e.message) from e return link_properties def update_link_ui(self, link: Link, ui: LinkUi) -> LinkUi: # todo: change this code when AntaresWeb will have a real endpoint - area1_id = link.area_from - area2_id = link.area_to + area1_id = link.area_from_id + area2_id = link.area_to_id raw_url = f"{self._base_url}/studies/{self.study_id}/raw?path=input/links/{area1_id}/properties/{area2_id}" try: new_ui = ui.model_dump(mode="json", by_alias=True, exclude_none=True) @@ -160,7 +160,7 @@ def update_link_ui(self, link: Link, ui: LinkUi) -> LinkUi: link_ui = LinkUi.model_validate(json_response) except APIError as e: - raise LinkUiUpdateError(link.name, e.message) from e + raise LinkUiUpdateError(link.id, e.message) from e return link_ui diff --git a/src/antares/service/local_services/link_local.py b/src/antares/service/local_services/link_local.py index 495e3772..66d82928 100644 --- a/src/antares/service/local_services/link_local.py +++ b/src/antares/service/local_services/link_local.py @@ -55,7 +55,6 @@ def create_link( Raises: LinkCreationError if an area doesn't exist or existing areas have not been provided """ - area_from, area_to = sorted([area_from, area_to]) link_dir = self.config.study_path / "input/links" / area_from os.makedirs(link_dir, exist_ok=True) diff --git a/tests/antares/services/api_services/test_link_api.py b/tests/antares/services/api_services/test_link_api.py index 3054f535..3ae3dcd7 100644 --- a/tests/antares/services/api_services/test_link_api.py +++ b/tests/antares/services/api_services/test_link_api.py @@ -67,7 +67,7 @@ def test_update_links_properties_fails(self): with pytest.raises( LinkPropertiesUpdateError, - match=f"Could not update properties for link {self.link.name}: {antares_web_description_msg}", + match=f"Could not update properties for link {self.link.id}: {antares_web_description_msg}", ): self.link.update_properties(properties) @@ -99,6 +99,6 @@ def test_update_links_ui_fails(self): mocker.get(raw_url, json={"description": antares_web_description_msg}, status_code=404) with pytest.raises( LinkUiUpdateError, - match=f"Could not update ui for link {self.link.name}: {antares_web_description_msg}", + match=f"Could not update ui for link {self.link.id}: {antares_web_description_msg}", ): self.link.update_ui(ui) diff --git a/tests/antares/services/api_services/test_study_api.py b/tests/antares/services/api_services/test_study_api.py index f1b33eac..695e4167 100644 --- a/tests/antares/services/api_services/test_study_api.py +++ b/tests/antares/services/api_services/test_study_api.py @@ -155,26 +155,6 @@ def test_create_link_success(self): link = self.study.create_link(area_from="area", area_to="area_to") assert isinstance(link, Link) - def test_create_link_fails(self): - with requests_mock.Mocker() as mocker: - url = f"https://antares.com/api/v1/studies/{self.study_id}/links" - mocker.post(url, json={"description": self.antares_web_description_msg}, status_code=404) - - self.study._areas["area_from"] = Area( - "area_from", - Mock(), - Mock(), - Mock(), - Mock(), - ) - area_to = "area_final" - - with pytest.raises( - LinkCreationError, - match=f"Could not create the link area_from / {area_to}: {area_to} does not exist", - ): - self.study.create_link(area_from="area_from", area_to=area_to) - def test_create_binding_constraint_success(self): with requests_mock.Mocker() as mocker: url = f"https://antares.com/api/v1/studies/{self.study_id}/bindingconstraints" @@ -289,31 +269,32 @@ def test_create_variant_fails(self): create_variant_api(self.api, self.study_id, variant_name) def test_create_duplicated_link(self): - area_from = "area_1" - area_to = "area_2" + area_a = "area_a" + area_b = "area_b" - self.study._areas[area_from] = Area( - area_from, + self.study._areas[area_a] = Area( + area_a, self.study._area_service, Mock(), Mock(), Mock(), ) - self.study._areas[area_to] = Area( - area_to, + self.study._areas[area_b] = Area( + area_b, self.study._area_service, Mock(), Mock(), Mock(), ) - self.study._links[f"{area_from}/{area_to}"] = Link(area_from, area_to, Mock()) + existing_link = Link(area_a, area_b, Mock()) + self.study._links[existing_link.id] = existing_link with pytest.raises( LinkCreationError, - match=f"Could not create the link {area_from} / {area_to}: A link from {area_from} to {area_to} already exists", + match=f"Could not create the link {area_a} / {area_b}: A link from {area_a} to {area_b} already exists", ): - self.study.create_link(area_from=area_from, area_to=area_to) + self.study.create_link(area_from=area_b, area_to=area_a) def test_create_link_unknown_area(self): area_from = "area_fr" diff --git a/tests/antares/services/local_services/test_study.py b/tests/antares/services/local_services/test_study.py index 93f7c133..f4845ef6 100644 --- a/tests/antares/services/local_services/test_study.py +++ b/tests/antares/services/local_services/test_study.py @@ -1660,8 +1660,8 @@ def test_create_link_alphabetically(self, tmp_path, local_study): area_to=area_to, ) - assert link_created.area_from == "at" - assert link_created.area_to == "fr" + assert link_created.area_from_id == "at" + assert link_created.area_to_id == "fr" def test_create_link_sets_ini_content(self, tmp_path, local_study_w_areas): # Given diff --git a/tests/integration/test_web_client.py b/tests/integration/test_web_client.py index bd79cbd8..d2ceb1c6 100644 --- a/tests/integration/test_web_client.py +++ b/tests/integration/test_web_client.py @@ -105,9 +105,9 @@ def test_creation_lifecycle(self, antares_web: AntaresWebDesktop): # tests link creation with default values link_de_fr = study.create_link(area_from=area_de.id, area_to=area_fr.id) - assert link_de_fr.area_from == area_de.id - assert link_de_fr.area_to == area_fr.id - assert link_de_fr.name == f"{area_de.id} / {area_fr.id}" + assert link_de_fr.area_from_id == area_de.id + assert link_de_fr.area_to_id == area_fr.id + assert link_de_fr.id == f"{area_de.id} / {area_fr.id}" # tests link creation with ui and properties link_ui = LinkUi(colorr=44) @@ -120,7 +120,7 @@ def test_creation_lifecycle(self, antares_web: AntaresWebDesktop): # asserts study contains all links and areas assert study.get_areas() == {area_be.id: area_be, area_fr.id: area_fr, area_de.id: area_de} - assert study.get_links() == {link_be_fr.name: link_be_fr, link_de_fr.name: link_de_fr} + assert study.get_links() == {link_be_fr.id: link_be_fr, link_de_fr.id: link_de_fr} # test thermal cluster creation with default values thermal_name = "Cluster_test %?" @@ -407,7 +407,7 @@ def test_creation_lifecycle(self, antares_web: AntaresWebDesktop): # tests link deletion study.delete_link(link_de_fr) - assert link_de_fr.name not in study.get_links() + assert link_de_fr.id not in study.get_links() # tests thermal cluster deletion area_be.delete_thermal_cluster(thermal_be) From e53416fa65a5ed4f3a8f90392aca40bc115f0a30 Mon Sep 17 00:00:00 2001 From: vargastat Date: Wed, 11 Dec 2024 16:10:03 +0100 Subject: [PATCH 2/4] check create_link from to same area added --- src/antares/model/study.py | 3 +++ .../services/api_services/test_study_api.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/antares/model/study.py b/src/antares/model/study.py index e082424d..bed93900 100644 --- a/src/antares/model/study.py +++ b/src/antares/model/study.py @@ -268,6 +268,9 @@ def create_link( properties: Optional[LinkProperties] = None, ui: Optional[LinkUi] = None, ) -> Link: + if area_from == area_to: + raise LinkCreationError(area_from, area_to, "A link cannot start and end at the same area") + sorted_areas = sorted([area_from, area_to]) area_from, area_to = sorted_areas diff --git a/tests/antares/services/api_services/test_study_api.py b/tests/antares/services/api_services/test_study_api.py index 695e4167..fbbb8fae 100644 --- a/tests/antares/services/api_services/test_study_api.py +++ b/tests/antares/services/api_services/test_study_api.py @@ -313,3 +313,20 @@ def test_create_link_unknown_area(self): match=f"Could not create the link {area_from} / {area_to}: {area_to} does not exist", ): self.study.create_link(area_from=area_from, area_to=area_to) + + def test_create_link_same_area(self): + area = "area_1" + + self.study._areas[area] = Area( + area, + self.study._area_service, + Mock(), + Mock(), + Mock(), + ) + + with pytest.raises( + LinkCreationError, + match=f"Could not create the link {area} / {area}: A link cannot start and end at the same area", + ): + self.study.create_link(area_from=area, area_to=area) From fea6f3dffa550e3cc4a07c810001d7e1f05d4ea6 Mon Sep 17 00:00:00 2001 From: vargastat Date: Thu, 12 Dec 2024 11:49:50 +0100 Subject: [PATCH 3/4] area_from_id and area_to_id checked for same area creation error --- src/antares/model/study.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/antares/model/study.py b/src/antares/model/study.py index bed93900..308509b4 100644 --- a/src/antares/model/study.py +++ b/src/antares/model/study.py @@ -268,9 +268,6 @@ def create_link( properties: Optional[LinkProperties] = None, ui: Optional[LinkUi] = None, ) -> Link: - if area_from == area_to: - raise LinkCreationError(area_from, area_to, "A link cannot start and end at the same area") - sorted_areas = sorted([area_from, area_to]) area_from, area_to = sorted_areas @@ -279,6 +276,10 @@ def create_link( raise LinkCreationError(area_from, area_to, f"{', '.join(missing_areas)} does not exist") temp_link = Link(area_from, area_to, link_service=None) + + if temp_link.area_from_id == temp_link.area_to_id: + raise LinkCreationError(area_from, area_to, "A link cannot start and end at the same area") + if temp_link.id in self._links: raise LinkCreationError(area_from, area_to, f"A link from {area_from} to {area_to} already exists") From a97c9460f4c3ac9bd9f6f21f7bc7a20db0d0dede Mon Sep 17 00:00:00 2001 From: belthlemar Date: Thu, 12 Dec 2024 15:56:00 +0100 Subject: [PATCH 4/4] put back the tests as they were --- src/antares/model/study.py | 18 +++++++++--------- tests/antares/integration/test_local_client.py | 8 ++++---- .../services/local_services/test_area.py | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/antares/model/study.py b/src/antares/model/study.py index 308509b4..07c5679c 100644 --- a/src/antares/model/study.py +++ b/src/antares/model/study.py @@ -268,22 +268,22 @@ def create_link( properties: Optional[LinkProperties] = None, ui: Optional[LinkUi] = None, ) -> Link: - sorted_areas = sorted([area_from, area_to]) - area_from, area_to = sorted_areas - - missing_areas = [area for area in [area_from, area_to] if area not in self._areas] - if missing_areas: - raise LinkCreationError(area_from, area_to, f"{', '.join(missing_areas)} does not exist") - temp_link = Link(area_from, area_to, link_service=None) + area_from, area_to = sorted([area_from, area_to]) + area_from_id = temp_link.area_from_id + area_to_id = temp_link.area_to_id - if temp_link.area_from_id == temp_link.area_to_id: + if area_from_id == area_to_id: raise LinkCreationError(area_from, area_to, "A link cannot start and end at the same area") + missing_areas = [area for area in [area_from_id, area_to_id] if area not in self._areas] + if missing_areas: + raise LinkCreationError(area_from, area_to, f"{', '.join(missing_areas)} does not exist") + if temp_link.id in self._links: raise LinkCreationError(area_from, area_to, f"A link from {area_from} to {area_to} already exists") - link = self._link_service.create_link(area_from, area_to, properties, ui) + link = self._link_service.create_link(area_from_id, area_to_id, properties, ui) self._links[link.id] = link return link diff --git a/tests/antares/integration/test_local_client.py b/tests/antares/integration/test_local_client.py index 91e3fcae..0bc14006 100644 --- a/tests/antares/integration/test_local_client.py +++ b/tests/antares/integration/test_local_client.py @@ -139,9 +139,9 @@ def test_local_study(self, tmp_path, unknown_area): # tests link creation with default values link_de_fr = test_study.create_link(area_from=area_de.id, area_to=fr.id) - assert link_de_fr.area_from == area_de.id - assert link_de_fr.area_to == fr.id - assert link_de_fr.name == f"{area_de.id} / {fr.id}" + assert link_de_fr.area_from_id == area_de.id + assert link_de_fr.area_to_id == fr.id + assert link_de_fr.id == f"{area_de.id} / {fr.id}" # tests link creation with ui and properties link_ui = LinkUi(colorr=44) @@ -161,7 +161,7 @@ def test_local_study(self, tmp_path, unknown_area): # asserts study contains all links and areas assert test_study.get_areas() == {at.id: at, area_be.id: area_be, fr.id: fr, area_de.id: area_de} - assert test_study.get_links() == {at_fr.name: at_fr, link_be_fr.name: link_be_fr, link_de_fr.name: link_de_fr} + assert test_study.get_links() == {at_fr.id: at_fr, link_be_fr.id: link_be_fr, link_de_fr.id: link_de_fr} # test thermal cluster creation with default values thermal_name = "Cluster_test" diff --git a/tests/antares/services/local_services/test_area.py b/tests/antares/services/local_services/test_area.py index a08120fb..f639d6ad 100644 --- a/tests/antares/services/local_services/test_area.py +++ b/tests/antares/services/local_services/test_area.py @@ -1409,7 +1409,7 @@ def test_read_links_local(self, local_study_w_links): links = local_study_object.read_links() for link in links: - if link.area_from == "fr": + if link.area_from_id == "fr": matrix = link.get_capacity_direct() matrix_2 = link.get_capacity_indirect() matrix_3 = link.get_parameters()