Skip to content

Added decorator to prevent pre-mature Run function calls #231

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

28 changes: 28 additions & 0 deletions simvue/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@
logger = logging.getLogger(__name__)


def check_run_initialised(
function: typing.Callable[..., typing.Any],
) -> typing.Callable[..., typing.Any]:
def _wrapper(self: "Run", *args: typing.Any, **kwargs: typing.Any) -> typing.Any:
if not self._simvue:
raise RuntimeError(
"Simvue Run must be initialised before calling "
f"'{function.__name__}'"
)
return function(self, *args, **kwargs)

_wrapper.__name__ = f"{function.__name__}__init_locked"

return _wrapper


class Run:
"""Track simulation details based on token and URL

Expand Down Expand Up @@ -822,6 +838,7 @@ def config(

return True

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def update_metadata(self, metadata: dict[str, typing.Any]) -> bool:
Expand All @@ -847,6 +864,7 @@ def update_metadata(self, metadata: dict[str, typing.Any]) -> bool:

return False

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def update_tags(self, tags: list[str]) -> bool:
Expand All @@ -867,6 +885,7 @@ def update_tags(self, tags: list[str]) -> bool:

return False

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def log_event(self, message, timestamp: typing.Optional[str] = None) -> bool:
Expand Down Expand Up @@ -941,6 +960,7 @@ def _add_metrics_to_dispatch(

return True

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def log_metrics(
Expand All @@ -959,6 +979,7 @@ def log_metrics(
self._step += 1
return add_dispatch

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def save(
Expand Down Expand Up @@ -1075,6 +1096,7 @@ def save(

return True

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def save_directory(
Expand Down Expand Up @@ -1111,6 +1133,7 @@ def save_directory(

return True

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def save_all(
Expand Down Expand Up @@ -1141,6 +1164,7 @@ def save_all(

return True

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def set_status(
Expand Down Expand Up @@ -1210,6 +1234,7 @@ def close(self) -> bool:

return True

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def set_folder_details(
Expand Down Expand Up @@ -1264,6 +1289,7 @@ def set_folder_details(

return False

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def add_alerts(
Expand Down Expand Up @@ -1311,6 +1337,7 @@ def add_alerts(

return False

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", None)
@pydantic.validate_call
def create_alert(
Expand Down Expand Up @@ -1472,6 +1499,7 @@ def create_alert(

return alert_id

@check_run_initialised
@skip_if_failed("_aborted", "_suppress_errors", False)
@pydantic.validate_call
def log_alert(
Expand Down
11 changes: 11 additions & 0 deletions tests/refactor/test_run_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import uuid
import concurrent.futures
import random
import inspect

import simvue.run as sv_run
import simvue.client as sv_cl
Expand All @@ -14,6 +15,16 @@
from .conftest import CountingLogHandler


@pytest.mark.run
def test_check_run_initialised_decorator() -> None:
with sv_run.Run(mode="offline") as run:
for method_name, method in inspect.getmembers(run, inspect.ismethod):
if not method.__name__.endswith("init_locked"):
continue
with pytest.raises(RuntimeError) as e:
getattr(run, method_name)()
assert "Simvue Run must be initialised" in str(e.value)

@pytest.mark.run
@pytest.mark.parametrize("overload_buffer", (True, False), ids=("overload", "normal"))
@pytest.mark.parametrize("visibility", ("bad_option", "tenant", "public", ["ciuser01"], None))
Expand Down