Skip to content

Project

Contained within this file are experimental interfaces for working with the Synapse Python Client. Unless otherwise noted these interfaces are subject to change at any time. Use at your own risk.

API reference

synapseclient.models.Project dataclass

Bases: ProjectSynchronousProtocol, AccessControllable, StorableContainer

A Project is a top-level container for organizing data in Synapse.

ATTRIBUTE DESCRIPTION
id

The unique immutable ID for this project. A new ID will be generated for new Projects. Once issued, this ID is guaranteed to never change or be re-issued

TYPE: Optional[str]

name

The name of this project. Must be 256 characters or less. Names may only contain: letters, numbers, spaces, underscores, hyphens, periods, plus signs, apostrophes, and parentheses

TYPE: Optional[str]

description

The description of this entity. Must be 1000 characters or less.

TYPE: Optional[str]

etag

Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle concurrent updates. Since the E-Tag changes every time an entity is updated it is used to detect when a client's current representation of an entity is out-of-date.

TYPE: Optional[str]

created_on

The date this entity was created.

TYPE: Optional[str]

modified_on

The date this entity was last modified.

TYPE: Optional[str]

created_by

The ID of the user that created this entity.

TYPE: Optional[str]

modified_by

The ID of the user that last modified this entity.

TYPE: Optional[str]

alias

The project alias for use in friendly project urls.

TYPE: Optional[str]

files

Any files that are at the root directory of the project.

TYPE: List[File]

folders

Any folders that are at the root directory of the project.

TYPE: List[Folder]

annotations

Additional metadata associated with the folder. The key is the name of your desired annotations. The value is an object containing a list of values (use empty list to represent no values for key) and the value type associated with all values in the list. To remove all annotations set this to an empty dict {} or None and store the entity.

TYPE: Optional[Dict[str, Union[List[str], List[bool], List[float], List[int], List[date], List[datetime]]]]

create_or_update

(Store only) Indicates whether the method should automatically perform an update if the resource conflicts with an existing Synapse object. When True this means that any changes to the resource will be non-destructive.

This boolean is ignored if you've already stored or retrieved the resource from Synapse for this instance at least once. Any changes to the resource will be destructive in this case. For example if you want to delete the content for a field you will need to call .get() and then modify the field.

TYPE: bool

parent_id

The parent ID of the project. In practice projects do not have a parent, but this is required for the inner workings of Synapse.

TYPE: Optional[str]

Creating a project

This example shows how to create a project

from synapseclient.models import Project, File
import synapseclient

synapseclient.login()

my_annotations = {
    "my_single_key_string": "a",
    "my_key_string": ["b", "a", "c"],
}
project = Project(
    name="My unique project name",
    annotations=my_annotations,
    description="This is a project with random data.",
)

project = project.store()

print(project)
Storing several files to a project

This example shows how to store several files to a project

file_1 = File(
    path=path_to_file_1,
    name=name_of_file_1,
)
file_2 = File(
    path=path_to_file_2,
    name=name_of_file_2,
)
project.files = [file_1, file_2]
project = project.store()
Source code in synapseclient/models/project.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
@dataclass()
@async_to_sync
class Project(ProjectSynchronousProtocol, AccessControllable, StorableContainer):
    """A Project is a top-level container for organizing data in Synapse.

    Attributes:
        id: The unique immutable ID for this project. A new ID will be generated for new
            Projects. Once issued, this ID is guaranteed to never change or be re-issued
        name: The name of this project. Must be 256 characters or less. Names may only
            contain: letters, numbers, spaces, underscores, hyphens, periods, plus
            signs, apostrophes, and parentheses
        description: The description of this entity. Must be 1000 characters or less.
        etag: Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
            concurrent updates. Since the E-Tag changes every time an entity is updated
            it is used to detect when a client's current representation of an entity
            is out-of-date.
        created_on: The date this entity was created.
        modified_on: The date this entity was last modified.
        created_by: The ID of the user that created this entity.
        modified_by: The ID of the user that last modified this entity.
        alias: The project alias for use in friendly project urls.
        files: Any files that are at the root directory of the project.
        folders: Any folders that are at the root directory of the project.
        annotations: Additional metadata associated with the folder. The key is the name
            of your desired annotations. The value is an object containing a list of
            values (use empty list to represent no values for key) and the value type
            associated with all values in the list. To remove all annotations set this
            to an empty dict `{}` or None and store the entity.
        create_or_update: (Store only) Indicates whether the method should
            automatically perform an update if the resource conflicts with an existing
            Synapse object. When True this means that any changes to the resource will
            be non-destructive.

            This boolean is ignored if you've already stored or retrieved the resource
            from Synapse for this instance at least once. Any changes to the resource
            will be destructive in this case. For example if you want to delete the
            content for a field you will need to call `.get()` and then modify the
            field.
        parent_id: The parent ID of the project. In practice projects do not have a
            parent, but this is required for the inner workings of Synapse.

    Example: Creating a project
        This example shows how to create a project

            from synapseclient.models import Project, File
            import synapseclient

            synapseclient.login()

            my_annotations = {
                "my_single_key_string": "a",
                "my_key_string": ["b", "a", "c"],
            }
            project = Project(
                name="My unique project name",
                annotations=my_annotations,
                description="This is a project with random data.",
            )

            project = project.store()

            print(project)

    Example: Storing several files to a project
        This example shows how to store several files to a project

            file_1 = File(
                path=path_to_file_1,
                name=name_of_file_1,
            )
            file_2 = File(
                path=path_to_file_2,
                name=name_of_file_2,
            )
            project.files = [file_1, file_2]
            project = project.store()

    """

    id: Optional[str] = None
    """The unique immutable ID for this project. A new ID will be generated for new
    Projects. Once issued, this ID is guaranteed to never change or be re-issued"""

    name: Optional[str] = None
    """The name of this project. Must be 256 characters or less. Names may only contain:
    letters, numbers, spaces, underscores, hyphens, periods, plus signs, apostrophes,
    and parentheses"""

    description: Optional[str] = None
    """The description of this entity. Must be 1000 characters or less."""

    etag: Optional[str] = None
    """Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
    concurrent updates. Since the E-Tag changes every time an entity is updated it
    is used to detect when a client's current representation of an entity is out-of-date."""

    created_on: Optional[str] = field(default=None, compare=False)
    """(Read Only) The date this entity was created."""

    modified_on: Optional[str] = field(default=None, compare=False)
    """(Read Only) The date this entity was last modified."""

    created_by: Optional[str] = field(default=None, compare=False)
    """(Read Only) The ID of the user that created this entity."""

    modified_by: Optional[str] = field(default=None, compare=False)
    """(Read Only) The ID of the user that last modified this entity."""

    alias: Optional[str] = None
    """The project alias for use in friendly project urls."""

    files: List["File"] = field(default_factory=list, compare=False)
    """Any files that are at the root directory of the project."""

    folders: List["Folder"] = field(default_factory=list, compare=False)
    """Any folders that are at the root directory of the project."""

    annotations: Optional[
        Dict[
            str,
            Union[
                List[str],
                List[bool],
                List[float],
                List[int],
                List[date],
                List[datetime],
            ],
        ]
    ] = field(default_factory=dict, compare=False)
    """Additional metadata associated with the folder. The key is the name of your
    desired annotations. The value is an object containing a list of values
    (use empty list to represent no values for key) and the value type associated with
    all values in the list. To remove all annotations set this to an empty dict `{}`
    or None and store the entity."""

    create_or_update: bool = field(default=True, repr=False)
    """
    (Store only)

    Indicates whether the method should automatically perform an update if the resource
    conflicts with an existing Synapse object. When True this means that any changes
    to the resource will be non-destructive.

    This boolean is ignored if you've already stored or retrieved the resource from
    Synapse for this instance at least once. Any changes to the resource will be
    destructive in this case. For example if you want to delete the content for a field
    you will need to call `.get()` and then modify the field.
    """

    parent_id: Optional[str] = None
    """The parent ID of the project. In practice projects do not have a parent, but this
    is required for the inner workings of Synapse."""

    _last_persistent_instance: Optional["Project"] = field(
        default=None, repr=False, compare=False
    )
    """The last persistent instance of this object. This is used to determine if the
    object has been changed and needs to be updated in Synapse."""

    @property
    def has_changed(self) -> bool:
        """Determines if the object has been changed and needs to be updated in Synapse."""
        return (
            not self._last_persistent_instance or self._last_persistent_instance != self
        )

    def _set_last_persistent_instance(self) -> None:
        """Stash the last time this object interacted with Synapse. This is used to
        determine if the object has been changed and needs to be updated in Synapse."""
        del self._last_persistent_instance
        self._last_persistent_instance = replace(self)
        self._last_persistent_instance.annotations = (
            deepcopy(self.annotations) if self.annotations else {}
        )

    def fill_from_dict(
        self,
        synapse_project: Union[Synapse_Project, Dict],
        set_annotations: bool = True,
    ) -> "Project":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_project: The response from the REST API.

        Returns:
            The Project object.
        """
        self.id = synapse_project.get("id", None)
        self.name = synapse_project.get("name", None)
        self.description = synapse_project.get("description", None)
        self.etag = synapse_project.get("etag", None)
        self.created_on = synapse_project.get("createdOn", None)
        self.modified_on = synapse_project.get("modifiedOn", None)
        self.created_by = synapse_project.get("createdBy", None)
        self.modified_by = synapse_project.get("modifiedBy", None)
        self.alias = synapse_project.get("alias", None)
        self.parent_id = synapse_project.get("parentId", None)
        if set_annotations:
            self.annotations = Annotations.from_dict(
                synapse_project.get("annotations", {})
            )
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Project_Store: ID: {self.id}, Name: {self.name}"
    )
    async def store_async(
        self,
        failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "Project":
        """
        Store project, files, and folders to synapse. If you have any files or folders
        attached to this project they will be stored as well. You may attach files
        and folders to this project by setting the `files` and `folders` attributes.

        By default the store operation will non-destructively update the project if
        you have not already retrieved the project from Synapse. If you have already
        retrieved the project from Synapse then the store operation will be destructive
        and will overwrite the project with the current state of this object. See the
        `create_or_update` attribute for more information.

        Arguments:
            failure_strategy: Determines how to handle failures when storing attached
                Files and Folders under this Project and an exception occurs.
            synapse_client: If not passed in and caching was not disabled by
                `Synapse.allow_client_caching(False)` this will use the last created
                instance from the Synapse class constructor.

        Returns:
            The project object.

        Example: Using this method to update the description
            Store the project to Synapse using ID

                project = await Project(id="syn123", description="new").store_async()

            Store the project to Synapse using Name

                project = await Project(name="my_project", description="new").store_async()

        Raises:
            ValueError: If the project name is not set.
        """
        if not self.name and not self.id:
            raise ValueError("Project ID or Name is required")

        if (
            self.create_or_update
            and not self._last_persistent_instance
            and (
                existing_project_id := await get_id(
                    entity=self, synapse_client=synapse_client, failure_strategy=None
                )
            )
            and (
                existing_project := await Project(id=existing_project_id).get_async(
                    synapse_client=synapse_client
                )
            )
        ):
            merge_dataclass_entities(source=existing_project, destination=self)
        trace.get_current_span().set_attributes(
            {
                "synapse.name": self.name or "",
                "synapse.id": self.id or "",
            }
        )
        if self.has_changed:
            loop = asyncio.get_event_loop()
            synapse_project = Synapse_Project(
                id=self.id,
                etag=self.etag,
                name=self.name,
                description=self.description,
                alias=self.alias,
                parentId=self.parent_id,
            )
            delete_none_keys(synapse_project)
            entity = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(synapse_client=synapse_client).store(
                    obj=synapse_project,
                    set_annotations=False,
                    createOrUpdate=False,
                ),
            )
            self.fill_from_dict(synapse_project=entity, set_annotations=False)

        await store_entity_components(
            root_resource=self,
            failure_strategy=failure_strategy,
            synapse_client=synapse_client,
        )

        self._set_last_persistent_instance()
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Saved Project {self.name}, id: {self.id}"
        )

        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Project_Get: ID: {self.id}, Name: {self.name}"
    )
    async def get_async(
        self,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "Project":
        """Get the project metadata from Synapse.

        Arguments:
            synapse_client: If not passed in and caching was not disabled by
                `Synapse.allow_client_caching(False)` this will use the last created
                instance from the Synapse class constructor.

        Returns:
            The project object.

        Example: Using this method
            Retrieve the project from Synapse using ID

                project = await Project(id="syn123").get_async()

            Retrieve the project from Synapse using Name

                project = await Project(name="my_project").get_async()

        Raises:
            ValueError: If the project ID or Name is not set.
            SynapseNotFoundError: If the project is not found in Synapse.
        """
        entity_id = await get_id(entity=self, synapse_client=synapse_client)

        await get_from_entity_factory(
            entity_to_update=self,
            synapse_id_or_path=entity_id,
            synapse_client=synapse_client,
        )

        self._set_last_persistent_instance()
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Project_Delete: {self.id}, Name: {self.name}"
    )
    async def delete_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
        """Delete the project from Synapse.

        Arguments:
            synapse_client: If not passed in and caching was not disabled by
                `Synapse.allow_client_caching(False)` this will use the last created
                instance from the Synapse class constructor.

        Returns:
            None

        Example: Using this method
            Delete the project from Synapse using ID

                await Project(id="syn123").delete_async()

            Delete the project from Synapse using Name

                await Project(name="my_project").delete_async()

        Raises:
            ValueError: If the project ID or Name is not set.
            SynapseNotFoundError: If the project is not found in Synapse.
        """
        entity_id = await get_id(entity=self, synapse_client=synapse_client)

        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).delete(
                obj=entity_id,
            ),
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Project_Copy: {self.id}"
    )
    async def copy_async(
        self,
        destination_id: str,
        copy_annotations: bool = True,
        copy_wiki: bool = True,
        exclude_types: Optional[List[str]] = None,
        file_update_existing: bool = False,
        file_copy_activity: Union[str, None] = "traceback",
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "Project":
        """
        You must have already created the Project you will be copying to. It will have
        it's own Synapse ID and unique name that you will use as the destination_id.


        Copy the project to another Synapse project. This will recursively copy all
        Tables, Links, Files, and Folders within the project.

        Arguments:
            destination_id: Synapse ID of a project to copy to.
            copy_annotations: True to copy the annotations.
            copy_wiki: True to copy the wiki pages.
            exclude_types: A list of entity types ['file', 'table', 'link'] which
                determines which entity types to not copy. Defaults to an empty list.
            file_update_existing: When the destination has a file that has the same
                name, users can choose to update that file.
            file_copy_activity: Has three options to set the activity of the copied file:

                    - traceback: Creates a copy of the source files Activity.
                    - existing: Link to the source file's original Activity (if it exists)
                    - None: No activity is set
            synapse_client: If not passed in and caching was not disabled by
                `Synapse.allow_client_caching(False)` this will use the last created
                instance from the Synapse class constructor.

        Returns:
            The copied project object.

        Example: Using this function
            Assuming you have a project with the ID "syn123" and you want to copy it to a
            project with the ID "syn456":

                new_instance = await Project(id="syn123").copy_async(destination_id="syn456")

            Copy the project but do not persist annotations:

                new_instance = await Project(id="syn123").copy_async(destination_id="syn456", copy_annotations=False)

        Raises:
            ValueError: If the project does not have an ID and destination_id to copy.
        """
        if not self.id or not destination_id:
            raise ValueError("The project must have an ID and destination_id to copy.")

        loop = asyncio.get_event_loop()

        syn = Synapse.get_client(synapse_client=synapse_client)
        source_and_destination = await loop.run_in_executor(
            None,
            lambda: copy(
                syn=syn,
                entity=self.id,
                destinationId=destination_id,
                excludeTypes=exclude_types or [],
                skipCopyAnnotations=not copy_annotations,
                skipCopyWikiPage=not copy_wiki,
                updateExisting=file_update_existing,
                setProvenance=file_copy_activity,
            ),
        )

        new_project_id = source_and_destination.get(self.id, None)
        if not new_project_id:
            raise SynapseError("Failed to copy project.")
        project_copy = await (
            await Project(id=new_project_id).get_async(synapse_client=syn)
        ).sync_from_synapse_async(
            download_file=False,
            synapse_client=synapse_client,
        )
        syn.logger.debug(f"Copied from project {self.id} to {destination_id}")
        return project_copy

Functions

get_async async

get_async(*, synapse_client: Optional[Synapse] = None) -> Project

Get the project metadata from Synapse.

PARAMETER DESCRIPTION
synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Project

The project object.

Using this method

Retrieve the project from Synapse using ID

project = await Project(id="syn123").get_async()

Retrieve the project from Synapse using Name

project = await Project(name="my_project").get_async()
RAISES DESCRIPTION
ValueError

If the project ID or Name is not set.

SynapseNotFoundError

If the project is not found in Synapse.

Source code in synapseclient/models/project.py
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
@otel_trace_method(
    method_to_trace_name=lambda self, **kwargs: f"Project_Get: ID: {self.id}, Name: {self.name}"
)
async def get_async(
    self,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "Project":
    """Get the project metadata from Synapse.

    Arguments:
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        The project object.

    Example: Using this method
        Retrieve the project from Synapse using ID

            project = await Project(id="syn123").get_async()

        Retrieve the project from Synapse using Name

            project = await Project(name="my_project").get_async()

    Raises:
        ValueError: If the project ID or Name is not set.
        SynapseNotFoundError: If the project is not found in Synapse.
    """
    entity_id = await get_id(entity=self, synapse_client=synapse_client)

    await get_from_entity_factory(
        entity_to_update=self,
        synapse_id_or_path=entity_id,
        synapse_client=synapse_client,
    )

    self._set_last_persistent_instance()
    return self

store_async async

store_async(failure_strategy: FailureStrategy = LOG_EXCEPTION, *, synapse_client: Optional[Synapse] = None) -> Project

Store project, files, and folders to synapse. If you have any files or folders attached to this project they will be stored as well. You may attach files and folders to this project by setting the files and folders attributes.

By default the store operation will non-destructively update the project if you have not already retrieved the project from Synapse. If you have already retrieved the project from Synapse then the store operation will be destructive and will overwrite the project with the current state of this object. See the create_or_update attribute for more information.

PARAMETER DESCRIPTION
failure_strategy

Determines how to handle failures when storing attached Files and Folders under this Project and an exception occurs.

TYPE: FailureStrategy DEFAULT: LOG_EXCEPTION

synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Project

The project object.

Using this method to update the description

Store the project to Synapse using ID

project = await Project(id="syn123", description="new").store_async()

Store the project to Synapse using Name

project = await Project(name="my_project", description="new").store_async()
RAISES DESCRIPTION
ValueError

If the project name is not set.

Source code in synapseclient/models/project.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
@otel_trace_method(
    method_to_trace_name=lambda self, **kwargs: f"Project_Store: ID: {self.id}, Name: {self.name}"
)
async def store_async(
    self,
    failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "Project":
    """
    Store project, files, and folders to synapse. If you have any files or folders
    attached to this project they will be stored as well. You may attach files
    and folders to this project by setting the `files` and `folders` attributes.

    By default the store operation will non-destructively update the project if
    you have not already retrieved the project from Synapse. If you have already
    retrieved the project from Synapse then the store operation will be destructive
    and will overwrite the project with the current state of this object. See the
    `create_or_update` attribute for more information.

    Arguments:
        failure_strategy: Determines how to handle failures when storing attached
            Files and Folders under this Project and an exception occurs.
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        The project object.

    Example: Using this method to update the description
        Store the project to Synapse using ID

            project = await Project(id="syn123", description="new").store_async()

        Store the project to Synapse using Name

            project = await Project(name="my_project", description="new").store_async()

    Raises:
        ValueError: If the project name is not set.
    """
    if not self.name and not self.id:
        raise ValueError("Project ID or Name is required")

    if (
        self.create_or_update
        and not self._last_persistent_instance
        and (
            existing_project_id := await get_id(
                entity=self, synapse_client=synapse_client, failure_strategy=None
            )
        )
        and (
            existing_project := await Project(id=existing_project_id).get_async(
                synapse_client=synapse_client
            )
        )
    ):
        merge_dataclass_entities(source=existing_project, destination=self)
    trace.get_current_span().set_attributes(
        {
            "synapse.name": self.name or "",
            "synapse.id": self.id or "",
        }
    )
    if self.has_changed:
        loop = asyncio.get_event_loop()
        synapse_project = Synapse_Project(
            id=self.id,
            etag=self.etag,
            name=self.name,
            description=self.description,
            alias=self.alias,
            parentId=self.parent_id,
        )
        delete_none_keys(synapse_project)
        entity = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).store(
                obj=synapse_project,
                set_annotations=False,
                createOrUpdate=False,
            ),
        )
        self.fill_from_dict(synapse_project=entity, set_annotations=False)

    await store_entity_components(
        root_resource=self,
        failure_strategy=failure_strategy,
        synapse_client=synapse_client,
    )

    self._set_last_persistent_instance()
    Synapse.get_client(synapse_client=synapse_client).logger.debug(
        f"Saved Project {self.name}, id: {self.id}"
    )

    return self

delete_async async

delete_async(*, synapse_client: Optional[Synapse] = None) -> None

Delete the project from Synapse.

PARAMETER DESCRIPTION
synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
None

None

Using this method

Delete the project from Synapse using ID

await Project(id="syn123").delete_async()

Delete the project from Synapse using Name

await Project(name="my_project").delete_async()
RAISES DESCRIPTION
ValueError

If the project ID or Name is not set.

SynapseNotFoundError

If the project is not found in Synapse.

Source code in synapseclient/models/project.py
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
@otel_trace_method(
    method_to_trace_name=lambda self, **kwargs: f"Project_Delete: {self.id}, Name: {self.name}"
)
async def delete_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
    """Delete the project from Synapse.

    Arguments:
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        None

    Example: Using this method
        Delete the project from Synapse using ID

            await Project(id="syn123").delete_async()

        Delete the project from Synapse using Name

            await Project(name="my_project").delete_async()

    Raises:
        ValueError: If the project ID or Name is not set.
        SynapseNotFoundError: If the project is not found in Synapse.
    """
    entity_id = await get_id(entity=self, synapse_client=synapse_client)

    loop = asyncio.get_event_loop()
    await loop.run_in_executor(
        None,
        lambda: Synapse.get_client(synapse_client=synapse_client).delete(
            obj=entity_id,
        ),
    )

sync_from_synapse_async async

sync_from_synapse_async(path: Optional[str] = None, recursive: bool = True, download_file: bool = True, if_collision: str = COLLISION_OVERWRITE_LOCAL, failure_strategy: FailureStrategy = LOG_EXCEPTION, include_activity: bool = True, follow_link: bool = False, link_hops: int = 1, queue: Queue = None, *, synapse_client: Optional[Synapse] = None) -> Self

Sync this container and all possible sub-folders from Synapse. By default this will download the files that are found and it will populate the files and folders attributes with the found files and folders. If you only want to retrieve the full tree of metadata about your container specify download_file as False.

This works similar to synapseutils.syncFromSynapse, however, this does not currently support the writing of data to a manifest TSV file. This will be a future enhancement.

Only Files and Folders are supported at this time to be synced from synapse.

PARAMETER DESCRIPTION
path

An optional path where the file hierarchy will be reproduced. If not specified the files will by default be placed in the synapseCache.

TYPE: Optional[str] DEFAULT: None

recursive

Whether or not to recursively get the entire hierarchy of the folder and sub-folders.

TYPE: bool DEFAULT: True

download_file

Whether to download the files found or not.

TYPE: bool DEFAULT: True

if_collision

Determines how to handle file collisions. May be

  • overwrite.local
  • keep.local
  • keep.both

TYPE: str DEFAULT: COLLISION_OVERWRITE_LOCAL

failure_strategy

Determines how to handle failures when retrieving children under this Folder and an exception occurs.

TYPE: FailureStrategy DEFAULT: LOG_EXCEPTION

include_activity

Whether to include the activity of the files.

TYPE: bool DEFAULT: True

follow_link

Whether to follow a link entity or not. Links can be used to point at other Synapse entities.

TYPE: bool DEFAULT: False

link_hops

The number of hops to follow the link. A number of 1 is used to prevent circular references. There is nothing in place to prevent infinite loops. Be careful if setting this above 1.

TYPE: int DEFAULT: 1

queue

An optional queue to use to download files in parallel.

TYPE: Queue DEFAULT: None

synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Self

The object that was called on. This will be the same object that was called on to start the sync.

Using this function

Suppose I want to walk the immediate children of a folder without downloading the files:

from synapseclient import Synapse
from synapseclient.models import Folder

syn = Synapse()
syn.login()

my_folder = Folder(id="syn12345")
await my_folder.sync_from_synapse_async(download_file=False, recursive=False)

for folder in my_folder.folders:
    print(folder.name)

for file in my_folder.files:
    print(file.name)

Suppose I want to download the immediate children of a folder:

from synapseclient import Synapse
from synapseclient.models import Folder

syn = Synapse()
syn.login()

my_folder = Folder(id="syn12345")
await my_folder.sync_from_synapse_async(path="/path/to/folder", recursive=False)

for folder in my_folder.folders:
    print(folder.name)

for file in my_folder.files:
    print(file.name)

Suppose I want to download the immediate all children of a Project and all sub-folders and files:

from synapseclient import Synapse
from synapseclient.models import Project

syn = Synapse()
syn.login()

my_project = Project(id="syn12345")
await my_project.sync_from_synapse_async(path="/path/to/folder")
RAISES DESCRIPTION
ValueError

If the folder does not have an id set.

A sequence diagram for this method is as follows:

sequenceDiagram
    autonumber
    participant project_or_folder
    activate project_or_folder
    project_or_folder->>sync_from_synapse: Recursive search and download files
    activate sync_from_synapse
        opt Current instance not retrieved from Synapse
            sync_from_synapse->>project_or_folder: Call `.get()` method
            project_or_folder-->>sync_from_synapse: .
        end

        loop For each return of the generator
            sync_from_synapse->>client: call `.getChildren()` method
            client-->>sync_from_synapse: .
            note over sync_from_synapse: Append to a running list
        end

        loop For each child
            note over sync_from_synapse: Create all `pending_tasks` at current depth

            alt Child is File
                note over sync_from_synapse: Append `file.get()` method
            else Child is Folder
                note over sync_from_synapse: Append `folder.get()` method
                alt Recursive is True
                    note over sync_from_synapse: Append `folder.sync_from_synapse()` method
                end
            else Child is Link and hops > 0
                note over sync_from_synapse: Append task to follow link
            end
        end

        loop For each task in pending_tasks
            par `file.get()`
                sync_from_synapse->>File: Retrieve File metadata and Optionally download
                File->>client: `.get()`
                client-->>File: .
                File-->>sync_from_synapse: .
            and `folder.get()`
                sync_from_synapse->>Folder: Retrieve Folder metadataa
                Folder->>client: `.get()`
                client-->>Folder: .
                Folder-->>sync_from_synapse: .
            and `folder.sync_from_synapse_async()`
                note over sync_from_synapse: This is a recursive call to `sync_from_synapse`
                sync_from_synapse->>sync_from_synapse: Recursive call to `.sync_from_synapse_async()`
            and `_follow_link`
                sync_from_synapse ->>client: call `get_entity_id_bundle2` function
                client-->sync_from_synapse: .
                note over sync_from_synapse: Do nothing if not link
                note over sync_from_synapse: call `_create_task_for_child` and execute
            end
        end

    deactivate sync_from_synapse
    deactivate project_or_folder
Source code in synapseclient/models/mixins/storable_container.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
@otel_trace_method(
    method_to_trace_name=lambda self, **kwargs: f"{self.__class__.__name__}_sync_from_synapse: {self.id}"
)
async def sync_from_synapse_async(
    self: Self,
    path: Optional[str] = None,
    recursive: bool = True,
    download_file: bool = True,
    if_collision: str = COLLISION_OVERWRITE_LOCAL,
    failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
    include_activity: bool = True,
    follow_link: bool = False,
    link_hops: int = 1,
    queue: asyncio.Queue = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> Self:
    """
    Sync this container and all possible sub-folders from Synapse. By default this
    will download the files that are found and it will populate the
    `files` and `folders` attributes with the found files and folders. If you only
    want to retrieve the full tree of metadata about your container specify
    `download_file` as False.

    This works similar to [synapseutils.syncFromSynapse][], however, this does not
    currently support the writing of data to a manifest TSV file. This will be a
    future enhancement.

    Only Files and Folders are supported at this time to be synced from synapse.

    Arguments:
        path: An optional path where the file hierarchy will be reproduced. If not
            specified the files will by default be placed in the synapseCache.
        recursive: Whether or not to recursively get the entire hierarchy of the
            folder and sub-folders.
        download_file: Whether to download the files found or not.
        if_collision: Determines how to handle file collisions. May be

            - `overwrite.local`
            - `keep.local`
            - `keep.both`
        failure_strategy: Determines how to handle failures when retrieving children
            under this Folder and an exception occurs.
        include_activity: Whether to include the activity of the files.
        follow_link: Whether to follow a link entity or not. Links can be used to
            point at other Synapse entities.
        link_hops: The number of hops to follow the link. A number of 1 is used to
            prevent circular references. There is nothing in place to prevent
            infinite loops. Be careful if setting this above 1.
        queue: An optional queue to use to download files in parallel.
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        The object that was called on. This will be the same object that was called on
            to start the sync.

    Example: Using this function
        Suppose I want to walk the immediate children of a folder without downloading the files:

            from synapseclient import Synapse
            from synapseclient.models import Folder

            syn = Synapse()
            syn.login()

            my_folder = Folder(id="syn12345")
            await my_folder.sync_from_synapse_async(download_file=False, recursive=False)

            for folder in my_folder.folders:
                print(folder.name)

            for file in my_folder.files:
                print(file.name)

        Suppose I want to download the immediate children of a folder:

            from synapseclient import Synapse
            from synapseclient.models import Folder

            syn = Synapse()
            syn.login()

            my_folder = Folder(id="syn12345")
            await my_folder.sync_from_synapse_async(path="/path/to/folder", recursive=False)

            for folder in my_folder.folders:
                print(folder.name)

            for file in my_folder.files:
                print(file.name)


        Suppose I want to download the immediate all children of a Project and all sub-folders and files:

            from synapseclient import Synapse
            from synapseclient.models import Project

            syn = Synapse()
            syn.login()

            my_project = Project(id="syn12345")
            await my_project.sync_from_synapse_async(path="/path/to/folder")


    Raises:
        ValueError: If the folder does not have an id set.


    A sequence diagram for this method is as follows:

    ```mermaid
    sequenceDiagram
        autonumber
        participant project_or_folder
        activate project_or_folder
        project_or_folder->>sync_from_synapse: Recursive search and download files
        activate sync_from_synapse
            opt Current instance not retrieved from Synapse
                sync_from_synapse->>project_or_folder: Call `.get()` method
                project_or_folder-->>sync_from_synapse: .
            end

            loop For each return of the generator
                sync_from_synapse->>client: call `.getChildren()` method
                client-->>sync_from_synapse: .
                note over sync_from_synapse: Append to a running list
            end

            loop For each child
                note over sync_from_synapse: Create all `pending_tasks` at current depth

                alt Child is File
                    note over sync_from_synapse: Append `file.get()` method
                else Child is Folder
                    note over sync_from_synapse: Append `folder.get()` method
                    alt Recursive is True
                        note over sync_from_synapse: Append `folder.sync_from_synapse()` method
                    end
                else Child is Link and hops > 0
                    note over sync_from_synapse: Append task to follow link
                end
            end

            loop For each task in pending_tasks
                par `file.get()`
                    sync_from_synapse->>File: Retrieve File metadata and Optionally download
                    File->>client: `.get()`
                    client-->>File: .
                    File-->>sync_from_synapse: .
                and `folder.get()`
                    sync_from_synapse->>Folder: Retrieve Folder metadataa
                    Folder->>client: `.get()`
                    client-->>Folder: .
                    Folder-->>sync_from_synapse: .
                and `folder.sync_from_synapse_async()`
                    note over sync_from_synapse: This is a recursive call to `sync_from_synapse`
                    sync_from_synapse->>sync_from_synapse: Recursive call to `.sync_from_synapse_async()`
                and `_follow_link`
                    sync_from_synapse ->>client: call `get_entity_id_bundle2` function
                    client-->sync_from_synapse: .
                    note over sync_from_synapse: Do nothing if not link
                    note over sync_from_synapse: call `_create_task_for_child` and execute
                end
            end

        deactivate sync_from_synapse
        deactivate project_or_folder
    ```

    """
    syn = Synapse.get_client(synapse_client=synapse_client)
    custom_message = "Syncing from Synapse" if not download_file else None
    with shared_download_progress_bar(
        file_size=1, synapse_client=syn, custom_message=custom_message
    ):
        return await self._sync_from_synapse_async(
            path=path,
            recursive=recursive,
            download_file=download_file,
            if_collision=if_collision,
            failure_strategy=failure_strategy,
            include_activity=include_activity,
            follow_link=follow_link,
            link_hops=link_hops,
            queue=queue,
            synapse_client=syn,
        )

get_permissions_async async

get_permissions_async(*, synapse_client: Optional[Synapse] = None) -> Permissions

Get the permissions that the caller has on an Entity.

PARAMETER DESCRIPTION
synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Permissions

A Permissions object

Using this function:

Getting permissions for a Synapse Entity

permissions = await File(id="syn123").get_permissions_async()

Getting access types list from the Permissions object

permissions.access_types
Source code in synapseclient/models/mixins/access_control.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
async def get_permissions_async(
    self,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "Permissions":
    """
    Get the [permissions][synapseclient.core.models.permission.Permissions]
    that the caller has on an Entity.

    Arguments:
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        A Permissions object


    Example: Using this function:
        Getting permissions for a Synapse Entity

            permissions = await File(id="syn123").get_permissions_async()

        Getting access types list from the Permissions object

            permissions.access_types
    """
    loop = asyncio.get_event_loop()

    return await loop.run_in_executor(
        None,
        lambda: Synapse.get_client(synapse_client=synapse_client).get_permissions(
            entity=self.id
        ),
    )

get_acl_async async

get_acl_async(principal_id: int = None, *, synapse_client: Optional[Synapse] = None) -> List[str]

Get the ACL that a user or group has on an Entity.

PARAMETER DESCRIPTION
principal_id

Identifier of a user or group (defaults to PUBLIC users)

TYPE: int DEFAULT: None

synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
List[str]

An array containing some combination of ['READ', 'UPDATE', 'CREATE', 'DELETE', 'DOWNLOAD', 'MODERATE', 'CHANGE_PERMISSIONS', 'CHANGE_SETTINGS'] or an empty array

Source code in synapseclient/models/mixins/access_control.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
async def get_acl_async(
    self, principal_id: int = None, *, synapse_client: Optional[Synapse] = None
) -> List[str]:
    """
    Get the [ACL][synapseclient.core.models.permission.Permissions.access_types]
    that a user or group has on an Entity.

    Arguments:
        principal_id: Identifier of a user or group (defaults to PUBLIC users)
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        An array containing some combination of
            ['READ', 'UPDATE', 'CREATE', 'DELETE', 'DOWNLOAD', 'MODERATE',
            'CHANGE_PERMISSIONS', 'CHANGE_SETTINGS']
            or an empty array
    """
    loop = asyncio.get_event_loop()

    return await loop.run_in_executor(
        None,
        lambda: Synapse.get_client(synapse_client=synapse_client).get_acl(
            entity=self.id, principal_id=principal_id
        ),
    )

set_permissions_async async

set_permissions_async(principal_id: int = None, access_type: List[str] = None, modify_benefactor: bool = False, warn_if_inherits: bool = True, overwrite: bool = True, *, synapse_client: Optional[Synapse] = None) -> Dict[str, Union[str, list]]

Sets permission that a user or group has on an Entity. An Entity may have its own ACL or inherit its ACL from a benefactor.

PARAMETER DESCRIPTION
principal_id

Identifier of a user or group. 273948 is for all registered Synapse users and 273949 is for public access. None implies public access.

TYPE: int DEFAULT: None

access_type

Type of permission to be granted. One or more of CREATE, READ, DOWNLOAD, UPDATE, DELETE, CHANGE_PERMISSIONS.

Defaults to ['READ', 'DOWNLOAD']

TYPE: List[str] DEFAULT: None

modify_benefactor

Set as True when modifying a benefactor's ACL

TYPE: bool DEFAULT: False

warn_if_inherits

Set as False, when creating a new ACL. Trying to modify the ACL of an Entity that inherits its ACL will result in a warning

TYPE: bool DEFAULT: True

overwrite

By default this function overwrites existing permissions for the specified user. Set this flag to False to add new permissions non-destructively.

TYPE: bool DEFAULT: True

synapse_client

If not passed in and caching was not disabled by Synapse.allow_client_caching(False) this will use the last created instance from the Synapse class constructor.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Union[str, list]]

An Access Control List object

Setting permissions

Grant all registered users download access

await File(id="syn123").set_permissions_async(principal_id=273948, access_type=['READ','DOWNLOAD'])

Grant the public view access

await File(id="syn123").set_permissions_async(principal_id=273949, access_type=['READ'])
Source code in synapseclient/models/mixins/access_control.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
async def set_permissions_async(
    self,
    principal_id: int = None,
    access_type: List[str] = None,
    modify_benefactor: bool = False,
    warn_if_inherits: bool = True,
    overwrite: bool = True,
    *,
    synapse_client: Optional[Synapse] = None,
) -> Dict[str, Union[str, list]]:
    """
    Sets permission that a user or group has on an Entity.
    An Entity may have its own ACL or inherit its ACL from a benefactor.

    Arguments:
        principal_id: Identifier of a user or group. `273948` is for all
            registered Synapse users and `273949` is for public access.
            None implies public access.
        access_type: Type of permission to be granted. One or more of CREATE,
            READ, DOWNLOAD, UPDATE, DELETE, CHANGE_PERMISSIONS.

            **Defaults to ['READ', 'DOWNLOAD']**
        modify_benefactor: Set as True when modifying a benefactor's ACL
        warn_if_inherits: Set as False, when creating a new ACL. Trying to modify
            the ACL of an Entity that inherits its ACL will result in a warning
        overwrite: By default this function overwrites existing permissions for
            the specified user. Set this flag to False to add new permissions
            non-destructively.
        synapse_client: If not passed in and caching was not disabled by
            `Synapse.allow_client_caching(False)` this will use the last created
            instance from the Synapse class constructor.

    Returns:
        An Access Control List object

    Example: Setting permissions
        Grant all registered users download access

            await File(id="syn123").set_permissions_async(principal_id=273948, access_type=['READ','DOWNLOAD'])

        Grant the public view access

            await File(id="syn123").set_permissions_async(principal_id=273949, access_type=['READ'])
    """
    if access_type is None:
        access_type = ["READ", "DOWNLOAD"]
    loop = asyncio.get_event_loop()

    return await loop.run_in_executor(
        None,
        lambda: Synapse.get_client(synapse_client=synapse_client).setPermissions(
            entity=self.id,
            principalId=principal_id,
            accessType=access_type,
            modify_benefactor=modify_benefactor,
            warn_if_inherits=warn_if_inherits,
            overwrite=overwrite,
        ),
    )