Skip to content

Commit af95cc5

Browse files
authored
Merge pull request #855 from simvue-io/wk9874/multi_d_offline_fix
Fixes offline mode for multi dimensional metrics
2 parents 1e9adc6 + 7babbec commit af95cc5

File tree

4 files changed

+66
-25
lines changed

4 files changed

+66
-25
lines changed

simvue/api/objects/grids.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,14 @@ def on_reconnect(self, id_mapping: dict[str, str]) -> None:
7979
id_mapping : dict[str, str]
8080
mapping from offline identifier to new online identifier.
8181
"""
82-
for run_id, metric_name in self._staging.pop("runs", []):
82+
_online_runs = (
83+
(id_mapping[run_id], metric_name)
84+
for run_id, metric_name in self._staging.pop("runs", [])
85+
)
86+
super().commit()
87+
for run_id, metric_name in _online_runs:
8388
try:
84-
self.attach_metric_for_run(
85-
run_id=id_mapping[run_id], metric_name=metric_name
86-
)
89+
self.attach_metric_for_run(run_id=run_id, metric_name=metric_name)
8790
except KeyError:
8891
raise RuntimeError("Failed to retrieve online run identifier.")
8992

@@ -146,6 +149,7 @@ def new(
146149
name=name,
147150
_read_only=False,
148151
_offline=offline,
152+
**kwargs,
149153
)
150154

151155
@property

simvue/run.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,10 @@ def assign_metric_to_grid(
14601460
return False
14611461

14621462
try:
1463-
_grid_attach = Grid(identifier=self._grids[grid_name]["id"])
1463+
_grid_attach = Grid(
1464+
identifier=self._grids[grid_name]["id"],
1465+
offline=self._user_config.run.mode == "offline",
1466+
)
14641467
_grid_attach.read_only(False)
14651468
_grid_attach.attach_metric_for_run(self.id, metric_name)
14661469
self._grids[metric_name] = self._grids[grid_name]

tests/functional/test_run_class.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,25 @@ def test_log_metrics_online(
236236
run.close()
237237

238238
#TODO: No client functions defined for grids yet
239-
if metric_type != "tensor":
240-
239+
# Temporary solution - use direct API endpoints
240+
if metric_type == "tensor":
241+
for name, values in METRICS.items():
242+
if overload_buffer:
243+
for i in range(run._dispatcher._max_buffer_size * 3):
244+
response = requests.get(
245+
url=f"{run._user_config.server.url}/runs/{run.id}/metrics/{name}/values?step={i}",
246+
headers=run._sv_obj._headers,
247+
)
248+
assert response.status_code == 200
249+
numpy.testing.assert_almost_equal(numpy.array(response.json().get("array")), i * numpy.identity(10))
250+
else:
251+
response = requests.get(
252+
url=f"{run._user_config.server.url}/runs/{run.id}/metrics/{name}/values?step=0",
253+
headers=run._sv_obj._headers,
254+
)
255+
assert response.status_code == 200
256+
numpy.testing.assert_almost_equal(numpy.array(response.json().get("array")), values)
257+
else:
241258
time.sleep(2.0 if overload_buffer else 1.0)
242259
client = sv_cl.Client()
243260
_data = client.get_metric_values(
@@ -282,7 +299,6 @@ def test_log_metrics_offline(
282299
create_plain_run_offline: tuple[sv_run.Run, dict],
283300
metric_type: typing.Literal["regular", "tensor"]
284301
) -> None:
285-
METRICS = {"a": 10, "b": 1.2, "c": 2}
286302
run, _ = create_plain_run_offline
287303
run_name = run.name
288304
if metric_type == "tensor":
@@ -296,25 +312,43 @@ def test_log_metrics_offline(
296312
]),
297313
axes_labels=["x", "y"]
298314
)
315+
else:
316+
METRICS = {"a": 10, "b": 1.2, "c": 2}
317+
299318
run.log_metrics(METRICS)
300-
client = sv_cl.Client()
301-
sv_send.sender(os.environ["SIMVUE_OFFLINE_DIRECTORY"], 2, 10)
302-
attempts: int = 0
319+
320+
time.sleep(1)
321+
id_mapping = sv_send.sender(os.environ["SIMVUE_OFFLINE_DIRECTORY"], 2, 10)
322+
time.sleep(1)
323+
324+
if metric_type == "tensor":
325+
for name, values in METRICS.items():
326+
response = requests.get(
327+
url=f"{run._user_config.server.url}/runs/{id_mapping[run.id]}/metrics/{name}/values?step=0",
328+
headers={
329+
"Authorization": f"Bearer {run._user_config.server.token.get_secret_value()}",
330+
"User-Agent": "Simvue Python client",
331+
"Accept-Encoding": "gzip",
332+
}
333+
)
334+
assert response.status_code == 200
335+
numpy.testing.assert_almost_equal(numpy.array(response.json().get("array")), values)
336+
else:
337+
client = sv_cl.Client()
303338

304-
while not (_data := client.get_metric_values(
305-
run_ids=[client.get_run_id_from_name(run_name)],
306-
metric_names=list(METRICS.keys()),
307-
xaxis="step",
308-
aggregate=False,
309-
)) and attempts < 5:
310-
sv_send.sender(os.environ["SIMVUE_OFFLINE_DIRECTORY"], 2, 10)
339+
_data = client.get_metric_values(
340+
run_ids=[client.get_run_id_from_name(run_name)],
341+
metric_names=list(METRICS.keys()),
342+
xaxis="step",
343+
aggregate=False,
344+
)
311345

312-
assert sorted(set(METRICS.keys())) == sorted(set(_data.keys()))
313-
_steps = []
314-
for entry in _data.values():
315-
_steps += [i[0] for i in entry.keys()]
316-
_steps = set(_steps)
317-
assert len(_steps) == 1
346+
assert sorted(set(METRICS.keys())) == sorted(set(_data.keys()))
347+
_steps = []
348+
for entry in _data.values():
349+
_steps += [i[0] for i in entry.keys()]
350+
_steps = set(_steps)
351+
assert len(_steps) == 1
318352

319353
@pytest.mark.run
320354
@pytest.mark.parametrize(

tests/unit/test_grids.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def test_grid_creation_offline() -> None:
7272
with _grid._local_staging_file.open() as in_f:
7373
_local_data = json.load(in_f)
7474

75-
assert _local_data.get("runs", [None])[0] == _run.id
75+
assert _local_data.get("runs", [None])[0] == [_run.id, "A"]
7676
npt.assert_array_equal(numpy.array(_local_data.get("grid")), _grid_def)
7777
_id_mapping = sender(_grid._local_staging_file.parents[1], 1, 10, ["folders", "runs", "grids"])
7878
time.sleep(1)

0 commit comments

Comments
 (0)