Skip to content

Commit

Permalink
refactor(settings): create settings service (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinBelthle authored Feb 7, 2025
1 parent a15b685 commit 7f10ab2
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 87 deletions.
48 changes: 25 additions & 23 deletions src/antares/craft/model/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from pathlib import Path, PurePath
from types import MappingProxyType
from typing import List, Optional, Union
from typing import List, Optional

import pandas as pd

Expand All @@ -40,9 +40,8 @@
from antares.craft.model.output import Output
from antares.craft.model.settings.study_settings import StudySettings
from antares.craft.model.simulation import AntaresSimulationParameters, Job
from antares.craft.service.api_services.services.settings import read_study_settings_api
from antares.craft.service.base_services import BaseStudyService
from antares.craft.service.local_services.services.settings import edit_study_settings, read_study_settings_local
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

Expand Down Expand Up @@ -83,10 +82,11 @@ def create_study_api(
response = wrapper.post(url)
study_id = response.json()
# Settings part
study_settings = None if settings else read_study_settings_api(base_url, study_id, wrapper)
study = Study(study_name, version, ServiceFactory(api_config, study_id), study_settings)
study = Study(study_name, version, ServiceFactory(api_config, study_id))
if settings:
study.update_settings(settings)
else:
study.read_settings()
# Move part
if parent_path:
study.move(parent_path)
Expand Down Expand Up @@ -177,14 +177,15 @@ def create_study_local(
_create_correlation_ini_files(study_directory)

logging.info(f"Study successfully created: {study_name}")
new_settings = edit_study_settings(study_directory, settings, update=False)
return Study(
study = Study(
name=study_name,
version=version,
service_factory=ServiceFactory(config=local_config, study_name=study_name),
settings=new_settings,
path=study_directory,
)
# We need to create the file with default value
study._settings = edit_study_settings(study_directory, settings, False)
return study


def read_study_local(study_directory: Path) -> "Study":
Expand All @@ -210,15 +211,14 @@ def _directory_not_exists(local_path: Path) -> None:

local_config = LocalConfiguration(study_directory.parent, study_directory.name)

settings = read_study_settings_local(study_directory)

return Study(
study = Study(
name=study_params["caption"],
version=study_params["version"],
service_factory=ServiceFactory(config=local_config, study_name=study_params["caption"]),
path=study_directory,
settings=settings,
)
study.read_settings()
return study


def read_study_api(api_config: APIconf, study_id: str) -> "Study":
Expand All @@ -232,11 +232,9 @@ def read_study_api(api_config: APIconf, study_id: str) -> "Study":
path = json_study.pop("folder")
pure_path = PurePath(path) if path else PurePath(".")

study_settings = read_study_settings_api(base_url, study_id, wrapper)
study = Study(
study_name, study_version, ServiceFactory(api_config, study_id, study_name), study_settings, pure_path
)
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()
Expand Down Expand Up @@ -265,7 +263,6 @@ def __init__(
name: str,
version: str,
service_factory: ServiceFactory,
settings: Union[StudySettings, None] = None,
path: PurePath = PurePath("."),
):
self.name = name
Expand All @@ -276,7 +273,8 @@ def __init__(
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 = settings or StudySettings()
self._settings_service = service_factory.create_settings_service()
self._settings = StudySettings()
self._areas: dict[str, Area] = dict()
self._links: dict[str, Link] = dict()
self._binding_constraints: dict[str, BindingConstraint] = dict()
Expand All @@ -298,7 +296,15 @@ def read_areas(self) -> list[Area]:
def read_links(self) -> list[Link]:
link_list = self._link_service.read_links()
self._links = {link.id: link for link in link_list}
return self._link_service.read_links()
return link_list

def read_settings(self) -> StudySettings:
study_settings = self._settings_service.read_study_settings()
self._settings = study_settings
return study_settings

def update_settings(self, settings: StudySettings) -> None:
self._settings = self._settings_service.edit_study_settings(settings)

def get_areas(self) -> MappingProxyType[str, Area]:
return MappingProxyType(dict(sorted(self._areas.items())))
Expand Down Expand Up @@ -389,10 +395,6 @@ def read_binding_constraints(self) -> list[BindingConstraint]:
self._binding_constraints = {constraint.id: constraint for constraint in constraints}
return constraints

def update_settings(self, settings: StudySettings) -> None:
self._study_service.update_study_settings(settings)
self._settings = settings

def delete_binding_constraint(self, constraint: BindingConstraint) -> None:
self._study_service.delete_binding_constraint(constraint)
self._binding_constraints.pop(constraint.id)
Expand Down
103 changes: 62 additions & 41 deletions src/antares/craft/service/api_services/services/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
# This file is part of the Antares project.
from dataclasses import asdict

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, StudySettingsReadError
from antares.craft.exceptions.exceptions import APIError, StudySettingsReadError, StudySettingsUpdateError
from antares.craft.model.settings.playlist_parameters import PlaylistParameters
from antares.craft.model.settings.study_settings import StudySettings
from antares.craft.service.api_services.models.settings import (
Expand All @@ -22,6 +23,29 @@
OptimizationParametersAPI,
ThematicTrimmingParametersAPI,
)
from antares.craft.service.base_services import BaseStudySettingsService


class StudySettingsAPIService(BaseStudySettingsService):
def __init__(self, config: APIconf, study_id: str):
super().__init__()
self.config = config
self.study_id = study_id
self._base_url = f"{self.config.get_host()}/api/v1"
self._wrapper = RequestWrapper(self.config.set_up_api_conf())

def edit_study_settings(self, settings: StudySettings) -> StudySettings:
try:
edit_study_settings(self._base_url, self.study_id, self._wrapper, settings)
return settings
except APIError as e:
raise StudySettingsUpdateError(self.study_id, e.message) from e

def read_study_settings(self) -> StudySettings:
try:
return read_study_settings_api(self._base_url, self.study_id, self._wrapper)
except APIError as e:
raise StudySettingsReadError(self.study_id, e.message) from e


def edit_study_settings(base_url: str, study_id: str, wrapper: RequestWrapper, settings: StudySettings) -> None:
Expand Down Expand Up @@ -79,51 +103,48 @@ def edit_study_settings(base_url: str, study_id: str, wrapper: RequestWrapper, s

def read_study_settings_api(base_url: str, study_id: str, wrapper: RequestWrapper) -> StudySettings:
settings_base_url = f"{base_url}/studies/{study_id}/config"
try:
# thematic trimming
thematic_trimming_url = f"{settings_base_url}/thematictrimming/form"
response = wrapper.get(thematic_trimming_url)
thematic_trimming_api_model = ThematicTrimmingParametersAPI.model_validate(response.json())
thematic_trimming_parameters = thematic_trimming_api_model.to_user_model()

# playlist
playlist_url = f"{settings_base_url}/playlist/form"
response = wrapper.get(playlist_url)
json_response = response.json()
user_playlist = {}
for key, value in json_response.items():
user_playlist[int(key)] = PlaylistParameters(**value)
# thematic trimming
thematic_trimming_url = f"{settings_base_url}/thematictrimming/form"
response = wrapper.get(thematic_trimming_url)
thematic_trimming_api_model = ThematicTrimmingParametersAPI.model_validate(response.json())
thematic_trimming_parameters = thematic_trimming_api_model.to_user_model()

# optimization
optimization_url = f"{settings_base_url}/optimization/form"
response = wrapper.get(optimization_url)
optimization_api_model = OptimizationParametersAPI.model_validate(response.json())
optimization_parameters = optimization_api_model.to_user_model()
# playlist
playlist_url = f"{settings_base_url}/playlist/form"
response = wrapper.get(playlist_url)
json_response = response.json()
user_playlist = {}
for key, value in json_response.items():
user_playlist[int(key)] = PlaylistParameters(**value)

# general and timeseries
general_url = f"{settings_base_url}/general/form"
response = wrapper.get(general_url)
general_api_model = GeneralParametersAPI.model_validate(response.json())
timeseries_url = f"{base_url}/studies/{study_id}/timeseries/config"
response = wrapper.get(timeseries_url)
nb_ts_thermal = response.json()["thermal"]["number"]
general_parameters = general_api_model.to_user_model(nb_ts_thermal)

# advanced and seed parameters
advanced_parameters_url = f"{settings_base_url}/advancedparameters/form"
response = wrapper.get(advanced_parameters_url)
advanced_parameters_api_model = AdvancedAndSeedParametersAPI.model_validate(response.json())
seed_parameters = advanced_parameters_api_model.to_user_seed_parameters_model()
advanced_parameters = advanced_parameters_api_model.to_user_advanced_parameters_model()
# optimization
optimization_url = f"{settings_base_url}/optimization/form"
response = wrapper.get(optimization_url)
optimization_api_model = OptimizationParametersAPI.model_validate(response.json())
optimization_parameters = optimization_api_model.to_user_model()

# adequacy patch
adequacy_patch_url = f"{settings_base_url}/adequacypatch/form"
response = wrapper.get(adequacy_patch_url)
adequacy_patch_api_model = AdequacyPatchParametersAPI.model_validate(response.json())
adequacy_patch_parameters = adequacy_patch_api_model.to_user_model()
# general and timeseries
general_url = f"{settings_base_url}/general/form"
response = wrapper.get(general_url)
general_api_model = GeneralParametersAPI.model_validate(response.json())
timeseries_url = f"{base_url}/studies/{study_id}/timeseries/config"
response = wrapper.get(timeseries_url)
nb_ts_thermal = response.json()["thermal"]["number"]
general_parameters = general_api_model.to_user_model(nb_ts_thermal)

# advanced and seed parameters
advanced_parameters_url = f"{settings_base_url}/advancedparameters/form"
response = wrapper.get(advanced_parameters_url)
advanced_parameters_api_model = AdvancedAndSeedParametersAPI.model_validate(response.json())
seed_parameters = advanced_parameters_api_model.to_user_seed_parameters_model()
advanced_parameters = advanced_parameters_api_model.to_user_advanced_parameters_model()

except APIError as e:
raise StudySettingsReadError(study_id, e.message) from e
# adequacy patch
adequacy_patch_url = f"{settings_base_url}/adequacypatch/form"
response = wrapper.get(adequacy_patch_url)
adequacy_patch_api_model = AdequacyPatchParametersAPI.model_validate(response.json())
adequacy_patch_parameters = adequacy_patch_api_model.to_user_model()

return StudySettings(
general_parameters=general_parameters,
Expand Down
9 changes: 0 additions & 9 deletions src/antares/craft/service/api_services/study_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,13 @@
OutputsRetrievalError,
StudyDeletionError,
StudyMoveError,
StudySettingsUpdateError,
StudyVariantCreationError,
TaskFailedError,
TaskTimeOutError,
ThermalTimeseriesGenerationError,
)
from antares.craft.model.binding_constraint import BindingConstraint
from antares.craft.model.output import Output
from antares.craft.model.settings.study_settings import StudySettings
from antares.craft.service.api_services.services.settings import edit_study_settings
from antares.craft.service.api_services.utils import wait_task_completion
from antares.craft.service.base_services import BaseOutputService, BaseStudyService

Expand Down Expand Up @@ -64,12 +61,6 @@ def output_service(self) -> Optional[BaseOutputService]:
def set_output_service(self, output_service: BaseOutputService) -> None:
self._output_service = output_service

def update_study_settings(self, settings: StudySettings) -> None:
try:
edit_study_settings(self._base_url, self.study_id, self._wrapper, settings)
except APIError as e:
raise StudySettingsUpdateError(self.study_id, e.message) from e

def delete_binding_constraint(self, constraint: BindingConstraint) -> None:
url = f"{self._base_url}/studies/{self.study_id}/bindingconstraints/{constraint.id}"
try:
Expand Down
29 changes: 21 additions & 8 deletions src/antares/craft/service/base_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,14 +563,6 @@ def config(self) -> BaseConfiguration:
"""The configuration of the study."""
pass

@abstractmethod
def update_study_settings(self, settings: StudySettings) -> None:
"""
Args:
settings: new study settings. Only registered fields will be updated.
"""
pass

@abstractmethod
def delete_binding_constraint(self, constraint: BindingConstraint) -> None:
"""
Expand Down Expand Up @@ -752,3 +744,24 @@ def aggregate_values(
Returns: Pandas DataFrame corresponding to the aggregated raw data
"""
pass


class BaseStudySettingsService(ABC):
@abstractmethod
def edit_study_settings(self, settings: StudySettings) -> StudySettings:
"""
Edit the settings for a given study
Args:
settings: the new Settings for the study
Returns: the new Settings for the study
"""
pass

@abstractmethod
def read_study_settings(self) -> StudySettings:
"""
Reads the settings of a study
"""
pass
18 changes: 17 additions & 1 deletion src/antares/craft/service/local_services/services/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
# This file is part of the Antares project.

from pathlib import Path
from typing import Any

from antares.craft.config.local_configuration import LocalConfiguration
from antares.craft.model.settings.adequacy_patch import AdequacyPatchParameters
from antares.craft.model.settings.advanced_parameters import (
AdvancedParameters,
Expand All @@ -22,6 +24,7 @@
OptimizationParameters,
)
from antares.craft.model.settings.study_settings import StudySettings
from antares.craft.service.base_services import BaseStudySettingsService
from antares.craft.service.local_services.models.settings import (
AdequacyPatchParametersLocal,
AdvancedAndSeedParametersLocal,
Expand All @@ -34,7 +37,20 @@
from antares.craft.tools.ini_tool import IniFile, InitializationFilesTypes


def read_study_settings_local(study_directory: Path) -> StudySettings:
class StudySettingsLocalService(BaseStudySettingsService):
def __init__(self, config: LocalConfiguration, study_name: str, **kwargs: Any) -> None:
super().__init__(**kwargs)
self.config = config
self.study_name = study_name

def edit_study_settings(self, settings: StudySettings) -> StudySettings:
return edit_study_settings(self.config.study_path, settings, update=True)

def read_study_settings(self) -> StudySettings:
return read_study_settings(self.config.study_path)


def read_study_settings(study_directory: Path) -> StudySettings:
general_data_ini = IniFile(study_directory, InitializationFilesTypes.GENERAL)
ini_content = general_data_ini.ini_dict

Expand Down
5 changes: 0 additions & 5 deletions src/antares/craft/service/local_services/study_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
from antares.craft.config.local_configuration import LocalConfiguration
from antares.craft.model.binding_constraint import BindingConstraint
from antares.craft.model.output import Output
from antares.craft.model.settings.study_settings import StudySettings
from antares.craft.service.base_services import BaseOutputService, BaseStudyService
from antares.craft.service.local_services.services.settings import edit_study_settings

if TYPE_CHECKING:
from antares.craft.model.study import Study
Expand Down Expand Up @@ -45,9 +43,6 @@ def output_service(self) -> Optional[BaseOutputService]:
def set_output_service(self, output_service: BaseOutputService) -> None:
self._output_service = output_service

def update_study_settings(self, settings: StudySettings) -> None:
edit_study_settings(self.config.study_path, settings, update=True)

def delete_binding_constraint(self, constraint: BindingConstraint) -> None:
raise NotImplementedError

Expand Down
Loading

0 comments on commit 7f10ab2

Please sign in to comment.