synapseclient 4.2.0__tar.gz → 4.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {synapseclient-4.2.0/synapseclient.egg-info → synapseclient-4.3.1}/PKG-INFO +27 -11
- {synapseclient-4.2.0 → synapseclient-4.3.1}/README.md +20 -5
- {synapseclient-4.2.0 → synapseclient-4.3.1}/setup.cfg +9 -7
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/__init__.py +5 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/__main__.py +1 -3
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/api/__init__.py +2 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/api/entity_services.py +20 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/client.py +40 -79
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/cache.py +1 -1
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/credentials/credential_provider.py +3 -3
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/logging_setup.py +10 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/retry.py +4 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/multipart_upload_async.py +27 -15
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/upload_functions_async.py +3 -27
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/utils.py +8 -36
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/activity.py +30 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/file.py +100 -18
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/mixins/storable_container.py +5 -1
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/activity_protocol.py +21 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/services/storable_entity_components.py +47 -4
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/table.py +11 -1
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/synapsePythonClient +1 -1
- {synapseclient-4.2.0 → synapseclient-4.3.1/synapseclient.egg-info}/PKG-INFO +27 -11
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient.egg-info/requires.txt +6 -5
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/__init__.py +2 -1
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/monitor.py +87 -3
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/sync.py +348 -282
- {synapseclient-4.2.0 → synapseclient-4.3.1}/MANIFEST.in +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/pyproject.toml +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/setup.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/.synapseConfig +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/activity.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/annotations.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/api/annotations.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/api/entity_bundle_services_v2.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/api/file_services.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/async_utils.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/config.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/constants/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/constants/concrete_types.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/constants/config_file_constants.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/constants/limits.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/constants/method_flags.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/credentials/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/credentials/cred_data.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/cumulative_transfer_progress.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/dozer.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/exceptions.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/lock.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/models/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/models/custom_json.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/models/dict_object.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/models/permission.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/multithread_download/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/multithread_download/download_threads.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/pool_provider.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/remote_file_storage_wrappers.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/sts_transfer.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/multipart_upload.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/upload_functions.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/upload_utils.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/version_check.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/entity.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/evaluation.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/annotations.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/evaluation.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/folder.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/mixins/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/mixins/access_control.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/project.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/access_control_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/annotations_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/file_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/folder_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/project_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/storable_container_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/table_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/team_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/protocols/user_protocol.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/services/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/services/search.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/services/storable_entity.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/team.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/user.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/models/wiki.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/services/__init__.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/services/json_schema.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/table.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/team.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/wiki.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient.egg-info/SOURCES.txt +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient.egg-info/dependency_links.txt +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient.egg-info/entry_points.txt +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient.egg-info/not-zip-safe +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient.egg-info/top_level.txt +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/copy_functions.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/describe_functions.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/migrate_functions.py +0 -0
- {synapseclient-4.2.0 → synapseclient-4.3.1}/synapseutils/walk_functions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: synapseclient
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: A client for Synapse, a collaborative, open-source research platform that allows teams to share data, track analyses, and collaborate.
|
|
5
5
|
Home-page: https://www.synapse.org
|
|
6
6
|
Author: The Synapse Engineering Team
|
|
@@ -39,14 +39,13 @@ Requires-Dist: nest-asyncio~=1.6.0
|
|
|
39
39
|
Requires-Dist: asyncio-atexit~=1.0.1
|
|
40
40
|
Requires-Dist: httpx~=0.27.0
|
|
41
41
|
Requires-Dist: tqdm<5.0,>=4.66.2
|
|
42
|
-
Requires-Dist: loky~=3.0.0
|
|
43
42
|
Requires-Dist: async-lru~=2.0.4
|
|
44
43
|
Requires-Dist: psutil~=5.9.8
|
|
45
44
|
Provides-Extra: dev
|
|
46
|
-
Requires-Dist: pytest<
|
|
45
|
+
Requires-Dist: pytest<8.0,>=7.0.0; extra == "dev"
|
|
47
46
|
Requires-Dist: pytest-mock<4.0,>=3.0; extra == "dev"
|
|
48
47
|
Requires-Dist: pytest-socket~=0.6.0; extra == "dev"
|
|
49
|
-
Requires-Dist: pytest-asyncio
|
|
48
|
+
Requires-Dist: pytest-asyncio<1.0,>=0.23.6; extra == "dev"
|
|
50
49
|
Requires-Dist: flake8<4.0,>=3.7.0; extra == "dev"
|
|
51
50
|
Requires-Dist: pytest-xdist[psutil]<3.0.0,>=2.2; extra == "dev"
|
|
52
51
|
Requires-Dist: pytest-rerunfailures~=12.0; extra == "dev"
|
|
@@ -54,16 +53,18 @@ Requires-Dist: func-timeout~=4.3; extra == "dev"
|
|
|
54
53
|
Requires-Dist: pytest-cov~=4.1.0; extra == "dev"
|
|
55
54
|
Requires-Dist: black; extra == "dev"
|
|
56
55
|
Requires-Dist: pre-commit; extra == "dev"
|
|
56
|
+
Requires-Dist: pandas<3.0,>=1.5; extra == "dev"
|
|
57
57
|
Provides-Extra: tests
|
|
58
|
-
Requires-Dist: pytest<
|
|
58
|
+
Requires-Dist: pytest<8.0,>=7.0.0; extra == "tests"
|
|
59
59
|
Requires-Dist: pytest-mock<4.0,>=3.0; extra == "tests"
|
|
60
60
|
Requires-Dist: pytest-socket~=0.6.0; extra == "tests"
|
|
61
|
-
Requires-Dist: pytest-asyncio
|
|
61
|
+
Requires-Dist: pytest-asyncio<1.0,>=0.23.6; extra == "tests"
|
|
62
62
|
Requires-Dist: flake8<4.0,>=3.7.0; extra == "tests"
|
|
63
63
|
Requires-Dist: pytest-xdist[psutil]<3.0.0,>=2.2; extra == "tests"
|
|
64
64
|
Requires-Dist: pytest-rerunfailures~=12.0; extra == "tests"
|
|
65
65
|
Requires-Dist: func-timeout~=4.3; extra == "tests"
|
|
66
66
|
Requires-Dist: pytest-cov~=4.1.0; extra == "tests"
|
|
67
|
+
Requires-Dist: pandas<3.0,>=1.5; extra == "tests"
|
|
67
68
|
Provides-Extra: pandas
|
|
68
69
|
Requires-Dist: pandas<3.0,>=1.5; extra == "pandas"
|
|
69
70
|
Provides-Extra: pysftp
|
|
@@ -125,16 +126,24 @@ The Python Synapse client has been tested on 3.8, 3.9, 3.10 and 3.11 on Mac OS X
|
|
|
125
126
|
|
|
126
127
|
The [Python Synapse Client is on PyPI](https://pypi.python.org/pypi/synapseclient) and can be installed with pip:
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
# Here are a few ways to install the client. Choose the one that fits your use-case
|
|
130
|
+
# sudo may optionally be needed depending on your setup
|
|
131
|
+
|
|
132
|
+
pip install --upgrade synapseclient
|
|
133
|
+
pip install --upgrade "synapseclient[pandas]"
|
|
134
|
+
pip install --upgrade "synapseclient[pandas, pysftp, boto3]"
|
|
129
135
|
|
|
130
136
|
...or to upgrade an existing installation of the Synapse client:
|
|
131
137
|
|
|
132
|
-
|
|
138
|
+
# sudo may optionally be needed depending on your setup
|
|
139
|
+
pip install --upgrade synapseclient
|
|
133
140
|
|
|
134
|
-
The dependencies on `pandas` and `
|
|
141
|
+
The dependencies on `pandas`, `pysftp`, and `boto3` are optional. Synapse
|
|
142
|
+
[Tables](https://python-docs.synapse.org/reference/tables/) integrate
|
|
135
143
|
with [Pandas](http://pandas.pydata.org/). The library `pysftp` is required for users of
|
|
136
|
-
[SFTP](https://python-docs.synapse.org/guides/data_storage/#sftp) file storage.
|
|
137
|
-
to be compiled or installed separately from prebuilt
|
|
144
|
+
[SFTP](https://python-docs.synapse.org/guides/data_storage/#sftp) file storage. All
|
|
145
|
+
libraries require native code to be compiled or installed separately from prebuilt
|
|
146
|
+
binaries.
|
|
138
147
|
|
|
139
148
|
### Install from source
|
|
140
149
|
|
|
@@ -144,6 +153,13 @@ Clone the [source code repository](https://github.com/Sage-Bionetworks/synapsePy
|
|
|
144
153
|
cd synapsePythonClient
|
|
145
154
|
pip install .
|
|
146
155
|
|
|
156
|
+
Alternatively, you can use pip to install a particular branch, commit, or other git reference:
|
|
157
|
+
|
|
158
|
+
pip install git+https://github.com/Sage-Bionetworks/synapsePythonClient@master
|
|
159
|
+
|
|
160
|
+
or
|
|
161
|
+
|
|
162
|
+
pip install git+https://github.com/Sage-Bionetworks/synapsePythonClient@my-commit-hash
|
|
147
163
|
|
|
148
164
|
Command line usage
|
|
149
165
|
------------------
|
|
@@ -44,16 +44,24 @@ The Python Synapse client has been tested on 3.8, 3.9, 3.10 and 3.11 on Mac OS X
|
|
|
44
44
|
|
|
45
45
|
The [Python Synapse Client is on PyPI](https://pypi.python.org/pypi/synapseclient) and can be installed with pip:
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
# Here are a few ways to install the client. Choose the one that fits your use-case
|
|
48
|
+
# sudo may optionally be needed depending on your setup
|
|
49
|
+
|
|
50
|
+
pip install --upgrade synapseclient
|
|
51
|
+
pip install --upgrade "synapseclient[pandas]"
|
|
52
|
+
pip install --upgrade "synapseclient[pandas, pysftp, boto3]"
|
|
48
53
|
|
|
49
54
|
...or to upgrade an existing installation of the Synapse client:
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
# sudo may optionally be needed depending on your setup
|
|
57
|
+
pip install --upgrade synapseclient
|
|
52
58
|
|
|
53
|
-
The dependencies on `pandas` and `
|
|
59
|
+
The dependencies on `pandas`, `pysftp`, and `boto3` are optional. Synapse
|
|
60
|
+
[Tables](https://python-docs.synapse.org/reference/tables/) integrate
|
|
54
61
|
with [Pandas](http://pandas.pydata.org/). The library `pysftp` is required for users of
|
|
55
|
-
[SFTP](https://python-docs.synapse.org/guides/data_storage/#sftp) file storage.
|
|
56
|
-
to be compiled or installed separately from prebuilt
|
|
62
|
+
[SFTP](https://python-docs.synapse.org/guides/data_storage/#sftp) file storage. All
|
|
63
|
+
libraries require native code to be compiled or installed separately from prebuilt
|
|
64
|
+
binaries.
|
|
57
65
|
|
|
58
66
|
### Install from source
|
|
59
67
|
|
|
@@ -63,6 +71,13 @@ Clone the [source code repository](https://github.com/Sage-Bionetworks/synapsePy
|
|
|
63
71
|
cd synapsePythonClient
|
|
64
72
|
pip install .
|
|
65
73
|
|
|
74
|
+
Alternatively, you can use pip to install a particular branch, commit, or other git reference:
|
|
75
|
+
|
|
76
|
+
pip install git+https://github.com/Sage-Bionetworks/synapsePythonClient@master
|
|
77
|
+
|
|
78
|
+
or
|
|
79
|
+
|
|
80
|
+
pip install git+https://github.com/Sage-Bionetworks/synapsePythonClient@my-commit-hash
|
|
66
81
|
|
|
67
82
|
Command line usage
|
|
68
83
|
------------------
|
|
@@ -48,26 +48,26 @@ install_requires =
|
|
|
48
48
|
asyncio-atexit~=1.0.1
|
|
49
49
|
httpx~=0.27.0
|
|
50
50
|
tqdm>=4.66.2,<5.0
|
|
51
|
-
loky~=3.0.0
|
|
52
51
|
async-lru~=2.0.4
|
|
53
52
|
psutil~=5.9.8
|
|
54
53
|
tests_require =
|
|
55
|
-
pytest>=
|
|
54
|
+
pytest>=7.0.0,<8.0
|
|
56
55
|
pytest-mock>=3.0,<4.0
|
|
57
56
|
pytest-socket~=0.6.0
|
|
58
|
-
pytest-asyncio
|
|
57
|
+
pytest-asyncio>=0.23.6,<1.0
|
|
59
58
|
flake8>=3.7.0,<4.0
|
|
60
59
|
pytest-xdist[psutil]>=2.2,<3.0.0
|
|
61
60
|
pytest-rerunfailures~=12.0
|
|
62
61
|
func-timeout~=4.3
|
|
63
62
|
pytest-cov~=4.1.0
|
|
63
|
+
pandas>=1.5,<3.0
|
|
64
64
|
|
|
65
65
|
[options.extras_require]
|
|
66
66
|
dev =
|
|
67
|
-
pytest>=
|
|
67
|
+
pytest>=7.0.0,<8.0
|
|
68
68
|
pytest-mock>=3.0,<4.0
|
|
69
69
|
pytest-socket~=0.6.0
|
|
70
|
-
pytest-asyncio
|
|
70
|
+
pytest-asyncio>=0.23.6,<1.0
|
|
71
71
|
flake8>=3.7.0,<4.0
|
|
72
72
|
pytest-xdist[psutil]>=2.2,<3.0.0
|
|
73
73
|
pytest-rerunfailures~=12.0
|
|
@@ -75,16 +75,18 @@ dev =
|
|
|
75
75
|
pytest-cov~=4.1.0
|
|
76
76
|
black
|
|
77
77
|
pre-commit
|
|
78
|
+
pandas>=1.5,<3.0
|
|
78
79
|
tests =
|
|
79
|
-
pytest>=
|
|
80
|
+
pytest>=7.0.0,<8.0
|
|
80
81
|
pytest-mock>=3.0,<4.0
|
|
81
82
|
pytest-socket~=0.6.0
|
|
82
|
-
pytest-asyncio
|
|
83
|
+
pytest-asyncio>=0.23.6,<1.0
|
|
83
84
|
flake8>=3.7.0,<4.0
|
|
84
85
|
pytest-xdist[psutil]>=2.2,<3.0.0
|
|
85
86
|
pytest-rerunfailures~=12.0
|
|
86
87
|
func-timeout~=4.3
|
|
87
88
|
pytest-cov~=4.1.0
|
|
89
|
+
pandas>=1.5,<3.0
|
|
88
90
|
pandas =
|
|
89
91
|
pandas>=1.5,<3.0
|
|
90
92
|
pysftp =
|
|
@@ -88,6 +88,11 @@ USER_AGENT = {
|
|
|
88
88
|
% (__version__, requests.utils.default_user_agent())
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
USER_AGENT_COMMAND_LINE = {
|
|
92
|
+
"User-Agent": "synapsecommandlineclient/%s %s"
|
|
93
|
+
% (__version__, requests.utils.default_user_agent())
|
|
94
|
+
}
|
|
95
|
+
|
|
91
96
|
# patch json
|
|
92
97
|
from .core.models import custom_json # noqa
|
|
93
98
|
|
|
@@ -1871,9 +1871,7 @@ def _authenticate_login(
|
|
|
1871
1871
|
|
|
1872
1872
|
def main():
|
|
1873
1873
|
args = build_parser().parse_args()
|
|
1874
|
-
synapseclient.USER_AGENT
|
|
1875
|
-
"synapsecommandlineclient " + synapseclient.USER_AGENT["User-Agent"]
|
|
1876
|
-
)
|
|
1874
|
+
synapseclient.USER_AGENT = synapseclient.USER_AGENT_COMMAND_LINE
|
|
1877
1875
|
if args.otel:
|
|
1878
1876
|
trace.set_tracer_provider(
|
|
1879
1877
|
TracerProvider(
|
|
@@ -13,6 +13,7 @@ from .entity_services import (
|
|
|
13
13
|
post_entity,
|
|
14
14
|
put_entity,
|
|
15
15
|
create_access_requirements_if_none,
|
|
16
|
+
delete_entity_generated_by,
|
|
16
17
|
)
|
|
17
18
|
from .file_services import (
|
|
18
19
|
get_file_handle,
|
|
@@ -51,4 +52,5 @@ __all__ = [
|
|
|
51
52
|
"get_upload_destination",
|
|
52
53
|
"get_upload_destination_location",
|
|
53
54
|
"create_access_requirements_if_none",
|
|
55
|
+
"delete_entity_generated_by",
|
|
54
56
|
]
|
|
@@ -175,3 +175,23 @@ async def create_access_requirements_if_none(
|
|
|
175
175
|
"the Synapse access control team to start the process of adding "
|
|
176
176
|
"terms-of-use or review board approval for this entity."
|
|
177
177
|
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
async def delete_entity_generated_by(
|
|
181
|
+
entity_id: str,
|
|
182
|
+
synapse_client: Optional["Synapse"] = None,
|
|
183
|
+
) -> None:
|
|
184
|
+
"""
|
|
185
|
+
Arguments:
|
|
186
|
+
entity_id: The ID of the entity.
|
|
187
|
+
synapse_client: If not passed in or None this will use the last client from
|
|
188
|
+
the `.login()` method.
|
|
189
|
+
|
|
190
|
+
Returns: None
|
|
191
|
+
"""
|
|
192
|
+
from synapseclient import Synapse
|
|
193
|
+
|
|
194
|
+
client = Synapse.get_client(synapse_client=synapse_client)
|
|
195
|
+
return await client.rest_delete_async(
|
|
196
|
+
uri=f"/entity/{entity_id}/generatedBy",
|
|
197
|
+
)
|
|
@@ -34,7 +34,6 @@ import httpx
|
|
|
34
34
|
from deprecated import deprecated
|
|
35
35
|
|
|
36
36
|
from concurrent.futures import ThreadPoolExecutor
|
|
37
|
-
from loky import get_reusable_executor
|
|
38
37
|
|
|
39
38
|
import synapseclient
|
|
40
39
|
from .annotations import (
|
|
@@ -121,9 +120,6 @@ from synapseclient.core.upload.multipart_upload_async import (
|
|
|
121
120
|
multipart_upload_string_async,
|
|
122
121
|
)
|
|
123
122
|
from synapseclient.core.remote_file_storage_wrappers import S3ClientWrapper, SFTPWrapper
|
|
124
|
-
from synapseclient.core.upload.upload_functions import (
|
|
125
|
-
upload_file_handle,
|
|
126
|
-
)
|
|
127
123
|
from synapseclient.core.upload.upload_functions_async import (
|
|
128
124
|
upload_file_handle as upload_file_handle_async,
|
|
129
125
|
upload_synapse_s3,
|
|
@@ -136,7 +132,6 @@ from synapseclient.core.models.permission import Permissions
|
|
|
136
132
|
from opentelemetry import trace
|
|
137
133
|
from opentelemetry.trace import SpanKind
|
|
138
134
|
|
|
139
|
-
|
|
140
135
|
tracer = trace.get_tracer("synapseclient")
|
|
141
136
|
|
|
142
137
|
PRODUCTION_ENDPOINTS = {
|
|
@@ -348,7 +343,7 @@ class Synapse(object):
|
|
|
348
343
|
span.end()
|
|
349
344
|
|
|
350
345
|
event_hooks = {"request": [log_request], "response": [log_response]}
|
|
351
|
-
httpx_timeout = httpx.Timeout(70)
|
|
346
|
+
httpx_timeout = httpx.Timeout(70, pool=None)
|
|
352
347
|
self._requests_session_storage = requests_session_storage or httpx.Client(
|
|
353
348
|
timeout=httpx_timeout, event_hooks=event_hooks
|
|
354
349
|
)
|
|
@@ -402,7 +397,7 @@ class Synapse(object):
|
|
|
402
397
|
self.max_threads = transfer_config["max_threads"]
|
|
403
398
|
self._thread_executor = {}
|
|
404
399
|
self._process_executor = {}
|
|
405
|
-
self.
|
|
400
|
+
self._parallel_file_transfer_semaphore = {}
|
|
406
401
|
self.use_boto_sts_transfers = transfer_config["use_boto_sts"]
|
|
407
402
|
|
|
408
403
|
def _get_requests_session_async_synapse(
|
|
@@ -435,7 +430,7 @@ class Synapse(object):
|
|
|
435
430
|
await self._requests_session_async_synapse[asyncio_event_loop].aclose()
|
|
436
431
|
del self._requests_session_async_synapse[asyncio_event_loop]
|
|
437
432
|
|
|
438
|
-
httpx_timeout = httpx.Timeout(70)
|
|
433
|
+
httpx_timeout = httpx.Timeout(70, pool=None)
|
|
439
434
|
span_dict: Dict[httpx.Request, trace.Span] = {}
|
|
440
435
|
|
|
441
436
|
async def log_request(request: httpx.Request) -> None:
|
|
@@ -513,54 +508,44 @@ class Synapse(object):
|
|
|
513
508
|
asyncio_atexit.register(close_pool)
|
|
514
509
|
return self._thread_executor[asyncio_event_loop]
|
|
515
510
|
|
|
516
|
-
def
|
|
511
|
+
def _get_parallel_file_transfer_semaphore(
|
|
512
|
+
self, asyncio_event_loop: asyncio.AbstractEventLoop
|
|
513
|
+
) -> asyncio.Semaphore:
|
|
517
514
|
"""
|
|
518
|
-
Retrieve the
|
|
519
|
-
|
|
515
|
+
Retrieve the semaphore for the Synapse client. Or create a new one if it does
|
|
516
|
+
not exist. This semaphore is used to limit the number of files that can actively
|
|
517
|
+
enter the uploading/downloading process.
|
|
520
518
|
|
|
521
519
|
This is expected to be called from within an AsyncIO loop.
|
|
522
520
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
To get around this Windows limitation this is using this package:
|
|
530
|
-
https://github.com/joblib/loky
|
|
531
|
-
"""
|
|
532
|
-
if (
|
|
533
|
-
hasattr(self, "_process_executor")
|
|
534
|
-
and asyncio_event_loop in self._process_executor
|
|
535
|
-
and self._process_executor[asyncio_event_loop] is not None
|
|
536
|
-
):
|
|
537
|
-
return self._process_executor[asyncio_event_loop]
|
|
538
|
-
|
|
539
|
-
self._process_executor.update({asyncio_event_loop: get_reusable_executor(1)})
|
|
521
|
+
By default the number of files that can enter the "uploading" state will be
|
|
522
|
+
limited to 2 * max_threads. This is to ensure that the files that are entering
|
|
523
|
+
into the "uploading" state will have priority to finish. Additionally, it means
|
|
524
|
+
that there should be a good spread of files getting up to the "uploading"
|
|
525
|
+
state, entering the "uploading" state, and finishing the "uploading" state.
|
|
540
526
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
""
|
|
547
|
-
Retrieve the semaphore for the Synapse client. Or create a new one if it does not
|
|
548
|
-
exist. This semaphore is used to ensure that only one process is calculating the
|
|
549
|
-
MD5 hash at a time. This is to prevent the custom process pool executor from
|
|
550
|
-
thrashing or handling the waiting. We should let asyncio handle the waiting.
|
|
527
|
+
If we break these states down into large components they would look like:
|
|
528
|
+
- Before "uploading" state: HTTP rest calls to retrieve what data Synapse has
|
|
529
|
+
- Entering "uploading" state: MD5 calculation and HTTP rest calls to determine
|
|
530
|
+
how/where to upload a file to.
|
|
531
|
+
- During "uploading" state: Uploading the file to a storage provider.
|
|
532
|
+
- After "uploading" state: HTTP rest calls to finalize the upload.
|
|
551
533
|
|
|
552
|
-
This
|
|
534
|
+
This has not yet been applied to parallel file downloads. That will take place
|
|
535
|
+
later on.
|
|
553
536
|
"""
|
|
554
537
|
if (
|
|
555
|
-
hasattr(self, "
|
|
556
|
-
and asyncio_event_loop in self.
|
|
557
|
-
and self.
|
|
538
|
+
hasattr(self, "_parallel_file_transfer_semaphore")
|
|
539
|
+
and asyncio_event_loop in self._parallel_file_transfer_semaphore
|
|
540
|
+
and self._parallel_file_transfer_semaphore[asyncio_event_loop] is not None
|
|
558
541
|
):
|
|
559
|
-
return self.
|
|
542
|
+
return self._parallel_file_transfer_semaphore[asyncio_event_loop]
|
|
560
543
|
|
|
561
|
-
self.
|
|
544
|
+
self._parallel_file_transfer_semaphore.update(
|
|
545
|
+
{asyncio_event_loop: asyncio.Semaphore(max(self.max_threads * 2, 1))}
|
|
546
|
+
)
|
|
562
547
|
|
|
563
|
-
return self.
|
|
548
|
+
return self._parallel_file_transfer_semaphore[asyncio_event_loop]
|
|
564
549
|
|
|
565
550
|
# initialize logging
|
|
566
551
|
def _init_logger(self):
|
|
@@ -716,10 +701,10 @@ class Synapse(object):
|
|
|
716
701
|
If no login arguments are provided or only username is provided, login() will attempt to log in using
|
|
717
702
|
information from these sources (in order of preference):
|
|
718
703
|
|
|
719
|
-
1.
|
|
720
|
-
2. User
|
|
704
|
+
1. .synapseConfig file (in user home folder unless configured otherwise)
|
|
705
|
+
2. User defined arguments during a CLI session
|
|
706
|
+
3. User's Personal Access Token (aka: Synapse Auth Token)
|
|
721
707
|
from the environment variable: SYNAPSE_AUTH_TOKEN
|
|
722
|
-
3. .synapseConfig file (in user home folder unless configured otherwise)
|
|
723
708
|
4. Retrieves user's authentication token from AWS SSM Parameter store (if configured)
|
|
724
709
|
|
|
725
710
|
Arguments:
|
|
@@ -1729,7 +1714,6 @@ class Synapse(object):
|
|
|
1729
1714
|
activityName=None,
|
|
1730
1715
|
activityDescription=None,
|
|
1731
1716
|
set_annotations=True,
|
|
1732
|
-
async_file_handle_upload: bool = True,
|
|
1733
1717
|
):
|
|
1734
1718
|
"""
|
|
1735
1719
|
Creates a new Entity or updates an existing Entity, uploading any files in the process.
|
|
@@ -1752,11 +1736,6 @@ class Synapse(object):
|
|
|
1752
1736
|
You will be contacted with regards to the specific data being restricted and the
|
|
1753
1737
|
requirements of access.
|
|
1754
1738
|
set_annotations: If True, set the annotations on the entity. If False, do not set the annotations.
|
|
1755
|
-
async_file_handle_upload: Temporary feature flag that will be removed at an
|
|
1756
|
-
unannounced later date. This is used during the Synapse Utils
|
|
1757
|
-
syncToSynapse to disable the async file handle upload. The is because
|
|
1758
|
-
the multi-threaded logic in the syncToSynapse is not compatible with
|
|
1759
|
-
the async file handle upload.
|
|
1760
1739
|
|
|
1761
1740
|
Returns:
|
|
1762
1741
|
A Synapse Entity, Evaluation, or Wiki
|
|
@@ -1916,37 +1895,20 @@ class Synapse(object):
|
|
|
1916
1895
|
"Entities of type File must have a parentId."
|
|
1917
1896
|
)
|
|
1918
1897
|
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
upload_file_handle_async(
|
|
1922
|
-
self,
|
|
1923
|
-
parent_id_for_upload,
|
|
1924
|
-
local_state["path"]
|
|
1925
|
-
if (
|
|
1926
|
-
synapseStore
|
|
1927
|
-
or local_state_fh.get("externalURL") is None
|
|
1928
|
-
)
|
|
1929
|
-
else local_state_fh.get("externalURL"),
|
|
1930
|
-
synapse_store=synapseStore,
|
|
1931
|
-
md5=local_file_md5_hex or local_state_fh.get("contentMd5"),
|
|
1932
|
-
file_size=local_state_fh.get("contentSize"),
|
|
1933
|
-
mimetype=local_state_fh.get("contentType"),
|
|
1934
|
-
),
|
|
1935
|
-
self,
|
|
1936
|
-
)
|
|
1937
|
-
else:
|
|
1938
|
-
fileHandle = upload_file_handle(
|
|
1898
|
+
fileHandle = wrap_async_to_sync(
|
|
1899
|
+
upload_file_handle_async(
|
|
1939
1900
|
self,
|
|
1940
1901
|
parent_id_for_upload,
|
|
1941
1902
|
local_state["path"]
|
|
1942
1903
|
if (synapseStore or local_state_fh.get("externalURL") is None)
|
|
1943
1904
|
else local_state_fh.get("externalURL"),
|
|
1944
|
-
|
|
1905
|
+
synapse_store=synapseStore,
|
|
1945
1906
|
md5=local_file_md5_hex or local_state_fh.get("contentMd5"),
|
|
1946
1907
|
file_size=local_state_fh.get("contentSize"),
|
|
1947
1908
|
mimetype=local_state_fh.get("contentType"),
|
|
1948
|
-
|
|
1949
|
-
|
|
1909
|
+
),
|
|
1910
|
+
self,
|
|
1911
|
+
)
|
|
1950
1912
|
properties["dataFileHandleId"] = fileHandle["id"]
|
|
1951
1913
|
local_state["_file_handle"] = fileHandle
|
|
1952
1914
|
|
|
@@ -3521,7 +3483,7 @@ class Synapse(object):
|
|
|
3521
3483
|
else:
|
|
3522
3484
|
mode = "wb"
|
|
3523
3485
|
previouslyTransferred = 0
|
|
3524
|
-
sig = hashlib.new("md5", usedforsecurity=False)
|
|
3486
|
+
sig = hashlib.new("md5", usedforsecurity=False) # nosec
|
|
3525
3487
|
|
|
3526
3488
|
try:
|
|
3527
3489
|
with open(temp_destination, mode) as fd:
|
|
@@ -6027,7 +5989,6 @@ class Synapse(object):
|
|
|
6027
5989
|
else:
|
|
6028
5990
|
return
|
|
6029
5991
|
data_dict = json.loads(data_to_parse)
|
|
6030
|
-
|
|
6031
5992
|
if "parentId" in data_dict:
|
|
6032
5993
|
current_span.set_attribute(
|
|
6033
5994
|
"synapse.parent_id", data_dict["parentId"]
|
|
@@ -87,7 +87,7 @@ class Cache:
|
|
|
87
87
|
value = os.path.expandvars(os.path.expanduser(value))
|
|
88
88
|
# create the cache_root_dir if it does not already exist
|
|
89
89
|
if not os.path.exists(value):
|
|
90
|
-
os.makedirs(value)
|
|
90
|
+
os.makedirs(value, exist_ok=True)
|
|
91
91
|
self.__dict__[key] = value
|
|
92
92
|
|
|
93
93
|
def __init__(self, cache_root_dir=CACHE_ROOT_DIR, fanout=1000):
|
{synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/credentials/credential_provider.py
RENAMED
|
@@ -209,9 +209,9 @@ class SynapseCredentialsProviderChain(object):
|
|
|
209
209
|
|
|
210
210
|
By default this class uses the following providers in this order:
|
|
211
211
|
|
|
212
|
-
1. [
|
|
213
|
-
2. [
|
|
214
|
-
3. [
|
|
212
|
+
1. [ConfigFileCredentialsProvider][synapseclient.core.credentials.credential_provider.ConfigFileCredentialsProvider]
|
|
213
|
+
2. [UserArgsCredentialsProvider][synapseclient.core.credentials.credential_provider.UserArgsCredentialsProvider]
|
|
214
|
+
3. [EnvironmentVariableCredentialsProvider][synapseclient.core.credentials.credential_provider.EnvironmentVariableCredentialsProvider]
|
|
215
215
|
4. [AWSParameterStoreCredentialsProvider][synapseclient.core.credentials.credential_provider.AWSParameterStoreCredentialsProvider]
|
|
216
216
|
|
|
217
217
|
Attributes:
|
|
@@ -96,6 +96,16 @@ logging_config.dictConfig(
|
|
|
96
96
|
"propagate": True,
|
|
97
97
|
},
|
|
98
98
|
SILENT_LOGGER_NAME: {"handlers": [], "level": "INFO", "propagate": False},
|
|
99
|
+
# "httpx": {
|
|
100
|
+
# "handlers": ["debug_stderr"],
|
|
101
|
+
# "level": "DEBUG",
|
|
102
|
+
# "propagate": True,
|
|
103
|
+
# },
|
|
104
|
+
# "httpcore": {
|
|
105
|
+
# "handlers": ["debug_stderr"],
|
|
106
|
+
# "level": "DEBUG",
|
|
107
|
+
# "propagate": True,
|
|
108
|
+
# },
|
|
99
109
|
},
|
|
100
110
|
}
|
|
101
111
|
)
|
|
@@ -328,6 +328,8 @@ async def with_retry_time_based_async(
|
|
|
328
328
|
caught_exception = None
|
|
329
329
|
caught_exception_info = None
|
|
330
330
|
response = None
|
|
331
|
+
current_span = trace.get_current_span()
|
|
332
|
+
current_span.set_attribute("synapse.retries", str(retries + 1))
|
|
331
333
|
|
|
332
334
|
try:
|
|
333
335
|
response = await function()
|
|
@@ -449,6 +451,8 @@ def with_retry_time_based(
|
|
|
449
451
|
caught_exception = None
|
|
450
452
|
caught_exception_info = None
|
|
451
453
|
response = None
|
|
454
|
+
current_span = trace.get_current_span()
|
|
455
|
+
current_span.set_attribute("synapse.retries", str(retries + 1))
|
|
452
456
|
|
|
453
457
|
try:
|
|
454
458
|
response = function()
|
{synapseclient-4.2.0 → synapseclient-4.3.1}/synapseclient/core/upload/multipart_upload_async.py
RENAMED
|
@@ -64,6 +64,7 @@ flowchart TD
|
|
|
64
64
|
|
|
65
65
|
# pylint: disable=protected-access
|
|
66
66
|
import asyncio
|
|
67
|
+
from contextlib import contextmanager
|
|
67
68
|
import gc
|
|
68
69
|
import mimetypes
|
|
69
70
|
import os
|
|
@@ -113,7 +114,7 @@ from synapseclient.core.upload.upload_utils import (
|
|
|
113
114
|
)
|
|
114
115
|
from synapseclient.core.utils import MB
|
|
115
116
|
from synapseclient.core.utils import md5_fn as md5_fn_util
|
|
116
|
-
from synapseclient.core.utils import
|
|
117
|
+
from synapseclient.core.utils import md5_for_file_hex
|
|
117
118
|
|
|
118
119
|
if TYPE_CHECKING:
|
|
119
120
|
from synapseclient import Synapse
|
|
@@ -126,6 +127,22 @@ MIN_PART_SIZE = 5 * MB
|
|
|
126
127
|
DEFAULT_PART_SIZE = 8 * MB
|
|
127
128
|
MAX_RETRIES = 7
|
|
128
129
|
|
|
130
|
+
_thread_local = threading.local()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@contextmanager
|
|
134
|
+
def shared_progress_bar(progress_bar):
|
|
135
|
+
"""An outside process that will eventually trigger an upload through this module
|
|
136
|
+
can configure a shared Progress Bar by running its code within this context manager.
|
|
137
|
+
"""
|
|
138
|
+
_thread_local.progress_bar = progress_bar
|
|
139
|
+
try:
|
|
140
|
+
yield
|
|
141
|
+
finally:
|
|
142
|
+
_thread_local.progress_bar.close()
|
|
143
|
+
_thread_local.progress_bar.refresh()
|
|
144
|
+
del _thread_local.progress_bar
|
|
145
|
+
|
|
129
146
|
|
|
130
147
|
@dataclass
|
|
131
148
|
class HandlePartResult:
|
|
@@ -173,6 +190,7 @@ class UploadAttemptAsync:
|
|
|
173
190
|
self._aborted = False
|
|
174
191
|
self._storage_str = storage_str
|
|
175
192
|
|
|
193
|
+
self._close_progress_bar = getattr(_thread_local, "progress_bar", None) is None
|
|
176
194
|
# populated later
|
|
177
195
|
self._upload_id: Optional[str] = None
|
|
178
196
|
self._pre_signed_part_urls: Optional[Mapping[int, str]] = None
|
|
@@ -329,7 +347,9 @@ class UploadAttemptAsync:
|
|
|
329
347
|
if self._is_copy():
|
|
330
348
|
# we won't have bytes to measure during a copy so the byte oriented
|
|
331
349
|
# progress bar is not useful
|
|
332
|
-
self._progress_bar =
|
|
350
|
+
self._progress_bar = getattr(
|
|
351
|
+
_thread_local, "progress_bar", None
|
|
352
|
+
) or tqdm(
|
|
333
353
|
total=part_count,
|
|
334
354
|
desc=self._storage_str or "Copying",
|
|
335
355
|
unit_scale=True,
|
|
@@ -343,7 +363,9 @@ class UploadAttemptAsync:
|
|
|
343
363
|
file_size,
|
|
344
364
|
)
|
|
345
365
|
|
|
346
|
-
self._progress_bar =
|
|
366
|
+
self._progress_bar = getattr(
|
|
367
|
+
_thread_local, "progress_bar", None
|
|
368
|
+
) or tqdm(
|
|
347
369
|
total=file_size,
|
|
348
370
|
desc=self._storage_str or "Uploading",
|
|
349
371
|
unit="B",
|
|
@@ -448,7 +470,7 @@ class UploadAttemptAsync:
|
|
|
448
470
|
Returns:
|
|
449
471
|
The response from the server for the completed upload.
|
|
450
472
|
"""
|
|
451
|
-
if not self._syn.silent and self._progress_bar:
|
|
473
|
+
if not self._syn.silent and self._progress_bar and self._close_progress_bar:
|
|
452
474
|
self._progress_bar.close()
|
|
453
475
|
upload_status_response = await put_file_multipart_complete(
|
|
454
476
|
upload_id=self._upload_id,
|
|
@@ -647,17 +669,7 @@ async def multipart_upload_file_async(
|
|
|
647
669
|
mime_type, _ = mimetypes.guess_type(file_path, strict=False)
|
|
648
670
|
content_type = mime_type or "application/octet-stream"
|
|
649
671
|
|
|
650
|
-
md5_hex = md5 or (
|
|
651
|
-
await md5_for_file_multiprocessing(
|
|
652
|
-
filename=file_path,
|
|
653
|
-
process_pool_executor=syn._get_process_pool_executor(
|
|
654
|
-
asyncio_event_loop=asyncio.get_running_loop()
|
|
655
|
-
),
|
|
656
|
-
md5_semaphore=syn._get_md5_semaphore(
|
|
657
|
-
asyncio_event_loop=asyncio.get_running_loop()
|
|
658
|
-
),
|
|
659
|
-
)
|
|
660
|
-
)
|
|
672
|
+
md5_hex = md5 or md5_for_file_hex(filename=file_path)
|
|
661
673
|
|
|
662
674
|
part_size = get_part_size(
|
|
663
675
|
part_size or DEFAULT_PART_SIZE,
|