Skip to content

Commit

Permalink
setup mypy and fix unitary tests
Browse files Browse the repository at this point in the history
  • Loading branch information
killian-scalian committed Oct 16, 2024
1 parent 26ee084 commit f4ef846
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 51 deletions.
1 change: 1 addition & 0 deletions src/antares/api_conf/request_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# This file is part of the Antares project.

import json

from typing import Any, Dict, Optional, Union

import requests
Expand Down
1 change: 1 addition & 0 deletions src/antares/model/binding_constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from typing import Any, Dict, List, Optional, Union

import pandas as pd

from pydantic import BaseModel, Field, model_validator
from pydantic.alias_generators import to_camel

Expand Down
109 changes: 72 additions & 37 deletions src/antares/model/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from antares.model.settings import StudySettings
from antares.service.api_services.study_api import _returns_study_settings
from antares.service.service_factory import ServiceFactory, ServiceReader
from antares.tools.ini_tool import IniFile
from antares.tools.ini_tool import IniFile, IniFileTypes

"""
The study module defines the data model for antares study.
Expand All @@ -45,17 +45,20 @@
"""


def verify_study_already_exists(study_directory: Path) -> None:
if os.path.exists(study_directory):
raise FileExistsError(f"Failed to create study. Study {study_directory} already exists")


def create_study_api(
study_name: str, version: str, api_config: APIconf, settings: Optional[StudySettings] = None
) -> "Study":
"""
Args:
study_name: antares study name to be created
version: antares version
api_config: host and token config for API
settings: study settings. If not provided, AntaresWeb will use its default values.
Raises:
MissingTokenError if api_token is missing
StudyCreationError if an HTTP Exception occurs
Expand All @@ -77,21 +80,6 @@ def create_study_api(
return Study(study_name, version, ServiceFactory(api_config, study_id), study_settings)


def _verify_study_already_exists(study_directory: Path) -> None:
if os.path.exists(study_directory):
raise FileExistsError(f"Study {study_directory} already exists.")


def _directories_can_be_read(local_path: Path) -> None:
if local_path.is_dir():
try:
for item in local_path.iterdir():
if item.is_dir():
next(item.iterdir())
except PermissionError:
raise PermissionError(f"Some content cannot be accessed in {local_path}")


def create_study_local(
study_name: str, version: str, local_config: LocalConfiguration, settings: Optional[StudySettings] = None
) -> "Study":
Expand All @@ -102,25 +90,55 @@ def create_study_local(
version: antares version for study
local_config: Local configuration options for example directory in which to story the study
settings: study settings. If not provided, AntaresWeb will use its default values.
Raises:
FileExistsError if the study already exists in the given location
ValueError if the provided directory does not exist
"""

def _directory_not_exists(local_path: Path) -> None:
if local_path is None or not os.path.exists(local_path):
raise ValueError(f"Provided directory {local_path} does not exist.")

_directory_not_exists(local_config.local_path)
def _create_directory_structure(study_path: Path) -> None:
subdirectories = [
"input/hydro/allocation",
"input/hydro/common/capacity",
"input/hydro/series",
"input/links",
"input/load/series",
"input/misc-gen",
"input/reserves",
"input/solar/series",
"input/thermal/clusters",
"input/thermal/prepro",
"input/thermal/series",
"input/wind/series",
"layers",
"output",
"settings/resources",
"settings/simulations",
"user",
]
for subdirectory in subdirectories:
(study_path / subdirectory).mkdir(parents=True, exist_ok=True)

def _correlation_defaults() -> dict[str, dict[str, str]]:
return {
"general": {"mode": "annual"},
"annual": {},
"0": {},
"1": {},
"2": {},
"3": {},
"4": {},
"5": {},
"6": {},
"7": {},
"8": {},
"9": {},
"10": {},
"11": {},
}

study_directory = local_config.local_path / study_name

_verify_study_already_exists(study_directory)

# Create the main study directory
os.makedirs(study_directory, exist_ok=True)
verify_study_already_exists(study_directory)
# Create the directory structure
_create_directory_structure(study_directory)

# Create study.antares file with timestamps and study_name
antares_file_path = os.path.join(study_directory, "study.antares")
Expand All @@ -145,18 +163,26 @@ def _directory_not_exists(local_path: Path) -> None:
with open(desktop_ini_path, "w") as desktop_ini_file:
desktop_ini_file.write(desktop_ini_content)

# Create subdirectories
subdirectories = ["input", "layers", "output", "setting", "user"]
for subdirectory in subdirectories:
subdirectory_path = os.path.join(study_directory, subdirectory)
os.makedirs(subdirectory_path, exist_ok=True)
# Create various .ini files for the study
correlation_inis_to_create = [
("solar_correlation", IniFileTypes.SOLAR_CORRELATION_INI),
("wind_correlation", IniFileTypes.WIND_CORRELATION_INI),
("load_correlation", IniFileTypes.LOAD_CORRELATION_INI),
]
ini_files = {
correlation: IniFile(study_directory, file_type, ini_contents=_correlation_defaults())
for (correlation, file_type) in correlation_inis_to_create
}
for ini_file in ini_files.keys():
ini_files[ini_file].write_ini_file()

logging.info(f"Study successfully created: {study_name}")
return Study(
name=study_name,
version=version,
service_factory=ServiceFactory(config=local_config, study_name=study_name),
settings=settings,
ini_files=ini_files,
)


Expand All @@ -174,6 +200,15 @@ def read_study_local(study_name: str, version: str, local_config: LocalConfigura
"""

def _directories_can_be_read(local_path: Path) -> None:
if local_path.is_dir():
try:
for item in local_path.iterdir():
if item.is_dir():
next(item.iterdir())
except PermissionError:
raise PermissionError(f"Some content cannot be accessed in {local_path}")

def _directory_not_exists(local_path: Path) -> None:
if local_path is None or not os.path.exists(local_path):
raise ValueError(f"Provided directory {local_path} does not exist.")
Expand All @@ -195,7 +230,7 @@ def __init__(
version: str,
service_factory: Union[ServiceFactory, ServiceReader],
settings: Optional[StudySettings] = None,
ini_files: Optional[dict[str, IniFile]] = None,
# ini_files: Optional[dict[str, IniFile]] = None,
**kwargs: Any,
):
self.name = name
Expand Down
13 changes: 9 additions & 4 deletions tests/antares/services/local_services/test_study.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import logging
import os
import re
import time

from configparser import ConfigParser
Expand Down Expand Up @@ -130,13 +131,17 @@ def test_verify_study_already_exists_error(self, monkeypatch, tmp_path, caplog):
def mock_verify_study_already_exists(study_directory):
raise FileExistsError(f"Failed to create study. Study {study_directory} already exists")

monkeypatch.setattr("antares.model.study._verify_study_already_exists", mock_verify_study_already_exists)
monkeypatch.setattr("antares.model.study.verify_study_already_exists", mock_verify_study_already_exists)

current_dir = Path(tmp_path)
relative_path = Path(f"{study_name}")
full_path = re.escape(str(current_dir / relative_path))

expected_message = f"Failed to create study. Study {full_path} already exists"

# When
with caplog.at_level(logging.ERROR):
with pytest.raises(
FileExistsError, match=f"Failed to create study. Study {tmp_path}/{study_name} already exists"
):
with pytest.raises(FileExistsError, match=expected_message):
create_study_local(study_name, version, LocalConfiguration(tmp_path, study_name))

def test_solar_correlation_ini_exists(self, local_study_with_hydro):
Expand Down
36 changes: 26 additions & 10 deletions tests/antares/services/local_services/test_study_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import pytest

import logging
import re

from pathlib import Path
from unittest import mock

from antares.config.local_configuration import LocalConfiguration
Expand All @@ -22,12 +24,16 @@

class TestReadStudy:
def test_directory_not_exists_error(self, caplog):
local_path = r"fake/path/"
study_name = "study_name"

current_dir = Path.cwd()
relative_path = Path("fake/path/")
full_path = current_dir / relative_path
escaped_full_path = re.escape(str(full_path))

with caplog.at_level(logging.ERROR):
regex_pattern = r"Provided directory fake\\path does not exist\."
with pytest.raises(ValueError, match=regex_pattern):
read_study_local(study_name, "880", LocalConfiguration(local_path, study_name))
with pytest.raises(ValueError, match=escaped_full_path):
read_study_local(study_name, "880", LocalConfiguration(full_path, study_name))

def test_directory_permission_denied(self, tmp_path, caplog):
# Given
Expand All @@ -50,9 +56,13 @@ def test_directory_permission_denied(self, tmp_path, caplog):
read_study_local(study_name, "880", LocalConfiguration(tmp_path, study_name))

def test_read_study_service(self, caplog):
local_path = r"../../studies_samples/"
study_name = "hydro_stockage"
content = read_study_local(study_name, "880", LocalConfiguration(local_path, study_name))

current_dir = Path.cwd()
relative_path = Path("../../studies_samples/")
full_path = current_dir / relative_path

content = read_study_local(study_name, "880", LocalConfiguration(full_path, study_name))

areas = content.service.read_areas()
study = content.service.read_study(areas)
Expand All @@ -67,10 +77,13 @@ def test_read_study_service(self, caplog):
), f"La clé '{not_expected_key}' ne devrait pas être présente dans le dictionnaire 'study'"

def test_directory_renewable_thermique(self, caplog):
local_path = r"../../studies_samples/"
study_name = "renewable_thermique"

content = read_study_local(study_name, "880", LocalConfiguration(local_path, study_name))
current_dir = Path.cwd()
relative_path = Path("../../studies_samples/")
full_path = current_dir / relative_path

content = read_study_local(study_name, "880", LocalConfiguration(full_path, study_name))
areas = content.service.read_areas()
study = content.service.read_study(areas)
assert study["thermals"].get("zone_rt").get("list") == {
Expand Down Expand Up @@ -138,10 +151,13 @@ def test_directory_renewable_thermique(self, caplog):
}

def test_directory_hydro_stockage(self, caplog):
local_path = r"../../studies_samples/"
study_name = "hydro_stockage"
content = read_study_local(study_name, "880", LocalConfiguration(local_path, study_name))

current_dir = Path.cwd()
relative_path = Path("../../studies_samples/")
full_path = current_dir / relative_path

content = read_study_local(study_name, "880", LocalConfiguration(full_path, study_name))
areas = content.service.read_areas()
study = content.service.read_study(areas)

Expand Down

0 comments on commit f4ef846

Please sign in to comment.