Skip to content

Commit 46fe05f

Browse files
authored
Merge pull request #785 from simvue-io/dev
2.1.1 release
2 parents 9178212 + 5ce8092 commit 46fe05f

33 files changed

+286
-177
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ repos:
2323
args: [--branch, main, --branch, dev]
2424
- id: check-added-large-files
2525
- repo: https://github.com/astral-sh/ruff-pre-commit
26-
rev: v0.11.2
26+
rev: v0.11.4
2727
hooks:
2828
- id: ruff
2929
args: [ --fix, --exit-non-zero-on-fix, "--ignore=C901" ]

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# Change log
2+
## [v2.1.1](https://github.com/simvue-io/client/releases/tag/v2.1.1) - 2025-04-25
3+
* Changed from CO2 Signal to ElectricityMaps
4+
* Fixed a number of bugs in how offline mode is handled with emissions
5+
* Streamlined EmissionsMonitor class and handling
6+
* Fixed bugs in client getting results from Simvue server arising from pagination
7+
* Fixed bug in setting visibility in `run.init` method
8+
* Default setting in `Client.get_runs` is now `show_shared=True`
29
## [v2.1.0](https://github.com/simvue-io/client/releases/tag/v2.1.0) - 2025-03-28
310
* Removed CodeCarbon dependence in favour of a slimmer solution using the CO2 Signal API.
411
* Added sorting to server queries, users can now specify to sort by columns during data retrieval from the database.

CITATION.cff

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ keywords:
4242
- alerting
4343
- simulation
4444
license: Apache-2.0
45-
commit: 8f13a7adb2ad0ec53f0a4949e44e1c5676ae342d
46-
version: 2.1.0
47-
date-released: '2025-03-28'
45+
commit: f1bde5646b33f01ec15ef72a0c5843c1fe181ac1
46+
version: 2.1.1
47+
date-released: '2025-04-25'

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "simvue"
3-
version = "2.1.0"
3+
version = "2.1.1"
44
description = "Simulation tracking and monitoring"
55
authors = [
66
{name = "Simvue Development Team", email = "[email protected]"}

simvue/api/objects/events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def get(
5151
_class_instance = cls(_read_only=True, _local=True)
5252
_count: int = 0
5353

54-
for response in cls._get_all_objects(offset, run=run_id, **kwargs):
54+
for response in cls._get_all_objects(offset, count=count, run=run_id, **kwargs):
5555
if (_data := response.get("data")) is None:
5656
raise RuntimeError(
5757
f"Expected key 'data' for retrieval of {_class_instance.__class__.__name__.lower()}s"

simvue/api/request.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,23 +303,18 @@ def get_paginated(
303303
server response
304304
"""
305305
_offset: int = offset or 0
306-
307306
while (
308-
(
309-
_response := get(
310-
url=url,
311-
headers=headers,
312-
params=(params or {})
313-
| {"count": count or MAX_ENTRIES_PER_PAGE, "start": _offset},
314-
timeout=timeout,
315-
json=json,
316-
)
307+
_response := get(
308+
url=url,
309+
headers=headers,
310+
params=(params or {})
311+
| {"count": count or MAX_ENTRIES_PER_PAGE, "start": _offset},
312+
timeout=timeout,
313+
json=json,
317314
)
318-
.json()
319-
.get("data")
320-
):
315+
).json():
321316
yield _response
322317
_offset += MAX_ENTRIES_PER_PAGE
323318

324-
if count and _offset > count:
319+
if (count and _offset > count) or (_response.json().get("count", 0) < _offset):
325320
break

simvue/client.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def get_runs(
181181
output_format: typing.Literal["dict", "objects", "dataframe"] = "objects",
182182
count_limit: pydantic.PositiveInt | None = 100,
183183
start_index: pydantic.NonNegativeInt = 0,
184-
show_shared: bool = False,
184+
show_shared: bool = True,
185185
sort_by_columns: list[tuple[str, bool]] | None = None,
186186
) -> DataFrame | typing.Generator[tuple[str, Run], None, None] | None:
187187
"""Retrieve all runs matching filters.
@@ -210,7 +210,7 @@ def get_runs(
210210
start_index : int, optional
211211
the index from which to count entries. Default is 0.
212212
show_shared : bool, optional
213-
whether to include runs shared with the current user. Default is False.
213+
whether to include runs shared with the current user. Default is True.
214214
sort_by_columns : list[tuple[str, bool]], optional
215215
sort by columns in the order given,
216216
list of tuples in the form (column_name: str, sort_descending: bool),
@@ -234,8 +234,9 @@ def get_runs(
234234
RuntimeError
235235
if there was a failure in data retrieval from the server
236236
"""
237+
filters = filters or []
237238
if not show_shared:
238-
filters = (filters or []) + ["user == self"]
239+
filters += ["user == self"]
239240

240241
_runs = Run.get(
241242
count=count_limit,
@@ -835,7 +836,8 @@ def get_metric_values(
835836

836837
_args = {"filters": json.dumps(run_filters)} if run_filters else {}
837838

838-
_run_data = dict(Run.get(**_args))
839+
if not run_ids:
840+
_run_data = dict(Run.get(**_args))
839841

840842
if not (
841843
_run_metrics := self._get_run_metrics_from_server(
@@ -853,7 +855,8 @@ def get_metric_values(
853855
)
854856
if use_run_names:
855857
_run_metrics = {
856-
_run_data[key].name: _run_metrics[key] for key in _run_metrics.keys()
858+
Run(identifier=key).name: _run_metrics[key]
859+
for key in _run_metrics.keys()
857860
}
858861
return parse_run_set_metrics(
859862
_run_metrics,

simvue/config/user.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ def fetch(
200200
_default_dir = _config_dict["offline"].get(
201201
"cache", DEFAULT_OFFLINE_DIRECTORY
202202
)
203+
pathlib.Path(_default_dir).mkdir(parents=True, exist_ok=True)
203204

204205
_config_dict["offline"]["cache"] = _default_dir
205206

simvue/eco/api_client.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,15 @@ def __init__(self, *args, **kwargs) -> None:
7777
co2_api_endpoint : str
7878
endpoint for CO2 signal API
7979
co2_api_token: str
80-
RECOMMENDED. The API token for the CO2 Signal API, default is None.
80+
The API token for the ElectricityMaps API, default is None.
8181
timeout : int
8282
timeout for API
8383
"""
8484
super().__init__(*args, **kwargs)
8585
self._logger = logging.getLogger(self.__class__.__name__)
8686

8787
if not self.co2_api_token:
88-
self._logger.warning(
89-
"⚠️ No API token provided for CO2 Signal, "
90-
"use of a token is strongly recommended."
91-
)
88+
raise ValueError("API token is required for ElectricityMaps API.")
9289

9390
self._get_user_location_info()
9491

simvue/eco/config.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88
__date__ = "2025-03-06"
99

1010
import pydantic
11-
import pathlib
12-
import os
13-
14-
from simvue.config.files import DEFAULT_OFFLINE_DIRECTORY
1511

1612

1713
class EcoConfig(pydantic.BaseModel):
@@ -25,30 +21,13 @@ class EcoConfig(pydantic.BaseModel):
2521
the TDP for the CPU
2622
gpu_thermal_design_power: int | None, optional
2723
the TDP for each GPU
28-
local_data_directory: str, optional
29-
the directory to store local data, default is Simvue offline directory
3024
"""
3125

3226
co2_signal_api_token: pydantic.SecretStr | None = None
3327
cpu_thermal_design_power: pydantic.PositiveInt | None = None
3428
cpu_n_cores: pydantic.PositiveInt | None = None
3529
gpu_thermal_design_power: pydantic.PositiveInt | None = None
36-
local_data_directory: pydantic.DirectoryPath | None = pydantic.Field(
37-
None, validate_default=True
38-
)
3930
intensity_refresh_interval: pydantic.PositiveInt | str | None = pydantic.Field(
40-
default="1 day", gt=2 * 60
31+
default="1 hour", gt=2 * 60
4132
)
4233
co2_intensity: float | None = None
43-
44-
@pydantic.field_validator("local_data_directory", mode="before", check_fields=True)
45-
@classmethod
46-
def check_local_data_env(
47-
cls, local_data_directory: pathlib.Path | None
48-
) -> pathlib.Path:
49-
if _data_directory := os.environ.get("SIMVUE_ECO_DATA_DIRECTORY"):
50-
return pathlib.Path(_data_directory)
51-
if not local_data_directory:
52-
local_data_directory = pathlib.Path(DEFAULT_OFFLINE_DIRECTORY)
53-
local_data_directory.mkdir(exist_ok=True, parents=True)
54-
return local_data_directory

0 commit comments

Comments
 (0)