From 3ce27f6b309fae271419d4980854e0763cf45764 Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Tue, 26 Mar 2024 13:59:06 +0100 Subject: [PATCH] feat(commands): add the `command_id` in `ICommand` --- .../business/utils_binding_constraint.py | 16 ++++--------- .../storage/variantstudy/command_factory.py | 22 +++++++++++------ .../command/create_binding_constraint.py | 3 ++- .../variantstudy/model/command/icommand.py | 24 ++++++++++++++----- .../command/remove_binding_constraint.py | 2 +- .../command/update_binding_constraint.py | 3 ++- .../model/command/update_config.py | 2 +- 7 files changed, 44 insertions(+), 28 deletions(-) diff --git a/antarest/study/storage/variantstudy/business/utils_binding_constraint.py b/antarest/study/storage/variantstudy/business/utils_binding_constraint.py index 0779f7e048..37f08b0323 100644 --- a/antarest/study/storage/variantstudy/business/utils_binding_constraint.py +++ b/antarest/study/storage/variantstudy/business/utils_binding_constraint.py @@ -8,7 +8,7 @@ ) from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy -from antarest.study.storage.variantstudy.model.command.common import BindingConstraintOperator, CommandOutput +from antarest.study.storage.variantstudy.model.command.common import BindingConstraintOperator def apply_binding_constraint( @@ -29,7 +29,7 @@ def apply_binding_constraint( filter_year_by_year: t.Optional[str] = None, filter_synthesis: t.Optional[str] = None, group: t.Optional[str] = None, -) -> CommandOutput: +) -> str: version = study_data.config.version binding_constraints[new_key] = { "name": name, @@ -52,19 +52,13 @@ def apply_binding_constraint( if "%" in link_or_cluster: area_1, area_2 = link_or_cluster.split("%") if area_1 not in study_data.config.areas or area_2 not in study_data.config.areas[area_1].links: - return CommandOutput( - status=False, - message=f"Link '{link_or_cluster}' does not exist in binding constraint '{bd_id}'", - ) + return f"Link '{link_or_cluster}' does not exist in binding constraint '{bd_id}'" elif "." in link_or_cluster: # Cluster IDs are stored in lower case in the binding constraints file. area, cluster_id = link_or_cluster.split(".") thermal_ids = {thermal.id.lower() for thermal in study_data.config.areas[area].thermals} if area not in study_data.config.areas or cluster_id.lower() not in thermal_ids: - return CommandOutput( - status=False, - message=f"Cluster '{link_or_cluster}' does not exist in binding constraint '{bd_id}'", - ) + return f"Cluster '{link_or_cluster}' does not exist in binding constraint '{bd_id}'" else: raise NotImplementedError(f"Invalid link or thermal ID: {link_or_cluster}") @@ -95,7 +89,7 @@ def apply_binding_constraint( raise TypeError(repr(matrix_term)) if version >= 870: study_data.tree.save(matrix_term, ["input", "bindingconstraints", f"{bd_id}_{matrix_alias}"]) - return CommandOutput(status=True) + return "" # success def parse_bindings_coeffs_and_save_into_config( diff --git a/antarest/study/storage/variantstudy/command_factory.py b/antarest/study/storage/variantstudy/command_factory.py index 5cf298b15e..33aa9b13c2 100644 --- a/antarest/study/storage/variantstudy/command_factory.py +++ b/antarest/study/storage/variantstudy/command_factory.py @@ -1,4 +1,4 @@ -from typing import List +import typing as t from antarest.core.model import JSON from antarest.matrixstore.service import ISimpleMatrixService @@ -74,14 +74,19 @@ def __init__( patch_service=patch_service, ) - def _to_single_command(self, action: str, args: JSON, version: int) -> ICommand: + def _to_single_command(self, command_id: t.Optional[str], action: str, args: JSON, version: int) -> ICommand: """Convert a single CommandDTO to ICommand.""" if action in COMMAND_MAPPING: command_class = COMMAND_MAPPING[action] - return command_class(**args, command_context=self.command_context, version=version) # type: ignore + return command_class( # type: ignore + **args, + command_context=self.command_context, + version=version, + command_id=command_id, + ) raise NotImplementedError(action) - def to_command(self, command_dto: CommandDTO) -> List[ICommand]: + def to_command(self, command_dto: CommandDTO) -> t.List[ICommand]: """ Convert a CommandDTO to a list of ICommand. @@ -96,12 +101,15 @@ def to_command(self, command_dto: CommandDTO) -> List[ICommand]: """ args = command_dto.args if isinstance(args, dict): - return [self._to_single_command(command_dto.action, args, command_dto.version)] + return [self._to_single_command(command_dto.id, command_dto.action, args, command_dto.version)] elif isinstance(args, list): - return [self._to_single_command(command_dto.action, argument, command_dto.version) for argument in args] + return [ + self._to_single_command(command_dto.id, command_dto.action, argument, command_dto.version) + for argument in args + ] raise NotImplementedError() - def to_commands(self, cmd_dto_list: List[CommandDTO]) -> List[ICommand]: + def to_commands(self, cmd_dto_list: t.List[CommandDTO]) -> t.List[ICommand]: """ Convert a list of CommandDTO to a list of ICommand. diff --git a/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py b/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py index 4b3885a5f0..c37abcc683 100644 --- a/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py @@ -241,7 +241,7 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: bd_id = transform_name_to_id(self.name) self.validates_and_fills_matrices(specific_matrices=None, version=study_data.config.version, create=True) - return apply_binding_constraint( + err_msg = apply_binding_constraint( study_data, binding_constraints, str(new_key), @@ -260,6 +260,7 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: self.filter_synthesis, self.group, ) + return CommandOutput(status=not err_msg, message=err_msg) def to_dto(self) -> CommandDTO: dto = super().to_dto() diff --git a/antarest/study/storage/variantstudy/model/command/icommand.py b/antarest/study/storage/variantstudy/model/command/icommand.py index 6a17c34c10..3fd31f58fe 100644 --- a/antarest/study/storage/variantstudy/model/command/icommand.py +++ b/antarest/study/storage/variantstudy/model/command/icommand.py @@ -1,6 +1,7 @@ import logging +import typing as t +import uuid from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Dict, List, Tuple from pydantic import BaseModel, Extra @@ -11,7 +12,7 @@ from antarest.study.storage.variantstudy.model.command_context import CommandContext from antarest.study.storage.variantstudy.model.model import CommandDTO -if TYPE_CHECKING: # False at runtime, for mypy +if t.TYPE_CHECKING: # False at runtime, for mypy from antarest.study.storage.variantstudy.business.command_extractor import CommandExtractor MATCH_SIGNATURE_SEPARATOR = "%" @@ -19,12 +20,23 @@ class ICommand(ABC, BaseModel, extra=Extra.forbid, arbitrary_types_allowed=True): + """ + Interface for all commands that can be applied to a study. + + Attributes: + command_id: The ID of the command extracted from the database, if any. + command_name: The name of the command. + version: The version of the command (currently always equal to 1). + command_context: The context of the command. + """ + + command_id: t.Optional[uuid.UUID] = None command_name: CommandName version: int command_context: CommandContext @abstractmethod - def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: + def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: """ Applies configuration changes to the study data. @@ -112,7 +124,7 @@ def match(self, other: "ICommand", equal: bool = False) -> bool: raise NotImplementedError() @abstractmethod - def _create_diff(self, other: "ICommand") -> List["ICommand"]: + def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: """ Creates a list of commands representing the differences between the current instance and another `ICommand` object. @@ -126,7 +138,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: """ raise NotImplementedError() - def create_diff(self, other: "ICommand") -> List["ICommand"]: + def create_diff(self, other: "ICommand") -> t.List["ICommand"]: """ Creates a list of commands representing the differences between the current instance and another `ICommand` object. @@ -142,7 +154,7 @@ def create_diff(self, other: "ICommand") -> List["ICommand"]: return self._create_diff(other) @abstractmethod - def get_inner_matrices(self) -> List[str]: + def get_inner_matrices(self) -> t.List[str]: """ Retrieves the list of matrix IDs. """ diff --git a/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py b/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py index 2bd52825c6..25b180c49d 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py @@ -26,7 +26,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, dict(), ) study_data.bindings.remove(next(iter([bind for bind in study_data.bindings if bind.id == self.id]))) - return CommandOutput(status=True), dict() + return CommandOutput(status=True), {} def _apply(self, study_data: FileStudy) -> CommandOutput: if self.id not in [bind.id for bind in study_data.config.bindings]: diff --git a/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py b/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py index 70ad16702f..211ea2f848 100644 --- a/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py @@ -56,7 +56,7 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: self.validates_and_fills_matrices(specific_matrices=updated_matrices or None, version=study_data.config.version, create=False) # fmt: on - return apply_binding_constraint( + err_msg = apply_binding_constraint( study_data, binding_constraints, new_key, @@ -75,6 +75,7 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: self.filter_synthesis, self.group, ) + return CommandOutput(status=not err_msg, message=err_msg) def to_dto(self) -> CommandDTO: dto = super().to_dto() diff --git a/antarest/study/storage/variantstudy/model/command/update_config.py b/antarest/study/storage/variantstudy/model/command/update_config.py index 91caa6a738..29887d42e1 100644 --- a/antarest/study/storage/variantstudy/model/command/update_config.py +++ b/antarest/study/storage/variantstudy/model/command/update_config.py @@ -27,7 +27,7 @@ class UpdateConfig(ICommand): data: Union[str, int, float, bool, JSON, None] def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: - return CommandOutput(status=True, message="ok"), dict() + return CommandOutput(status=True, message="ok"), {} def _apply(self, study_data: FileStudy) -> CommandOutput: url = self.target.split("/")