Skip to content

Commit 47a953f

Browse files
committed
Create separate function for inject_extra_info and handle batch data
Signed-off-by: Bram Stoeller <[email protected]>
1 parent e4230d5 commit 47a953f

File tree

2 files changed

+106
-10
lines changed

2 files changed

+106
-10
lines changed

src/power_grid_model/manual_testing.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import json
1010
from pathlib import Path
11-
from typing import Any, Dict, List, IO, Optional, Union
11+
from typing import IO, Any, Dict, List, Optional, Union
1212

1313
import numpy as np
1414

@@ -256,7 +256,7 @@ def export_json_data(
256256
data: Union[Dict[str, np.ndarray], List[Dict[str, np.ndarray]]],
257257
indent: Optional[int] = 2,
258258
compact: bool = False,
259-
extra_info: Optional[Dict[int, Any]] = None,
259+
extra_info: Optional[Union[Dict[int, Any], List[Dict[int, Any]]]] = None,
260260
):
261261
"""
262262
export json data
@@ -272,13 +272,8 @@ def export_json_data(
272272
Save to file
273273
"""
274274
json_data = convert_numpy_to_python(data)
275-
276-
# Inject extra info
277275
if extra_info is not None:
278-
for component, objects in json_data.items():
279-
for obj in objects:
280-
if obj["id"] in extra_info:
281-
obj["extra"] = extra_info[obj["id"]]
276+
_inject_extra_info(data=json_data, extra_info=extra_info)
282277

283278
with open(json_file, mode="w", encoding="utf-8") as file_pointer:
284279
if compact and indent:
@@ -289,6 +284,38 @@ def export_json_data(
289284
json.dump(json_data, file_pointer, indent=indent)
290285

291286

287+
def _inject_extra_info(
288+
data: Union[Dict[str, List[Dict[str, Union[float, int]]]], List[Dict[str, List[Dict[str, Union[float, int]]]]]],
289+
extra_info: Union[Dict[int, Any], List[Dict[int, Any]]],
290+
):
291+
"""
292+
Injects extra info to the objects by ID
293+
294+
Args:
295+
data: Power Grid Model Python data, as written to pgm json files.
296+
extra_info: A dictionary indexed by object id. The value may be anything.
297+
298+
"""
299+
if isinstance(data, list):
300+
if isinstance(extra_info, list):
301+
# If both data and extra_info are lists, expect one extra info set per batch
302+
for batch, info in zip(data, extra_info):
303+
_inject_extra_info(batch, info)
304+
else:
305+
# If only data is a list, copy extra_info for each batch
306+
for batch in data:
307+
_inject_extra_info(batch, extra_info)
308+
elif isinstance(data, dict):
309+
if not isinstance(extra_info, dict):
310+
raise TypeError("Invalid extra info data type")
311+
for component, objects in data.items():
312+
for obj in objects:
313+
if obj["id"] in extra_info:
314+
obj["extra"] = extra_info[obj["id"]]
315+
else:
316+
raise TypeError("Invalid data type")
317+
318+
292319
def _compact_json_dump(data: Any, io_stream: IO[str], indent: int, max_level: int, level: int = 0):
293320
"""Custom compact JSON writer that is intended to put data belonging to a single object on a single line.
294321

tests/unit/test_manual_testing.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44

55
import io
66
from pathlib import Path
7-
from unittest.mock import patch, mock_open, MagicMock
7+
from unittest.mock import MagicMock, mock_open, patch
88

99
import numpy as np
1010
import pytest
11+
1112
from power_grid_model.manual_testing import (
13+
_compact_json_dump,
14+
_inject_extra_info,
1215
convert_batch_to_list_data,
1316
convert_numpy_to_python,
1417
convert_python_to_numpy,
1518
export_json_data,
1619
is_nan,
17-
_compact_json_dump,
1820
)
1921

2022

@@ -136,6 +138,73 @@ def test_export_json_data(convert_mock: MagicMock, open_mock: MagicMock, json_du
136138
json_dump_mock.assert_called_once_with({"foo": [{"val": 123}]}, open_mock(), indent=2)
137139

138140

141+
@patch("json.dump")
142+
@patch("builtins.open", new_callable=mock_open)
143+
@patch("power_grid_model.manual_testing.convert_numpy_to_python")
144+
@patch("power_grid_model.manual_testing._inject_extra_info")
145+
def test_export_json_data_extra_info(
146+
extra_info_mock: MagicMock, convert_mock: MagicMock, _open_mock: MagicMock, _json_dump_mock: MagicMock
147+
):
148+
convert_mock.return_value = {"foo": [{"id": 123}]}
149+
export_json_data(json_file=Path(), data={}, extra_info={123: "Extra information"})
150+
extra_info_mock.assert_called_once_with(data={"foo": [{"id": 123}]}, extra_info={123: "Extra information"})
151+
152+
153+
def test_inject_extra_info_single():
154+
data = {"node": [{"id": 0, "foo": 123}, {"id": 1, "bar": 456}], "line": [{"id": 2, "baz": 789}]}
155+
extra_info = {2: 42, 1: {"sheet": "Nodes", "Number": "00123"}}
156+
_inject_extra_info(data=data, extra_info=extra_info)
157+
assert data == {
158+
"node": [{"id": 0, "foo": 123}, {"id": 1, "bar": 456, "extra": {"sheet": "Nodes", "Number": "00123"}}],
159+
"line": [{"id": 2, "baz": 789, "extra": 42}],
160+
}
161+
162+
163+
def test_inject_extra_info_batch():
164+
data = [
165+
{"node": [{"id": 0, "foo": 111}, {"id": 1, "bar": 222}], "line": [{"id": 2, "baz": 333}]},
166+
{"node": [{"id": 0, "foo": 444}, {"id": 1, "bar": 555}], "line": [{"id": 2, "baz": 666}]},
167+
]
168+
extra_info = [{2: 42, 1: {"sheet": "Nodes", "Number": "00123"}}, {2: 43, 0: None}]
169+
_inject_extra_info(data=data, extra_info=extra_info)
170+
assert data == [
171+
{
172+
"node": [{"id": 0, "foo": 111}, {"id": 1, "bar": 222, "extra": {"sheet": "Nodes", "Number": "00123"}}],
173+
"line": [{"id": 2, "baz": 333, "extra": 42}],
174+
},
175+
{
176+
"node": [{"id": 0, "foo": 444, "extra": None}, {"id": 1, "bar": 555}],
177+
"line": [{"id": 2, "baz": 666, "extra": 43}],
178+
},
179+
]
180+
181+
182+
def test_inject_extra_info_batch_copy_info():
183+
data = [
184+
{"node": [{"id": 0, "foo": 111}, {"id": 1, "bar": 222}], "line": [{"id": 2, "baz": 333}]},
185+
{"node": [{"id": 0, "foo": 444}, {"id": 1, "bar": 555}], "line": [{"id": 2, "baz": 666}]},
186+
]
187+
extra_info = {2: 42, 1: {"sheet": "Nodes", "Number": "00123"}}
188+
_inject_extra_info(data=data, extra_info=extra_info)
189+
assert data == [
190+
{
191+
"node": [{"id": 0, "foo": 111}, {"id": 1, "bar": 222, "extra": {"sheet": "Nodes", "Number": "00123"}}],
192+
"line": [{"id": 2, "baz": 333, "extra": 42}],
193+
},
194+
{
195+
"node": [{"id": 0, "foo": 444}, {"id": 1, "bar": 555, "extra": {"sheet": "Nodes", "Number": "00123"}}],
196+
"line": [{"id": 2, "baz": 666, "extra": 42}],
197+
},
198+
]
199+
200+
201+
def test_inject_extra_info_single_dataset_with_batch_info():
202+
data = {"node": [{"id": 0, "foo": 123}, {"id": 1, "bar": 456}], "line": [{"id": 2, "baz": 789}]}
203+
extra_info = [{2: 42, 1: {"sheet": "Nodes", "Number": "00123"}}, {2: 43, 0: None}]
204+
with pytest.raises(TypeError):
205+
_inject_extra_info(data=data, extra_info=extra_info)
206+
207+
139208
def test_compact_json_dump():
140209
data = {
141210
"node": [{"id": 1, "x": 2}, {"id": 3, "x": 4}],

0 commit comments

Comments
 (0)