Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
a07b2ee
add OOP DownloadList class
andrewelamb Apr 2, 2026
5b52a89
update docs and docstring examples
andrewelamb Apr 2, 2026
2baab73
add module-scoped syn class
andrewelamb Apr 2, 2026
2e13576
add comment
andrewelamb Apr 2, 2026
fafb10c
various fixes claude found
andrewelamb Apr 2, 2026
27c1307
import methods so they cna be used without the class
andrewelamb Apr 2, 2026
03f64e9
replaced Typing.List with list
andrewelamb Apr 2, 2026
17ee9bf
DownLoadListItem.version_number is now optional
andrewelamb Apr 2, 2026
a4f600a
allow DownloadListItem.version number to be null
andrewelamb Apr 3, 2026
fed3d6f
removed module level synapse fixture
andrewelamb Apr 7, 2026
d5371b3
added back module level syn object
andrewelamb Apr 7, 2026
af26caf
Merge branch 'develop' into SYNPY-1802
andrewelamb Apr 7, 2026
dced8c7
fix tests were mocking leaked to other tests, and update claude.md file
andrewelamb Apr 8, 2026
4ed83b1
remove uneeded import
andrewelamb Apr 8, 2026
8dafe64
changed link format
andrewelamb Apr 8, 2026
f243490
funtion now raises an error when mumberOfFilesAdded is nto returned
andrewelamb Apr 8, 2026
5f8a0e1
added link to API doc
andrewelamb Apr 8, 2026
ebb6044
updated docstring
andrewelamb Apr 8, 2026
3d43bc3
now using CsvTableDescriptor class
andrewelamb Apr 8, 2026
868edba
changed link format
andrewelamb Apr 8, 2026
90d100f
add exception and warning
andrewelamb Apr 8, 2026
7d9ea03
added link to API docs
andrewelamb Apr 8, 2026
c76e749
PR suggestions
andrewelamb Apr 10, 2026
04badb6
updated docstrings
andrewelamb Apr 10, 2026
167d8f9
remove warning test
andrewelamb Apr 10, 2026
278af37
fix imports
andrewelamb Apr 10, 2026
a2354cc
fix docstring
andrewelamb Apr 10, 2026
b5a3d07
Merge branch 'develop' into SYNPY-1802
andrewelamb Apr 15, 2026
0052482
redo docs
andrewelamb Apr 15, 2026
0219c58
undo review date change
andrewelamb Apr 15, 2026
7c8e680
uncommit a dir that wasnt supposed to be
andrewelamb Apr 15, 2026
5028295
fix style issues
andrewelamb Apr 15, 2026
85412d6
combined all static methods as functions into one section
andrewelamb Apr 15, 2026
094b8af
added destination parameter
andrewelamb Apr 15, 2026
1ee92b6
created new api service fucntion for download of manifest
andrewelamb Apr 15, 2026
43a3a21
fix stale docstring
andrewelamb Apr 15, 2026
6313ea6
fix unit test error type
andrewelamb Apr 15, 2026
da715af
revert claude date
andrewelamb Apr 15, 2026
80cbe11
removed unit tests
andrewelamb Apr 15, 2026
f1b322e
added integration tests
andrewelamb Apr 15, 2026
6cbca41
added to docstring
andrewelamb Apr 15, 2026
cbcad15
cleaed up and renamed download_row func
andrewelamb Apr 15, 2026
3a30b22
made consistent use of methods
andrewelamb Apr 15, 2026
7b9ed4b
made max_concurrant more consistent
andrewelamb Apr 15, 2026
e80aab2
added tests
andrewelamb Apr 15, 2026
3b73e72
remove uneeded parens
andrewelamb Apr 15, 2026
b2d5d3d
did some clean up
andrewelamb Apr 15, 2026
7e36cb8
added helper function
andrewelamb Apr 15, 2026
a74be07
redid simpler unit tests
andrewelamb Apr 15, 2026
4a55581
refactored tests
andrewelamb Apr 15, 2026
53edf77
added integration test
andrewelamb Apr 15, 2026
db854eb
expanded test
andrewelamb Apr 15, 2026
ef60977
clarified how versions work in docstrings
andrewelamb Apr 15, 2026
b1ac8d1
light refactoring
andrewelamb Apr 15, 2026
861e6ab
add fix for test failing on Mac OS
andrewelamb Apr 16, 2026
8b04266
Merge branch 'develop' into SYNPY-1802
andrewelamb Apr 16, 2026
5c87093
Merge branch 'develop' into SYNPY-1802
andrewelamb Apr 17, 2026
33415e0
fixed tests to work in parallel
andrewelamb Apr 21, 2026
3568ee8
linglings suggestions
andrewelamb Apr 21, 2026
9231112
linglings suggestions
andrewelamb Apr 21, 2026
5d93c23
ran black
andrewelamb Apr 21, 2026
a0d5c70
changed class to operations functions
andrewelamb Apr 21, 2026
c9aaf13
changed class to operations functions
andrewelamb Apr 21, 2026
ed4208e
Merge branch 'develop' into SYNPY-1802
andrewelamb Apr 21, 2026
886e484
added ability to delete null verison files if downloaded
andrewelamb Apr 21, 2026
6197f55
added ability to delete null verison files if downloaded
andrewelamb Apr 21, 2026
16c1a66
linglings suggestions
andrewelamb Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions docs/reference/download_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[](){ #download-list-reference }
# Download List

The Synapse Download List (cart) lets you queue files for bulk download via the Synapse
web UI or API. Files are downloaded individually rather than packaged into a zip because
download lists can exceed 100 GB. Successfully downloaded files are removed from the cart
automatically, so interrupted runs are safely resumable.

## Example

```python
from synapseclient import Synapse
from synapseclient.models import DownloadList

syn = Synapse()
syn.login()

# Download all files in the cart to a local directory
manifest_path = DownloadList().download_files(download_location="./downloads")
```

## API Reference

::: synapseclient.models.DownloadList
options:
inherited_members: true
members:
- download_files
- get_manifest
- add_files
- remove_files
- clear

---

[](){ #download-list-item-reference }
## DownloadListItem

Identifies a specific file version in the download list. Used as input to
`add_files` and `remove_files`.

::: synapseclient.models.DownloadListItem
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ nav:
- Project: reference/project.md
- Folder: reference/folder.md
- File: reference/file.md
- Download List: reference/download_list.md
- Annotations: reference/annotations.md
- Tables: reference/tables.md
- Table Schema: reference/table_schema.md
Expand Down
7 changes: 6 additions & 1 deletion synapseclient/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,12 @@ def submit(args, syn):

def get_download_list(args, syn: synapseclient.Synapse) -> None:
"""Download files from the Synapse download cart"""
manifest_path = syn.get_download_list(downloadLocation=args.downloadLocation)
from synapseclient.models import DownloadList

manifest_path = DownloadList().download_files(
download_location=args.downloadLocation,
synapse_client=syn,
)
syn.logger.info(f"Manifest file: {manifest_path}")


Expand Down
93 changes: 93 additions & 0 deletions synapseclient/api/download_list_services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""This module is responsible for exposing the services defined at:
<https://rest-docs.synapse.org/rest/#org.sagebionetworks.repo.web.controller.DownloadListController>
"""

import json
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
from synapseclient import Synapse
from synapseclient.models.download_list import DownloadListItem


async def clear_download_list_async(
*,
synapse_client: Optional["Synapse"] = None,
) -> None:
"""Clear all files from the user's Synapse download list.

[Endpoint](https://rest-docs.synapse.org/rest/DELETE/download/list.html)

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.
"""
from synapseclient import Synapse

client = Synapse.get_client(synapse_client=synapse_client)
await client.rest_delete_async("/download/list")


async def add_to_download_list_async(
files: list["DownloadListItem"],
*,
synapse_client: Optional["Synapse"] = None,
) -> int:
"""Add a batch of specific file versions to the user's Synapse download list.

[Endpoint](https://rest-docs.synapse.org/rest/POST/download/list/add.html)
Comment thread
andrewelamb marked this conversation as resolved.
Outdated

Arguments:
files: List of DownloadListItem objects identifying the file versions to add.
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 number of files added to the download list.
"""
from synapseclient import Synapse

client = Synapse.get_client(synapse_client=synapse_client)
batch = [
{"fileEntityId": item.file_entity_id, "versionNumber": item.version_number}
for item in files
]
request_body = {"batchToAdd": batch}
result = await client.rest_post_async(
"/download/list/add", body=json.dumps(request_body)
)
return result.get("numberOfFilesAdded", 0)
Comment thread
andrewelamb marked this conversation as resolved.
Outdated


async def remove_from_download_list_async(
files: list["DownloadListItem"],
*,
synapse_client: Optional["Synapse"] = None,
) -> int:
"""Remove a batch of specific file versions from the user's Synapse download list.

[Endpoint](https://rest-docs.synapse.org/rest/POST/download/list/remove.html)

Arguments:
files: List of DownloadListItem objects identifying the file versions to remove.
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 number of files removed from the download list.
"""
from synapseclient import Synapse

client = Synapse.get_client(synapse_client=synapse_client)
batch = [
{"fileEntityId": item.file_entity_id, "versionNumber": item.version_number}
for item in files
]
request_body = {"batchToRemove": batch}
result = await client.rest_post_async(
"/download/list/remove", body=json.dumps(request_body)
)
return result.get("numberOfFilesRemoved", 0)
Comment thread
andrewelamb marked this conversation as resolved.
Outdated
140 changes: 132 additions & 8 deletions synapseclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3146,15 +3146,68 @@ async def upload_file():
############################################################
# Download List #
############################################################
# TODO: Deprecate method in https://sagebionetworks.jira.com/browse/SYNPY-1439
@deprecated(
version="4.13.0",
reason=(
"Use `DownloadList().clear()` instead. "
"See synapseclient.models.DownloadList for the new OOP interface."
),
)
def clear_download_list(self):
"""Clear all files from download list"""
"""Clear all files from download list

Example: Migration to new method
&nbsp;

```python
# Old approach (DEPRECATED)
# syn.clear_download_list()

# New approach (RECOMMENDED)
from synapseclient import Synapse
from synapseclient.models import DownloadList

syn = Synapse()
syn.login()

# Clear all files from the download list
DownloadList().clear()
```
"""
self.restDELETE("/download/list")

# TODO: Deprecate method in https://sagebionetworks.jira.com/browse/SYNPY-1439
@deprecated(
version="4.13.0",
reason=(
"Use `DownloadList().remove_files(files)` instead. "
"See synapseclient.models.DownloadList for the new OOP interface."
),
)
def remove_from_download_list(self, list_of_files: typing.List[typing.Dict]) -> int:
"""Remove a batch of files from download list

Example: Migration to new method
&nbsp;

```python
# Old approach (DEPRECATED)
# syn.remove_from_download_list([
# {"fileEntityId": "syn123", "versionNumber": 1},
# ])

# New approach (RECOMMENDED)
from synapseclient import Synapse
from synapseclient.models import DownloadList, DownloadListItem

syn = Synapse()
syn.login()

# Remove specific file versions from the download list
DownloadList().remove_files([
DownloadListItem(file_entity_id="syn123", version_number=1),
])
```

Arguments:
list_of_files: Array of files in the format of a mapping {fileEntityId: synid, versionNumber: version}

Expand All @@ -3167,7 +3220,13 @@ def remove_from_download_list(self, list_of_files: typing.List[typing.Dict]) ->
)
return num_files_removed

# TODO: Deprecate method in https://sagebionetworks.jira.com/browse/SYNPY-1439
@deprecated(
version="4.13.0",
reason=(
"Use `DownloadList().get_manifest()` instead. "
"See synapseclient.models.DownloadList for the new OOP interface."
),
)
def _generate_manifest_from_download_list(
self,
quoteCharacter: str = '"',
Expand All @@ -3176,8 +3235,25 @@ def _generate_manifest_from_download_list(
separator: str = ",",
header: bool = True,
):
"""
Creates a download list manifest generation request
"""Creates a download list manifest generation request

Example: Migration to new method
&nbsp;

```python
# Old approach (DEPRECATED)
# manifest_handle = syn._generate_manifest_from_download_list()

# New approach (RECOMMENDED)
from synapseclient import Synapse
from synapseclient.models import DownloadList

syn = Synapse()
syn.login()

# Generate and download the manifest CSV
manifest_path = DownloadList().get_manifest()
```

Arguments:
quoteCharacter: The character to be used for quoted elements in the resulting file.
Expand All @@ -3203,10 +3279,34 @@ def _generate_manifest_from_download_list(
uri="/download/list/manifest/async", request=request_body
)

# TODO: Deprecate method in https://sagebionetworks.jira.com/browse/SYNPY-1439
@deprecated(
version="4.13.0",
reason=(
"Use `DownloadList().get_manifest()` instead. "
"See synapseclient.models.DownloadList for the new OOP interface."
),
)
def get_download_list_manifest(self):
"""Get the path of the download list manifest file

Example: Migration to new method
&nbsp;

```python
# Old approach (DEPRECATED)
# manifest_path = syn.get_download_list_manifest()

# New approach (RECOMMENDED)
from synapseclient import Synapse
from synapseclient.models import DownloadList

syn = Synapse()
syn.login()

# Generate and download the manifest CSV
manifest_path = DownloadList().get_manifest()
```

Returns:
Path of download list manifest file
"""
Expand All @@ -3230,10 +3330,34 @@ def get_download_list_manifest(self):
)
return downloaded_path

# TODO: Deprecate method in https://sagebionetworks.jira.com/browse/SYNPY-1439
@deprecated(
version="4.13.0",
reason=(
"Use `DownloadList().download_files(download_location=...)` instead. "
"See synapseclient.models.DownloadList for the new OOP interface."
),
)
def get_download_list(self, downloadLocation: str = None) -> str:
"""Download all files from your Synapse download list

Example: Migration to new method
&nbsp;

```python
# Old approach (DEPRECATED)
# manifest_path = syn.get_download_list(downloadLocation="./downloads")

# New approach (RECOMMENDED)
from synapseclient import Synapse
from synapseclient.models import DownloadList

syn = Synapse()
syn.login()

# Download all files in the cart and get the result manifest path
manifest_path = DownloadList().download_files(download_location="./downloads")
```

Arguments:
downloadLocation: Directory to download files to.

Expand Down
5 changes: 5 additions & 0 deletions synapseclient/core/constants/concrete_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@
"org.sagebionetworks.repo.model.curation.metadata.RecordBasedMetadataTaskProperties"
)

# Download List
DOWNLOAD_LIST_MANIFEST_REQUEST = (
"org.sagebionetworks.repo.model.download.DownloadListManifestRequest"
)

# Grid Session Types
CREATE_GRID_REQUEST = "org.sagebionetworks.repo.model.grid.CreateGridRequest"
GRID_RECORD_SET_EXPORT_REQUEST = (
Expand Down
Loading
Loading