synapseclient 4.2.0__tar.gz → 4.3.0__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.
Files changed (103) hide show
  1. {synapseclient-4.2.0/synapseclient.egg-info → synapseclient-4.3.0}/PKG-INFO +27 -10
  2. {synapseclient-4.2.0 → synapseclient-4.3.0}/README.md +20 -5
  3. {synapseclient-4.2.0 → synapseclient-4.3.0}/setup.cfg +9 -6
  4. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/__init__.py +5 -0
  5. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/__main__.py +1 -3
  6. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/api/__init__.py +2 -0
  7. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/api/entity_services.py +20 -0
  8. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/client.py +51 -39
  9. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/cache.py +1 -1
  10. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/credentials/credential_provider.py +3 -3
  11. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/logging_setup.py +10 -0
  12. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/retry.py +4 -0
  13. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/upload/multipart_upload_async.py +25 -3
  14. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/utils.py +6 -2
  15. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/activity.py +30 -0
  16. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/file.py +99 -9
  17. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/mixins/storable_container.py +5 -1
  18. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/activity_protocol.py +21 -0
  19. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/services/storable_entity_components.py +47 -4
  20. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/table.py +11 -1
  21. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/synapsePythonClient +1 -1
  22. {synapseclient-4.2.0 → synapseclient-4.3.0/synapseclient.egg-info}/PKG-INFO +27 -10
  23. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient.egg-info/requires.txt +6 -4
  24. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/__init__.py +2 -1
  25. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/monitor.py +87 -3
  26. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/sync.py +348 -282
  27. {synapseclient-4.2.0 → synapseclient-4.3.0}/MANIFEST.in +0 -0
  28. {synapseclient-4.2.0 → synapseclient-4.3.0}/pyproject.toml +0 -0
  29. {synapseclient-4.2.0 → synapseclient-4.3.0}/setup.py +0 -0
  30. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/.synapseConfig +0 -0
  31. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/activity.py +0 -0
  32. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/annotations.py +0 -0
  33. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/api/annotations.py +0 -0
  34. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/api/entity_bundle_services_v2.py +0 -0
  35. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/api/file_services.py +0 -0
  36. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/__init__.py +0 -0
  37. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/async_utils.py +0 -0
  38. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/config.py +0 -0
  39. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/constants/__init__.py +0 -0
  40. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/constants/concrete_types.py +0 -0
  41. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/constants/config_file_constants.py +0 -0
  42. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/constants/limits.py +0 -0
  43. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/constants/method_flags.py +0 -0
  44. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/credentials/__init__.py +0 -0
  45. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/credentials/cred_data.py +0 -0
  46. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/cumulative_transfer_progress.py +0 -0
  47. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/dozer.py +0 -0
  48. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/exceptions.py +0 -0
  49. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/lock.py +0 -0
  50. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/models/__init__.py +0 -0
  51. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/models/custom_json.py +0 -0
  52. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/models/dict_object.py +0 -0
  53. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/models/permission.py +0 -0
  54. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/multithread_download/__init__.py +0 -0
  55. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/multithread_download/download_threads.py +0 -0
  56. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/pool_provider.py +0 -0
  57. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/remote_file_storage_wrappers.py +0 -0
  58. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/sts_transfer.py +0 -0
  59. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/upload/__init__.py +0 -0
  60. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/upload/multipart_upload.py +0 -0
  61. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/upload/upload_functions.py +0 -0
  62. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/upload/upload_functions_async.py +0 -0
  63. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/upload/upload_utils.py +0 -0
  64. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/core/version_check.py +0 -0
  65. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/entity.py +0 -0
  66. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/evaluation.py +0 -0
  67. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/__init__.py +0 -0
  68. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/annotations.py +0 -0
  69. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/evaluation.py +0 -0
  70. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/folder.py +0 -0
  71. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/mixins/__init__.py +0 -0
  72. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/mixins/access_control.py +0 -0
  73. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/project.py +0 -0
  74. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/__init__.py +0 -0
  75. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/access_control_protocol.py +0 -0
  76. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/annotations_protocol.py +0 -0
  77. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/file_protocol.py +0 -0
  78. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/folder_protocol.py +0 -0
  79. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/project_protocol.py +0 -0
  80. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/storable_container_protocol.py +0 -0
  81. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/table_protocol.py +0 -0
  82. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/team_protocol.py +0 -0
  83. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/protocols/user_protocol.py +0 -0
  84. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/services/__init__.py +0 -0
  85. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/services/search.py +0 -0
  86. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/services/storable_entity.py +0 -0
  87. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/team.py +0 -0
  88. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/user.py +0 -0
  89. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/models/wiki.py +0 -0
  90. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/services/__init__.py +0 -0
  91. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/services/json_schema.py +0 -0
  92. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/table.py +0 -0
  93. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/team.py +0 -0
  94. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient/wiki.py +0 -0
  95. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient.egg-info/SOURCES.txt +0 -0
  96. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient.egg-info/dependency_links.txt +0 -0
  97. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient.egg-info/entry_points.txt +0 -0
  98. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient.egg-info/not-zip-safe +0 -0
  99. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseclient.egg-info/top_level.txt +0 -0
  100. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/copy_functions.py +0 -0
  101. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/describe_functions.py +0 -0
  102. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/migrate_functions.py +0 -0
  103. {synapseclient-4.2.0 → synapseclient-4.3.0}/synapseutils/walk_functions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: synapseclient
3
- Version: 4.2.0
3
+ Version: 4.3.0
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
@@ -43,10 +43,10 @@ Requires-Dist: loky~=3.0.0
43
43
  Requires-Dist: async-lru~=2.0.4
44
44
  Requires-Dist: psutil~=5.9.8
45
45
  Provides-Extra: dev
46
- Requires-Dist: pytest<7.0,>=6.0.0; extra == "dev"
46
+ Requires-Dist: pytest<8.0,>=7.0.0; extra == "dev"
47
47
  Requires-Dist: pytest-mock<4.0,>=3.0; extra == "dev"
48
48
  Requires-Dist: pytest-socket~=0.6.0; extra == "dev"
49
- Requires-Dist: pytest-asyncio~=0.19; extra == "dev"
49
+ Requires-Dist: pytest-asyncio<1.0,>=0.23.6; extra == "dev"
50
50
  Requires-Dist: flake8<4.0,>=3.7.0; extra == "dev"
51
51
  Requires-Dist: pytest-xdist[psutil]<3.0.0,>=2.2; extra == "dev"
52
52
  Requires-Dist: pytest-rerunfailures~=12.0; extra == "dev"
@@ -54,16 +54,18 @@ Requires-Dist: func-timeout~=4.3; extra == "dev"
54
54
  Requires-Dist: pytest-cov~=4.1.0; extra == "dev"
55
55
  Requires-Dist: black; extra == "dev"
56
56
  Requires-Dist: pre-commit; extra == "dev"
57
+ Requires-Dist: pandas<3.0,>=1.5; extra == "dev"
57
58
  Provides-Extra: tests
58
- Requires-Dist: pytest<7.0,>=6.0.0; extra == "tests"
59
+ Requires-Dist: pytest<8.0,>=7.0.0; extra == "tests"
59
60
  Requires-Dist: pytest-mock<4.0,>=3.0; extra == "tests"
60
61
  Requires-Dist: pytest-socket~=0.6.0; extra == "tests"
61
- Requires-Dist: pytest-asyncio~=0.19; extra == "tests"
62
+ Requires-Dist: pytest-asyncio<1.0,>=0.23.6; extra == "tests"
62
63
  Requires-Dist: flake8<4.0,>=3.7.0; extra == "tests"
63
64
  Requires-Dist: pytest-xdist[psutil]<3.0.0,>=2.2; extra == "tests"
64
65
  Requires-Dist: pytest-rerunfailures~=12.0; extra == "tests"
65
66
  Requires-Dist: func-timeout~=4.3; extra == "tests"
66
67
  Requires-Dist: pytest-cov~=4.1.0; extra == "tests"
68
+ Requires-Dist: pandas<3.0,>=1.5; extra == "tests"
67
69
  Provides-Extra: pandas
68
70
  Requires-Dist: pandas<3.0,>=1.5; extra == "pandas"
69
71
  Provides-Extra: pysftp
@@ -125,16 +127,24 @@ The Python Synapse client has been tested on 3.8, 3.9, 3.10 and 3.11 on Mac OS X
125
127
 
126
128
  The [Python Synapse Client is on PyPI](https://pypi.python.org/pypi/synapseclient) and can be installed with pip:
127
129
 
128
- (sudo) pip install synapseclient[pandas,pysftp]
130
+ # Here are a few ways to install the client. Choose the one that fits your use-case
131
+ # sudo may optionally be needed depending on your setup
132
+
133
+ pip install --upgrade synapseclient
134
+ pip install --upgrade "synapseclient[pandas]"
135
+ pip install --upgrade "synapseclient[pandas, pysftp, boto3]"
129
136
 
130
137
  ...or to upgrade an existing installation of the Synapse client:
131
138
 
132
- (sudo) pip install --upgrade synapseclient
139
+ # sudo may optionally be needed depending on your setup
140
+ pip install --upgrade synapseclient
133
141
 
134
- The dependencies on `pandas` and `pysftp` are optional. Synapse [Tables](https://python-docs.synapse.org/reference/tables/) integrate
142
+ The dependencies on `pandas`, `pysftp`, and `boto3` are optional. Synapse
143
+ [Tables](https://python-docs.synapse.org/reference/tables/) integrate
135
144
  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. Both libraries require native code
137
- to be compiled or installed separately from prebuilt binaries.
145
+ [SFTP](https://python-docs.synapse.org/guides/data_storage/#sftp) file storage. All
146
+ libraries require native code to be compiled or installed separately from prebuilt
147
+ binaries.
138
148
 
139
149
  ### Install from source
140
150
 
@@ -144,6 +154,13 @@ Clone the [source code repository](https://github.com/Sage-Bionetworks/synapsePy
144
154
  cd synapsePythonClient
145
155
  pip install .
146
156
 
157
+ Alternatively, you can use pip to install a particular branch, commit, or other git reference:
158
+
159
+ pip install git+https://github.com/Sage-Bionetworks/synapsePythonClient@master
160
+
161
+ or
162
+
163
+ pip install git+https://github.com/Sage-Bionetworks/synapsePythonClient@my-commit-hash
147
164
 
148
165
  Command line usage
149
166
  ------------------
@@ -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
- (sudo) pip install synapseclient[pandas,pysftp]
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
- (sudo) pip install --upgrade synapseclient
56
+ # sudo may optionally be needed depending on your setup
57
+ pip install --upgrade synapseclient
52
58
 
53
- The dependencies on `pandas` and `pysftp` are optional. Synapse [Tables](https://python-docs.synapse.org/reference/tables/) integrate
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. Both libraries require native code
56
- to be compiled or installed separately from prebuilt binaries.
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
  ------------------
@@ -52,22 +52,23 @@ install_requires =
52
52
  async-lru~=2.0.4
53
53
  psutil~=5.9.8
54
54
  tests_require =
55
- pytest>=6.0.0,<7.0
55
+ pytest>=7.0.0,<8.0
56
56
  pytest-mock>=3.0,<4.0
57
57
  pytest-socket~=0.6.0
58
- pytest-asyncio~=0.19
58
+ pytest-asyncio>=0.23.6,<1.0
59
59
  flake8>=3.7.0,<4.0
60
60
  pytest-xdist[psutil]>=2.2,<3.0.0
61
61
  pytest-rerunfailures~=12.0
62
62
  func-timeout~=4.3
63
63
  pytest-cov~=4.1.0
64
+ pandas>=1.5,<3.0
64
65
 
65
66
  [options.extras_require]
66
67
  dev =
67
- pytest>=6.0.0,<7.0
68
+ pytest>=7.0.0,<8.0
68
69
  pytest-mock>=3.0,<4.0
69
70
  pytest-socket~=0.6.0
70
- pytest-asyncio~=0.19
71
+ pytest-asyncio>=0.23.6,<1.0
71
72
  flake8>=3.7.0,<4.0
72
73
  pytest-xdist[psutil]>=2.2,<3.0.0
73
74
  pytest-rerunfailures~=12.0
@@ -75,16 +76,18 @@ dev =
75
76
  pytest-cov~=4.1.0
76
77
  black
77
78
  pre-commit
79
+ pandas>=1.5,<3.0
78
80
  tests =
79
- pytest>=6.0.0,<7.0
81
+ pytest>=7.0.0,<8.0
80
82
  pytest-mock>=3.0,<4.0
81
83
  pytest-socket~=0.6.0
82
- pytest-asyncio~=0.19
84
+ pytest-asyncio>=0.23.6,<1.0
83
85
  flake8>=3.7.0,<4.0
84
86
  pytest-xdist[psutil]>=2.2,<3.0.0
85
87
  pytest-rerunfailures~=12.0
86
88
  func-timeout~=4.3
87
89
  pytest-cov~=4.1.0
90
+ pandas>=1.5,<3.0
88
91
  pandas =
89
92
  pandas>=1.5,<3.0
90
93
  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["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
+ )
@@ -121,9 +121,6 @@ from synapseclient.core.upload.multipart_upload_async import (
121
121
  multipart_upload_string_async,
122
122
  )
123
123
  from synapseclient.core.remote_file_storage_wrappers import S3ClientWrapper, SFTPWrapper
124
- from synapseclient.core.upload.upload_functions import (
125
- upload_file_handle,
126
- )
127
124
  from synapseclient.core.upload.upload_functions_async import (
128
125
  upload_file_handle as upload_file_handle_async,
129
126
  upload_synapse_s3,
@@ -136,7 +133,6 @@ from synapseclient.core.models.permission import Permissions
136
133
  from opentelemetry import trace
137
134
  from opentelemetry.trace import SpanKind
138
135
 
139
-
140
136
  tracer = trace.get_tracer("synapseclient")
141
137
 
142
138
  PRODUCTION_ENDPOINTS = {
@@ -348,7 +344,7 @@ class Synapse(object):
348
344
  span.end()
349
345
 
350
346
  event_hooks = {"request": [log_request], "response": [log_response]}
351
- httpx_timeout = httpx.Timeout(70)
347
+ httpx_timeout = httpx.Timeout(70, pool=None)
352
348
  self._requests_session_storage = requests_session_storage or httpx.Client(
353
349
  timeout=httpx_timeout, event_hooks=event_hooks
354
350
  )
@@ -402,6 +398,7 @@ class Synapse(object):
402
398
  self.max_threads = transfer_config["max_threads"]
403
399
  self._thread_executor = {}
404
400
  self._process_executor = {}
401
+ self._parallel_file_transfer_semaphore = {}
405
402
  self._md5_semaphore = {}
406
403
  self.use_boto_sts_transfers = transfer_config["use_boto_sts"]
407
404
 
@@ -435,7 +432,7 @@ class Synapse(object):
435
432
  await self._requests_session_async_synapse[asyncio_event_loop].aclose()
436
433
  del self._requests_session_async_synapse[asyncio_event_loop]
437
434
 
438
- httpx_timeout = httpx.Timeout(70)
435
+ httpx_timeout = httpx.Timeout(70, pool=None)
439
436
  span_dict: Dict[httpx.Request, trace.Span] = {}
440
437
 
441
438
  async def log_request(request: httpx.Request) -> None:
@@ -562,6 +559,45 @@ class Synapse(object):
562
559
 
563
560
  return self._md5_semaphore[asyncio_event_loop]
564
561
 
562
+ def _get_parallel_file_transfer_semaphore(
563
+ self, asyncio_event_loop: asyncio.AbstractEventLoop
564
+ ) -> asyncio.Semaphore:
565
+ """
566
+ Retrieve the semaphore for the Synapse client. Or create a new one if it does
567
+ not exist. This semaphore is used to limit the number of files that can actively
568
+ enter the uploading/downloading process.
569
+
570
+ This is expected to be called from within an AsyncIO loop.
571
+
572
+ By default the number of files that can enter the "uploading" state will be
573
+ limited to 2 * max_threads. This is to ensure that the files that are entering
574
+ into the "uploading" state will have priority to finish. Additionally, it means
575
+ that there should be a good spread of files getting up to the "uploading"
576
+ state, entering the "uploading" state, and finishing the "uploading" state.
577
+
578
+ If we break these states down into large components they would look like:
579
+ - Before "uploading" state: HTTP rest calls to retrieve what data Synapse has
580
+ - Entering "uploading" state: MD5 calculation and HTTP rest calls to determine
581
+ how/where to upload a file to.
582
+ - During "uploading" state: Uploading the file to a storage provider.
583
+ - After "uploading" state: HTTP rest calls to finalize the upload.
584
+
585
+ This has not yet been applied to parallel file downloads. That will take place
586
+ later on.
587
+ """
588
+ if (
589
+ hasattr(self, "_parallel_file_transfer_semaphore")
590
+ and asyncio_event_loop in self._parallel_file_transfer_semaphore
591
+ and self._parallel_file_transfer_semaphore[asyncio_event_loop] is not None
592
+ ):
593
+ return self._parallel_file_transfer_semaphore[asyncio_event_loop]
594
+
595
+ self._parallel_file_transfer_semaphore.update(
596
+ {asyncio_event_loop: asyncio.Semaphore(max(self.max_threads * 2, 1))}
597
+ )
598
+
599
+ return self._parallel_file_transfer_semaphore[asyncio_event_loop]
600
+
565
601
  # initialize logging
566
602
  def _init_logger(self):
567
603
  """
@@ -716,10 +752,10 @@ class Synapse(object):
716
752
  If no login arguments are provided or only username is provided, login() will attempt to log in using
717
753
  information from these sources (in order of preference):
718
754
 
719
- 1. User defined arguments during a CLI session
720
- 2. User's Personal Access Token (aka: Synapse Auth Token)
755
+ 1. .synapseConfig file (in user home folder unless configured otherwise)
756
+ 2. User defined arguments during a CLI session
757
+ 3. User's Personal Access Token (aka: Synapse Auth Token)
721
758
  from the environment variable: SYNAPSE_AUTH_TOKEN
722
- 3. .synapseConfig file (in user home folder unless configured otherwise)
723
759
  4. Retrieves user's authentication token from AWS SSM Parameter store (if configured)
724
760
 
725
761
  Arguments:
@@ -1729,7 +1765,6 @@ class Synapse(object):
1729
1765
  activityName=None,
1730
1766
  activityDescription=None,
1731
1767
  set_annotations=True,
1732
- async_file_handle_upload: bool = True,
1733
1768
  ):
1734
1769
  """
1735
1770
  Creates a new Entity or updates an existing Entity, uploading any files in the process.
@@ -1752,11 +1787,6 @@ class Synapse(object):
1752
1787
  You will be contacted with regards to the specific data being restricted and the
1753
1788
  requirements of access.
1754
1789
  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
1790
 
1761
1791
  Returns:
1762
1792
  A Synapse Entity, Evaluation, or Wiki
@@ -1916,37 +1946,20 @@ class Synapse(object):
1916
1946
  "Entities of type File must have a parentId."
1917
1947
  )
1918
1948
 
1919
- if async_file_handle_upload:
1920
- fileHandle = wrap_async_to_sync(
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(
1949
+ fileHandle = wrap_async_to_sync(
1950
+ upload_file_handle_async(
1939
1951
  self,
1940
1952
  parent_id_for_upload,
1941
1953
  local_state["path"]
1942
1954
  if (synapseStore or local_state_fh.get("externalURL") is None)
1943
1955
  else local_state_fh.get("externalURL"),
1944
- synapseStore=synapseStore,
1956
+ synapse_store=synapseStore,
1945
1957
  md5=local_file_md5_hex or local_state_fh.get("contentMd5"),
1946
1958
  file_size=local_state_fh.get("contentSize"),
1947
1959
  mimetype=local_state_fh.get("contentType"),
1948
- max_threads=self.max_threads,
1949
- )
1960
+ ),
1961
+ self,
1962
+ )
1950
1963
  properties["dataFileHandleId"] = fileHandle["id"]
1951
1964
  local_state["_file_handle"] = fileHandle
1952
1965
 
@@ -6027,7 +6040,6 @@ class Synapse(object):
6027
6040
  else:
6028
6041
  return
6029
6042
  data_dict = json.loads(data_to_parse)
6030
-
6031
6043
  if "parentId" in data_dict:
6032
6044
  current_span.set_attribute(
6033
6045
  "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):
@@ -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. [UserArgsCredentialsProvider][synapseclient.core.credentials.credential_provider.UserArgsCredentialsProvider]
213
- 2. [EnvironmentVariableCredentialsProvider][synapseclient.core.credentials.credential_provider.EnvironmentVariableCredentialsProvider]
214
- 3. [ConfigFileCredentialsProvider][synapseclient.core.credentials.credential_provider.ConfigFileCredentialsProvider]
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()
@@ -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
@@ -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 = tqdm(
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 = tqdm(
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,
@@ -1400,8 +1400,9 @@ def delete_none_keys(incoming_object: typing.Dict) -> None:
1400
1400
 
1401
1401
  def merge_dataclass_entities(
1402
1402
  source: typing.Union["Project", "Folder", "File"],
1403
- destination: typing.Union["Project", "Folder"],
1404
- ) -> typing.Union["Project", "Folder"]:
1403
+ destination: typing.Union["Project", "Folder", "File"],
1404
+ fields_to_ignore: typing.List[str] = None,
1405
+ ) -> typing.Union["Project", "Folder", "File"]:
1405
1406
  """
1406
1407
  Utility function to merge two dataclass entities together. This is used when we are
1407
1408
  upserting an entity from the Synapse service with the requested changes.
@@ -1409,6 +1410,7 @@ def merge_dataclass_entities(
1409
1410
  Arguments:
1410
1411
  source: The source entity to merge from.
1411
1412
  destination: The destination entity to merge into.
1413
+ fields_to_ignore: A list of fields to ignore when merging.
1412
1414
 
1413
1415
  Returns:
1414
1416
  The destination entity with the merged values.
@@ -1420,6 +1422,8 @@ def merge_dataclass_entities(
1420
1422
 
1421
1423
  # Update destination_dict with source_dict, keeping destination's values in case of conflicts
1422
1424
  for key, value in source_dict.items():
1425
+ if fields_to_ignore is not None and key in fields_to_ignore:
1426
+ continue
1423
1427
  if is_dataclass(getattr(source, key)):
1424
1428
  if hasattr(destination, key):
1425
1429
  setattr(destination, key, getattr(source, key))
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Dict, List, NamedTuple, Optional, Union
5
5
  from opentelemetry import context, trace
6
6
 
7
7
  from synapseclient import Synapse
8
+ from synapseclient.api import delete_entity_generated_by
8
9
  from synapseclient.activity import Activity as Synapse_Activity
9
10
  from synapseclient.core.async_utils import async_to_sync, otel_trace_method
10
11
  from synapseclient.core.constants.concrete_types import USED_ENTITY, USED_URL
@@ -389,3 +390,32 @@ class Activity(ActivitySynchronousProtocol):
389
390
  current_context,
390
391
  ),
391
392
  )
393
+ parent.activity = None
394
+
395
+ @classmethod
396
+ async def disassociate_from_entity_async(
397
+ cls,
398
+ parent: Union["Table", "File"],
399
+ synapse_client: Optional[Synapse] = None,
400
+ ) -> None:
401
+ """
402
+ Disassociate the Activity from the parent entity. This is the first step in
403
+ deleting the Activity. If you have other entities that are associated with this
404
+ Activity you must disassociate them by calling this method on them as well.
405
+
406
+ Arguments:
407
+ parent: The parent entity this activity is associated with.
408
+ synapse_client: If not passed in or None this will use the last client
409
+ from the `.login()` method.
410
+
411
+ Raises:
412
+ ValueError: If the parent does not have an ID.
413
+ """
414
+ # TODO: Input validation: SYNPY-1400
415
+ with tracer.start_as_current_span(
416
+ name=f"Activity_disassociate: Parent_ID: {parent.id}"
417
+ ):
418
+ await delete_entity_generated_by(
419
+ entity_id=parent.id, synapse_client=synapse_client
420
+ )
421
+ parent.activity = None