Skip to content

Commit 113bdc1

Browse files
committed
Merge branch 'v1.1' into dev
2 parents 4506c27 + 5abefea commit 113bdc1

File tree

10 files changed

+528
-414
lines changed

10 files changed

+528
-414
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@
55
* Add support for defining Simvue run defaults using `tool.simvue` in a project `pyproject.toml` file.
66
* Drop support for INI based configuration files.
77
* Retrieve all metric values if `max_points` is unspecified or set to `None`.
8+
9+
## [v1.1.3](https://github.com/simvue-io/client/releases/tag/v1.1.3) - 2024-12-09
10+
811
* Fixed bug with `requirements.txt` metadata read.
12+
* Added Simvue server version check.
13+
* Remove checking of server version in offline mode and add default run mode to configuration options.
14+
* Fix offline mode class initialisation, and propagation of configuration.
15+
916
## [v1.1.2](https://github.com/simvue-io/client/releases/tag/v1.1.2) - 2024-11-06
1017

1118
* Fix bug in offline mode directory retrieval.
19+
1220
## [v1.1.1](https://github.com/simvue-io/client/releases/tag/v1.1.1) - 2024-10-22
1321

1422
* Add missing `offline.cache` key to TOML config.

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: e220740c747a56de0915d583918e1999d253fdfc
46-
version: 1.1.2
47-
date-released: '2024-11-06'
45+
commit: 3ea5c3f1a579a44bc144a8fa0e2983475e46dd63
46+
version: 1.1.3
47+
date-released: '2024-12-09'

poetry.lock

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

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ tabulate = "^0.9.0"
5555
randomname = "^0.2.1"
5656
codecarbon = "^2.7.1"
5757
numpy = "^2.1.2"
58+
semver = "^3.0.2"
5859

5960
[tool.poetry.extras]
6061
plot = ["matplotlib", "plotly"]

simvue/config/parameters.py

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,13 @@
77
"""
88

99
import logging
10-
import os
1110
import time
1211
import pydantic
1312
import typing
1413
import pathlib
15-
import http
16-
import functools
1714

1815
import simvue.models as sv_models
1916
from simvue.utilities import get_expiry
20-
from simvue.version import __version__
21-
from simvue.api import get
2217

2318

2419
logger = logging.getLogger(__file__)
@@ -42,37 +37,6 @@ def check_token(cls, v: typing.Any) -> str:
4237
raise AssertionError("Simvue token has expired")
4338
return value
4439

45-
@classmethod
46-
@functools.lru_cache
47-
def _check_server(cls, token: str, url: str) -> None:
48-
headers: dict[str, str] = {
49-
"Authorization": f"Bearer {token}",
50-
"User-Agent": f"Simvue Python client {__version__}",
51-
}
52-
try:
53-
response = get(f"{url}/api/version", headers)
54-
55-
if response.status_code != http.HTTPStatus.OK or not response.json().get(
56-
"version"
57-
):
58-
raise AssertionError
59-
60-
if response.status_code == http.HTTPStatus.UNAUTHORIZED:
61-
raise AssertionError("Unauthorised token")
62-
63-
except Exception as err:
64-
raise AssertionError(f"Exception retrieving server version: {str(err)}")
65-
66-
@pydantic.model_validator(mode="after")
67-
@classmethod
68-
def check_valid_server(cls, values: "ServerSpecifications") -> bool:
69-
if os.environ.get("SIMVUE_NO_SERVER_CHECK"):
70-
return values
71-
72-
cls._check_server(values.token, values.url)
73-
74-
return values
75-
7640

7741
class OfflineSpecifications(pydantic.BaseModel):
7842
cache: typing.Optional[pathlib.Path] = None
@@ -89,6 +53,7 @@ class DefaultRunSpecifications(pydantic.BaseModel):
8953
tags: typing.Optional[list[str]] = None
9054
folder: str = pydantic.Field("/", pattern=sv_models.FOLDER_REGEX)
9155
metadata: typing.Optional[dict[str, typing.Union[str, int, float, bool]]] = None
56+
mode: typing.Literal["offline", "disabled", "online"] = "online"
9257

9358

9459
class ClientGeneralOptions(pydantic.BaseModel):

simvue/config/user.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
import logging
1111
import os
1212
import typing
13+
import http
1314
import pathlib
14-
1515
import pydantic
1616
import toml
17+
import semver
1718

1819
import simvue.utilities as sv_util
1920
from simvue.config.parameters import (
@@ -28,9 +29,16 @@
2829
CONFIG_INI_FILE_NAMES,
2930
DEFAULT_OFFLINE_DIRECTORY,
3031
)
32+
from simvue.version import __version__
33+
from simvue.api import get
3134

3235
logger = logging.getLogger(__name__)
3336

37+
SIMVUE_SERVER_UPPER_CONSTRAINT: typing.Optional[semver.Version] = semver.Version.parse(
38+
"1.0.0"
39+
)
40+
SIMVUE_SERVER_LOWER_CONSTRAINT: typing.Optional[semver.Version] = None
41+
3442

3543
class SimvueConfiguration(pydantic.BaseModel):
3644
# Hide values as they contain token and URL
@@ -74,12 +82,65 @@ def _load_pyproject_configs(cls) -> typing.Optional[dict]:
7482

7583
return _simvue_setup
7684

85+
@classmethod
86+
@functools.lru_cache
87+
def _check_server(
88+
cls, token: str, url: str, mode: typing.Literal["offline", "online", "disabled"]
89+
) -> None:
90+
if mode in ("offline", "disabled"):
91+
return
92+
93+
headers: dict[str, str] = {
94+
"Authorization": f"Bearer {token}",
95+
"User-Agent": f"Simvue Python client {__version__}",
96+
}
97+
try:
98+
response = get(f"{url}/api/version", headers)
99+
100+
if response.status_code != http.HTTPStatus.OK or not (
101+
_version_str := response.json().get("version")
102+
):
103+
raise AssertionError
104+
105+
if response.status_code == http.HTTPStatus.UNAUTHORIZED:
106+
raise AssertionError("Unauthorised token")
107+
108+
except Exception as err:
109+
raise AssertionError(f"Exception retrieving server version: {str(err)}")
110+
111+
_version = semver.Version.parse(_version_str)
112+
113+
if (
114+
SIMVUE_SERVER_UPPER_CONSTRAINT
115+
and _version >= SIMVUE_SERVER_UPPER_CONSTRAINT
116+
):
117+
raise AssertionError(
118+
f"Python API v{_version_str} is not compatible with Simvue server versions "
119+
f">= {SIMVUE_SERVER_UPPER_CONSTRAINT}"
120+
)
121+
if SIMVUE_SERVER_LOWER_CONSTRAINT and _version < SIMVUE_SERVER_LOWER_CONSTRAINT:
122+
raise AssertionError(
123+
f"Python API v{_version_str} is not compatible with Simvue server versions "
124+
f"< {SIMVUE_SERVER_LOWER_CONSTRAINT}"
125+
)
126+
127+
@pydantic.model_validator(mode="after")
128+
@classmethod
129+
def check_valid_server(cls, values: "SimvueConfiguration") -> bool:
130+
if os.environ.get("SIMVUE_NO_SERVER_CHECK"):
131+
return values
132+
133+
cls._check_server(values.server.token, values.server.url, values.run.mode)
134+
135+
return values
136+
77137
@classmethod
78138
@sv_util.prettify_pydantic
79139
def fetch(
80140
cls,
81141
server_url: typing.Optional[str] = None,
82142
server_token: typing.Optional[str] = None,
143+
mode: typing.Optional[typing.Literal["offline", "online", "disabled"]] = None,
83144
) -> "SimvueConfiguration":
84145
"""Retrieve the Simvue configuration from this project
85146
@@ -92,6 +153,8 @@ def fetch(
92153
override the URL used for this session
93154
server_token : str, optional
94155
override the token used for this session
156+
mode : 'online' | 'offline' | 'disabled'
157+
set the run mode for this session
95158
96159
Return
97160
------
@@ -116,6 +179,8 @@ def fetch(
116179

117180
_config_dict["offline"] = _config_dict.get("offline", {})
118181

182+
_config_dict["run"] = _config_dict.get("run", {})
183+
119184
# Allow override of specification of offline directory via environment variable
120185
if not (_default_dir := os.environ.get("SIMVUE_OFFLINE_DIRECTORY")):
121186
_default_dir = _config_dict["offline"].get(
@@ -135,6 +200,8 @@ def fetch(
135200
"SIMVUE_TOKEN", server_token or _config_dict["server"].get("token")
136201
)
137202

203+
_run_mode = mode or _config_dict["run"].get("mode")
204+
138205
if not _server_url:
139206
raise RuntimeError("No server URL was specified")
140207

@@ -143,6 +210,7 @@ def fetch(
143210

144211
_config_dict["server"]["token"] = _server_token
145212
_config_dict["server"]["url"] = _server_url
213+
_config_dict["run"]["mode"] = _run_mode
146214

147215
return SimvueConfiguration(**_config_dict)
148216

simvue/factory/proxy/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ def Simvue(
2323
suppress_errors: bool = True,
2424
) -> "SimvueBaseClass":
2525
if mode == "offline":
26-
return Offline(name=name, uniq_id=uniq_id, suppress_errors=suppress_errors)
26+
return Offline(
27+
name=name, uniq_id=uniq_id, suppress_errors=suppress_errors, config=config
28+
)
2729
else:
2830
return Remote(
2931
name=name, uniq_id=uniq_id, config=config, suppress_errors=suppress_errors

simvue/factory/proxy/offline.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ class Offline(SimvueBaseClass):
2828
"""
2929

3030
def __init__(
31-
self, name: typing.Optional[str], uniq_id: str, suppress_errors: bool = True
31+
self,
32+
name: typing.Optional[str],
33+
uniq_id: str,
34+
config: SimvueConfiguration,
35+
suppress_errors: bool = True,
3236
) -> None:
33-
super().__init__(name, uniq_id, suppress_errors)
37+
super().__init__(name=name, uniq_id=uniq_id, suppress_errors=suppress_errors)
3438

35-
_offline_dir = SimvueConfiguration.fetch().offline.cache
39+
_offline_dir = config.offline.cache
3640
self._directory: str = os.path.join(_offline_dir, self._uuid)
3741

3842
os.makedirs(self._directory, exist_ok=True)

0 commit comments

Comments
 (0)