Skip to content

Commit 2da7784

Browse files
authored
Merge pull request #231 from simvue-io/224-prevent-use-of-run-update-methods-when-the-run-instance-has-not-been-initialised
Added decorator to prevent pre-mature Run function calls
2 parents 855f365 + 23c4635 commit 2da7784

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

simvue/run.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,22 @@
6060
logger = logging.getLogger(__name__)
6161

6262

63+
def check_run_initialised(
64+
function: typing.Callable[..., typing.Any],
65+
) -> typing.Callable[..., typing.Any]:
66+
def _wrapper(self: "Run", *args: typing.Any, **kwargs: typing.Any) -> typing.Any:
67+
if not self._simvue:
68+
raise RuntimeError(
69+
"Simvue Run must be initialised before calling "
70+
f"'{function.__name__}'"
71+
)
72+
return function(self, *args, **kwargs)
73+
74+
_wrapper.__name__ = f"{function.__name__}__init_locked"
75+
76+
return _wrapper
77+
78+
6379
class Run:
6480
"""Track simulation details based on token and URL
6581
@@ -822,6 +838,7 @@ def config(
822838

823839
return True
824840

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

848865
return False
849866

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

868886
return False
869887

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

942961
return True
943962

963+
@check_run_initialised
944964
@skip_if_failed("_aborted", "_suppress_errors", False)
945965
@pydantic.validate_call
946966
def log_metrics(
@@ -959,6 +979,7 @@ def log_metrics(
959979
self._step += 1
960980
return add_dispatch
961981

982+
@check_run_initialised
962983
@skip_if_failed("_aborted", "_suppress_errors", False)
963984
@pydantic.validate_call
964985
def save(
@@ -1075,6 +1096,7 @@ def save(
10751096

10761097
return True
10771098

1099+
@check_run_initialised
10781100
@skip_if_failed("_aborted", "_suppress_errors", False)
10791101
@pydantic.validate_call
10801102
def save_directory(
@@ -1111,6 +1133,7 @@ def save_directory(
11111133

11121134
return True
11131135

1136+
@check_run_initialised
11141137
@skip_if_failed("_aborted", "_suppress_errors", False)
11151138
@pydantic.validate_call
11161139
def save_all(
@@ -1141,6 +1164,7 @@ def save_all(
11411164

11421165
return True
11431166

1167+
@check_run_initialised
11441168
@skip_if_failed("_aborted", "_suppress_errors", False)
11451169
@pydantic.validate_call
11461170
def set_status(
@@ -1210,6 +1234,7 @@ def close(self) -> bool:
12101234

12111235
return True
12121236

1237+
@check_run_initialised
12131238
@skip_if_failed("_aborted", "_suppress_errors", False)
12141239
@pydantic.validate_call
12151240
def set_folder_details(
@@ -1264,6 +1289,7 @@ def set_folder_details(
12641289

12651290
return False
12661291

1292+
@check_run_initialised
12671293
@skip_if_failed("_aborted", "_suppress_errors", False)
12681294
@pydantic.validate_call
12691295
def add_alerts(
@@ -1311,6 +1337,7 @@ def add_alerts(
13111337

13121338
return False
13131339

1340+
@check_run_initialised
13141341
@skip_if_failed("_aborted", "_suppress_errors", None)
13151342
@pydantic.validate_call
13161343
def create_alert(
@@ -1472,6 +1499,7 @@ def create_alert(
14721499

14731500
return alert_id
14741501

1502+
@check_run_initialised
14751503
@skip_if_failed("_aborted", "_suppress_errors", False)
14761504
@pydantic.validate_call
14771505
def log_alert(

tests/refactor/test_run_class.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import uuid
77
import concurrent.futures
88
import random
9+
import inspect
910

1011
import simvue.run as sv_run
1112
import simvue.client as sv_cl
@@ -14,6 +15,16 @@
1415
from .conftest import CountingLogHandler
1516

1617

18+
@pytest.mark.run
19+
def test_check_run_initialised_decorator() -> None:
20+
with sv_run.Run(mode="offline") as run:
21+
for method_name, method in inspect.getmembers(run, inspect.ismethod):
22+
if not method.__name__.endswith("init_locked"):
23+
continue
24+
with pytest.raises(RuntimeError) as e:
25+
getattr(run, method_name)()
26+
assert "Simvue Run must be initialised" in str(e.value)
27+
1728
@pytest.mark.run
1829
@pytest.mark.parametrize("overload_buffer", (True, False), ids=("overload", "normal"))
1930
@pytest.mark.parametrize("visibility", ("bad_option", "tenant", "public", ["ciuser01"], None))

0 commit comments

Comments
 (0)