Skip to content

Object-Orientated Models

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.

Sample Scripts:

Working with a project
"""
Expects that ~/temp exists and is a directory.

The purpose of this script is to demonstrate how to use the new OOP interface for projects.
The following actions are shown in this script:
1. Creating a project
2. Retrieving a project by id or name
3. Upserting data on a project
4. Storing several files to a project
5. Storing several folders in a project
6. Updating the annotations in bulk for a number of folders and files
7. Downloading an entire project structure to disk
8. Copy a project and all content to a new project
9. Deleting a project
"""

import os
import uuid
from datetime import date, datetime, timedelta, timezone

import synapseclient
from synapseclient.models import File, Folder, Project

syn = synapseclient.Synapse(debug=True)
syn.login()


def create_random_file(
    path: str,
) -> None:
    """Create a random file with random data."""
    with open(path, "wb") as f:
        f.write(os.urandom(1))


def store_project():
    # Creating annotations for my project ==================================================
    my_annotations = {
        "my_single_key_string": "a",
        "my_key_string": ["b", "a", "c"],
        "my_key_bool": [False, False, False],
        "my_key_double": [1.2, 3.4, 5.6],
        "my_key_long": [1, 2, 3],
        "my_key_date": [date.today(), date.today() - timedelta(days=1)],
        "my_key_datetime": [
            datetime.today(),
            datetime.today() - timedelta(days=1),
            datetime.now(tz=timezone(timedelta(hours=-5))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=0))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=-7))),
        ],
        "annotation_i_want_to_delete": "I want to delete this annotation",
    }

    # 1) Creating a project ==============================================================
    project = Project(
        name="my_new_project_for_testing",
        annotations=my_annotations,
        description="This is a project with random data.",
        alias="my_project_alias_" + str(uuid.uuid4()).replace("-", "_"),
    )

    project = project.store()

    print(f"Project created with id: {project.id}")

    # 2) Retrieving a project by id or name ==============================================
    project = Project(name="my_new_project_for_testing").get()
    print(f"Project retrieved by name: {project.name} with id: {project.id}")

    project = Project(id=project.id).get()
    print(f"Project retrieved by id: {project.name} with id: {project.id}")

    # 3) Upserting data on a project =====================================================
    # When you have not already use `.store()` or `.get()` on a project any updates will
    # be a non-destructive upsert. This means that if the project does not exist it will
    # be created, if it does exist it will be updated.
    project = Project(
        name="my_new_project_for_testing", description="my new description"
    ).store()
    print(f"Project description updated to {project.description}")

    # After the instance has interacted with Synapse any changes will be destructive,
    # meaning changes in the data will act as a replacement instead of an addition.
    print(f"Annotations before update: {project.annotations}")
    del project.annotations["annotation_i_want_to_delete"]
    project = project.store()
    print(f"Annotations after update: {project.annotations}")

    # 4) Storing several files to a project ==============================================
    files_to_store = []
    for loop in range(1, 10):
        name_of_file = f"my_file_with_random_data_{loop}.txt"
        path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
        create_random_file(path_to_file)

        file = File(
            path=path_to_file,
            name=name_of_file,
            annotations=my_annotations,
        )
        files_to_store.append(file)
    project.files = files_to_store
    project = project.store()

    # 5) Storing several folders in a project ============================================
    folders_to_store = []
    for loop in range(1, 10):
        folder_to_store = Folder(
            name=f"my_folder_for_this_project_{loop}",
            annotations=my_annotations,
        )
        folders_to_store.append(folder_to_store)
    project.folders = folders_to_store
    print(
        f"Storing project ({project.id}) with {len(project.folders)} folders and {len(project.files)} files"
    )
    project = project.store()

    # 6) Updating the annotations in bulk for a number of folders and files ==============
    project_copy = Project(id=project.id).sync_from_synapse(download_file=False)

    print(
        f"Found {len(project_copy.files)} files and {len(project_copy.folders)} folder at the root level for {project_copy.name} with id: {project_copy.id}"
    )

    new_annotations = {
        "my_new_key_string": ["b", "a", "c"],
    }

    for file in project_copy.files:
        file.annotations = new_annotations

    for folder in project_copy.folders:
        folder.annotations = new_annotations

    project_copy.store()

    # 7) Downloading an entire project structure to disk =================================
    print(f"Downloading project ({project.id}) to ~/temp")
    Project(id=project.id).sync_from_synapse(
        download_file=True, path="~/temp/recursiveDownload", recursive=True
    )

    # 8) Copy a project and all content to a new project =================================
    project_to_delete = Project(
        name="my_new_project_I_want_to_delete_" + str(uuid.uuid4()).replace("-", "_"),
    ).store()
    print(f"Project created with id: {project_to_delete.id}")

    project_to_delete = project.copy(destination_id=project_to_delete.id)
    print(
        f"Copied to new project, copied {len(project_to_delete.folders)} folders and {len(project_to_delete.files)} files"
    )

    # 9) Deleting a project ==============================================================
    project_to_delete.delete()
    print(f"Project with id: {project_to_delete.id} deleted")


store_project()
Working with folders
"""
Expects that ~/temp exists and is a directory.

The purpose of this script is to demonstrate how to use the new OOP interface for folders.
The following actions are shown in this script:
1. Creating a folder
2. Storing a folder to a project
3. Storing several files to a folder
4. Storing several folders in a folder
5. Getting metadata about a folder and it's immediate children
6. Updating the annotations in bulk for a number of folders and files
7. Deleting a folder
8. Copying a folder
9. Moving a folder
10. Using sync_from_synapse to download the files and folders
"""

import os
from datetime import date, datetime, timedelta, timezone

import synapseclient
from synapseclient.models import File, Folder

PROJECT_ID = "syn52948289"

syn = synapseclient.Synapse(debug=True)
syn.login()


def create_random_file(
    path: str,
) -> None:
    """Create a random file with random data.

    :param path: The path to create the file at.
    """
    with open(path, "wb") as f:
        f.write(os.urandom(1))


def try_delete_folder(folder_name: str, parent_id: str) -> None:
    """Simple try catch to delete a folder."""
    try:
        Folder(name=folder_name, parent_id=parent_id).get().delete()
    except Exception:
        pass


def store_folder():
    # Clean up synapse for previous runs:
    try_delete_folder("my_new_folder_for_this_project", PROJECT_ID)
    try_delete_folder("destination_for_copy", PROJECT_ID)
    try_delete_folder("my_new_folder_for_this_project_I_want_to_delete", PROJECT_ID)

    # Creating annotations for my folder ==================================================
    annotations_for_my_folder = {
        "my_single_key_string": "a",
        "my_key_string": ["b", "a", "c"],
        "my_key_bool": [False, False, False],
        "my_key_double": [1.2, 3.4, 5.6],
        "my_key_long": [1, 2, 3],
        "my_key_date": [date.today(), date.today() - timedelta(days=1)],
        "my_key_datetime": [
            datetime.today(),
            datetime.today() - timedelta(days=1),
            datetime.now(tz=timezone(timedelta(hours=-5))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=0))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=-7))),
        ],
    }

    # 1) Creating a folder ===============================================================
    root_folder_for_my_project = Folder(
        name="my_new_folder_for_this_project",
        annotations=annotations_for_my_folder,
        parent_id=PROJECT_ID,
        description="This is a folder with random data.",
    )

    root_folder_for_my_project = root_folder_for_my_project.store()

    print(
        f"Folder created: {root_folder_for_my_project.name} with id: {root_folder_for_my_project.id}"
    )

    # 2) Updating and storing an annotation ==============================================
    new_folder_instance = Folder(id=root_folder_for_my_project.id).get()
    new_folder_instance.annotations["my_key_string"] = ["new", "values", "here"]
    stored_folder = new_folder_instance.store()
    print(f"Folder {stored_folder.name} updated with new annotations:")
    print(stored_folder.annotations)

    # 3) Storing several files to a folder ===============================================
    files_to_store = []
    for loop in range(1, 10):
        name_of_file = f"my_file_with_random_data_{loop}.txt"
        path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
        create_random_file(path_to_file)

        file = File(
            path=path_to_file,
            name=name_of_file,
        )
        files_to_store.append(file)
    root_folder_for_my_project.files = files_to_store
    root_folder_for_my_project = root_folder_for_my_project.store()

    # 4) Storing several folders in a folder =============================================
    folders_to_store = []
    for loop in range(1, 10):
        folder_to_store = Folder(
            name=f"my_new_folder_for_this_project_{loop}",
        )
        folders_to_store.append(folder_to_store)
    root_folder_for_my_project.folders = folders_to_store
    root_folder_for_my_project = root_folder_for_my_project.store()

    # 5) Getting metadata about a folder and it's immediate children =====================
    new_folder_instance = Folder(id=root_folder_for_my_project.id).sync_from_synapse(
        download_file=False, recursive=False
    )

    print(f"Synced folder {new_folder_instance.name} from synapse")
    for file in new_folder_instance.files:
        print(f"Found File in Synapse at: {new_folder_instance.name}/{file.name}")

    for folder in new_folder_instance.folders:
        print(f"Found Folder in Synapse at: {new_folder_instance.name}/{folder.name}")

    # 6) Updating the annotations in bulk for a number of folders and files ==============
    new_annotations = {
        "my_new_key_string": ["b", "a", "c"],
    }

    for file in new_folder_instance.files:
        file.annotations = new_annotations

    for folder in new_folder_instance.folders:
        folder.annotations = new_annotations

    new_folder_instance.store()

    # 7) Deleting a folder ===============================================================
    folder_to_delete = Folder(
        name="my_new_folder_for_this_project_I_want_to_delete",
        parent_id=PROJECT_ID,
    ).store()

    folder_to_delete.delete()

    # 8) Copying a folder ===============================================================
    destination_folder_to_copy_to = Folder(
        name="destination_for_copy", parent_id=PROJECT_ID
    ).store()
    coped_folder = root_folder_for_my_project.copy(
        parent_id=destination_folder_to_copy_to.id
    )

    print(
        f"Copied folder from {root_folder_for_my_project.id} to {coped_folder.id} in synapse"
    )

    # You'll also see all the files/folders were copied too
    for file in coped_folder.files:
        print(f"Found (copied) File in Synapse at: {coped_folder.name}/{file.name}")

    for folder in coped_folder.folders:
        print(f"Found (copied) Folder in Synapse at: {coped_folder.name}/{folder.name}")

    # 9) Moving a folder ===============================================================
    folder_i_am_going_to_move = Folder(
        name="folder_i_am_going_to_move", parent_id=PROJECT_ID
    ).store()
    current_parent_id = folder_i_am_going_to_move.parent_id
    folder_i_am_going_to_move.parent_id = destination_folder_to_copy_to.id
    folder_i_am_going_to_move.store()
    print(
        f"Moved folder from {current_parent_id} to {folder_i_am_going_to_move.parent_id}"
    )

    # 10) Using sync_from_synapse to download the files and folders ======================
    # This will download all the files and folders in the folder to the local file system
    path_to_download = os.path.expanduser("~/temp/recursiveDownload")
    if not os.path.exists(path_to_download):
        os.mkdir(path_to_download)
    root_folder_for_my_project.sync_from_synapse(path=path_to_download)


store_folder()
Working with files
"""
Expects that ~/temp exists and is a directory.

The purpose of this script is to demonstrate how to use the new OOP interface for files.
The following actions are shown in this script:
1. Creating a file
2. Storing a file
3. Storing a file in a sub-folder
4. Renaming a file
5. Downloading a file
6. Deleting a file
7. Copying a file
8. Storing an activity to a file
9. Retrieve an activity from a file
"""

import os
from datetime import date, datetime, timedelta, timezone

import synapseclient
from synapseclient.core import utils
from synapseclient.models import Activity, File, Folder, UsedEntity, UsedURL

PROJECT_ID = "syn52948289"

syn = synapseclient.Synapse(debug=True)
syn.login()


def create_random_file(
    path: str,
) -> None:
    """Create a random file with random data.

    :param path: The path to create the file at.
    """
    with open(path, "wb") as f:
        f.write(os.urandom(1))


def store_file():
    # Cleanup synapse for previous runs - Does not delete local files/directories:
    try:
        Folder(name="file_script_folder", parent_id=PROJECT_ID).get().delete()
    except Exception:
        pass
    if not os.path.exists(os.path.expanduser("~/temp/myNewFolder")):
        os.mkdir(os.path.expanduser("~/temp/myNewFolder"))

    script_file_folder = Folder(name="file_script_folder", parent_id=PROJECT_ID).store()

    # Creating annotations for my file ==================================================
    annotations_for_my_file = {
        "my_single_key_string": "a",
        "my_key_string": ["b", "a", "c"],
        "my_key_bool": [False, False, False],
        "my_key_double": [1.2, 3.4, 5.6],
        "my_key_long": [1, 2, 3],
        "my_key_date": [date.today(), date.today() - timedelta(days=1)],
        "my_key_datetime": [
            datetime.today(),
            datetime.today() - timedelta(days=1),
            datetime.now(tz=timezone(timedelta(hours=-5))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=0))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=-7))),
        ],
    }

    name_of_file = "file_script_my_file_with_random_data.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # 1. Creating a file =================================================================
    file = File(
        path=path_to_file,
        annotations=annotations_for_my_file,
        parent_id=script_file_folder.id,
        description="This is a file with random data.",
    )

    # 2. Storing a file ==================================================================
    file = file.store()

    print(f"File created: ID: {file.id}, Parent ID: {file.parent_id}")

    name_of_file = "file_in_a_sub_folder.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # 3. Storing a file to a sub-folder ==================================================
    script_sub_folder = Folder(
        name="file_script_sub_folder", parent_id=script_file_folder.id
    ).store()
    file_in_a_sub_folder = File(
        path=path_to_file,
        annotations=annotations_for_my_file,
        parent_id=script_sub_folder.id,
        description="This is a file with random data.",
    )
    file_in_a_sub_folder = file_in_a_sub_folder.store()

    print(
        f"File created in sub folder: ID: {file_in_a_sub_folder.id}, Parent ID: {file_in_a_sub_folder.parent_id}"
    )

    # 4. Renaming a file =================================================================
    name_of_file = "file_script_my_file_to_rename.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # The name of the entity, and the name of the file is disjointed.
    # For example, the name of the file is "file_script_my_file_to_rename.txt"
    # and the name of the entity is "this_name_is_different"
    file: File = File(
        path=path_to_file,
        name="this_name_is_different",
        parent_id=script_file_folder.id,
    ).store()
    print(f"File created with name: {file.name}")
    print(f"The path of the file is: {file.path}")

    # You can change the name of the entity without changing the name of the file.
    file.name = "modified_name_attribute"
    file.store()
    print(f"File renamed to: {file.name}")

    # You can then change the name of the file that would be downloaded like:
    file.change_metadata(download_as="new_name_for_downloading.txt")
    print(f"File download values changed to: {file.file_handle.file_name}")

    # 5. Downloading a file ===============================================================
    # Downloading a file to a location has a default beahvior of "keep.both"
    downloaded_file = File(
        id=file.id, path=os.path.expanduser("~/temp/myNewFolder")
    ).get()
    print(f"Downloaded file: {downloaded_file.path}")

    # I can also specify how collisions are handled when downloading a file.
    # This will replace the file on disk if it already exists and is different (after).
    path_to_file = downloaded_file.path
    create_random_file(path_to_file)
    print(f"Before file md5: {utils.md5_for_file(path_to_file).hexdigest()}")
    downloaded_file = File(
        id=downloaded_file.id,
        path=os.path.expanduser("~/temp/myNewFolder"),
        if_collision="overwrite.local",
    ).get()
    print(f"After file md5: {utils.md5_for_file(path_to_file).hexdigest()}")

    # This will keep the file on disk (before), and no file is downloaded
    path_to_file = downloaded_file.path
    create_random_file(path_to_file)
    print(f"Before file md5: {utils.md5_for_file(path_to_file).hexdigest()}")
    downloaded_file = File(
        id=downloaded_file.id,
        path=os.path.expanduser("~/temp/myNewFolder"),
        if_collision="keep.local",
    ).get()
    print(f"After file md5: {utils.md5_for_file(path_to_file).hexdigest()}")

    # 6. Deleting a file =================================================================
    # Suppose I have a file that I want to delete.
    name_of_file = "file_to_delete.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)
    file_to_delete = File(path=path_to_file, parent_id=script_file_folder.id).store()
    file_to_delete.delete()

    # 7. Copying a file ===================================================================
    print(
        f"File I am going to copy: ID: {file_in_a_sub_folder.id}, Parent ID: {file_in_a_sub_folder.parent_id}"
    )
    new_sub_folder = Folder(
        name="sub_sub_folder", parent_id=script_file_folder.id
    ).store()
    copied_file_instance = file_in_a_sub_folder.copy(parent_id=new_sub_folder.id)
    print(
        f"File I copied: ID: {copied_file_instance.id}, Parent ID: {copied_file_instance.parent_id}"
    )

    # 8. Storing an activity to a file =====================================================
    activity = Activity(
        name="some_name",
        description="some_description",
        used=[
            UsedURL(name="example", url="https://www.synapse.org/"),
            UsedEntity(target_id="syn456", target_version_number=1),
        ],
        executed=[
            UsedURL(name="example", url="https://www.synapse.org/"),
            UsedEntity(target_id="syn789", target_version_number=1),
        ],
    )

    name_of_file = "file_with_an_activity.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)
    file_with_activity = File(
        path=path_to_file, parent_id=script_file_folder.id, activity=activity
    ).store()
    print(file_with_activity.activity)

    # 9. When I am retrieving that file later on I can get the activity like =============
    # By also specifying download_file=False, I can get the activity without downloading the file.
    new_file_with_activity_instance = File(
        id=file_with_activity.id, download_file=False
    ).get(include_activity=True)
    print(new_file_with_activity_instance.activity)


store_file()
Working with tables
"""The purpose of this script is to demonstrate how to use the new OOP interface for tables.
The following actions are shown in this script:
1. Creating a table
2. Storing a table
3. Getting a table
4. Storing rows in a table
5. Querying for data from a table
6. Deleting a row from a table
7. Deleting a table
"""

import csv
import os
import random
import string
from datetime import date, datetime, timedelta, timezone

import synapseclient
from synapseclient.models import Column, ColumnType, CsvResultFormat, Row, Table

PROJECT_ID = "syn52948289"

syn = synapseclient.Synapse(debug=True)
syn.login()


def write_random_csv_with_data(path: str):
    randomized_data_columns = {
        "my_string_column": str,
        "my_integer_column": int,
        "my_double_column": float,
        "my_boolean_column": bool,
    }

    # Generate randomized data
    data = {}
    for name, type in randomized_data_columns.items():
        if type == int:
            data[name] = [random.randint(0, 100) for _ in range(10)]
        elif type == float:
            data[name] = [random.uniform(0, 100) for _ in range(10)]
        elif type == bool:
            data[name] = [bool(random.getrandbits(1)) for _ in range(10)]
        elif type == str:
            data[name] = [
                "".join(random.choices(string.ascii_uppercase + string.digits, k=5))
                for _ in range(10)
            ]

    with open(path, "w", newline="", encoding="utf-8") as csvfile:
        writer = csv.writer(csvfile)

        # Write column names
        writer.writerow(data.keys())

        # Write data
        for i in range(10):
            writer.writerow([values[i] for values in data.values()])


def store_table():
    # Creating annotations for my table ==================================================
    annotations_for_my_table = {
        "my_single_key_string": "a",
        "my_key_string": ["b", "a", "c"],
        "my_key_bool": [False, False, False],
        "my_key_double": [1.2, 3.4, 5.6],
        "my_key_long": [1, 2, 3],
        "my_key_date": [date.today(), date.today() - timedelta(days=1)],
        "my_key_datetime": [
            datetime.today(),
            datetime.today() - timedelta(days=1),
            datetime.now(tz=timezone(timedelta(hours=-5))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=0))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=-7))),
        ],
    }

    # Creating columns for my table ======================================================
    columns = [
        Column(id=None, name="my_string_column", column_type=ColumnType.STRING),
        Column(id=None, name="my_integer_column", column_type=ColumnType.INTEGER),
        Column(id=None, name="my_double_column", column_type=ColumnType.DOUBLE),
        Column(id=None, name="my_boolean_column", column_type=ColumnType.BOOLEAN),
    ]

    # Creating a table ===============================================================
    table = Table(
        name="my_first_test_table",
        columns=columns,
        parent_id=PROJECT_ID,
        annotations=annotations_for_my_table,
    )

    table = table.store_schema()

    print("Table created:")
    print(table)

    # Getting a table =================================================================
    copy_of_table = Table(id=table.id)

    copy_of_table = copy_of_table.get()

    print("Table retrieved:")
    print(copy_of_table)

    # Updating annotations on my table ===============================================
    copy_of_table.annotations["my_key_string"] = ["new", "values", "here"]
    stored_table = copy_of_table.store_schema()
    print("Table updated:")
    print(stored_table)

    # Storing data to a table =========================================================
    name_of_csv = "my_csv_file_with_random_data"
    path_to_csv = os.path.join(os.path.expanduser("~/temp"), f"{name_of_csv}.csv")
    write_random_csv_with_data(path_to_csv)

    csv_path = copy_of_table.store_rows_from_csv(csv_path=path_to_csv)

    print("Stored data to table from CSV:")
    print(csv_path)

    # Querying for data from a table =================================================
    destination_csv_location = os.path.expanduser("~/temp/my_query_results")

    table_id_to_query = copy_of_table.id
    Table.query(
        query=f"SELECT * FROM {table_id_to_query}",
        result_format=CsvResultFormat(download_location=destination_csv_location),
    )

    print(f"Created results at: {destination_csv_location}")

    # Deleting rows from a table =====================================================
    copy_of_table.delete_rows(rows=[Row(row_id=1)])

    # Deleting a table ===============================================================
    table_to_delete = Table(
        name="my_test_table_I_want_to_delete",
        columns=columns,
        parent_id=PROJECT_ID,
    ).store_schema()

    table_to_delete.delete()


store_table()
Current Synapse interface for working with a project
"""The purpose of this script is to demonstrate how to use the current synapse interface for projects.
The following actions are shown in this script:
1. Creating a project
2. Getting metadata about a project
3. Storing several files to a project
4. Storing several folders in a project with a file in each folder
5. Updating the annotations in bulk for a number of folders and files
6. Using synapseutils to sync a project from and to synapse
7. Deleting a project

All steps also include setting a number of annotations for the objects.
"""
import os
import uuid
from datetime import datetime, timedelta, timezone

import synapseclient
import synapseutils
from synapseclient import Annotations, File, Folder, Project

syn = synapseclient.Synapse(debug=True)
syn.login()


def create_random_file(
    path: str,
) -> None:
    """Create a random file with random data.

    :param path: The path to create the file at.
    """
    with open(path, "wb") as f:
        f.write(os.urandom(1))


# Creating annotations for my project ==================================================
my_annotations_dict = {
    "my_key_string": ["b", "a", "c"],
    "my_key_bool": [False, False, False],
    "my_key_double": [1.2, 3.4, 5.6],
    "my_key_long": [1, 2, 3],
    "my_key_timestamp": [
        datetime.today(),
        datetime.today() - timedelta(days=1),
        datetime.now(tz=timezone(timedelta(hours=-5))),
        datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=0))),
        datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=-7))),
    ],
}

# Creating a project =====================================================================
project = Project(
    name="my_new_project_for_testing_synapse_client",
    annotations=my_annotations_dict,
    description="This is a project with random data.",
)

my_stored_project: Project = syn.store(project)

print(my_stored_project)

# Getting metadata about a project =======================================================
my_project = syn.get(entity=my_stored_project.id)
print(my_project)

# Storing several files to a project =====================================================
for loop in range(1, 10):
    name_of_file = f"my_file_with_random_data_{loop}.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # Creating and uploading a file to a project =====================================
    file = File(
        path=path_to_file,
        name=name_of_file,
        parent=my_stored_project.id,
    )
    my_stored_file = syn.store(obj=file)

    my_annotations = Annotations(
        id=my_stored_file.id,
        etag=my_stored_file.etag,
        **my_annotations_dict,
    )

    syn.set_annotations(annotations=my_annotations)

# Storing several folders to a project ===================================================
for loop in range(1, 10):
    # Creating and uploading a folder to a project ===================================
    folder = Folder(
        name=f"my_folder_{loop}",
        parent=my_stored_project.id,
    )

    my_stored_folder = syn.store(obj=folder)

    my_annotations = Annotations(
        id=my_stored_folder.id,
        etag=my_stored_folder.etag,
        **my_annotations_dict,
    )

    syn.set_annotations(annotations=my_annotations)

    # Adding a file to a folder ======================================================
    name_of_file = f"my_file_with_random_data_{uuid.uuid4()}.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    file = File(
        path=path_to_file,
        name=name_of_file,
        parent=my_stored_folder.id,
    )
    my_stored_file = syn.store(obj=file)

    my_annotations = Annotations(
        id=my_stored_file.id,
        etag=my_stored_file.etag,
        **my_annotations_dict,
    )

    syn.set_annotations(annotations=my_annotations)

# Updating the annotations in bulk for a number of folders and files =====================
new_annotations = {
    "my_key_string": ["bbbbb", "aaaaa", "ccccc"],
}

# Note: This `getChildren` function will only return the items that are directly
# under the `parent`. You would need to recursively call this function to get all
# of the children for all folders under the parent.
for child in syn.getChildren(
    parent=my_stored_project.id, includeTypes=["folder", "file"]
):
    is_folder = (
        "type" in child and child["type"] == "org.sagebionetworks.repo.model.Folder"
    )
    is_file = (
        "type" in child and child["type"] == "org.sagebionetworks.repo.model.FileEntity"
    )

    if is_folder:
        my_folder = syn.get(entity=child["id"])
        new_saved_annotations = syn.set_annotations(
            Annotations(id=child["id"], etag=my_folder.etag, **new_annotations)
        )
        print(new_saved_annotations)
    elif is_file:
        my_file = syn.get(entity=child["id"], downloadFile=False)
        new_saved_annotations = syn.set_annotations(
            Annotations(id=child["id"], etag=my_file.etag, **new_annotations)
        )
        print(new_saved_annotations)

# Using synapseutils to sync a project from and to synapse ===============================
# This `syncFromSynapse` will download all files and folders under the project.
# In addition it creates a manifest TSV file that contains the metadata for all
# of the files and folders under the project.
project_download_location = os.path.expanduser("~/my_synapse_project")
result = synapseutils.syncFromSynapse(
    syn=syn, entity=my_stored_project, path=project_download_location
)
print(result)

# This `syncToSynapse` will upload all files and folders under the project that
# are defined in the manifest TSV file.
# ---
# 12/08/2023 note: There is a bug in the `syncToSynapse` method if you are using
# multiple annotations for a single key. This will be fixed in the next few releases.
# Track https://sagebionetworks.jira.com/browse/SYNPY-1357 for more information.
synapseutils.syncToSynapse(
    syn,
    manifestFile=f"{project_download_location}/SYNAPSE_METADATA_MANIFEST.tsv",
    sendMessages=False,
)

# Creating and then deleting a project ===================================================
project = Project(
    name="my_new_project_for_testing_synapse_client_that_will_be_deleted",
    annotations=my_annotations_dict,
    description="This is a project with random data.",
)

my_stored_project: Project = syn.store(project)
syn.delete(obj=my_stored_project.id)
Working with activities
"""The purpose of this script is to demonstrate how to use the OOP interface for Activity.
The following actions are shown in this script:
1. Creating a file with an Activity
2. Retrieve an activity by parent File
3. Creating a second file with the same activity
4. Modifying the activity attached to both Files
5. Creating a table with an Activity
"""

import os

import synapseclient
from synapseclient.models import (
    Activity,
    Column,
    ColumnType,
    File,
    Table,
    UsedEntity,
    UsedURL,
)

PROJECT_ID = "syn52948289"

syn = synapseclient.Synapse(debug=True)
syn.login()


def create_random_file(
    path: str,
) -> None:
    """Create a random file with random data.

    Arguments:
        path: The path to create the file at.
    """
    with open(path, "wb") as f:
        f.write(os.urandom(1))


def store_activity_on_file():
    name_of_file = "my_file_with_random_data.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    name_of_second_file = "my_second_file_with_random_data.txt"
    path_to_second_file = os.path.join(
        os.path.expanduser("~/temp"), name_of_second_file
    )
    create_random_file(path_to_second_file)

    # Create an activity =================================================================
    activity = Activity(
        name="My Activity",
        description="This is an activity.",
        used=[
            UsedURL(name="Used URL", url="https://www.synapse.org/"),
            UsedEntity(target_id=PROJECT_ID),
        ],
        executed=[
            UsedURL(name="Used URL", url="https://www.synapse.org/"),
            UsedEntity(target_id=PROJECT_ID),
        ],
    )

    # Creating and uploading a file to a project =========================================
    file = File(
        path=path_to_file,
        name=name_of_file,
        parent_id=PROJECT_ID,
        description="This is a file with random data.",
        activity=activity,
    )

    file = file.store()

    print("File created with activity:")
    print(activity)

    activity_copy = Activity.from_parent(parent=file)

    # Storing a second file to a project and re-use the activity =========================
    second_file = File(
        path=path_to_second_file,
        name=name_of_second_file,
        parent_id=PROJECT_ID,
        description="This is a file with random data.",
        activity=activity_copy,
    )

    second_file.store()

    print("Second file created with activity:")
    print(second_file.activity)

    # # Update the already created activity, which updates the activity on both files ====
    new_activity_instance = Activity(
        # In order to update an existing activity you must provide the id and etag.
        id=second_file.activity.id,
        etag=second_file.activity.etag if second_file.activity else None,
        name="My Activity - MODIFIED",
        used=[
            UsedURL(name="Used URL", url="https://www.synapse.org/"),
            UsedEntity(target_id=PROJECT_ID),
        ],
        executed=[
            UsedURL(name="Used URL", url="https://www.synapse.org/"),
            UsedEntity(target_id=PROJECT_ID),
        ],
    )
    # These 3 will be the same activity
    print("Modified activity showing name is updated for all files:")
    print(new_activity_instance.store().name)
    print(Activity.from_parent(parent=file).name)
    print(Activity.from_parent(parent=second_file).name)


def store_activity_on_table():
    # Create an activity =================================================================
    activity = Activity(
        name="My Activity",
        description="This is an activity.",
        used=[
            UsedURL(name="Used URL", url="https://www.synapse.org/"),
            UsedEntity(target_id=PROJECT_ID),
        ],
        executed=[
            UsedURL(name="Used URL", url="https://www.synapse.org/"),
            UsedEntity(target_id=PROJECT_ID),
        ],
    )

    # Creating columns for my table ======================================================
    columns = [
        Column(id=None, name="my_string_column", column_type=ColumnType.STRING),
    ]

    # Creating a table ===============================================================
    table = Table(
        name="my_first_test_table",
        columns=columns,
        parent_id=PROJECT_ID,
        activity=activity,
    )

    table = table.store_schema()

    print("Table created with activity:")
    print(table.activity)


store_activity_on_file()
store_activity_on_table()
Working with teams
"""The purpose of this script is to demonstrate how to use the new OOP interface for teams.
The following actions are shown in this script:
1. Creating a Team
2. Instantiating a Team object from Synapse
3. Getting information about the members of a Team
4. Inviting a user to a Team
5. Checking on invitations to join a Team
6. Deleting a Team
"""

import time

import synapseclient
from synapseclient.models.team import Team

syn = synapseclient.Synapse(debug=True)
syn.login()


def new_team():
    # Create a team
    new_team = Team(
        name="python-client-test-team",
        description="testing OOP interface",
        can_public_join=False,
    )
    my_synapse_team = new_team.create()
    print(my_synapse_team)

    # Instantiate a Team object from a Synapse team
    my_team = Team.from_id(id=my_synapse_team.id)
    print(my_team)

    # Sleep because the API for retrieving a team by name is eventually consistent. from_id works right away, however.
    time.sleep(5)
    my_team = Team.from_name(name=my_synapse_team.name)
    print(my_team)

    # Refresh the team to get the latest information
    my_team.get()
    print(my_team)

    # Get information about the members of a Team
    members = my_team.members()
    print(members)

    # Invite a user to a Team
    invite = my_team.invite(
        user="test_account_synapse_client",
        message="testing OOP interface (do not accept)",
    )
    print(invite)

    # Get open invitations for the Team
    invitations = my_team.open_invitations()
    print(invitations)

    # Delete the Team
    my_team.delete()


new_team()

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(*, synapse_client=None)

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 = Project(id="syn123").get()

Retrieve the project from Synapse using Name

project = Project(name="my_project").get()
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/protocols/project_protocol.py
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
def get(
    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 = Project(id="syn123").get()

        Retrieve the project from Synapse using Name

            project = Project(name="my_project").get()

    Raises:
        ValueError: If the project ID or Name is not set.
        SynapseNotFoundError: If the project is not found in Synapse.
    """
    return self

store(failure_strategy=FailureStrategy.LOG_EXCEPTION, *, synapse_client=None)

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 = Project(id="syn123", description="new").store()

Store the project to Synapse using Name

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

If the project name is not set.

Source code in synapseclient/models/protocols/project_protocol.py
19
20
21
22
23
24
25
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
def store(
    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 = Project(id="syn123", description="new").store()

        Store the project to Synapse using Name

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

    Raises:
        ValueError: If the project name is not set.
    """
    return self

delete(*, synapse_client=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

Project(id="syn123").delete()

Delete the project from Synapse using Name

Project(name="my_project").delete()
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/protocols/project_protocol.py
 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
def delete(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

            Project(id="syn123").delete()

        Delete the project from Synapse using Name

            Project(name="my_project").delete()

    Raises:
        ValueError: If the project ID or Name is not set.
        SynapseNotFoundError: If the project is not found in Synapse.
    """
    return None

sync_from_synapse(path=None, recursive=True, download_file=True, if_collision=COLLISION_OVERWRITE_LOCAL, failure_strategy=FailureStrategy.LOG_EXCEPTION, *, synapse_client=None)

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

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")
my_folder.sync_from_synapse(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")
my_folder.sync_from_synapse(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")
my_project.sync_from_synapse(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
            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()`
                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()`
            end
        end

    deactivate sync_from_synapse
    deactivate project_or_folder
Source code in synapseclient/models/protocols/storable_container_protocol.py
 19
 20
 21
 22
 23
 24
 25
 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
def sync_from_synapse(
    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,
    *,
    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.
        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")
            my_folder.sync_from_synapse(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")
            my_folder.sync_from_synapse(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")
            my_project.sync_from_synapse(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
                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()`
                    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()`
                end
            end

        deactivate sync_from_synapse
        deactivate project_or_folder
    ```

    """
    return self

get_permissions(*, synapse_client=None)

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 = File(id="syn123").get_permissions()

Getting access types list from the Permissions object

permissions.access_types
Source code in synapseclient/models/protocols/access_control_protocol.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def get_permissions(
    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 = File(id="syn123").get_permissions()

        Getting access types list from the Permissions object

            permissions.access_types
    """
    return self

get_acl(principal_id=None, *, synapse_client=None)

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/protocols/access_control_protocol.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def get_acl(
    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
    """
    return [""]

set_permissions(principal_id=None, access_type=None, modify_benefactor=False, warn_if_inherits=True, overwrite=True, *, synapse_client=None)

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

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

Grant the public view access

File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
Source code in synapseclient/models/protocols/access_control_protocol.py
 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
def set_permissions(
    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

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

        Grant the public view access

            File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
    """
    return {}

synapseclient.models.Folder dataclass

Bases: FolderSynchronousProtocol, AccessControllable, StorableContainer

Folder is a hierarchical container for organizing data in Synapse.

ATTRIBUTE DESCRIPTION
id

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

TYPE: Optional[str]

name

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

TYPE: Optional[str]

parent_id

The ID of the Project or Folder that is the parent of this Folder.

TYPE: Optional[str]

description

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

TYPE: Optional[str]

etag

(Read Only) 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

(Read Only) The date this entity was created.

TYPE: Optional[str]

modified_on

(Read Only) The date this entity was last modified.

TYPE: Optional[str]

created_by

(Read Only) The ID of the user that created this entity.

TYPE: Optional[str]

modified_by

(Read Only) The ID of the user that last modified this entity.

TYPE: Optional[str]

files

Files that exist within this folder.

TYPE: List[File]

folders

Folders that exist within this folder.

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

Source code in synapseclient/models/folder.py
 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
@dataclass()
@async_to_sync
class Folder(FolderSynchronousProtocol, AccessControllable, StorableContainer):
    """Folder is a hierarchical container for organizing data in Synapse.

    Attributes:
        id: The unique immutable ID for this folder. A new ID will be generated for new
            Folders. Once issued, this ID is guaranteed to never change or be re-issued.
        name: The name of this folder. Must be 256 characters or less. Names may only
            contain: letters, numbers, spaces, underscores, hyphens, periods, plus
            signs, apostrophes, and parentheses.
        parent_id: The ID of the Project or Folder that is the parent of this Folder.
        description: The description of this entity. Must be 1000 characters or less.
        etag: (Read Only)
            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: (Read Only) The date this entity was created.
        modified_on: (Read Only) The date this entity was last modified.
        created_by: (Read Only) The ID of the user that created this entity.
        modified_by: (Read Only) The ID of the user that last modified this entity.
        files: Files that exist within this folder.
        folders: Folders that exist within this 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.
        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.
    """

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

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

    parent_id: Optional[str] = None
    """The ID of the Project or Folder that is the parent of this Folder."""

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

    etag: Optional[str] = None
    """(Read Only)
    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] = None
    """(Read Only) The date this entity was created."""

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

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

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

    files: List["File"] = field(default_factory=list, compare=False)
    """Files that exist within this folder."""

    folders: List["Folder"] = field(default_factory=list, compare=False)
    """Folders that exist within this folder."""

    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."""

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

    If set to true, an email will be sent to the Synapse access control team to start
    the process of adding terms-of-use or review board approval for this entity.
    You will be contacted with regards to the specific data being restricted and the
    requirements of access.
    """

    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.
    """

    _last_persistent_instance: Optional["Folder"] = 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_folder: Synapse_Folder, set_annotations: bool = True
    ) -> "Folder":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_file: The response from the REST API.
            set_annotations: Whether to set the annotations from the response.

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

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

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

        Arguments:
            parent: The parent folder or project to store the folder in.
            failure_strategy: Determines how to handle failures when storing attached
                Files and Folders under this Folder 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 folder object.

        Raises:
            ValueError: If the folder does not have an id or a
                (name and (`parent_id` or parent with an id)) set.
        """
        parent_id = parent.id if parent else self.parent_id
        if not (self.id or (self.name and parent_id)):
            raise ValueError(
                "The folder must have an id or a "
                "(name and (`parent_id` or parent with an id)) set."
            )
        self.parent_id = parent_id

        if (
            self.create_or_update
            and not self._last_persistent_instance
            and (
                existing_folder_id := await get_id(
                    entity=self, failure_strategy=None, synapse_client=synapse_client
                )
            )
            and (
                existing_folder := await Folder(id=existing_folder_id).get_async(
                    synapse_client=synapse_client
                )
            )
        ):
            merge_dataclass_entities(source=existing_folder, 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_folder = Synapse_Folder(
                id=self.id,
                name=self.name,
                parent=parent_id,
                etag=self.etag,
                description=self.description,
            )
            delete_none_keys(synapse_folder)
            entity = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(synapse_client=synapse_client).store(
                    obj=synapse_folder,
                    set_annotations=False,
                    isRestricted=self.is_restricted,
                    createOrUpdate=False,
                ),
            )

            self.fill_from_dict(synapse_folder=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 Folder {self.name}, id: {self.id}: parent: {self.parent_id}"
        )

        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Folder_Get: {self.id}"
    )
    async def get_async(
        self,
        parent: Optional[Union["Folder", "Project"]] = None,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "Folder":
        """Get the folder metadata from Synapse. You are able to find a folder by
        either the id or the name and parent_id.

        Arguments:
            parent: The parent folder or project this folder exists under.
            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 folder object.

        Raises:
            ValueError: If the folder does not have an id or a
                (name and (`parent_id` or parent with an id)) set.
        """
        parent_id = parent.id if parent else self.parent_id
        if not (self.id or (self.name and parent_id)):
            raise ValueError(
                "The folder must have an id or a "
                "(name and (`parent_id` or parent with an id)) set."
            )
        self.parent_id = parent_id

        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"Folder_Delete: {self.id}"
    )
    async def delete_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
        """Delete the folder from Synapse by its id.

        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

        Raises:
            ValueError: If the folder does not have an id set.
        """
        if not self.id:
            raise ValueError("The folder must have an id set.")
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).delete(
                obj=self.id,
            ),
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Folder_Copy: {self.id}"
    )
    async def copy_async(
        self,
        parent_id: str,
        copy_annotations: 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,
    ) -> "Folder":
        """
        Copy the folder to another Synapse location. This will recursively copy all
        Tables, Links, Files, and Folders within the folder.

        Arguments:
            parent_id: Synapse ID of a folder/project that the copied entity is
                being copied to
            copy_annotations: True to copy the annotations.
            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 folder object.

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

                new_folder_instance = await Folder(id="syn123").copy_async(parent_id="syn456")

            Copy the folder but do not persist annotations:

                new_folder_instance = await Folder(id="syn123").copy_async(parent_id="syn456", copy_annotations=False)

        Raises:
            ValueError: If the folder does not have an ID and parent_id to copy.
        """
        if not self.id or not parent_id:
            raise ValueError("The folder must have an ID and parent_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=parent_id,
                excludeTypes=exclude_types or [],
                skipCopyAnnotations=not copy_annotations,
                updateExisting=file_update_existing,
                setProvenance=file_copy_activity,
            ),
        )

        new_folder_id = source_and_destination.get(self.id, None)
        if not new_folder_id:
            raise SynapseError("Failed to copy folder.")
        folder_copy = await (
            await Folder(id=new_folder_id).get_async(synapse_client=synapse_client)
        ).sync_from_synapse_async(
            download_file=False,
            synapse_client=synapse_client,
        )
        syn.logger.debug(
            f"Copied from folder {self.id} to {parent_id} with new id of {folder_copy.id}"
        )
        return folder_copy

Functions

get(parent=None, *, synapse_client=None)

Get the folder metadata from Synapse. You are able to find a folder by either the id or the name and parent_id.

PARAMETER DESCRIPTION
parent

The parent folder or project this folder exists under.

TYPE: Optional[Union[Folder, Project]] 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
Folder

The folder object.

RAISES DESCRIPTION
ValueError

If the folder does not have an id or a (name and (parent_id or parent with an id)) set.

Source code in synapseclient/models/protocols/folder_protocol.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def get(
    self,
    parent: Optional[Union["Folder", "Project"]] = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "Folder":
    """Get the folder metadata from Synapse. You are able to find a folder by
    either the id or the name and parent_id.

    Arguments:
        parent: The parent folder or project this folder exists under.
        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 folder object.

    Raises:
        ValueError: If the folder does not have an id or a
            (name and (`parent_id` or parent with an id)) set.
    """
    return self

store(parent=None, failure_strategy=FailureStrategy.LOG_EXCEPTION, *, synapse_client=None)

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

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

PARAMETER DESCRIPTION
parent

The parent folder or project to store the folder in.

TYPE: Optional[Union[Folder, Project]] DEFAULT: None

failure_strategy

Determines how to handle failures when storing attached Files and Folders under this Folder 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
Folder

The folder object.

RAISES DESCRIPTION
ValueError

If the folder does not have an id or a (name and (parent_id or parent with an id)) set.

Source code in synapseclient/models/protocols/folder_protocol.py
19
20
21
22
23
24
25
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
def store(
    self,
    parent: Optional[Union["Folder", "Project"]] = None,
    failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "Folder":
    """Store folders and files to synapse. If you have any files or folders attached
    to this folder they will be stored as well. You may attach files and folders
    to this folder by setting the `files` and `folders` attributes.

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

    Arguments:
        parent: The parent folder or project to store the folder in.
        failure_strategy: Determines how to handle failures when storing attached
            Files and Folders under this Folder 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 folder object.

    Raises:
        ValueError: If the folder does not have an id or a
            (name and (`parent_id` or parent with an id)) set.
    """
    return self

delete(*, synapse_client=None)

Delete the folder from Synapse by its id.

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

RAISES DESCRIPTION
ValueError

If the folder does not have an id set.

Source code in synapseclient/models/protocols/folder_protocol.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def delete(self, *, synapse_client: Optional[Synapse] = None) -> None:
    """Delete the folder from Synapse by its id.

    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

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

copy(parent_id, copy_annotations=True, exclude_types=None, file_update_existing=False, file_copy_activity='traceback', *, synapse_client=None)

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

PARAMETER DESCRIPTION
parent_id

Synapse ID of a folder/project that the copied entity is being copied to

TYPE: str

copy_annotations

True to copy the annotations.

TYPE: bool DEFAULT: True

exclude_types

A list of entity types ['file', 'table', 'link'] which determines which entity types to not copy. Defaults to an empty list.

TYPE: Optional[List[str]] DEFAULT: None

file_update_existing

When the destination has a file that has the same name, users can choose to update that file.

TYPE: bool DEFAULT: False

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

TYPE: Union[str, None] DEFAULT: 'traceback'

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
Folder

The copied folder object.

Using this function

Assuming you have a folder with the ID "syn123" and you want to copy it to a project with the ID "syn456":

new_folder_instance = await Folder(id="syn123").copy(parent_id="syn456")

Copy the folder but do not persist annotations:

new_folder_instance = await Folder(id="syn123").copy(parent_id="syn456", copy_annotations=False)
RAISES DESCRIPTION
ValueError

If the folder does not have an ID and parent_id to copy.

Source code in synapseclient/models/protocols/folder_protocol.py
 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
def copy(
    self,
    parent_id: str,
    copy_annotations: 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,
) -> "Folder":
    """
    Copy the folder to another Synapse location. This will recursively copy all
    Tables, Links, Files, and Folders within the folder.

    Arguments:
        parent_id: Synapse ID of a folder/project that the copied entity is
            being copied to
        copy_annotations: True to copy the annotations.
        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 folder object.

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

            new_folder_instance = await Folder(id="syn123").copy(parent_id="syn456")

        Copy the folder but do not persist annotations:

            new_folder_instance = await Folder(id="syn123").copy(parent_id="syn456", copy_annotations=False)

    Raises:
        ValueError: If the folder does not have an ID and parent_id to copy.
    """
    return self

sync_from_synapse(path=None, recursive=True, download_file=True, if_collision=COLLISION_OVERWRITE_LOCAL, failure_strategy=FailureStrategy.LOG_EXCEPTION, *, synapse_client=None)

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

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")
my_folder.sync_from_synapse(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")
my_folder.sync_from_synapse(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")
my_project.sync_from_synapse(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
            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()`
                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()`
            end
        end

    deactivate sync_from_synapse
    deactivate project_or_folder
Source code in synapseclient/models/protocols/storable_container_protocol.py
 19
 20
 21
 22
 23
 24
 25
 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
def sync_from_synapse(
    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,
    *,
    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.
        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")
            my_folder.sync_from_synapse(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")
            my_folder.sync_from_synapse(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")
            my_project.sync_from_synapse(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
                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()`
                    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()`
                end
            end

        deactivate sync_from_synapse
        deactivate project_or_folder
    ```

    """
    return self

get_permissions(*, synapse_client=None)

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 = File(id="syn123").get_permissions()

Getting access types list from the Permissions object

permissions.access_types
Source code in synapseclient/models/protocols/access_control_protocol.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def get_permissions(
    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 = File(id="syn123").get_permissions()

        Getting access types list from the Permissions object

            permissions.access_types
    """
    return self

get_acl(principal_id=None, *, synapse_client=None)

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/protocols/access_control_protocol.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def get_acl(
    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
    """
    return [""]

set_permissions(principal_id=None, access_type=None, modify_benefactor=False, warn_if_inherits=True, overwrite=True, *, synapse_client=None)

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

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

Grant the public view access

File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
Source code in synapseclient/models/protocols/access_control_protocol.py
 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
def set_permissions(
    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

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

        Grant the public view access

            File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
    """
    return {}

synapseclient.models.File dataclass

Bases: FileSynchronousProtocol, AccessControllable

A file within Synapse.

ATTRIBUTE DESCRIPTION
id

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

TYPE: Optional[str]

name

The name of this entity. Must be 256 characters or less. Names may only contain: letters, numbers, spaces, underscores, hyphens, periods, plus signs, apostrophes, and parentheses. If not specified, the name will be derived from the file name.

TYPE: Optional[str]

path

The path to the file on disk. Using shorthand ~ will be expanded to the user's home directory.

This is used during a get operation to specify where to download the file to. It should be pointing to a directory.

This is also used during a store operation to specify the file to upload. It should be pointing to a file.

TYPE: Optional[str]

description

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

TYPE: Optional[str]

parent_id

The ID of the Entity that is the parent of this Entity. Setting this to a new value and storing it will move this File under the new parent.

TYPE: Optional[str]

version_label

The version label for this entity. Updates to the entity will increment the version number.

TYPE: Optional[str]

version_comment

The version comment for this entity

TYPE: Optional[str]

data_file_handle_id

ID of the file associated with this entity. You may define an existing data_file_handle_id to use the existing data_file_handle_id. The creator of the file must also be the owner of the data_file_handle_id to have permission to store the file.

TYPE: Optional[str]

external_url

The external URL of this file. If this is set AND synapse_store is False, only a reference to this URL and the file metadata will be stored in Synapse. The file itself will not be uploaded. If this attribute is set it will override the path.

TYPE: Optional[str]

activity

The Activity model represents the main record of Provenance in Synapse. It is analygous to the Activity defined in the W3C Specification on Provenance. Activity cannot be removed during a store operation by setting it to None. You must use: synapseclient.models.Activity.delete_async or [synapseclient.models.Activity.disassociate_from_entity_async][].

TYPE: Optional[Activity]

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]]]]

ATTRIBUTE DESCRIPTION
content_type

(New Upload Only) Used to manually specify Content-type header, for example 'application/png' or 'application/json; charset=UTF-8'. If not specified, the content type will be derived from the file extension.

This can be specified only during the initial store of this file or any time there is a new file to upload. In order to change this after the File has been created use synapseclient.models.File.change_metadata.

TYPE: Optional[str]

content_size

(New Upload Only) The size of the file in bytes. This can be specified only during the initial creation of the File. This is also only applicable to files not uploaded to Synapse. ie: synapse_store is False.

TYPE: Optional[int]

ATTRIBUTE DESCRIPTION
content_md5

(Store only) The MD5 of the file is known. If not supplied this will be computed in the client is possible. If supplied for a file entity already stored in Synapse it will be calculated again to check if a new upload needs to occur. This will not be filled in during a read for data. It is only used during a store operation. To retrieve the md5 of the file after read from synapse use the .file_handle.content_md5 attribute.

TYPE: Optional[str]

create_or_update

(Store only) Indicates whether the method should automatically perform an update if the file conflicts with an existing Synapse object.

TYPE: bool

force_version

(Store only) Indicates whether the method should increment the version of the object if something within the entity has changed. For example updating the description or name. You may set this to False and an update to the entity will not increment the version.

Updating the version_label attribute will also cause a version update regardless of this flag.

An update to the MD5 of the file will force a version update regardless of this flag.

TYPE: bool

is_restricted

(Store only) If set to true, an email will be sent to the Synapse access control team to start the process of adding terms-of-use or review board approval for this entity. You will be contacted with regards to the specific data being restricted and the requirements of access.

This may be used only by an administrator of the specified file.

TYPE: bool

merge_existing_annotations

(Store only) Works in conjunction with create_or_update in that this is only evaluated if create_or_update is True. If this entity exists in Synapse that has annotations that are not present in a store operation, these annotations will be added to the entity. If this is False any annotations that are not present within a store operation will be removed from this entity. This allows one to complete a destructive update of annotations on an entity.

TYPE: bool

associate_activity_to_new_version

(Store only) Works in conjunction with create_or_update in that this is only evaluated if create_or_update is True. When true an activity already attached to the current version of this entity will be associated the new version during a store operation if the version was updated. This is useful if you are updating the entity and want to ensure that the activity is persisted onto the new version the entity.

TYPE: bool

synapse_store

(Store only) Whether the File should be uploaded or if false: only the path should be stored when synapseclient.models.File.store is called.

TYPE: bool

ATTRIBUTE DESCRIPTION
download_file

(Get only) If True the file will be downloaded.

TYPE: bool

if_collision

(Get only) Determines how to handle file collisions. Defaults to "keep.both". May be:

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

TYPE: str

synapse_container_limit

(Get only) A Synanpse ID used to limit the search in Synapse if file is specified as a local file. That is, if the file is stored in multiple locations in Synapse only the ones in the specified folder/project will be returned.

TYPE: Optional[str]

ATTRIBUTE DESCRIPTION
etag

(Read Only) 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

(Read Only) The date this entity was created.

TYPE: Optional[str]

modified_on

(Read Only) The date this entity was last modified.

TYPE: Optional[str]

created_by

(Read Only) The ID of the user that created this entity.

TYPE: Optional[str]

modified_by

(Read Only) The ID of the user that last modified this entity.

TYPE: Optional[str]

version_number

(Read Only) The version number issued to this version on the object.

TYPE: Optional[int]

is_latest_version

(Read Only) If this is the latest version of the object.

TYPE: Optional[bool]

file_handle

(Read Only) The file handle associated with this entity.

TYPE: Optional[FileHandle]

Source code in synapseclient/models/file.py
 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
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
@dataclass()
@async_to_sync
class File(FileSynchronousProtocol, AccessControllable):
    """A file within Synapse.

    Attributes:
        id: The unique immutable ID for this file. A new ID will be generated for new
            Files. Once issued, this ID is guaranteed to never change or be re-issued.
        name: The name of this entity. Must be 256 characters or less. Names may only
            contain: letters, numbers, spaces, underscores, hyphens, periods, plus
            signs, apostrophes, and parentheses. If not specified, the name will be
            derived from the file name.
        path: The path to the file on disk. Using shorthand `~` will be expanded to the
            user's home directory.

            This is used during a `get` operation to specify where to download the file
            to. It should be pointing to a directory.

            This is also used during a `store` operation to specify the file to upload.
            It should be pointing to a file.

        description: The description of this file. Must be 1000 characters or less.
        parent_id: The ID of the Entity that is the parent of this Entity. Setting this
            to a new value and storing it will move this File under the new parent.
        version_label: The version label for this entity. Updates to the entity will
            increment the version number.
        version_comment: The version comment for this entity
        data_file_handle_id: ID of the file associated with this entity. You may define
            an existing data_file_handle_id to use the existing data_file_handle_id. The
            creator of the file must also be the owner of the data_file_handle_id to
            have permission to store the file.
        external_url: The external URL of this file. If this is set AND `synapse_store`
            is False, only a reference to this URL and the file metadata will be stored
            in Synapse. The file itself will not be uploaded. If this attribute is set
            it will override the `path`.
        activity: The Activity model represents the main record of Provenance in
            Synapse. It is analygous to the Activity defined in the
            [W3C Specification](https://www.w3.org/TR/prov-n/) on Provenance. Activity
            cannot be removed during a store operation by setting it to None. You must
            use: [synapseclient.models.Activity.delete_async][] or
            [synapseclient.models.Activity.disassociate_from_entity_async][].
        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.

    Attributes:
        content_type: (New Upload Only)
            Used to manually specify Content-type header, for example
            'application/png' or 'application/json; charset=UTF-8'. If not specified,
            the content type will be derived from the file extension.


            This can be specified only during the initial store of this file or any time
            there is a new file to upload.
            In order to change this after the File has been created use
            [synapseclient.models.File.change_metadata][].
        content_size: (New Upload Only)
            The size of the file in bytes. This can be specified only during the initial
            creation of the File. This is also only applicable to files not uploaded to
            Synapse. ie: `synapse_store` is False.

    Attributes:
        content_md5: (Store only) The MD5 of the file is known. If not supplied this
            will be computed in the client is possible. If supplied for a file entity
            already stored in Synapse it will be calculated again to check if a new
            upload needs to occur. This will not be filled in during a read for data. It
            is only used during a store operation. To retrieve the md5 of the file after
            read from synapse use the `.file_handle.content_md5` attribute.
        create_or_update: (Store only)
            Indicates whether the method should automatically perform an
            update if the `file` conflicts with an existing Synapse object.
        force_version: (Store only)
            Indicates whether the method should increment the version of the object if
            something within the entity has changed. For example updating the
            description or name. You may set this to False and an update to the
            entity will not increment the version.

            Updating the `version_label` attribute will also cause a version update
            regardless  of this flag.

            An update to the MD5 of the file will force a version update regardless of
            this  flag.
        is_restricted: (Store only)
            If set to true, an email will be sent to the Synapse access control
            team to start the process of adding terms-of-use or review board approval
            for this entity. You will be contacted with regards to the specific data
            being restricted and the requirements of access.

            This may be used only by an administrator of the specified file.
        merge_existing_annotations: (Store only)
            Works in conjunction with `create_or_update` in that this is only evaluated
            if `create_or_update` is True. If this entity exists in Synapse that has
            annotations that are not present in a store operation, these annotations
            will be added to the entity. If this is False any annotations that are not
            present within a store operation will be removed from this entity. This
            allows one to complete a destructive update of annotations on an entity.
        associate_activity_to_new_version: (Store only)
            Works in conjunction with `create_or_update` in that this is only evaluated
            if `create_or_update` is True. When true an activity already attached to the
            current version of this entity will be associated the new version during a
            store operation if the version was updated. This is useful if you are
            updating the entity and want to ensure that the activity is persisted onto
            the new version the entity.
        synapse_store: (Store only)
            Whether the File should be uploaded or if false: only the path should
            be stored when [synapseclient.models.File.store][] is called.

    Attributes:
        download_file: (Get only) If True the file will be downloaded.
        if_collision: (Get only)
            Determines how to handle file collisions. Defaults to "keep.both". May be:

            - `overwrite.local`
            - `keep.local`
            - `keep.both`
        synapse_container_limit: (Get only)
            A Synanpse ID used to limit the search in Synapse if
            file is specified as a local file. That is, if the file is stored in
            multiple locations in Synapse only the ones in the specified folder/project
            will be returned.

    Attributes:
        etag: (Read Only) 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: (Read Only) The date this entity was created.
        modified_on: (Read Only) The date this entity was last modified.
        created_by: (Read Only) The ID of the user that created this entity.
        modified_by: (Read Only) The ID of the user that last modified this entity.
        version_number: (Read Only) The version number issued to this version on the
            object.
        is_latest_version: (Read Only) If this is the latest version of the object.
        file_handle: (Read Only) The file handle associated with this entity.
    """

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

    name: Optional[str] = None
    """
    The name of this entity. Must be 256 characters or less.
    Names may only contain: letters, numbers, spaces, underscores, hyphens, periods,
    plus signs, apostrophes, and parentheses. If not specified, the name will be
    derived from the file name.
    """

    path: Optional[str] = field(default=None, compare=False)
    """The path to the file on disk. Using shorthand `~` will be expanded to the user's
    home directory.

    This is used during a `get` operation to specify where to download the file to. It
    should be pointing to a directory.

    This is also used during a `store` operation to specify the file to upload. It
    should be pointing to a file."""

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

    parent_id: Optional[str] = None
    """The ID of the Entity that is the parent of this Entity. Setting this to a new
    value and storing it will move this File under the new parent."""

    version_label: Optional[str] = None
    """The version label for this entity. Updates to the entity will increment the
    version number."""

    version_comment: Optional[str] = None
    """The version comment for this entity."""

    data_file_handle_id: Optional[str] = None
    """
    ID of the file handle associated with this entity. You may define an existing
    data_file_handle_id to use the existing data_file_handle_id. The creator of the
    file must also be the owner of the data_file_handle_id to have permission to
    store the file.
    """

    external_url: Optional[str] = field(default=None, compare=False)
    """
    The external URL of this file. If this is set AND `synapse_store` is False, only
    a reference to this URL and the file metadata will be stored in Synapse. The file
    itself will not be uploaded. If this attribute is set it will override the `path`.
    """

    activity: Optional[Activity] = field(default=None, compare=False)
    """The Activity model represents the main record of Provenance in Synapse.  It is
    analygous to the Activity defined in the
    [W3C Specification](https://www.w3.org/TR/prov-n/) on Provenance. Activity cannot
    be removed during a store operation by setting it to None. You must use:
    [synapseclient.models.Activity.delete_async][] or
    [synapseclient.models.Activity.disassociate_from_entity_async][].
    """

    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 `{}`."""

    content_type: Optional[str] = None
    """
    (New Upload Only)
    Used to manually specify Content-type header, for example 'application/png'
    or 'application/json; charset=UTF-8'. If not specified, the content type will be
    derived from the file extension.

    This can be specified only during the initial store of this file. In order to change
    this after the File has been created use
    [synapseclient.models.File.change_metadata][].
    """

    content_size: Optional[int] = None
    """
    (New Upload Only)
    The size of the file in bytes. This can be specified only during the initial
    creation of the File. This is also only applicable to files not uploaded to Synapse.
    ie: `synapse_store` is False.
    """

    content_md5: Optional[str] = field(default=None, compare=False)
    """
    (Store only)
    The MD5 of the file is known. If not supplied this will be computed in the client
    is possible. If supplied for a file entity already stored in Synapse it will be
    calculated again to check if a new upload needs to occur. This will not be filled
    in during a read for data. It is only used during a store operation. To retrieve
    the md5 of the file after read from synapse use the `.file_handle.content_md5`
    attribute.
    """

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

    Indicates whether the method should automatically perform an update if the file
    conflicts with an existing Synapse object.
    """

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

    Indicates whether the method should increment the version of the object if something
    within the entity has changed. For example updating the description or name.
    You may set this to False and an update to the entity will not increment the
    version.

    Updating the `version_label` attribute will also cause a version update regardless
    of this flag.

    An update to the MD5 of the file will force a version update regardless of this
    flag.
    """

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

    If set to true, an email will be sent to the Synapse access control team to start
    the process of adding terms-of-use or review board approval for this entity.
    You will be contacted with regards to the specific data being restricted and the
    requirements of access.

    This may be used only by an administrator of the specified file.
    """

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

    Works in conjunction with `create_or_update` in that this is only evaluated if
    `create_or_update` is True. If this entity exists in Synapse that has annotations
    that are not present in a store operation, these annotations will be added to the
    entity. If this is False any annotations that are not present within a store
    operation will be removed from this entity. This allows one to complete a
    destructive update of annotations on an entity.
    """

    associate_activity_to_new_version: bool = field(
        default=False, repr=False, compare=False
    )
    """
    (Store only)

    Works in conjunction with `create_or_update` in that this is only evaluated if
    `create_or_update` is True. When true an activity already attached to the current
    version of this entity will be associated the new version during a store operation
    if the version was updated. This is useful if you are updating the entity and want
    to ensure that the activity is persisted onto the new version the entity.

    When this is False the activity will not be associated to the new version of the
    entity during a store operation.

    Regardless of this setting, if you have an Activity object on the entity it will be
    persisted onto the new version. This is only used when you don't have an Activity
    object on the entity.
    """

    _present_manifest_fields: List[str] = field(default=None, repr=False, compare=False)
    """Hidden attribute to pass along what columns were present in a manifest upload."""

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

    Whether the File should be uploaded or if false: only the path should be stored when
    [synapseclient.models.File.store][] is called.
    """

    download_file: bool = field(default=True, repr=False, compare=False)
    """
    (Get only)

    If True the file will be downloaded."""

    if_collision: str = field(default="keep.both", repr=False, compare=False)
    """
    (Get only)

    Determines how to handle file collisions. Defaults to "keep.both".
            May be

            - `overwrite.local`
            - `keep.local`
            - `keep.both`
    """

    synapse_container_limit: Optional[str] = field(
        default=None, repr=False, compare=False
    )
    """A Synanpse ID used to limit the search in Synapse if file is specified as a local
    file. That is, if the file is stored in multiple locations in Synapse only the
    ones in the specified folder/project will be returned."""

    etag: Optional[str] = field(default=None, compare=False)
    """
    (Read Only)
    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."""

    version_number: Optional[int] = field(default=None, compare=False)
    """(Read Only) The version number issued to this version on the object."""

    is_latest_version: Optional[bool] = field(default=None, compare=False)
    """(Read Only) If this is the latest version of the object."""

    file_handle: Optional[FileHandle] = field(default=None, compare=False)
    """(Read Only) The file handle associated with this entity."""

    _last_persistent_instance: Optional["File"] = 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 = dataclasses.replace(self)
        self._last_persistent_instance.activity = (
            dataclasses.replace(self.activity) if self.activity else None
        )
        self._last_persistent_instance.annotations = (
            deepcopy(self.annotations) if self.annotations else {}
        )

    def _fill_from_file_handle(self) -> None:
        """Fill the file object from the file handle."""
        if self.file_handle:
            self.data_file_handle_id = self.file_handle.id
            self.content_type = self.file_handle.content_type
            self.content_size = self.file_handle.content_size
            self.external_url = self.file_handle.external_url

    def fill_from_dict(
        self,
        synapse_file: Union[Synapse_File, Dict[str, Union[bool, str, int]]],
        set_annotations: bool = True,
    ) -> "File":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_file: The response from the REST API.
            set_annotations: Whether to set the annotations from the response.

        Returns:
            The File object.
        """
        self.id = synapse_file.get("id", None)
        self.name = synapse_file.get("name", None)
        self.description = synapse_file.get("description", None)
        self.etag = synapse_file.get("etag", None)
        self.created_on = synapse_file.get("createdOn", None)
        self.modified_on = synapse_file.get("modifiedOn", None)
        self.created_by = synapse_file.get("createdBy", None)
        self.modified_by = synapse_file.get("modifiedBy", None)
        self.parent_id = synapse_file.get("parentId", None)
        self.version_number = synapse_file.get("versionNumber", None)
        self.version_label = synapse_file.get("versionLabel", None)
        self.version_comment = synapse_file.get("versionComment", None)
        self.is_latest_version = synapse_file.get("isLatestVersion", False)
        self.data_file_handle_id = synapse_file.get("dataFileHandleId", None)
        self.path = synapse_file.get("path", self.path)
        synapse_file_handle = synapse_file.get("_file_handle", None)
        if synapse_file_handle:
            file_handle = self.file_handle or FileHandle()
            self.file_handle = file_handle.fill_from_dict(
                synapse_instance=synapse_file_handle
            )
            self._fill_from_file_handle()

        if set_annotations:
            self.annotations = Annotations.from_dict(
                synapse_file.get("annotations", {})
            )
        return self

    def _cannot_store(self) -> bool:
        """Determines based on some guard conditions if we are unable to continue with
        a store operation."""
        return (
            not (
                self.id is not None
                and (self.path is not None or self.data_file_handle_id is not None)
            )
            and not (self.path is not None and self.parent_id is not None)
            and not (
                self.parent_id is not None and self.data_file_handle_id is not None
            )
        )

    async def _load_local_md5(self) -> None:
        """Load the MD5 of the file if it's a local file and we have not already loaded
        it."""
        if not self.content_md5 and self.path and os.path.isfile(self.path):
            self.content_md5 = utils.md5_for_file_hex(filename=self.path)

    async def _find_existing_file(
        self, *, synapse_client: Optional[Synapse] = None
    ) -> Union["File", None]:
        """Determines if the file already exists in Synapse. If it does it will return
        the file object, otherwise it will return None. This is used to determine if the
        file should be updated or created."""

        async def get_file(existing_id: str) -> "File":
            """Small wrapper to retrieve a file instance without raising an error if it
            does not exist.

            Arguments:
                existing_id: The ID of the file to retrieve.

            Returns:
                The file object if it exists, otherwise None.
            """
            try:
                file_copy = File(
                    id=existing_id,
                    download_file=False,
                    version_number=self.version_number,
                    synapse_container_limit=self.synapse_container_limit,
                    parent_id=self.parent_id,
                )
                return await file_copy.get_async(
                    synapse_client=synapse_client,
                    include_activity=self.activity is not None
                    or self.associate_activity_to_new_version,
                )
            except SynapseFileNotFoundError:
                return None

        if (
            self.create_or_update
            and not self._last_persistent_instance
            and (
                existing_file_id := await get_id(
                    entity=self,
                    failure_strategy=None,
                    synapse_client=synapse_client,
                )
            )
            and (existing_file := await get_file(existing_file_id))
        ):
            return existing_file
        return None

    def _determine_fields_to_ignore_in_merge(self) -> List[str]:
        """This is used to determine what fields should not be merged when merging two
        entities. This allows for a fine tuned destructive update of an entity.

        This also has special handling during a manifest upload of files. If a manifest
        is specifying fields we'll use those values rather than copying them from the
        existing entity. This is to allow for a destructive update of an entity.

        """
        fields_to_not_merge = []
        if not self.merge_existing_annotations:
            fields_to_not_merge.append("annotations")

        if not self.associate_activity_to_new_version:
            fields_to_not_merge.append("activity")

        if self._present_manifest_fields:
            if "name" in self._present_manifest_fields:
                fields_to_not_merge.append("name")

            if "contentType" in self._present_manifest_fields:
                fields_to_not_merge.append("content_type")

        return fields_to_not_merge

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Store: {self.path if self.path else self.id}"
    )
    async def store_async(
        self,
        parent: Optional[Union["Folder", "Project"]] = None,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Store the file in Synapse. With this method you may:

        - Upload a file into Synapse
        - Update the metadata of a file in Synapse
        - Store a File object in Synapse without updating a file by setting
            `synapse_store` to False.
        - Change the name of a file in Synapse by setting the `name` attribute of the
            File object. Also see the [synapseclient.models.File.change_metadata][]
            method for changing the name of the downloaded file.
        - Moving a file to a new parent by setting the `parent_id` attribute of the
            File object.

        If no Name is specified this will be derived from the file name. This is the
        reccommended way to store a file in Synapse.

        Please note:
        The file, as it appears on disk, will be the file that is downloaded from
        Synapse. The name of the actual File is different from the name of the File
        Entity in Synapse. It is generally not reccommended to specify a different
        name for the Entity and the file as it will cause confusion and potential
        conflicts later on.

        Arguments:
            parent: The parent folder or project to store the file in. May also be
                specified in the File object. If both are provided the parent passed
                into `store` will take precedence.
            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 file object.

        Raises:
            ValueError: If the file does not have an ID and a path, or a path and a
                parent ID, or a data file handle ID and a parent ID.

        Example: Using this function
            File with the ID `syn123` at path `path/to/file.txt`:

                file_instance = await File(id="syn123", path="path/to/file.txt").store_async()

            File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

                file_instance = await File(path="path/to/file.txt", parent_id="syn456").store_async()

            File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

                file_instance = await File(path="path/to/file.txt").store_async(parent=Folder(id="syn456"))

            File with a parent and existing file handle (This allows multiple entities to reference the underlying file):

                file_instance = await File(data_file_handle_id="123", parent_id="syn456").store_async()

            Rename a file (Does not update the file on disk or the name of the downloaded file):

                file_instance = await File(id="syn123", download_file=False).get_async()
                print(file_instance.name)  ## prints, e.g., "my_file.txt"
                await file_instance.change_metadata_async(name="my_new_name_file.txt")

            Rename a file, and the name of the file as downloaded
                (Does not update the file on disk). Is is reccommended that `name` and
                `download_as` match to prevent confusion later on:

                file_instance = await File(id="syn123", download_file=False).get_async()
                print(file_instance.name)  ## prints, e.g., "my_file.txt"
                await file_instance.change_metadata_async(name="my_new_name_file.txt", download_as="my_new_name_file.txt")

        """
        self.parent_id = parent.id if parent else self.parent_id
        if self._cannot_store():
            raise ValueError(
                "The file must have an (ID with a (path or `data_file_handle_id`)), or a "
                "(path with a (`parent_id` or parent with an id)), or a "
                "(data_file_handle_id with a (`parent_id` or parent with an id)) to store."
            )
        self.name = self.name or (guess_file_name(self.path) if self.path else None)
        client = Synapse.get_client(synapse_client=synapse_client)

        if existing_file := await self._find_existing_file(synapse_client=client):
            merge_dataclass_entities(
                source=existing_file,
                destination=self,
                fields_to_ignore=self._determine_fields_to_ignore_in_merge(),
            )

        if self.path:
            self.path = os.path.expanduser(self.path)
            async with client._get_parallel_file_transfer_semaphore(
                asyncio_event_loop=asyncio.get_running_loop()
            ):
                await self._upload_file(synapse_client=client)
        elif self.data_file_handle_id:
            self.path = client.cache.get(file_handle_id=self.data_file_handle_id)

        if self.has_changed:
            synapse_file = Synapse_File(
                id=self.id,
                path=self.path,
                description=self.description,
                etag=self.etag,
                name=self.name,
                parent=parent.id if parent else self.parent_id,
                contentType=self.content_type,
                contentSize=self.content_size,
                dataFileHandleId=self.data_file_handle_id,
                synapseStore=self.synapse_store,
                modifiedOn=self.modified_on,
                versionLabel=self.version_label,
                versionNumber=self.version_number,
                versionComment=self.version_comment,
            )
            delete_none_keys(synapse_file)

            entity = await store_entity(
                resource=self, entity=synapse_file, synapse_client=client
            )

            self.fill_from_dict(synapse_file=entity, set_annotations=False)

        re_read_required = await store_entity_components(
            root_resource=self, synapse_client=client
        )
        if re_read_required:
            before_download_file = self.download_file
            self.download_file = False
            await self.get_async(
                synapse_client=client,
            )
            self.download_file = before_download_file

        self._set_last_persistent_instance()

        client.logger.debug(f"Stored File {self.name}, id: {self.id}: {self.path}")
        # Clear the content_md5 so that it is recalculated if the file is updated
        self.content_md5 = None
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Change_Metadata: {self.id}"
    )
    async def change_metadata_async(
        self,
        name: Optional[str] = None,
        download_as: Optional[str] = None,
        content_type: Optional[str] = None,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Change File Entity metadata for properties that are immutable after creation
        through the store method.

        Arguments:
            name: Specify to change the filename of a file as seen on Synapse.
            download_as: Specify filename to change the filename of a filehandle.
            content_type: Specify content type to change the content type of a
                filehandle.
            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 file object.

        Example: Using this function
            Can be used to change the filename, the filename when the file is
            downloaded, or the file content-type without downloading:

                file_entity = await File(id="syn123", download_file=False).get_async()
                print(os.path.basename(file_entity.path))  ## prints, e.g., "my_file.txt"
                file_entity = await file_entity.change_metadata_async(name="my_new_name_file.txt", download_as="my_new_downloadAs_name_file.txt", content_type="text/plain")
                print(os.path.basename(file_entity.path))  ## prints, "my_new_downloadAs_name_file.txt"
                print(file_entity.name) ## prints, "my_new_name_file.txt"

        Raises:
            ValueError: If the file does not have an ID to change metadata.
        """
        if not self.id:
            raise ValueError("The file must have an ID to change metadata.")
        from synapseutils.copy_functions import changeFileMetaData

        loop = asyncio.get_event_loop()

        syn = Synapse.get_client(synapse_client=synapse_client)
        entity = await loop.run_in_executor(
            None,
            lambda: changeFileMetaData(
                syn=syn,
                entity=self.id,
                name=name,
                downloadAs=download_as,
                contentType=content_type,
                forceVersion=self.force_version,
            ),
        )

        self.fill_from_dict(synapse_file=entity, set_annotations=True)
        self._set_last_persistent_instance()
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Change metadata for file {self.name}, id: {self.id}: {self.path}"
        )
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Get: {self.id}, {self.path}"
    )
    async def get_async(
        self,
        include_activity: bool = False,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Get the file from Synapse. You may retrieve a File entity by either:

        - id
        - path


        If you specify both, the `id` will take precedence.


        If you specify the `path` and the file is stored in multiple locations in
        Synapse only the first one found will be returned. The other matching files
        will be printed to the console.


        You may also specify a `version_number` to get a specific version of the file.

        Arguments:
            include_activity: If True the activity will be included in the file
                if it exists.
            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 file object.

        Raises:
            ValueError: If the file does not have an ID or path to get.


        Example: Using this function
            Assuming you have a file with the ID "syn123":

                file_instance = await File(id="syn123").get_async()

            Assuming you want to download a file to this directory: "path/to/directory":

                file_instance = await File(path="path/to/directory").get_async()
        """
        if not self.id and not self.path:
            raise ValueError("The file must have an ID or path to get.")
        syn = Synapse.get_client(synapse_client=synapse_client)

        await self._load_local_md5()

        await get_from_entity_factory(
            entity_to_update=self,
            synapse_id_or_path=self.id or self.path,
            version=self.version_number,
            if_collision=self.if_collision,
            limit_search=self.synapse_container_limit or self.parent_id,
            download_file=self.download_file,
            download_location=os.path.dirname(self.path)
            if self.path and os.path.isfile(self.path)
            else self.path,
            md5=self.content_md5,
            synapse_client=syn,
        )

        if (
            self.data_file_handle_id
            and (not self.path or (self.path and not os.path.isfile(self.path)))
            and (cached_path := syn.cache.get(file_handle_id=self.data_file_handle_id))
        ):
            self.path = cached_path

        if include_activity:
            self.activity = await Activity.from_parent_async(
                parent=self, synapse_client=synapse_client
            )

        self._set_last_persistent_instance()
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Got file {self.name}, id: {self.id}, path: {self.path}"
        )
        return self

    @classmethod
    async def from_id_async(
        cls,
        synapse_id: str,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """Wrapper for [synapseclient.models.File.get][].

        Arguments:
            synapse_id: The ID of the file in Synapse.
            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 file object.

        Example: Using this function
            Assuming you have a file with the ID "syn123":

                file_instance = await File.from_id_async(synapse_id="syn123")
        """
        return await cls(id=synapse_id).get_async(
            synapse_client=synapse_client,
        )

    @classmethod
    async def from_path_async(
        cls,
        path: str,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """Get the file from Synapse. If the path of the file matches multiple files
        within Synapse the first one found will be returned. The other matching
        files will be printed to the console.


        Wrapper for [synapseclient.models.File.get][].

        Arguments:
            path: The path to the file on disk.
            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 file object.

        Example: Using this function
            Assuming you have a file at the path "path/to/file.txt":

                file_instance = await File.from_path_async(path="path/to/file.txt")
        """
        return await cls(path=path).get_async(
            synapse_client=synapse_client,
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Delete: {self.id}"
    )
    async def delete_async(
        self,
        version_only: Optional[bool] = False,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> None:
        """
        Delete the file from Synapse using the ID of the file.

        Arguments:
            version_only: If True only the version specified in the `version_number`
                attribute of the file will be deleted. If False the entire file will
                be deleted.
            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

        Raises:
            ValueError: If the file does not have an ID to delete.
            ValueError: If the file does not have a version number to delete a version,
                and `version_only` is True.

        Example: Using this function
            Assuming you have a file with the ID "syn123":

                await File(id="syn123").delete_async()
        """
        if not self.id:
            raise ValueError("The file must have an ID to delete.")
        if version_only and not self.version_number:
            raise ValueError("The file must have a version number to delete a version.")

        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).delete(
                obj=self.id,
                version=self.version_number if version_only else None,
            ),
        )
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Deleted file {self.id}"
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Copy: {self.id}"
    )
    async def copy_async(
        self,
        parent_id: str,
        update_existing: bool = False,
        copy_annotations: bool = True,
        copy_activity: Union[str, None] = "traceback",
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Copy the file to another Synapse location. Defaults to the latest version of the
        file, or the version_number specified in the instance.

        Arguments:
            parent_id: Synapse ID of a folder/project that the copied entity is being
                copied to
            update_existing: When the destination has a file that has the same name,
                users can choose to update that file.
            copy_annotations: True to copy the annotations.
            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 file object.

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

                new_file_instance = await File(id="syn123").copy_async(parent_id="syn456")

            Copy the file but do not persist annotations or activity:

                new_file_instance = await File(id="syn123").copy_async(parent_id="syn456", copy_annotations=False, copy_activity=None)

        Raises:
            ValueError: If the file does not have an ID and parent_id to copy.
        """
        if not self.id or not parent_id:
            raise ValueError("The file must have an ID and parent_id to copy.")
        from synapseutils.copy_functions import 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,
                version=self.version_number,
                entity=self.id,
                destinationId=parent_id,
                skipCopyAnnotations=not copy_annotations,
                updateExisting=update_existing,
                setProvenance=copy_activity,
            ),
        )

        parent_id = source_and_destination.get(self.id, None)
        if not parent_id:
            raise SynapseError("Failed to copy file.")
        file_copy = await File(id=parent_id, download_file=False).get_async(
            synapse_client=synapse_client
        )
        file_copy.download_file = True
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Copied from file {self.id} to {parent_id} with new id of {file_copy.id}"
        )
        return file_copy

    async def _needs_upload(self, syn: Synapse) -> bool:
        """
        Determines if a file needs to be uploaded to Synapse. The following conditions
        apply:

        - The file exists and is an ExternalFileHandle and the url has changed
        - The file exists and is a local file and the MD5 has changed
        - The file is not present in Synapse

        If the file is already specifying a data_file_handle_id then it is assumed that
        the file is already uploaded to Synapse. It does not need to be uploaded and
        the only thing that will occur is the File metadata will be added to Synapse
        outside of this upload process.

        Arguments:
            syn: 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:
            True if the file needs to be uploaded, otherwise False.
        """
        needs_upload = False
        # Check if the file should be uploaded
        if self._last_persistent_instance is not None:
            if (
                self.file_handle
                and self.file_handle.concrete_type
                == "org.sagebionetworks.repo.model.file.ExternalFileHandle"
            ):
                # switching away from ExternalFileHandle or the url was updated
                needs_upload = self.synapse_store or (
                    self.file_handle.external_url != self.external_url
                )
            else:
                # Check if we need to upload a new version of an existing
                # file. If the file referred to by entity['path'] has been
                # modified, we want to upload the new version.
                # If synapeStore is false then we must upload a ExternalFileHandle
                needs_upload = (
                    not self.synapse_store
                    or not self.file_handle
                    or not (
                        exists_in_cache := syn.cache.contains(
                            self.file_handle.id, self.path
                        )
                    )
                )

                md5_stored_in_synapse = (
                    self.file_handle.content_md5 if self.file_handle else None
                )

                # Check if we got an MD5 checksum from Synapse and compare it to the local file
                if (
                    self.synapse_store
                    and needs_upload
                    and os.path.isfile(self.path)
                    and md5_stored_in_synapse
                ):
                    await self._load_local_md5()
                    if md5_stored_in_synapse == (
                        local_file_md5_hex := self.content_md5
                    ):
                        needs_upload = False

                    # If we had a cache miss, but already uploaded to Synapse we
                    # can add the file to the cache.
                    if (
                        not exists_in_cache
                        and self.file_handle
                        and self.file_handle.id
                        and local_file_md5_hex
                    ):
                        syn.cache.add(
                            file_handle_id=self.file_handle.id,
                            path=self.path,
                            md5=local_file_md5_hex,
                        )
        elif self.data_file_handle_id is not None:
            needs_upload = False
        else:
            needs_upload = True
        return needs_upload

    async def _upload_file(
        self,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """The upload process for a file. This will upload the file to Synapse if it
        needs to be uploaded. If the file does not need to be uploaded the file
        metadata will be added to Synapse outside of this upload process.

        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 file object.
        """
        syn = Synapse.get_client(synapse_client=synapse_client)

        needs_upload = await self._needs_upload(syn=syn)

        if needs_upload:
            parent_id_for_upload = self.parent_id

            if not parent_id_for_upload:
                raise SynapseMalformedEntityError(
                    "Entities of type File must have a parentId."
                )

            updated_file_handle = await upload_file_handle(
                syn=syn,
                parent_entity_id=parent_id_for_upload,
                path=(
                    self.path
                    if (self.synapse_store or self.external_url is None)
                    else self.external_url
                ),
                synapse_store=self.synapse_store,
                md5=self.content_md5,
                file_size=self.content_size,
                mimetype=self.content_type,
            )

            self.file_handle = FileHandle().fill_from_dict(updated_file_handle)
            self._fill_from_file_handle()

        return self

    def _convert_into_legacy_file(self) -> SynapseFile:
        """Convert the file object into a SynapseFile object."""
        return_data = SynapseFile(
            id=self.id,
            name=self.name,
            description=self.description,
            etag=self.etag,
            createdOn=self.created_on,
            modifiedOn=self.modified_on,
            createdBy=self.created_by,
            modifiedBy=self.modified_by,
            parentId=self.parent_id,
            versionNumber=self.version_number,
            versionLabel=self.version_label,
            versionComment=self.version_comment,
            dataFileHandleId=self.data_file_handle_id,
            path=self.path,
            properties={
                "isLatestVersion": self.is_latest_version,
            },
            _file_handle=(
                self.file_handle._convert_into_legacy_file_handle()
                if self.file_handle
                else None
            ),
            annotations=self.annotations,
        )
        delete_none_keys(return_data)
        return return_data

Functions

get(include_activity=False, *, synapse_client=None)

Get the file from Synapse. You may retrieve a File entity by either:

  • id
  • path

If you specify both, the id will take precedence.

If you specify the path and the file is stored in multiple locations in Synapse only the first one found will be returned. The other matching files will be printed to the console.

You may also specify a version_number to get a specific version of the file.

PARAMETER DESCRIPTION
include_activity

If True the activity will be included in the file if it exists.

TYPE: bool DEFAULT: False

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
File

The file object.

RAISES DESCRIPTION
ValueError

If the file does not have an ID or path to get.

Using this function

Assuming you have a file with the ID "syn123":

file_instance = File(id="syn123").get()

Assuming you want to download a file to this directory: "path/to/directory":

file_instance = File(path="path/to/directory").get()
Source code in synapseclient/models/protocols/file_protocol.py
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
def get(
    self,
    include_activity: bool = False,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Get the file from Synapse. You may retrieve a File entity by either:

    - id
    - path


    If you specify both, the `id` will take precedence.


    If you specify the `path` and the file is stored in multiple locations in Synapse
    only the first one found will be returned. The other matching files will be
    printed to the console.


    You may also specify a `version_number` to get a specific version of the file.

    Arguments:
        include_activity: If True the activity will be included in the file if it exists.
        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 file object.

    Raises:
        ValueError: If the file does not have an ID or path to get.


    Example: Using this function
        Assuming you have a file with the ID "syn123":

            file_instance = File(id="syn123").get()

        Assuming you want to download a file to this directory: "path/to/directory":

            file_instance = File(path="path/to/directory").get()
    """
    return self

store(parent=None, *, synapse_client=None)

Store the file in Synapse. With this method you may:

  • Upload a file into Synapse
  • Update the metadata of a file in Synapse
  • Store a File object in Synapse without updating a file by setting synapse_store to False.
  • Change the name of a file in Synapse by setting the name attribute of the File object. Also see the synapseclient.models.File.change_metadata method for changing the name of the downloaded file.
  • Moving a file to a new parent by setting the parent_id attribute of the File object.
PARAMETER DESCRIPTION
parent

The parent folder or project to store the file in. May also be specified in the File object. If both are provided the parent passed into store will take precedence.

TYPE: Optional[Union[Folder, Project]] 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
File

The file object.

Using this function

File with the ID syn123 at path path/to/file.txt:

file_instance = File(id="syn123", path="path/to/file.txt").store()

File at the path path/to/file.txt and a parent folder with the ID syn456:

file_instance = File(path="path/to/file.txt", parent_id="syn456").store()

File at the path path/to/file.txt and a parent folder with the ID syn456:

file_instance = File(path="path/to/file.txt").store(parent=Folder(id="syn456"))

Rename a file (Does not update the file on disk or the name of the downloaded file):

file_instance = File(id="syn123", download_file=False).get()
print(file_instance.name)  ## prints, e.g., "my_file.txt"
file_instance.change_metadata(name="my_new_name_file.txt")

Rename a file, and the name of the file as downloaded (Does not update the file on disk):

file_instance = File(id="syn123", download_file=False).get()
print(file_instance.name)  ## prints, e.g., "my_file.txt"
file_instance.change_metadata(name="my_new_name_file.txt", download_as="my_new_name_file.txt")
Source code in synapseclient/models/protocols/file_protocol.py
20
21
22
23
24
25
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
def store(
    self,
    parent: Optional[Union["Folder", "Project"]] = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Store the file in Synapse. With this method you may:

    - Upload a file into Synapse
    - Update the metadata of a file in Synapse
    - Store a File object in Synapse without updating a file by setting
        `synapse_store` to False.
    - Change the name of a file in Synapse by setting the `name` attribute of the
        File object. Also see the [synapseclient.models.File.change_metadata][]
        method for changing the name of the downloaded file.
    - Moving a file to a new parent by setting the `parent_id` attribute of the
        File object.

    Arguments:
        parent: The parent folder or project to store the file in. May also be
            specified in the File object. If both are provided the parent passed
            into `store` will take precedence.
        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 file object.


    Example: Using this function
        File with the ID `syn123` at path `path/to/file.txt`:

            file_instance = File(id="syn123", path="path/to/file.txt").store()

        File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

            file_instance = File(path="path/to/file.txt", parent_id="syn456").store()

        File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

            file_instance = File(path="path/to/file.txt").store(parent=Folder(id="syn456"))

        Rename a file (Does not update the file on disk or the name of the downloaded file):

            file_instance = File(id="syn123", download_file=False).get()
            print(file_instance.name)  ## prints, e.g., "my_file.txt"
            file_instance.change_metadata(name="my_new_name_file.txt")

        Rename a file, and the name of the file as downloaded (Does not update the file on disk):

            file_instance = File(id="syn123", download_file=False).get()
            print(file_instance.name)  ## prints, e.g., "my_file.txt"
            file_instance.change_metadata(name="my_new_name_file.txt", download_as="my_new_name_file.txt")

    """
    return self

copy(parent_id, update_existing=False, copy_annotations=True, copy_activity='traceback', *, synapse_client=None)

Copy the file to another Synapse location. Defaults to the latest version of the file, or the version_number specified in the instance.

PARAMETER DESCRIPTION
parent_id

Synapse ID of a folder/project that the copied entity is being copied to

TYPE: str

update_existing

When the destination has a file that has the same name, users can choose to update that file.

TYPE: bool DEFAULT: False

copy_annotations

True to copy the annotations.

TYPE: bool DEFAULT: True

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

TYPE: Union[str, None] DEFAULT: 'traceback'

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
File

The copied file object.

Using this function

Assuming you have a file with the ID "syn123" and you want to copy it to a folder with the ID "syn456":

new_file_instance = File(id="syn123").copy(parent_id="syn456")

Copy the file but do not persist annotations or activity:

new_file_instance = File(id="syn123").copy(parent_id="syn456", copy_annotations=False, copy_activity=None)
RAISES DESCRIPTION
ValueError

If the file does not have an ID and parent_id to copy.

Source code in synapseclient/models/protocols/file_protocol.py
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
def copy(
    self,
    parent_id: str,
    update_existing: bool = False,
    copy_annotations: bool = True,
    copy_activity: Union[str, None] = "traceback",
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Copy the file to another Synapse location. Defaults to the latest version of the
    file, or the version_number specified in the instance.

    Arguments:
        parent_id: Synapse ID of a folder/project that the copied entity is being
            copied to
        update_existing: When the destination has a file that has the same name,
            users can choose to update that file.
        copy_annotations: True to copy the annotations.
        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 file object.

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

            new_file_instance = File(id="syn123").copy(parent_id="syn456")

        Copy the file but do not persist annotations or activity:

            new_file_instance = File(id="syn123").copy(parent_id="syn456", copy_annotations=False, copy_activity=None)

    Raises:
        ValueError: If the file does not have an ID and parent_id to copy.
    """
    from synapseclient.models import File

    return File()

delete(version_only=False, *, synapse_client=None)

Delete the file from Synapse.

PARAMETER DESCRIPTION
version_only

If True only the version specified in the version_number attribute of the file will be deleted. If False the entire file will be deleted.

TYPE: Optional[bool] DEFAULT: False

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

RAISES DESCRIPTION
ValueError

If the file does not have an ID to delete.

ValueError

If the file does not have a version number to delete a version, and version_only is True.

Using this function

Assuming you have a file with the ID "syn123":

File(id="syn123").delete()
Source code in synapseclient/models/protocols/file_protocol.py
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
def delete(
    self,
    version_only: Optional[bool] = False,
    *,
    synapse_client: Optional[Synapse] = None,
) -> None:
    """Delete the file from Synapse.

    Arguments:
        version_only: If True only the version specified in the `version_number`
            attribute of the file will be deleted. If False the entire file will
            be deleted.
        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

    Raises:
        ValueError: If the file does not have an ID to delete.
        ValueError: If the file does not have a version number to delete a version,
            and `version_only` is True.

    Example: Using this function
        Assuming you have a file with the ID "syn123":

            File(id="syn123").delete()
    """
    return None

from_id(synapse_id, *, synapse_client=None) classmethod

Wrapper for synapseclient.models.File.get.

PARAMETER DESCRIPTION
synapse_id

The ID of the file in Synapse.

TYPE: str

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
File

The file object.

Using this function

Assuming you have a file with the ID "syn123":

file_instance = File.from_id(synapse_id="syn123")
Source code in synapseclient/models/protocols/file_protocol.py
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
@classmethod
def from_id(
    cls,
    synapse_id: str,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """Wrapper for [synapseclient.models.File.get][].

    Arguments:
        synapse_id: The ID of the file in Synapse.
        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 file object.

    Example: Using this function
        Assuming you have a file with the ID "syn123":

            file_instance = File.from_id(synapse_id="syn123")
    """
    from synapseclient.models import File

    return File()

from_path(path, *, synapse_client=None) classmethod

Get the file from Synapse. If the path of the file matches multiple files within Synapse the first one found will be returned. The other matching files will be printed to the console.

Wrapper for synapseclient.models.File.get.

PARAMETER DESCRIPTION
path

The path to the file on disk.

TYPE: str

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
File

The file object.

Using this function

Assuming you have a file at the path "path/to/file.txt":

file_instance = File.from_path(path="path/to/file.txt")
Source code in synapseclient/models/protocols/file_protocol.py
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
@classmethod
def from_path(
    cls,
    path: str,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """Get the file from Synapse. If the path of the file matches multiple files
    within Synapse the first one found will be returned. The other matching
    files will be printed to the console.


    Wrapper for [synapseclient.models.File.get][].

    Arguments:
        path: The path to the file on disk.
        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 file object.

    Example: Using this function
        Assuming you have a file at the path "path/to/file.txt":

            file_instance = File.from_path(path="path/to/file.txt")
    """
    from synapseclient.models import File

    return File()

change_metadata(name=None, download_as=None, content_type=None, *, synapse_client=None)

Change File Entity metadata for properties that are immutable after creation through the store method.

PARAMETER DESCRIPTION
name

Specify to change the filename of a file as seen on Synapse.

TYPE: Optional[str] DEFAULT: None

download_as

Specify filename to change the filename of a filehandle.

TYPE: Optional[str] DEFAULT: None

content_type

Specify content type to change the content type of a filehandle.

TYPE: Optional[str] 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
File

The file object.

Using this function

Can be used to change the filename, the filename when the file is downloaded, or the file content-type without downloading:

file_entity = File(id="syn123", download_file=False).get()
print(os.path.basename(file_entity.path))  ## prints, e.g., "my_file.txt"
file_entity = file_entity.change_metadata(name="my_new_name_file.txt", download_as="my_new_downloadAs_name_file.txt", content_type="text/plain")
print(os.path.basename(file_entity.path))  ## prints, "my_new_downloadAs_name_file.txt"
print(file_entity.name) ## prints, "my_new_name_file.txt"
RAISES DESCRIPTION
ValueError

If the file does not have an ID to change metadata.

Source code in synapseclient/models/protocols/file_protocol.py
 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
def change_metadata(
    self,
    name: Optional[str] = None,
    download_as: Optional[str] = None,
    content_type: Optional[str] = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Change File Entity metadata for properties that are immutable after creation
    through the store method.

    Arguments:
        name: Specify to change the filename of a file as seen on Synapse.
        download_as: Specify filename to change the filename of a filehandle.
        content_type: Specify content type to change the content type of a
            filehandle.
        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 file object.

    Example: Using this function
        Can be used to change the filename, the filename when the file is downloaded, or the file content-type without downloading:

            file_entity = File(id="syn123", download_file=False).get()
            print(os.path.basename(file_entity.path))  ## prints, e.g., "my_file.txt"
            file_entity = file_entity.change_metadata(name="my_new_name_file.txt", download_as="my_new_downloadAs_name_file.txt", content_type="text/plain")
            print(os.path.basename(file_entity.path))  ## prints, "my_new_downloadAs_name_file.txt"
            print(file_entity.name) ## prints, "my_new_name_file.txt"

    Raises:
        ValueError: If the file does not have an ID to change metadata.
    """
    return self

get_permissions(*, synapse_client=None)

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 = File(id="syn123").get_permissions()

Getting access types list from the Permissions object

permissions.access_types
Source code in synapseclient/models/protocols/access_control_protocol.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def get_permissions(
    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 = File(id="syn123").get_permissions()

        Getting access types list from the Permissions object

            permissions.access_types
    """
    return self

get_acl(principal_id=None, *, synapse_client=None)

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/protocols/access_control_protocol.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def get_acl(
    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
    """
    return [""]

set_permissions(principal_id=None, access_type=None, modify_benefactor=False, warn_if_inherits=True, overwrite=True, *, synapse_client=None)

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

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

Grant the public view access

File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
Source code in synapseclient/models/protocols/access_control_protocol.py
 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
def set_permissions(
    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

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

        Grant the public view access

            File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
    """
    return {}

synapseclient.models.file.FileHandle dataclass

A file handle is a pointer to a file stored in a specific location.

ATTRIBUTE DESCRIPTION
id

The ID of this FileHandle. All references to this FileHandle will use this ID. Synapse will generate this ID when the FileHandle is created.

TYPE: Optional[str]

etag

FileHandles are immutable from the perspective of the API. The only field that can be change is the previewId. When a new previewId is set, the etag will change.

TYPE: Optional[str]

created_by

The ID Of the user that created this file.

TYPE: Optional[str]

created_on

The date when this file was uploaded.

TYPE: Optional[str]

modified_on

The date when the file was modified. This is handled by the backend and cannot be modified.

TYPE: Optional[str]

concrete_type

This is used to indicate the implementation of this interface. For example, an S3FileHandle should be set to: org.sagebionetworks.repo.model.file.S3FileHandle

TYPE: Optional[str]

content_type

TYPE: Optional[str]

content_md5

The file's content MD5.

TYPE: Optional[str]

file_name

The short, user visible name for this file.

TYPE: Optional[str]

storage_location_id

The optional storage location descriptor.

TYPE: Optional[int]

content_size

The size of the file in bytes.

TYPE: Optional[int]

status

The status of the file handle as computed by the backend. This value cannot be changed, any file handle that is not AVAILABLE should not be used.

TYPE: Optional[str]

bucket_name

The name of the bucket where this file resides.

TYPE: Optional[str]

key

The path or resource name for this object.

TYPE: Optional[str]

preview_id

If this file has a preview, then this will be the file ID of the preview.

TYPE: Optional[str]

is_preview

Whether or not this is a preview of another file.

TYPE: Optional[bool]

external_url

The URL of the file if it is stored externally.

TYPE: Optional[str]

Source code in synapseclient/models/file.py
 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
@dataclass()
class FileHandle:
    """A file handle is a pointer to a file stored in a specific location.

    Attributes:
        id: The ID of this FileHandle. All references to this FileHandle will use this
            ID. Synapse will generate this ID when the FileHandle is created.
        etag: FileHandles are immutable from the perspective of the API. The only field
            that can be change is the previewId. When a new previewId is set, the
            etag will change.
        created_by: The ID Of the user that created this file.
        created_on: The date when this file was uploaded.
        modified_on: The date when the file was modified. This is handled by the backend
            and cannot be modified.
        concrete_type: This is used to indicate the implementation of this interface.
            For example, an S3FileHandle should be set to:
            org.sagebionetworks.repo.model.file.S3FileHandle
        content_type: Must be: <http://en.wikipedia.org/wiki/Internet_media_type>.
        content_md5: The file's content MD5.
        file_name: The short, user visible name for this file.
        storage_location_id: The optional storage location descriptor.
        content_size: The size of the file in bytes.
        status: The status of the file handle as computed by the backend. This value
            cannot be changed, any file handle that is not AVAILABLE should not be used.
        bucket_name: The name of the bucket where this file resides.
        key: The path or resource name for this object.
        preview_id: If this file has a preview, then this will be the file ID of the
            preview.
        is_preview: Whether or not this is a preview of another file.
        external_url: The URL of the file if it is stored externally.
    """

    id: Optional[str] = None
    """The ID of this FileHandle. All references to this FileHandle will use this ID.
        Synapse will generate this ID when the FileHandle is created."""

    etag: Optional[str] = None
    """
    FileHandles are immutable from the perspective of the API. The only field that can
    be change is the previewId. When a new previewId is set, the etag will change.
    """

    created_by: Optional[str] = None
    """The ID Of the user that created this file."""

    created_on: Optional[str] = None
    """The date when this file was uploaded."""

    modified_on: Optional[str] = None
    """The date when the file was modified. This is handled by the backend and cannot
    be modified."""

    concrete_type: Optional[str] = None
    """
    This is used to indicate the implementation of this interface. For example,
    an S3FileHandle should be set to: org.sagebionetworks.repo.model.file.S3FileHandle
    """

    content_type: Optional[str] = None
    """Must be: <http://en.wikipedia.org/wiki/Internet_media_type>."""

    content_md5: Optional[str] = None
    """The file's content MD5."""

    file_name: Optional[str] = None
    """The short, user visible name for this file."""

    storage_location_id: Optional[int] = None
    """The optional storage location descriptor."""

    content_size: Optional[int] = None
    """The size of the file in bytes."""

    status: Optional[str] = None
    """The status of the file handle as computed by the backend. This value cannot be
    changed, any file handle that is not AVAILABLE should not be used."""

    bucket_name: Optional[str] = None
    """The name of the bucket where this file resides."""

    key: Optional[str] = None
    """The path or resource name for this object."""

    preview_id: Optional[str] = None
    """If this file has a preview, then this will be the file ID of the preview."""

    is_preview: Optional[bool] = None
    """Whether or not this is a preview of another file."""

    external_url: Optional[str] = None
    """The URL of the file if it is stored externally."""

    def fill_from_dict(
        self, synapse_instance: Dict[str, Union[bool, str, int]]
    ) -> "FileHandle":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_instance: The response from the REST API.
            set_annotations: Whether to set the annotations from the response.

        Returns:
            The File object.
        """
        file_handle = self or FileHandle()
        file_handle.id = synapse_instance.get("id", None)
        file_handle.etag = synapse_instance.get("etag", None)
        file_handle.created_by = synapse_instance.get("createdBy", None)
        file_handle.created_on = synapse_instance.get("createdOn", None)
        file_handle.modified_on = synapse_instance.get("modifiedOn", None)
        file_handle.concrete_type = synapse_instance.get("concreteType", None)
        file_handle.content_type = synapse_instance.get("contentType", None)
        file_handle.content_md5 = synapse_instance.get("contentMd5", None)
        file_handle.file_name = synapse_instance.get("fileName", None)
        file_handle.storage_location_id = synapse_instance.get(
            "storageLocationId", None
        )
        file_handle.content_size = synapse_instance.get("contentSize", None)
        file_handle.status = synapse_instance.get("status", None)
        file_handle.bucket_name = synapse_instance.get("bucketName", None)
        file_handle.key = synapse_instance.get("key", None)
        file_handle.preview_id = synapse_instance.get("previewId", None)
        file_handle.is_preview = synapse_instance.get("isPreview", None)
        file_handle.external_url = synapse_instance.get("externalURL", None)

        return self

    def _convert_into_legacy_file_handle(self) -> Dict[str, Union[str, bool, int]]:
        """Convert the file handle object into a legacy File Handle object."""
        return_data = {
            "id": self.id,
            "etag": self.etag,
            "createdBy": self.created_by,
            "createdOn": self.created_on,
            "modifiedOn": self.modified_on,
            "concreteType": self.concrete_type,
            "contentType": self.content_type,
            "contentMd5": self.content_md5,
            "fileName": self.file_name,
            "storageLocationId": self.storage_location_id,
            "contentSize": self.content_size,
            "status": self.status,
            "bucketName": self.bucket_name,
            "key": self.key,
            "previewId": self.preview_id,
            "isPreview": self.is_preview,
            "externalURL": self.external_url,
        }
        delete_none_keys(return_data)
        return return_data

synapseclient.models.Table dataclass

Bases: TableSynchronousProtocol, AccessControllable

A Table represents the metadata of a table.

ATTRIBUTE DESCRIPTION
id

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

TYPE: Optional[str]

name

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

TYPE: Optional[str]

parent_id

The ID of the Entity that is the parent of this table.

TYPE: Optional[str]

columns

The columns of this table.

TYPE: Optional[List[Column]]

description

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

TYPE: Optional[List[Column]]

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 table was created.

TYPE: Optional[str]

created_by

The ID of the user that created this table.

TYPE: Optional[str]

modified_on

The date this table was last modified. In YYYY-MM-DD-Thh:mm:ss.sssZ format

TYPE: Optional[str]

modified_by

The ID of the user that last modified this table.

TYPE: Optional[str]

version_number

The version number issued to this version on the object.

TYPE: Optional[int]

version_label

The version label for this table

TYPE: Optional[str]

version_comment

The version comment for this table

TYPE: Optional[str]

is_latest_version

If this is the latest version of the object.

TYPE: Optional[bool]

is_search_enabled

When creating or updating a table or view specifies if full text search should be enabled. Note that enabling full text search might slow down the indexing of the table or view.

TYPE: Optional[bool]

activity

The Activity model represents the main record of Provenance in Synapse. It is analygous to the Activity defined in the W3C Specification on Provenance. Activity cannot be removed during a store operation by setting it to None. You must use: synapseclient.models.Activity.delete_async or [synapseclient.models.Activity.disassociate_from_entity_async][].

TYPE: Optional[Activity]

annotations

Additional metadata associated with the table. 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]]]]

Source code in synapseclient/models/table.py
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
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
@dataclass()
@async_to_sync
class Table(TableSynchronousProtocol, AccessControllable):
    """A Table represents the metadata of a table.

    Attributes:
        id: The unique immutable ID for this table. A new ID will be generated for new
            Tables. Once issued, this ID is guaranteed to never change or be re-issued
        name: The name of this table. Must be 256 characters or less. Names may only
            contain: letters, numbers, spaces, underscores, hyphens, periods, plus
            signs, apostrophes, and parentheses
        parent_id: The ID of the Entity that is the parent of this table.
        columns: The columns of this table.
        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 table was created.
        created_by: The ID of the user that created this table.
        modified_on: The date this table was last modified.
            In YYYY-MM-DD-Thh:mm:ss.sssZ format
        modified_by: The ID of the user that last modified this table.
        version_number: The version number issued to this version on the object.
        version_label: The version label for this table
        version_comment: The version comment for this table
        is_latest_version: If this is the latest version of the object.
        is_search_enabled: When creating or updating a table or view specifies if full
            text search should be enabled. Note that enabling full text search might
            slow down the indexing of the table or view.
        activity: The Activity model represents the main record of Provenance in
            Synapse. It is analygous to the Activity defined in the
            [W3C Specification](https://www.w3.org/TR/prov-n/) on Provenance. Activity
            cannot be removed during a store operation by setting it to None. You must
            use: [synapseclient.models.Activity.delete_async][] or
            [synapseclient.models.Activity.disassociate_from_entity_async][].
        annotations: Additional metadata associated with the table. 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.

    """

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

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

    parent_id: Optional[str] = None
    """The ID of the Entity that is the parent of this table."""

    columns: Optional[List[Column]] = None

    # TODO: Description doesn't seem to be returned from the API. Look into why.
    # 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] = None
    """The date this table was created."""

    created_by: Optional[str] = None
    """The ID of the user that created this table."""

    modified_on: Optional[str] = None
    """The date this table was last modified. In YYYY-MM-DD-Thh:mm:ss.sssZ format"""

    modified_by: Optional[str] = None
    """The ID of the user that last modified this table."""

    version_number: Optional[int] = None
    """The version number issued to this version on the object."""

    version_label: Optional[str] = None
    """The version label for this table"""

    version_comment: Optional[str] = None
    """The version comment for this table"""

    is_latest_version: Optional[bool] = None
    """If this is the latest version of the object."""

    is_search_enabled: Optional[bool] = None
    """When creating or updating a table or view specifies if full text search
    should be enabled. Note that enabling full text search might slow down the
    indexing of the table or view."""

    activity: Optional[Activity] = None
    """The Activity model represents the main record of Provenance in Synapse.  It is
    analygous to the Activity defined in the
    [W3C Specification](https://www.w3.org/TR/prov-n/) on Provenance. Activity cannot
    be removed during a store operation by setting it to None. You must use:
    [synapseclient.models.Activity.delete_async][] or
    [synapseclient.models.Activity.disassociate_from_entity_async][].
    """

    annotations: Optional[
        Dict[
            str,
            Union[
                List[str],
                List[bool],
                List[float],
                List[int],
                List[date],
                List[datetime],
            ],
        ]
    ] = field(default_factory=dict)
    """Additional metadata associated with the table. 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."""

    def fill_from_dict(
        self, synapse_table: Synapse_Table, set_annotations: bool = True
    ) -> "Table":
        """Converts the data coming from the Synapse API into this datamodel.

        :param synapse_table: The data coming from the Synapse API
        """
        self.id = synapse_table.get("id", None)
        self.name = synapse_table.get("name", None)
        self.parent_id = synapse_table.get("parentId", None)
        # TODO: Description doesn't seem to be returned from the API. Look into why.
        # self.description = synapse_table.description
        self.etag = synapse_table.get("etag", None)
        self.created_on = synapse_table.get("createdOn", None)
        self.created_by = synapse_table.get("createdBy", None)
        self.modified_on = synapse_table.get("modifiedOn", None)
        self.modified_by = synapse_table.get("modifiedBy", None)
        self.version_number = synapse_table.get("versionNumber", None)
        self.version_label = synapse_table.get("versionLabel", None)
        self.version_comment = synapse_table.get("versionComment", None)
        self.is_latest_version = synapse_table.get("isLatestVersion", None)
        self.is_search_enabled = synapse_table.get("isSearchEnabled", False)
        self.columns = [
            Column(id=columnId, name=None, column_type=None)
            for columnId in synapse_table.get("columnIds", [])
        ]
        if set_annotations:
            self.annotations = Annotations.from_dict(
                synapse_table.get("annotations", {})
            )
        return self

    @otel_trace_method(
        method_to_trace_name=lambda _, **kwargs: f"Store_rows_by_csv: {kwargs.get('csv_path', None)}"
    )
    async def store_rows_from_csv_async(
        self, csv_path: str, *, synapse_client: Optional[Synapse] = None
    ) -> str:
        """Takes in a path to a CSV and stores the rows to Synapse.

        Arguments:
            csv_path: The path to the CSV to store.
            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 path to the CSV that was stored.
        """
        synapse_table = Synapse_Table(schema=self.id, values=csv_path)
        loop = asyncio.get_event_loop()
        entity = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).store(
                obj=synapse_table
            ),
        )
        print(entity)
        # TODO: What should this return?
        return csv_path

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Delete_rows: {self.name}"
    )
    async def delete_rows_async(
        self, rows: List[Row], *, synapse_client: Optional[Synapse] = None
    ) -> None:
        """Delete rows from a table.

        Arguments:
            rows: The rows to delete.
            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
        """
        rows_to_delete = []
        for row in rows:
            rows_to_delete.append([row.row_id, row.version_number])
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: delete_rows(
                syn=Synapse.get_client(synapse_client=synapse_client),
                table_id=self.id,
                row_id_vers_list=rows_to_delete,
            ),
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Table_Schema_Store: {self.name}"
    )
    async def store_schema_async(
        self, *, synapse_client: Optional[Synapse] = None
    ) -> "Table":
        """Store non-row information about a table including the columns and annotations.

        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 Table instance stored in synapse.
        """
        tasks = []
        if self.columns:
            # TODO: When a table is retrieved via `.get()` we create Column objects but
            # TODO: We only have the ID attribute. THis is causing this if check to eval
            # TODO: To True, however, we aren't actually modifying the column.
            # TODO: Perhaps we should have a `has_changed` boolean on all dataclasses
            # TODO: That we can check to see if we need to store the data.
            tasks.extend(
                column.store_async(synapse_client=synapse_client)
                for column in self.columns
            )
            try:
                results = await asyncio.gather(*tasks, return_exceptions=True)

                # TODO: Proper exception handling
                for result in results:
                    if isinstance(result, Column):
                        print(f"Stored {result.name}")
                    else:
                        if isinstance(result, BaseException):
                            raise result
                        raise ValueError(f"Unknown type: {type(result)}", result)
            except Exception as ex:
                Synapse.get_client(synapse_client=synapse_client).logger.exception(ex)
                print("I hit an exception")

        synapse_schema = Synapse_Schema(
            name=self.name,
            columns=self.columns,
            parent=self.parent_id,
        )
        trace.get_current_span().set_attributes(
            {
                "synapse.name": self.name or "",
                "synapse.id": self.id or "",
            }
        )
        loop = asyncio.get_event_loop()
        entity = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).store(
                obj=synapse_schema
            ),
        )

        self.fill_from_dict(synapse_table=entity, set_annotations=False)

        re_read_required = await store_entity_components(
            root_resource=self, synapse_client=synapse_client
        )
        if re_read_required:
            await self.get_async(
                synapse_client=synapse_client,
            )

        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Table_Get: {self.name}"
    )
    async def get_async(self, *, synapse_client: Optional[Synapse] = None) -> "Table":
        """Get the metadata about the table 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 Table instance stored in synapse.
        """
        # TODO: How do we want to support retriving the table? Do we want to support by name, and parent?
        loop = asyncio.get_event_loop()
        entity = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).get(
                entity=self.id
            ),
        )
        self.fill_from_dict(synapse_table=entity, set_annotations=True)
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Table_Delete: {self.name}"
    )
    # TODO: Synapse allows immediate deletion of entities, but the Synapse Client does not
    # TODO: Should we support immediate deletion?
    async def delete_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
        """Delete the table 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
        """
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).delete(
                obj=self.id
            ),
        )

    @classmethod
    async def query_async(
        cls,
        query: str,
        result_format: Union[CsvResultFormat, RowsetResultFormat] = CsvResultFormat(),
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> Union[Synapse_CsvFileTable, Synaspe_TableQueryResult]:
        """Query for data on a table stored in Synapse.

        Arguments:
            query: The query to run.
            result_format: The format of the results. Defaults to CsvResultFormat().
            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 results of the query.
        """
        loop = asyncio.get_event_loop()

        # TODO: Future Idea - We stream back a CSV, and let those reading this to handle the CSV however they want
        results = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).tableQuery(
                query=query,
                **result_format.to_dict(),
            ),
        )
        print(results)
        return results

Functions

get(*, synapse_client=None)

Get the metadata about the table 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
Table

The Table instance stored in synapse.

Source code in synapseclient/models/protocols/table_protocol.py
88
89
90
91
92
93
94
95
96
97
98
99
def get(self, *, synapse_client: Optional[Synapse] = None) -> "Table":
    """Get the metadata about the table 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 Table instance stored in synapse.
    """
    return self

store_schema(*, synapse_client=None)

Store non-row information about a table including the columns and annotations.

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
Table

The Table instance stored in synapse.

Source code in synapseclient/models/protocols/table_protocol.py
75
76
77
78
79
80
81
82
83
84
85
86
def store_schema(self, *, synapse_client: Optional[Synapse] = None) -> "Table":
    """Store non-row information about a table including the columns and annotations.

    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 Table instance stored in synapse.
    """
    return self

store_rows_from_csv(csv_path, *, synapse_client=None)

Takes in a path to a CSV and stores the rows to Synapse.

PARAMETER DESCRIPTION
csv_path

The path to the CSV to store.

TYPE: str

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
str

The path to the CSV that was stored.

Source code in synapseclient/models/protocols/table_protocol.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def store_rows_from_csv(
    self, csv_path: str, *, synapse_client: Optional[Synapse] = None
) -> str:
    """Takes in a path to a CSV and stores the rows to Synapse.

    Arguments:
        csv_path: The path to the CSV to store.
        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 path to the CSV that was stored.
    """
    return ""

delete_rows(rows, *, synapse_client=None)

Delete rows from a table.

PARAMETER DESCRIPTION
rows

The rows to delete.

TYPE: List[Row]

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

Source code in synapseclient/models/protocols/table_protocol.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def delete_rows(
    self, rows: List["Row"], *, synapse_client: Optional[Synapse] = None
) -> None:
    """Delete rows from a table.

    Arguments:
        rows: The rows to delete.
        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
    """
    return None

query(query, result_format=None, *, synapse_client=None) classmethod

Query for data on a table stored in Synapse.

PARAMETER DESCRIPTION
query

The query to run.

TYPE: str

result_format

The format of the results. Defaults to CsvResultFormat().

TYPE: Union[CsvResultFormat, RowsetResultFormat] 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
Union[CsvFileTable, TableQueryResult, None]

The results of the query.

Source code in synapseclient/models/protocols/table_protocol.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
@classmethod
def query(
    cls,
    query: str,
    result_format: Union["CsvResultFormat", "RowsetResultFormat"] = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> Union[Synapse_CsvFileTable, Synaspe_TableQueryResult, None]:
    """Query for data on a table stored in Synapse.

    Arguments:
        query: The query to run.
        result_format: The format of the results. Defaults to CsvResultFormat().
        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 results of the query.
    """
    return None

delete(*, synapse_client=None)

Delete the table 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

Source code in synapseclient/models/protocols/table_protocol.py
101
102
103
104
105
106
107
108
109
110
111
112
def delete(self, *, synapse_client: Optional[Synapse] = None) -> None:
    """Delete the table 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
    """
    return None

get_permissions(*, synapse_client=None)

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 = File(id="syn123").get_permissions()

Getting access types list from the Permissions object

permissions.access_types
Source code in synapseclient/models/protocols/access_control_protocol.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def get_permissions(
    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 = File(id="syn123").get_permissions()

        Getting access types list from the Permissions object

            permissions.access_types
    """
    return self

get_acl(principal_id=None, *, synapse_client=None)

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/protocols/access_control_protocol.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def get_acl(
    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
    """
    return [""]

set_permissions(principal_id=None, access_type=None, modify_benefactor=False, warn_if_inherits=True, overwrite=True, *, synapse_client=None)

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

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

Grant the public view access

File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
Source code in synapseclient/models/protocols/access_control_protocol.py
 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
def set_permissions(
    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

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

        Grant the public view access

            File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
    """
    return {}

synapseclient.models.Activity dataclass

Bases: ActivitySynchronousProtocol

An activity is a Synapse object that helps to keep track of what objects were used in an analysis step, as well as what objects were generated. Thus, all relationships between Synapse objects and an activity are governed by dependencies. That is, an activity needs to know what it used, and outputs need to know what activity they were generatedBy.

ATTRIBUTE DESCRIPTION
id

The unique immutable ID for this actvity.

TYPE: Optional[str]

name

A name for this Activity.

TYPE: Optional[str]

description

A description for this Activity.

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 object was created.

TYPE: Optional[str]

modified_on

The date this object was last modified.

TYPE: Optional[str]

created_by

The user that created this object.

TYPE: Optional[str]

modified_by

The user that last modified this object.

TYPE: Optional[str]

used

The entities or URLs used by this Activity.

TYPE: List[Union[UsedEntity, UsedURL]]

executed

The entities or URLs executed by this Activity.

TYPE: List[Union[UsedEntity, UsedURL]]

Source code in synapseclient/models/activity.py
 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
@dataclass
@async_to_sync
class Activity(ActivitySynchronousProtocol):
    """
    An activity is a Synapse object that helps to keep track of what objects were used
    in an analysis step, as well as what objects were generated. Thus, all relationships
    between Synapse objects and an activity are governed by dependencies. That is, an
    activity needs to know what it `used`, and outputs need to know what activity
    they were `generatedBy`.

    Attributes:
        id: The unique immutable ID for this actvity.
        name: A name for this Activity.
        description: A description for this Activity.
        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 object was created.
        modified_on: The date this object was last modified.
        created_by: The user that created this object.
        modified_by: The user that last modified this object.
        used: The entities or URLs used by this Activity.
        executed: The entities or URLs executed by this Activity.
    """

    id: Optional[str] = None
    """The unique immutable ID for this actvity."""

    name: Optional[str] = None
    """A name for this Activity."""

    description: Optional[str] = None
    """A description for this Activity."""

    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] = None
    """The date this object was created."""

    modified_on: Optional[str] = None
    """The date this object was last modified."""

    created_by: Optional[str] = None
    """The user that created this object."""

    modified_by: Optional[str] = None
    """The user that last modified this object."""

    used: List[Union[UsedEntity, UsedURL]] = field(default_factory=list)
    """The entities used by this Activity."""

    executed: List[Union[UsedEntity, UsedURL]] = field(default_factory=list)
    """The entities executed by this Activity."""

    def fill_from_dict(
        self, synapse_activity: Union[Synapse_Activity, Dict]
    ) -> "Activity":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_activity: The response from the REST API.

        Returns:
            The Activity object.
        """
        if not synapse_activity:
            synapse_activity = {}
        self.id = synapse_activity.get("id", None)
        self.name = synapse_activity.get("name", None)
        self.description = synapse_activity.get("description", None)
        self.etag = synapse_activity.get("etag", None)
        self.created_on = synapse_activity.get("createdOn", None)
        self.modified_on = synapse_activity.get("modifiedOn", None)
        self.created_by = synapse_activity.get("createdBy", None)
        self.modified_by = synapse_activity.get("modifiedBy", None)
        self.executed = []
        self.used = []
        for used in synapse_activity.get("used", []):
            concrete_type = used.get("concreteType", None)
            if USED_URL == concrete_type:
                used_url = UsedURL(
                    name=used.get("name", None),
                    url=used.get("url", None),
                )

                if used.get("wasExecuted", False):
                    self.executed.append(used_url)
                else:
                    self.used.append(used_url)
            elif USED_ENTITY == concrete_type:
                reference = used.get("reference", {})
                used_entity = UsedEntity(
                    target_id=reference.get("targetId", None),
                    target_version_number=reference.get("targetVersionNumber", None),
                )

                if used.get("wasExecuted", False):
                    self.executed.append(used_entity)
                else:
                    self.used.append(used_entity)

        return self

    def _create_used_and_executed_synapse_activities(
        self,
    ) -> UsedAndExecutedSynapseActivities:
        """
        Helper function to create the used and executed activities for the
        Synapse Activity.

        Returns:
            A tuple of the used and executed activities.
        """
        synapse_activity_used = []
        synapse_activity_executed = []

        for used in self.used:
            if isinstance(used, UsedEntity):
                synapse_activity_used.append(
                    {
                        "reference": {
                            "targetId": used.target_id,
                            "targetVersionNumber": used.target_version_number,
                        }
                    }
                )
            elif isinstance(used, UsedURL):
                synapse_activity_used.append(
                    {
                        "name": used.name,
                        "url": used.url,
                    }
                )

        for executed in self.executed:
            if isinstance(executed, UsedEntity):
                synapse_activity_executed.append(
                    {
                        "reference": {
                            "targetId": executed.target_id,
                            "targetVersionNumber": executed.target_version_number,
                        },
                        "wasExecuted": True,
                    }
                )
            elif isinstance(executed, UsedURL):
                synapse_activity_executed.append(
                    {"name": executed.name, "url": executed.url, "wasExecuted": True}
                )
        return UsedAndExecutedSynapseActivities(
            used=synapse_activity_used, executed=synapse_activity_executed
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Activity_store: {self.name}"
    )
    async def store_async(
        self,
        parent: Optional[Union["Table", "File"]] = None,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "Activity":
        """
        Store the Activity in Synapse.

        Arguments:
            parent: The parent entity to associate this activity with.
            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 activity object.

        Raises:
            ValueError: Raised if both of the following are true:

                - If the parent does not have an ID.
                - If the Activity does not have an ID and ETag.
        """
        # TODO: Input validation: SYNPY-1400
        used_and_executed_activities = (
            self._create_used_and_executed_synapse_activities()
        )

        synapse_activity = Synapse_Activity(
            name=self.name,
            description=self.description,
            used=used_and_executed_activities.used,
            executed=used_and_executed_activities.executed,
        )

        loop = asyncio.get_event_loop()
        if self.id:
            # Despite init in `Synapse_Activity` not accepting an ID/ETAG the
            # `updateActivity` method expects that it exists on the dict
            # and `setProvenance` accepts it as well.
            synapse_activity["id"] = self.id
            synapse_activity["etag"] = self.etag
        if parent:
            saved_activity = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(synapse_client=synapse_client).setProvenance(
                    entity=parent.id,
                    activity=synapse_activity,
                ),
            )
        else:
            saved_activity = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(
                    synapse_client=synapse_client
                ).updateActivity(
                    activity=synapse_activity,
                ),
            )
        self.fill_from_dict(synapse_activity=saved_activity)
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Stored activity {self.id}"
        )

        return self

    @classmethod
    async def from_parent_async(
        cls,
        parent: Union["Table", "File"],
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> Union["Activity", None]:
        """
        Get the Activity from Synapse based on the parent entity.

        Arguments:
            parent: The parent entity this activity is associated with. The parent may
                also have a version_number. Gets the most recent version if version is
                omitted.
            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 activity object or None if it does not exist.

        Raises:
            ValueError: If the parent does not have an ID.
        """
        # TODO: Input validation: SYNPY-1400
        with tracer.start_as_current_span(name=f"Activity_get: Parent_ID: {parent.id}"):
            loop = asyncio.get_event_loop()
            try:
                synapse_activity = await loop.run_in_executor(
                    None,
                    lambda: Synapse.get_client(
                        synapse_client=synapse_client
                    ).getProvenance(
                        entity=parent.id,
                        version=parent.version_number,
                    ),
                )
            except SynapseHTTPError as ex:
                if ex.response.status_code == 404:
                    return None
                else:
                    raise ex
            if synapse_activity:
                return cls().fill_from_dict(synapse_activity=synapse_activity)
            else:
                return None

    @classmethod
    async def delete_async(
        cls,
        parent: Union["Table", "File"],
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> None:
        """
        Delete the Activity from Synapse. The Activity must be disassociated from
        all entities before it can be deleted. The first step of this delete call
        is to disassociate the Activity from the parent entity. If you have other
        entities that are associated with this Activity you must disassociate them
        by calling this method on them as well. You'll receive an error for all entities
        until the last one which will delete the Activity.

        Arguments:
            parent: The parent entity this activity is associated with.
            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.

        Raises:
            ValueError: If the parent does not have an ID.
        """
        # TODO: Input validation: SYNPY-1400
        with tracer.start_as_current_span(
            name=f"Activity_delete: Parent_ID: {parent.id}"
        ):
            loop = asyncio.get_event_loop()
            await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(
                    synapse_client=synapse_client
                ).deleteProvenance(
                    entity=parent.id,
                ),
            )
            parent.activity = None

    @classmethod
    async def disassociate_from_entity_async(
        cls,
        parent: Union["Table", "File"],
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> None:
        """
        Disassociate the Activity from the parent entity. This is the first step in
        deleting the Activity. If you have other entities that are associated with this
        Activity you must disassociate them by calling this method on them as well.

        Arguments:
            parent: The parent entity this activity is associated with.
            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.

        Raises:
            ValueError: If the parent does not have an ID.
        """
        # TODO: Input validation: SYNPY-1400
        with tracer.start_as_current_span(
            name=f"Activity_disassociate: Parent_ID: {parent.id}"
        ):
            await delete_entity_generated_by(
                entity_id=parent.id, synapse_client=synapse_client
            )
            parent.activity = None

synapseclient.models.UsedEntity dataclass

Reference to a Synapse entity that was used or executed by an Activity.

ATTRIBUTE DESCRIPTION
target_id

The ID of the entity to which this reference refers.

TYPE: Optional[str]

target_version_number

The version number of the entity to which this reference refers.

TYPE: Optional[int]

Source code in synapseclient/models/activity.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@dataclass
class UsedEntity:
    """
    Reference to a Synapse entity that was used or executed by an Activity.

    Attributes:
        target_id: The ID of the entity to which this reference refers.
        target_version_number: The version number of the entity to which this reference refers.
    """

    target_id: Optional[str] = None
    """The the id of the entity to which this reference refers."""

    target_version_number: Optional[int] = None
    """The version number of the entity to which this reference refers."""

    def format_for_manifest(self) -> str:
        """
        Format the content of this data class to be written to a manifest file.

        Returns:
            The formatted string.
        """
        return_value = f"{self.target_id}"
        if self.target_version_number is not None:
            return_value += f".{self.target_version_number}"
        return return_value

synapseclient.models.UsedURL dataclass

URL that was used or executed by an Activity such as a link to a GitHub commit or a link to a specific version of a software tool.

ATTRIBUTE DESCRIPTION
name

The name of the URL.

TYPE: Optional[str]

url

The external URL of the file that was used such as a link to a GitHub commit or a link to a specific version of a software tool.

TYPE: Optional[str]

Source code in synapseclient/models/activity.py
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
@dataclass
class UsedURL:
    """
    URL that was used or executed by an Activity such as a link to a
    GitHub commit or a link to a specific version of a software tool.

    Attributes:
        name: The name of the URL.
        url: The external URL of the file that was used such as a link to a
            GitHub commit or a link to a specific version of a software tool.
    """

    name: Optional[str] = None
    """The name of the URL."""

    url: Optional[str] = None
    """The external URL of the file that was used such as a link to a GitHub commit
    or a link to a specific version of a software tool."""

    def format_for_manifest(self) -> str:
        """
        Format the content of this data class to be written to a manifest file.

        Returns:
            The formatted string.
        """
        if self.name:
            return_value = self.name
        else:
            return_value = self.url

        return return_value

synapseclient.models.Team dataclass

Bases: TeamSynchronousProtocol

Represents a Synapse Team. User definable fields are:

ATTRIBUTE DESCRIPTION
id

The ID of the team

TYPE: Optional[int]

name

The name of the team

TYPE: Optional[str]

description

A short description of the team

TYPE: Optional[str]

icon

A file handle ID for the icon image of the team

TYPE: Optional[str]

can_public_join

True if members can join without an invitation or approval

TYPE: Optional[bool]

can_request_membership

True if users can create a membership request to join

TYPE: Optional[bool]

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 team was created

TYPE: Optional[str]

modified_on

The date this team was last modified

TYPE: Optional[str]

created_by

The ID of the user that created this team

TYPE: Optional[str]

modified_by

The ID of the user that last modified this team

TYPE: Optional[str]

Source code in synapseclient/models/team.py
 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
@dataclass
@async_to_sync
class Team(TeamSynchronousProtocol):
    """
    Represents a [Synapse Team](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/Team.html).
    User definable fields are:

    Attributes:
        id: The ID of the team
        name: The name of the team
        description: A short description of the team
        icon: A file handle ID for the icon image of the team
        can_public_join: True if members can join without an invitation or approval
        can_request_membership: True if users can create a membership request to join
        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 team was created
        modified_on: The date this team was last modified
        created_by: The ID of the user that created this team
        modified_by: The ID of the user that last modified this team
    """

    id: Optional[int] = None
    """The ID of the team"""

    name: Optional[str] = None
    """The name of the team"""

    description: Optional[str] = None
    """A short description of the team"""

    icon: Optional[str] = None
    """A file handle ID for the icon image of the team"""

    can_public_join: Optional[bool] = False
    """True if members can join without an invitation or approval"""

    can_request_membership: Optional[bool] = True
    """True if users can create a membership request to join"""

    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] = None
    """The date this team was created"""

    modified_on: Optional[str] = None
    """The date this team was last modified"""

    created_by: Optional[str] = None
    """The ID of the user that created this team"""

    modified_by: Optional[str] = None
    """The ID of the user that last modified this team"""

    def fill_from_dict(
        self, synapse_team: Union[Synapse_Team, Dict[str, str]]
    ) -> "Team":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_team: The response from the REST API.

        Returns:
            The Team object.
        """
        self.id = (
            int(synapse_team.get("id", None)) if synapse_team.get("id", None) else None
        )
        self.name = synapse_team.get("name", None)
        self.description = synapse_team.get("description", None)
        self.icon = synapse_team.get("icon", None)
        self.can_public_join = synapse_team.get("canPublicJoin", False)
        self.can_request_membership = synapse_team.get("canRequestMembership", True)
        self.etag = synapse_team.get("etag", None)
        self.created_on = synapse_team.get("createdOn", None)
        self.modified_on = synapse_team.get("modifiedOn", None)
        self.created_by = synapse_team.get("createdBy", None)
        self.modified_by = synapse_team.get("modifiedBy", None)
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Team_Create: {self.name}"
    )
    async def create_async(self, *, synapse_client: Optional[Synapse] = None) -> "Team":
        """Creates a new team on 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:
            Team: The Team object.
        """
        loop = asyncio.get_event_loop()
        trace.get_current_span().set_attributes(
            {
                "synapse.name": self.name or "",
                "synapse.id": self.id or "",
            }
        )
        team = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).create_team(
                name=self.name,
                description=self.description,
                icon=self.icon,
                can_public_join=self.can_public_join,
                can_request_membership=self.can_request_membership,
            ),
        )
        self.fill_from_dict(synapse_team=team)
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Team_Delete: {self.id}"
    )
    async def delete_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
        """Deletes a team 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
        """
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).delete_team(
                id=self.id,
            ),
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Team_Get: {self.id if self.id else self.name}"
    )
    async def get_async(self, *, synapse_client: Optional[Synapse] = None) -> "Team":
        """
        Gets a Team from Synapse by ID or Name. If both are added to the Team instance
        it will use the ID.

        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.

        Raises:
            ValueError: If the Team object has neither an id nor a name.

        Returns:
            Team: The Team object.
        """
        if self.id:
            loop = asyncio.get_event_loop()
            api_team = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(synapse_client=synapse_client).getTeam(
                    id=self.id,
                ),
            )
            return self.fill_from_dict(api_team)
        elif self.name:
            loop = asyncio.get_event_loop()
            api_team = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(synapse_client=synapse_client).getTeam(
                    id=self.name,
                ),
            )
            return self.fill_from_dict(api_team)
        raise ValueError("Team must have either an id or a name")

    @classmethod
    @otel_trace_method(
        method_to_trace_name=lambda cls, id, **kwargs: f"Team_From_Id: {id}"
    )
    async def from_id_async(
        cls, id: int, *, synapse_client: Optional[Synapse] = None
    ) -> "Team":
        """Gets Team object using its integer id.

        Arguments:
            id: The id of the team.
            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:
            Team: The Team object.
        """

        return await cls(id=id).get_async(synapse_client=synapse_client)

    @classmethod
    @otel_trace_method(
        method_to_trace_name=lambda cls, name, **kwargs: f"Team_From_Name: {name}"
    )
    async def from_name_async(
        cls, name: str, *, synapse_client: Optional[Synapse] = None
    ) -> "Team":
        """Gets Team object using its string name.

        *** You will be unable to retrieve a team by name immediately after its
        creation because the fragment service is eventually consistent. If you need to
        retrieve a team immediately following creation you should use the
        [from_id][synapseclient.models.Team.from_id] method. ***

        Arguments:
            name: The name of the team.
            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:
            Team: The Team object.
        """
        return await cls(name=name).get_async(synapse_client=synapse_client)

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Team_Members: {self.name}"
    )
    async def members_async(
        self, *, synapse_client: Optional[Synapse] = None
    ) -> List[TeamMember]:
        """
        Gets the TeamMembers associated with a team given the ID field on the
        Team instance.

        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:
            List[TeamMember]: A List of TeamMember objects.
        """
        loop = asyncio.get_event_loop()
        team_members = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).getTeamMembers(
                team=self
            ),
        )
        team_member_list = [
            TeamMember().fill_from_dict(synapse_team_member=member)
            for member in team_members
        ]
        return team_member_list

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Team_Invite: {self.name}"
    )
    async def invite_async(
        self,
        user: str,
        message: str,
        force: bool = True,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> Dict[str, str]:
        """Invites a user to a team given the ID field on the Team instance.

        Arguments:
            user: The username of the user to invite.
            message: The message to send.
            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:
            dict: The invite response.
        """
        loop = asyncio.get_event_loop()
        invite = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).invite_to_team(
                team=self,
                user=user,
                message=message,
                force=force,
            ),
        )
        return invite

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Team_Open_Invitations: {self.name}"
    )
    async def open_invitations_async(
        self, *, synapse_client: Optional[Synapse] = None
    ) -> List[Dict[str, str]]:
        """Gets all open invitations for a team given the ID field on the Team instance.

        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:
            List[dict]: A list of invitations.
        """
        loop = asyncio.get_event_loop()
        invitations = await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(
                synapse_client=synapse_client
            ).get_team_open_invitations(
                team=self,
            ),
        )
        return list(invitations)

synapseclient.models.UserProfile dataclass

Bases: UserProfileSynchronousProtocol

UserProfile represents a user's profile in the system.

ATTRIBUTE DESCRIPTION
id

A foreign key to the ID of the 'principal' object for the user.

TYPE: Optional[int]

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 currentrepresentation of an entity is out-of-date.

TYPE: Optional[str]

first_name

This person's given name (forename)

TYPE: Optional[str]

last_name

This person's family name (surname)

TYPE: Optional[str]

emails

The list of user email addresses registered to this user.

TYPE: List[str]

open_ids

The list of OpenIds bound to this user's account.

TYPE: List[str]

username

A name chosen by the user that uniquely identifies them.

TYPE: Optional[str]

display_name

This field is deprecated and will always be null.

TYPE: Optional[str]

r_studio_url

URL for RStudio server assigned to the user.

TYPE: Optional[str]

summary

A summary description about this person.

TYPE: Optional[str]

position

This person's current position title.

TYPE: Optional[str]

location

This person's location.

TYPE: Optional[str]

industry

The industry/discipline that this person is associated with.

TYPE: Optional[str]

company

This person's current affiliation.

TYPE: Optional[str]

profile_picure_file_handle_id

The File Handle id of the user's profile picture.

TYPE: Optional[str]

url

A link to more information about this person.

TYPE: Optional[str]

team_name

This person's default team name.

TYPE: Optional[str]

notification_settings

Contains a user's notification settings.

TYPE: Optional[str]

preferences

User preferences

TYPE: Optional[List[UserPreference]]

created_on

The date this profile was created.

TYPE: Optional[str]

Source code in synapseclient/models/user.py
 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
@dataclass()
@async_to_sync
class UserProfile(UserProfileSynchronousProtocol):
    """
    UserProfile represents a user's profile in the system.

    Attributes:
        id: A foreign key to the ID of the 'principal' object for the user.
        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 currentrepresentation of an entity is
            out-of-date.
        first_name: This person's given name (forename)
        last_name: This person's family name (surname)
        emails: The list of user email addresses registered to this user.
        open_ids: The list of OpenIds bound to this user's account.
        username: A name chosen by the user that uniquely identifies them.
        display_name: This field is deprecated and will always be null.
        r_studio_url: URL for RStudio server assigned to the user.
        summary: A summary description about this person.
        position: This person's current position title.
        location: This person's location.
        industry: The industry/discipline that this person is associated with.
        company: This person's current affiliation.
        profile_picure_file_handle_id: The File Handle id of the user's profile picture.
        url: A link to more information about this person.
        team_name: This person's default team name.
        notification_settings: Contains a user's notification settings.
        preferences: User preferences
        created_on: The date this profile was created.
    """

    id: Optional[int] = None
    """A foreign key to the ID of the 'principal' object for the user."""

    username: Optional[str] = None
    """A name chosen by the user that uniquely identifies them."""

    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.
    """

    first_name: Optional[str] = None
    """This person's given name (forename)"""

    last_name: Optional[str] = None
    """This person's family name (surname)"""

    emails: List[str] = field(default_factory=list)
    """The list of user email addresses registered to this user."""

    open_ids: List[str] = field(default_factory=list)
    """The list of OpenIds bound to this user's account."""

    r_studio_url: Optional[str] = None
    """URL for RStudio server assigned to the user"""

    summary: Optional[str] = None
    """A summary description about this person"""

    position: Optional[str] = None
    """This person's current position title"""

    location: Optional[str] = None
    """This person's location"""

    industry: Optional[str] = None
    """The industry/discipline that this person is associated with"""

    company: Optional[str] = None
    """This person's current affiliation"""

    profile_picure_file_handle_id: Optional[str] = None
    """The File Handle id of the user's profile picture"""

    url: Optional[str] = None
    """A link to more information about this person"""

    team_name: Optional[str] = None
    """This person's default team name"""

    send_email_notifications: Optional[bool] = True
    """Should the user receive email notifications? Default true."""

    mark_emailed_messages_as_read: Optional[bool] = False
    """Should messages that are emailed to the user be marked as
    READ in Synapse? Default false."""

    preferences: Optional[List[UserPreference]] = field(default_factory=list)
    """User preferences"""

    created_on: Optional[str] = None
    """The date this profile was created."""

    def fill_from_dict(
        self, synapse_user_profile: Union[Synapse_UserProfile, Dict]
    ) -> "UserProfile":
        """Fills the UserProfile object from a dictionary.

        Arguments:
            synapse_user_profile: The dictionary to fill the UserProfile object from.
                Typically filled from a
                [Synapse UserProfile](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/UserProfile.html) object.
        """
        self.id = (
            int(synapse_user_profile.get("ownerId", None))
            if synapse_user_profile.get("ownerId", None)
            else None
        )
        self.etag = synapse_user_profile.get("etag", None)
        self.first_name = synapse_user_profile.get("firstName", None)
        self.last_name = synapse_user_profile.get("lastName", None)
        self.emails = synapse_user_profile.get("emails", [])
        self.open_ids = synapse_user_profile.get("openIds", [])
        self.username = synapse_user_profile.get("userName", None)
        self.r_studio_url = synapse_user_profile.get("rStudioUrl", None)
        self.summary = synapse_user_profile.get("summary", None)
        self.position = synapse_user_profile.get("position", None)
        self.location = synapse_user_profile.get("location", None)
        self.industry = synapse_user_profile.get("industry", None)
        self.company = synapse_user_profile.get("company", None)
        self.profile_picure_file_handle_id = synapse_user_profile.get(
            "profilePicureFileHandleId", None
        )
        self.url = synapse_user_profile.get("url", None)
        self.team_name = synapse_user_profile.get("teamName", None)
        notification_settings = synapse_user_profile.get("notificationSettings", {})
        self.send_email_notifications = notification_settings.get(
            "sendEmailNotifications", True
        )
        self.mark_emailed_messages_as_read = notification_settings.get(
            "markEmailedMessagesAsRead", False
        )
        synapse_preferences_list = synapse_user_profile.get("preferences", [])
        preferences = []
        for preference in synapse_preferences_list:
            preferences.append(
                UserPreference(
                    name=preference.get("name", None),
                    value=preference.get("value", None),
                )
            )
        self.preferences = preferences
        self.created_on = synapse_user_profile.get("createdOn", None)

        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Profile_Get: Username: {self.username}, id: {self.id}"
    )
    async def get_async(
        self,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "UserProfile":
        """
        Gets a UserProfile object using its id or username in that order. If an id
        and username is not specified this will retrieve the current user's profile.

        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 UserProfile object.

        """
        loop = asyncio.get_event_loop()

        if self.id:
            synapse_user_profile = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(
                    synapse_client=synapse_client
                ).get_user_profile_by_id(id=self.id),
            )
        elif self.username:
            synapse_user_profile = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(
                    synapse_client=synapse_client
                ).get_user_profile_by_username(username=self.username),
            )
        else:
            synapse_user_profile = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(
                    synapse_client=synapse_client
                ).get_user_profile_by_username(),
            )

        self.fill_from_dict(synapse_user_profile=synapse_user_profile)
        return self

    @classmethod
    @otel_trace_method(
        method_to_trace_name=lambda cls, user_id, **kwargs: f"Profile_From_Id: {user_id}"
    )
    async def from_id_async(
        cls, user_id: int, *, synapse_client: Optional[Synapse] = None
    ) -> "UserProfile":
        """Gets UserProfile object using its integer id. Wrapper for the
        [get][synapseclient.models.UserProfile.get] method.

        Arguments:
            user_id: The id of the user.
            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 UserProfile object.
        """

        return await cls(id=user_id).get_async(synapse_client=synapse_client)

    @classmethod
    @otel_trace_method(
        method_to_trace_name=lambda cls, username, **kwargs: f"Profile_From_Username: {username}"
    )
    async def from_username_async(
        cls, username: str, *, synapse_client: Optional[Synapse] = None
    ) -> "UserProfile":
        """
        Gets UserProfile object using its string name. Wrapper for the
        [get][synapseclient.models.UserProfile.get] method.

        Arguments:
            username: A name chosen by the user that uniquely identifies them.
            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 UserProfile object.
        """
        return await cls(username=username).get_async(synapse_client=synapse_client)

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"Profile_is_certified: Username: {self.username}, id: {self.id}"
    )
    async def is_certified_async(
        self,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "bool":
        """
        Determine whether a user is certified.

        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:
            True if the user is certified, False otherwise.

        Raises:
            ValueError: If id nor username is specified.
        """
        loop = asyncio.get_event_loop()

        if self.id or self.username:
            is_certified = await loop.run_in_executor(
                None,
                lambda: Synapse.get_client(synapse_client=synapse_client).is_certified(
                    user=self.id or self.username
                ),
            )
        else:
            raise ValueError("Must specify either id or username")

        return is_certified

synapseclient.models.UserPreference dataclass

A UserPreference represents a user preference in the system.

ATTRIBUTE DESCRIPTION
name

The name of the user preference.

TYPE: Optional[str]

value

The value of the user preference.

TYPE: Optional[bool]

Source code in synapseclient/models/user.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
@dataclass()
class UserPreference:
    """
    A UserPreference represents a user preference in the system.

    Attributes:
        name: The name of the user preference.
        value: The value of the user preference.
    """

    name: Optional[str] = None
    """The name of the user preference."""

    value: Optional[bool] = None
    """The value of the user preference."""

Attributes

name: Optional[str] = None class-attribute instance-attribute

The name of the user preference.

value: Optional[bool] = None class-attribute instance-attribute

The value of the user preference.


synapseclient.models.Annotations dataclass

Bases: AnnotationsSynchronousProtocol

Annotations that can be applied to a number of Synapse resources to provide additional information.

ATTRIBUTE DESCRIPTION
annotations

Additional metadata associated with the object. The key is the name of your desired annotations. The value is an object containing a list of string values (use empty list to represent no values for key) and the value type associated with all values in the list.

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

id

ID of the object to which this annotation belongs. Not required if being used as a member variable on another class.

TYPE: Optional[str]

etag

Etag of the object to which this annotation belongs. This field must match the current etag on the object. Not required if being used as a member variable on another class.

TYPE: Optional[str]

Source code in synapseclient/models/annotations.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 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
@dataclass()
@async_to_sync
class Annotations(AnnotationsSynchronousProtocol):
    """Annotations that can be applied to a number of Synapse resources to provide
    additional information.

    Attributes:
        annotations: Additional metadata associated with the object. The key is the name
            of your desired annotations. The value is an object containing a list of
            string values (use empty list to represent no values for key) and the value
            type associated with all values in the list.
        id: ID of the object to which this annotation belongs. Not required if being
            used as a member variable on another class.
        etag: Etag of the object to which this annotation belongs. This field must match
            the current etag on the object. Not required if being used as a member
            variable on another class.
    """

    annotations: Union[
        Dict[
            str,
            Union[
                List[str],
                List[bool],
                List[float],
                List[int],
                List[date],
                List[datetime],
            ],
        ],
        None,
    ] = field(default_factory=dict)
    """Additional metadata associated with the object. The key is the name of your
    desired annotations. The value is an object containing a list of string values
    (use empty list to represent no values for key) and the value type associated with
    all values in the list.
    """

    id: Optional[str] = None
    """ID of the object to which this annotation belongs. Not required if being used as
    a member variable on another class."""

    etag: Optional[str] = None
    """ Etag of the object to which this annotation belongs. To update an AnnotationV2,
    this field must match the current etag on the object. Not required if being used as
    a member variable on another class."""

    async def store_async(
        self,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "Annotations":
        """Storing annotations to 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 stored annotations.

        Raises:
            ValueError: If the id or etag are not set.
        """
        if self.id is None or self.etag is None:
            raise ValueError("id and etag are required to store annotations.")

        result = await set_annotations_async(
            annotations=self,
            synapse_client=synapse_client,
        )
        self.annotations = Annotations.from_dict(result)
        self.etag = result["etag"]
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Annotations stored for {self.id}"
        )
        return self

    @classmethod
    def from_dict(
        cls, synapse_annotations: dict
    ) -> Union[
        Dict[
            str,
            Union[
                List[str],
                List[bool],
                List[float],
                List[int],
                List[date],
                List[datetime],
            ],
        ],
        None,
    ]:
        """Convert the annotations from the format the synapse rest API works in -
        to the format used by this class.

        Arguments:
            synapse_annotations: The annotations from the synapse rest API.

        Returns:
            The annotations in python class format or None.
        """
        if synapse_annotations is None:
            return None
        annotations = {}
        dict_to_convert = (
            synapse_annotations["annotations"]
            if "annotations" in synapse_annotations
            else synapse_annotations
        )
        for key in dict_to_convert:
            if isinstance(dict_to_convert[key], dict):
                conversion_func = ANNO_TYPE_TO_FUNC[dict_to_convert[key]["type"]]
                annotations[key] = [
                    conversion_func(v) for v in dict_to_convert[key]["value"]
                ]
            else:
                annotations[key] = dict_to_convert[key]

        return annotations

Functions

from_dict(synapse_annotations) classmethod

Convert the annotations from the format the synapse rest API works in - to the format used by this class.

PARAMETER DESCRIPTION
synapse_annotations

The annotations from the synapse rest API.

TYPE: dict

RETURNS DESCRIPTION
Union[Dict[str, Union[List[str], List[bool], List[float], List[int], List[date], List[datetime]]], None]

The annotations in python class format or None.

Source code in synapseclient/models/annotations.py
 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
@classmethod
def from_dict(
    cls, synapse_annotations: dict
) -> Union[
    Dict[
        str,
        Union[
            List[str],
            List[bool],
            List[float],
            List[int],
            List[date],
            List[datetime],
        ],
    ],
    None,
]:
    """Convert the annotations from the format the synapse rest API works in -
    to the format used by this class.

    Arguments:
        synapse_annotations: The annotations from the synapse rest API.

    Returns:
        The annotations in python class format or None.
    """
    if synapse_annotations is None:
        return None
    annotations = {}
    dict_to_convert = (
        synapse_annotations["annotations"]
        if "annotations" in synapse_annotations
        else synapse_annotations
    )
    for key in dict_to_convert:
        if isinstance(dict_to_convert[key], dict):
            conversion_func = ANNO_TYPE_TO_FUNC[dict_to_convert[key]["type"]]
            annotations[key] = [
                conversion_func(v) for v in dict_to_convert[key]["value"]
            ]
        else:
            annotations[key] = dict_to_convert[key]

    return annotations

synapseclient.models.mixins.AccessControllable

Bases: AccessControllableSynchronousProtocol

Mixin for objects that can be controlled by an Access Control List (ACL).

In order to use this mixin, the class must have an id attribute.

Source code in synapseclient/models/mixins/access_control.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 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
@async_to_sync
class AccessControllable(AccessControllableSynchronousProtocol):
    """
    Mixin for objects that can be controlled by an Access Control List (ACL).

    In order to use this mixin, the class must have an `id` attribute.
    """

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

    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
            ),
        )

    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
            ),
        )

    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,
            ),
        )

Attributes

id: Optional[str] = None class-attribute instance-attribute

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

Functions

get_permissions_async(*, synapse_client=None) async

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(principal_id=None, *, synapse_client=None) async

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(principal_id=None, access_type=None, modify_benefactor=False, warn_if_inherits=True, overwrite=True, *, synapse_client=None) async

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,
        ),
    )

synapseclient.models.mixins.StorableContainer

Bases: StorableContainerSynchronousProtocol

Mixin for objects that can have Folders and Files stored in them.

In order to use this mixin, the class must have the following attributes:

  • id
  • files
  • folders
  • _last_persistent_instance

The class must have the following method:

  • get
Source code in synapseclient/models/mixins/storable_container.py
 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
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
@async_to_sync
class StorableContainer(StorableContainerSynchronousProtocol):
    """
    Mixin for objects that can have Folders and Files stored in them.

    In order to use this mixin, the class must have the following attributes:

    - `id`
    - `files`
    - `folders`
    - `_last_persistent_instance`

    The class must have the following method:

    - `get`
    """

    id: None = None
    name: None = None
    files: "File" = None
    folders: "Folder" = None
    _last_persistent_instance: None = None

    async def get_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
        """Used to satisfy the usage in this mixin from the parent class."""

    @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,
        *,
        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.
            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
        ```

        """
        if not self._last_persistent_instance:
            await self.get_async(synapse_client=synapse_client)
        Synapse.get_client(synapse_client=synapse_client).logger.info(
            f"Syncing {self.__class__.__name__} ({self.id}:{self.name}) from Synapse."
        )
        path = os.path.expanduser(path) if path else None

        loop = asyncio.get_event_loop()
        children = await loop.run_in_executor(
            None,
            lambda: self._retrieve_children(
                follow_link=follow_link,
                synapse_client=synapse_client,
            ),
        )

        pending_tasks = []
        self.folders = []
        self.files = []

        for child in children:
            pending_tasks.extend(
                self._create_task_for_child(
                    child=child,
                    recursive=recursive,
                    path=path,
                    download_file=download_file,
                    if_collision=if_collision,
                    failure_strategy=failure_strategy,
                    synapse_client=synapse_client,
                    include_activity=include_activity,
                    follow_link=follow_link,
                    link_hops=link_hops,
                )
            )

        for task in asyncio.as_completed(pending_tasks):
            result = await task
            self._resolve_sync_from_synapse_result(
                result=result,
                failure_strategy=failure_strategy,
                synapse_client=synapse_client,
            )
        return self

    def flatten_file_list(self) -> List["File"]:
        """
        Recursively loop over all of the already retrieved files and folders and return
        a list of all files in the container.

        Returns:
            A list of all files in the container.
        """
        files = []
        for file in self.files:
            files.append(file)
        for folder in self.folders:
            files.extend(folder.flatten_file_list())
        return files

    def map_directory_to_all_contained_files(
        self, root_path: str
    ) -> Dict[str, List["File"]]:
        """
        Recursively loop over all of the already retrieved files and folders. Then
        return back a dictionary where the key is the path to the directory at each
        level. The value is a list of all files in that directory AND all files in
        the child directories.

        This is used during the creation of the manifest TSV file during the
        syncFromSynapse utility function.

        Example: Using this function
           Returning back a dict with 2 keys:

                Given:
                root_folder
                ├── sub_folder
                │   ├── file1.txt
                │   └── file2.txt

                Returns:
                {
                    "root_folder": [file1, file2],
                    "root_folder/sub_folder": [file1, file2]
                }


           Returning back a dict with 3 keys:

                Given:
                root_folder
                ├── sub_folder_1
                │   ├── file1.txt
                ├── sub_folder_2
                │   └── file2.txt

                Returns:
                {
                    "root_folder": [file1, file2],
                    "root_folder/sub_folder_1": [file1]
                    "root_folder/sub_folder_2": [file2]
                }

        Arguments:
            root_path: The root path where the top level files are stored.

        Returns:
            A dictionary where the key is the path to the directory at each level. The
                value is a list of all files in that directory AND all files in the child
                directories.
        """
        directory_map = {}
        directory_map.update({root_path: self.flatten_file_list()})

        for folder in self.folders:
            directory_map.update(
                **folder.map_directory_to_all_contained_files(
                    root_path=os.path.join(root_path, folder.name)
                )
            )

        return directory_map

    def _retrieve_children(
        self,
        follow_link: bool,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> List:
        """
        This wraps the `getChildren` generator to return back a list of children.

        Arguments:
            follow_link: Whether to follow a link entity or not. Links can be used to
                point at other Synapse entities.
            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.
        """
        include_types = ["folder", "file"]
        if follow_link:
            include_types.append("link")
        children_objects = Synapse.get_client(
            synapse_client=synapse_client
        ).getChildren(
            parent=self.id,
            includeTypes=include_types,
        )
        children = []
        for child in children_objects:
            children.append(child)
        return children

    async def _wrap_recursive_get_children(
        self,
        folder: "Folder",
        recursive: bool = False,
        path: Optional[str] = None,
        download_file: bool = False,
        if_collision: str = COLLISION_OVERWRITE_LOCAL,
        failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
        include_activity: bool = True,
        follow_link: bool = False,
        link_hops: int = 1,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> None:
        """
        Wrap the recursive get children method to return nothing. We are updating
        the folder object in place. We do not want to cause the result of this
        method to cause any folder of file objects to be added to this level of the
        hierarchy.
        """
        new_resolved_path = (
            os.path.join(path, folder.name) if path and folder.name else None
        )
        if new_resolved_path and not os.path.exists(new_resolved_path):
            os.makedirs(new_resolved_path)
        await folder.sync_from_synapse_async(
            recursive=recursive,
            download_file=download_file,
            path=new_resolved_path,
            if_collision=if_collision,
            failure_strategy=failure_strategy,
            include_activity=include_activity,
            follow_link=follow_link,
            link_hops=link_hops,
            synapse_client=synapse_client,
        )

    def _create_task_for_child(
        self,
        child,
        recursive: bool = False,
        path: Optional[str] = None,
        download_file: bool = False,
        if_collision: str = COLLISION_OVERWRITE_LOCAL,
        failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
        include_activity: bool = True,
        follow_link: bool = False,
        link_hops: int = 1,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> List[asyncio.Task]:
        """
        Determines based off the type of child which tasks should be created to handle
        the child. This will return a list of tasks that will be executed in parallel
        to handle the child. The tasks will retrieve the File and Folder objects from
        Synapse. In the case of a Folder object, it will also retrieve the children of
        that folder if `recursive` is set to True.


        Arguments:
            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.
            path: An optional path where the file hierarchy will be reproduced. If not
                specified the files will by default be placed in the synapseCache.
            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.
            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.

        """

        pending_tasks = []
        synapse_id = child.get("id", None)
        child_type = child.get("type", None)
        name = child.get("name", None)
        if synapse_id and child_type == FOLDER_ENTITY:
            # Lazy import to avoid circular import
            from synapseclient.models import Folder

            folder = Folder(id=synapse_id, name=name)
            self.folders.append(folder)

            if recursive:
                pending_tasks.append(
                    asyncio.create_task(
                        self._wrap_recursive_get_children(
                            folder=folder,
                            recursive=recursive,
                            path=path,
                            download_file=download_file,
                            if_collision=if_collision,
                            failure_strategy=failure_strategy,
                            include_activity=include_activity,
                            follow_link=follow_link,
                            link_hops=link_hops,
                            synapse_client=synapse_client,
                        )
                    )
                )
            else:
                pending_tasks.append(
                    asyncio.create_task(
                        wrap_coroutine(folder.get_async(synapse_client=synapse_client))
                    )
                )

        elif synapse_id and child_type == FILE_ENTITY:
            # Lazy import to avoid circular import
            from synapseclient.models import File

            file = File(id=synapse_id, name=name, download_file=download_file)
            self.files.append(file)
            if path:
                file.path = path
            if if_collision:
                file.if_collision = if_collision

            pending_tasks.append(
                asyncio.create_task(
                    wrap_coroutine(
                        file.get_async(
                            include_activity=include_activity,
                            synapse_client=synapse_client,
                        )
                    )
                )
            )
        elif link_hops > 0 and synapse_id and child_type == LINK_ENTITY:
            pending_tasks.append(
                asyncio.create_task(
                    wrap_coroutine(
                        self._follow_link(
                            child=child,
                            recursive=recursive,
                            path=path,
                            download_file=download_file,
                            if_collision=if_collision,
                            failure_strategy=failure_strategy,
                            synapse_client=synapse_client,
                            include_activity=include_activity,
                            follow_link=follow_link,
                            link_hops=link_hops - 1,
                        )
                    )
                )
            )

        return pending_tasks

    async def _follow_link(
        self,
        child,
        recursive: bool = False,
        path: Optional[str] = None,
        download_file: bool = False,
        if_collision: str = COLLISION_OVERWRITE_LOCAL,
        failure_strategy: FailureStrategy = FailureStrategy.LOG_EXCEPTION,
        include_activity: bool = True,
        follow_link: bool = False,
        link_hops: int = 0,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> None:
        """Follow a link to get a target entity.

        Arguments in this function are all supplied in order to recursively traverse
        the container hierarchy.

        Returns:
            None
        """

        synapse_id = child.get("id", None)
        # TODO: Until Link is an official Model dataclass this logic will suffice for
        # the purpose of following a link to potentially download a File or open another
        # Folder.
        entity_bundle = await get_entity_id_bundle2(
            entity_id=synapse_id,
            request={"includeEntity": True},
            synapse_client=synapse_client,
        )

        if (
            entity_bundle is None
            or not (entity := entity_bundle.get("entity", None))
            or not (links_to := entity.get("linksTo", None))
            or not (link_class_name := entity.get("linksToClassName", None))
            or not (link_target_id := links_to.get("targetId", None))
        ):
            return

        pending_tasks = self._create_task_for_child(
            child={
                "id": link_target_id,
                "type": link_class_name,
            },
            recursive=recursive,
            path=path,
            download_file=download_file,
            if_collision=if_collision,
            failure_strategy=failure_strategy,
            include_activity=include_activity,
            follow_link=follow_link,
            link_hops=link_hops,
            synapse_client=synapse_client,
        )
        for task in asyncio.as_completed(pending_tasks):
            result = await task
            self._resolve_sync_from_synapse_result(
                result=result,
                failure_strategy=failure_strategy,
                synapse_client=synapse_client,
            )

    def _resolve_sync_from_synapse_result(
        self,
        result: Union[None, "Folder", "File", BaseException],
        failure_strategy: FailureStrategy,
        *,
        synapse_client: Union[None, Synapse],
    ) -> None:
        """
        Handle what to do based on what was returned from the latest task to complete.
        We are updating the object in place and appending the returned Folder/Files to
        the appropriate list.

        Arguments:
            result: The result of the task that was completed.
            failure_strategy: Determines how to handle failures when retrieving children
                under this Folder 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.
        """
        if result is None:
            # We will recieve None when executing `_wrap_recursive_get_children` as
            # it will internally be recursively calling this method and setting the
            # appropriate folder/file objects in place.
            pass
        elif (
            result.__class__.__name__ == "Folder" or result.__class__.__name__ == "File"
        ):
            # Do nothing as the objects are updated in place and the container has
            # already been updated to append the new objects.
            pass
        elif isinstance(result, BaseException):
            Synapse.get_client(synapse_client=synapse_client).logger.exception(result)

            if failure_strategy == FailureStrategy.RAISE_EXCEPTION:
                raise result
        else:
            exception = SynapseError(
                f"Unknown failure retrieving children of Folder ({self.id}): {type(result)}",
                result,
            )
            Synapse.get_client(synapse_client=synapse_client).logger.exception(
                exception
            )
            if failure_strategy == FailureStrategy.RAISE_EXCEPTION:
                raise exception

Functions

get_async(*, synapse_client=None) async

Used to satisfy the usage in this mixin from the parent class.

Source code in synapseclient/models/mixins/storable_container.py
54
55
async def get_async(self, *, synapse_client: Optional[Synapse] = None) -> None:
    """Used to satisfy the usage in this mixin from the parent class."""

sync_from_synapse_async(path=None, recursive=True, download_file=True, if_collision=COLLISION_OVERWRITE_LOCAL, failure_strategy=FailureStrategy.LOG_EXCEPTION, include_activity=True, follow_link=False, link_hops=1, *, synapse_client=None) async

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

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
 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
@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,
    *,
    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.
        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
    ```

    """
    if not self._last_persistent_instance:
        await self.get_async(synapse_client=synapse_client)
    Synapse.get_client(synapse_client=synapse_client).logger.info(
        f"Syncing {self.__class__.__name__} ({self.id}:{self.name}) from Synapse."
    )
    path = os.path.expanduser(path) if path else None

    loop = asyncio.get_event_loop()
    children = await loop.run_in_executor(
        None,
        lambda: self._retrieve_children(
            follow_link=follow_link,
            synapse_client=synapse_client,
        ),
    )

    pending_tasks = []
    self.folders = []
    self.files = []

    for child in children:
        pending_tasks.extend(
            self._create_task_for_child(
                child=child,
                recursive=recursive,
                path=path,
                download_file=download_file,
                if_collision=if_collision,
                failure_strategy=failure_strategy,
                synapse_client=synapse_client,
                include_activity=include_activity,
                follow_link=follow_link,
                link_hops=link_hops,
            )
        )

    for task in asyncio.as_completed(pending_tasks):
        result = await task
        self._resolve_sync_from_synapse_result(
            result=result,
            failure_strategy=failure_strategy,
            synapse_client=synapse_client,
        )
    return self

flatten_file_list()

Recursively loop over all of the already retrieved files and folders and return a list of all files in the container.

RETURNS DESCRIPTION
List[File]

A list of all files in the container.

Source code in synapseclient/models/mixins/storable_container.py
272
273
274
275
276
277
278
279
280
281
282
283
284
285
def flatten_file_list(self) -> List["File"]:
    """
    Recursively loop over all of the already retrieved files and folders and return
    a list of all files in the container.

    Returns:
        A list of all files in the container.
    """
    files = []
    for file in self.files:
        files.append(file)
    for folder in self.folders:
        files.extend(folder.flatten_file_list())
    return files

map_directory_to_all_contained_files(root_path)

Recursively loop over all of the already retrieved files and folders. Then return back a dictionary where the key is the path to the directory at each level. The value is a list of all files in that directory AND all files in the child directories.

This is used during the creation of the manifest TSV file during the syncFromSynapse utility function.

Using this function

Returning back a dict with 2 keys:

 Given:
 root_folder
 ├── sub_folder
 │   ├── file1.txt
 │   └── file2.txt

 Returns:
 {
     "root_folder": [file1, file2],
     "root_folder/sub_folder": [file1, file2]
 }

Returning back a dict with 3 keys:

 Given:
 root_folder
 ├── sub_folder_1
 │   ├── file1.txt
 ├── sub_folder_2
 │   └── file2.txt

 Returns:
 {
     "root_folder": [file1, file2],
     "root_folder/sub_folder_1": [file1]
     "root_folder/sub_folder_2": [file2]
 }
PARAMETER DESCRIPTION
root_path

The root path where the top level files are stored.

TYPE: str

RETURNS DESCRIPTION
Dict[str, List[File]]

A dictionary where the key is the path to the directory at each level. The value is a list of all files in that directory AND all files in the child directories.

Source code in synapseclient/models/mixins/storable_container.py
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
def map_directory_to_all_contained_files(
    self, root_path: str
) -> Dict[str, List["File"]]:
    """
    Recursively loop over all of the already retrieved files and folders. Then
    return back a dictionary where the key is the path to the directory at each
    level. The value is a list of all files in that directory AND all files in
    the child directories.

    This is used during the creation of the manifest TSV file during the
    syncFromSynapse utility function.

    Example: Using this function
       Returning back a dict with 2 keys:

            Given:
            root_folder
            ├── sub_folder
            │   ├── file1.txt
            │   └── file2.txt

            Returns:
            {
                "root_folder": [file1, file2],
                "root_folder/sub_folder": [file1, file2]
            }


       Returning back a dict with 3 keys:

            Given:
            root_folder
            ├── sub_folder_1
            │   ├── file1.txt
            ├── sub_folder_2
            │   └── file2.txt

            Returns:
            {
                "root_folder": [file1, file2],
                "root_folder/sub_folder_1": [file1]
                "root_folder/sub_folder_2": [file2]
            }

    Arguments:
        root_path: The root path where the top level files are stored.

    Returns:
        A dictionary where the key is the path to the directory at each level. The
            value is a list of all files in that directory AND all files in the child
            directories.
    """
    directory_map = {}
    directory_map.update({root_path: self.flatten_file_list()})

    for folder in self.folders:
        directory_map.update(
            **folder.map_directory_to_all_contained_files(
                root_path=os.path.join(root_path, folder.name)
            )
        )

    return directory_map

synapseclient.models.FailureStrategy

Bases: Enum

When storing a large number of items through bulk actions like Project(id="syn123").store() or Folder(id="syn456").store() individual failures may occur. Passing this ENUM will allow you to define how you want to respond to failures.

Source code in synapseclient/models/services/storable_entity_components.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class FailureStrategy(Enum):
    """
    When storing a large number of items through bulk actions like
    `Project(id="syn123").store()` or `Folder(id="syn456").store()` individual failures
    may occur. Passing this ENUM will allow you to define how you want to respond to
    failures.
    """

    RAISE_EXCEPTION = "RAISE_EXCEPTION"
    """An exception is raised on the first failure and all tasks yet to be completed
    are cancelled. The exception will also be logged."""

    LOG_EXCEPTION = "LOG_EXCEPTION"
    """An exception is logged and all tasks yet to be completed continue to be
    processed."""

Attributes

RAISE_EXCEPTION = 'RAISE_EXCEPTION' class-attribute instance-attribute

An exception is raised on the first failure and all tasks yet to be completed are cancelled. The exception will also be logged.

LOG_EXCEPTION = 'LOG_EXCEPTION' class-attribute instance-attribute

An exception is logged and all tasks yet to be completed continue to be processed.