Skip to content

Commit 0d89b23

Browse files
amickanjmsmkn
andauthored
Allow extending overlay segments for sockets (#4034)
Closes DIAGNijmegen/rse-grand-challenge-admin#520 --------- Co-authored-by: James Meakin <12661555+jmsmkn@users.noreply.github.com>
1 parent 972726a commit 0d89b23

2 files changed

Lines changed: 62 additions & 11 deletions

File tree

app/grandchallenge/components/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ def _clean_overlay_segments(self):
622622
if (
623623
self.pk is not None
624624
and self._overlay_segments_orig != self.overlay_segments
625+
and not self._overlay_segments_preserved
625626
and (
626627
ComponentInterfaceValue.objects.filter(interface=self).exists()
627628
or Question.objects.filter(interface=self).exists()
@@ -632,6 +633,16 @@ def _clean_overlay_segments(self):
632633
"for this ComponentInterface exist."
633634
)
634635

636+
@property
637+
def _overlay_segments_preserved(self):
638+
orig_overlay_segments = {
639+
tuple(sorted(d.items())) for d in self._overlay_segments_orig
640+
}
641+
new_overlay_segments = {
642+
tuple(sorted(d.items())) for d in self.overlay_segments
643+
}
644+
return orig_overlay_segments <= new_overlay_segments
645+
635646
def _clean_relative_path(self):
636647
if (
637648
self.is_file_kind or self.is_json_kind

app/tests/components_tests/test_models.py

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,15 +1110,15 @@ def test_runtime_metrics_chart():
11101110

11111111
@pytest.mark.django_db
11121112
def test_clean_overlay_segments_with_values():
1113-
ci = ComponentInterfaceFactory(kind=InterfaceKindChoices.SEGMENTATION)
1114-
ci.overlay_segments = [{"name": "s1", "visible": True, "voxel_value": 1}]
1113+
ci = ComponentInterfaceFactory(
1114+
kind=InterfaceKindChoices.SEGMENTATION,
1115+
overlay_segments=[{"name": "s1", "visible": True, "voxel_value": 1}],
1116+
)
11151117
ci._clean_overlay_segments()
1116-
ci.save()
11171118

11181119
ComponentInterfaceValueFactory(interface=ci)
11191120
ci.overlay_segments = [
1120-
{"name": "s1", "visible": True, "voxel_value": 1},
1121-
{"name": "s2", "visible": True, "voxel_value": 2},
1121+
{"name": "s2", "visible": True, "voxel_value": 1},
11221122
]
11231123
with pytest.raises(ValidationError) as e:
11241124
ci._clean_overlay_segments()
@@ -1136,18 +1136,17 @@ def test_clean_overlay_segments_with_questions(reader_study_with_gt):
11361136
)
11371137
assert question.interface is None
11381138

1139-
ci = ComponentInterface(
1140-
kind=InterfaceKindChoices.SEGMENTATION, relative_path="images/test"
1139+
ci = ComponentInterfaceFactory(
1140+
kind=InterfaceKindChoices.SEGMENTATION,
1141+
relative_path="images/test",
1142+
overlay_segments=[{"name": "s1", "visible": True, "voxel_value": 1}],
11411143
)
1142-
ci.overlay_segments = [{"name": "s1", "visible": True, "voxel_value": 1}]
11431144
ci._clean_overlay_segments()
1144-
ci.save()
11451145

11461146
question.interface = ci
11471147
question.save()
11481148
ci.overlay_segments = [
1149-
{"name": "s1", "visible": True, "voxel_value": 1},
1150-
{"name": "s2", "visible": True, "voxel_value": 2},
1149+
{"name": "s2", "visible": True, "voxel_value": 1},
11511150
]
11521151
with pytest.raises(ValidationError) as e:
11531152
ci._clean_overlay_segments()
@@ -1191,6 +1190,47 @@ def test_clean_overlay_segments():
11911190
ci._clean_overlay_segments()
11921191

11931192

1193+
@pytest.mark.parametrize(
1194+
"updated_segments, expectation",
1195+
(
1196+
[
1197+
[{"name": "s1", "visible": True, "voxel_value": 1}],
1198+
pytest.raises(ValidationError),
1199+
], # deletes existing voxel values
1200+
[
1201+
[
1202+
{"name": "sfoo", "visible": True, "voxel_value": 1},
1203+
{"name": "s2", "visible": True, "voxel_value": 2},
1204+
],
1205+
pytest.raises(ValidationError),
1206+
], # changes name of existing voxel value
1207+
[
1208+
[
1209+
{"name": "s1", "visible": True, "voxel_value": 1},
1210+
{"name": "s2", "visible": True, "voxel_value": 2},
1211+
{"name": "s3", "visible": True, "voxel_value": 3},
1212+
],
1213+
nullcontext(),
1214+
], # adds new voxel value
1215+
),
1216+
)
1217+
@pytest.mark.django_db
1218+
def test_overlay_segments_can_be_extended(updated_segments, expectation):
1219+
ci = ComponentInterfaceFactory(
1220+
kind=InterfaceKindChoices.SEGMENTATION,
1221+
overlay_segments=[
1222+
{"name": "s1", "visible": True, "voxel_value": 1},
1223+
{"name": "s2", "visible": True, "voxel_value": 2},
1224+
],
1225+
)
1226+
ComponentInterfaceValueFactory(interface=ci)
1227+
1228+
ci.overlay_segments = updated_segments
1229+
1230+
with expectation:
1231+
ci._clean_overlay_segments()
1232+
1233+
11941234
@pytest.mark.django_db
11951235
def test_validate_voxel_values():
11961236
ci = ComponentInterfaceFactory(kind=InterfaceKindChoices.SEGMENTATION)

0 commit comments

Comments
 (0)