Skip to content

Commit 3b5978c

Browse files
committed
added delete_recod_set and selete_file_view
1 parent 5ca3142 commit 3b5978c

2 files changed

Lines changed: 290 additions & 7 deletions

File tree

synapseclient/models/curation.py

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class FileBasedMetadataTaskProperties:
4545
A CurationTaskProperties for file-based data, describing where data is uploaded
4646
and a view which contains the annotations.
4747
48-
Represents a [Synapse FileBasedMetadataTaskProperties](https://rest-docs.synapse.org/org/sagebionetworks/repo/model/curation/metadata/FileBasedMetadataTaskProperties.html).
48+
Represents a [Synapse FileBasedMetadataTaskProperties](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/curation/metadata/FileBasedMetadataTaskProperties.html).
4949
5050
Attributes:
5151
upload_folder_id: The synId of the folder where data files of this type are to be uploaded
@@ -94,7 +94,7 @@ class RecordBasedMetadataTaskProperties:
9494
"""
9595
A CurationTaskProperties for record-based metadata.
9696
97-
Represents a [Synapse RecordBasedMetadataTaskProperties](https://rest-docs.synapse.org/org/sagebionetworks/repo/model/curation/metadata/RecordBasedMetadataTaskProperties.html).
97+
Represents a [Synapse RecordBasedMetadataTaskProperties](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/curation/metadata/RecordBasedMetadataTaskProperties.html).
9898
9999
Attributes:
100100
record_set_id: The synId of the RecordSet that will contain all record-based metadata
@@ -213,11 +213,21 @@ def get(self, *, synapse_client: Optional[Synapse] = None) -> "CurationTask":
213213
"""
214214
return self
215215

216-
def delete(self, *, synapse_client: Optional[Synapse] = None) -> None:
216+
def delete(
217+
self,
218+
delete_file_view: bool = False,
219+
delete_record_set: bool = False,
220+
*,
221+
synapse_client: Optional[Synapse] = None,
222+
) -> None:
217223
"""
218224
Deletes a CurationTask from Synapse.
219225
220226
Arguments:
227+
delete_file_view: If True, the associated EntityView will also be deleted
228+
if the task is a FileBasedMetadataTask. Defaults to False.
229+
delete_record_set: If True, the associated RecordSet will also be deleted
230+
if the task is a RecordBasedMetadataTask. Defaults to False.
221231
synapse_client: If not passed in and caching was not disabled by
222232
`Synapse.allow_client_caching(False)` this will use the last created
223233
instance from the Synapse class constructor.
@@ -238,6 +248,34 @@ def delete(self, *, synapse_client: Optional[Synapse] = None) -> None:
238248
task = CurationTask(task_id=123)
239249
task.delete()
240250
```
251+
252+
Example: Delete a curation task and its associated file view
253+
 
254+
255+
```python
256+
from synapseclient import Synapse
257+
from synapseclient.models import CurationTask
258+
259+
syn = Synapse()
260+
syn.login()
261+
262+
task = CurationTask(task_id=123)
263+
task.delete(delete_file_view=True)
264+
```
265+
266+
Example: Delete a curation task and its associated record set
267+
 
268+
269+
```python
270+
from synapseclient import Synapse
271+
from synapseclient.models import CurationTask
272+
273+
syn = Synapse()
274+
syn.login()
275+
276+
task = CurationTask(task_id=123)
277+
task.delete(delete_record_set=True)
278+
```
241279
"""
242280
return None
243281

@@ -602,17 +640,32 @@ async def main():
602640
self._set_last_persistent_instance()
603641
return self
604642

605-
async def delete_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
643+
async def delete_async(
644+
self,
645+
delete_file_view: bool = False,
646+
delete_record_set: bool = False,
647+
*,
648+
synapse_client: Optional[Synapse] = None,
649+
) -> None:
606650
"""
607651
Deletes a CurationTask from Synapse.
608652
609653
Arguments:
654+
delete_file_view: If True, the associated EntityView will also be deleted
655+
if the task is a FileBasedMetadataTask. Defaults to False.
656+
delete_record_set: If True, the associated RecordSet will also be deleted
657+
if the task is a RecordBasedMetadataTask. Defaults to False.
610658
synapse_client: If not passed in and caching was not disabled by
611659
`Synapse.allow_client_caching(False)` this will use the last created
612660
instance from the Synapse class constructor.
613661
614662
Raises:
615663
ValueError: If the CurationTask object does not have a task_id.
664+
ValueError: If delete_file_view=True but the task is not a FileBasedMetadataTask or does not have a
665+
file_view_id.
666+
ValueError: If delete_record_set=True but the task is not a RecordBasedMetadataTask or does not have a
667+
record_set_id.
668+
616669
617670
Example: Delete a curation task asynchronously
618671
 
@@ -632,6 +685,44 @@ async def main():
632685
633686
asyncio.run(main())
634687
```
688+
689+
Example: Delete a curation task and its associated file view asynchronously
690+
 
691+
692+
```python
693+
import asyncio
694+
from synapseclient import Synapse
695+
from synapseclient.models import CurationTask
696+
697+
syn = Synapse()
698+
syn.login()
699+
700+
async def main():
701+
task = CurationTask(task_id=123)
702+
await task.delete_async(delete_file_view=True)
703+
print("Task and file view deleted successfully")
704+
705+
asyncio.run(main())
706+
```
707+
708+
Example: Delete a curation task and its associated record set asynchronously
709+
 
710+
711+
```python
712+
import asyncio
713+
from synapseclient import Synapse
714+
from synapseclient.models import CurationTask
715+
716+
syn = Synapse()
717+
syn.login()
718+
719+
async def main():
720+
task = CurationTask(task_id=123)
721+
await task.delete_async(delete_record_set=True)
722+
print("Task and record set deleted successfully")
723+
724+
asyncio.run(main())
725+
```
635726
"""
636727
if not self.task_id:
637728
raise ValueError("task_id is required to delete a CurationTask")
@@ -642,6 +733,64 @@ async def main():
642733
}
643734
)
644735

736+
if delete_file_view or delete_record_set:
737+
if not self.task_properties:
738+
await self.get_async(synapse_client=synapse_client)
739+
740+
if delete_file_view:
741+
if (
742+
isinstance(self.task_properties, FileBasedMetadataTaskProperties)
743+
and self.task_properties.file_view_id
744+
):
745+
from synapseclient.models.entityview import EntityView
746+
747+
await EntityView(id=self.task_properties.file_view_id).delete_async(
748+
synapse_client=synapse_client
749+
)
750+
751+
elif not isinstance(self.task_properties, FileBasedMetadataTaskProperties):
752+
raise ValueError(
753+
(
754+
"The `delete_file_view` parameter was set to True, "
755+
"but the task is not configured as a FileBasedMetadataTask."
756+
)
757+
)
758+
else:
759+
raise ValueError(
760+
(
761+
"The `delete_file_view` parameter was set to True, "
762+
"but the task does not have an associated file view ID."
763+
)
764+
)
765+
766+
if delete_record_set:
767+
if (
768+
isinstance(self.task_properties, RecordBasedMetadataTaskProperties)
769+
and self.task_properties.record_set_id
770+
):
771+
from synapseclient.models.recordset import RecordSet
772+
773+
await RecordSet(id=self.task_properties.record_set_id).delete_async(
774+
synapse_client=synapse_client
775+
)
776+
777+
elif not isinstance(
778+
self.task_properties, RecordBasedMetadataTaskProperties
779+
):
780+
raise ValueError(
781+
(
782+
"The `delete_record_set` parameter was set to True, "
783+
"but the task is not configured as a RecordBasedMetadataTask."
784+
)
785+
)
786+
else:
787+
raise ValueError(
788+
(
789+
"The `delete_record_set` parameter was set to True, "
790+
"but the task does not have an associated record set ID."
791+
)
792+
)
793+
645794
await delete_curation_task(task_id=self.task_id, synapse_client=synapse_client)
646795

647796
async def store_async(

tests/integration/synapseclient/models/async/test_curation_async.py

Lines changed: 137 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from synapseclient import Synapse
1212
from synapseclient.core.exceptions import SynapseHTTPError
13+
from synapseclient.core.utils import make_bogus_uuid_file
1314
from synapseclient.models import (
1415
Column,
1516
ColumnType,
@@ -412,7 +413,35 @@ async def folder_with_view(
412413

413414
return folder, entity_view
414415

415-
async def test_delete_curation_task_async(
416+
@pytest.fixture(scope="class")
417+
async def folder_with_record_set(
418+
self,
419+
project_model: Project,
420+
syn: Synapse,
421+
schedule_for_cleanup: Callable[..., None],
422+
) -> tuple[Folder, EntityView]:
423+
"""Create a folder with a a record set for record-based testing."""
424+
# Create a folder
425+
folder = await Folder(
426+
name=str(uuid.uuid4()),
427+
parent_id=project_model.id,
428+
).store_async(synapse_client=syn)
429+
schedule_for_cleanup(folder.id)
430+
431+
filename = make_bogus_uuid_file()
432+
schedule_for_cleanup(filename)
433+
434+
record_set = await RecordSet(
435+
name=str(uuid.uuid4()),
436+
parent_id=folder.id,
437+
path=filename,
438+
upsert_keys=["xxx"],
439+
).store_async(synapse_client=syn)
440+
schedule_for_cleanup(record_set.id)
441+
442+
return folder, record_set
443+
444+
async def test_delete_file_based_curation_task_async(
416445
self, project_model: Project, folder_with_view: tuple[Folder, EntityView]
417446
) -> None:
418447
# GIVEN a project, folder, and entity view
@@ -434,13 +463,118 @@ async def test_delete_curation_task_async(
434463
task_id = curation_task.task_id
435464
assert task_id is not None
436465

437-
# WHEN I delete the task asynchronously
438-
await curation_task.delete_async(synapse_client=self.syn)
466+
# WHEN I delete the task asynchronously, without deleting the file view
467+
await curation_task.delete_async(
468+
synapse_client=self.syn, delete_file_view=False
469+
)
439470

440471
# THEN the task should be deleted and no longer retrievable
441472
with pytest.raises(SynapseHTTPError):
442473
await CurationTask(task_id=task_id).get_async(synapse_client=self.syn)
443474

475+
# AND the file view should not be deleted
476+
await EntityView(entity_view.id).get_async(synapse_client=self.syn)
477+
478+
async def test_delete_file_based_curation_task_and_fileview_async(
479+
self, project_model: Project, folder_with_view: tuple[Folder, EntityView]
480+
) -> None:
481+
# GIVEN a project, folder, and entity view
482+
folder, entity_view = folder_with_view
483+
484+
# GIVEN an existing curation task
485+
data_type = f"test_data_type_{str(uuid.uuid4()).replace('-', '_')}"
486+
task_properties = FileBasedMetadataTaskProperties(
487+
upload_folder_id=folder.id,
488+
file_view_id=entity_view.id,
489+
)
490+
curation_task = await CurationTask(
491+
data_type=data_type,
492+
project_id=project_model.id,
493+
instructions="Task to be deleted",
494+
task_properties=task_properties,
495+
).store_async(synapse_client=self.syn)
496+
497+
task_id = curation_task.task_id
498+
assert task_id is not None
499+
500+
# WHEN I delete the task and fileview asynchronously
501+
await curation_task.delete_async(synapse_client=self.syn, delete_file_view=True)
502+
503+
# THEN the task should be deleted and no longer retrievable
504+
with pytest.raises(SynapseHTTPError):
505+
await CurationTask(task_id=task_id).get_async(synapse_client=self.syn)
506+
507+
# AND the file view should be deleted and no longer retrievable
508+
with pytest.raises(SynapseHTTPError):
509+
await EntityView(entity_view.id).get_async(synapse_client=self.syn)
510+
511+
async def test_delete_record_based_curation_task_async(
512+
self, project_model: Project, folder_with_record_set: tuple[Folder, EntityView]
513+
) -> None:
514+
# GIVEN a folder, and record set
515+
_, record_set = folder_with_record_set
516+
517+
# GIVEN an existing curation task
518+
data_type = f"test_data_type_{str(uuid.uuid4()).replace('-', '_')}"
519+
task_properties = RecordBasedMetadataTaskProperties(
520+
record_set_id=record_set.id,
521+
)
522+
curation_task = await CurationTask(
523+
data_type=data_type,
524+
project_id=project_model.id,
525+
instructions="Task to be deleted",
526+
task_properties=task_properties,
527+
).store_async(synapse_client=self.syn)
528+
529+
task_id = curation_task.task_id
530+
assert task_id is not None
531+
532+
# WHEN I delete the task asynchronously, without deleting the record set
533+
await curation_task.delete_async(
534+
synapse_client=self.syn, delete_record_set=False
535+
)
536+
537+
# THEN the task should be deleted and no longer retrievable
538+
with pytest.raises(SynapseHTTPError):
539+
await CurationTask(task_id=task_id).get_async(synapse_client=self.syn)
540+
541+
# AND the record set should not be deleted
542+
await RecordSet(record_set.id).get_async(synapse_client=self.syn)
543+
544+
async def test_delete_record_based_curation_task_and_record_set_async(
545+
self, project_model: Project, folder_with_record_set: tuple[Folder, EntityView]
546+
) -> None:
547+
# GIVEN a folder, and record set
548+
_, record_set = folder_with_record_set
549+
550+
# GIVEN an existing curation task
551+
data_type = f"test_data_type_{str(uuid.uuid4()).replace('-', '_')}"
552+
task_properties = RecordBasedMetadataTaskProperties(
553+
record_set_id=record_set.id,
554+
)
555+
curation_task = await CurationTask(
556+
data_type=data_type,
557+
project_id=project_model.id,
558+
instructions="Task to be deleted",
559+
task_properties=task_properties,
560+
).store_async(synapse_client=self.syn)
561+
562+
task_id = curation_task.task_id
563+
assert task_id is not None
564+
565+
# WHEN I delete the task asynchronously, without deleting the record set
566+
await curation_task.delete_async(
567+
synapse_client=self.syn, delete_record_set=True
568+
)
569+
570+
# THEN the task should be deleted and no longer retrievable
571+
with pytest.raises(SynapseHTTPError):
572+
await CurationTask(task_id=task_id).get_async(synapse_client=self.syn)
573+
574+
# AND the record set should be deleted and not retrievable
575+
with pytest.raises(SynapseHTTPError):
576+
await RecordSet(record_set.id).get_async(synapse_client=self.syn)
577+
444578
async def test_delete_validation_error_async(self) -> None:
445579
# GIVEN a CurationTask without a task_id
446580
curation_task = CurationTask()

0 commit comments

Comments
 (0)