From 777a4432b3041b56a9f715d2dbed96147b122bb7 Mon Sep 17 00:00:00 2001 From: Matt Field Date: Mon, 17 Feb 2025 18:06:14 +0000 Subject: [PATCH 1/3] Remove existing folder check and rely on 409 from server --- simvue/api/objects/base.py | 2 +- simvue/run.py | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/simvue/api/objects/base.py b/simvue/api/objects/base.py index 7f43904f..16f2af13 100644 --- a/simvue/api/objects/base.py +++ b/simvue/api/objects/base.py @@ -423,7 +423,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}", ) diff --git a/simvue/run.py b/simvue/run.py index af7a5aa0..1ae01f28 100644 --- a/simvue/run.py +++ b/simvue/run.py @@ -31,8 +31,8 @@ from simvue.api.objects.alert.base import AlertBase from simvue.api.objects.alert.fetch import Alert -from simvue.api.objects.folder import Folder, get_folder_from_path -from simvue.exception import ObjectNotFoundError, SimvueRunError +from simvue.api.objects.folder import Folder +from simvue.exception import SimvueRunError from simvue.utilities import prettify_pydantic @@ -621,13 +621,10 @@ def init( self._term_color = not no_color - try: - self._folder = get_folder_from_path(path=folder) - except ObjectNotFoundError: - self._folder = Folder.new( - path=folder, offline=self._user_config.run.mode == "offline" - ) - self._folder.commit() # type: ignore + self._folder = Folder.new( + path=folder, offline=self._user_config.run.mode == "offline" + ) + self._folder.commit() # type: ignore if isinstance(visibility, str) and visibility not in ("public", "tenant"): self._error( From 6d77bde6bebe8606e48c111fed16d4e16710f6ef Mon Sep 17 00:00:00 2001 From: Matt Field Date: Tue, 18 Feb 2025 13:02:39 +0000 Subject: [PATCH 2/3] Removed server url and token validation checks if mode is offline --- simvue/api/objects/base.py | 12 ++++++++---- simvue/config/parameters.py | 28 ++++++++++++++++------------ simvue/config/user.py | 4 ++-- simvue/run.py | 18 +++++++++++++----- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/simvue/api/objects/base.py b/simvue/api/objects/base.py index 16f2af13..334af761 100644 --- a/simvue/api/objects/base.py +++ b/simvue/api/objects/base.py @@ -164,10 +164,14 @@ 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._staging: dict[str, typing.Any] = {} diff --git a/simvue/config/parameters.py b/simvue/config/parameters.py index 472811f6..eb26e523 100644 --- a/simvue/config/parameters.py +++ b/simvue/config/parameters.py @@ -21,25 +21,29 @@ class ServerSpecifications(pydantic.BaseModel): - url: pydantic.AnyHttpUrl - token: pydantic.SecretStr + url: pydantic.AnyHttpUrl | None + token: pydantic.SecretStr | None @pydantic.field_validator("url") @classmethod def url_to_api_url(cls, v: typing.Any) -> str: - if f"{v}".endswith("/api"): - return f"{v}" - _url = URL(f"{v}") / "api" - return f"{_url}" + if v: + if f"{v}".endswith("/api"): + return f"{v}" + _url = URL(f"{v}") / "api" + return f"{_url}" @pydantic.field_validator("token") def check_token(cls, v: typing.Any) -> str: - value = v.get_secret_value() - if not (expiry := get_expiry(value)): - raise AssertionError("Failed to parse Simvue token - invalid token form") - if time.time() - expiry > 0: - raise AssertionError("Simvue token has expired") - return v + if v: + value = v.get_secret_value() + if not (expiry := get_expiry(value)): + raise AssertionError( + "Failed to parse Simvue token - invalid token form" + ) + if time.time() - expiry > 0: + raise AssertionError("Simvue token has expired") + return v class OfflineSpecifications(pydantic.BaseModel): diff --git a/simvue/config/user.py b/simvue/config/user.py index 931d2fa5..22357ce5 100644 --- a/simvue/config/user.py +++ b/simvue/config/user.py @@ -212,10 +212,10 @@ def fetch( _run_mode = mode or _config_dict["run"].get("mode") or "online" - if not _server_url: + if not _server_url and _run_mode != "offline": raise RuntimeError("No server URL was specified") - if not _server_token: + if not _server_token and _run_mode != "offline": raise RuntimeError("No server token was specified") _config_dict["server"]["token"] = _server_token diff --git a/simvue/run.py b/simvue/run.py index 1ae01f28..a618f04c 100644 --- a/simvue/run.py +++ b/simvue/run.py @@ -185,9 +185,13 @@ def __init__( if self._user_config.metrics.resources_metrics_interval < 1 else self._user_config.metrics.resources_metrics_interval ) - self._headers: dict[str, str] = { - "Authorization": f"Bearer {self._user_config.server.token.get_secret_value()}" - } + self._headers: dict[str, str] = ( + { + "Authorization": f"Bearer {self._user_config.server.token.get_secret_value()}" + } + if mode != "offline" + else {} + ) self._sv_obj: RunObject | None = None self._pid: int | None = 0 self._shutdown_event: threading.Event | None = None @@ -419,7 +423,9 @@ def _create_dispatch_callback( if self._user_config.run.mode == "online" and not self._id: raise RuntimeError("Expected identifier for run") - if not self._user_config.server.url or not self._sv_obj: + if ( + self._user_config.run.mode != "offline" and not self._user_config.server.url + ) or not self._sv_obj: raise RuntimeError("Cannot commence dispatch, run not initialised") def _dispatch_callback( @@ -635,7 +641,9 @@ def init( self._error("invalid mode specified, must be online, offline or disabled") return False - if not self._user_config.server.token or not self._user_config.server.url: + if self._user_config.run.mode != "offline" and ( + not self._user_config.server.token or not self._user_config.server.url + ): self._error( "Unable to get URL and token from environment variables or config file" ) From 2f9882f8266d77e513c80837f90576f45e09e003 Mon Sep 17 00:00:00 2001 From: Matt Field Date: Wed, 19 Feb 2025 14:38:45 +0000 Subject: [PATCH 3/3] Respond to MR comments --- simvue/config/parameters.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/simvue/config/parameters.py b/simvue/config/parameters.py index eb26e523..c6d65c93 100644 --- a/simvue/config/parameters.py +++ b/simvue/config/parameters.py @@ -26,24 +26,24 @@ class ServerSpecifications(pydantic.BaseModel): @pydantic.field_validator("url") @classmethod - def url_to_api_url(cls, v: typing.Any) -> str: - if v: - if f"{v}".endswith("/api"): - return f"{v}" - _url = URL(f"{v}") / "api" - return f"{_url}" + def url_to_api_url(cls, v: typing.Any) -> str | None: + if not v: + return + if f"{v}".endswith("/api"): + return f"{v}" + _url = URL(f"{v}") / "api" + return f"{_url}" @pydantic.field_validator("token") - def check_token(cls, v: typing.Any) -> str: - if v: - value = v.get_secret_value() - if not (expiry := get_expiry(value)): - raise AssertionError( - "Failed to parse Simvue token - invalid token form" - ) - if time.time() - expiry > 0: - raise AssertionError("Simvue token has expired") - return v + def check_token(cls, v: typing.Any) -> str | None: + if not v: + return + value = v.get_secret_value() + if not (expiry := get_expiry(value)): + raise AssertionError("Failed to parse Simvue token - invalid token form") + if time.time() - expiry > 0: + raise AssertionError("Simvue token has expired") + return v class OfflineSpecifications(pydantic.BaseModel):