Skip to content

Commit

Permalink
v2.16.0
Browse files Browse the repository at this point in the history
Merge pull request #1844 from AntaresSimulatorTeam/release/2.16.0
  • Loading branch information
laurent-laporte-pro authored Nov 30, 2023
2 parents 050ed55 + db365d1 commit 50dad17
Show file tree
Hide file tree
Showing 398 changed files with 18,706 additions and 8,109 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/compatibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm install
run: npm install --legacy-peer-deps
working-directory: webapp
- name: Build
run: npm run build
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Install the front-end dependencies:

```shell script
cd webapp
npm install
npm install --legacy-peer-deps
cd ..
```

Expand Down
4 changes: 2 additions & 2 deletions antarest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

# Standard project metadata

__version__ = "2.15.6"
__version__ = "2.16.0"
__author__ = "RTE, Antares Web Team"
__date__ = "2023-11-24"
__date__ = "2023-11-30"
# noinspection SpellCheckingInspection
__credits__ = "(c) Réseau de Transport de l’Électricité (RTE)"

Expand Down
16 changes: 16 additions & 0 deletions antarest/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,19 @@ def __init__(self) -> None:
HTTPStatus.BAD_REQUEST,
"You cannot scan the default internal workspace",
)


class ClusterNotFound(HTTPException):
def __init__(self, cluster_id: str) -> None:
super().__init__(
HTTPStatus.NOT_FOUND,
f"Cluster: '{cluster_id}' not found",
)


class ClusterConfigNotFound(HTTPException):
def __init__(self, area_id: str) -> None:
super().__init__(
HTTPStatus.NOT_FOUND,
f"Cluster configuration for area: '{area_id}' not found",
)
1 change: 0 additions & 1 deletion antarest/core/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class StudyPermissionType(str, enum.Enum):
READ = "READ"
RUN = "RUN"
WRITE = "WRITE"
DELETE = "DELETE"
MANAGE_PERMISSIONS = "MANAGE_PERMISSIONS"


Expand Down
4 changes: 0 additions & 4 deletions antarest/core/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
"roles": [RoleType.ADMIN, RoleType.WRITER],
"public_modes": [PublicMode.FULL, PublicMode.EDIT],
},
StudyPermissionType.DELETE: {
"roles": [RoleType.ADMIN],
"public_modes": [PublicMode.FULL],
},
StudyPermissionType.MANAGE_PERMISSIONS: {
"roles": [RoleType.ADMIN],
"public_modes": [],
Expand Down
36 changes: 34 additions & 2 deletions antarest/core/roles.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
import enum
import functools

__all__ = ["RoleType"]


@functools.total_ordering
class RoleType(enum.Enum):
"""
Role type privilege
Usage:
>>> from antarest.core.roles import RoleType
>>> RoleType.ADMIN == RoleType.ADMIN
True
>>> RoleType.ADMIN == RoleType.WRITER
False
>>> RoleType.ADMIN > RoleType.WRITER
True
>>> RoleType.ADMIN >= RoleType.WRITER
True
>>> # noinspection PyTypeChecker
>>> RoleType.RUNNER > 10
True
>>> # noinspection PyTypeChecker
>>> RoleType.READER > "foo"
Traceback (most recent call last):
...
TypeError: '>' not supported between instances of 'RoleType' and 'str'
"""

ADMIN = 40
WRITER = 30
RUNNER = 20
READER = 10

def is_higher_or_equals(self, other: "RoleType") -> bool:
return int(self.value) >= int(other.value)
def __ge__(self, other: object) -> bool:
"""
Returns `True` if the current role has same or greater privilege than other role.
"""

if isinstance(other, RoleType):
return self.value >= other.value
elif isinstance(other, int):
return self.value >= other
else:
return NotImplemented
97 changes: 62 additions & 35 deletions antarest/core/utils/utils.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import glob
import logging
import os
import shutil
import tempfile
import time
from glob import escape
import typing as t
import zipfile
from pathlib import Path
from typing import IO, Any, Callable, List, Optional, Tuple, TypeVar
from zipfile import ZIP_DEFLATED, BadZipFile, ZipFile

import py7zr
import redis

from antarest.core.config import RedisConfig
from antarest.core.exceptions import BadZipBinary, ShouldNotHappenException
from antarest.core.exceptions import ShouldNotHappenException

logger = logging.getLogger(__name__)

Expand All @@ -24,7 +25,7 @@ class DTO:
def __hash__(self) -> int:
return hash(tuple(sorted(self.__dict__.items())))

def __eq__(self, other: Any) -> bool:
def __eq__(self, other: t.Any) -> bool:
return isinstance(other, type(self)) and self.__dict__ == other.__dict__

def __str__(self) -> str:
Expand All @@ -38,27 +39,53 @@ def __repr__(self) -> str:


def sanitize_uuid(uuid: str) -> str:
return str(escape(uuid))
return str(glob.escape(uuid))


def extract_zip(stream: IO[bytes], dst: Path) -> None:
class BadArchiveContent(Exception):
"""
Exception raised when the archive file is corrupted (or unknown).
"""
Extract zip archive
Args:
stream: zip file
dst: destination path

Returns:
def __init__(self, message: str = "Unsupported archive format") -> None:
super().__init__(message)


def extract_zip(stream: t.BinaryIO, target_dir: Path) -> None:
"""
try:
with ZipFile(stream) as zip_output:
zip_output.extractall(path=dst)
except BadZipFile:
raise BadZipBinary("Only zip file are allowed.")
Extract a ZIP archive to a given destination.
Args:
stream: The stream containing the archive.
target_dir: The directory where to extract the archive.
Raises:
BadArchiveContent: If the archive is corrupted or in an unknown format.
"""

# Read the first few bytes to identify the file format
file_format = stream.read(4)
stream.seek(0)

if file_format[:4] == b"PK\x03\x04":
try:
with zipfile.ZipFile(stream) as zf:
zf.extractall(path=target_dir)
except zipfile.BadZipFile as error:
raise BadArchiveContent("Unsupported ZIP format") from error

elif file_format[:2] == b"7z":
try:
with py7zr.SevenZipFile(stream, "r") as zf:
zf.extractall(target_dir)
except py7zr.exceptions.Bad7zFile as error:
raise BadArchiveContent("Unsupported 7z format") from error

else:
raise BadArchiveContent


def get_default_config_path() -> Optional[Path]:
def get_default_config_path() -> t.Optional[Path]:
config = Path("config.yaml")
if config.exists():
return config
Expand Down Expand Up @@ -98,17 +125,17 @@ def __init__(self) -> None:
def reset_current(self) -> None:
self.current_time = time.time()

def log_elapsed(self, logger: Callable[[float], None], since_start: bool = False) -> None:
logger(time.time() - (self.start_time if since_start else self.current_time))
def log_elapsed(self, logger_: t.Callable[[float], None], since_start: bool = False) -> None:
logger_(time.time() - (self.start_time if since_start else self.current_time))
self.current_time = time.time()


T = TypeVar("T")
T = t.TypeVar("T")


def retry(func: Callable[[], T], attempts: int = 10, interval: float = 0.5) -> T:
def retry(func: t.Callable[[], T], attempts: int = 10, interval: float = 0.5) -> T:
attempt = 0
caught_exception: Optional[Exception] = None
caught_exception: t.Optional[Exception] = None
while attempt < attempts:
try:
attempt += 1
Expand All @@ -120,20 +147,20 @@ def retry(func: Callable[[], T], attempts: int = 10, interval: float = 0.5) -> T
raise caught_exception or ShouldNotHappenException()


def assert_this(b: Any) -> None:
def assert_this(b: t.Any) -> None:
if not b:
raise AssertionError


def concat_files(files: List[Path], target: Path) -> None:
def concat_files(files: t.List[Path], target: Path) -> None:
with open(target, "w") as fh:
for item in files:
with open(item, "r") as infile:
for line in infile:
fh.write(line)


def concat_files_to_str(files: List[Path]) -> str:
def concat_files_to_str(files: t.List[Path]) -> str:
concat_str = ""
for item in files:
with open(item, "r") as infile:
Expand All @@ -143,7 +170,7 @@ def concat_files_to_str(files: List[Path]) -> str:


def zip_dir(dir_path: Path, zip_path: Path, remove_source_dir: bool = False) -> None:
with ZipFile(zip_path, mode="w", compression=ZIP_DEFLATED, compresslevel=2) as zipf:
with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=2) as zipf:
len_dir_path = len(str(dir_path))
for root, _, files in os.walk(dir_path):
for file in files:
Expand All @@ -154,7 +181,7 @@ def zip_dir(dir_path: Path, zip_path: Path, remove_source_dir: bool = False) ->


def unzip(dir_path: Path, zip_path: Path, remove_source_zip: bool = False) -> None:
with ZipFile(zip_path, mode="r") as zipf:
with zipfile.ZipFile(zip_path, mode="r") as zipf:
zipf.extractall(dir_path)
if remove_source_zip:
zip_path.unlink()
Expand All @@ -164,11 +191,11 @@ def is_zip(path: Path) -> bool:
return path.name.endswith(".zip")


def extract_file_to_tmp_dir(zip_path: Path, inside_zip_path: Path) -> Tuple[Path, Any]:
def extract_file_to_tmp_dir(zip_path: Path, inside_zip_path: Path) -> t.Tuple[Path, t.Any]:
str_inside_zip_path = str(inside_zip_path).replace("\\", "/")
tmp_dir = tempfile.TemporaryDirectory()
try:
with ZipFile(zip_path) as zip_obj:
with zipfile.ZipFile(zip_path) as zip_obj:
zip_obj.extract(str_inside_zip_path, tmp_dir.name)
except Exception as e:
logger.warning(
Expand All @@ -184,7 +211,7 @@ def extract_file_to_tmp_dir(zip_path: Path, inside_zip_path: Path) -> Tuple[Path
def read_in_zip(
zip_path: Path,
inside_zip_path: Path,
read: Callable[[Optional[Path]], None],
read: t.Callable[[t.Optional[Path]], None],
) -> None:
tmp_dir = None
try:
Expand All @@ -199,11 +226,11 @@ def read_in_zip(


def suppress_exception(
callback: Callable[[], T],
logger: Callable[[Exception], None],
) -> Optional[T]:
callback: t.Callable[[], T],
logger_: t.Callable[[Exception], None],
) -> t.Optional[T]:
try:
return callback()
except Exception as e:
logger(e)
logger_(e)
return None
Loading

0 comments on commit 50dad17

Please sign in to comment.