Skip to content

Commit e62c9f3

Browse files
committed
Delete snapshot after upload
1 parent 50a78f6 commit e62c9f3

File tree

3 files changed

+49
-23
lines changed

3 files changed

+49
-23
lines changed

simvue/api/objects/artifact/file.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,8 @@ def new(
124124
with open(_file_orig_path, "rb") as out_f:
125125
_artifact._upload(file=out_f, timeout=upload_timeout, file_size=_file_size)
126126

127+
# If snapshot created, delete it after uploading
128+
if pathlib.Path(_file_orig_path).parent == _artifact._local_staging_file.parent:
129+
pathlib.Path(_file_orig_path).unlink()
130+
127131
return _artifact

simvue/sender.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,39 +86,38 @@ def upload_cached_file(
8686
if issubclass(_instance_class, simvue.api.objects.ObjectArtifact):
8787
with open(file_path.parent.joinpath(f"{_current_id}.object"), "rb") as file:
8888
_data["serialized"] = file.read()
89+
try:
90+
# We want to reconnect if there is an online ID stored for this file
91+
if _online_id := id_mapping.get(_current_id):
92+
obj_for_upload = _instance_class(
93+
identifier=_online_id, _read_only=False, **_data
94+
)
95+
else:
96+
obj_for_upload = _instance_class.new(**_data)
8997

90-
# We want to reconnect if there is an online ID stored for this file
91-
if _online_id := id_mapping.get(_current_id):
92-
obj_for_upload = _instance_class(
93-
identifier=_online_id, _read_only=False, **_data
94-
)
95-
else:
96-
obj_for_upload = _instance_class.new(**_data)
97-
98-
with lock:
99-
obj_for_upload.on_reconnect(id_mapping)
98+
with lock:
99+
obj_for_upload.on_reconnect(id_mapping)
100100

101-
try:
102101
if not issubclass(_instance_class, ArtifactBase):
103102
obj_for_upload.commit()
104103
_new_id = obj_for_upload.id
104+
105105
except Exception as error:
106106
if "status 409" in error.args[0]:
107107
return
108+
108109
_logger.error(
109-
f"Error while committing '{obj_for_upload.__class__.__name__}': {error.args[0]}"
110+
f"Error while committing '{_instance_class.__name__}': {error.args[0]}"
110111
)
111112
_log_upload_failed(file_path)
112113
return
113114
if not _new_id:
114-
_logger.error(
115-
f"Object of type '{obj_for_upload.__class__.__name__}' has no identifier"
116-
)
115+
_logger.error(f"Object of type '{_instance_class.__name__}' has no identifier")
117116
_log_upload_failed(file_path)
118117
return
119118

120119
_logger.info(
121-
f"{'Updated' if id_mapping.get(_current_id) else 'Created'} {obj_for_upload.__class__.__name__} '{_new_id}'"
120+
f"{'Updated' if id_mapping.get(_current_id) else 'Created'} {_instance_class.__name__} '{_new_id}'"
122121
)
123122

124123
file_path.unlink(missing_ok=True)

tests/unit/test_file_artifact.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@
1010
from simvue.api.objects.folder import Folder
1111
from simvue.sender import sender
1212
from simvue.client import Client
13+
import logging
1314

1415
@pytest.mark.api
1516
@pytest.mark.online
16-
def test_file_artifact_creation_online() -> None:
17+
@pytest.mark.parametrize(
18+
"snapshot",
19+
(True, False)
20+
)
21+
def test_file_artifact_creation_online(offline_cache_setup, snapshot) -> None:
1722
_uuid: str = f"{uuid.uuid4()}".split("-")[0]
1823
_folder_name = f"/simvue_unit_testing/{_uuid}"
1924
_folder = Folder.new(path=_folder_name)
@@ -32,7 +37,8 @@ def test_file_artifact_creation_online() -> None:
3237
file_path=_path,
3338
storage=None,
3439
mime_type=None,
35-
metadata=None
40+
metadata=None,
41+
snapshot=snapshot
3642
)
3743
_artifact.attach_to_run(_run.id, "input")
3844
time.sleep(1)
@@ -45,6 +51,11 @@ def test_file_artifact_creation_online() -> None:
4551
_content = b"".join(_artifact.download_content()).decode("UTF-8")
4652
assert _content == f"Hello World! {_uuid}"
4753
assert _artifact.to_dict()
54+
55+
# If snapshotting, check no local copy remains
56+
if snapshot:
57+
assert len(list(_artifact._local_staging_file.parent.iterdir())) == 0
58+
4859
_run.delete()
4960
_folder.delete(recursive=True, delete_runs=True, runs_only=False)
5061
with contextlib.suppress(FileNotFoundError):
@@ -55,7 +66,11 @@ def test_file_artifact_creation_online() -> None:
5566

5667
@pytest.mark.api
5768
@pytest.mark.offline
58-
def test_file_artifact_creation_offline(offline_cache_setup) -> None:
69+
@pytest.mark.parametrize(
70+
"snapshot",
71+
(True, False)
72+
)
73+
def test_file_artifact_creation_offline(offline_cache_setup, snapshot) -> None:
5974
_uuid: str = f"{uuid.uuid4()}".split("-")[0]
6075
_folder_name = f"/simvue_unit_testing/{_uuid}"
6176
_folder = Folder.new(path=_folder_name, offline=True)
@@ -74,7 +89,8 @@ def test_file_artifact_creation_offline(offline_cache_setup) -> None:
7489
storage=None,
7590
mime_type=None,
7691
offline=True,
77-
metadata=None
92+
metadata=None,
93+
snapshot=snapshot
7894
)
7995
_artifact.attach_to_run(_run._identifier, category="input")
8096

@@ -84,9 +100,15 @@ def test_file_artifact_creation_offline(offline_cache_setup) -> None:
84100
assert _local_data.get("name") == f"test_file_artifact_{_uuid}"
85101
assert _local_data.get("runs") == {_run._identifier: "input"}
86102

103+
# If snapshot, check artifact definition file and a copy of the actual file exist in staging area
104+
assert len(list(_artifact._local_staging_file.parent.iterdir())) == 2 if snapshot else 1
105+
87106
_id_mapping = sender(pathlib.Path(offline_cache_setup.name), 1, 10)
88107
time.sleep(1)
89108

109+
# Check file(s) deleted after upload
110+
assert len(list(_artifact._local_staging_file.parent.iterdir())) == 0
111+
90112
_online_artifact = Artifact(_id_mapping[_artifact.id])
91113
assert _online_artifact.name == _artifact.name
92114
_content = b"".join(_online_artifact.download_content()).decode("UTF-8")
@@ -101,11 +123,11 @@ def test_file_artifact_creation_offline(offline_cache_setup) -> None:
101123
"snapshot",
102124
(True, False)
103125
)
104-
def test_file_artifact_creation_offline_snapshot(offline_cache_setup, snapshot) -> None:
126+
def test_file_artifact_creation_offline_updated(offline_cache_setup, caplog, snapshot) -> None:
105127
_uuid: str = f"{uuid.uuid4()}".split("-")[0]
106128
_folder_name = f"/simvue_unit_testing/{_uuid}"
107129
_folder = Folder.new(path=_folder_name, offline=True)
108-
_run = Run.new(name=f"test_file_artifact_creation_offline_snapshot_{_uuid}",folder=_folder_name, offline=True)
130+
_run = Run.new(name=f"test_file_artifact_creation_offline_updated_{_uuid}",folder=_folder_name, offline=True)
109131

110132
_path = pathlib.Path(offline_cache_setup.name).joinpath("hello_world.txt")
111133

@@ -136,8 +158,9 @@ def test_file_artifact_creation_offline_snapshot(offline_cache_setup, snapshot)
136158
out_f.write("File changed!")
137159

138160
if not snapshot:
139-
with pytest.raises(RuntimeError): # TODO: Make sender be resilient to this?
161+
with caplog.at_level(logging.ERROR):
140162
_id_mapping = sender(pathlib.Path(offline_cache_setup.name), 1, 10)
163+
assert "The SHA256 you specified did not match the calculated checksum." in caplog.text
141164
return
142165
else:
143166
_id_mapping = sender(pathlib.Path(offline_cache_setup.name), 1, 10)

0 commit comments

Comments
 (0)