Skip to content

Commit

Permalink
feat(api): fix single dict response in read_outputs and minor changes
Browse files Browse the repository at this point in the history
  • Loading branch information
salemsd committed Dec 17, 2024
1 parent 68ff655 commit 04f6f2e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 197 deletions.
12 changes: 7 additions & 5 deletions src/antares/model/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,24 +381,26 @@ def read_outputs(self) -> list[Output]:
self._outputs = {output.name: output for output in outputs}
return outputs

def get_outputs(self) -> dict[str, Output]:
def get_outputs(self) -> MappingProxyType[str, Output]:
"""
Get outputs of current study
Returns: (output_id, Output) dictionary
Returns: read-only proxy of the (output_id, Output) mapping
"""
return self._outputs.copy()
return MappingProxyType(self._outputs)

def get_output(self, output_id: str) -> Optional[Output]:
def get_output(self, output_id: str) -> Output:
"""
Get a specific output
Args:
output_id: id of the output to get
Returns: Output with the output_id
Raises: KeyError if it doesn't exist
"""
return self._outputs.get(output_id)
return self._outputs["output_id"]


def _verify_study_already_exists(study_directory: Path) -> None:
Expand Down
9 changes: 5 additions & 4 deletions src/antares/service/api_services/output_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.


from antares.api_conf.api_conf import APIconf
from antares.api_conf.request_wrapper import RequestWrapper
from antares.exceptions.exceptions import APIError, OutputsRetrievalError
Expand All @@ -29,9 +31,8 @@ def read_outputs(self) -> list[Output]:
try:
response = self._wrapper.get(url)
outputs_json_list = response.json()
outputs_list: list[Output] = list()
for output in outputs_json_list:
outputs_list.append(Output(name=output["name"], archived=output["archived"]))
return outputs_list
if isinstance(outputs_json_list, dict):
outputs_json_list = [outputs_json_list]
return [Output(name=output["name"], archived=output["archived"]) for output in outputs_json_list]
except APIError as e:
raise OutputsRetrievalError(self.study_id, e.message)
5 changes: 5 additions & 0 deletions src/antares/service/local_services/output_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# This file is part of the Antares project.
from typing import Any

from pandas import DataFrame

from antares.config.local_configuration import LocalConfiguration
from antares.model.output import Output
from antares.service.base_services import BaseOutputService
Expand All @@ -24,3 +26,6 @@ def __init__(self, config: LocalConfiguration, study_name: str, **kwargs: Any) -

def read_outputs(self) -> list[Output]:
raise NotImplementedError

def get_matrix(self, path: str) -> DataFrame:
raise NotImplementedError
223 changes: 38 additions & 185 deletions tests/antares/services/api_services/test_study_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,184 +53,6 @@ class TestCreateAPI:
ServiceFactory(api, study_id).create_thermal_service(),
ServiceFactory(api, study_id).create_renewable_service(),
)
json_output = [
{
"name": "20241217-1114eco",
"type": "economy",
"settings": {
"general": {
"mode": "Economy",
"horizon": "",
"nbyears": 1,
"simulation.start": 1,
"simulation.end": 365,
"january.1st": "Monday",
"first-month-in-year": "january",
"first.weekday": "Monday",
"leapyear": False,
"year-by-year": False,
"derated": False,
"custom-scenario": False,
"user-playlist": False,
"thematic-trimming": False,
"geographic-trimming": False,
"generate": "",
"nbtimeseriesload": 1,
"nbtimeserieshydro": 1,
"nbtimeserieswind": 1,
"nbtimeseriesthermal": 1,
"nbtimeseriessolar": 1,
"refreshtimeseries": "",
"intra-modal": "",
"inter-modal": "",
"refreshintervalload": 100,
"refreshintervalhydro": 100,
"refreshintervalwind": 100,
"refreshintervalthermal": 100,
"refreshintervalsolar": 100,
"readonly": False,
},
"input": {"import": ""},
"output": {"synthesis": True, "storenewset": False, "archives": ""},
"optimization": {
"simplex-range": "week",
"transmission-capacities": "local-values",
"link-type": "local",
"include-constraints": True,
"include-hurdlecosts": True,
"include-tc-minstablepower": True,
"include-tc-min-ud-time": True,
"include-dayahead": True,
"include-strategicreserve": True,
"include-spinningreserve": True,
"include-primaryreserve": True,
"include-exportmps": False,
"include-exportstructure": False,
"include-unfeasible-problem-behavior": "error-verbose",
},
"otherPreferences": {
"initial-reservoir-levels": "cold start",
"hydro-heuristic-policy": "accommodate rule curves",
"hydro-pricing-mode": "fast",
"power-fluctuations": "free modulations",
"shedding-strategy": "share margins",
"shedding-policy": "shave peaks",
"unit-commitment-mode": "fast",
"number-of-cores-mode": "medium",
"renewable-generation-modelling": "clusters",
"day-ahead-reserve-management": "global",
},
"advancedParameters": {"accuracy-on-correlation": "", "adequacy-block-size": 100},
"seedsMersenneTwister": {
"seed-tsgen-wind": 5489,
"seed-tsgen-load": 1005489,
"seed-tsgen-hydro": 2005489,
"seed-tsgen-thermal": 3005489,
"seed-tsgen-solar": 4005489,
"seed-tsnumbers": 5005489,
"seed-unsupplied-energy-costs": 6005489,
"seed-spilled-energy-costs": 7005489,
"seed-thermal-costs": 8005489,
"seed-hydro-costs": 9005489,
"seed-initial-reservoir-levels": 10005489,
},
"playlist": [],
},
"completionDate": "",
"referenceStatus": False,
"synchronized": False,
"status": "",
"archived": False,
},
{
"name": "20241217-1115eco-sdqsd",
"type": "economy",
"settings": {
"general": {
"mode": "Economy",
"horizon": "",
"nbyears": 1,
"simulation.start": 1,
"simulation.end": 365,
"january.1st": "Monday",
"first-month-in-year": "january",
"first.weekday": "Monday",
"leapyear": False,
"year-by-year": False,
"derated": False,
"custom-scenario": False,
"user-playlist": False,
"thematic-trimming": False,
"geographic-trimming": False,
"generate": "",
"nbtimeseriesload": 1,
"nbtimeserieshydro": 1,
"nbtimeserieswind": 1,
"nbtimeseriesthermal": 1,
"nbtimeseriessolar": 1,
"refreshtimeseries": "",
"intra-modal": "",
"inter-modal": "",
"refreshintervalload": 100,
"refreshintervalhydro": 100,
"refreshintervalwind": 100,
"refreshintervalthermal": 100,
"refreshintervalsolar": 100,
"readonly": False,
},
"input": {"import": ""},
"output": {"synthesis": True, "storenewset": False, "archives": ""},
"optimization": {
"simplex-range": "week",
"transmission-capacities": "local-values",
"link-type": "local",
"include-constraints": True,
"include-hurdlecosts": True,
"include-tc-minstablepower": True,
"include-tc-min-ud-time": True,
"include-dayahead": True,
"include-strategicreserve": True,
"include-spinningreserve": True,
"include-primaryreserve": True,
"include-exportmps": False,
"include-exportstructure": False,
"include-unfeasible-problem-behavior": "error-verbose",
},
"otherPreferences": {
"initial-reservoir-levels": "cold start",
"hydro-heuristic-policy": "accommodate rule curves",
"hydro-pricing-mode": "fast",
"power-fluctuations": "free modulations",
"shedding-strategy": "share margins",
"shedding-policy": "shave peaks",
"unit-commitment-mode": "fast",
"number-of-cores-mode": "medium",
"renewable-generation-modelling": "clusters",
"day-ahead-reserve-management": "global",
},
"advancedParameters": {"accuracy-on-correlation": "", "adequacy-block-size": 100},
"seedsMersenneTwister": {
"seed-tsgen-wind": 5489,
"seed-tsgen-load": 1005489,
"seed-tsgen-hydro": 2005489,
"seed-tsgen-thermal": 3005489,
"seed-tsgen-solar": 4005489,
"seed-tsnumbers": 5005489,
"seed-unsupplied-energy-costs": 6005489,
"seed-spilled-energy-costs": 7005489,
"seed-thermal-costs": 8005489,
"seed-hydro-costs": 9005489,
"seed-initial-reservoir-levels": 10005489,
},
"playlist": [],
},
"completionDate": "",
"referenceStatus": False,
"synchronized": False,
"status": "",
"archived": False,
},
]

def test_create_study_test_ok(self) -> None:
with requests_mock.Mocker() as mocker:
Expand Down Expand Up @@ -395,7 +217,15 @@ def test_read_study_api(self):
mocker.get(renewable_url, json=[])
mocker.get(thermal_url, json=[])
mocker.get(storage_url, json=[])
mocker.get(output_url, json=self.json_output)
mocker.get(
output_url,
json={
"name": "20241217-1115eco-sdqsd",
"type": "economy",
"settings": {},
"archived": False,
},
)
actual_study = read_study_api(self.api, self.study_id)

expected_study_name = json_study.pop("name")
Expand Down Expand Up @@ -431,7 +261,16 @@ def test_create_variant_success(self):
mocker.get(areas_url, json={}, status_code=200)

output_url = f"{base_url}/studies/{variant_id}/outputs"
mocker.get(output_url, json=self.json_output, status_code=200)
mocker.get(
output_url,
json={
"name": "20241217-1115eco-sdqsd",
"type": "economy",
"settings": {},
"archived": False,
},
status_code=200,
)

variant = self.study.create_variant(variant_name)
variant_from_api = create_variant_api(self.api, self.study_id, variant_name)
Expand Down Expand Up @@ -614,17 +453,31 @@ def test_read_outputs(self):
with requests_mock.Mocker() as mocker:
run_url = f"https://antares.com/api/v1/studies/{self.study_id}/outputs"

mocker.get(run_url, json=self.json_output, status_code=200)
json_output = [
{
"name": "20241217-1115eco-sdqsd",
"type": "economy",
"settings": {},
"archived": False,
},
{
"name": "20241217-1115eco-abcd",
"type": "economy",
"settings": {},
"archived": True,
},
]
mocker.get(run_url, json=json_output, status_code=200)

self.study.read_outputs()

assert len(self.study.get_outputs()) == 2
output1 = self.study.get_output(self.json_output[0].get("name"))
output2 = self.study.get_output(self.json_output[1].get("name"))
output1 = self.study.get_output(json_output[0].get("name"))
output2 = self.study.get_output(json_output[1].get("name"))
assert output1 is not None
assert output2 is not None
assert output1.archived == self.json_output[0].get("archived")
assert output2.archived == self.json_output[1].get("archived")
assert output1.archived == json_output[0].get("archived")
assert output2.archived == json_output[1].get("archived")

# ===== FAILING TEST =====
error_message = f"Couldn't get outputs for study {self.study_id}"
Expand Down
7 changes: 4 additions & 3 deletions tests/integration/test_web_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ def test_creation_lifecycle(self, antares_web: AntaresWebDesktop):
new_study.get_binding_constraints().keys()
)

# ===== Test outputs (Part 1) =====
# ===== Test outputs (Part 1 - before simulation) =====

assert len(study.read_outputs()) == 0

Expand All @@ -520,8 +520,9 @@ def test_creation_lifecycle(self, antares_web: AntaresWebDesktop):

# ===== Test outputs (Part 2 - after simulation) =====

study.read_outputs()
output = study.read_outputs()[0]
outputs = study.get_outputs()
assert len(outputs) > 0
assert len(outputs) == 1
assert outputs.get(output.name).archived == False
study_with_outputs = read_study_api(api_config, study._study_service.study_id)
assert study_with_outputs.get_outputs() == outputs

0 comments on commit 04f6f2e

Please sign in to comment.