Skip to content

Commit

Permalink
merge with dev
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinBelthle committed Dec 2, 2024
2 parents 757054d + 9ea20c6 commit cd84e2f
Show file tree
Hide file tree
Showing 162 changed files with 3,201 additions and 1,711 deletions.
4 changes: 2 additions & 2 deletions antarest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

# Standard project metadata

__version__ = "2.17.6"
__version__ = "2.18.0"
__author__ = "RTE, Antares Web Team"
__date__ = "2024-09-25"
__date__ = "2024-11-29"
# noinspection SpellCheckingInspection
__credits__ = "(c) Réseau de Transport de l’Électricité (RTE)"

Expand Down
19 changes: 17 additions & 2 deletions antarest/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ def __init__(self, message: str) -> None:
super().__init__(HTTPStatus.UNPROCESSABLE_ENTITY, message)


class LinkNotFound(HTTPException):
def __init__(self, message: str) -> None:
super().__init__(HTTPStatus.NOT_FOUND, message)


class VariantStudyParentNotValid(HTTPException):
def __init__(self, message: str) -> None:
super().__init__(HTTPStatus.UNPROCESSABLE_ENTITY, message)
Expand Down Expand Up @@ -348,13 +353,23 @@ def __init__(self, is_variant: bool) -> None:
super().__init__(HTTPStatus.EXPECTATION_FAILED, "Upgrade not supported for parent of variants")


class FileDeletionNotAllowed(HTTPException):
class ResourceDeletionNotAllowed(HTTPException):
"""
Exception raised when deleting a file or a folder which isn't inside the 'User' folder.
"""

def __init__(self, message: str) -> None:
msg = f"Raw deletion failed because {message}"
msg = f"Resource deletion failed because {message}"
super().__init__(HTTPStatus.FORBIDDEN, msg)


class FolderCreationNotAllowed(HTTPException):
"""
Exception raised when creating a folder which isn't inside the 'User' folder.
"""

def __init__(self, message: str) -> None:
msg = f"Folder creation failed because {message}"
super().__init__(HTTPStatus.FORBIDDEN, msg)


Expand Down
20 changes: 15 additions & 5 deletions antarest/desktop/systray_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ def start_server(config_file: Path) -> Process:
return server


def open_app() -> None:
webbrowser.open("http://localhost:8080")
def open_app(wait_seconds: int = 0) -> None:
"""
Open antares-web in a new browser tab.
Optionally, waits for some seconds to ensure it does have time for opening.
"""
webbrowser.open_new_tab("http://localhost:8080")
time.sleep(wait_seconds)


def monitor_server_process(server: Process, app: QApplication) -> None:
Expand Down Expand Up @@ -173,7 +178,9 @@ def run_systray_app(config_file: Path) -> None:
notification_popup(
"Antares Web Server already running, you can manage the application within the system tray.", threaded=False
)
open_app()
# On windows at least, if the current process closes too fast,
# the browser does not have time to open --> waiting an arbitrary 10s
open_app(wait_seconds=10)
return
notification_popup("Starting Antares Web Server...")
systray_app = create_systray_app()
Expand All @@ -182,5 +189,8 @@ def run_systray_app(config_file: Path) -> None:
wait_for_server_start()
notification_popup("Antares Web Server started, you can manage the application within the system tray.")
open_app()
systray_app.app.exec_()
server.kill()
try:
systray_app.app.exec_()
finally:
# Kill server also on exception, in particular on keyboard interrupt
server.kill()
47 changes: 45 additions & 2 deletions antarest/study/business/link_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@
# This file is part of the Antares project.

import typing as t
from typing import Any, Dict

from antares.study.version import StudyVersion

from antarest.core.exceptions import ConfigFileNotFound
from antarest.core.exceptions import ConfigFileNotFound, LinkNotFound, LinkValidationError
from antarest.core.model import JSON
from antarest.study.business.all_optional_meta import all_optional_model, camel_case_model
from antarest.study.business.model.link_model import LinkDTO, LinkInternal
from antarest.study.business.model.link_model import LinkBaseDTO, LinkDTO, LinkInternal
from antarest.study.business.utils import execute_or_add_commands
from antarest.study.model import RawStudy, Study
from antarest.study.storage.rawstudy.model.filesystem.config.links import LinkProperties
from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy
from antarest.study.storage.storage_service import StudyStorageService
from antarest.study.storage.variantstudy.model.command.create_link import CreateLink
from antarest.study.storage.variantstudy.model.command.remove_link import RemoveLink
from antarest.study.storage.variantstudy.model.command.update_config import UpdateConfig
from antarest.study.storage.variantstudy.model.command.update_link import UpdateLink

_ALL_LINKS_PATH = "input/links"

Expand Down Expand Up @@ -76,6 +79,46 @@ def create_link(self, study: Study, link_creation_dto: LinkDTO) -> LinkDTO:

return link_creation_dto

def update_link(self, study: RawStudy, area_from: str, area_to: str, link_update_dto: LinkBaseDTO) -> LinkDTO:
link_dto = LinkDTO(area1=area_from, area2=area_to, **link_update_dto.model_dump())

link = link_dto.to_internal(StudyVersion.parse(study.version))
file_study = self.storage_service.get_storage(study).get_raw(study)

self.get_link_if_exists(file_study, link)

command = UpdateLink(
area1=area_from,
area2=area_to,
parameters=link.model_dump(
include=link_update_dto.model_fields_set, exclude={"area1", "area2"}, exclude_none=True
),
command_context=self.storage_service.variant_study_service.command_factory.command_context,
study_version=file_study.config.version,
)

execute_or_add_commands(study, file_study, [command], self.storage_service)

updated_link = self.get_internal_link(study, link)

return updated_link.to_dto()

def get_link_if_exists(self, file_study: FileStudy, link: LinkInternal) -> dict[str, Any]:
try:
return file_study.tree.get(["input", "links", link.area1, "properties", link.area2])
except KeyError:
raise LinkNotFound(f"The link {link.area1} -> {link.area2} is not present in the study")

def get_internal_link(self, study: RawStudy, link: LinkInternal) -> LinkInternal:
file_study = self.storage_service.get_storage(study).get_raw(study)

link_properties = self.get_link_if_exists(file_study, link)

link_properties.update({"area1": link.area1, "area2": link.area2})
updated_link = LinkInternal.model_validate(link_properties)

return updated_link

def delete_link(self, study: RawStudy, area1_id: str, area2_id: str) -> None:
file_study = self.storage_service.get_storage(study).get_raw(study)
command = RemoveLink(
Expand Down
30 changes: 17 additions & 13 deletions antarest/study/business/model/link_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,7 @@
]


class Area(AntaresBaseModel):
area1: str
area2: str

@model_validator(mode="after")
def validate_areas(self) -> t.Self:
if self.area1 == self.area2:
raise LinkValidationError(f"Cannot create a link that goes from and to the same single area: {self.area1}")
return self


class LinkDTO(Area):
class LinkBaseDTO(AntaresBaseModel):
model_config = ConfigDict(alias_generator=to_camel_case, populate_by_name=True, extra="forbid")

hurdles_cost: bool = False
Expand All @@ -61,10 +50,25 @@ class LinkDTO(Area):
colorg: int = Field(default=DEFAULT_COLOR, ge=0, le=255)
link_width: float = 1
link_style: LinkStyle = LinkStyle.PLAIN

filter_synthesis: t.Optional[comma_separated_enum_list] = FILTER_VALUES
filter_year_by_year: t.Optional[comma_separated_enum_list] = FILTER_VALUES


class Area(AntaresBaseModel):
area1: str
area2: str

@model_validator(mode="after")
def validate_areas(self) -> t.Self:
if self.area1 == self.area2:
raise LinkValidationError(f"Cannot create a link that goes from and to the same single area: {self.area1}")
area_from, area_to = sorted([self.area1, self.area2])
self.area1 = area_from
self.area2 = area_to
return self


class LinkDTO(Area, LinkBaseDTO):
def to_internal(self, version: StudyVersion) -> "LinkInternal":
if version < STUDY_VERSION_8_2 and {"filter_synthesis", "filter_year_by_year"} & self.model_fields_set:
raise LinkValidationError("Cannot specify a filter value for study's version earlier than v8.2")
Expand Down
6 changes: 5 additions & 1 deletion antarest/study/business/table_mode_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ def update_table_data(
elif table_type == TableModeType.LINK:
links_map = {tuple(key.split(" / ")): LinkOutput(**values) for key, values in data.items()}
updated_map = self._link_manager.update_links_props(study, links_map) # type: ignore
excludes = set() if int(study.version) >= STUDY_VERSION_8_2 else {"filter_synthesis", "filter_year_by_year"}
excludes = (
set()
if StudyVersion.parse(study.version) >= STUDY_VERSION_8_2
else {"filter_synthesis", "filter_year_by_year"}
)
data = {
f"{area1_id} / {area2_id}": link.model_dump(by_alias=True, exclude=excludes)
for (area1_id, area2_id), link in updated_map.items()
Expand Down
7 changes: 1 addition & 6 deletions antarest/study/business/xpansion_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from fastapi import HTTPException, UploadFile
from pydantic import Field, ValidationError, field_validator, model_validator

from antarest.core.exceptions import BadZipBinary, ChildNotFoundError
from antarest.core.exceptions import BadZipBinary, ChildNotFoundError, LinkNotFound
from antarest.core.model import JSON
from antarest.core.serialization import AntaresBaseModel
from antarest.study.business.all_optional_meta import all_optional_model
Expand Down Expand Up @@ -255,11 +255,6 @@ class XpansionCandidateDTO(AntaresBaseModel):
)


class LinkNotFound(HTTPException):
def __init__(self, message: str) -> None:
super().__init__(http.HTTPStatus.NOT_FOUND, message)


class XpansionFileNotFoundError(HTTPException):
def __init__(self, message: str) -> None:
super().__init__(http.HTTPStatus.NOT_FOUND, message)
Expand Down
Loading

0 comments on commit cd84e2f

Please sign in to comment.