Skip to content

Commit e666f9b

Browse files
committed
Merge branch 'dev' into hotfix/add-missing-tests
2 parents 64d75f1 + 4517e63 commit e666f9b

File tree

11 files changed

+147
-40
lines changed

11 files changed

+147
-40
lines changed

.github/workflows/citation.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Citation File Validation
2+
3+
on:
4+
push:
5+
branches: [ "main", "dev", "hotfix/update-ci" ]
6+
pull_request:
7+
branches: [ "main", "dev", "hotfix/update-ci" ]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
timeout-minutes: 20
16+
steps:
17+
- uses: actions/checkout@v3
18+
- name: Set up Python
19+
uses: actions/setup-python@v3
20+
- name: Install Checker
21+
run: python3 -m pip install cffconvert
22+
- name: Check Citation File
23+
run: cffconvert --validate

CITATION.cff

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# This CITATION.cff file was generated with cffinit.
2+
# Visit https://bit.ly/cffinit to generate yours today!
3+
4+
cff-version: 1.2.0
5+
title: Simvue
6+
message: >-
7+
If you use this software, please cite it using the
8+
metadata from this file.
9+
type: software
10+
authors:
11+
- given-names: Andrew
12+
family-names: Lahiff
13+
affiliation: United Kingdom Atomic Energy Authority
14+
orcid: 'https://orcid.org/0000-0002-2785-4116'
15+
- given-names: Aby
16+
family-names: Abraham
17+
affiliation: United Kingdom Atomic Energy Authority
18+
- given-names: Vignesh
19+
family-names: Gopakumar
20+
orcid: 'https://orcid.org/0000-0002-6773-1049'
21+
affiliation: United Kingdom Atomic Energy Authority
22+
- given-names: Kristian
23+
family-names: Zarebski
24+
affiliation: United Kingdom Atomic Energy Authority
25+
orcid: 'https://orcid.org/0000-0002-6773-1049'
26+
- given-names: Matthew
27+
family-names: Field
28+
affiliation: United Kingdom Atomic Energy Authority
29+
- given-names: James
30+
family-names: Panayis
31+
affiliation: United Kingdom Atomic Energy Authority
32+
repository-code: 'https://github.com/simvue-io/client'
33+
url: 'https://simvue.io/'
34+
abstract: >-
35+
Simvue allows users to organise and gain insights in simulations,
36+
processing tasks and AI/ML training by capturing metadata and
37+
data combined with real-time monitoring, logging and alerting.
38+
keywords:
39+
- tracking
40+
- monitoring
41+
- metrics
42+
- alerting
43+
- simulation
44+
license: Apache-2.0

simvue/run.py

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

6363

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

824840
return True
825841

842+
@check_run_initialised
826843
@skip_if_failed("_aborted", "_suppress_errors", False)
827844
@pydantic.validate_call
828845
def update_metadata(self, metadata: dict[str, typing.Any]) -> bool:
@@ -848,6 +865,7 @@ def update_metadata(self, metadata: dict[str, typing.Any]) -> bool:
848865

849866
return False
850867

868+
@check_run_initialised
851869
@skip_if_failed("_aborted", "_suppress_errors", False)
852870
@pydantic.validate_call
853871
def update_tags(self, tags: list[str]) -> bool:
@@ -868,6 +886,7 @@ def update_tags(self, tags: list[str]) -> bool:
868886

869887
return False
870888

889+
@check_run_initialised
871890
@skip_if_failed("_aborted", "_suppress_errors", False)
872891
@pydantic.validate_call
873892
def log_event(self, message, timestamp: typing.Optional[str] = None) -> bool:
@@ -942,6 +961,7 @@ def _add_metrics_to_dispatch(
942961

943962
return True
944963

964+
@check_run_initialised
945965
@skip_if_failed("_aborted", "_suppress_errors", False)
946966
@pydantic.validate_call
947967
def log_metrics(
@@ -960,6 +980,7 @@ def log_metrics(
960980
self._step += 1
961981
return add_dispatch
962982

983+
@check_run_initialised
963984
@skip_if_failed("_aborted", "_suppress_errors", False)
964985
@pydantic.validate_call
965986
def save_object(
@@ -1081,6 +1102,7 @@ def save_file(
10811102
# Register file
10821103
return self._simvue.save_file(data) is not None
10831104

1105+
@check_run_initialised
10841106
@skip_if_failed("_aborted", "_suppress_errors", False)
10851107
@pydantic.validate_call
10861108
def save_directory(
@@ -1117,6 +1139,7 @@ def save_directory(
11171139

11181140
return True
11191141

1142+
@check_run_initialised
11201143
@skip_if_failed("_aborted", "_suppress_errors", False)
11211144
@pydantic.validate_call
11221145
def save_all(
@@ -1147,6 +1170,7 @@ def save_all(
11471170

11481171
return True
11491172

1173+
@check_run_initialised
11501174
@skip_if_failed("_aborted", "_suppress_errors", False)
11511175
@pydantic.validate_call
11521176
def set_status(
@@ -1216,6 +1240,7 @@ def close(self) -> bool:
12161240

12171241
return True
12181242

1243+
@check_run_initialised
12191244
@skip_if_failed("_aborted", "_suppress_errors", False)
12201245
@pydantic.validate_call
12211246
def set_folder_details(
@@ -1270,6 +1295,7 @@ def set_folder_details(
12701295

12711296
return False
12721297

1298+
@check_run_initialised
12731299
@skip_if_failed("_aborted", "_suppress_errors", False)
12741300
@pydantic.validate_call
12751301
def add_alerts(
@@ -1317,6 +1343,7 @@ def add_alerts(
13171343

13181344
return False
13191345

1346+
@check_run_initialised
13201347
@skip_if_failed("_aborted", "_suppress_errors", None)
13211348
@pydantic.validate_call
13221349
def create_alert(
@@ -1478,6 +1505,7 @@ def create_alert(
14781505

14791506
return alert_id
14801507

1508+
@check_run_initialised
14811509
@skip_if_failed("_aborted", "_suppress_errors", False)
14821510
@pydantic.validate_call
14831511
def log_alert(

tests/functional/test_run_offline_folder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_basic_run_folder(self):
2424
pass
2525

2626
name = "test-%s" % str(uuid.uuid4())
27-
folder = "/test-%s" % str(uuid.uuid4())
27+
folder = "/simvue_unit_testing"
2828
metadata = {str(uuid.uuid4()): 100 * random.random()}
2929
run = Run("offline")
3030
run.init(name, folder=folder)

tests/refactor/conftest.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,48 +42,53 @@ def log_messages(caplog):
4242

4343

4444
@pytest.fixture
45-
def create_test_run() -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
45+
def create_test_run(request) -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
4646
with sv_run.Run() as run:
47-
yield run, setup_test_run(run, True)
47+
yield run, setup_test_run(run, True, request)
4848

4949

5050
@pytest.fixture
51-
def create_test_run_offline(mocker: pytest_mock.MockerFixture) -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
51+
def create_test_run_offline(mocker: pytest_mock.MockerFixture, request) -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
5252
with tempfile.TemporaryDirectory() as temp_d:
5353
mocker.patch.object(simvue.utilities, "get_offline_directory", lambda *_: temp_d)
5454
with sv_run.Run("offline") as run:
55-
yield run, setup_test_run(run, True)
55+
yield run, setup_test_run(run, True, request)
5656

5757

5858
@pytest.fixture
59-
def create_plain_run() -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
59+
def create_plain_run(request) -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
6060
with sv_run.Run() as run:
61-
yield run, setup_test_run(run, False)
61+
yield run, setup_test_run(run, False, request)
6262

6363

6464
@pytest.fixture
65-
def create_plain_run_offline(mocker: pytest_mock.MockerFixture) -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
65+
def create_plain_run_offline(mocker: pytest_mock.MockerFixture, request) -> typing.Generator[typing.Tuple[sv_run.Run, dict], None, None]:
6666
with tempfile.TemporaryDirectory() as temp_d:
6767
mocker.patch.object(simvue.utilities, "get_offline_directory", lambda *_: temp_d)
6868
with sv_run.Run("offline") as run:
6969

70-
yield run, setup_test_run(run, False)
70+
yield run, setup_test_run(run, False, request)
7171

7272

73-
def setup_test_run(run: sv_run.Run, create_objects: bool):
73+
def setup_test_run(run: sv_run.Run, create_objects: bool, request: pytest.FixtureRequest):
7474
fix_use_id: str = str(uuid.uuid4()).split('-', 1)[0]
7575
TEST_DATA = {
7676
"event_contains": "sent event",
7777
"metadata": {
7878
"test_engine": "pytest",
7979
"test_identifier": fix_use_id
8080
},
81-
"folder": f"/simvue_unit_testing/{fix_use_id}"
81+
"folder": f"/simvue_unit_testing/{fix_use_id}",
82+
"tags": ["simvue_client_unit_tests", request.node.name]
8283
}
84+
85+
if os.environ.get("CI"):
86+
TEST_DATA["tags"].append("ci")
87+
8388
run.config(suppress_errors=False)
8489
run.init(
8590
name=f"test_run_{TEST_DATA['metadata']['test_identifier']}",
86-
tags=["simvue_client_unit_tests"],
91+
tags=TEST_DATA["tags"],
8792
folder=TEST_DATA["folder"],
8893
visibility="tenant",
8994
retention_period="1 hour"

tests/refactor/test_client.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ def test_run_deletion(create_test_run: tuple[sv_run.Run, dict]) -> None:
175175
@pytest.mark.client(depends=PRE_DELETION_TESTS)
176176
def test_runs_deletion(create_test_run: tuple[sv_run.Run, dict]) -> None:
177177
run, run_data = create_test_run
178-
run.update_tags(["simvue_client_unit_tests", "test_runs_deletion"])
179178
run.close()
180179
client = svc.Client()
181180
assert len(client.delete_runs(run_data["folder"])) > 0
@@ -185,7 +184,6 @@ def test_runs_deletion(create_test_run: tuple[sv_run.Run, dict]) -> None:
185184
@pytest.mark.client(depends=PRE_DELETION_TESTS + ["test_runs_deletion"])
186185
def test_folder_deletion(create_test_run: tuple[sv_run.Run, dict]) -> None:
187186
run, run_data = create_test_run
188-
run.update_tags(["simvue_client_unit_tests", "test_folder_deletion"])
189187
run.close()
190188
client = svc.Client()
191189
# This test is called last, one run created so expect length 1

tests/refactor/test_executor.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
@pytest.mark.executor
99
@pytest.mark.parametrize("successful", (True, False), ids=("successful", "failing"))
1010
def test_executor_add_process(
11-
successful: bool
11+
successful: bool,
12+
request: pytest.FixtureRequest
1213
) -> None:
1314
run = simvue.Run()
1415
completion_trigger = multiprocessing.Event()
1516
run.init(
1617
f"test_executor_{'success' if successful else 'fail'}",
17-
tags=["simvue_client_unit_tests"],
18-
folder="/simvue_unit_test_folder"
18+
tags=["simvue_client_unit_tests", request.node.name],
19+
folder="/simvue_unit_testing"
1920
)
2021

2122
run.add_process(

0 commit comments

Comments
 (0)