From 1996f62c2ddfcaa165b2675f58564b0190b4cda4 Mon Sep 17 00:00:00 2001 From: Sylvain Leclerc Date: Tue, 17 Dec 2024 11:40:16 +0100 Subject: [PATCH 1/2] feat(mypy): enable explicit overrides Signed-off-by: Sylvain Leclerc --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 6073d80770..3b3b9a3849 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ exclude = "antarest/fastapi_jwt_auth/*" strict = true files = "antarest" plugins = "pydantic.mypy" +enable_error_code = "explicit-override" [[tool.mypy.overrides]] module = ["antarest/fastapi_jwt_auth.*"] From 9cea805bb16ac43c385217b14e2dbf3390baee87 Mon Sep 17 00:00:00 2001 From: belthlemar Date: Tue, 17 Dec 2024 15:34:50 +0100 Subject: [PATCH 2/2] chore(mypy): add override where needed --- antarest/core/cache/business/local_chache.py | 7 +++++++ antarest/core/cache/business/redis_cache.py | 6 ++++++ antarest/core/configdata/model.py | 3 +++ antarest/core/exceptions.py | 11 +++++++++++ antarest/core/filetransfer/model.py | 2 ++ antarest/core/interfaces/eventbus.py | 9 +++++++++ antarest/core/logging/utils.py | 4 ++++ antarest/core/requests.py | 8 ++++++++ antarest/core/tasks/model.py | 5 +++++ antarest/core/tasks/service.py | 10 ++++++++++ .../core/utils/fastapi_sqlalchemy/middleware.py | 2 ++ antarest/core/utils/utils.py | 5 +++++ antarest/eventbus/business/local_eventbus.py | 7 +++++++ antarest/eventbus/business/redis_eventbus.py | 6 ++++++ antarest/eventbus/service.py | 9 +++++++++ antarest/front.py | 2 ++ .../adapters/local_launcher/local_launcher.py | 5 +++++ .../adapters/slurm_launcher/slurm_launcher.py | 4 ++++ .../extensions/adequacy_patch/extension.py | 4 ++++ antarest/launcher/model.py | 5 +++++ antarest/login/model.py | 6 ++++++ antarest/matrixstore/matrix_editor.py | 3 +++ antarest/matrixstore/matrix_garbage_collector.py | 3 +++ antarest/matrixstore/model.py | 7 +++++++ antarest/matrixstore/service.py | 9 +++++++++ antarest/study/business/enum_ignore_case.py | 3 +++ .../study/business/scenario_builder_management.py | 2 ++ antarest/study/business/table_mode_management.py | 2 ++ antarest/study/model.py | 11 +++++++++++ antarest/study/service.py | 2 ++ .../study/storage/abstract_storage_service.py | 12 ++++++++++++ antarest/study/storage/auto_archive_service.py | 3 +++ antarest/study/storage/df_download.py | 2 ++ antarest/study/storage/rawstudy/ini_reader.py | 5 +++++ antarest/study/storage/rawstudy/ini_writer.py | 4 ++++ .../rawstudy/model/filesystem/bucket_node.py | 5 +++++ .../model/filesystem/common/area_matrix_list.py | 7 +++++++ .../rawstudy/model/filesystem/common/prepro.py | 3 +++ .../rawstudy/model/filesystem/config/area.py | 3 +++ .../model/filesystem/config/exceptions.py | 4 ++++ .../model/filesystem/config/ini_properties.py | 3 +++ .../rawstudy/model/filesystem/config/model.py | 2 ++ .../rawstudy/model/filesystem/config/renewable.py | 3 +++ .../model/filesystem/config/ruleset_matrices.py | 2 ++ .../rawstudy/model/filesystem/config/thermal.py | 5 +++++ .../rawstudy/model/filesystem/folder_node.py | 10 ++++++++++ .../rawstudy/model/filesystem/ini_file_node.py | 8 ++++++++ .../rawstudy/model/filesystem/json_file_node.py | 4 ++++ .../rawstudy/model/filesystem/lazy_node.py | 6 ++++++ .../model/filesystem/matrix/date_serializer.py | 11 +++++++++++ .../model/filesystem/matrix/head_writer.py | 4 ++++ .../filesystem/matrix/input_series_matrix.py | 4 ++++ .../rawstudy/model/filesystem/matrix/matrix.py | 6 ++++++ .../filesystem/matrix/output_series_matrix.py | 7 +++++++ .../rawstudy/model/filesystem/raw_file_node.py | 8 ++++++++ .../model/filesystem/root/filestudytree.py | 3 +++ .../model/filesystem/root/input/areas/areas.py | 2 ++ .../filesystem/root/input/areas/item/item.py | 2 ++ .../model/filesystem/root/input/areas/list.py | 9 +++++++++ .../input/bindingconstraints/bindingcontraints.py | 2 ++ .../root/input/commons/prepro_series.py | 2 ++ .../root/input/hydro/allocation/allocation.py | 2 ++ .../root/input/hydro/common/capacity/capacity.py | 2 ++ .../filesystem/root/input/hydro/common/common.py | 2 ++ .../model/filesystem/root/input/hydro/hydro.py | 2 ++ .../root/input/hydro/prepro/area/area.py | 2 ++ .../filesystem/root/input/hydro/prepro/prepro.py | 2 ++ .../root/input/hydro/series/area/area.py | 3 +++ .../filesystem/root/input/hydro/series/series.py | 2 ++ .../rawstudy/model/filesystem/root/input/input.py | 2 ++ .../model/filesystem/root/input/link/area/area.py | 2 ++ .../root/input/link/area/capacities/capacities.py | 2 ++ .../model/filesystem/root/input/link/link.py | 2 ++ .../filesystem/root/input/miscgen/miscgen.py | 2 ++ .../filesystem/root/input/renewables/clusters.py | 3 +++ .../filesystem/root/input/renewables/renewable.py | 2 ++ .../filesystem/root/input/renewables/series.py | 4 ++++ .../filesystem/root/input/reserves/reserves.py | 2 ++ .../root/input/st_storage/clusters/area/area.py | 2 ++ .../root/input/st_storage/clusters/clusters.py | 2 ++ .../root/input/st_storage/series/area/area.py | 2 ++ .../series/area/st_storage/st_storage.py | 2 ++ .../root/input/st_storage/series/series.py | 2 ++ .../root/input/st_storage/st_storage.py | 3 +++ .../root/input/thermal/cluster/area/area.py | 2 ++ .../root/input/thermal/cluster/cluster.py | 2 ++ .../root/input/thermal/prepro/area/area.py | 2 ++ .../input/thermal/prepro/area/thermal/thermal.py | 2 ++ .../root/input/thermal/prepro/prepro.py | 2 ++ .../root/input/thermal/series/area/area.py | 2 ++ .../input/thermal/series/area/thermal/thermal.py | 2 ++ .../root/input/thermal/series/series.py | 2 ++ .../filesystem/root/input/thermal/thermal.py | 2 ++ .../model/filesystem/root/layers/layers.py | 2 ++ .../model/filesystem/root/output/output.py | 2 ++ .../root/output/simulation/about/about.py | 2 ++ .../root/output/simulation/mode/common/area.py | 2 ++ .../root/output/simulation/mode/common/areas.py | 2 ++ .../simulation/mode/common/binding_const.py | 2 ++ .../root/output/simulation/mode/common/link.py | 2 ++ .../root/output/simulation/mode/common/links.py | 4 ++++ .../root/output/simulation/mode/common/set.py | 2 ++ .../root/output/simulation/mode/common/utils.py | 2 ++ .../root/output/simulation/mode/economy.py | 2 ++ .../root/output/simulation/mode/mcall/grid.py | 9 +++++++++ .../root/output/simulation/mode/mcind/mcind.py | 2 ++ .../root/output/simulation/simulation.py | 2 ++ .../simulation/ts_generator/ts_generator.py | 5 +++++ .../output/simulation/ts_numbers/ts_numbers.py | 2 ++ .../simulation/ts_numbers/ts_numbers_data.py | 7 +++++++ .../output/simulation/xpansion/sensitivity.py | 2 ++ .../root/output/simulation/xpansion/xpansion.py | 2 ++ .../root/settings/resources/resources.py | 2 ++ .../filesystem/root/settings/scenariobuilder.py | 2 ++ .../model/filesystem/root/settings/settings.py | 2 ++ .../root/settings/simulations/simulations.py | 2 ++ .../filesystem/root/user/expansion/sensitivity.py | 3 +++ .../study/storage/rawstudy/raw_study_service.py | 12 ++++++++++++ antarest/study/storage/rawstudy/watcher.py | 3 +++ .../variantstudy/business/command_extractor.py | 13 +++++++++++++ .../variantstudy/model/command/create_area.py | 8 ++++++++ .../model/command/create_binding_constraint.py | 9 +++++++++ .../variantstudy/model/command/create_cluster.py | 8 ++++++++ .../variantstudy/model/command/create_district.py | 8 ++++++++ .../variantstudy/model/command/create_link.py | 13 +++++++++++++ .../model/command/create_renewables_cluster.py | 8 ++++++++ .../model/command/create_st_storage.py | 8 ++++++++ .../model/command/create_user_resource.py | 9 +++++++++ .../generate_thermal_cluster_timeseries.py | 8 ++++++++ .../variantstudy/model/command/remove_area.py | 9 +++++++++ .../model/command/remove_binding_constraint.py | 9 +++++++++ .../variantstudy/model/command/remove_cluster.py | 8 ++++++++ .../variantstudy/model/command/remove_district.py | 9 +++++++++ .../variantstudy/model/command/remove_link.py | 8 ++++++++ .../model/command/remove_renewables_cluster.py | 11 +++++++++-- .../model/command/remove_st_storage.py | 8 ++++++++ .../model/command/remove_user_resource.py | 9 +++++++++ .../variantstudy/model/command/replace_matrix.py | 8 ++++++++ .../model/command/update_binding_constraint.py | 8 ++++++++ .../variantstudy/model/command/update_comments.py | 9 +++++++++ .../variantstudy/model/command/update_config.py | 8 ++++++++ .../variantstudy/model/command/update_district.py | 9 +++++++++ .../variantstudy/model/command/update_link.py | 8 ++++++++ .../variantstudy/model/command/update_playlist.py | 9 +++++++++ .../variantstudy/model/command/update_raw_file.py | 10 ++++++++++ .../model/command/update_scenario_builder.py | 8 ++++++++ .../study/storage/variantstudy/model/dbmodel.py | 4 ++++ antarest/study/storage/variantstudy/repository.py | 2 ++ .../storage/variantstudy/variant_study_service.py | 15 +++++++++++++++ antarest/tools/lib.py | 3 +++ antarest/worker/archive_worker.py | 3 +++ antarest/worker/worker.py | 3 +++ 152 files changed, 731 insertions(+), 2 deletions(-) diff --git a/antarest/core/cache/business/local_chache.py b/antarest/core/cache/business/local_chache.py index e903ff9080..493322b9c6 100644 --- a/antarest/core/cache/business/local_chache.py +++ b/antarest/core/cache/business/local_chache.py @@ -15,6 +15,8 @@ import time from typing import Dict, List, Optional +from typing_extensions import override + from antarest.core.config import CacheConfig from antarest.core.interfaces.cache import ICache from antarest.core.model import JSON @@ -40,6 +42,7 @@ def __init__(self, config: CacheConfig = CacheConfig()): daemon=True, ) + @override def start(self) -> None: self.checker_thread.start() @@ -55,6 +58,7 @@ def checker(self) -> None: for id in to_delete: del self.cache[id] + @override def put(self, id: str, data: JSON, duration: int = 3600) -> None: # Duration in second with self.lock: logger.info(f"Adding cache key {id}") @@ -64,6 +68,7 @@ def put(self, id: str, data: JSON, duration: int = 3600) -> None: # Duration in duration=duration, ) + @override def get(self, id: str, refresh_duration: Optional[int] = None) -> Optional[JSON]: res = None with self.lock: @@ -76,12 +81,14 @@ def get(self, id: str, refresh_duration: Optional[int] = None) -> Optional[JSON] res = self.cache[id].data return res + @override def invalidate(self, id: str) -> None: with self.lock: logger.info(f"Removing cache key {id}") if id in self.cache: del self.cache[id] + @override def invalidate_all(self, ids: List[str]) -> None: with self.lock: logger.info(f"Removing cache keys {ids}") diff --git a/antarest/core/cache/business/redis_cache.py b/antarest/core/cache/business/redis_cache.py index 11eb3fcffd..ee7e30a6d1 100644 --- a/antarest/core/cache/business/redis_cache.py +++ b/antarest/core/cache/business/redis_cache.py @@ -14,6 +14,7 @@ from typing import List, Optional from redis.client import Redis +from typing_extensions import override from antarest.core.interfaces.cache import ICache from antarest.core.model import JSON @@ -31,10 +32,12 @@ class RedisCache(ICache): def __init__(self, redis_client: Redis): # type: ignore self.redis = redis_client + @override def start(self) -> None: # Assuming the Redis service is already running; no need to start it here. pass + @override def put(self, id: str, data: JSON, duration: int = 3600) -> None: redis_element = RedisCacheElement(duration=duration, data=data) redis_key = f"cache:{id}" @@ -42,6 +45,7 @@ def put(self, id: str, data: JSON, duration: int = 3600) -> None: self.redis.set(redis_key, redis_element.model_dump_json()) self.redis.expire(redis_key, duration) + @override def get(self, id: str, refresh_timeout: Optional[int] = None) -> Optional[JSON]: redis_key = f"cache:{id}" result = self.redis.get(redis_key) @@ -58,10 +62,12 @@ def get(self, id: str, refresh_timeout: Optional[int] = None) -> Optional[JSON]: logger.info(f"Cache key {id} not found") return None + @override def invalidate(self, id: str) -> None: logger.info(f"Removing cache key {id}") self.redis.delete(f"cache:{id}") + @override def invalidate_all(self, ids: List[str]) -> None: logger.info(f"Removing cache keys {ids}") self.redis.delete(*[f"cache:{id}" for id in ids]) diff --git a/antarest/core/configdata/model.py b/antarest/core/configdata/model.py index 3a4512e44c..faa6589709 100644 --- a/antarest/core/configdata/model.py +++ b/antarest/core/configdata/model.py @@ -14,6 +14,7 @@ from typing import Any, Optional from sqlalchemy import Column, Integer, String # type: ignore +from typing_extensions import override from antarest.core.persistence import Base from antarest.core.serialization import AntaresBaseModel @@ -30,11 +31,13 @@ class ConfigData(Base): # type: ignore key = Column(String(), primary_key=True) value = Column(String(), nullable=True) + @override def __eq__(self, other: Any) -> bool: if not isinstance(other, ConfigData): return False return bool(other.key == self.key and other.value == self.value and other.owner == self.owner) + @override def __repr__(self) -> str: return f"key={self.key}, value={self.value}, owner={self.owner}" diff --git a/antarest/core/exceptions.py b/antarest/core/exceptions.py index d6c392b9cf..722a385b26 100644 --- a/antarest/core/exceptions.py +++ b/antarest/core/exceptions.py @@ -15,6 +15,7 @@ from http import HTTPStatus from fastapi.exceptions import HTTPException +from typing_extensions import override class ShouldNotHappenException(Exception): @@ -81,6 +82,7 @@ def __init__(self, path: str, *area_ids: str): detail = f"{self.object_name.title()} {detail}" super().__init__(HTTPStatus.NOT_FOUND, detail) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -127,6 +129,7 @@ def __init__(self, path: str, section_id: str): detail = f"{object_name.title()} '{section_id}' not found in '{path}'" super().__init__(HTTPStatus.NOT_FOUND, detail) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -172,6 +175,7 @@ def __init__(self, path: str): detail = f"{self.object_name.title()} {detail}" super().__init__(HTTPStatus.NOT_FOUND, detail) + @override def __str__(self) -> str: return self.detail @@ -227,6 +231,7 @@ def __init__(self, area_id: str, *duplicates: str): detail = f"{self.object_name.title()} {detail}" super().__init__(HTTPStatus.CONFLICT, detail) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -397,6 +402,7 @@ def __init__(self, object_id: str, binding_ids: t.Sequence[str], *, object_type: ) super().__init__(HTTPStatus.FORBIDDEN, message) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -429,6 +435,7 @@ def __init__(self, output_id: str) -> None: message = f"Output '{output_id}' not found" super().__init__(HTTPStatus.NOT_FOUND, message) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -463,6 +470,7 @@ def __init__(self, output_id: str, mc_root: str) -> None: message = f"The output '{output_id}' sub-folder '{mc_root}' does not exist" super().__init__(HTTPStatus.NOT_FOUND, message) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -552,6 +560,7 @@ def __init__(self, binding_constraint_id: str, *ids: str) -> None: }[min(count, 2)] super().__init__(HTTPStatus.NOT_FOUND, message) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -572,6 +581,7 @@ def __init__(self, binding_constraint_id: str, *ids: str) -> None: }[min(count, 2)] super().__init__(HTTPStatus.CONFLICT, message) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail @@ -589,6 +599,7 @@ def __init__(self, binding_constraint_id: str, term_json: str) -> None: ) super().__init__(HTTPStatus.UNPROCESSABLE_ENTITY, message) + @override def __str__(self) -> str: """Return a string representation of the exception.""" return self.detail diff --git a/antarest/core/filetransfer/model.py b/antarest/core/filetransfer/model.py index 6ce194ed19..0a5958d57a 100644 --- a/antarest/core/filetransfer/model.py +++ b/antarest/core/filetransfer/model.py @@ -16,6 +16,7 @@ from typing import Optional from sqlalchemy import Boolean, Column, DateTime, Integer, String # type: ignore +from typing_extensions import override from antarest.core.persistence import Base from antarest.core.serialization import AntaresBaseModel @@ -81,6 +82,7 @@ def to_dto(self) -> FileDownloadDTO: error_message=self.error_message or "", ) + @override def __repr__(self) -> str: return ( f"(id={self.id}," diff --git a/antarest/core/interfaces/eventbus.py b/antarest/core/interfaces/eventbus.py index a60aaf481a..d9075dc49e 100644 --- a/antarest/core/interfaces/eventbus.py +++ b/antarest/core/interfaces/eventbus.py @@ -14,6 +14,8 @@ from enum import StrEnum from typing import Any, Awaitable, Callable, List, Optional +from typing_extensions import override + from antarest.core.model import PermissionInfo from antarest.core.serialization import AntaresBaseModel @@ -140,21 +142,26 @@ class DummyEventBusService(IEventBus): def __init__(self) -> None: self.events: List[Event] = [] + @override def queue(self, event: Event, queue: str) -> None: # Noop pass + @override def add_queue_consumer(self, listener: Callable[[Event], Awaitable[None]], queue: str) -> str: return "" + @override def remove_queue_consumer(self, listener_id: str) -> None: # Noop pass + @override def push(self, event: Event) -> None: # Noop self.events.append(event) + @override def add_listener( self, listener: Callable[[Event], Awaitable[None]], @@ -162,10 +169,12 @@ def add_listener( ) -> str: return "" + @override def remove_listener(self, listener_id: str) -> None: # Noop pass + @override def start(self, threaded: bool = True) -> None: # Noop pass diff --git a/antarest/core/logging/utils.py b/antarest/core/logging/utils.py index 991f21b846..2fa8c4a040 100644 --- a/antarest/core/logging/utils.py +++ b/antarest/core/logging/utils.py @@ -20,6 +20,7 @@ from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from starlette.requests import Request from starlette.responses import Response +from typing_extensions import override from antarest.core.config import Config @@ -39,6 +40,7 @@ class CustomDefaultFormatter(logging.Formatter): fields to the log record with a value of `None`. """ + @override def format(self, record: logging.LogRecord) -> str: """ Formats the specified log record using the custom formatter, @@ -169,6 +171,7 @@ def configure_logger(config: Config, handler_cls: str = "logging.FileHandler") - class LoggingMiddleware(BaseHTTPMiddleware): + @override async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: with RequestContext(request): response = await call_next(request) @@ -176,6 +179,7 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) - class ContextFilter(logging.Filter): + @override def filter(self, record: logging.LogRecord) -> bool: request: Optional[Request] = _request.get() request_id: Optional[str] = _request_id.get() diff --git a/antarest/core/requests.py b/antarest/core/requests.py index d276f79dca..055bbd8cdd 100644 --- a/antarest/core/requests.py +++ b/antarest/core/requests.py @@ -18,6 +18,7 @@ from fastapi import HTTPException from markupsafe import escape from ratelimit import Rule # type: ignore +from typing_extensions import override from antarest.core.jwt import JWTUser @@ -38,24 +39,30 @@ def __init__(self, data=None, **kwargs) -> None: # type: ignore data = {} self.update(data, **kwargs) + @override def __setitem__(self, key: str, value: t.Any) -> None: self._store[key.lower()] = (key, value) + @override def __getitem__(self, key: str) -> t.Any: return self._store[key.lower()][1] + @override def __delitem__(self, key: str) -> None: del self._store[key.lower()] + @override def __iter__(self) -> t.Any: return (casedkey for casedkey, mappedvalue in self._store.values()) + @override def __len__(self) -> int: return len(self._store) def lower_items(self) -> Generator[Tuple[Any, Any], Any, None]: return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()) + @override def __eq__(self, other: t.Any) -> bool: if isinstance(other, t.Mapping): other = CaseInsensitiveDict(other) @@ -66,6 +73,7 @@ def __eq__(self, other: t.Any) -> bool: def copy(self) -> "CaseInsensitiveDict": return CaseInsensitiveDict(self._store.values()) + @override def __repr__(self) -> str: return str(dict(self.items())) diff --git a/antarest/core/tasks/model.py b/antarest/core/tasks/model.py index 0b414b12c6..a533b73baf 100644 --- a/antarest/core/tasks/model.py +++ b/antarest/core/tasks/model.py @@ -18,6 +18,7 @@ from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, Sequence, String # type: ignore from sqlalchemy.engine.base import Engine # type: ignore from sqlalchemy.orm import relationship, sessionmaker # type: ignore +from typing_extensions import override from antarest.core.persistence import Base from antarest.core.serialization import AntaresBaseModel @@ -122,11 +123,13 @@ class TaskJobLog(Base): # type: ignore # If the TaskJob is deleted, all attached logs must also be deleted in cascade. job: "TaskJob" = relationship("TaskJob", back_populates="logs", uselist=False) + @override def __eq__(self, other: t.Any) -> bool: if not isinstance(other, TaskJobLog): return False return bool(other.id == self.id and other.message == self.message and other.task_id == self.task_id) + @override def __repr__(self) -> str: return f"id={self.id}, message={self.message}, task_id={self.task_id}" @@ -198,6 +201,7 @@ def to_dto(self, with_logs: bool = False) -> TaskDTO: progress=self.progress, ) + @override def __eq__(self, other: t.Any) -> bool: if not isinstance(other, TaskJob): return False @@ -213,6 +217,7 @@ def __eq__(self, other: t.Any) -> bool: and other.logs == self.logs ) + @override def __repr__(self) -> str: return ( f"id={self.id}," diff --git a/antarest/core/tasks/service.py b/antarest/core/tasks/service.py index a97a2fedf5..9b7efb8344 100644 --- a/antarest/core/tasks/service.py +++ b/antarest/core/tasks/service.py @@ -20,6 +20,7 @@ from fastapi import HTTPException from sqlalchemy.orm import Session # type: ignore +from typing_extensions import override from antarest.core.config import Config from antarest.core.interfaces.eventbus import Event, EventChannelDirectory, EventType, IEventBus @@ -108,9 +109,11 @@ def await_task(self, task_id: str, timeout_sec: int = DEFAULT_AWAIT_MAX_TIMEOUT) class NoopNotifier(ITaskNotifier): """This class is used in tasks when no notification is required.""" + @override def notify_message(self, message: str) -> None: return + @override def notify_progress(self, progress: int) -> None: return @@ -129,12 +132,14 @@ def __init__(self, task_id: str, session: Session, event_bus: IEventBus) -> None self.task_id = task_id self.event_bus = event_bus + @override def notify_message(self, message: str) -> None: task = self.session.query(TaskJob).get(self.task_id) if task: task.logs.append(TaskJobLog(message=message, task_id=self.task_id)) self.session.commit() + @override def notify_progress(self, progress: int) -> None: self.session.query(TaskJob).filter(TaskJob.id == self.task_id).update({TaskJob.progress: progress}) self.session.commit() @@ -215,6 +220,7 @@ def _send_worker_task(logger_: ITaskNotifier) -> TaskResult: def check_remote_worker_for_queue(self, task_queue: str) -> bool: return any(task_queue in rw.queues for rw in self.remote_workers) + @override def add_worker_task( self, task_type: TaskType, @@ -237,6 +243,7 @@ def add_worker_task( ) return str(task.id) + @override def add_task( self, action: Task, @@ -328,6 +335,7 @@ def _cancel_task(self, task_id: str, dispatch: bool = False) -> None: ) ) + @override def status_task( self, task_id: str, @@ -344,6 +352,7 @@ def status_task( detail=f"Failed to retrieve task {task_id} in db", ) + @override def list_tasks(self, task_filter: TaskListFilter, request_params: RequestParameters) -> t.List[TaskDTO]: return [task.to_dto() for task in self.list_db_tasks(task_filter, request_params)] @@ -353,6 +362,7 @@ def list_db_tasks(self, task_filter: TaskListFilter, request_params: RequestPara user = None if request_params.user.is_site_admin() else request_params.user.impersonator return self.repo.list(task_filter, user) + @override def await_task(self, task_id: str, timeout_sec: int = DEFAULT_AWAIT_MAX_TIMEOUT) -> None: if task_id in self.tasks: try: diff --git a/antarest/core/utils/fastapi_sqlalchemy/middleware.py b/antarest/core/utils/fastapi_sqlalchemy/middleware.py index 73a073e033..db18bc3efc 100644 --- a/antarest/core/utils/fastapi_sqlalchemy/middleware.py +++ b/antarest/core/utils/fastapi_sqlalchemy/middleware.py @@ -10,6 +10,7 @@ from starlette.requests import Request from starlette.responses import Response from starlette.types import ASGIApp +from typing_extensions import override from antarest.core.utils.fastapi_sqlalchemy.exceptions import MissingSessionError, SessionNotInitialisedError @@ -60,6 +61,7 @@ def __init__( _Session = sessionmaker(bind=engine, **session_args) + @override async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: with db(commit_on_exit=self.commit_on_exit): response = await call_next(request) diff --git a/antarest/core/utils/utils.py b/antarest/core/utils/utils.py index 2940db582a..0abe2a6fb4 100644 --- a/antarest/core/utils/utils.py +++ b/antarest/core/utils/utils.py @@ -20,6 +20,7 @@ from pathlib import Path from fastapi import HTTPException +from typing_extensions import override from antarest.core.exceptions import ShouldNotHappenException @@ -33,18 +34,22 @@ class DTO: Implement basic method for DTO objects """ + @override def __hash__(self) -> int: return hash(tuple(sorted(self.__dict__.items()))) + @override def __eq__(self, other: t.Any) -> bool: return isinstance(other, type(self)) and self.__dict__ == other.__dict__ + @override def __str__(self) -> str: return "{}({})".format( type(self).__name__, ", ".join(["{}={}".format(k, str(self.__dict__[k])) for k in sorted(self.__dict__)]), ) + @override def __repr__(self) -> str: return self.__str__() diff --git a/antarest/eventbus/business/local_eventbus.py b/antarest/eventbus/business/local_eventbus.py index bfe0e6992d..774278d5e4 100644 --- a/antarest/eventbus/business/local_eventbus.py +++ b/antarest/eventbus/business/local_eventbus.py @@ -13,6 +13,8 @@ import logging from typing import Dict, List, Optional +from typing_extensions import override + from antarest.core.interfaces.eventbus import Event from antarest.eventbus.business.interfaces import IEventBusBackend @@ -24,20 +26,25 @@ def __init__(self) -> None: self.events: List[Event] = [] self.queues: Dict[str, List[Event]] = {} + @override def push_event(self, event: Event) -> None: self.events.append(event) + @override def get_events(self) -> List[Event]: return self.events + @override def clear_events(self) -> None: self.events.clear() + @override def queue_event(self, event: Event, queue: str) -> None: if queue not in self.queues: self.queues[queue] = [] self.queues[queue].append(event) + @override def pull_queue(self, queue: str) -> Optional[Event]: if queue in self.queues and len(self.queues[queue]) > 0: return self.queues[queue].pop(0) diff --git a/antarest/eventbus/business/redis_eventbus.py b/antarest/eventbus/business/redis_eventbus.py index 8bbf6cbc38..db89c7bc68 100644 --- a/antarest/eventbus/business/redis_eventbus.py +++ b/antarest/eventbus/business/redis_eventbus.py @@ -14,6 +14,7 @@ from typing import List, Optional, cast from redis.client import Redis +from typing_extensions import override from antarest.core.interfaces.eventbus import Event from antarest.eventbus.business.interfaces import IEventBusBackend @@ -29,18 +30,22 @@ def __init__(self, redis_client: Redis) -> None: # type: ignore self.pubsub = self.redis.pubsub() self.pubsub.subscribe(REDIS_STORE_KEY) + @override def push_event(self, event: Event) -> None: self.redis.publish(REDIS_STORE_KEY, event.model_dump_json()) + @override def queue_event(self, event: Event, queue: str) -> None: self.redis.rpush(queue, event.model_dump_json()) + @override def pull_queue(self, queue: str) -> Optional[Event]: event = self.redis.lpop(queue) if event: return cast(Optional[Event], Event.parse_raw(event)) return None + @override def get_events(self) -> List[Event]: messages = [] try: @@ -60,6 +65,7 @@ def get_events(self) -> List[Event]: return events + @override def clear_events(self) -> None: # Nothing to do pass diff --git a/antarest/eventbus/service.py b/antarest/eventbus/service.py index eadf75e8c8..63b519e954 100644 --- a/antarest/eventbus/service.py +++ b/antarest/eventbus/service.py @@ -18,6 +18,8 @@ import uuid from typing import Awaitable, Callable, Dict, List, Optional +from typing_extensions import override + from antarest.core.interfaces.eventbus import Event, EventType, IEventBus from antarest.eventbus.business.interfaces import IEventBusBackend @@ -39,12 +41,15 @@ def __init__(self, backend: IEventBusBackend, autostart: bool = True) -> None: if autostart: self.start() + @override def push(self, event: Event) -> None: self.backend.push_event(event) + @override def queue(self, event: Event, queue: str) -> None: self.backend.queue_event(event, queue) + @override def add_queue_consumer(self, listener: Callable[[Event], Awaitable[None]], queue: str) -> str: with self.lock: listener_id = str(uuid.uuid4()) @@ -53,12 +58,14 @@ def add_queue_consumer(self, listener: Callable[[Event], Awaitable[None]], queue self.consumers[queue][listener_id] = listener return listener_id + @override def remove_queue_consumer(self, listener_id: str) -> None: with self.lock: for queue in self.consumers: if listener_id in self.consumers[queue]: del self.consumers[queue][listener_id] + @override def add_listener( self, listener: Callable[[Event], Awaitable[None]], @@ -71,6 +78,7 @@ def add_listener( self.listeners[listener_type][listener_id] = listener return listener_id + @override def remove_listener(self, listener_id: str) -> None: with self.lock: for listener_type in self.listeners: @@ -130,6 +138,7 @@ def _async_loop(self, new_loop: bool = True) -> None: loop = asyncio.new_event_loop() if new_loop else asyncio.get_event_loop() loop.run_until_complete(self._run_loop()) + @override def start(self, threaded: bool = True) -> None: if threaded: t = threading.Thread( diff --git a/antarest/front.py b/antarest/front.py index 16cd92544f..33314eb3f4 100644 --- a/antarest/front.py +++ b/antarest/front.py @@ -30,6 +30,7 @@ from starlette.responses import FileResponse from starlette.staticfiles import StaticFiles from starlette.types import ASGIApp +from typing_extensions import override from antarest.core.serialization import AntaresBaseModel from antarest.core.utils.string import to_camel_case @@ -76,6 +77,7 @@ def _path_matches_protected_paths(self, path: str) -> bool: return True return False + @override async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Any: """ Intercepts the incoming request and rewrites the URL path if necessary. diff --git a/antarest/launcher/adapters/local_launcher/local_launcher.py b/antarest/launcher/adapters/local_launcher/local_launcher.py index a3ad8fc703..30560977a7 100644 --- a/antarest/launcher/adapters/local_launcher/local_launcher.py +++ b/antarest/launcher/adapters/local_launcher/local_launcher.py @@ -23,6 +23,7 @@ from uuid import UUID from antares.study.version import SolverVersion +from typing_extensions import override from antarest.core.config import Config from antarest.core.interfaces.cache import ICache @@ -73,6 +74,7 @@ def _select_best_binary(self, version: str) -> Path: ) return antares_solver_path + @override def run_study( self, study_uuid: str, @@ -195,6 +197,7 @@ def stop_reading_output() -> bool: end = True shutil.rmtree(tmp_path) + @override def create_update_log(self, job_id: str) -> Callable[[str], None]: base_func = super().create_update_log(job_id) self.logs[job_id] = "" @@ -205,6 +208,7 @@ def append_to_log(log_line: str) -> None: return append_to_log + @override def get_log(self, job_id: str, log_type: LogType) -> Optional[str]: if job_id in self.job_id_to_study_id and job_id in self.logs: return self.logs[job_id] @@ -212,6 +216,7 @@ def get_log(self, job_id: str, log_type: LogType) -> Optional[str]: return self._get_job_final_output_path(job_id).read_text() return None + @override def kill_job(self, job_id: str) -> None: if job_id in self.job_id_to_study_id: return self.job_id_to_study_id[job_id][2].send_signal(signal.SIGTERM) diff --git a/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py b/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py index d4f5c30da8..0506ad5694 100644 --- a/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py +++ b/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py @@ -28,6 +28,7 @@ from antareslauncher.main_option_parser import MainOptionParser, ParserParameters from antareslauncher.study_dto import StudyDTO from filelock import FileLock +from typing_extensions import override from antarest.core.config import Config, NbCoresConfig, SlurmConfig, TimeLimitConfig from antarest.core.interfaces.cache import ICache @@ -589,6 +590,7 @@ def _apply_params(self, launcher_params: LauncherParametersDTO) -> argparse.Name return self.launcher_args + @override def run_study( self, study_uuid: str, @@ -604,6 +606,7 @@ def run_study( ) thread.start() + @override def get_log(self, job_id: str, log_type: LogType) -> t.Optional[str]: log_path: t.Optional[Path] = None for study in self.data_repo_tinydb.get_list_of_studies(): @@ -621,6 +624,7 @@ async def _listen_to_kill_job(event: Event) -> None: return _listen_to_kill_job + @override def kill_job(self, job_id: str, dispatch: bool = True) -> None: launcher_args = LauncherArgs(self.launcher_args) for study in self.data_repo_tinydb.get_list_of_studies(): diff --git a/antarest/launcher/extensions/adequacy_patch/extension.py b/antarest/launcher/extensions/adequacy_patch/extension.py index bb4d19f323..10f2f28f52 100644 --- a/antarest/launcher/extensions/adequacy_patch/extension.py +++ b/antarest/launcher/extensions/adequacy_patch/extension.py @@ -16,6 +16,7 @@ from typing import Any, Dict, List, cast import yaml +from typing_extensions import override from antarest.core.config import Config from antarest.core.model import JSON @@ -95,9 +96,11 @@ class AdequacyPatchExtension(ILauncherExtension): def __init__(self, study_service: StudyService, config: Config): self.study_service = study_service + @override def get_name(self) -> str: return AdequacyPatchExtension.EXTENSION_NAME + @override def after_export_flat_hook( self, job_id: str, @@ -129,6 +132,7 @@ def after_export_flat_hook( post_processing_file = Path(__file__).parent / "resources" / "post-processing.R" shutil.copy(post_processing_file, study_export_path / "post-processing.R") + @override def before_import_hook( self, job_id: str, diff --git a/antarest/launcher/model.py b/antarest/launcher/model.py index dbd90e3ef4..934b2b5753 100644 --- a/antarest/launcher/model.py +++ b/antarest/launcher/model.py @@ -17,6 +17,7 @@ from pydantic import Field from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, Sequence, String # type: ignore from sqlalchemy.orm import relationship # type: ignore +from typing_extensions import override from antarest.core.persistence import Base from antarest.core.serialization import AntaresBaseModel, from_json @@ -157,9 +158,11 @@ class JobLog(Base): # type: ignore # that the comparison is based on the database identity of the objects. # So, implementing `__eq__` and `__ne__` is not necessary. + @override def __str__(self) -> str: return f"Job log #{self.id} {self.log_type}: '{self.message}'" + @override def __repr__(self) -> str: return ( f" JobResultDTO: # that the comparison is based on the database identity of the objects. # So, implementing `__eq__` and `__ne__` is not necessary. + @override def __str__(self) -> str: return f"Job result #{self.id} (study '{self.study_id}'): {self.job_status}" + @override def __repr__(self) -> str: return ( f" str: def check(self, pwd: str) -> bool: return bcrypt.checkpw(pwd.encode(), self._pwd) + @override def __str__(self) -> str: return "*****" + @override def __repr__(self) -> str: return self.__str__() @@ -245,6 +248,7 @@ class Bot(Identity): owner = Column(Integer, ForeignKey("identities.id", name="bots_owner_fkey")) is_author = Column(Boolean(), default=True) + @override def get_impersonator(self) -> int: return int(self.id if self.is_author else self.owner) @@ -253,6 +257,7 @@ def get_impersonator(self) -> int: "inherit_condition": id == Identity.id, } + @override def to_dto(self) -> BotDTO: return BotDTO( id=self.id, @@ -286,6 +291,7 @@ def to_dto(self) -> GroupDTO: # Implementing a `__eq__` method is superfluous, since the default implementation # is to compare the identity of the objects using the primary key. + @override def __repr__(self) -> str: return f"Group(id={self.id}, name={self.name})" diff --git a/antarest/matrixstore/matrix_editor.py b/antarest/matrixstore/matrix_editor.py index 89bb866336..33bf780cab 100644 --- a/antarest/matrixstore/matrix_editor.py +++ b/antarest/matrixstore/matrix_editor.py @@ -15,6 +15,7 @@ from typing import Any, Dict, List, Optional, Tuple from pydantic import Field, field_validator, model_validator +from typing_extensions import override from antarest.core.serialization import AntaresBaseModel @@ -128,6 +129,7 @@ def compute(self, x: Any, use_coords: bool = False) -> Any: return x return OPERATIONS[self.operation](x, self.value) # type: ignore + @override def __str__(self) -> str: """Returns a string representation used in error messages.""" return f"['{self.operation}' {self.value}]" @@ -215,6 +217,7 @@ def validate_coordinates(cls, coordinates: Optional[List[Tuple[int, int]]]) -> O raise ValueError(f"Invalid coordinate {coordinate}: values must be greater than or equal to 0.") return coordinates + @override def __str__(self) -> str: """Returns a string representation used in error messages.""" diff --git a/antarest/matrixstore/matrix_garbage_collector.py b/antarest/matrixstore/matrix_garbage_collector.py index eecbf19f96..3d7e513b94 100644 --- a/antarest/matrixstore/matrix_garbage_collector.py +++ b/antarest/matrixstore/matrix_garbage_collector.py @@ -16,6 +16,8 @@ from pathlib import Path from typing import List, Set +from typing_extensions import override + from antarest.core.config import Config from antarest.core.interfaces.service import IService from antarest.core.utils.fastapi_sqlalchemy import db @@ -119,6 +121,7 @@ def _clean_matrices(self) -> None: self._delete_unused_saved_matrices(unused_matrices=unused_matrices) stopwatch.log_elapsed(lambda x: logger.info(f"Finished cleaning matrices in {x}s")) + @override def _loop(self) -> None: while True: try: diff --git a/antarest/matrixstore/model.py b/antarest/matrixstore/model.py index 2dccd350ab..a46dad9455 100644 --- a/antarest/matrixstore/model.py +++ b/antarest/matrixstore/model.py @@ -16,6 +16,7 @@ from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Table # type: ignore from sqlalchemy.orm import relationship # type: ignore +from typing_extensions import override from antarest.core.persistence import Base from antarest.core.serialization import AntaresBaseModel @@ -41,10 +42,12 @@ class Matrix(Base): # type: ignore height: int = Column(Integer) created_at: datetime.datetime = Column(DateTime) + @override def __repr__(self) -> str: # pragma: no cover """Returns a string representation of the matrix.""" return f"Matrix(id={self.id}, shape={(self.height, self.width)}, created_at={self.created_at})" + @override def __eq__(self, other: t.Any) -> bool: if not isinstance(other, Matrix): return False @@ -101,10 +104,12 @@ class MatrixDataSetRelation(Base): # type: ignore name: str = Column(String, primary_key=True) matrix: Matrix = relationship(Matrix) + @override def __repr__(self) -> str: # pragma: no cover """Returns a string representation of the matrix.""" return f"MatrixDataSetRelation(dataset_id={self.dataset_id}, matrix_id={self.matrix_id}, name={self.name})" + @override def __eq__(self, other: t.Any) -> bool: if not isinstance(other, MatrixDataSetRelation): return False @@ -172,6 +177,7 @@ def to_dto(self) -> MatrixDataSetDTO: updated_at=str(self.updated_at), ) + @override def __repr__(self) -> str: # pragma: no cover """Returns a string representation of the matrix.""" return ( @@ -183,6 +189,7 @@ def __repr__(self) -> str: # pragma: no cover f" updated_at={self.updated_at})" ) + @override def __eq__(self, other: t.Any) -> bool: if not isinstance(other, MatrixDataSet): return False diff --git a/antarest/matrixstore/service.py b/antarest/matrixstore/service.py index c2a8ca5c5d..055fbca413 100644 --- a/antarest/matrixstore/service.py +++ b/antarest/matrixstore/service.py @@ -24,6 +24,7 @@ import py7zr from fastapi import UploadFile from numpy import typing as npt +from typing_extensions import override from antarest.core.config import Config from antarest.core.filetransfer.model import FileDownloadTaskDTO @@ -112,9 +113,11 @@ class SimpleMatrixService(ISimpleMatrixService): def __init__(self, matrix_content_repository: MatrixContentRepository): super().__init__(matrix_content_repository=matrix_content_repository) + @override def create(self, data: t.Union[t.List[t.List[MatrixData]], npt.NDArray[np.float64]]) -> str: return self.matrix_content_repository.save(data) + @override def get(self, matrix_id: str) -> MatrixDTO: data = self.matrix_content_repository.get(matrix_id) return MatrixDTO.construct( @@ -126,9 +129,11 @@ def get(self, matrix_id: str) -> MatrixDTO: data=data.data, ) + @override def exists(self, matrix_id: str) -> bool: return self.matrix_content_repository.exists(matrix_id) + @override def delete(self, matrix_id: str) -> None: self.matrix_content_repository.delete(matrix_id) @@ -165,6 +170,7 @@ def _from_dto(dto: MatrixDTO) -> t.Tuple[Matrix, MatrixContent]: return matrix, content + @override def create(self, data: t.Union[t.List[t.List[MatrixData]], npt.NDArray[np.float64]]) -> str: """ Creates a new matrix object with the specified data. @@ -372,6 +378,7 @@ def delete_dataset(self, id: str, params: RequestParameters) -> str: self.repo_dataset.delete(id) return id + @override def get(self, matrix_id: str) -> t.Optional[MatrixDTO]: """ Get a matrix object from the database and the matrix content repository. @@ -397,6 +404,7 @@ def get(self, matrix_id: str) -> t.Optional[MatrixDTO]: data=content.data, ) + @override def exists(self, matrix_id: str) -> bool: """ Check if a matrix object exists in both the matrix content repository and the database. @@ -409,6 +417,7 @@ def exists(self, matrix_id: str) -> bool: """ return self.matrix_content_repository.exists(matrix_id) and self.repo.exists(matrix_id) + @override def delete(self, matrix_id: str) -> None: """ Delete a matrix object from the matrix content repository and the database. diff --git a/antarest/study/business/enum_ignore_case.py b/antarest/study/business/enum_ignore_case.py index 9d0bcf3396..56a06fabc1 100644 --- a/antarest/study/business/enum_ignore_case.py +++ b/antarest/study/business/enum_ignore_case.py @@ -13,6 +13,8 @@ import enum import typing +from typing_extensions import override + class EnumIgnoreCase(enum.StrEnum): """ @@ -35,6 +37,7 @@ class EnumIgnoreCase(enum.StrEnum): """ @classmethod + @override def _missing_(cls, value: object) -> typing.Optional["EnumIgnoreCase"]: if isinstance(value, str): for member in cls: diff --git a/antarest/study/business/scenario_builder_management.py b/antarest/study/business/scenario_builder_management.py index ce8834fbeb..71a7833cee 100644 --- a/antarest/study/business/scenario_builder_management.py +++ b/antarest/study/business/scenario_builder_management.py @@ -14,6 +14,7 @@ import typing as t import typing_extensions as te +from typing_extensions import override from antarest.study.business.utils import execute_or_add_commands from antarest.study.model import Study @@ -66,6 +67,7 @@ class ScenarioType(enum.StrEnum): HYDRO_FINAL_LEVEL = "hydroFinalLevels" HYDRO_GENERATION_POWER = "hydroGenerationPower" + @override def __str__(self) -> str: """Return the string representation of the enum value.""" return self.value diff --git a/antarest/study/business/table_mode_management.py b/antarest/study/business/table_mode_management.py index e7a12b0289..f5824d0296 100644 --- a/antarest/study/business/table_mode_management.py +++ b/antarest/study/business/table_mode_management.py @@ -16,6 +16,7 @@ import numpy as np import pandas as pd from antares.study.version import StudyVersion +from typing_extensions import override from antarest.core.exceptions import ChildNotFoundError from antarest.core.model import JSON @@ -61,6 +62,7 @@ class TableModeType(EnumIgnoreCase): BINDING_CONSTRAINT = "binding-constraints" @classmethod + @override def _missing_(cls, value: object) -> t.Optional["EnumIgnoreCase"]: if isinstance(value, str): # handle aliases of old table types diff --git a/antarest/study/model.py b/antarest/study/model.py index b8378aa356..9aed7c852a 100644 --- a/antarest/study/model.py +++ b/antarest/study/model.py @@ -31,6 +31,7 @@ String, ) from sqlalchemy.orm import relationship # type: ignore +from typing_extensions import override from antarest.core.exceptions import ShouldNotHappenException from antarest.core.model import PublicMode @@ -103,10 +104,12 @@ class StudyGroup(Base): # type:ignore group_id: str = Column(String(36), ForeignKey("groups.id", ondelete="CASCADE"), index=True, nullable=False) study_id: str = Column(String(36), ForeignKey("study.id", ondelete="CASCADE"), index=True, nullable=False) + @override def __str__(self) -> str: # pragma: no cover cls_name = self.__class__.__name__ return f"[{cls_name}] study_id={self.study_id}, group={self.group_id}" + @override def __repr__(self) -> str: # pragma: no cover cls_name = self.__class__.__name__ study_id = self.study_id @@ -129,10 +132,12 @@ class StudyTag(Base): # type:ignore study_id: str = Column(String(36), ForeignKey("study.id", ondelete="CASCADE"), index=True, nullable=False) tag_label: str = Column(String(40), ForeignKey("tag.label", ondelete="CASCADE"), index=True, nullable=False) + @override def __str__(self) -> str: # pragma: no cover cls_name = self.__class__.__name__ return f"[{cls_name}] study_id={self.study_id}, tag={self.tag}" + @override def __repr__(self) -> str: # pragma: no cover cls_name = self.__class__.__name__ study_id = self.study_id @@ -158,9 +163,11 @@ class Tag(Base): # type:ignore studies: t.List["Study"] = relationship("Study", secondary=StudyTag.__table__, back_populates="tags") + @override def __str__(self) -> str: # pragma: no cover return t.cast(str, self.label) + @override def __repr__(self) -> str: # pragma: no cover cls_name = self.__class__.__name__ label = self.label @@ -194,6 +201,7 @@ class StudyAdditionalData(Base): # type:ignore horizon = Column(String) patch = Column(String(), index=True, nullable=True) + @override def __eq__(self, other: t.Any) -> bool: if not super().__eq__(other): return False @@ -244,6 +252,7 @@ class Study(Base): # type: ignore __mapper_args__ = {"polymorphic_identity": "study", "polymorphic_on": type} + @override def __str__(self) -> str: cls = self.__class__.__name__ return ( @@ -258,6 +267,7 @@ def __str__(self) -> str: f" groups={[str(u) + ',' for u in self.groups]}" ) + @override def __eq__(self, other: t.Any) -> bool: if not isinstance(other, Study): return False @@ -299,6 +309,7 @@ class RawStudy(Study): "polymorphic_identity": "rawstudy", } + @override def __eq__(self, other: t.Any) -> bool: if not super().__eq__(other): return False diff --git a/antarest/study/service.py b/antarest/study/service.py index 3e198addb3..d394056f95 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -30,6 +30,7 @@ from fastapi import HTTPException, UploadFile from markupsafe import escape from starlette.responses import FileResponse, Response +from typing_extensions import override from antarest.core.config import Config from antarest.core.exceptions import ( @@ -212,6 +213,7 @@ class TaskProgressRecorder(ICommandListener): def __init__(self, notifier: ITaskNotifier) -> None: self.notifier = notifier + @override def notify_progress(self, progress: int) -> None: return self.notifier.notify_progress(progress) diff --git a/antarest/study/storage/abstract_storage_service.py b/antarest/study/storage/abstract_storage_service.py index 3b4c002597..f845eab757 100644 --- a/antarest/study/storage/abstract_storage_service.py +++ b/antarest/study/storage/abstract_storage_service.py @@ -18,6 +18,8 @@ from pathlib import Path from uuid import uuid4 +from typing_extensions import override + from antarest.core.config import Config from antarest.core.exceptions import BadOutputError, StudyOutputNotFoundError from antarest.core.interfaces.cache import CacheConstants, ICache @@ -63,6 +65,7 @@ def __init__( self.patch_service = patch_service self.cache = cache + @override def patch_update_study_metadata( self, study: T, @@ -82,6 +85,7 @@ def patch_update_study_metadata( remove_from_cache(self.cache, study.id) return self.get_study_information(study) + @override def get_study_information( self, study: T, @@ -129,6 +133,7 @@ def get_study_information( tags=[tag.label for tag in study.tags], ) + @override def get( self, metadata: T, @@ -170,6 +175,7 @@ def get( del study return data + @override def get_file( self, metadata: T, @@ -194,6 +200,7 @@ def get_file( return file_node.get_file_content() + @override def get_study_sim_result( self, study: T, @@ -243,6 +250,7 @@ def get_study_sim_result( ) return results + @override def import_output( self, metadata: T, @@ -302,6 +310,7 @@ def import_output( return output_full_name + @override def export_study(self, metadata: T, target: Path, outputs: bool = True) -> Path: """ Export and compress the study inside a 7zip file. @@ -326,6 +335,7 @@ def export_study(self, metadata: T, target: Path, outputs: bool = True) -> Path: ) return target + @override def export_output(self, metadata: T, output_id: str, target: Path) -> None: """ Export and compresses study inside zip @@ -358,6 +368,7 @@ def _read_additional_data_from_files(self, file_study: FileStudy) -> StudyAdditi study_additional_data = StudyAdditionalData(horizon=horizon, author=author, patch=patch.model_dump_json()) return study_additional_data + @override def archive_study_output(self, study: T, output_id: str) -> bool: try: archive_dir( @@ -375,6 +386,7 @@ def archive_study_output(self, study: T, output_id: str) -> bool: ) return False + @override def unarchive_study_output(self, study: T, output_id: str, keep_src_zip: bool) -> bool: if not (Path(study.path) / "output" / f"{output_id}{ArchiveFormat.ZIP}").exists(): logger.warning( diff --git a/antarest/study/storage/auto_archive_service.py b/antarest/study/storage/auto_archive_service.py index 8dbf6c3de0..5efd2dda1c 100644 --- a/antarest/study/storage/auto_archive_service.py +++ b/antarest/study/storage/auto_archive_service.py @@ -15,6 +15,8 @@ import time import typing as t +from typing_extensions import override + from antarest.core.config import Config from antarest.core.exceptions import TaskAlreadyRunning from antarest.core.interfaces.service import IService @@ -90,6 +92,7 @@ def _try_archive_studies(self) -> None: params=RequestParameters(DEFAULT_ADMIN_USER), ) + @override def _loop(self) -> None: while True: try: diff --git a/antarest/study/storage/df_download.py b/antarest/study/storage/df_download.py index 97882e2d2e..f1c4b80a3f 100644 --- a/antarest/study/storage/df_download.py +++ b/antarest/study/storage/df_download.py @@ -17,6 +17,7 @@ import pandas as pd from fastapi import HTTPException from starlette.responses import FileResponse +from typing_extensions import override from antarest.core.filetransfer.model import FileDownloadNotFound from antarest.core.filetransfer.service import FileTransferManager @@ -33,6 +34,7 @@ class TableExportFormat(EnumIgnoreCase): CSV = "csv" CSV_SEMICOLON = "csv (semicolon)" + @override def __str__(self) -> str: """Return the format as a string for display.""" return self.value.title() diff --git a/antarest/study/storage/rawstudy/ini_reader.py b/antarest/study/storage/rawstudy/ini_reader.py index fd3bac2dea..e51d9c9672 100644 --- a/antarest/study/storage/rawstudy/ini_reader.py +++ b/antarest/study/storage/rawstudy/ini_reader.py @@ -16,6 +16,8 @@ from abc import ABC, abstractmethod from pathlib import Path +from typing_extensions import override + from antarest.core.model import JSON @@ -168,6 +170,7 @@ def __init__(self, special_keys: t.Sequence[str] = (), section_name: str = "sett # Current option name used during paring self._curr_option = "" + @override def __repr__(self) -> str: # pragma: no cover """Return a string representation of the object.""" cls = self.__class__.__name__ @@ -176,6 +179,7 @@ def __repr__(self) -> str: # pragma: no cover section_name = getattr(self, "_section_name", "settings") return f"{cls}(special_keys={special_keys!r}, section_name={section_name!r})" + @override def read(self, path: t.Any, **kwargs: t.Any) -> JSON: if isinstance(path, (Path, str)): try: @@ -321,6 +325,7 @@ class SimpleKeyValueReader(IniReader): Simple INI reader for "settings.ini" file which has no section. """ + @override def read(self, path: t.Any, **kwargs: t.Any) -> JSON: """ Parse `.ini` file which has no section to JSON object. diff --git a/antarest/study/storage/rawstudy/ini_writer.py b/antarest/study/storage/rawstudy/ini_writer.py index f72f9b2197..d4ba73cf5d 100644 --- a/antarest/study/storage/rawstudy/ini_writer.py +++ b/antarest/study/storage/rawstudy/ini_writer.py @@ -15,6 +15,8 @@ import typing as t from pathlib import Path +from typing_extensions import override + from antarest.core.model import JSON @@ -24,6 +26,7 @@ def __init__(self, special_keys: t.Optional[t.List[str]] = None) -> None: self.special_keys = special_keys # noinspection SpellCheckingInspection + @override def optionxform(self, optionstr: str) -> str: return optionstr @@ -89,6 +92,7 @@ class SimpleKeyValueWriter(IniWriter): Simple key/value INI writer. """ + @override def write(self, data: JSON, path: Path) -> None: """ Write `.ini` file from JSON content diff --git a/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py b/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py index ad10455b2e..3def015763 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.core.model import JSON, SUB_JSON from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -54,6 +56,7 @@ def _get_registered_file_by_key(self, key: str) -> t.Optional[RegisteredFile]: def _get_registered_file_by_filename(self, filename: str) -> t.Optional[RegisteredFile]: return next((rf for rf in self.registered_files if rf.filename == filename), None) + @override def save( self, data: SUB_JSON, @@ -93,6 +96,7 @@ def _save(self, data: SUB_JSON, key: str) -> None: elif isinstance(data, dict): BucketNode(self.context, self.config.next_file(key)).save(data) + @override def build(self) -> TREE: if not self.config.path.is_dir(): return {} @@ -110,6 +114,7 @@ def build(self) -> TREE: return children + @override def check_errors( self, data: JSON, diff --git a/antarest/study/storage/rawstudy/model/filesystem/common/area_matrix_list.py b/antarest/study/storage/rawstudy/model/filesystem/common/area_matrix_list.py index 0cff5af838..e4022a3600 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/common/area_matrix_list.py +++ b/antarest/study/storage/rawstudy/model/filesystem/common/area_matrix_list.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -66,6 +68,7 @@ def __init__( self.matrix_class = matrix_class self.additional_matrix_params = additional_matrix_params or {} + @override def build(self) -> TREE: """ Builds the folder structure and creates child nodes representing each matrix file. @@ -100,6 +103,7 @@ def __init__( self.area = area self.matrix_class = matrix_class + @override def build(self) -> TREE: children: TREE = { "ror": self.matrix_class(self.context, self.config.next_file("ror.txt")), @@ -118,6 +122,7 @@ def __init__( super().__init__(context, config) self.matrix_class = matrix_class + @override def build(self) -> TREE: """Builds the folder structure and creates child nodes representing each matrix file.""" return { @@ -138,6 +143,7 @@ def __init__( self.area = area self.matrix_class = matrix_class + @override def build(self) -> TREE: # Note that cluster IDs are case-insensitive, but series IDs are in lower case. # For instance, if your cluster ID is "Base", then the series ID will be "base". @@ -185,6 +191,7 @@ def __init__( self.klass = klass self.matrix_class = matrix_class + @override def build(self) -> TREE: folders = [d.name for d in self.config.path.iterdir() if d.is_dir()] children: TREE = { diff --git a/antarest/study/storage/rawstudy/model/filesystem/common/prepro.py b/antarest/study/storage/rawstudy/model/filesystem/common/prepro.py index 1813760f13..b18d53b81d 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/common/prepro.py +++ b/antarest/study/storage/rawstudy/model/filesystem/common/prepro.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -44,6 +45,7 @@ def __init__(self, context: ContextServer, config: FileStudyTreeConfig): class PreproArea(FolderNode): + @override def build(self) -> TREE: children: TREE = { "conversion": InputSeriesMatrix(self.context, self.config.next_file("conversion.txt")), @@ -56,6 +58,7 @@ def build(self) -> TREE: class InputPrepro(FolderNode): + @override def build(self) -> TREE: children: TREE = {a: PreproArea(self.context, self.config.next_file(a)) for a in self.config.area_names()} children["correlation"] = PreproCorrelation(self.context, self.config.next_file("correlation.ini")) diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/area.py b/antarest/study/storage/rawstudy/model/filesystem/config/area.py index 74d15e5b55..db83868816 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/area.py @@ -17,6 +17,7 @@ import typing as t from pydantic import Field, field_validator, model_validator +from typing_extensions import override from antarest.study.business.enum_ignore_case import EnumIgnoreCase from antarest.study.storage.rawstudy.model.filesystem.config.field_validators import ( @@ -185,6 +186,7 @@ def _validate_color_rgb(cls, v: t.Any) -> str: def _validate_colors(cls, values: t.MutableMapping[str, t.Any]) -> t.Mapping[str, t.Any]: return validate_colors(values) + @override def to_config(self) -> t.Dict[str, t.Any]: """ Convert the object to a dictionary for writing to a configuration file: @@ -342,6 +344,7 @@ def _validate_layers(cls, values: t.MutableMapping[str, t.Any]) -> t.Mapping[str return values + @override def to_config(self) -> t.Dict[str, t.Dict[str, t.Any]]: """ Convert the object to a dictionary for writing to a configuration file: diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/exceptions.py b/antarest/study/storage/rawstudy/model/filesystem/config/exceptions.py index 936f7f76e2..3a903d9cf4 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/exceptions.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/exceptions.py @@ -13,6 +13,8 @@ from pathlib import Path from typing import cast +from typing_extensions import override + class BaseConfigError(Exception): """Base class of the configuration errors.""" @@ -30,6 +32,7 @@ def output_path(self) -> Path: def reason(self) -> str: return cast(str, self.args[1]) + @override def __str__(self) -> str: output_path = self.output_path reason = self.reason @@ -48,6 +51,7 @@ def xpansion_json(self) -> Path: def reason(self) -> str: return cast(str, self.args[1]) + @override def __str__(self) -> str: xpansion_json = self.xpansion_json reason = self.reason diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/ini_properties.py b/antarest/study/storage/rawstudy/model/filesystem/config/ini_properties.py index c5c3c83950..abbf6fb77b 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/ini_properties.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/ini_properties.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.core.serialization import AntaresBaseModel, from_json, to_json @@ -52,6 +54,7 @@ def to_config(self) -> t.Dict[str, t.Any]: return config @classmethod + @override def construct(cls, _fields_set: t.Optional[t.Set[str]] = None, **values: t.Any) -> "IniProperties": """ Construct a new model instance from a dict of values, replacing aliases with real field names. diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/model.py b/antarest/study/storage/rawstudy/model/filesystem/config/model.py index 938cddaba3..bd35498e38 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/model.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/model.py @@ -16,6 +16,7 @@ from antares.study.version import StudyVersion from pydantic import Field, model_validator +from typing_extensions import override from antarest.core.serialization import AntaresBaseModel from antarest.core.utils.utils import DTO @@ -47,6 +48,7 @@ class EnrModelling(EnumIgnoreCase): AGGREGATED = "aggregated" CLUSTERS = "clusters" + @override def __str__(self) -> str: """Return the string representation of the enum value.""" return self.value diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/renewable.py b/antarest/study/storage/rawstudy/model/filesystem/config/renewable.py index dcd7e6f16c..d9f4f9897e 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/renewable.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/renewable.py @@ -14,6 +14,7 @@ from antares.study.version import StudyVersion from pydantic import Field +from typing_extensions import override from antarest.study.business.enum_ignore_case import EnumIgnoreCase from antarest.study.model import STUDY_VERSION_8_1 @@ -54,10 +55,12 @@ class RenewableClusterGroup(EnumIgnoreCase): OTHER3 = "other res 3" OTHER4 = "other res 4" + @override def __repr__(self) -> str: return f"{self.__class__.__name__}.{self.name}" @classmethod + @override def _missing_(cls, value: object) -> t.Optional["RenewableClusterGroup"]: """ Retrieves the default group or the matched group when an unknown value is encountered. diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/ruleset_matrices.py b/antarest/study/storage/rawstudy/model/filesystem/config/ruleset_matrices.py index 6ed47a3e17..ca9ff2e724 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/ruleset_matrices.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/ruleset_matrices.py @@ -15,6 +15,7 @@ import numpy as np import pandas as pd import typing_extensions as te +from typing_extensions import override SCENARIO_TYPES = { "l": "load", @@ -107,6 +108,7 @@ def __init__( self.scenarios: _ScenarioMapping = {} self._setup() + @override def __str__(self) -> str: lines = [] for symbol, scenario_type in self.scenario_types.items(): diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py b/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py index 5093c9c289..78794052f9 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/thermal.py @@ -14,6 +14,7 @@ from antares.study.version import StudyVersion from pydantic import Field, ValidationError +from typing_extensions import override from antarest.study.business.enum_ignore_case import EnumIgnoreCase from antarest.study.storage.rawstudy.model.filesystem.config.cluster import ClusterProperties @@ -35,6 +36,7 @@ class LocalTSGenerationBehavior(EnumIgnoreCase): FORCE_NO_GENERATION = "force no generation" FORCE_GENERATION = "force generation" + @override def __repr__(self) -> str: # pragma: no cover return f"{self.__class__.__name__}.{self.name}" @@ -48,6 +50,7 @@ class LawOption(EnumIgnoreCase): UNIFORM = "uniform" GEOMETRIC = "geometric" + @override def __repr__(self) -> str: # pragma: no cover return f"{self.__class__.__name__}.{self.name}" @@ -69,10 +72,12 @@ class ThermalClusterGroup(EnumIgnoreCase): OTHER3 = "other 3" OTHER4 = "other 4" + @override def __repr__(self) -> str: # pragma: no cover return f"{self.__class__.__name__}.{self.name}" @classmethod + @override def _missing_(cls, value: object) -> t.Optional["ThermalClusterGroup"]: """ Retrieves the default group or the matched group when an unknown value is encountered. diff --git a/antarest/study/storage/rawstudy/model/filesystem/folder_node.py b/antarest/study/storage/rawstudy/model/filesystem/folder_node.py index 974c2acdfa..c8b3604e88 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/folder_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/folder_node.py @@ -14,6 +14,8 @@ import typing as t from abc import ABC, abstractmethod +from typing_extensions import override + from antarest.core.exceptions import ChildNotFoundError, PathIsAFolderError from antarest.core.model import JSON, SUB_JSON from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig @@ -114,6 +116,7 @@ def _get( else: return self._expand_get(depth, formatted, get_node) + @override def get( self, url: t.Optional[t.List[str]] = None, @@ -125,6 +128,7 @@ def get( assert not isinstance(output, INode) return output + @override def get_node( self, url: t.Optional[t.List[str]] = None, @@ -133,6 +137,7 @@ def get_node( assert isinstance(output, INode) return output + @override def save( self, data: SUB_JSON, @@ -151,6 +156,7 @@ def save( for key in data: children[key].save(data[key]) + @override def delete(self, url: t.Optional[t.List[str]] = None) -> None: if url and url != [""]: children = self.build() @@ -160,6 +166,7 @@ def delete(self, url: t.Optional[t.List[str]] = None) -> None: elif self.config.path.exists(): shutil.rmtree(self.config.path) + @override def check_errors( self, data: JSON, @@ -183,10 +190,12 @@ def check_errors( errors += children[key].check_errors(data[key], raising=raising) return errors + @override def normalize(self) -> None: for child in self.build().values(): child.normalize() + @override def denormalize(self) -> None: for child in self.build().values(): child.denormalize() @@ -217,6 +226,7 @@ def extract_child(self, children: TREE, url: t.List[str]) -> t.Tuple[t.List[str] raise FilterError("Filter selection has different classes") return names, sub_url + @override def get_file_content(self) -> OriginalFile: relative_path = self.config.path.relative_to(self.config.study_path).as_posix() raise PathIsAFolderError(f"Node at {relative_path} is a folder node.") diff --git a/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py b/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py index 55a8645ab6..dda7a2a6c0 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py @@ -23,6 +23,7 @@ import py7zr import pydantic_core from filelock import FileLock +from typing_extensions import override from antarest.core.exceptions import ShouldNotHappenException from antarest.core.model import JSON, SUB_JSON @@ -168,6 +169,7 @@ def _get_filtering_kwargs(self, url: t.List[str]) -> t.Dict[str, str]: else: return {} + @override def get( self, url: t.Optional[t.List[str]] = None, @@ -179,6 +181,7 @@ def get( assert not isinstance(output, INode) return output + @override def get_node( self, url: t.Optional[t.List[str]] = None, @@ -187,6 +190,7 @@ def get_node( assert isinstance(output, INode) return output + @override def save(self, data: SUB_JSON, url: t.Optional[t.List[str]] = None) -> None: self._assert_not_in_zipped_file() url = url or [] @@ -212,6 +216,7 @@ def save(self, data: SUB_JSON, url: t.Optional[t.List[str]] = None) -> None: self.writer.write(info, self.path) @log_warning + @override def delete(self, url: t.Optional[t.List[str]] = None) -> None: """ Deletes the specified section or key from the INI file, @@ -274,6 +279,7 @@ def delete(self, url: t.Optional[t.List[str]] = None) -> None: self.writer.write(data, self.path) + @override def check_errors( self, data: JSON, @@ -292,9 +298,11 @@ def check_errors( return errors + @override def normalize(self) -> None: pass # no external store in this node + @override def denormalize(self) -> None: pass # no external store in this node diff --git a/antarest/study/storage/rawstudy/model/filesystem/json_file_node.py b/antarest/study/storage/rawstudy/model/filesystem/json_file_node.py index 54333e2c4b..ca877e9fd6 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/json_file_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/json_file_node.py @@ -14,6 +14,8 @@ import typing as t from pathlib import Path +from typing_extensions import override + from antarest.core.model import JSON from antarest.core.serialization import from_json, to_json from antarest.study.storage.rawstudy.ini_reader import IReader @@ -28,6 +30,7 @@ class JsonReader(IReader): JSON file reader. """ + @override def read(self, path: t.Any, **kwargs: t.Any) -> JSON: content: t.Union[str, bytes] @@ -59,6 +62,7 @@ class JsonWriter(IniWriter): JSON file writer. """ + @override def write(self, data: JSON, path: Path) -> None: with open(path, "wb") as fh: fh.write(to_json(data)) diff --git a/antarest/study/storage/rawstudy/model/filesystem/lazy_node.py b/antarest/study/storage/rawstudy/model/filesystem/lazy_node.py index 296f3efc13..d442d9d732 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/lazy_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/lazy_node.py @@ -16,6 +16,8 @@ from pathlib import Path from zipfile import ZipFile +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer from antarest.study.storage.rawstudy.model.filesystem.inode import G, INode, S, V @@ -92,6 +94,7 @@ def _get( else: return self.load(url, depth, expanded, formatted) + @override def get( self, url: t.Optional[t.List[str]] = None, @@ -103,6 +106,7 @@ def get( assert not isinstance(output, INode) return output + @override def get_node( self, url: t.Optional[t.List[str]] = None, @@ -111,6 +115,7 @@ def get_node( assert isinstance(output, INode) return output + @override def delete(self, url: t.Optional[t.List[str]] = None) -> None: self._assert_url_end(url) if self.get_link_path().exists(): @@ -122,6 +127,7 @@ def get_link_path(self) -> Path: path = self.config.path.parent / (self.config.path.name + ".link") return path + @override def save(self, data: t.Union[str, bytes, S], url: t.Optional[t.List[str]] = None) -> None: self._assert_not_in_zipped_file() self._assert_url_end(url) diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/date_serializer.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/date_serializer.py index 2b8c431085..ef856c5f91 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/date_serializer.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/date_serializer.py @@ -17,6 +17,7 @@ from typing import Hashable, List, Sequence, Tuple, cast import pandas as pd +from typing_extensions import override class IDateMatrixSerializer(ABC): @@ -80,6 +81,7 @@ class HourlyMatrixSerializer(IDateMatrixSerializer): Class implementation for hourly index """ + @override def build_date(self, index: pd.Index[str]) -> pd.DataFrame: def _map(row: str) -> Tuple[str, int, str, str, str]: m, d, h = re.split(r"[\s/]", row) @@ -99,6 +101,7 @@ def _map(row: str) -> Tuple[str, int, str, str, str]: return pd.concat([headers, matrix], axis=0) + @override def extract_date(self, df: pd.DataFrame) -> Tuple[pd.Index[str], pd.DataFrame]: # Extract left part with date df_date = df.iloc[:, 2:5] @@ -118,6 +121,7 @@ class DailyMatrixSerializer(IDateMatrixSerializer): Class implementation for daily index """ + @override def build_date(self, index: pd.Index[str]) -> pd.DataFrame: def _map(row: str) -> Tuple[str, int, str, str]: m, d = row.split("/") @@ -137,6 +141,7 @@ def _map(row: str) -> Tuple[str, int, str, str]: return pd.concat([headers, matrix], axis=0) + @override def extract_date(self, df: pd.DataFrame) -> Tuple[pd.Index[str], pd.DataFrame]: # Extract left part with date df_date = df.iloc[:, 2:4] @@ -156,6 +161,7 @@ class WeeklyMatrixSerializer(IDateMatrixSerializer): Class implementation for weekly index """ + @override def build_date(self, index: pd.Index[str]) -> pd.DataFrame: matrix = pd.DataFrame({0: [""] * index.size, 1: index.values}) @@ -169,6 +175,7 @@ def build_date(self, index: pd.Index[str]) -> pd.DataFrame: return pd.concat([headers, matrix], axis=0) + @override def extract_date(self, df: pd.DataFrame) -> Tuple[pd.Index[str], pd.DataFrame]: # Extract left part with date df_date = df.iloc[:, 1:2] @@ -186,6 +193,7 @@ class MonthlyMatrixSerializer(IDateMatrixSerializer): Class implementation for monthly index """ + @override def build_date(self, index: pd.Index[str]) -> pd.DataFrame: matrix = pd.DataFrame( { @@ -205,6 +213,7 @@ def build_date(self, index: pd.Index[str]) -> pd.DataFrame: return pd.concat([headers, matrix], axis=0) + @override def extract_date(self, df: pd.DataFrame) -> Tuple[pd.Index[str], pd.DataFrame]: # Extract left part with date df_date = df.iloc[:, 2:3] @@ -224,6 +233,7 @@ class AnnualMatrixSerializer(IDateMatrixSerializer): Class implementation for annual index """ + @override def build_date(self, index: pd.Index[str]) -> pd.DataFrame: return pd.DataFrame( [ @@ -234,6 +244,7 @@ def build_date(self, index: pd.Index[str]) -> pd.DataFrame: ] ) + @override def extract_date(self, df: pd.DataFrame) -> Tuple[pd.Index[str], pd.DataFrame]: # Extract left part with date df_date = df.iloc[:, 1:2] diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/head_writer.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/head_writer.py index 5909f69ba7..7c8d2fd588 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/head_writer.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/head_writer.py @@ -12,6 +12,8 @@ from abc import ABC, abstractmethod +from typing_extensions import override + class HeadWriter(ABC): """ @@ -43,6 +45,7 @@ def __init__(self, area: str, data_type: str, freq: str): \tVARIABLES\tBEGIN\tEND """ + @override def build(self, var: int, end: int, start: int = 1) -> str: return self.head + f"\t{var}\t{start}\t{end}\n\n" @@ -57,5 +60,6 @@ def __init__(self, src: str, dest: str, freq: str): {dest.upper()}\tVARIABLES\tBEGIN\tEND """ + @override def build(self, var: int, end: int, start: int = 1) -> str: return self.head + f"\t{var}\t{start}\t{end}\n\n" diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py index ec9d04a2a9..d2ac83c19c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py @@ -19,6 +19,7 @@ import pandas as pd from numpy import typing as npt from pandas.errors import EmptyDataError +from typing_extensions import override from antarest.core.exceptions import ChildNotFoundError from antarest.core.model import JSON @@ -89,6 +90,7 @@ def parse_as_dataframe(self, file_path: t.Optional[Path] = None) -> pd.DataFrame final_matrix = pd.DataFrame(self.default_empty) return final_matrix + @override def parse_as_json(self, file_path: t.Optional[Path] = None) -> JSON: df = self.parse_as_dataframe(file_path) stopwatch = StopWatch() @@ -96,6 +98,7 @@ def parse_as_json(self, file_path: t.Optional[Path] = None) -> JSON: stopwatch.log_elapsed(lambda x: logger.info(f"Matrix to dict in {x}s")) return data + @override def check_errors( self, data: JSON, @@ -128,6 +131,7 @@ def copy_file(self, target: str) -> None: target_path.unlink(missing_ok=True) shutil.copy(self._infer_path(), target_path) + @override def get_file_content(self) -> OriginalFile: suffix = self.config.path.suffix filename = self.config.path.name diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/matrix.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/matrix.py index 6af089a8a5..7897715f92 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/matrix.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/matrix.py @@ -17,6 +17,7 @@ from typing import List, Optional, Union, cast import pandas as pd +from typing_extensions import override from antarest.core.model import JSON from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig @@ -64,6 +65,7 @@ def __init__( LazyNode.__init__(self, context, config) self.freq = freq + @override def get_lazy_content( self, url: Optional[List[str]] = None, @@ -72,6 +74,7 @@ def get_lazy_content( ) -> str: return f"matrixfile://{self.config.path.name}" + @override def normalize(self) -> None: # noinspection SpellCheckingInspection """ @@ -95,6 +98,7 @@ def normalize(self) -> None: self.get_link_path().write_text(self.context.resolver.build_matrix_uri(uuid)) self.config.path.unlink() + @override def denormalize(self) -> None: """ Read the matrix ID from the matrix link, retrieve the original matrix @@ -114,6 +118,7 @@ def denormalize(self) -> None: self.dump(matrix) self.get_link_path().unlink() + @override def load( self, url: Optional[List[str]] = None, @@ -140,6 +145,7 @@ def parse_as_json(self, file_path: Optional[Path] = None) -> JSON: """ raise NotImplementedError() + @override def dump( self, data: Union[bytes, JSON], diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py index 52c9867b2f..c3b66d1245 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py @@ -16,6 +16,7 @@ import pandas as pd from pandas import DataFrame +from typing_extensions import override from antarest.core.exceptions import ChildNotFoundError, MustNotModifyOutputException from antarest.core.model import JSON @@ -56,6 +57,7 @@ def __init__( self.head_writer = head_writer self.freq = freq + @override def get_lazy_content( self, url: Optional[List[str]] = None, @@ -106,6 +108,7 @@ def parse( matrix = self.parse_dataframe(file_path, tmp_dir) return cast(JSON, matrix.to_dict(orient="split")) + @override def check_errors( self, data: JSON, @@ -119,6 +122,7 @@ def check_errors( errors.append(f"Output Series Matrix f{self.config.path} not exists") return errors + @override def load( self, url: Optional[List[str]] = None, @@ -148,12 +152,15 @@ def load( f"Output file '{self.config.path.name}' not found in study {self.config.study_id}" ) from e + @override def dump(self, data: Union[bytes, JSON], url: Optional[List[str]] = None) -> None: raise MustNotModifyOutputException(self.config.path.name) + @override def normalize(self) -> None: pass # no external store in this node + @override def denormalize(self) -> None: pass # no external store in this node diff --git a/antarest/study/storage/rawstudy/model/filesystem/raw_file_node.py b/antarest/study/storage/rawstudy/model/filesystem/raw_file_node.py index c92f3d9152..7752e93e0c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/raw_file_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/raw_file_node.py @@ -13,6 +13,8 @@ import logging from typing import List, Optional +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer from antarest.study.storage.rawstudy.model.filesystem.lazy_node import LazyNode @@ -28,6 +30,7 @@ class RawFileNode(LazyNode[bytes, bytes, str]): def __init__(self, context: ContextServer, config: FileStudyTreeConfig): LazyNode.__init__(self, config=config, context=context) + @override def get_lazy_content( self, url: Optional[List[str]] = None, @@ -36,6 +39,7 @@ def get_lazy_content( ) -> str: return f"file://{self.config.path.name}" + @override def load( self, url: Optional[List[str]] = None, @@ -56,10 +60,12 @@ def load( return bytes + @override def dump(self, data: bytes, url: Optional[List[str]] = None) -> None: self.config.path.parent.mkdir(exist_ok=True, parents=True) self.config.path.write_bytes(data) + @override def check_errors(self, data: str, url: Optional[List[str]] = None, raising: bool = False) -> List[str]: if not self.config.path.exists(): msg = f"{self.config.path} not exist" @@ -68,8 +74,10 @@ def check_errors(self, data: str, url: Optional[List[str]] = None, raising: bool return [msg] return [] + @override def normalize(self) -> None: pass # no external store in this node + @override def denormalize(self) -> None: pass # no external store in this node diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py b/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py index bfef345ccc..409c8aac7f 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py @@ -12,6 +12,8 @@ import logging +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE from antarest.study.storage.rawstudy.model.filesystem.root.desktop import Desktop @@ -31,6 +33,7 @@ class FileStudyTree(FolderNode): Top level node of antares tree structure """ + @override def build(self) -> TREE: children: TREE = { "Desktop": Desktop(self.context, self.config.next_file("Desktop.ini")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/areas.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/areas.py index 7dadadcc87..c9dd2b4e41 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/areas.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/areas.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -23,6 +24,7 @@ class InputAreas(FolderNode): def __init__(self, context: ContextServer, config: FileStudyTreeConfig): super().__init__(context, config, ["list", "sets"]) + @override def build(self) -> TREE: children: TREE = {a: InputAreasItem(self.context, self.config.next_file(a)) for a in self.config.area_names()} children["list"] = InputAreasList(self.context, self.config.next_file("list.txt")) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/item/item.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/item/item.py index 5ea6ad808a..822e3f80a3 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/item/item.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/item/item.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.model import STUDY_VERSION_8_3 from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -21,6 +22,7 @@ class InputAreasItem(FolderNode): + @override def build(self) -> TREE: children: TREE = { "ui": InputAreasUi(self.context, self.config.next_file("ui.ini")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/list.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/list.py index 04564300c6..cdc26f097e 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/list.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/areas/list.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.core.utils.archives import extract_lines_from_archive from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -21,9 +23,11 @@ class InputAreasList(INode[t.List[str], t.List[str], t.List[str]]): + @override def normalize(self) -> None: pass # no external store in this node + @override def denormalize(self) -> None: pass # no external store in this node @@ -31,6 +35,7 @@ def __init__(self, context: ContextServer, config: FileStudyTreeConfig): super().__init__(config) self.context = context + @override def get_node( self, url: t.Optional[t.List[str]] = None, @@ -40,6 +45,7 @@ def get_node( ) -> INode[t.List[str], t.List[str], t.List[str]]: return self + @override def get( self, url: t.Optional[t.List[str]] = None, @@ -53,14 +59,17 @@ def get( lines = self.config.path.read_text().split("\n") return [l.strip() for l in lines if l.strip()] + @override def save(self, data: t.List[str], url: t.Optional[t.List[str]] = None) -> None: self._assert_not_in_zipped_file() self.config.path.write_text("\n".join(data)) + @override def delete(self, url: t.Optional[t.List[str]] = None) -> None: if self.config.path.exists(): self.config.path.unlink() + @override def check_errors( self, data: t.List[str], diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/bindingconstraints/bindingcontraints.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/bindingconstraints/bindingcontraints.py index 28dba53eb5..fedaa47d54 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/bindingconstraints/bindingcontraints.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/bindingconstraints/bindingcontraints.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.binding_constraint import ( OPERATOR_MATRICES_MAP, @@ -41,6 +42,7 @@ class BindingConstraints(FolderNode): configuration and matrices. """ + @override def build(self) -> TREE: cfg = self.config frequency_mapping = { diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/commons/prepro_series.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/commons/prepro_series.py index 277e2311be..74c99bf04b 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/commons/prepro_series.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/commons/prepro_series.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.common.area_matrix_list import AreaMatrixList from antarest.study.storage.rawstudy.model.filesystem.common.prepro import InputPrepro @@ -51,6 +52,7 @@ def __init__(self, context: ContextServer, config: FileStudyTreeConfig, prefix: super().__init__(context, config) self.prefix = prefix + @override def build(self) -> TREE: children: TREE = { "prepro": InputPrepro(self.context, self.config.next_file("prepro")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/allocation/allocation.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/allocation/allocation.py index 0714f710a5..afa09c4c0e 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/allocation/allocation.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/allocation/allocation.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class InputHydroAllocation(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputHydroAllocationArea(self.context, self.config.next_file(f"{a}.ini"), area=a) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/capacity/capacity.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/capacity/capacity.py index 56eeceadd2..33a6e999e7 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/capacity/capacity.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/capacity/capacity.py @@ -13,6 +13,7 @@ from typing import List, TypedDict from antares.study.version import StudyVersion +from typing_extensions import override from antarest.study.model import STUDY_VERSION_6_5 from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -59,6 +60,7 @@ class MatrixInfo(TypedDict, total=False): class InputHydroCommonCapacity(FolderNode): + @override def build(self) -> TREE: children: TREE = {} for info in MATRICES_INFO: diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/common.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/common.py index 46715ff6b7..d89d80014a 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/common.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/common/common.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -18,6 +19,7 @@ class InputHydroCommon(FolderNode): + @override def build(self) -> TREE: children: TREE = {"capacity": InputHydroCommonCapacity(self.context, self.config.next_file("capacity"))} return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/hydro.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/hydro.py index c1c3d2984a..f5e021ce61 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/hydro.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/hydro.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -20,6 +21,7 @@ class InputHydro(FolderNode): + @override def build(self) -> TREE: children: TREE = { "allocation": InputHydroAllocation(self.context, self.config.next_file("allocation")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/area/area.py index 13d504d1c0..bdd8ac80db 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -19,6 +20,7 @@ class InputHydroPreproArea(FolderNode): + @override def build(self) -> TREE: children: TREE = { "energy": InputSeriesMatrix(self.context, self.config.next_file("energy.txt")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/prepro.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/prepro.py index 93104392f3..ba884200d5 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/prepro.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/prepro/prepro.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.common.prepro import PreproCorrelation from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -17,6 +18,7 @@ class InputHydroPrepro(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputHydroPreproArea(self.context, self.config.next_file(a)) for a in self.config.area_names() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/area/area.py index 792fb9335f..4c6ada156a 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/area/area.py @@ -12,6 +12,8 @@ from typing import Any, Dict +from typing_extensions import override + from antarest.study.model import STUDY_VERSION_6_5, STUDY_VERSION_8_6 from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE, INode @@ -25,6 +27,7 @@ class InputHydroSeriesArea(FolderNode): + @override def build(self) -> TREE: study_version = self.config.version freq = MatrixFrequency.DAILY if study_version >= STUDY_VERSION_6_5 else MatrixFrequency.MONTHLY diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/series.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/series.py index 0a92743b2b..bb22eab408 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/series.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/hydro/series/series.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class InputHydroSeries(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputHydroSeriesArea(self.context, self.config.next_file(a)) for a in self.config.area_names() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/input.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/input.py index 1c19358baf..429831b818 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/input.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/input.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.model import STUDY_VERSION_8_1, STUDY_VERSION_8_6 from antarest.study.storage.rawstudy.model.filesystem.config.model import EnrModelling @@ -33,6 +34,7 @@ class Input(FolderNode): Handle the input folder which contains all the input data of the study. """ + @override def build(self) -> TREE: config = self.config diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py index a67fbf6dfc..1eefe1d53c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.model import STUDY_VERSION_8_2 from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig @@ -32,6 +33,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: children: TREE ctx = self.context diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py index cb86c24c89..aabc88f5f4 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -27,6 +28,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: children: TREE = {} for area_to in self.config.get_links(self.area): diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/link.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/link.py index e12f804f9a..d94faabe71 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/link.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/link.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class InputLink(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputLinkArea(self.context, self.config.next_file(a), area=a) for a in self.config.area_names() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/miscgen/miscgen.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/miscgen/miscgen.py index 0590793e5c..213c9b9632 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/miscgen/miscgen.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/miscgen/miscgen.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -17,6 +18,7 @@ class InputMiscGen(FolderNode): + @override def build(self) -> TREE: children: TREE = { f"miscgen-{a}": InputSeriesMatrix( diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/clusters.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/clusters.py index d1be73eff4..5f82229251 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/clusters.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/clusters.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -46,11 +47,13 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: return {"list": ClusteredRenewableClusterConfig(self.context, self.config.next_file("list.ini"), self.area)} class ClusteredRenewableAreaCluster(FolderNode): + @override def build(self) -> TREE: return { area: ClusteredRenewableCluster(self.context, self.config.next_file(area), area) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/renewable.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/renewable.py index e9b7181a19..aa6e9bd94b 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/renewable.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/renewable.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -19,6 +20,7 @@ class ClusteredRenewables(FolderNode): + @override def build(self) -> TREE: children: TREE = { "clusters": ClusteredRenewableAreaCluster(self.context, self.config.next_file("clusters")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/series.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/series.py index cf323c311d..91aa09642d 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/series.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/renewables/series.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -19,6 +20,7 @@ class ClusteredRenewableSeries(FolderNode): + @override def build(self) -> TREE: series_config = self.config.next_file("series.txt") children: TREE = { @@ -41,6 +43,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: # Note that cluster IDs may not be in lower case, but series IDs are. series_ids = map(str.lower, self.config.get_renewable_ids(self.area)) @@ -52,6 +55,7 @@ def build(self) -> TREE: class ClusteredRenewableAreaSeries(FolderNode): + @override def build(self) -> TREE: return { area: ClusteredRenewableClusterSeries(self.context, self.config.next_file(area), area) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/reserves/reserves.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/reserves/reserves.py index 6c558e115c..7b9b89c982 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/reserves/reserves.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/reserves/reserves.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -17,6 +18,7 @@ class InputReserves(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputSeriesMatrix( diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/area/area.py index e77b3e16a2..375a8d64fa 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -29,6 +30,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: # Each area has a folder containing a file named "list.ini" # If the area does not have any short term storage cluster, the file is empty. diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/clusters.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/clusters.py index ea2c055bed..3723410414 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/clusters.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/clusters/clusters.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -17,6 +18,7 @@ class InputSTStorageClusters(FolderNode): # Each area has it own folder named after the area id. + @override def build(self) -> TREE: children: TREE = { a: InputSTStorageArea(self.context, self.config.next_file(a), area=a) for a in self.config.area_names() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/area.py index 3a24f37dc6..3acba900a1 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -29,6 +30,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: children: TREE = { st_storage_id: InputSTStorageAreaStorage(self.context, self.config.next_file(st_storage_id)) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py index a531bd4bee..c2a2a4a19a 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/area/st_storage/st_storage.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -17,6 +18,7 @@ class InputSTStorageAreaStorage(FolderNode): + @override def build(self) -> TREE: children: TREE = { "pmax_injection": InputSeriesMatrix( diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/series.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/series.py index 32aebb3351..3c071bfcd8 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/series.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/series/series.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -20,6 +21,7 @@ class InputSTStorageSeries(FolderNode): # For each short-term storage, a time-series matrix is created after the name of the cluster. # This matrix is created inside the folder's area corresponding to the cluster. + @override def build(self) -> TREE: children: TREE = { a: InputSTStorageSeriesArea(self.context, self.config.next_file(a), area=a) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/st_storage.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/st_storage.py index b70e60381f..4ce2fcbe9c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/st_storage.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/st_storage/st_storage.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -21,6 +22,8 @@ class InputSTStorage(FolderNode): # Short-term storage objects are introduced in the v8.6 of AntaresSimulator. # This new object simplifies the previously complex modeling of short-term storage such as batteries or STEPs. + + @override def build(self) -> TREE: children: TREE = { "clusters": InputSTStorageClusters(self.context, self.config.next_file("clusters")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/area/area.py index 6fefc8ca31..e97c5d07ae 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -29,6 +30,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: children: TREE = { "list": InputThermalClustersAreaList(self.context, self.config.next_file("list.ini"), self.area) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/cluster.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/cluster.py index d30376d3b3..77ec2e705f 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/cluster.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/cluster/cluster.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -18,6 +19,7 @@ class InputThermalClusters(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputThermalClustersArea(self.context, self.config.next_file(a), area=a) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/area.py index a804f5dbae..8d4fb248b8 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -29,6 +30,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: children: TREE = { series_id: InputThermalPreproAreaThermal(self.context, self.config.next_file(series_id)) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/thermal/thermal.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/thermal/thermal.py index 1beeb19797..dc57ee3c4a 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/thermal/thermal.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/area/thermal/thermal.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -26,6 +27,7 @@ class InputThermalPreproAreaThermal(FolderNode): - `modulation.txt` (matrix): Modulation matrix (hourly) """ + @override def build(self) -> TREE: children: TREE = { "data": InputSeriesMatrix(self.context, self.config.next_file("data.txt"), freq=MatrixFrequency.DAILY), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/prepro.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/prepro.py index a9e3c19db6..bf75f6ad07 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/prepro.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/prepro/prepro.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class InputThermalPrepro(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputThermalPreproArea(self.context, self.config.next_file(a), area=a) for a in self.config.area_names() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/area.py index 33d3bf15b1..c87e73a108 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -29,6 +30,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: # Note that cluster IDs are case-insensitive, but series IDs are in lower case. # For instance, if your cluster ID is "Base", then the series ID will be "base". diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/thermal/thermal.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/thermal/thermal.py index 8d765a2c16..b18dde23a7 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/thermal/thermal.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/area/thermal/thermal.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -18,6 +19,7 @@ class InputThermalSeriesAreaThermal(FolderNode): + @override def build(self) -> TREE: children: TREE = { "series": InputSeriesMatrix( diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/series.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/series.py index 44bb37d4b4..fc639c99d9 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/series.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/series/series.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class InputThermalSeries(FolderNode): + @override def build(self) -> TREE: children: TREE = { a: InputThermalSeriesArea(self.context, self.config.next_file(a), area=a) for a in self.config.area_names() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/thermal.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/thermal.py index d5ee6cc7b1..dcdcd5dc70 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/thermal.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/thermal/thermal.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -19,6 +20,7 @@ class InputThermal(FolderNode): + @override def build(self) -> TREE: children: TREE = { "clusters": InputThermalClusters(self.context, self.config.next_file("clusters")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/layers/layers.py b/antarest/study/storage/rawstudy/model/filesystem/root/layers/layers.py index 086475e021..9f40e3fc6d 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/layers/layers.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/layers/layers.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class Layers(FolderNode): + @override def build(self) -> TREE: children: TREE = {"layers": LayersIni(self.context, self.config.next_file("layers.ini"))} return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/output.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/output.py index b45cc32c22..f33ed11bb8 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/output.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/output.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.bucket_node import BucketNode from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -17,6 +18,7 @@ class Output(FolderNode): + @override def build(self) -> TREE: children: TREE = { str(s.get_file()): OutputSimulation( diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/about/about.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/about/about.py index bf2ce89c37..35cffab3db 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/about/about.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/about/about.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -20,6 +21,7 @@ class OutputSimulationAbout(FolderNode): + @override def build(self) -> TREE: children: TREE = { "areas": RawFileNode(self.context, self.config.next_file("areas.txt")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/area.py index 0b97fa5735..398ec9bf4e 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/area.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -28,6 +29,7 @@ def __init__( super().__init__(context, config) self.area = area + @override def build(self) -> TREE: children: TREE = {} freq: MatrixFrequency diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/areas.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/areas.py index 5dcac4d82e..4c1a14cdff 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/areas.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/areas.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -30,6 +31,7 @@ def __init__( ) -> None: super().__init__(context, config) + @override def build(self) -> TREE: areas = set() sets = set() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/binding_const.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/binding_const.py index 662cef5af6..e956da727b 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/binding_const.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/binding_const.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -19,6 +20,7 @@ class OutputSimulationBindingConstraintItem(FolderNode): + @override def build(self) -> TREE: existing_files = [d.stem.replace("binding-constraints-", "") for d in self.config.path.iterdir()] children: TREE = { diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/link.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/link.py index b5f0b15dcb..81922bc9c9 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/link.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/link.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -30,6 +31,7 @@ def __init__( self.area = area self.link = link + @override def build(self) -> TREE: children: TREE = {} freq: MatrixFrequency diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/links.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/links.py index 9d1109ee5f..b7d4ad1d70 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/links.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/links.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode @@ -33,6 +35,7 @@ def __init__( self.area_from = area_from self.link_names = link_names + @override def build(self) -> TREE: children: TREE = {} for link_name in self.link_names: @@ -51,6 +54,7 @@ def __init__( ): super().__init__(context, config) + @override def build(self) -> TREE: children: TREE = {} links = [d.stem for d in self.config.path.iterdir()] diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/set.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/set.py index 4c8a624a5c..11076e977c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/set.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/set.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -28,6 +29,7 @@ def __init__( super().__init__(context, config) self.set = set + @override def build(self) -> TREE: children: TREE = {} freq: MatrixFrequency diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/utils.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/utils.py index f8f940fd28..d5d6b6495c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/utils.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/common/utils.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -34,6 +35,7 @@ class OutputSimulationModeCommon(FolderNode): + @override def build(self) -> TREE: if not self.config.output_path: return {} diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/economy.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/economy.py index a7da7fa642..c39642589e 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/economy.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/economy.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig, Simulation from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -32,6 +33,7 @@ def __init__( super().__init__(context, config) self.simulation = simulation + @override def build(self) -> TREE: children: TREE = {} if self.simulation.by_year: diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcall/grid.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcall/grid.py index 943de12ef2..374b4fc6a1 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcall/grid.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcall/grid.py @@ -13,6 +13,7 @@ import typing as t import pandas as pd +from typing_extensions import override from antarest.core.exceptions import MustNotModifyOutputException from antarest.core.model import JSON @@ -24,6 +25,7 @@ class OutputSimulationModeMcAllGrid(FolderNode): + @override def build(self) -> TREE: files = [d.stem for d in self.config.path.iterdir()] children: TREE = {} @@ -37,6 +39,7 @@ class OutputSynthesis(LazyNode[JSON, bytes, bytes]): def __init__(self, context: ContextServer, config: FileStudyTreeConfig): super().__init__(context, config) + @override def get_lazy_content( self, url: t.Optional[t.List[str]] = None, @@ -45,6 +48,7 @@ def get_lazy_content( ) -> str: return f"matrix://{self.config.path.name}" # prefix used by the front to parse the back-end response + @override def load( self, url: t.Optional[t.List[str]] = None, @@ -59,9 +63,11 @@ def load( del output["index"] return t.cast(JSON, output) + @override def dump(self, data: bytes, url: t.Optional[t.List[str]] = None) -> None: raise MustNotModifyOutputException(self.config.path.name) + @override def check_errors(self, data: str, url: t.Optional[t.List[str]] = None, raising: bool = False) -> t.List[str]: if not self.config.path.exists(): msg = f"{self.config.path} not exist" @@ -70,9 +76,11 @@ def check_errors(self, data: str, url: t.Optional[t.List[str]] = None, raising: return [msg] return [] + @override def normalize(self) -> None: pass # shouldn't be normalized as it's an output file + @override def denormalize(self) -> None: pass # shouldn't be denormalized as it's an output file @@ -81,6 +89,7 @@ class DigestSynthesis(OutputSynthesis): def __init__(self, context: ContextServer, config: FileStudyTreeConfig): super().__init__(context, config) + @override def load( self, url: t.Optional[t.List[str]] = None, diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcind/mcind.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcind/mcind.py index e6cac924ea..ea1c5d2c58 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcind/mcind.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/mode/mcind/mcind.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig, Simulation from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -29,6 +30,7 @@ def __init__( super().__init__(context, config) self.simulation = simulation + @override def build(self) -> TREE: children: TREE = { f"{scn:05d}": OutputSimulationModeCommon(self.context, self.config.next_file(f"{scn:05d}")) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/simulation.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/simulation.py index 129b05f147..12ecb930d9 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/simulation.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/simulation.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig, Simulation from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer @@ -42,6 +43,7 @@ def __init__( super().__init__(context, config) self.simulation = simulation + @override def build(self) -> TREE: children: TREE = { "about-the-study": OutputSimulationAbout(self.context, self.config.next_file("about-the-study")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_generator/ts_generator.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_generator/ts_generator.py index 73e0ae6ed0..b99307d01d 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_generator/ts_generator.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_generator/ts_generator.py @@ -12,6 +12,8 @@ from typing import Any, Callable +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.common.area_matrix_list import ( AreaMatrixList, AreaMultipleMatrixList, @@ -26,6 +28,7 @@ class OutputSimulationTsGeneratorSimpleMatrixList(FolderNode): + @override def build(self) -> TREE: children: TREE = { "mc-0": AreaMatrixList(self.context, self.config.next_file("mc-0")), @@ -54,6 +57,7 @@ def __init__( super().__init__(context, config) self.klass = klass + @override def build(self) -> TREE: children: TREE = { "mc-0": AreaMultipleMatrixList( @@ -67,6 +71,7 @@ def build(self) -> TREE: class OutputSimulationTsGenerator(FolderNode): + @override def build(self) -> TREE: children: TREE = {} for output_type in ["load", "solar", "wind"]: diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers.py index 2d5f9d729b..4c84635f4a 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.common.area_matrix_list import ( AreaMatrixList, @@ -68,6 +69,7 @@ class OutputSimulationTsNumbers(FolderNode): └── turbinage.txt """ + @override def build(self) -> TREE: children: TREE = {} for output_type in ["hydro", "load", "solar", "wind"]: diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers_data.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers_data.py index 670a6526ca..45512a2af2 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers_data.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/ts_numbers/ts_numbers_data.py @@ -13,6 +13,8 @@ import logging from typing import List, Optional, Union +from typing_extensions import override + from antarest.core.model import JSON from antarest.study.storage.rawstudy.model.filesystem.lazy_node import LazyNode @@ -20,6 +22,7 @@ class TsNumbersVector(LazyNode[List[int], List[int], JSON]): + @override def load( self, url: Optional[List[str]] = None, @@ -44,6 +47,7 @@ def load( logger.warning(f"Missing file {self.config.path}") return [] + @override def dump( self, data: Union[str, bytes, List[int]], @@ -55,6 +59,7 @@ def dump( for d in data: fh.write(f"{d}\n") + @override def check_errors( self, data: JSON, @@ -63,10 +68,12 @@ def check_errors( ) -> List[str]: return [] + @override def normalize(self) -> None: # this is not normalizable pass + @override def denormalize(self) -> None: # this is not normalizable pass diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/sensitivity.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/sensitivity.py index 6e3e5a4ee5..8383dbbcad 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/sensitivity.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/sensitivity.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -17,6 +18,7 @@ class Sensitivity(FolderNode): + @override def build(self) -> TREE: return { "out": JsonFileNode(self.context, self.config.next_file("sensitivity_out.json")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/xpansion.py b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/xpansion.py index 9635e8be82..2815bac089 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/xpansion.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/output/simulation/xpansion/xpansion.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class Xpansion(FolderNode): + @override def build(self) -> TREE: return { "out": JsonFileNode(self.context, self.config.next_file("out.json")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/settings/resources/resources.py b/antarest/study/storage/rawstudy/model/filesystem/root/settings/resources/resources.py index 347d90f609..4ff236f7be 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/settings/resources/resources.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/settings/resources/resources.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -16,6 +17,7 @@ class Resources(FolderNode): + @override def build(self) -> TREE: children: TREE = {"study": RawFileNode(self.context, self.config.next_file("study.ico"))} return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/settings/scenariobuilder.py b/antarest/study/storage/rawstudy/model/filesystem/root/settings/scenariobuilder.py index bf0501d531..f1960d9984 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/settings/scenariobuilder.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/settings/scenariobuilder.py @@ -14,6 +14,7 @@ import typing as t import typing_extensions as te +from typing_extensions import override from antarest.study.model import ( STUDY_VERSION_8, @@ -124,6 +125,7 @@ def _populate_hydro_generation_power_rules(self, rules: _Rules) -> None: for area_id in self.config.areas: rules[f"hgp,{area_id},0"] = _TSNumber + @override def _get_filtering_kwargs(self, url: t.List[str]) -> t.Dict[str, str]: # If the URL contains 2 elements, we can filter the options based on the generator type. if len(url) == 2: diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/settings/settings.py b/antarest/study/storage/rawstudy/model/filesystem/root/settings/settings.py index 61d32f6012..f63b7cb69d 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/settings/settings.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/settings/settings.py @@ -9,6 +9,7 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE @@ -20,6 +21,7 @@ class Settings(FolderNode): + @override def build(self) -> TREE: children: TREE = { "resources": Resources(self.context, self.config.next_file("resources")), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/settings/simulations/simulations.py b/antarest/study/storage/rawstudy/model/filesystem/root/settings/simulations/simulations.py index 5a8e832e11..64e074623e 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/settings/simulations/simulations.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/settings/simulations/simulations.py @@ -9,12 +9,14 @@ # SPDX-License-Identifier: MPL-2.0 # # This file is part of the Antares project. +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE class SettingsSimulations(FolderNode): + @override def build(self) -> TREE: children: TREE = {} return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/sensitivity.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/sensitivity.py index da42e73c64..2a2ea7c9c3 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/sensitivity.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/sensitivity.py @@ -12,12 +12,15 @@ from typing import List +from typing_extensions import override + from antarest.study.storage.rawstudy.model.filesystem.folder_node import FolderNode from antarest.study.storage.rawstudy.model.filesystem.inode import TREE from antarest.study.storage.rawstudy.model.filesystem.json_file_node import JsonFileNode class SensitivityConfig(FolderNode): + @override def build(self) -> TREE: types = {"epsilon": float, "capex": bool, "projection": List[str]} return { diff --git a/antarest/study/storage/rawstudy/raw_study_service.py b/antarest/study/storage/rawstudy/raw_study_service.py index e90b9b33ed..11572d6710 100644 --- a/antarest/study/storage/rawstudy/raw_study_service.py +++ b/antarest/study/storage/rawstudy/raw_study_service.py @@ -20,6 +20,7 @@ from uuid import uuid4 from antares.study.version import StudyVersion +from typing_extensions import override from antarest.core.config import Config from antarest.core.exceptions import StudyDeletionNotAllowed @@ -142,6 +143,7 @@ def update_name_and_version_from_raw_meta(self, metadata: RawStudy) -> bool: ) return False + @override def exists(self, study: RawStudy) -> bool: """ Check if the study exists in the filesystem. @@ -158,6 +160,7 @@ def exists(self, study: RawStudy) -> bool: path = self.get_study_path(study) return path.joinpath("study.antares").is_file() + @override def get_raw( self, metadata: RawStudy, @@ -177,12 +180,14 @@ def get_raw( study_path = self.get_study_path(metadata) return self.study_factory.create_from_fs(study_path, metadata.id, output_dir, use_cache=use_cache) + @override def get_synthesis(self, metadata: RawStudy, params: t.Optional[RequestParameters] = None) -> FileStudyTreeConfigDTO: self._check_study_exists(metadata) study_path = self.get_study_path(metadata) study = self.study_factory.create_from_fs(study_path, metadata.id) return FileStudyTreeConfigDTO.from_build_config(study.config) + @override def create(self, metadata: RawStudy) -> RawStudy: """ Create a new empty study based on the given metadata. @@ -216,6 +221,7 @@ def create(self, metadata: RawStudy) -> RawStudy: return metadata + @override def copy( self, src_meta: RawStudy, @@ -273,6 +279,7 @@ def copy( return dest_study + @override def delete(self, metadata: RawStudy) -> None: """ Delete study @@ -290,6 +297,7 @@ def delete(self, metadata: RawStudy) -> None: else: raise StudyDeletionNotAllowed(metadata.id) + @override def delete_output(self, metadata: RawStudy, output_name: str) -> None: """ Delete output folder @@ -338,6 +346,7 @@ def import_study(self, metadata: RawStudy, stream: t.BinaryIO) -> Study: metadata.path = str(study_path) return metadata + @override def export_study_flat( self, metadata: RawStudy, @@ -379,6 +388,7 @@ def check_errors( study = self.study_factory.create_from_fs(path, metadata.id) return study.tree.check_errors(study.tree.get()) + @override def set_reference_output(self, study: RawStudy, output_id: str, status: bool) -> None: self.patch_service.set_reference_output(study, output_id, status) remove_from_cache(self.cache, study.id) @@ -422,6 +432,7 @@ def find_archive_path(self, study: RawStudy) -> Path: return path raise FileNotFoundError(f"Study {study.id} archiving process is corrupted (no archive file found).") + @override def get_study_path(self, metadata: Study) -> Path: """ Get study path @@ -435,6 +446,7 @@ def get_study_path(self, metadata: Study) -> Path: return self.find_archive_path(metadata) return Path(metadata.path) + @override def initialize_additional_data(self, raw_study: RawStudy) -> bool: try: study = self.study_factory.create_from_fs( diff --git a/antarest/study/storage/rawstudy/watcher.py b/antarest/study/storage/rawstudy/watcher.py index 3166bbe40f..75541c009b 100644 --- a/antarest/study/storage/rawstudy/watcher.py +++ b/antarest/study/storage/rawstudy/watcher.py @@ -19,6 +19,7 @@ from typing import List, Optional from filelock import FileLock +from typing_extensions import override from antarest.core.config import Config from antarest.core.interfaces.service import IService @@ -70,6 +71,7 @@ def __init__( self.should_stop = False self.allowed_to_start = not config.storage.watcher_lock or Watcher._get_lock(config.storage.watcher_lock_delay) + @override def start(self, threaded: bool = True) -> None: self.should_stop = False if self.allowed_to_start: @@ -97,6 +99,7 @@ def _get_lock(lock_delay: int) -> bool: logger.info("Watcher doesn't get lock") return False + @override def _loop(self) -> None: try: logger.info( diff --git a/antarest/study/storage/variantstudy/business/command_extractor.py b/antarest/study/storage/variantstudy/business/command_extractor.py index 0f034f8a37..dbac37aff9 100644 --- a/antarest/study/storage/variantstudy/business/command_extractor.py +++ b/antarest/study/storage/variantstudy/business/command_extractor.py @@ -15,6 +15,7 @@ import typing as t import numpy as np +from typing_extensions import override from antarest.core.model import JSON from antarest.core.utils.utils import StopWatch @@ -67,6 +68,7 @@ def __init__(self, matrix_service: ISimpleMatrixService, patch_service: PatchSer patch_service=self.patch_service, ) + @override def extract_area(self, study: FileStudy, area_id: str) -> t.Tuple[t.List[ICommand], t.List[ICommand]]: stopwatch = StopWatch() study_tree = study.tree @@ -147,6 +149,7 @@ def extract_area(self, study: FileStudy, area_id: str) -> t.Tuple[t.List[IComman stopwatch.log_elapsed(lambda x: logger.info(f"Hydro command extraction done in {x}s")) return study_commands, links_commands + @override def extract_link( self, study: FileStudy, @@ -249,12 +252,15 @@ def _extract_cluster(self, study: FileStudy, area_id: str, cluster_id: str, rene ) return study_commands + @override def extract_cluster(self, study: FileStudy, area_id: str, thermal_id: str) -> t.List[ICommand]: return self._extract_cluster(study, area_id, thermal_id, False) + @override def extract_renewables_cluster(self, study: FileStudy, area_id: str, renewables_id: str) -> t.List[ICommand]: return self._extract_cluster(study, area_id, renewables_id, True) + @override def extract_hydro(self, study: FileStudy, area_id: str) -> t.List[ICommand]: study_tree = study.tree commands = [ @@ -316,6 +322,7 @@ def extract_hydro(self, study: FileStudy, area_id: str) -> t.List[ICommand]: return commands + @override def extract_district(self, study: FileStudy, district_id: str) -> t.List[ICommand]: study_commands: t.List[ICommand] = [] study_config = study.config @@ -337,6 +344,7 @@ def extract_district(self, study: FileStudy, district_id: str) -> t.List[IComman ) return study_commands + @override def extract_comments(self, study: FileStudy) -> t.List[ICommand]: study_tree = study.tree content = t.cast(bytes, study_tree.get(["settings", "comments"])) @@ -347,6 +355,7 @@ def extract_comments(self, study: FileStudy) -> t.List[ICommand]: ) ] + @override def extract_binding_constraint( self, study: FileStudy, @@ -400,6 +409,7 @@ def extract_binding_constraint( return [create_cmd] + @override def generate_update_config(self, study_tree: FileStudyTree, url: t.List[str]) -> ICommand: data = study_tree.get(url) return UpdateConfig( @@ -409,6 +419,7 @@ def generate_update_config(self, study_tree: FileStudyTree, url: t.List[str]) -> study_version=study_tree.config.version, ) + @override def generate_update_raw_file(self, study_tree: FileStudyTree, url: t.List[str]) -> ICommand: data = study_tree.get(url) return UpdateRawFile( @@ -418,6 +429,7 @@ def generate_update_raw_file(self, study_tree: FileStudyTree, url: t.List[str]) study_version=study_tree.config.version, ) + @override def generate_update_comments( self, study_tree: FileStudyTree, @@ -443,6 +455,7 @@ def generate_update_playlist( study_version=study_tree.config.version, ) + @override def generate_replace_matrix( self, study_tree: FileStudyTree, diff --git a/antarest/study/storage/variantstudy/model/command/create_area.py b/antarest/study/storage/variantstudy/model/command/create_area.py index 1eefb00d1a..d05cc931d4 100644 --- a/antarest/study/storage/variantstudy/model/command/create_area.py +++ b/antarest/study/storage/variantstudy/model/command/create_area.py @@ -13,6 +13,7 @@ import typing as t from pydantic import Field +from typing_extensions import override from antarest.core.model import JSON from antarest.study.model import STUDY_VERSION_6_5, STUDY_VERSION_8_1, STUDY_VERSION_8_3, STUDY_VERSION_8_6 @@ -74,6 +75,7 @@ class CreateArea(ICommand): # or if we don't want to support this feature. metadata: t.Dict[str, str] = Field(default_factory=dict, description="Area metadata: country and tag list") + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: if self.command_context.generator_matrix_constants is None: raise ValueError() @@ -102,6 +104,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu {"area_id": area_id}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: config = study_data.config @@ -287,21 +290,26 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.CREATE_AREA.value, args={"area_name": self.area_name}, study_version=self.study_version ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.area_name) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, CreateArea): return False return self.area_name == other.area_name + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [] + @override def get_inner_matrices(self) -> t.List[str]: return [] 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 93a65ff25a..b41fb2dd93 100644 --- a/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/create_binding_constraint.py @@ -17,6 +17,7 @@ import numpy as np from antares.study.version import StudyVersion from pydantic import Field, field_validator, model_validator +from typing_extensions import override from antarest.core.model import LowerCaseStr from antarest.core.serialization import AntaresBaseModel @@ -221,6 +222,7 @@ class AbstractBindingConstraintCommand(OptionalProperties, BindingConstraintMatr coeffs: t.Optional[t.Dict[str, t.List[float]]] = None + @override def to_dto(self) -> CommandDTO: json_command = self.model_dump(mode="json", exclude={"command_context"}) args = {} @@ -248,6 +250,7 @@ def to_dto(self) -> CommandDTO: action=self.command_name.value, args=args, version=self.version, study_version=self.study_version ) + @override def get_inner_matrices(self) -> t.List[str]: matrix_service = self.command_context.matrix_service return [ @@ -416,6 +419,7 @@ class CreateBindingConstraint(AbstractBindingConstraintCommand): # Properties of the `CREATE_BINDING_CONSTRAINT` command: name: str + @override def _apply_config(self, study_data_config: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: bd_id = transform_name_to_id(self.name) group = self.group or DEFAULT_GROUP @@ -431,6 +435,7 @@ def _apply_config(self, study_data_config: FileStudyTreeConfig) -> t.Tuple[Comma ) return CommandOutput(status=True), {} + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: binding_constraints = study_data.tree.get(["input", "bindingconstraints", "bindingconstraints"]) new_key = str(len(binding_constraints)) @@ -449,14 +454,17 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = ) return super().apply_binding_constraint(study_data, binding_constraints, new_key, bd_id) + @override def to_dto(self) -> CommandDTO: dto = super().to_dto() dto.args["name"] = self.name # type: ignore return dto + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.name) + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: from antarest.study.storage.variantstudy.model.command.update_binding_constraint import UpdateBindingConstraint @@ -492,6 +500,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [UpdateBindingConstraint.model_validate(args)] + @override def match(self, other: "ICommand", equal: bool = False) -> bool: if not isinstance(other, self.__class__): return False diff --git a/antarest/study/storage/variantstudy/model/command/create_cluster.py b/antarest/study/storage/variantstudy/model/command/create_cluster.py index 779d85ee3c..de4eb70ffc 100644 --- a/antarest/study/storage/variantstudy/model/command/create_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/create_cluster.py @@ -13,6 +13,7 @@ import typing as t from pydantic import Field, model_validator +from typing_extensions import override from antarest.core.model import JSON, LowerCaseStr from antarest.core.utils.utils import assert_this @@ -73,6 +74,7 @@ def validate_model(cls, values: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: return values + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: # Search the Area in the configuration if self.area_id not in study_data.areas: @@ -107,6 +109,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu {"cluster_id": cluster.id}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: output, data = self._apply_config(study_data.config) if not output.status: @@ -144,6 +147,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -157,6 +161,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str( self.command_name.value @@ -166,6 +171,7 @@ def match_signature(self) -> str: + self.cluster_name ) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, CreateCluster): return False @@ -181,6 +187,7 @@ def match(self, other: ICommand, equal: bool = False) -> bool: and self.modulation == other.modulation ) + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: other = t.cast(CreateCluster, other) from antarest.study.storage.variantstudy.model.command.replace_matrix import ReplaceMatrix @@ -220,6 +227,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: ) return commands + @override def get_inner_matrices(self) -> t.List[str]: matrices: t.List[str] = [] if self.prepro: diff --git a/antarest/study/storage/variantstudy/model/command/create_district.py b/antarest/study/storage/variantstudy/model/command/create_district.py index e8ed7f69d9..668ace46f1 100644 --- a/antarest/study/storage/variantstudy/model/command/create_district.py +++ b/antarest/study/storage/variantstudy/model/command/create_district.py @@ -14,6 +14,7 @@ from typing import Any, Dict, List, Optional, Tuple, cast from pydantic import field_validator +from typing_extensions import override from antarest.core.model import LowerCaseStr from antarest.study.storage.rawstudy.model.filesystem.config.field_validators import transform_name_to_id @@ -50,6 +51,7 @@ class CreateDistrict(ICommand): output: bool = True comments: str = "" + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: district_id = transform_name_to_id(self.name) if district_id in study_data.sets: @@ -75,6 +77,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, "item_key": item_key, } + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: output, data = self._apply_config(study_data.config) if not output.status: @@ -94,6 +97,7 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.CREATE_DISTRICT.value, @@ -107,9 +111,11 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.name) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, CreateDistrict): return False @@ -124,6 +130,7 @@ def match(self, other: ICommand, equal: bool = False) -> bool: and self.comments == other.comments ) + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: other = cast(CreateDistrict, other) district_id = transform_name_to_id(self.name) @@ -147,5 +154,6 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: ) ] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/create_link.py b/antarest/study/storage/variantstudy/model/command/create_link.py index 1e46c20bf1..134491ce8c 100644 --- a/antarest/study/storage/variantstudy/model/command/create_link.py +++ b/antarest/study/storage/variantstudy/model/command/create_link.py @@ -14,6 +14,7 @@ from antares.study.version import StudyVersion from pydantic import ValidationInfo, field_validator, model_validator +from typing_extensions import override from antarest.core.exceptions import LinkValidationError from antarest.core.utils.utils import assert_this @@ -65,6 +66,7 @@ def validate_areas(self) -> "AbstractLinkCommand": return self + @override def to_dto(self) -> CommandDTO: args = { "area1": self.area1, @@ -76,6 +78,7 @@ def to_dto(self) -> CommandDTO: args[attr] = strip_matrix_protocol(value) return CommandDTO(action=self.command_name.value, args=args, study_version=self.study_version) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, self.__class__): return False @@ -90,11 +93,13 @@ def match(self, other: ICommand, equal: bool = False) -> bool: and self.indirect == other.indirect ) + @override def match_signature(self) -> str: return str( self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.area1 + MATCH_SIGNATURE_SEPARATOR + self.area2 ) + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: other = cast(AbstractLinkCommand, other) @@ -123,6 +128,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: ) return commands + @override def get_inner_matrices(self) -> List[str]: list_matrices = [] for attr in MATRIX_ATTRIBUTES: @@ -200,6 +206,7 @@ def _create_link_in_config(self, area_from: str, area_to: str, study_data: FileS ], ) + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: if self.area1 not in study_data.areas: return ( @@ -254,6 +261,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, {"area_from": area_from, "area_to": area_to}, ) + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: version = study_data.config.version output, data = self._apply_config(study_data.config) @@ -283,17 +291,22 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N return output + @override def to_dto(self) -> CommandDTO: return super().to_dto() + @override def match_signature(self) -> str: return super().match_signature() + @override def match(self, other: ICommand, equal: bool = False) -> bool: return super().match(other, equal) + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return super()._create_diff(other) + @override def get_inner_matrices(self) -> List[str]: return super().get_inner_matrices() diff --git a/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py b/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py index 6c0c6381c8..057791ca10 100644 --- a/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/create_renewables_cluster.py @@ -13,6 +13,7 @@ import typing as t from pydantic import model_validator +from typing_extensions import override from antarest.core.model import JSON, LowerCaseStr from antarest.study.storage.rawstudy.model.filesystem.config.model import Area, EnrModelling, FileStudyTreeConfig @@ -53,6 +54,7 @@ def validate_model(cls, values: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: values["parameters"] = create_renewable_properties(values["study_version"], **args) return values + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: if EnrModelling(study_data.enr_modelling) != EnrModelling.CLUSTERS: # Since version 8.1 of the solver, we can use renewable clusters @@ -100,6 +102,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu {"cluster_id": cluster.id}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: output, data = self._apply_config(study_data.config) if not output.status: @@ -127,6 +130,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -138,6 +142,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str( self.command_name.value @@ -147,6 +152,7 @@ def match_signature(self) -> str: + self.cluster_name ) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, CreateRenewablesCluster): return False @@ -157,6 +163,7 @@ def match(self, other: ICommand, equal: bool = False) -> bool: other_params = other.parameters.model_dump(mode="json", by_alias=True) return simple_match and self_params == other_params + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: other = t.cast(CreateRenewablesCluster, other) from antarest.study.storage.variantstudy.model.command.update_config import UpdateConfig @@ -175,5 +182,6 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: ) return commands + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/create_st_storage.py b/antarest/study/storage/variantstudy/model/command/create_st_storage.py index 8d15d5c625..42a3e66253 100644 --- a/antarest/study/storage/variantstudy/model/command/create_st_storage.py +++ b/antarest/study/storage/variantstudy/model/command/create_st_storage.py @@ -14,6 +14,7 @@ import numpy as np from pydantic import Field, ValidationInfo, model_validator +from typing_extensions import override from antarest.core.model import JSON, LowerCaseStr from antarest.matrixstore.model import MatrixData @@ -170,6 +171,7 @@ def validate_matrices(cls, values: t.Union[t.Dict[str, t.Any], ValidationInfo]) new_values[field] = cls.validate_field(new_values.get(field, None), new_values, field) return new_values + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: """ Applies configuration changes to the study data: add the short-term storage in the storages list. @@ -229,6 +231,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu {"storage_id": storage_id}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: """ Applies the study data to update storage configurations and saves the changes. @@ -263,6 +266,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return output + @override def to_dto(self) -> CommandDTO: """ Converts the current object to a Data Transfer Object (DTO) @@ -281,6 +285,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: """Returns the command signature.""" return str( @@ -291,6 +296,7 @@ def match_signature(self) -> str: + self.storage_id ) + @override def match(self, other: "ICommand", equal: bool = False) -> bool: """ Checks if the current instance matches another `ICommand` object. @@ -310,6 +316,7 @@ def match(self, other: "ICommand", equal: bool = False) -> bool: else: return self.area_id == other.area_id and self.storage_id == other.storage_id + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: """ Creates a list of commands representing the differences between @@ -350,6 +357,7 @@ def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: ) return commands + @override def get_inner_matrices(self) -> t.List[str]: """ Retrieves the list of matrix IDs. diff --git a/antarest/study/storage/variantstudy/model/command/create_user_resource.py b/antarest/study/storage/variantstudy/model/command/create_user_resource.py index a62fd1f8b0..0afb321e54 100644 --- a/antarest/study/storage/variantstudy/model/command/create_user_resource.py +++ b/antarest/study/storage/variantstudy/model/command/create_user_resource.py @@ -12,6 +12,8 @@ import typing as t from enum import StrEnum +from typing_extensions import override + from antarest.core.exceptions import ChildNotFoundError from antarest.core.model import JSON from antarest.core.serialization import AntaresBaseModel @@ -50,9 +52,11 @@ class CreateUserResource(ICommand): data: CreateUserResourceData + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: return CommandOutput(status=True, message="ok"), {} + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: url = [item for item in self.data.path.split("/") if item] study_tree = study_data.tree @@ -74,6 +78,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return CommandOutput(status=False, message=f"the given resource already exists: {self.data.path}") return CommandOutput(status=True, message="ok") + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -81,6 +86,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str( self.command_name.value @@ -90,13 +96,16 @@ def match_signature(self) -> str: + self.data.resource_type.value ) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, CreateUserResource): return False return self.data.path == other.data.path and self.data.resource_type == other.data.resource_type + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py b/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py index e6e4bf17a1..9f8631b608 100644 --- a/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py +++ b/antarest/study/storage/variantstudy/model/command/generate_thermal_cluster_timeseries.py @@ -21,6 +21,7 @@ from antares.tsgen.duration_generator import ProbabilityLaw from antares.tsgen.random_generator import MersenneTwisterRNG from antares.tsgen.ts_generator import OutageGenerationParameters, ThermalCluster, TimeseriesGenerator +from typing_extensions import override from antarest.study.storage.rawstudy.model.filesystem.config.model import Area, FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.config.thermal import LocalTSGenerationBehavior @@ -47,9 +48,11 @@ class GenerateThermalClusterTimeSeries(ICommand): command_name: CommandName = CommandName.GENERATE_THERMAL_CLUSTER_TIMESERIES version: int = 1 + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> OutputTuple: return CommandOutput(status=True, message="Nothing to do"), {} + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: study_path = study_data.config.study_path with tempfile.TemporaryDirectory(suffix=TS_GEN_SUFFIX, prefix=TS_GEN_PREFIX, dir=study_path.parent) as path: @@ -141,22 +144,27 @@ def _build_timeseries( e.args = (f"Area {area_id}, cluster {thermal.id.lower()}: " + e.args[0],) raise + @override def to_dto(self) -> CommandDTO: return CommandDTO(action=self.command_name.value, args={}, study_version=self.study_version) + @override def match_signature(self) -> str: return str(self.command_name.value) + @override def match(self, other: "ICommand", equal: bool = False) -> bool: # Only used inside the cli app that no one uses I believe. if not isinstance(other, GenerateThermalClusterTimeSeries): return False return True + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: # Only used inside the cli app that no one uses I believe. raise NotImplementedError() + @override def get_inner_matrices(self) -> t.List[str]: # This is used to get used matrices and not remove them inside the garbage collector loop. return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_area.py b/antarest/study/storage/variantstudy/model/command/remove_area.py index af536c37df..4d7c33e922 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_area.py +++ b/antarest/study/storage/variantstudy/model/command/remove_area.py @@ -14,6 +14,8 @@ import logging import typing as t +from typing_extensions import override + from antarest.core.exceptions import ChildNotFoundError from antarest.core.model import JSON from antarest.study.model import ( @@ -64,6 +66,7 @@ def _remove_area_from_sets_in_config(self, study_data_config: FileStudyTreeConfi set_.areas.remove(self.id) study_data_config.sets[id_] = set_ + @override def _apply_config(self, study_data_config: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: del study_data_config.areas[self.id] @@ -223,6 +226,7 @@ def _remove_area_from_scenario_builder(self, study_data: FileStudy) -> None: study_data.tree.save(rulesets, ["settings", "scenariobuilder"]) # noinspection SpellCheckingInspection + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: study_data.tree.delete(["input", "areas", self.id]) study_data.tree.delete(["input", "hydro", "common", "capacity", f"maxpower_{self.id}"]) @@ -281,6 +285,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.REMOVE_AREA.value, @@ -290,14 +295,18 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.id) + @override def match(self, other: ICommand, equal: bool = False) -> bool: return isinstance(other, RemoveArea) and self.id == other.id + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [] + @override def get_inner_matrices(self) -> t.List[str]: return [] 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 916ba5ea70..55dd971133 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/remove_binding_constraint.py @@ -12,6 +12,8 @@ from typing import Any, Dict, List, Optional, Tuple +from typing_extensions import override + from antarest.core.model import JSON from antarest.study.model import STUDY_VERSION_8_7 from antarest.study.storage.rawstudy.model.filesystem.config.binding_constraint import DEFAULT_GROUP @@ -35,6 +37,7 @@ class RemoveBindingConstraint(ICommand): # Properties of the `REMOVE_BINDING_CONSTRAINT` command: id: str + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: if self.id not in [bind.id for bind in study_data.bindings]: return ( @@ -44,6 +47,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, study_data.bindings.remove(next(iter([bind for bind in study_data.bindings if bind.id == self.id]))) return CommandOutput(status=True), {} + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: if self.id not in [bind.id for bind in study_data.config.bindings]: return CommandOutput(status=False, message=f"Binding constraint not found: '{self.id}'") @@ -76,6 +80,7 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N return self._apply_config(study_data.config)[0] + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.REMOVE_BINDING_CONSTRAINT.value, @@ -85,16 +90,20 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.id) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, RemoveBindingConstraint): return False return self.id == other.id + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return [] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_cluster.py b/antarest/study/storage/variantstudy/model/command/remove_cluster.py index b64bbdfc39..396d0d5d7b 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/remove_cluster.py @@ -13,6 +13,7 @@ import typing as t from pydantic import Field +from typing_extensions import override from antarest.core.model import LowerCaseStr from antarest.study.storage.rawstudy.model.filesystem.config.model import Area, FileStudyTreeConfig @@ -43,6 +44,7 @@ class RemoveCluster(ICommand): area_id: str cluster_id: LowerCaseStr = Field(description="Cluster ID", pattern=r"[a-z0-9_(),& -]+") + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: """ Applies configuration changes to the study data: remove the thermal clusters from the storages list. @@ -101,6 +103,7 @@ def _remove_cluster_from_scenario_builder(self, study_data: FileStudy) -> None: study_data.tree.save(rulesets, ["settings", "scenariobuilder"]) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: """ Applies the study data to update thermal cluster configurations and saves the changes: @@ -142,6 +145,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = # deleting the files and folders. return self._apply_config(study_data.config)[0] + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -149,6 +153,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str( self.command_name.value @@ -158,14 +163,17 @@ def match_signature(self) -> str: + self.area_id ) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, RemoveCluster): return False return self.cluster_id == other.cluster_id and self.area_id == other.area_id + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_district.py b/antarest/study/storage/variantstudy/model/command/remove_district.py index 9e842d9872..2b675aed3f 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_district.py +++ b/antarest/study/storage/variantstudy/model/command/remove_district.py @@ -12,6 +12,8 @@ from typing import Any, Dict, List, Optional, Tuple +from typing_extensions import override + 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 CommandName, CommandOutput @@ -36,15 +38,18 @@ class RemoveDistrict(ICommand): id: str + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: del study_data.sets[self.id] return CommandOutput(status=True, message=self.id), dict() + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: output, _ = self._apply_config(study_data.config) study_data.tree.delete(["input", "areas", "sets", self.id]) return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.REMOVE_DISTRICT.value, @@ -54,16 +59,20 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.id) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, RemoveDistrict): return False return self.id == other.id + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return [] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_link.py b/antarest/study/storage/variantstudy/model/command/remove_link.py index 9b372e906f..668c5ff2b9 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_link.py +++ b/antarest/study/storage/variantstudy/model/command/remove_link.py @@ -13,6 +13,7 @@ import typing as t from pydantic import field_validator, model_validator +from typing_extensions import override from antarest.study.model import STUDY_VERSION_8_2 from antarest.study.storage.rawstudy.model.filesystem.config.field_validators import transform_name_to_id @@ -91,6 +92,7 @@ def _check_link_exists(self, study_cfg: FileStudyTreeConfig) -> OutputTuple: return CommandOutput(status=bool(data), message=message), data + @override def _apply_config(self, study_cfg: FileStudyTreeConfig) -> OutputTuple: """ Update the study configuration by removing the link between the source and target areas. @@ -126,6 +128,7 @@ def _remove_link_from_scenario_builder(self, study_data: FileStudy) -> None: study_data.tree.save(rulesets, ["settings", "scenariobuilder"]) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: """ Update the configuration and the study data by removing the link between the source and target areas. @@ -152,6 +155,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return self._apply_config(study_data.config)[0] + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.REMOVE_LINK.value, @@ -159,17 +163,21 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: sep = MATCH_SIGNATURE_SEPARATOR return f"{self.command_name.value}{sep}{self.area1}{sep}{self.area2}" + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, RemoveLink): return False return self.area1 == other.area1 and self.area2 == other.area2 + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py b/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py index 592b75bfbb..8e62dabbfa 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py +++ b/antarest/study/storage/variantstudy/model/command/remove_renewables_cluster.py @@ -12,10 +12,10 @@ import typing as t -from pydantic import Field, field_validator +from pydantic import Field +from typing_extensions import override from antarest.core.model import LowerCaseStr -from antarest.study.storage.rawstudy.model.filesystem.config.field_validators import validate_id_against_name from antarest.study.storage.rawstudy.model.filesystem.config.model import Area, FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.variantstudy.model.command.common import CommandName, CommandOutput @@ -41,6 +41,7 @@ class RemoveRenewablesCluster(ICommand): area_id: str cluster_id: LowerCaseStr = Field(description="Cluster ID", pattern=r"[a-z0-9_(),& -]+") + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: """ Applies configuration changes to the study data: remove the renewable clusters from the storages list. @@ -97,6 +98,7 @@ def _remove_cluster_from_scenario_builder(self, study_data: FileStudy) -> None: study_data.tree.save(rulesets, ["settings", "scenariobuilder"]) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: """ Applies the study data to update renewable cluster configurations and saves the changes: @@ -135,6 +137,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = # deleting the files and folders. return self._apply_config(study_data.config)[0] + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -142,6 +145,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str( self.command_name.value @@ -151,13 +155,16 @@ def match_signature(self) -> str: + self.area_id ) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, RemoveRenewablesCluster): return False return self.cluster_id == other.cluster_id and self.area_id == other.area_id + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_st_storage.py b/antarest/study/storage/variantstudy/model/command/remove_st_storage.py index f27ebc5a58..3d10466793 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_st_storage.py +++ b/antarest/study/storage/variantstudy/model/command/remove_st_storage.py @@ -13,6 +13,7 @@ import typing as t from pydantic import Field +from typing_extensions import override from antarest.core.model import LowerCaseStr from antarest.study.model import STUDY_VERSION_8_6 @@ -44,6 +45,7 @@ class RemoveSTStorage(ICommand): area_id: str = Field(description="Area ID", pattern=r"[a-z0-9_(),& -]+") storage_id: LowerCaseStr = Field(description="Short term storage ID", pattern=r"[a-z0-9_(),& -]+") + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: """ Applies configuration changes to the study data: remove the storage from the storages list. @@ -101,6 +103,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu {}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: """ Applies the study data to update storage configurations and saves the changes: @@ -130,6 +133,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = # deleting the files and folders. return self._apply_config(study_data.config)[0] + @override def to_dto(self) -> CommandDTO: """ Converts the current object to a Data Transfer Object (DTO) @@ -144,6 +148,7 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: """Returns the command signature.""" return str( @@ -154,13 +159,16 @@ def match_signature(self) -> str: + self.storage_id ) + @override def match(self, other: "ICommand", equal: bool = False) -> bool: # always perform a deep comparison, as there are no parameters # or matrices, so that shallow and deep comparisons are identical. return self.__eq__(other) + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/remove_user_resource.py b/antarest/study/storage/variantstudy/model/command/remove_user_resource.py index 4f24041589..f873ec2d10 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_user_resource.py +++ b/antarest/study/storage/variantstudy/model/command/remove_user_resource.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.core.exceptions import ChildNotFoundError from antarest.core.serialization import AntaresBaseModel from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig @@ -43,9 +45,11 @@ class RemoveUserResource(ICommand): data: RemoveUserResourceData + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: return CommandOutput(status=True, message="ok"), {} + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: url = [item for item in self.data.path.split("/") if item] study_tree = study_data.tree @@ -62,6 +66,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return CommandOutput(status=True, message="ok") + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -69,16 +74,20 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.data.path) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, RemoveUserResource): return False return self.data.path == other.data.path + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/replace_matrix.py b/antarest/study/storage/variantstudy/model/command/replace_matrix.py index b26dd717f1..c796c47ce2 100644 --- a/antarest/study/storage/variantstudy/model/command/replace_matrix.py +++ b/antarest/study/storage/variantstudy/model/command/replace_matrix.py @@ -13,6 +13,7 @@ import typing as t from pydantic import Field, ValidationInfo, field_validator +from typing_extensions import override from antarest.core.exceptions import ChildNotFoundError from antarest.core.model import JSON @@ -49,6 +50,7 @@ class ReplaceMatrix(ICommand): def matrix_validator(cls, matrix: t.Union[t.List[t.List[MatrixData]], str], values: ValidationInfo) -> str: return validate_matrix(matrix, values.data) + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: return ( CommandOutput( @@ -58,6 +60,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu {}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: if self.target[0] == "@": self.target = AliasDecoder.decode(self.target, study_data) @@ -89,6 +92,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = output, _ = self._apply_config(study_data.config) return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.REPLACE_MATRIX.value, @@ -99,9 +103,11 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.target) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, ReplaceMatrix): return False @@ -109,9 +115,11 @@ def match(self, other: ICommand, equal: bool = False) -> bool: return self.target == other.target and self.matrix == other.matrix return self.target == other.target + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> t.List[str]: assert_this(isinstance(self.matrix, str)) return [strip_matrix_protocol(self.matrix)] 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 5f0f134494..6c247b4c05 100644 --- a/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py +++ b/antarest/study/storage/variantstudy/model/command/update_binding_constraint.py @@ -12,6 +12,8 @@ import typing as t +from typing_extensions import override + from antarest.core.model import JSON from antarest.study.model import STUDY_VERSION_8_7 from antarest.study.storage.rawstudy.model.filesystem.config.binding_constraint import ( @@ -112,6 +114,7 @@ class UpdateBindingConstraint(AbstractBindingConstraintCommand): # Properties of the `UPDATE_BINDING_CONSTRAINT` command: id: str + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: index = next(i for i, bc in enumerate(study_data.bindings) if bc.id == self.id) existing_constraint = study_data.bindings[index] @@ -151,6 +154,7 @@ def _find_binding_config(self, binding_constraints: t.Mapping[str, JSON]) -> t.O return str(index), binding_config return None + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: binding_constraints = study_data.tree.get(["input", "bindingconstraints", "bindingconstraints"]) @@ -200,6 +204,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return super().apply_binding_constraint(study_data, binding_constraints, index, self.id, old_groups=old_groups) + @override def to_dto(self) -> CommandDTO: matrices = ["values"] + [m.value for m in TermMatrices] matrix_service = self.command_context.matrix_service @@ -214,12 +219,15 @@ def to_dto(self) -> CommandDTO: action=self.command_name.value, args=json_command, version=self.version, study_version=self.study_version ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.id) + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [other] + @override def match(self, other: "ICommand", equal: bool = False) -> bool: if not isinstance(other, self.__class__): return False diff --git a/antarest/study/storage/variantstudy/model/command/update_comments.py b/antarest/study/storage/variantstudy/model/command/update_comments.py index 108363a3a3..b5300d171c 100644 --- a/antarest/study/storage/variantstudy/model/command/update_comments.py +++ b/antarest/study/storage/variantstudy/model/command/update_comments.py @@ -12,6 +12,8 @@ from typing import Any, Dict, List, Optional, Tuple +from typing_extensions import override + from antarest.core.model import JSON from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy @@ -37,6 +39,7 @@ class UpdateComments(ICommand): comments: str + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: return ( CommandOutput( @@ -46,6 +49,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, dict(), ) + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: replace_comment_data: JSON = {"settings": {"comments": self.comments.encode("utf-8")}} @@ -54,6 +58,7 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N output, _ = self._apply_config(study_data.config) return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.UPDATE_COMMENTS.value, @@ -63,16 +68,20 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, UpdateComments): return False return not equal or (self.comments == other.comments and equal) + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/update_config.py b/antarest/study/storage/variantstudy/model/command/update_config.py index 258c64e80d..ef054383f0 100644 --- a/antarest/study/storage/variantstudy/model/command/update_config.py +++ b/antarest/study/storage/variantstudy/model/command/update_config.py @@ -13,6 +13,7 @@ import typing as t import typing_extensions as te +from typing_extensions import override from antarest.core.model import JSON from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig @@ -54,6 +55,7 @@ class UpdateConfig(ICommand): target: str data: _Data + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: # The renewable-generation-modelling parameter must be reflected in the config if self.target.startswith("settings"): @@ -64,6 +66,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutpu return CommandOutput(status=True, message="ok"), {} + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: url = self.target.split("/") tree_node = study_data.tree.get_node(url) @@ -78,6 +81,7 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = output, _ = self._apply_config(study_data.config) return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.UPDATE_CONFIG.value, @@ -88,9 +92,11 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.target) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, UpdateConfig): return False @@ -99,8 +105,10 @@ def match(self, other: ICommand, equal: bool = False) -> bool: return simple_match return simple_match and self.data == other.data + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/update_district.py b/antarest/study/storage/variantstudy/model/command/update_district.py index 2819e822a8..5d0b706484 100644 --- a/antarest/study/storage/variantstudy/model/command/update_district.py +++ b/antarest/study/storage/variantstudy/model/command/update_district.py @@ -12,6 +12,8 @@ from typing import Any, Dict, List, Optional, Tuple +from typing_extensions import override + 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 CommandName, CommandOutput @@ -41,6 +43,7 @@ class UpdateDistrict(ICommand): output: Optional[bool] = None comments: Optional[str] = None + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: base_set = study_data.sets[self.id] if self.id not in study_data.sets: @@ -67,6 +70,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, "item_key": item_key, } + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: output, data = self._apply_config(study_data.config) if not output.status: @@ -90,6 +94,7 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N return output + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.UPDATE_DISTRICT.value, @@ -103,9 +108,11 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.id) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, UpdateDistrict): return False @@ -120,8 +127,10 @@ def match(self, other: ICommand, equal: bool = False) -> bool: and self.comments == other.comments ) + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/update_link.py b/antarest/study/storage/variantstudy/model/command/update_link.py index ceab38ed56..16a13fa7e3 100644 --- a/antarest/study/storage/variantstudy/model/command/update_link.py +++ b/antarest/study/storage/variantstudy/model/command/update_link.py @@ -11,6 +11,8 @@ # This file is part of the Antares project. import typing as t +from typing_extensions import override + from antarest.study.business.model.link_model import LinkInternal from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy @@ -32,6 +34,7 @@ class UpdateLink(AbstractLinkCommand): command_name: CommandName = CommandName.UPDATE_LINK version: int = 1 + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> OutputTuple: return ( CommandOutput( @@ -41,6 +44,7 @@ def _apply_config(self, study_data: FileStudyTreeConfig) -> OutputTuple: {}, ) + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: version = study_data.config.version @@ -65,14 +69,18 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = return output + @override def to_dto(self) -> CommandDTO: return super().to_dto() + @override def match_signature(self) -> str: return super().match_signature() + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return super()._create_diff(other) + @override def get_inner_matrices(self) -> t.List[str]: return super().get_inner_matrices() diff --git a/antarest/study/storage/variantstudy/model/command/update_playlist.py b/antarest/study/storage/variantstudy/model/command/update_playlist.py index 7840019672..3c19b9a2f4 100644 --- a/antarest/study/storage/variantstudy/model/command/update_playlist.py +++ b/antarest/study/storage/variantstudy/model/command/update_playlist.py @@ -12,6 +12,8 @@ from typing import Any, Dict, List, Optional, Tuple +from typing_extensions import override + 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.rawstudy.model.helpers import FileStudyHelpers @@ -40,6 +42,7 @@ class UpdatePlaylist(ICommand): weights: Optional[Dict[int, float]] = None reverse: bool = False + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: FileStudyHelpers.set_playlist( study_data, @@ -50,9 +53,11 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N ) return CommandOutput(status=True) + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: return CommandOutput(status=True), {} + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.UPDATE_PLAYLIST.value, @@ -65,9 +70,11 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return CommandName.UPDATE_PLAYLIST.name + @override def match(self, other: "ICommand", equal: bool = False) -> bool: if not isinstance(other, UpdatePlaylist): return False @@ -80,8 +87,10 @@ def match(self, other: "ICommand", equal: bool = False) -> bool: ) return True + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/update_raw_file.py b/antarest/study/storage/variantstudy/model/command/update_raw_file.py index 4090b5ead1..97446dadcc 100644 --- a/antarest/study/storage/variantstudy/model/command/update_raw_file.py +++ b/antarest/study/storage/variantstudy/model/command/update_raw_file.py @@ -13,6 +13,8 @@ import base64 from typing import Any, Dict, List, Optional, Tuple +from typing_extensions import override + 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.rawstudy.model.filesystem.raw_file_node import RawFileNode @@ -39,6 +41,7 @@ class UpdateRawFile(ICommand): target: str b64Data: str + @override def __repr__(self) -> str: cls = self.__class__.__name__ target = self.target @@ -48,9 +51,11 @@ def __repr__(self) -> str: except (ValueError, TypeError): return f"{cls}(target={target!r}, b64Data={self.b64Data!r})" + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> Tuple[CommandOutput, Dict[str, Any]]: return CommandOutput(status=True, message="ok"), {} + @override def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = None) -> CommandOutput: url = self.target.split("/") tree_node = study_data.tree.get_node(url) @@ -63,6 +68,7 @@ def _apply(self, study_data: FileStudy, listener: Optional[ICommandListener] = N study_data.tree.save(base64.decodebytes(self.b64Data.encode("utf-8")), url) return CommandOutput(status=True, message="ok") + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=self.command_name.value, @@ -70,9 +76,11 @@ def to_dto(self) -> CommandDTO: study_version=self.study_version, ) + @override def match_signature(self) -> str: return str(self.command_name.value + MATCH_SIGNATURE_SEPARATOR + self.target) + @override def match(self, other: ICommand, equal: bool = False) -> bool: if not isinstance(other, UpdateRawFile): return False @@ -81,8 +89,10 @@ def match(self, other: ICommand, equal: bool = False) -> bool: return simple_match return simple_match and self.b64Data == other.b64Data + @override def _create_diff(self, other: "ICommand") -> List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py b/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py index 89b12b5e51..4328bcf1fe 100644 --- a/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py +++ b/antarest/study/storage/variantstudy/model/command/update_scenario_builder.py @@ -13,6 +13,7 @@ import typing as t import numpy as np +from typing_extensions import override from antarest.core.requests import CaseInsensitiveDict from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig @@ -54,6 +55,7 @@ class UpdateScenarioBuilder(ICommand): data: t.Union[t.Dict[str, t.Any], t.Mapping[str, t.Any], t.MutableMapping[str, t.Any]] + @override def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = None) -> CommandOutput: """ Apply the command to the study data. @@ -95,17 +97,21 @@ def _apply(self, study_data: FileStudy, listener: t.Optional[ICommandListener] = study_data.tree.save(curr_cfg, url) # type: ignore return CommandOutput(status=True) + @override def _apply_config(self, study_data: FileStudyTreeConfig) -> t.Tuple[CommandOutput, t.Dict[str, t.Any]]: return CommandOutput(status=True), {} + @override def to_dto(self) -> CommandDTO: return CommandDTO( action=CommandName.UPDATE_SCENARIO_BUILDER.value, args={"data": self.data}, study_version=self.study_version ) + @override def match_signature(self) -> str: return CommandName.UPDATE_SCENARIO_BUILDER.value + @override def match(self, other: "ICommand", equal: bool = False) -> bool: if not isinstance(other, UpdateScenarioBuilder): return False @@ -113,8 +119,10 @@ def match(self, other: "ICommand", equal: bool = False) -> bool: return self.data == other.data return True + @override def _create_diff(self, other: "ICommand") -> t.List["ICommand"]: return [other] + @override def get_inner_matrices(self) -> t.List[str]: return [] diff --git a/antarest/study/storage/variantstudy/model/dbmodel.py b/antarest/study/storage/variantstudy/model/dbmodel.py index 180b7105ef..b855a75cf9 100644 --- a/antarest/study/storage/variantstudy/model/dbmodel.py +++ b/antarest/study/storage/variantstudy/model/dbmodel.py @@ -17,6 +17,7 @@ from sqlalchemy import Column, DateTime, ForeignKey, Integer, String # type: ignore from sqlalchemy.orm import relationship # type: ignore +from typing_extensions import override from antarest.core.persistence import Base from antarest.core.serialization import from_json @@ -43,6 +44,7 @@ class VariantStudySnapshot(Base): # type: ignore "polymorphic_identity": "variant_study_snapshot", } + @override def __str__(self) -> str: return f"[Snapshot] id={self.id}, created_at={self.created_at}" @@ -82,6 +84,7 @@ def to_dto(self) -> CommandDTO: updated_at=self.updated_at, ) + @override def __str__(self) -> str: return ( f"CommandBlock(id={self.id!r}," @@ -125,6 +128,7 @@ class VariantStudy(Study): cascade="all, delete, delete-orphan", ) + @override def __str__(self) -> str: return super().__str__() + f", snapshot={self.snapshot}" diff --git a/antarest/study/storage/variantstudy/repository.py b/antarest/study/storage/variantstudy/repository.py index fc4fcc3809..a090b84c5a 100644 --- a/antarest/study/storage/variantstudy/repository.py +++ b/antarest/study/storage/variantstudy/repository.py @@ -13,6 +13,7 @@ import typing as t from sqlalchemy.orm import Session, joinedload # type: ignore +from typing_extensions import override from antarest.core.interfaces.cache import ICache from antarest.core.utils.fastapi_sqlalchemy import db @@ -37,6 +38,7 @@ def __init__(self, cache_service: ICache, session: t.Optional[Session] = None): super().__init__(cache_service) self._session = session + @override @property def session(self) -> Session: """ diff --git a/antarest/study/storage/variantstudy/variant_study_service.py b/antarest/study/storage/variantstudy/variant_study_service.py index 75154dae95..82fed1d98e 100644 --- a/antarest/study/storage/variantstudy/variant_study_service.py +++ b/antarest/study/storage/variantstudy/variant_study_service.py @@ -24,6 +24,7 @@ from antares.study.version import StudyVersion from fastapi import HTTPException from filelock import FileLock +from typing_extensions import override from antarest.core.config import Config from antarest.core.exceptions import ( @@ -532,6 +533,7 @@ def _get_variants_parents(self, id: str, params: RequestParameters) -> t.List[St return output_list + @override def get( self, metadata: VariantStudy, @@ -561,6 +563,7 @@ def get( use_cache=use_cache, ) + @override def get_file( self, metadata: VariantStudy, @@ -870,6 +873,7 @@ def get_study_task(self, study_id: str, params: RequestParameters) -> TaskDTO: return self.task_service.status_task(task_id=task_id, request_params=params, with_logs=True) raise StudyValidationError(f"Variant study '{study_id}' has no generation task") + @override def create(self, study: VariantStudy) -> VariantStudy: """ Create an empty new study. @@ -879,6 +883,7 @@ def create(self, study: VariantStudy) -> VariantStudy: """ raise NotImplementedError() + @override def exists(self, metadata: VariantStudy) -> bool: """ Check if the study snapshot exists and is up-to-date. @@ -894,6 +899,7 @@ def exists(self, metadata: VariantStudy) -> bool: and (self.get_study_path(metadata) / "study.antares").is_file() ) + @override def copy( self, src_meta: VariantStudy, @@ -991,6 +997,7 @@ def _get_snapshot_last_executed_command_index( return last_executed_command_index if last_executed_command_index >= 0 else None return None + @override def get_raw( self, metadata: VariantStudy, @@ -1015,6 +1022,7 @@ def get_raw( use_cache=use_cache, ) + @override def get_study_sim_result(self, study: VariantStudy) -> t.List[StudySimResultDTO]: """ Get global result information @@ -1025,6 +1033,7 @@ def get_study_sim_result(self, study: VariantStudy) -> t.List[StudySimResultDTO] self._safe_generation(study, timeout=600) return super().get_study_sim_result(study=study) + @override def set_reference_output(self, metadata: VariantStudy, output_id: str, status: bool) -> None: """ Set an output to the reference output of a study @@ -1037,6 +1046,7 @@ def set_reference_output(self, metadata: VariantStudy, output_id: str, status: b self.patch_service.set_reference_output(metadata, output_id, status) remove_from_cache(self.cache, metadata.id) + @override def delete(self, metadata: VariantStudy) -> None: """ Delete study @@ -1049,6 +1059,7 @@ def delete(self, metadata: VariantStudy) -> None: shutil.rmtree(study_path) remove_from_cache(self.cache, metadata.id) + @override def delete_output(self, metadata: VariantStudy, output_id: str) -> None: """ Delete a simulation output @@ -1062,6 +1073,7 @@ def delete_output(self, metadata: VariantStudy, output_id: str) -> None: shutil.rmtree(output_path, ignore_errors=True) remove_from_cache(self.cache, metadata.id) + @override def get_study_path(self, metadata: Study) -> Path: """ Get study path @@ -1073,6 +1085,7 @@ def get_study_path(self, metadata: Study) -> Path: """ return Path(metadata.path) / SNAPSHOT_RELATIVE_PATH + @override def export_study_flat( self, metadata: VariantStudy, @@ -1096,6 +1109,7 @@ def export_study_flat( output_src_path, ) + @override def get_synthesis( self, metadata: VariantStudy, @@ -1118,6 +1132,7 @@ def get_synthesis( raise VariantGenerationError(f"Error during light generation of {metadata.id}") + @override def initialize_additional_data(self, variant_study: VariantStudy) -> bool: try: if self.exists(variant_study): diff --git a/antarest/tools/lib.py b/antarest/tools/lib.py index a8cef7e371..03d59a1949 100644 --- a/antarest/tools/lib.py +++ b/antarest/tools/lib.py @@ -22,6 +22,7 @@ import numpy as np from antares.study.version import StudyVersion from httpx import Client +from typing_extensions import override from antarest.core.cache.business.local_chache import LocalCache from antarest.core.config import CacheConfig @@ -76,6 +77,7 @@ def __init__( self.session = session self.host = host + @override def apply_commands( self, commands: List[CommandDTO], @@ -139,6 +141,7 @@ def render_template(self, study_version: StudyVersion = NEW_DEFAULT_STUDY_VERSIO sets_ini = self.output_path.joinpath("input/areas/sets.ini") sets_ini.write_bytes(b"") + @override def apply_commands(self, commands: List[CommandDTO], matrices_dir: Path) -> GenerationResultInfoDTO: stopwatch = StopWatch() matrix_content_repository = MatrixContentRepository( diff --git a/antarest/worker/archive_worker.py b/antarest/worker/archive_worker.py index 6ce01acf85..23bcd3aa69 100644 --- a/antarest/worker/archive_worker.py +++ b/antarest/worker/archive_worker.py @@ -13,6 +13,8 @@ import logging from pathlib import Path +from typing_extensions import override + from antarest.core.config import Config from antarest.core.interfaces.eventbus import IEventBus from antarest.core.serialization import AntaresBaseModel @@ -57,6 +59,7 @@ def __init__( [f"{ArchiveWorker.TASK_TYPE}_{workspace}"], ) + @override def _execute_task(self, task_info: WorkerTaskCommand) -> TaskResult: logger.info(f"Executing task {task_info.model_dump_json()}") try: diff --git a/antarest/worker/worker.py b/antarest/worker/worker.py index f73dd551f0..6de459efbb 100644 --- a/antarest/worker/worker.py +++ b/antarest/worker/worker.py @@ -16,6 +16,8 @@ from concurrent.futures import Future, ThreadPoolExecutor from typing import Any, Dict, List, Union +from typing_extensions import override + from antarest.core.interfaces.eventbus import Event, EventType, IEventBus from antarest.core.interfaces.service import IService from antarest.core.model import PermissionInfo, PublicMode @@ -99,6 +101,7 @@ def __init__( thread_name_prefix="worker_task_", ) + @override def _loop(self) -> None: for task_type in self.accept: self.event_bus.add_queue_consumer(self._listen_for_tasks, task_type)