Skip to content

Create v2.0.0a0 release #708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 76 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
1e02b74
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Feb 10, 2025
e5585e1
Merge pull request #677 from simvue-io/pre-commit-ci-update-config
kzscisoft Feb 11, 2025
37707e3
Added offline user alert set status test
wk9874 Feb 11, 2025
5cc27c0
Added offline events test
wk9874 Feb 11, 2025
860232e
Added offline metrics test
wk9874 Feb 11, 2025
b717d99
Added small sleep to fix test
wk9874 Feb 11, 2025
2b03ed1
Fixed missing start and end times
wk9874 Feb 12, 2025
1531497
Fixed offline file artifact path
wk9874 Feb 12, 2025
c1ab236
Loosen numpy requirement
wk9874 Feb 12, 2025
9f8ba81
Make timestamp validation in utilities consistent
wk9874 Feb 12, 2025
8e31759
Added missing runtime attribute to Run
wk9874 Feb 12, 2025
d176787
Use time not datetime
wk9874 Feb 12, 2025
21d0f0c
Improved get_artifacts_as_files test
wk9874 Feb 12, 2025
cd80cda
Added new from_run method to Artifact and fixed client
wk9874 Feb 13, 2025
6f7c16c
Add docstrings to new artifact methods
wk9874 Feb 13, 2025
5a69cb1
Fix hierarchical artifact download
wk9874 Feb 13, 2025
5315252
Add params option to post and put
wk9874 Feb 13, 2025
0fb38ea
Add optional attach to run
wk9874 Feb 13, 2025
8ba756f
Added params correctly in new of each alert
wk9874 Feb 13, 2025
e2669b4
Fixed post in artifacts
wk9874 Feb 13, 2025
5470a08
Merge branch 'wk9874/alert_deduplication' into wk9874/offline_fixes
wk9874 Feb 13, 2025
2d0af8d
Drop requirement for initialized run for creating alerts and move to …
wk9874 Feb 13, 2025
71c157e
Drop requirement for initialized run for creating alerts and move to …
wk9874 Feb 13, 2025
95f5845
Change .alerts to return a list and fix add_alerts
wk9874 Feb 13, 2025
8d3d547
Merge branch 'wk9874/alert_deduplication' into wk9874/offline_fixes
wk9874 Feb 13, 2025
607fb9f
Removed logger.setLevel from dispatch
wk9874 Feb 14, 2025
65dfac4
Added deepmerge to dependencies and extra tests
wk9874 Feb 14, 2025
683c6f4
Remove attach_to_run as it isnt required, replace with add_alerts
wk9874 Feb 14, 2025
58a623b
Added custom merge strategy to override lists
wk9874 Feb 14, 2025
a83f149
Merge branch 'wk9874/update_metadata_tags_offline' into wk9874/offlin…
wk9874 Feb 14, 2025
261453a
Merge branch 'wk9874/alert_deduplication' into wk9874/offline_fixes
wk9874 Feb 14, 2025
e4ac228
Add initial sv_obj.alert as an empty list in init
wk9874 Feb 14, 2025
161d625
Merge branch 'wk9874/alert_deduplication' into wk9874/offline_fixes
wk9874 Feb 14, 2025
030f854
Fixed alert retrieval in offline
wk9874 Feb 14, 2025
51fb0a4
Fixing add alerts wip
wk9874 Feb 14, 2025
6407544
Still fixing add_alert
wk9874 Feb 14, 2025
475cb92
Create add_alerts test
wk9874 Feb 17, 2025
f884daa
Moved get status to under sleep in test
wk9874 Feb 17, 2025
48ad8ee
Merge branch 'wk9874/alert_deduplication' into wk9874/offline_fixes
wk9874 Feb 17, 2025
28b84b2
Remove artifact changes which shouldnt be in this PR£
wk9874 Feb 17, 2025
f1a1e69
Fix alerts setter
wk9874 Feb 17, 2025
8e30ffc
Fix alerts setter
wk9874 Feb 17, 2025
ad2f13d
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Feb 17, 2025
777a443
Remove existing folder check and rely on 409 from server
wk9874 Feb 17, 2025
cb02213
Add randomname generator if run mode is offline
wk9874 Feb 18, 2025
8912d8a
Add randomname generator if run mode is offline
wk9874 Feb 18, 2025
6d77bde
Removed server url and token validation checks if mode is offline
wk9874 Feb 18, 2025
e916238
Added created to simvue run
wk9874 Feb 18, 2025
7a82c87
Removed api from url printed to screen on run start
wk9874 Feb 18, 2025
8f53b2b
Suppressed runtime error in log_event for tracebacks
wk9874 Feb 18, 2025
7f48657
Fixed toml file finder
wk9874 Feb 18, 2025
1a28c76
Parameterized log_metrics tests to include timestamp
wk9874 Feb 19, 2025
56cead2
Correct format of notifications getter and setter
wk9874 Feb 19, 2025
01c20ca
Add notification option to run init
wk9874 Feb 19, 2025
01c9b9d
Only change status to running in _start if not already set to that
wk9874 Feb 19, 2025
d25345a
Merge pull request #701 from simvue-io/wk9874/680_toml_finding
kzscisoft Feb 19, 2025
9531b62
Merge pull request #705 from simvue-io/wk9874/run_notifications
kzscisoft Feb 19, 2025
5313dae
Merge pull request #697 from simvue-io/pre-commit-ci-update-config
kzscisoft Feb 19, 2025
9b209fc
Merge pull request #692 from simvue-io/wk9874/update_metadata_tags_of…
kzscisoft Feb 19, 2025
a0966a0
Merge pull request #679 from simvue-io/wk9874/user_alert_test
kzscisoft Feb 19, 2025
2f9882f
Respond to MR comments
wk9874 Feb 19, 2025
b608c5e
Merge pull request #700 from simvue-io/wk9874/folder_409
wk9874 Feb 19, 2025
1fac4cb
Merge branch 'v2.0' into wk9874/alert_deduplication
wk9874 Feb 19, 2025
3639a4f
Merge pull request #688 from simvue-io/wk9874/alert_deduplication
wk9874 Feb 19, 2025
9de939c
Merge branch 'v2.0' into wk9874/offline_fixes
wk9874 Feb 19, 2025
45be82f
Simplify conversion from alert names to ids
wk9874 Feb 19, 2025
be7fa45
Merge pull request #703 from simvue-io/wk9874/offline_fixes
wk9874 Feb 19, 2025
12046af
Update pyproject, citation and changelog for a1 release
wk9874 Feb 19, 2025
f4a9e21
Update citation and changelog
wk9874 Feb 19, 2025
7ba6d06
Fix missing start time
wk9874 Feb 19, 2025
124b299
Reduce redundant commit calls
wk9874 Feb 19, 2025
010abe5
Update citation
wk9874 Feb 19, 2025
3af12eb
Merge pull request #706 from simvue-io/v2.0
kzscisoft Feb 20, 2025
51a4337
fixed bug where None.closed file is created if closing a non initiali…
wk9874 Feb 20, 2025
ef9464a
Merge pull request #709 from simvue-io/hotfix/none_closed
wk9874 Feb 20, 2025
cd73666
Merge pull request #710 from simvue-io/v2.0
wk9874 Feb 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ repos:
args: [--branch, main, --branch, dev]
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.4
rev: v0.9.6
hooks:
- id: ruff
args: [ --fix, --exit-non-zero-on-fix, "--ignore=C901" ]
Expand All @@ -35,7 +35,7 @@ repos:
pass_filenames: false

- repo: https://github.com/PyCQA/bandit.git
rev: 1.8.2
rev: 1.8.3
hooks:
- id: bandit
args: [-lll, --recursive, clumper]
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Change log

## [v2.0.0-alpha1](https://github.com/simvue-io/client/releases/tag/v2.0.0a1) - 2025-02-19
* Fixed `add_alerts` so that it now works with both IDs and names
* Improved alert and folder deduplication methods to rely on 409 responses from server upon creation
* Added `attach_to_run` option to create alerts methods so that alerts can be created without a run attached
* Improved merging of local staging file and _staged dict using `deepmerge` - fixes bugs with tags, alerts and metadata in offline mode
* Added `started`, `created` and `ended` timestamps to runs in offline mode
* Remove all erronous server calls in offline mode
* Fixed method to find simvue.toml config files, now just looks in cwd and home
* Added run notification option to `run.init` so that users can now get emails upon their runs completing
* Fixed artifact retrieval by run so that `category` parameter works correctly
* Fixed bug where file artifacts wouldn't be saved correctly in offline mode if sender runs in different location to script
* Fixed bug where DEBUG log messages were spamming to the console
* Fixed link to run dashboard printed to the console by removing `/api`
* Fixed bug where offline mode wouldn't work if no run name provided
* Fixed bug where errors would be thrown if a traceback was logged as an event when a run was already terminated
* Fixed hierarchical artifact retrieval to maintain directory structure
* Loosened Numpy requirement to >2.0.0

## [v2.0.0-alpha0](https://github.com/simvue-io/client/releases/tag/v2.0.0a0) - 2025-02-10

* Add support for defining Simvue run defaults using `tool.simvue` in a project `pyproject.toml` file.
Expand Down
6 changes: 3 additions & 3 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ keywords:
- alerting
- simulation
license: Apache-2.0
commit: 5aaebe682d7ec2f80fefc3eb2a8a26f5bdca1e0c
version: 2.0.0a0
date-released: '2025-02-11'
commit: 124b2993d91dbff2e475aa972916b11e7bd02fa4
version: 2.0.0a1
date-released: '2025-02-19'
references:
- title: mlco2/codecarbon
version: v2.8.2
Expand Down
471 changes: 246 additions & 225 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "simvue"
version = "2.0.0a0"
version = "2.0.0a1"
description = "Simulation tracking and monitoring"
authors = [
{name = "Simvue Development Team", email = "[email protected]"}
Expand Down Expand Up @@ -46,13 +46,14 @@ dependencies = [
"humanfriendly (>=10.0,<11.0)",
"randomname (>=0.2.1,<0.3.0)",
"codecarbon (>=2.8.3,<3.0.0)",
"numpy (>=2.2.2,<3.0.0)",
"numpy (>=2.0.0,<3.0.0)",
"flatdict (>=4.0.1,<5.0.0)",
"semver (>=3.0.4,<4.0.0)",
"email-validator (>=2.2.0,<3.0.0)",
"psutil (>=6.1.1,<7.0.0)",
"tenacity (>=9.0.0,<10.0.0)",
"typing-extensions (>=4.12.2,<5.0.0) ; python_version < \"3.11\"",
"deepmerge (>=2.0,<3.0)",
]

[project.urls]
Expand Down
1 change: 1 addition & 0 deletions simvue/api/objects/alert/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def new(
_offline=offline,
)
_alert._staging |= _alert_definition
_alert._params = {"deduplicate": True}
return _alert


Expand Down
3 changes: 3 additions & 0 deletions simvue/api/objects/alert/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ def new(
_offline=offline,
)
_alert._staging |= _alert_definition
_alert._params = {"deduplicate": True}

return _alert


Expand Down Expand Up @@ -194,6 +196,7 @@ def new(
_offline=offline,
)
_alert._staging |= _alert_definition
_alert._params = {"deduplicate": True}
return _alert


Expand Down
4 changes: 3 additions & 1 deletion simvue/api/objects/alert/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def new(
whether this alert should be created locally, default is False

"""
return UserAlert(
_alert = UserAlert(
name=name,
description=description,
notification=notification,
Expand All @@ -66,6 +66,8 @@ def new(
_read_only=False,
_offline=offline,
)
_alert._params = {"deduplicate": True}
return _alert

@classmethod
def get(
Expand Down
1 change: 1 addition & 0 deletions simvue/api/objects/artifact/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def _upload(self, file: io.BytesIO) -> None:
_response = sv_post(
url=_url,
headers={},
params={},
is_json=False,
files={"file": file},
data=self._init_data.get("fields"),
Expand Down
76 changes: 60 additions & 16 deletions simvue/api/objects/artifact/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,62 @@ def __new__(cls, identifier: str | None = None, **kwargs):
else:
return ObjectArtifact(identifier=identifier, **kwargs)

@classmethod
def from_run(
cls,
run_id: str,
category: typing.Literal["input", "output", "code"] | None = None,
**kwargs,
) -> typing.Generator[tuple[str, FileArtifact | ObjectArtifact], None, None]:
"""Return artifacts associated with a given run.

Parameters
----------
run_id : str
The ID of the run to retriece artifacts from
category : typing.Literal["input", "output", "code"] | None, optional
The category of artifacts to return, by default all artifacts are returned

Returns
-------
typing.Generator[tuple[str, FileArtifact | ObjectArtifact], None, None]
The artifacts

Yields
------
Iterator[typing.Generator[tuple[str, FileArtifact | ObjectArtifact], None, None]]
identifier for artifact
the artifact itself as a class instance

Raises
------
ObjectNotFoundError
Raised if artifacts could not be found for that run
"""
_temp = ArtifactBase(**kwargs)
_url = URL(_temp._user_config.server.url) / f"runs/{run_id}/artifacts"
_response = sv_get(
url=f"{_url}", params={"category": category}, headers=_temp._headers
)
_json_response = get_json_from_response(
expected_type=list,
response=_response,
expected_status=[http.HTTPStatus.OK, http.HTTPStatus.NOT_FOUND],
scenario=f"Retrieval of artifacts for run '{run_id}'",
)

if _response.status_code == http.HTTPStatus.NOT_FOUND or not _json_response:
raise ObjectNotFoundError(
_temp._label, category, extra=f"for run '{run_id}'"
)

for _entry in _json_response:
_id = _entry.pop("id")
yield (
_id,
Artifact(_local=True, _read_only=True, identifier=_id, **_entry),
)

@classmethod
def from_name(
cls, run_id: str, name: str, **kwargs
Expand Down Expand Up @@ -99,21 +155,9 @@ def get(
if (_data := _json_response.get("data")) is None:
raise RuntimeError(f"Expected key 'data' for retrieval of {_label}s")

_out_dict: dict[str, FileArtifact | ObjectArtifact] = {}

for _entry in _data:
_id = _entry.pop("id")
if _entry["original_path"]:
yield (
_id,
FileArtifact(
_local=True, _read_only=True, identifier=_id, **_entry
),
)
else:
yield (
_id,
ObjectArtifact(
_local=True, _read_only=True, identifier=_id, **_entry
),
)
yield (
_id,
Artifact(_local=True, _read_only=True, identifier=_id, **_entry),
)
15 changes: 8 additions & 7 deletions simvue/api/objects/artifact/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ def new(

if _mime_type not in get_mimetypes():
raise ValueError(f"Invalid MIME type '{mime_type}' specified")
file_path = pathlib.Path(file_path)
_file_size = file_path.stat().st_size
_file_orig_path = file_path.expanduser().absolute()
_file_checksum = calculate_sha256(f"{file_path}", is_file=True)

kwargs.pop("original_path", None)
kwargs.pop("size", None)
kwargs.pop("checksum", None)
if _file_orig_path := kwargs.pop("original_path", None):
_file_size = kwargs.pop("size")
_file_checksum = kwargs.pop("checksum")
else:
file_path = pathlib.Path(file_path)
_file_size = file_path.stat().st_size
_file_orig_path = file_path.expanduser().absolute()
_file_checksum = calculate_sha256(f"{file_path}", is_file=True)

_artifact = FileArtifact(
name=name,
Expand Down
23 changes: 16 additions & 7 deletions simvue/api/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import msgpack
import pydantic

from simvue.utilities import staging_merger
from simvue.config.user import SimvueConfiguration
from simvue.exception import ObjectNotFoundError
from simvue.version import __version__
Expand Down Expand Up @@ -164,10 +165,16 @@ def __init__(
)
)

self._headers: dict[str, str] = {
"Authorization": f"Bearer {self._user_config.server.token.get_secret_value()}",
"User-Agent": _user_agent or f"Simvue Python client {__version__}",
}
self._headers: dict[str, str] = (
{
"Authorization": f"Bearer {self._user_config.server.token.get_secret_value()}",
"User-Agent": _user_agent or f"Simvue Python client {__version__}",
}
if not self._offline
else {}
)

self._params: dict[str, str] = {}

self._staging: dict[str, typing.Any] = {}

Expand Down Expand Up @@ -412,6 +419,7 @@ def _post(self, is_json: bool = True, **kwargs) -> dict[str, typing.Any]:
_response = sv_post(
url=f"{self._base_url}",
headers=self._headers | {"Content-Type": "application/msgpack"},
params=self._params,
data=kwargs,
is_json=is_json,
)
Expand All @@ -423,7 +431,7 @@ def _post(self, is_json: bool = True, **kwargs) -> dict[str, typing.Any]:

_json_response = get_json_from_response(
response=_response,
expected_status=[http.HTTPStatus.OK],
expected_status=[http.HTTPStatus.OK, http.HTTPStatus.CONFLICT],
scenario=f"Creation of {self._label}",
)

Expand Down Expand Up @@ -452,7 +460,7 @@ def _put(self, **kwargs) -> dict[str, typing.Any]:

return get_json_from_response(
response=_response,
expected_status=[http.HTTPStatus.OK],
expected_status=[http.HTTPStatus.OK, http.HTTPStatus.CONFLICT],
scenario=f"Creation of {self._label} '{self._identifier}",
)

Expand Down Expand Up @@ -524,7 +532,8 @@ def _cache(self) -> None:
with self._local_staging_file.open() as in_f:
_local_data = json.load(in_f)

_local_data |= self._staging
staging_merger.merge(_local_data, self._staging)

with self._local_staging_file.open("w", encoding="utf-8") as out_f:
json.dump(_local_data, out_f, indent=2)

Expand Down
28 changes: 12 additions & 16 deletions simvue/api/objects/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(
def new(
cls, *, run: str, offline: bool = False, metrics: list[MetricSet], **kwargs
):
"""Create a new Events entry on the Simvue server"""
"""Create a new Metrics entry on the Simvue server"""
return Metrics(
run=run,
metrics=[metric.model_dump() for metric in metrics],
Expand All @@ -51,27 +51,23 @@ def get(
cls,
metrics: list[str],
xaxis: typing.Literal["timestamp", "step", "time"],
runs: list[str],
*,
count: pydantic.PositiveInt | None = None,
offset: pydantic.PositiveInt | None = None,
**kwargs,
) -> typing.Generator[MetricSet, None, None]:
_class_instance = cls(_read_only=True, _local=True)
if (
_data := cls._get_all_objects(
count,
offset,
metrics=json.dumps(metrics),
xaxis=xaxis,
**kwargs,
).get("data")
) is None:
raise RuntimeError(
f"Expected key 'data' for retrieval of {_class_instance.__class__.__name__.lower()}s"
)

for _entry in _data:
yield MetricSet(**_entry)
_data = cls._get_all_objects(
count,
offset,
metrics=json.dumps(metrics),
runs=json.dumps(runs),
xaxis=xaxis,
**kwargs,
)
# TODO: Temp fix, just return the dictionary. Not sure what format we really want this in...
return _data

@pydantic.validate_call
def span(self, run_ids: list[str]) -> dict[str, int | float]:
Expand Down
Loading
Loading