Skip to content

Commit fdea3d7

Browse files
authored
Merge pull request #844 from simvue-io/kzscisoft/833-add-support-for-multidimensional-metrics
Add support for multidimensional metrics
2 parents 36b9eee + af95cc5 commit fdea3d7

File tree

14 files changed

+1616
-470
lines changed

14 files changed

+1616
-470
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Improves handling of Conda based environments in metadata collection.
66
- Adds additional options to `Client.get_runs`.
77
- Added ability to include environment variables within metadata for runs.
8+
- Added new feature allowing users to log tensors as multidimensional metrics after defining a grid.
89
- Improves checks on `offline.cache` directory specification in config file.
910

1011
## [v2.1.2](https://github.com/simvue-io/client/releases/tag/v2.1.2) - 2025-06-25

poetry.lock

Lines changed: 567 additions & 385 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

simvue/api/objects/__init__.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,54 @@
88
99
"""
1010

11-
from .administrator import Tenant as Tenant, User as User
11+
from .administrator import Tenant, User
1212
from .alert import (
13-
Alert as Alert,
14-
EventsAlert as EventsAlert,
15-
MetricsThresholdAlert as MetricsThresholdAlert,
16-
MetricsRangeAlert as MetricsRangeAlert,
17-
UserAlert as UserAlert,
13+
Alert,
14+
EventsAlert,
15+
MetricsThresholdAlert,
16+
MetricsRangeAlert,
17+
UserAlert,
1818
)
1919
from .storage import (
20-
S3Storage as S3Storage,
21-
FileStorage as FileStorage,
22-
Storage as Storage,
20+
S3Storage,
21+
FileStorage,
22+
Storage,
2323
)
2424
from .artifact import (
25-
FileArtifact as FileArtifact,
26-
ObjectArtifact as ObjectArtifact,
27-
Artifact as Artifact,
25+
FileArtifact,
26+
ObjectArtifact,
27+
Artifact,
2828
)
2929

30-
from .stats import Stats as Stats
31-
from .run import Run as Run
32-
from .tag import Tag as Tag
33-
from .folder import Folder as Folder, get_folder_from_path as get_folder_from_path
30+
from .stats import Stats
31+
from .run import Run
32+
from .tag import Tag
33+
from .folder import Folder, get_folder_from_path
3434
from .events import Events as Events
3535
from .metrics import Metrics as Metrics
36+
from .grids import Grid, GridMetrics
37+
38+
__all__ = [
39+
"Grid",
40+
"GridMetrics",
41+
"Metrics",
42+
"Events",
43+
"get_folder_from_path",
44+
"Folder",
45+
"Stats",
46+
"Run",
47+
"Tag",
48+
"Artifact",
49+
"FileArtifact",
50+
"ObjectArtifact",
51+
"S3Storage",
52+
"FileStorage",
53+
"Storage",
54+
"MetricsRangeAlert",
55+
"MetricsThresholdAlert",
56+
"UserAlert",
57+
"EventsAlert",
58+
"Alert",
59+
"Tenant",
60+
"User",
61+
]

simvue/api/objects/base.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,22 @@ def count(cls, **kwargs) -> int:
461461

462462
@classmethod
463463
def _get_all_objects(
464-
cls, offset: int | None, count: int | None, **kwargs
464+
cls,
465+
offset: int | None,
466+
count: int | None,
467+
endpoint: str | None = None,
468+
expected_type: type = dict,
469+
**kwargs,
465470
) -> typing.Generator[dict, None, None]:
466471
_class_instance = cls(_read_only=True)
467-
_url = f"{_class_instance._base_url}"
472+
473+
# Allow the possibility of paginating a URL that is not the
474+
# main class endpoint
475+
_url = (
476+
f"{_class_instance._user_config.server.url}/{endpoint}"
477+
if endpoint
478+
else f"{_class_instance._base_url}"
479+
)
468480

469481
_label = _class_instance.__class__.__name__.lower()
470482
if _label.endswith("s"):
@@ -473,12 +485,18 @@ def _get_all_objects(
473485
for response in get_paginated(
474486
_url, headers=_class_instance._headers, offset=offset, count=count, **kwargs
475487
):
476-
yield get_json_from_response(
488+
_generator = get_json_from_response(
477489
response=response,
478490
expected_status=[http.HTTPStatus.OK],
479491
scenario=f"Retrieval of {_label}s",
492+
expected_type=expected_type,
480493
) # type: ignore
481494

495+
if expected_type is dict:
496+
yield _generator
497+
else:
498+
yield from _generator
499+
482500
def read_only(self, is_read_only: bool) -> None:
483501
"""Set whether this object is in read only state.
484502
@@ -552,14 +570,16 @@ def url(self) -> URL | None:
552570
"""
553571
return None if self._identifier is None else self._base_url / self._identifier
554572

555-
def _post(self, is_json: bool = True, **kwargs) -> dict[str, typing.Any]:
573+
def _post(
574+
self, *, is_json: bool = True, data: list | dict | None = None, **kwargs
575+
) -> dict[str, typing.Any]:
556576
if not is_json:
557-
kwargs = msgpack.packb(kwargs, use_bin_type=True)
577+
kwargs = msgpack.packb(data or kwargs, use_bin_type=True)
558578
_response = sv_post(
559579
url=f"{self._base_url}",
560580
headers=self._headers | {"Content-Type": "application/msgpack"},
561581
params=self._params,
562-
data=kwargs,
582+
data=data or kwargs,
563583
is_json=is_json,
564584
)
565585

0 commit comments

Comments
 (0)