From b25e6f65021b2d9900110f167354446f1882732d Mon Sep 17 00:00:00 2001 From: Sylvain Leclerc Date: Fri, 14 Feb 2025 10:37:35 +0100 Subject: [PATCH] refactor(factory): move creation methods to implementation packages (#86) Signed-off-by: Sylvain Leclerc --- src/antares/craft/__init__.py | 24 +- src/antares/craft/model/study.py | 317 +++--------------- .../craft/service/api_services/factory.py | 159 +++++++++ .../craft/service/api_services/study_api.py | 6 +- src/antares/craft/service/base_services.py | 16 + .../craft/service/local_services/factory.py | 207 ++++++++++++ .../service/local_services/services/output.py | 4 +- .../service/local_services/study_local.py | 7 +- src/antares/craft/service/service_factory.py | 177 ---------- tests/antares/integration/conftest.py | 2 +- .../antares/integration/test_local_client.py | 3 +- .../services/api_services/test_area_api.py | 15 +- .../test_binding_constraint_api.py | 37 +- .../services/api_services/test_link_api.py | 10 +- .../services/api_services/test_matrix_api.py | 15 +- .../api_services/test_renewable_api.py | 15 +- .../api_services/test_st_storage_api.py | 15 +- .../services/api_services/test_study_api.py | 21 +- .../services/api_services/test_thermal_api.py | 17 +- .../services/local_services/conftest.py | 3 +- .../services/local_services/test_area.py | 2 +- .../services/local_services/test_study.py | 2 +- .../local_services/test_study_read.py | 2 +- tests/integration/test_web_client.py | 2 +- 24 files changed, 545 insertions(+), 533 deletions(-) create mode 100644 src/antares/craft/service/api_services/factory.py create mode 100644 src/antares/craft/service/local_services/factory.py delete mode 100644 src/antares/craft/service/service_factory.py diff --git a/src/antares/craft/__init__.py b/src/antares/craft/__init__.py index 9f7ee3df..8c848ba3 100644 --- a/src/antares/craft/__init__.py +++ b/src/antares/craft/__init__.py @@ -10,6 +10,26 @@ # # This file is part of the Antares project. -from antares.craft.model.study import create_study_api, create_study_local +from antares.craft.api_conf.api_conf import APIconf +from antares.craft.config.local_configuration import LocalConfiguration +from antares.craft.model.study import ( + Study, + create_study_api, + create_study_local, + create_variant_api, + import_study_api, + read_study_api, + read_study_local, +) -__all__ = ["create_study_api", "create_study_local"] +__all__ = [ + "Study", + "APIconf", + "LocalConfiguration", + "create_study_api", + "import_study_api", + "read_study_api", + "create_variant_api", + "read_study_local", + "create_study_local", +] diff --git a/src/antares/craft/model/study.py b/src/antares/craft/model/study.py index 040deb41..a4c6e793 100644 --- a/src/antares/craft/model/study.py +++ b/src/antares/craft/model/study.py @@ -9,10 +9,6 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. -import io -import logging -import os -import time from pathlib import Path, PurePath from types import MappingProxyType @@ -20,15 +16,9 @@ import pandas as pd -from antares.craft.api_conf.api_conf import APIconf -from antares.craft.api_conf.request_wrapper import RequestWrapper -from antares.craft.config.local_configuration import LocalConfiguration +from antares.craft import APIconf from antares.craft.exceptions.exceptions import ( - APIError, LinkCreationError, - StudyCreationError, - StudyImportError, - StudyMoveError, ) from antares.craft.model.area import Area, AreaProperties, AreaUi from antares.craft.model.binding_constraint import ( @@ -40,10 +30,7 @@ from antares.craft.model.output import Output from antares.craft.model.settings.study_settings import StudySettings, StudySettingsUpdate from antares.craft.model.simulation import AntaresSimulationParameters, Job -from antares.craft.service.base_services import BaseLinkService, BaseStudyService -from antares.craft.service.local_services.services.settings import edit_study_settings -from antares.craft.service.service_factory import ServiceFactory -from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes +from antares.craft.service.base_services import BaseLinkService, BaseStudyService, StudyServices """ The study module defines the data model for antares study. @@ -54,218 +41,23 @@ """ -def create_study_api( - study_name: str, - version: str, - api_config: APIconf, - parent_path: Optional[Path] = None, -) -> "Study": - """ - Args: - study_name: antares study name to be created - version: antares version - api_config: host and token config for API - - Raises: - MissingTokenError if api_token is missing - StudyCreationError if an HTTP Exception occurs - """ - - session = api_config.set_up_api_conf() - wrapper = RequestWrapper(session) - base_url = f"{api_config.get_host()}/api/v1" - - try: - url = f"{base_url}/studies?name={study_name}&version={version}" - response = wrapper.post(url) - study_id = response.json() - # Settings part - study = Study(study_name, version, ServiceFactory(api_config, study_id)) - study.read_settings() - # Move part - if parent_path: - study.move(parent_path) - url = f"{base_url}/studies/{study_id}" - json_study = wrapper.get(url).json() - folder = json_study.pop("folder") - study.path = PurePath(folder) if folder else PurePath(".") - return study - except (APIError, StudyMoveError) as e: - raise StudyCreationError(study_name, e.message) from e - - -def import_study_api(api_config: APIconf, study_path: Path, destination_path: Optional[Path] = None) -> "Study": - session = api_config.set_up_api_conf() - wrapper = RequestWrapper(session) - base_url = f"{api_config.get_host()}/api/v1" - - if study_path.suffix not in {".zip", ".7z"}: - raise StudyImportError( - study_path.name, f"File doesn't have the right extensions (.zip/.7z): {study_path.suffix}" - ) - - try: - files = {"study": io.BytesIO(study_path.read_bytes())} - url = f"{base_url}/studies/_import" - study_id = wrapper.post(url, files=files).json() - - study = read_study_api(api_config, study_id) - if destination_path is not None: - study.move(destination_path) - - return study - except APIError as e: - raise StudyImportError(study_path.name, e.message) from e - - -def create_study_local(study_name: str, version: str, parent_directory: Path) -> "Study": - """ - Create a directory structure for the study with empty files. - - Args: - study_name: antares study name to be created - version: antares version for study - parent_directory: Local directory to store the study in. - - Raises: - FileExistsError if the study already exists in the given location - """ - local_config = LocalConfiguration(parent_directory, study_name) - - study_directory = local_config.local_path / study_name - - _verify_study_already_exists(study_directory) - - # Create the directory structure - _create_directory_structure(study_directory) - - # Create study.antares file with timestamps and study_name - antares_file_path = os.path.join(study_directory, "study.antares") - current_time = int(time.time()) - antares_content = f"""[antares] -version = {version} -caption = {study_name} -created = {current_time} -lastsave = {current_time} -author = Unknown -""" - with open(antares_file_path, "w") as antares_file: - antares_file.write(antares_content) - - # Create Desktop.ini file - desktop_ini_path = study_directory / "Desktop.ini" - desktop_ini_content = f"""[.ShellClassInfo] -IconFile = settings/resources/study.ico -IconIndex = 0 -InfoTip = Antares Study {version}: {study_name} -""" - with open(desktop_ini_path, "w") as desktop_ini_file: - desktop_ini_file.write(desktop_ini_content) - - # Create various .ini files for the study - _create_correlation_ini_files(study_directory) - - logging.info(f"Study successfully created: {study_name}") - study = Study( - name=study_name, - version=version, - service_factory=ServiceFactory(config=local_config, study_name=study_name), - path=study_directory, - ) - # We need to create the file with default value - default_settings = StudySettings() - update_settings = default_settings.to_update_settings() - edit_study_settings(study_directory, update_settings, True) - study._settings = default_settings - return study - - -def read_study_local(study_directory: Path) -> "Study": - """ - Read a study structure by returning a study object. - Args: - study_directory: antares study path to be read - - Raises: - FileNotFoundError: If the provided directory does not exist. - - """ - - def _directory_not_exists(local_path: Path) -> None: - if not local_path.is_dir(): - raise FileNotFoundError(f"The path {local_path} doesn't exist or isn't a folder.") - - _directory_not_exists(study_directory) - - study_antares = IniFile(study_directory, InitializationFilesTypes.ANTARES) - - study_params = study_antares.ini_dict["antares"] - - local_config = LocalConfiguration(study_directory.parent, study_directory.name) - - study = Study( - name=study_params["caption"], - version=study_params["version"], - service_factory=ServiceFactory(config=local_config, study_name=study_params["caption"]), - path=study_directory, - ) - study.read_settings() - return study - - -def read_study_api(api_config: APIconf, study_id: str) -> "Study": - session = api_config.set_up_api_conf() - wrapper = RequestWrapper(session) - base_url = f"{api_config.get_host()}/api/v1" - json_study = wrapper.get(f"{base_url}/studies/{study_id}").json() - - study_name = json_study.pop("name") - study_version = str(json_study.pop("version")) - path = json_study.pop("folder") - pure_path = PurePath(path) if path else PurePath(".") - - study = Study(study_name, study_version, ServiceFactory(api_config, study_id, study_name), pure_path) - - study.read_settings() - study.read_areas() - study.read_outputs() - study.read_binding_constraints() - - return study - - -def create_variant_api(api_config: APIconf, study_id: str, variant_name: str) -> "Study": - """ - Creates a variant from a study_id - Args: - api_config: API configuration - study_id: The id of the study to create a variant of - variant_name: the name of the new variant - Returns: The variant in the form of a Study object - """ - factory = ServiceFactory(api_config, study_id) - api_service = factory.create_study_service() - - return api_service.create_variant(variant_name) - - class Study: def __init__( self, name: str, version: str, - service_factory: ServiceFactory, + services: StudyServices, path: PurePath = PurePath("."), ): self.name = name self.version = version self.path = path - self._study_service = service_factory.create_study_service() - self._area_service = service_factory.create_area_service() - self._link_service = service_factory.create_link_service() - self._run_service = service_factory.create_run_service() - self._binding_constraints_service = service_factory.create_binding_constraints_service() - self._settings_service = service_factory.create_settings_service() + self._study_service = services.study_service + self._area_service = services.area_service + self._link_service = services.link_service + self._run_service = services.run_service + self._binding_constraints_service = services.bc_service + self._settings_service = services.settings_service self._settings = StudySettings() self._areas: dict[str, Area] = dict() self._links: dict[str, Link] = dict() @@ -473,49 +265,48 @@ def generate_thermal_timeseries(self) -> None: self._study_service.generate_thermal_timeseries() -def _verify_study_already_exists(study_directory: Path) -> None: - if study_directory.exists(): - raise FileExistsError(f"Study {study_directory.name} already exists.") - - -def _create_directory_structure(study_path: Path) -> None: - subdirectories = [ - "input/hydro/allocation", - "input/hydro/common/capacity", - "input/hydro/series", - "input/links", - "input/load/series", - "input/misc-gen", - "input/reserves", - "input/solar/series", - "input/thermal/clusters", - "input/thermal/prepro", - "input/thermal/series", - "input/wind/series", - "layers", - "output", - "settings/resources", - "settings/simulations", - "user", - ] - for subdirectory in subdirectories: - (study_path / subdirectory).mkdir(parents=True, exist_ok=True) - - -def _create_correlation_ini_files(study_directory: Path) -> None: - correlation_inis_to_create = [ - getattr(InitializationFilesTypes, field.upper() + "_CORRELATION_INI") - for field in ["hydro", "load", "solar", "wind"] - ] - - ini_content = {"general": {"mode": "annual"}, "annual": {}} - for k in range(12): - ini_content[str(k)] = {} - - for file_type in correlation_inis_to_create: - ini_file = IniFile( - study_directory, - file_type, - ini_contents=ini_content, - ) - ini_file.write_ini_file() +# Design note: +# all following methods are entry points for study creation. +# They use methods defined in "local" and "API" implementation services, +# that we inject here. +# Generally speaking, implementations should reference the API, not the +# opposite. Here we perform dependency injection, and because of python +# import mechanics, we need to use local imports to avoid circular dependencies. + + +def create_study_local(study_name: str, version: str, parent_directory: "Path") -> "Study": + from antares.craft.service.local_services.factory import create_study_local + + return create_study_local(study_name, version, parent_directory) + + +def read_study_local(study_path: "Path") -> "Study": + from antares.craft.service.local_services.factory import read_study_local + + return read_study_local(study_path) + + +def create_study_api( + study_name: str, version: str, api_config: APIconf, parent_path: "Optional[Path]" = None +) -> "Study": + from antares.craft.service.api_services.factory import create_study_api + + return create_study_api(study_name, version, api_config, parent_path) + + +def import_study_api(api_config: APIconf, study_path: "Path", destination_path: "Optional[Path]" = None) -> "Study": + from antares.craft.service.api_services.factory import import_study_api + + return import_study_api(api_config, study_path, destination_path) + + +def read_study_api(api_config: APIconf, study_id: str) -> "Study": + from antares.craft.service.api_services.factory import read_study_api + + return read_study_api(api_config, study_id) + + +def create_variant_api(api_config: APIconf, study_id: str, variant_name: str) -> "Study": + from antares.craft.service.api_services.factory import create_variant_api + + return create_variant_api(api_config, study_id, variant_name) diff --git a/src/antares/craft/service/api_services/factory.py b/src/antares/craft/service/api_services/factory.py new file mode 100644 index 00000000..ece105e8 --- /dev/null +++ b/src/antares/craft/service/api_services/factory.py @@ -0,0 +1,159 @@ +# Copyright (c) 2024, RTE (https://www.rte-france.com) +# +# See AUTHORS.txt +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 +# +# This file is part of the Antares project. +import io + +from pathlib import Path, PurePath +from typing import Optional + +from antares.craft.api_conf.api_conf import APIconf +from antares.craft.api_conf.request_wrapper import RequestWrapper +from antares.craft.exceptions.exceptions import APIError, StudyCreationError, StudyImportError, StudyMoveError +from antares.craft.model.study import Study +from antares.craft.service.api_services.area_api import AreaApiService +from antares.craft.service.api_services.link_api import LinkApiService +from antares.craft.service.api_services.services.binding_constraint import BindingConstraintApiService +from antares.craft.service.api_services.services.hydro import HydroApiService +from antares.craft.service.api_services.services.output import OutputApiService +from antares.craft.service.api_services.services.renewable import RenewableApiService +from antares.craft.service.api_services.services.run import RunApiService +from antares.craft.service.api_services.services.settings import StudySettingsAPIService +from antares.craft.service.api_services.services.st_storage import ShortTermStorageApiService +from antares.craft.service.api_services.services.thermal import ThermalApiService +from antares.craft.service.api_services.study_api import StudyApiService +from antares.craft.service.base_services import ( + StudyServices, +) + + +def create_api_services(config: APIconf, study_id: str = "") -> StudyServices: + storage_service = ShortTermStorageApiService(config, study_id) + thermal_service = ThermalApiService(config, study_id) + renewable_service = RenewableApiService(config, study_id) + hydro_service = HydroApiService(config, study_id) + area_service = AreaApiService(config, study_id, storage_service, thermal_service, renewable_service, hydro_service) + link_service = LinkApiService(config, study_id) + output_service = OutputApiService(config, study_id) + study_service = StudyApiService(config, study_id, output_service) + bc_service = BindingConstraintApiService(config, study_id) + run_service = RunApiService(config, study_id) + settings_service = StudySettingsAPIService(config, study_id) + return StudyServices( + area_service=area_service, + bc_service=bc_service, + run_service=run_service, + thermal_service=thermal_service, + hydro_service=hydro_service, + output_service=output_service, + study_service=study_service, + link_service=link_service, + renewable_service=renewable_service, + settings_service=settings_service, + short_term_storage_service=storage_service, + ) + + +def create_study_api( + study_name: str, + version: str, + api_config: APIconf, + parent_path: Optional[Path] = None, +) -> Study: + """ + Args: + study_name: antares study name to be created + version: antares version + api_config: host and token config for API + + Raises: + MissingTokenError if api_token is missing + StudyCreationError if an HTTP Exception occurs + """ + + session = api_config.set_up_api_conf() + wrapper = RequestWrapper(session) + base_url = f"{api_config.get_host()}/api/v1" + + try: + url = f"{base_url}/studies?name={study_name}&version={version}" + response = wrapper.post(url) + study_id = response.json() + # Settings part + study = Study(study_name, version, create_api_services(api_config, study_id)) + study.read_settings() + # Move part + if parent_path: + study.move(parent_path) + url = f"{base_url}/studies/{study_id}" + json_study = wrapper.get(url).json() + folder = json_study.pop("folder") + study.path = PurePath(folder) if folder else PurePath(".") + return study + except (APIError, StudyMoveError) as e: + raise StudyCreationError(study_name, e.message) from e + + +def import_study_api(api_config: APIconf, study_path: Path, destination_path: Optional[Path] = None) -> "Study": + session = api_config.set_up_api_conf() + wrapper = RequestWrapper(session) + base_url = f"{api_config.get_host()}/api/v1" + + if study_path.suffix not in {".zip", ".7z"}: + raise StudyImportError( + study_path.name, f"File doesn't have the right extensions (.zip/.7z): {study_path.suffix}" + ) + + try: + files = {"study": io.BytesIO(study_path.read_bytes())} + url = f"{base_url}/studies/_import" + study_id = wrapper.post(url, files=files).json() + + study = read_study_api(api_config, study_id) + if destination_path is not None: + study.move(destination_path) + + return study + except APIError as e: + raise StudyImportError(study_path.name, e.message) from e + + +def read_study_api(api_config: APIconf, study_id: str) -> "Study": + session = api_config.set_up_api_conf() + wrapper = RequestWrapper(session) + base_url = f"{api_config.get_host()}/api/v1" + json_study = wrapper.get(f"{base_url}/studies/{study_id}").json() + + study_name = json_study.pop("name") + study_version = str(json_study.pop("version")) + path = json_study.pop("folder") + pure_path = PurePath(path) if path else PurePath(".") + + study = Study(study_name, study_version, create_api_services(api_config, study_id), pure_path) + + study.read_settings() + study.read_areas() + study.read_outputs() + study.read_binding_constraints() + + return study + + +def create_variant_api(api_config: APIconf, study_id: str, variant_name: str) -> "Study": + """ + Creates a variant from a study_id + Args: + api_config: API configuration + study_id: The id of the study to create a variant of + variant_name: the name of the new variant + Returns: The variant in the form of a Study object + """ + services = create_api_services(api_config, study_id) + return services.study_service.create_variant(variant_name) diff --git a/src/antares/craft/service/api_services/study_api.py b/src/antares/craft/service/api_services/study_api.py index 3c56f1d4..9c925181 100644 --- a/src/antares/craft/service/api_services/study_api.py +++ b/src/antares/craft/service/api_services/study_api.py @@ -12,8 +12,6 @@ from pathlib import Path, PurePath from typing import TYPE_CHECKING -import antares.craft.model.study as study - from antares.craft.api_conf.api_conf import APIconf from antares.craft.api_conf.request_wrapper import RequestWrapper from antares.craft.exceptions.exceptions import ( @@ -79,11 +77,13 @@ def delete(self, children: bool) -> None: @override def create_variant(self, variant_name: str) -> "Study": + from antares.craft.service.api_services.factory import read_study_api + url = f"{self._base_url}/studies/{self.study_id}/variants?name={variant_name}" try: response = self._wrapper.post(url) variant_id = response.json() - return study.read_study_api(self.config, variant_id) + return read_study_api(self.config, variant_id) except APIError as e: raise StudyVariantCreationError(self.study_id, e.message) from e diff --git a/src/antares/craft/service/base_services.py b/src/antares/craft/service/base_services.py index 38aa0291..c55b60e5 100644 --- a/src/antares/craft/service/base_services.py +++ b/src/antares/craft/service/base_services.py @@ -11,6 +11,7 @@ # This file is part of the Antares project. from abc import ABC, abstractmethod +from dataclasses import dataclass from pathlib import Path, PurePath from typing import TYPE_CHECKING, Optional @@ -813,3 +814,18 @@ def read_study_settings(self) -> StudySettings: Reads the settings of a study """ pass + + +@dataclass(frozen=True) +class StudyServices: + settings_service: BaseStudySettingsService + study_service: BaseStudyService + area_service: BaseAreaService + link_service: BaseLinkService + thermal_service: BaseThermalService + hydro_service: BaseHydroService + bc_service: BaseBindingConstraintService + renewable_service: BaseRenewableService + short_term_storage_service: BaseShortTermStorageService + run_service: BaseRunService + output_service: BaseOutputService diff --git a/src/antares/craft/service/local_services/factory.py b/src/antares/craft/service/local_services/factory.py new file mode 100644 index 00000000..d2957b52 --- /dev/null +++ b/src/antares/craft/service/local_services/factory.py @@ -0,0 +1,207 @@ +# Copyright (c) 2024, RTE (https://www.rte-france.com) +# +# See AUTHORS.txt +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 +# +# This file is part of the Antares project. +import logging +import os +import time + +from pathlib import Path + +from antares.craft.config.local_configuration import LocalConfiguration +from antares.craft.model.settings.study_settings import StudySettings +from antares.craft.model.study import Study +from antares.craft.service.base_services import ( + StudyServices, +) +from antares.craft.service.local_services.area_local import AreaLocalService +from antares.craft.service.local_services.link_local import LinkLocalService +from antares.craft.service.local_services.services.binding_constraint import BindingConstraintLocalService +from antares.craft.service.local_services.services.hydro import HydroLocalService +from antares.craft.service.local_services.services.output import OutputLocalService +from antares.craft.service.local_services.services.renewable import RenewableLocalService +from antares.craft.service.local_services.services.run import RunLocalService +from antares.craft.service.local_services.services.settings import StudySettingsLocalService, edit_study_settings +from antares.craft.service.local_services.services.st_storage import ShortTermStorageLocalService +from antares.craft.service.local_services.services.thermal import ThermalLocalService +from antares.craft.service.local_services.study_local import StudyLocalService +from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes + + +def create_local_services(config: LocalConfiguration, study_name: str = "") -> StudyServices: + storage_service = ShortTermStorageLocalService(config, study_name) + thermal_service = ThermalLocalService(config, study_name) + renewable_service = RenewableLocalService(config, study_name) + hydro_service = HydroLocalService(config, study_name) + area_service = AreaLocalService( + config, study_name, storage_service, thermal_service, renewable_service, hydro_service + ) + link_service = LinkLocalService(config, study_name) + output_service = OutputLocalService(config, study_name) + study_service = StudyLocalService(config, study_name, output_service) + bc_service = BindingConstraintLocalService(config, study_name) + run_service = RunLocalService(config, study_name) + settings_service = StudySettingsLocalService(config, study_name) + short_term_storage_service = ShortTermStorageLocalService(config, study_name) + return StudyServices( + area_service=area_service, + bc_service=bc_service, + run_service=run_service, + thermal_service=thermal_service, + hydro_service=hydro_service, + output_service=output_service, + study_service=study_service, + link_service=link_service, + renewable_service=renewable_service, + settings_service=settings_service, + short_term_storage_service=short_term_storage_service, + ) + + +def _create_correlation_ini_files(study_directory: Path) -> None: + correlation_inis_to_create = [ + getattr(InitializationFilesTypes, field.upper() + "_CORRELATION_INI") + for field in ["hydro", "load", "solar", "wind"] + ] + + ini_content = {"general": {"mode": "annual"}, "annual": {}} + for k in range(12): + ini_content[str(k)] = {} + + for file_type in correlation_inis_to_create: + ini_file = IniFile( + study_directory, + file_type, + ini_contents=ini_content, + ) + ini_file.write_ini_file() + + +def _verify_study_already_exists(study_directory: Path) -> None: + if study_directory.exists(): + raise FileExistsError(f"Study {study_directory.name} already exists.") + + +def _create_directory_structure(study_path: Path) -> None: + subdirectories = [ + "input/hydro/allocation", + "input/hydro/common/capacity", + "input/hydro/series", + "input/links", + "input/load/series", + "input/misc-gen", + "input/reserves", + "input/solar/series", + "input/thermal/clusters", + "input/thermal/prepro", + "input/thermal/series", + "input/wind/series", + "layers", + "output", + "settings/resources", + "settings/simulations", + "user", + ] + for subdirectory in subdirectories: + (study_path / subdirectory).mkdir(parents=True, exist_ok=True) + + +def create_study_local(study_name: str, version: str, parent_directory: Path) -> "Study": + """ + Create a directory structure for the study with empty files. + + Args: + study_name: antares study name to be created + version: antares version for study + parent_directory: Local directory to store the study in. + + Raises: + FileExistsError if the study already exists in the given location + """ + local_config = LocalConfiguration(parent_directory, study_name) + + study_directory = local_config.local_path / study_name + + _verify_study_already_exists(study_directory) + + # Create the directory structure + _create_directory_structure(study_directory) + + # Create study.antares file with timestamps and study_name + antares_file_path = os.path.join(study_directory, "study.antares") + current_time = int(time.time()) + antares_content = f"""[antares] +version = {version} +caption = {study_name} +created = {current_time} +lastsave = {current_time} +author = Unknown +""" + with open(antares_file_path, "w") as antares_file: + antares_file.write(antares_content) + + # Create Desktop.ini file + desktop_ini_path = study_directory / "Desktop.ini" + desktop_ini_content = f"""[.ShellClassInfo] +IconFile = settings/resources/study.ico +IconIndex = 0 +InfoTip = Antares Study {version}: {study_name} +""" + with open(desktop_ini_path, "w") as desktop_ini_file: + desktop_ini_file.write(desktop_ini_content) + + # Create various .ini files for the study + _create_correlation_ini_files(study_directory) + + logging.info(f"Study successfully created: {study_name}") + study = Study( + name=study_name, + version=version, + services=create_local_services(config=local_config, study_name=study_name), + path=study_directory, + ) + # We need to create the file with default value + default_settings = StudySettings() + update_settings = default_settings.to_update_settings() + edit_study_settings(study_directory, update_settings, True) + study._settings = default_settings + return study + + +def read_study_local(study_directory: Path) -> "Study": + """ + Read a study structure by returning a study object. + Args: + study_directory: antares study path to be read + + Raises: + FileNotFoundError: If the provided directory does not exist. + """ + + def _directory_not_exists(local_path: Path) -> None: + if not local_path.is_dir(): + raise FileNotFoundError(f"The path {local_path} doesn't exist or isn't a folder.") + + _directory_not_exists(study_directory) + + study_antares = IniFile(study_directory, InitializationFilesTypes.ANTARES) + + study_params = study_antares.ini_dict["antares"] + + local_config = LocalConfiguration(study_directory.parent, study_directory.name) + + study = Study( + name=study_params["caption"], + version=study_params["version"], + services=create_local_services(config=local_config, study_name=study_params["caption"]), + path=study_directory, + ) + study.read_settings() + return study diff --git a/src/antares/craft/service/local_services/services/output.py b/src/antares/craft/service/local_services/services/output.py index a2fb0f06..52db1707 100644 --- a/src/antares/craft/service/local_services/services/output.py +++ b/src/antares/craft/service/local_services/services/output.py @@ -9,7 +9,6 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. -from typing import Any import pandas as pd @@ -20,8 +19,7 @@ class OutputLocalService(BaseOutputService): - def __init__(self, config: LocalConfiguration, study_name: str, **kwargs: Any) -> None: - super().__init__(**kwargs) + def __init__(self, config: LocalConfiguration, study_name: str) -> None: self.config = config self.study_name = study_name diff --git a/src/antares/craft/service/local_services/study_local.py b/src/antares/craft/service/local_services/study_local.py index 3b0e8b49..a02f3f98 100644 --- a/src/antares/craft/service/local_services/study_local.py +++ b/src/antares/craft/service/local_services/study_local.py @@ -10,7 +10,7 @@ # # This file is part of the Antares project. from pathlib import Path, PurePath -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from antares.craft.config.local_configuration import LocalConfiguration from antares.craft.model.binding_constraint import BindingConstraint @@ -23,10 +23,7 @@ class StudyLocalService(BaseStudyService): - def __init__( - self, config: LocalConfiguration, study_name: str, output_service: BaseOutputService, **kwargs: Any - ) -> None: - super().__init__(**kwargs) + def __init__(self, config: LocalConfiguration, study_name: str, output_service: BaseOutputService) -> None: self._config = config self._study_name = study_name self._output_service: BaseOutputService = output_service diff --git a/src/antares/craft/service/service_factory.py b/src/antares/craft/service/service_factory.py deleted file mode 100644 index 4d201508..00000000 --- a/src/antares/craft/service/service_factory.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright (c) 2024, RTE (https://www.rte-france.com) -# -# See AUTHORS.txt -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# SPDX-License-Identifier: MPL-2.0 -# -# This file is part of the Antares project. - -from antares.craft.api_conf.api_conf import APIconf -from antares.craft.config.base_configuration import BaseConfiguration -from antares.craft.config.local_configuration import LocalConfiguration -from antares.craft.service.api_services.area_api import AreaApiService -from antares.craft.service.api_services.link_api import LinkApiService -from antares.craft.service.api_services.services.binding_constraint import BindingConstraintApiService -from antares.craft.service.api_services.services.hydro import HydroApiService -from antares.craft.service.api_services.services.output import OutputApiService -from antares.craft.service.api_services.services.renewable import RenewableApiService -from antares.craft.service.api_services.services.run import RunApiService -from antares.craft.service.api_services.services.settings import StudySettingsAPIService -from antares.craft.service.api_services.services.st_storage import ShortTermStorageApiService -from antares.craft.service.api_services.services.thermal import ThermalApiService -from antares.craft.service.api_services.study_api import StudyApiService -from antares.craft.service.base_services import ( - BaseAreaService, - BaseBindingConstraintService, - BaseHydroService, - BaseLinkService, - BaseOutputService, - BaseRenewableService, - BaseRunService, - BaseShortTermStorageService, - BaseStudyService, - BaseStudySettingsService, - BaseThermalService, -) -from antares.craft.service.local_services.area_local import AreaLocalService -from antares.craft.service.local_services.link_local import LinkLocalService -from antares.craft.service.local_services.services.binding_constraint import BindingConstraintLocalService -from antares.craft.service.local_services.services.hydro import HydroLocalService -from antares.craft.service.local_services.services.output import OutputLocalService -from antares.craft.service.local_services.services.renewable import RenewableLocalService -from antares.craft.service.local_services.services.run import RunLocalService -from antares.craft.service.local_services.services.settings import StudySettingsLocalService -from antares.craft.service.local_services.services.st_storage import ShortTermStorageLocalService -from antares.craft.service.local_services.services.thermal import ThermalLocalService -from antares.craft.service.local_services.study_local import StudyLocalService - -ERROR_MESSAGE = "Unsupported configuration type: " - - -class ServiceFactory: - def __init__(self, config: BaseConfiguration, study_id: str = "", study_name: str = ""): - self.config = config - self.study_id = study_id - self.study_name = study_name - - def create_area_service(self) -> BaseAreaService: - if isinstance(self.config, APIconf): - storage_service: BaseShortTermStorageService = ShortTermStorageApiService(self.config, self.study_id) - thermal_service: BaseThermalService = ThermalApiService(self.config, self.study_id) - renewable_service: BaseRenewableService = RenewableApiService(self.config, self.study_id) - hydro_service: BaseHydroService = HydroApiService(self.config, self.study_id) - area_service: BaseAreaService = AreaApiService( - self.config, self.study_id, storage_service, thermal_service, renewable_service, hydro_service - ) - elif isinstance(self.config, LocalConfiguration): - storage_service = ShortTermStorageLocalService(self.config, self.study_name) - thermal_service = ThermalLocalService(self.config, self.study_name) - renewable_service = RenewableLocalService(self.config, self.study_name) - hydro_service = HydroLocalService(self.config, self.study_name) - area_service = AreaLocalService( - self.config, self.study_name, storage_service, thermal_service, renewable_service, hydro_service - ) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return area_service - - def create_link_service(self) -> BaseLinkService: - if isinstance(self.config, APIconf): - link_service: BaseLinkService = LinkApiService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - link_service = LinkLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return link_service - - def create_thermal_service(self) -> BaseThermalService: - if isinstance(self.config, APIconf): - thermal_service: BaseThermalService = ThermalApiService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - thermal_service = ThermalLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return thermal_service - - def create_binding_constraints_service(self) -> BaseBindingConstraintService: - if isinstance(self.config, APIconf): - binding_constraint_service: BaseBindingConstraintService = BindingConstraintApiService( - self.config, self.study_id - ) - elif isinstance(self.config, LocalConfiguration): - binding_constraint_service = BindingConstraintLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return binding_constraint_service - - def create_study_service(self) -> BaseStudyService: - study_service: BaseStudyService - output_service = self.create_output_service() - if isinstance(self.config, APIconf): - study_service = StudyApiService(self.config, self.study_id, output_service) - elif isinstance(self.config, LocalConfiguration): - study_service = StudyLocalService(self.config, self.study_name, output_service) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - - return study_service - - def create_renewable_service(self) -> BaseRenewableService: - if isinstance(self.config, APIconf): - renewable_service: BaseRenewableService = RenewableApiService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - renewable_service = RenewableLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return renewable_service - - def create_st_storage_service(self) -> BaseShortTermStorageService: - if isinstance(self.config, APIconf): - short_term_storage_service: BaseShortTermStorageService = ShortTermStorageApiService( - self.config, self.study_id - ) - elif isinstance(self.config, LocalConfiguration): - short_term_storage_service = ShortTermStorageLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return short_term_storage_service - - def create_run_service(self) -> BaseRunService: - if isinstance(self.config, APIconf): - run_service: BaseRunService = RunApiService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - run_service = RunLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return run_service - - def create_output_service(self) -> BaseOutputService: - if isinstance(self.config, APIconf): - output_service: BaseOutputService = OutputApiService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - output_service = OutputLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return output_service - - def create_settings_service(self) -> BaseStudySettingsService: - if isinstance(self.config, APIconf): - settings_service: BaseStudySettingsService = StudySettingsAPIService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - settings_service = StudySettingsLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return settings_service - - def create_hydro_service(self) -> BaseHydroService: - if isinstance(self.config, APIconf): - hydro_service: BaseHydroService = HydroApiService(self.config, self.study_id) - elif isinstance(self.config, LocalConfiguration): - hydro_service = HydroLocalService(self.config, self.study_name) - else: - raise TypeError(f"{ERROR_MESSAGE}{repr(self.config)}") - return hydro_service diff --git a/tests/antares/integration/conftest.py b/tests/antares/integration/conftest.py index cbaf13f6..c14f8ec7 100644 --- a/tests/antares/integration/conftest.py +++ b/tests/antares/integration/conftest.py @@ -12,8 +12,8 @@ import pytest +from antares.craft import Study, create_study_local from antares.craft.model.area import Area -from antares.craft.model.study import Study, create_study_local @pytest.fixture diff --git a/tests/antares/integration/test_local_client.py b/tests/antares/integration/test_local_client.py index e0a85316..cf351c90 100644 --- a/tests/antares/integration/test_local_client.py +++ b/tests/antares/integration/test_local_client.py @@ -16,6 +16,7 @@ import numpy as np import pandas as pd +from antares.craft import create_study_local from antares.craft.exceptions.exceptions import AreaCreationError, LinkCreationError from antares.craft.model.area import AdequacyPatchMode, Area, AreaProperties, AreaUi from antares.craft.model.binding_constraint import ( @@ -35,7 +36,7 @@ from antares.craft.model.settings.general import GeneralParametersUpdate from antares.craft.model.settings.study_settings import StudySettingsUpdate from antares.craft.model.st_storage import STStorageGroup, STStorageProperties -from antares.craft.model.study import Study, create_study_local +from antares.craft.model.study import Study from antares.craft.model.thermal import ThermalCluster, ThermalClusterGroup, ThermalClusterProperties from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes diff --git a/tests/antares/services/api_services/test_area_api.py b/tests/antares/services/api_services/test_area_api.py index 127189f3..983871c6 100644 --- a/tests/antares/services/api_services/test_area_api.py +++ b/tests/antares/services/api_services/test_area_api.py @@ -31,21 +31,22 @@ from antares.craft.model.study import Study from antares.craft.model.thermal import ThermalCluster, ThermalClusterProperties from antares.craft.service.api_services.area_api import AreaApiService +from antares.craft.service.api_services.factory import create_api_services from antares.craft.service.api_services.models.hydro import HydroPropertiesAPI from antares.craft.service.api_services.models.renewable import RenewableClusterPropertiesAPI from antares.craft.service.api_services.models.st_storage import STStoragePropertiesAPI from antares.craft.service.api_services.models.thermal import ThermalClusterPropertiesAPI -from antares.craft.service.service_factory import ServiceFactory class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" - area_service = ServiceFactory(api, study_id).create_area_service() - st_storage_service = ServiceFactory(api, study_id).create_st_storage_service() - thermal_service = ServiceFactory(api, study_id).create_thermal_service() - renewable_service = ServiceFactory(api, study_id).create_renewable_service() - hydro_service = ServiceFactory(api, study_id).create_hydro_service() + services = create_api_services(api, study_id) + area_service = services.area_service + st_storage_service = services.short_term_storage_service + thermal_service = services.thermal_service + renewable_service = services.renewable_service + hydro_service = services.hydro_service area = Area("area_test", area_service, st_storage_service, thermal_service, renewable_service, hydro_service) area_api = AreaApiService( @@ -58,7 +59,7 @@ class TestCreateAPI: ) antares_web_description_msg = "Mocked Server KO" matrix = pd.DataFrame(data=[[1]]) - study = Study("TestStudy", "880", ServiceFactory(api, study_id)) + study = Study("TestStudy", "880", services) def test_update_area_properties_success(self): with requests_mock.Mocker() as mocker: diff --git a/tests/antares/services/api_services/test_binding_constraint_api.py b/tests/antares/services/api_services/test_binding_constraint_api.py index 76967973..a0cd19ad 100644 --- a/tests/antares/services/api_services/test_binding_constraint_api.py +++ b/tests/antares/services/api_services/test_binding_constraint_api.py @@ -32,8 +32,8 @@ LinkData, ) from antares.craft.model.study import Study +from antares.craft.service.api_services.factory import create_api_services from antares.craft.service.api_services.models.binding_constraint import BindingConstraintPropertiesAPI -from antares.craft.service.service_factory import ServiceFactory @pytest.fixture @@ -49,14 +49,15 @@ def constraint_set(): class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" - study = Study("study_test", "870", ServiceFactory(api, study_id)) + services = create_api_services(api, study_id) + study = Study("study_test", "870", services) area = Area( "study_test", - ServiceFactory(api, study_id).create_area_service(), - ServiceFactory(api, study_id).create_st_storage_service(), - ServiceFactory(api, study_id).create_thermal_service(), - ServiceFactory(api, study_id).create_renewable_service(), - ServiceFactory(api, study_id).create_hydro_service(), + services.area_service, + services.short_term_storage_service, + services.thermal_service, + services.renewable_service, + services.hydro_service, ) antares_web_description_msg = "Mocked Server KO" matrix = pd.DataFrame(data=[[0]]) @@ -66,9 +67,7 @@ def test_update_binding_constraint_properties_success(self): update_properties = BindingConstraintPropertiesUpdate(enabled=False) creation_properties = BindingConstraintProperties(enabled=False) api_properties = BindingConstraintPropertiesAPI.from_user_model(creation_properties) - constraint = BindingConstraint( - "bc_1", ServiceFactory(self.api, self.study_id).create_binding_constraints_service() - ) + constraint = BindingConstraint("bc_1", self.services.bc_service) url = f"https://antares.com/api/v1/studies/{self.study_id}/bindingconstraints/{constraint.id}" mocker.put( url, @@ -81,9 +80,7 @@ def test_update_binding_constraint_properties_success(self): def test_update_binding_constraint_properties_fails(self): with requests_mock.Mocker() as mocker: update_properties = BindingConstraintPropertiesUpdate(enabled=False) - constraint = BindingConstraint( - "bc_1", ServiceFactory(self.api, self.study_id).create_binding_constraints_service() - ) + constraint = BindingConstraint("bc_1", self.services.bc_service) url = f"https://antares.com/api/v1/studies/{self.study_id}/bindingconstraints/{constraint.id}" antares_web_description_msg = "Server KO" mocker.put(url, json={"description": antares_web_description_msg}, status_code=404) @@ -97,8 +94,7 @@ def test_update_binding_constraint_properties_fails(self): def test_update_binding_constraint_term_success(self): with requests_mock.Mocker() as mocker: existing_term = ConstraintTerm(data=LinkData(area1="fr", area2="be"), weight=4, offset=3) - service = ServiceFactory(self.api, self.study_id).create_binding_constraints_service() - constraint = BindingConstraint("bc_1", service, None, [existing_term]) + constraint = BindingConstraint("bc_1", self.services.bc_service, None, [existing_term]) url = f"https://antares.com/api/v1/studies/{self.study_id}/bindingconstraints/{constraint.id}/term" mocker.put(url, status_code=200) @@ -111,8 +107,7 @@ def test_update_binding_constraint_term_success(self): def test_update_binding_constraint_term_fails(self): with requests_mock.Mocker() as mocker: existing_term = ConstraintTerm(data=LinkData(area1="fr", area2="be"), weight=4, offset=3) - service = ServiceFactory(self.api, self.study_id).create_binding_constraints_service() - constraint = BindingConstraint("bc_1", service, None, [existing_term]) + constraint = BindingConstraint("bc_1", self.services.bc_service, None, [existing_term]) url = f"https://antares.com/api/v1/studies/{self.study_id}/bindingconstraints/{constraint.id}/term" mocker.put(url, json={"description": self.antares_web_description_msg}, status_code=422) @@ -125,9 +120,7 @@ def test_update_binding_constraint_term_fails(self): constraint.update_term(new_term) def test_get_constraint_matrix_success(self, constraint_set): - constraint = BindingConstraint( - "bc_test", ServiceFactory(self.api, self.study_id).create_binding_constraints_service() - ) + constraint = BindingConstraint("bc_test", self.services.bc_service) for matrix_method, enum_value, path, expected_matrix in constraint_set: with requests_mock.Mocker() as mocker: url = f"https://antares.com/api/v1/studies/{self.study_id}/raw?path={path}" @@ -136,9 +129,7 @@ def test_get_constraint_matrix_success(self, constraint_set): assert constraint_matrix.equals(self.matrix) def test_get_constraint_matrix_fails(self, constraint_set): - constraint = BindingConstraint( - "bc_test", ServiceFactory(self.api, self.study_id).create_binding_constraints_service() - ) + constraint = BindingConstraint("bc_test", self.services.bc_service) for matrix_method, enum_value, path, _ in constraint_set: with requests_mock.Mocker() as mocker: url = f"https://antares.com/api/v1/studies/{self.study_id}/raw?path={path}" diff --git a/tests/antares/services/api_services/test_link_api.py b/tests/antares/services/api_services/test_link_api.py index b8bfd7cc..f6a98e10 100644 --- a/tests/antares/services/api_services/test_link_api.py +++ b/tests/antares/services/api_services/test_link_api.py @@ -27,7 +27,7 @@ from antares.craft.model.commons import FilterOption from antares.craft.model.link import Link, LinkProperties, LinkUi from antares.craft.model.study import Study -from antares.craft.service.service_factory import ServiceFactory +from antares.craft.service.api_services.factory import create_api_services @pytest.fixture() @@ -36,7 +36,8 @@ def expected_link(): area_to_name = "zone4auto" api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" - link_service = ServiceFactory(api, study_id).create_link_service() + services = create_api_services(api, study_id) + link_service = services.link_service properties = { "hurdles-cost": False, "loop-flow": False, @@ -65,7 +66,8 @@ def expected_link(): class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" - study = Study("study_test", "870", ServiceFactory(api, study_id)) + services = create_api_services(api, study_id) + study = Study("study_test", "870", services) area_from = Area( name="area_from", area_service=api, @@ -83,7 +85,7 @@ class TestCreateAPI: hydro_service=api, ) antares_web_description_msg = "Mocked Server KO" - link = Link(area_from.id, area_to.id, ServiceFactory(api, study_id).create_link_service()) + link = Link(area_from.id, area_to.id, services.link_service) matrix = pd.DataFrame(data=[[0]]) def test_update_links_properties_success(self): diff --git a/tests/antares/services/api_services/test_matrix_api.py b/tests/antares/services/api_services/test_matrix_api.py index 8e8b99c2..f71c5fb3 100644 --- a/tests/antares/services/api_services/test_matrix_api.py +++ b/tests/antares/services/api_services/test_matrix_api.py @@ -20,24 +20,25 @@ from antares.craft.exceptions.exceptions import MatrixDownloadError, MatrixUploadError from antares.craft.model.area import Area from antares.craft.model.hydro import Hydro, HydroProperties -from antares.craft.service.service_factory import ServiceFactory +from antares.craft.service.api_services.factory import create_api_services class TestMatrixAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" + services = create_api_services(api, study_id) area = Area( "area_test", - ServiceFactory(api, study_id).create_area_service(), - ServiceFactory(api, study_id).create_st_storage_service(), - ServiceFactory(api, study_id).create_thermal_service(), - ServiceFactory(api, study_id).create_renewable_service(), - ServiceFactory(api, study_id).create_hydro_service(), + services.area_service, + services.short_term_storage_service, + services.thermal_service, + services.renewable_service, + services.hydro_service, ) antares_web_description_msg = "Mocked Server KO" matrix = pd.DataFrame(data=[[0]]) - hydro = Hydro(ServiceFactory(api, study_id).create_hydro_service(), "area_test", properties=HydroProperties()) + hydro = Hydro(services.hydro_service, "area_test", properties=HydroProperties()) # ======================= # LOAD diff --git a/tests/antares/services/api_services/test_renewable_api.py b/tests/antares/services/api_services/test_renewable_api.py index 8105950e..db781ed1 100644 --- a/tests/antares/services/api_services/test_renewable_api.py +++ b/tests/antares/services/api_services/test_renewable_api.py @@ -25,23 +25,24 @@ from antares.craft.model.area import Area from antares.craft.model.renewable import RenewableCluster, RenewableClusterProperties, RenewableClusterPropertiesUpdate from antares.craft.service.api_services.area_api import AreaApiService +from antares.craft.service.api_services.factory import create_api_services from antares.craft.service.api_services.models.renewable import RenewableClusterPropertiesAPI from antares.craft.service.api_services.services.renewable import RenewableApiService -from antares.craft.service.service_factory import ServiceFactory class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" + services = create_api_services(api, study_id) area = Area( "study_test", - ServiceFactory(api, study_id).create_area_service(), - ServiceFactory(api, study_id).create_st_storage_service(), - ServiceFactory(api, study_id).create_thermal_service(), - ServiceFactory(api, study_id).create_renewable_service(), - ServiceFactory(api, study_id).create_hydro_service(), + services.area_service, + services.short_term_storage_service, + services.thermal_service, + services.renewable_service, + services.hydro_service, ) - renewable = RenewableCluster(ServiceFactory(api, study_id).create_renewable_service(), area.id, "onshore_fr") + renewable = RenewableCluster(services.renewable_service, area.id, "onshore_fr") antares_web_description_msg = "Mocked Server KO" matrix = pd.DataFrame(data=[[0]]) diff --git a/tests/antares/services/api_services/test_st_storage_api.py b/tests/antares/services/api_services/test_st_storage_api.py index ba6bce8f..f7bf2ff6 100644 --- a/tests/antares/services/api_services/test_st_storage_api.py +++ b/tests/antares/services/api_services/test_st_storage_api.py @@ -25,23 +25,24 @@ from antares.craft.model.area import Area from antares.craft.model.st_storage import STStorage, STStorageProperties from antares.craft.service.api_services.area_api import AreaApiService +from antares.craft.service.api_services.factory import create_api_services from antares.craft.service.api_services.models.st_storage import STStoragePropertiesAPI from antares.craft.service.api_services.services.st_storage import ShortTermStorageApiService -from antares.craft.service.service_factory import ServiceFactory class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" + services = create_api_services(api, study_id) area = Area( "study_test", - ServiceFactory(api, study_id).create_area_service(), - ServiceFactory(api, study_id).create_st_storage_service(), - ServiceFactory(api, study_id).create_thermal_service(), - ServiceFactory(api, study_id).create_renewable_service(), - ServiceFactory(api, study_id).create_hydro_service(), + services.area_service, + services.short_term_storage_service, + services.thermal_service, + services.renewable_service, + services.hydro_service, ) - storage = STStorage(ServiceFactory(api, study_id).create_st_storage_service(), area.id, "battery_fr") + storage = STStorage(services.short_term_storage_service, area.id, "battery_fr") antares_web_description_msg = "Mocked Server KO" matrix = pd.DataFrame(data=[[0]]) diff --git a/tests/antares/services/api_services/test_study_api.py b/tests/antares/services/api_services/test_study_api.py index dbae4938..d3cf770d 100644 --- a/tests/antares/services/api_services/test_study_api.py +++ b/tests/antares/services/api_services/test_study_api.py @@ -21,6 +21,7 @@ import pandas as pd +from antares.craft import create_study_api, create_variant_api, import_study_api, read_study_api from antares.craft.api_conf.api_conf import APIconf from antares.craft.exceptions.exceptions import ( AreaCreationError, @@ -51,25 +52,26 @@ from antares.craft.model.settings.general import GeneralParametersUpdate, Mode from antares.craft.model.settings.study_settings import StudySettingsUpdate from antares.craft.model.simulation import AntaresSimulationParameters, Job, JobStatus, Solver -from antares.craft.model.study import Study, create_study_api, create_variant_api, import_study_api, read_study_api +from antares.craft.model.study import Study +from antares.craft.service.api_services.factory import create_api_services from antares.craft.service.api_services.models.binding_constraint import BindingConstraintPropertiesAPI from antares.craft.service.api_services.models.hydro import HydroPropertiesAPI from antares.craft.service.api_services.services.output import OutputApiService -from antares.craft.service.service_factory import ServiceFactory class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" antares_web_description_msg = "Mocked Server KO" - study = Study("TestStudy", "880", ServiceFactory(api, study_id)) + services = create_api_services(api, study_id) + study = Study("TestStudy", "880", services) area = Area( "area_test", - ServiceFactory(api, study_id).create_area_service(), - ServiceFactory(api, study_id).create_st_storage_service(), - ServiceFactory(api, study_id).create_thermal_service(), - ServiceFactory(api, study_id).create_renewable_service(), - ServiceFactory(api, study_id).create_hydro_service(), + services.area_service, + services.short_term_storage_service, + services.thermal_service, + services.renewable_service, + services.hydro_service, ) def test_create_study_test_ok(self) -> None: @@ -270,13 +272,12 @@ def test_read_study_api(self): actual_study = read_study_api(self.api, self.study_id) expected_study_name = json_study.pop("name") - expected_study_id = json_study.pop("id") expected_study_version = json_study.pop("version") expected_study = Study( expected_study_name, expected_study_version, - ServiceFactory(self.api, expected_study_id, expected_study_name), + self.services, None, ) diff --git a/tests/antares/services/api_services/test_thermal_api.py b/tests/antares/services/api_services/test_thermal_api.py index f46bb223..aa9bca2d 100644 --- a/tests/antares/services/api_services/test_thermal_api.py +++ b/tests/antares/services/api_services/test_thermal_api.py @@ -31,9 +31,9 @@ ThermalClusterPropertiesUpdate, ) from antares.craft.service.api_services.area_api import AreaApiService +from antares.craft.service.api_services.factory import create_api_services from antares.craft.service.api_services.models.thermal import ThermalClusterPropertiesAPI from antares.craft.service.api_services.services.thermal import ThermalApiService -from antares.craft.service.service_factory import ServiceFactory @pytest.fixture @@ -51,16 +51,17 @@ def thermal_matrix_set(): class TestCreateAPI: api = APIconf("https://antares.com", "token", verify=False) study_id = "22c52f44-4c2a-407b-862b-490887f93dd8" - study = Study("study_test", "870", ServiceFactory(api, study_id)) + services = create_api_services(api, study_id) + study = Study("study_test", "870", services) area = Area( "area-test", - ServiceFactory(api, study_id).create_area_service(), - ServiceFactory(api, study_id).create_st_storage_service(), - ServiceFactory(api, study_id).create_thermal_service(), - ServiceFactory(api, study_id).create_renewable_service(), - ServiceFactory(api, study_id).create_hydro_service(), + services.area_service, + services.short_term_storage_service, + services.thermal_service, + services.renewable_service, + services.hydro_service, ) - thermal = ThermalCluster(ServiceFactory(api, study_id).create_thermal_service(), "area-test", "thermal-test") + thermal = ThermalCluster(services.thermal_service, "area-test", "thermal-test") antares_web_description_msg = "Mocked Server KO" matrix = pd.DataFrame(data=[[0]]) diff --git a/tests/antares/services/local_services/conftest.py b/tests/antares/services/local_services/conftest.py index edf31d86..0a7962c7 100644 --- a/tests/antares/services/local_services/conftest.py +++ b/tests/antares/services/local_services/conftest.py @@ -13,6 +13,7 @@ import pandas as pd +from antares.craft import create_study_local from antares.craft.model.area import Area, AreaPropertiesLocal from antares.craft.model.binding_constraint import ( BindingConstraint, @@ -23,7 +24,7 @@ from antares.craft.model.hydro import HydroProperties, HydroPropertiesUpdate from antares.craft.model.renewable import RenewableClusterGroup, RenewableClusterProperties, TimeSeriesInterpretation from antares.craft.model.st_storage import STStorageGroup, STStorageProperties -from antares.craft.model.study import Study, create_study_local +from antares.craft.model.study import Study from antares.craft.model.thermal import ( LawOption, LocalTSGenerationBehavior, diff --git a/tests/antares/services/local_services/test_area.py b/tests/antares/services/local_services/test_area.py index 723dcbcb..ddbea24f 100644 --- a/tests/antares/services/local_services/test_area.py +++ b/tests/antares/services/local_services/test_area.py @@ -22,6 +22,7 @@ import numpy as np import pandas as pd +from antares.craft import read_study_local from antares.craft.config.local_configuration import LocalConfiguration from antares.craft.model.renewable import ( RenewableCluster, @@ -30,7 +31,6 @@ TimeSeriesInterpretation, ) from antares.craft.model.st_storage import STStorage, STStorageGroup, STStorageProperties -from antares.craft.model.study import read_study_local from antares.craft.model.thermal import ThermalCluster from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes from antares.craft.tools.matrix_tool import df_save diff --git a/tests/antares/services/local_services/test_study.py b/tests/antares/services/local_services/test_study.py index 4be5b471..9e286b71 100644 --- a/tests/antares/services/local_services/test_study.py +++ b/tests/antares/services/local_services/test_study.py @@ -22,6 +22,7 @@ import numpy as np import pandas as pd +from antares.craft import create_study_local from antares.craft.config.local_configuration import LocalConfiguration from antares.craft.exceptions.exceptions import ( AreaCreationError, @@ -82,7 +83,6 @@ ) from antares.craft.model.settings.study_settings import StudySettings from antares.craft.model.settings.thematic_trimming import ThematicTrimmingParameters -from antares.craft.model.study import create_study_local from antares.craft.tools.ini_tool import InitializationFilesTypes diff --git a/tests/antares/services/local_services/test_study_read.py b/tests/antares/services/local_services/test_study_read.py index bbabf1fd..0c826a1d 100644 --- a/tests/antares/services/local_services/test_study_read.py +++ b/tests/antares/services/local_services/test_study_read.py @@ -16,7 +16,7 @@ from pathlib import Path -from antares.craft.model.study import read_study_local +from antares.craft import read_study_local class TestReadStudy: diff --git a/tests/integration/test_web_client.py b/tests/integration/test_web_client.py index 1f11f098..52d560de 100644 --- a/tests/integration/test_web_client.py +++ b/tests/integration/test_web_client.py @@ -18,6 +18,7 @@ import numpy as np import pandas as pd +from antares.craft import create_study_api, create_variant_api, import_study_api, read_study_api from antares.craft.api_conf.api_conf import APIconf from antares.craft.exceptions.exceptions import ( AreaDeletionError, @@ -61,7 +62,6 @@ STStorageProperties, STStoragePropertiesUpdate, ) -from antares.craft.model.study import create_study_api, create_variant_api, import_study_api, read_study_api from antares.craft.model.thermal import ThermalClusterGroup, ThermalClusterProperties, ThermalClusterPropertiesUpdate from tests.integration.antares_web_desktop import AntaresWebDesktop