toil 7.0.0__py3-none-any.whl → 8.0.0__py3-none-any.whl

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 (190) hide show
  1. toil/__init__.py +121 -83
  2. toil/batchSystems/__init__.py +1 -0
  3. toil/batchSystems/abstractBatchSystem.py +137 -77
  4. toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
  5. toil/batchSystems/awsBatch.py +237 -128
  6. toil/batchSystems/cleanup_support.py +22 -16
  7. toil/batchSystems/contained_executor.py +30 -26
  8. toil/batchSystems/gridengine.py +85 -49
  9. toil/batchSystems/htcondor.py +164 -87
  10. toil/batchSystems/kubernetes.py +622 -386
  11. toil/batchSystems/local_support.py +17 -12
  12. toil/batchSystems/lsf.py +132 -79
  13. toil/batchSystems/lsfHelper.py +13 -11
  14. toil/batchSystems/mesos/__init__.py +41 -29
  15. toil/batchSystems/mesos/batchSystem.py +288 -149
  16. toil/batchSystems/mesos/executor.py +77 -49
  17. toil/batchSystems/mesos/test/__init__.py +31 -23
  18. toil/batchSystems/options.py +38 -29
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +293 -123
  21. toil/batchSystems/slurm.py +489 -137
  22. toil/batchSystems/torque.py +46 -32
  23. toil/bus.py +141 -73
  24. toil/common.py +630 -359
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1114 -532
  27. toil/cwl/utils.py +17 -22
  28. toil/deferred.py +62 -41
  29. toil/exceptions.py +5 -3
  30. toil/fileStores/__init__.py +5 -5
  31. toil/fileStores/abstractFileStore.py +88 -57
  32. toil/fileStores/cachingFileStore.py +711 -247
  33. toil/fileStores/nonCachingFileStore.py +113 -75
  34. toil/job.py +988 -315
  35. toil/jobStores/abstractJobStore.py +387 -243
  36. toil/jobStores/aws/jobStore.py +727 -403
  37. toil/jobStores/aws/utils.py +161 -109
  38. toil/jobStores/conftest.py +1 -0
  39. toil/jobStores/fileJobStore.py +289 -151
  40. toil/jobStores/googleJobStore.py +137 -70
  41. toil/jobStores/utils.py +36 -15
  42. toil/leader.py +614 -269
  43. toil/lib/accelerators.py +115 -18
  44. toil/lib/aws/__init__.py +55 -28
  45. toil/lib/aws/ami.py +122 -87
  46. toil/lib/aws/iam.py +284 -108
  47. toil/lib/aws/s3.py +31 -0
  48. toil/lib/aws/session.py +193 -58
  49. toil/lib/aws/utils.py +238 -218
  50. toil/lib/bioio.py +13 -5
  51. toil/lib/compatibility.py +11 -6
  52. toil/lib/conversions.py +83 -49
  53. toil/lib/docker.py +131 -103
  54. toil/lib/ec2.py +322 -209
  55. toil/lib/ec2nodes.py +174 -106
  56. toil/lib/encryption/_dummy.py +5 -3
  57. toil/lib/encryption/_nacl.py +10 -6
  58. toil/lib/encryption/conftest.py +1 -0
  59. toil/lib/exceptions.py +26 -7
  60. toil/lib/expando.py +4 -2
  61. toil/lib/ftp_utils.py +217 -0
  62. toil/lib/generatedEC2Lists.py +127 -19
  63. toil/lib/humanize.py +6 -2
  64. toil/lib/integration.py +341 -0
  65. toil/lib/io.py +99 -11
  66. toil/lib/iterables.py +4 -2
  67. toil/lib/memoize.py +12 -8
  68. toil/lib/misc.py +65 -18
  69. toil/lib/objects.py +2 -2
  70. toil/lib/resources.py +19 -7
  71. toil/lib/retry.py +115 -77
  72. toil/lib/threading.py +282 -80
  73. toil/lib/throttle.py +15 -14
  74. toil/options/common.py +834 -401
  75. toil/options/cwl.py +175 -90
  76. toil/options/runner.py +50 -0
  77. toil/options/wdl.py +70 -19
  78. toil/provisioners/__init__.py +111 -46
  79. toil/provisioners/abstractProvisioner.py +322 -157
  80. toil/provisioners/aws/__init__.py +62 -30
  81. toil/provisioners/aws/awsProvisioner.py +980 -627
  82. toil/provisioners/clusterScaler.py +541 -279
  83. toil/provisioners/gceProvisioner.py +282 -179
  84. toil/provisioners/node.py +147 -79
  85. toil/realtimeLogger.py +34 -22
  86. toil/resource.py +137 -75
  87. toil/server/app.py +127 -61
  88. toil/server/celery_app.py +3 -1
  89. toil/server/cli/wes_cwl_runner.py +82 -53
  90. toil/server/utils.py +54 -28
  91. toil/server/wes/abstract_backend.py +64 -26
  92. toil/server/wes/amazon_wes_utils.py +21 -15
  93. toil/server/wes/tasks.py +121 -63
  94. toil/server/wes/toil_backend.py +142 -107
  95. toil/server/wsgi_app.py +4 -3
  96. toil/serviceManager.py +58 -22
  97. toil/statsAndLogging.py +148 -64
  98. toil/test/__init__.py +263 -179
  99. toil/test/batchSystems/batchSystemTest.py +438 -195
  100. toil/test/batchSystems/batch_system_plugin_test.py +18 -7
  101. toil/test/batchSystems/test_gridengine.py +173 -0
  102. toil/test/batchSystems/test_lsf_helper.py +67 -58
  103. toil/test/batchSystems/test_slurm.py +93 -47
  104. toil/test/cactus/test_cactus_integration.py +20 -22
  105. toil/test/cwl/cwlTest.py +271 -71
  106. toil/test/cwl/measure_default_memory.cwl +12 -0
  107. toil/test/cwl/not_run_required_input.cwl +29 -0
  108. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  109. toil/test/docs/scriptsTest.py +60 -34
  110. toil/test/jobStores/jobStoreTest.py +412 -235
  111. toil/test/lib/aws/test_iam.py +116 -48
  112. toil/test/lib/aws/test_s3.py +16 -9
  113. toil/test/lib/aws/test_utils.py +5 -6
  114. toil/test/lib/dockerTest.py +118 -141
  115. toil/test/lib/test_conversions.py +113 -115
  116. toil/test/lib/test_ec2.py +57 -49
  117. toil/test/lib/test_integration.py +104 -0
  118. toil/test/lib/test_misc.py +12 -5
  119. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  120. toil/test/mesos/helloWorld.py +7 -6
  121. toil/test/mesos/stress.py +25 -20
  122. toil/test/options/options.py +7 -2
  123. toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
  124. toil/test/provisioners/clusterScalerTest.py +440 -250
  125. toil/test/provisioners/clusterTest.py +81 -42
  126. toil/test/provisioners/gceProvisionerTest.py +174 -100
  127. toil/test/provisioners/provisionerTest.py +25 -13
  128. toil/test/provisioners/restartScript.py +5 -4
  129. toil/test/server/serverTest.py +188 -141
  130. toil/test/sort/restart_sort.py +137 -68
  131. toil/test/sort/sort.py +134 -66
  132. toil/test/sort/sortTest.py +91 -49
  133. toil/test/src/autoDeploymentTest.py +140 -100
  134. toil/test/src/busTest.py +20 -18
  135. toil/test/src/checkpointTest.py +8 -2
  136. toil/test/src/deferredFunctionTest.py +49 -35
  137. toil/test/src/dockerCheckTest.py +33 -26
  138. toil/test/src/environmentTest.py +20 -10
  139. toil/test/src/fileStoreTest.py +538 -271
  140. toil/test/src/helloWorldTest.py +7 -4
  141. toil/test/src/importExportFileTest.py +61 -31
  142. toil/test/src/jobDescriptionTest.py +32 -17
  143. toil/test/src/jobEncapsulationTest.py +2 -0
  144. toil/test/src/jobFileStoreTest.py +74 -50
  145. toil/test/src/jobServiceTest.py +187 -73
  146. toil/test/src/jobTest.py +120 -70
  147. toil/test/src/miscTests.py +19 -18
  148. toil/test/src/promisedRequirementTest.py +82 -36
  149. toil/test/src/promisesTest.py +7 -6
  150. toil/test/src/realtimeLoggerTest.py +6 -6
  151. toil/test/src/regularLogTest.py +71 -37
  152. toil/test/src/resourceTest.py +80 -49
  153. toil/test/src/restartDAGTest.py +36 -22
  154. toil/test/src/resumabilityTest.py +9 -2
  155. toil/test/src/retainTempDirTest.py +45 -14
  156. toil/test/src/systemTest.py +12 -8
  157. toil/test/src/threadingTest.py +44 -25
  158. toil/test/src/toilContextManagerTest.py +10 -7
  159. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  160. toil/test/src/workerTest.py +33 -16
  161. toil/test/utils/toilDebugTest.py +70 -58
  162. toil/test/utils/toilKillTest.py +4 -5
  163. toil/test/utils/utilsTest.py +239 -102
  164. toil/test/wdl/wdltoil_test.py +789 -148
  165. toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
  166. toil/toilState.py +52 -26
  167. toil/utils/toilConfig.py +13 -4
  168. toil/utils/toilDebugFile.py +44 -27
  169. toil/utils/toilDebugJob.py +85 -25
  170. toil/utils/toilDestroyCluster.py +11 -6
  171. toil/utils/toilKill.py +8 -3
  172. toil/utils/toilLaunchCluster.py +251 -145
  173. toil/utils/toilMain.py +37 -16
  174. toil/utils/toilRsyncCluster.py +27 -14
  175. toil/utils/toilSshCluster.py +45 -22
  176. toil/utils/toilStats.py +75 -36
  177. toil/utils/toilStatus.py +226 -119
  178. toil/utils/toilUpdateEC2Instances.py +3 -1
  179. toil/version.py +11 -11
  180. toil/wdl/utils.py +5 -5
  181. toil/wdl/wdltoil.py +3513 -1052
  182. toil/worker.py +269 -128
  183. toil-8.0.0.dist-info/METADATA +173 -0
  184. toil-8.0.0.dist-info/RECORD +253 -0
  185. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
  186. toil-7.0.0.dist-info/METADATA +0 -158
  187. toil-7.0.0.dist-info/RECORD +0 -244
  188. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/LICENSE +0 -0
  189. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
  190. {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
toil/lib/ftp_utils.py ADDED
@@ -0,0 +1,217 @@
1
+ # Copyright 2017 Oregon Health and Science University
2
+ #
3
+ # Copyright (C) 2015-2021 Regents of the University of California
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+
18
+ import ftplib
19
+ import logging
20
+ import netrc
21
+ import os
22
+ from contextlib import closing
23
+ from typing import Optional, Any, cast, IO
24
+ from urllib.parse import urlparse
25
+ from urllib.request import urlopen
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class FtpFsAccess:
31
+ """
32
+ FTP access with upload.
33
+
34
+ Taken and modified from https://github.com/ohsu-comp-bio/cwl-tes/blob/03f0096f9fae8acd527687d3460a726e09190c3a/cwl_tes/ftp.py#L37-L251
35
+ """
36
+ # TODO: Properly support FTP over SSL
37
+
38
+ def __init__(
39
+ self, cache: Optional[dict[Any, ftplib.FTP]] = None
40
+ ):
41
+ """
42
+ FTP object to handle FTP connections. By default, connect over FTP with TLS.
43
+
44
+ :param cache: cache of generated FTP objects
45
+ """
46
+ self.cache = cache or {}
47
+ self.netrc = None
48
+ try:
49
+ if "HOME" in os.environ:
50
+ if os.path.exists(os.path.join(os.environ["HOME"], ".netrc")):
51
+ self.netrc = netrc.netrc(os.path.join(os.environ["HOME"], ".netrc"))
52
+ elif os.path.exists(os.path.join(os.curdir, ".netrc")):
53
+ self.netrc = netrc.netrc(os.path.join(os.curdir, ".netrc"))
54
+ except netrc.NetrcParseError as err:
55
+ logger.debug(err)
56
+
57
+ def exists(self, fn: str) -> bool:
58
+ """
59
+ Check if a file/directory exists over an FTP server
60
+ :param fn: FTP url
61
+ :return: True or false depending on whether the object exists on the server
62
+ """
63
+ return self.isfile(fn) or self.isdir(fn)
64
+
65
+ def isfile(self, fn: str) -> bool:
66
+ """
67
+ Check if the FTP url points to a file
68
+ :param fn: FTP url
69
+ :return: True if url is file, else false
70
+ """
71
+ ftp = self._connect(fn)
72
+ if ftp:
73
+ try:
74
+ if not self.size(fn) is None:
75
+ return True
76
+ else:
77
+ return False
78
+ except ftplib.all_errors:
79
+ return False
80
+ return False
81
+
82
+ def isdir(self, fn: str) -> bool:
83
+ """
84
+ Check if the FTP url points to a directory
85
+ :param fn: FTP url
86
+ :return: True if url is directory, else false
87
+ """
88
+ ftp = self._connect(fn)
89
+ if ftp:
90
+ try:
91
+ cwd = ftp.pwd()
92
+ ftp.cwd(urlparse(fn).path)
93
+ ftp.cwd(cwd)
94
+ return True
95
+ except ftplib.all_errors:
96
+ return False
97
+ return False
98
+
99
+ def open(self, fn: str, mode: str) -> IO[bytes]:
100
+ """
101
+ Open an FTP url.
102
+
103
+ Only supports reading, no write support.
104
+ :param fn: FTP url
105
+ :param mode: Mode to open FTP url in
106
+ :return:
107
+ """
108
+ if "r" in mode:
109
+ host, port, user, passwd, path = self._parse_url(fn)
110
+ handle = urlopen("ftp://{}:{}@{}:{}/{}".format(user, passwd, host, port, path))
111
+ return cast(IO[bytes], closing(handle))
112
+ # TODO: support write mode
113
+ raise Exception("Write mode FTP not implemented")
114
+
115
+ def _parse_url(
116
+ self, url: str
117
+ ) -> tuple[str, int, Optional[str], Optional[str], str]:
118
+ """
119
+ Parse an FTP url into hostname, username, password, and path
120
+ :param url:
121
+ :return: hostname, username, password, path
122
+ """
123
+ parse = urlparse(url)
124
+ user = parse.username
125
+ passwd = parse.password
126
+ host = parse.hostname
127
+ port = parse.port
128
+ path = parse.path
129
+ if host is None:
130
+ # The URL we connect to must have a host
131
+ raise RuntimeError(f"FTP URL does not contain a host: {url}")
132
+ # default port is 21
133
+ if port is None:
134
+ port = 21
135
+ if parse.scheme == "ftp":
136
+ if not user and self.netrc:
137
+ if host is not None:
138
+ creds = self.netrc.authenticators(host)
139
+ if creds:
140
+ user, _, passwd = creds
141
+ if not user:
142
+ if host is not None:
143
+ user, passwd = self._recall_credentials(host)
144
+ if passwd is None:
145
+ passwd = "anonymous@"
146
+ if user is None:
147
+ user = "anonymous"
148
+ return host, port, user, passwd, path
149
+
150
+ def _connect(self, url: str) -> Optional[ftplib.FTP]:
151
+ """
152
+ Connect to an FTP server. Handles authentication.
153
+ :param url: FTP url
154
+ :return: FTP object
155
+ """
156
+ parse = urlparse(url)
157
+ if parse.scheme == "ftp":
158
+ host, port, user, passwd, _ = self._parse_url(url)
159
+ if host is None:
160
+ # there has to be a host
161
+ return None
162
+ if (host, user, passwd) in self.cache:
163
+ if self.cache[(host, user, passwd)].pwd():
164
+ return self.cache[(host, user, passwd)]
165
+ ftp = ftplib.FTP_TLS()
166
+ # Note: the FTP lib logger handles logging itself and doesn't go through our logging implementation
167
+ ftp.set_debuglevel(1 if logger.isEnabledFor(logging.DEBUG) else 0)
168
+ ftp.connect(host, port)
169
+ env_user = os.getenv("TOIL_FTP_USER")
170
+ env_passwd = os.getenv("TOIL_FTP_PASSWORD")
171
+ if env_user:
172
+ user = env_user
173
+ if env_passwd:
174
+ passwd = env_passwd
175
+ ftp.login(user or "", passwd or "", secure=False)
176
+ self.cache[(host, user, passwd)] = ftp
177
+ return ftp
178
+ return None
179
+
180
+ def _recall_credentials(
181
+ self, desired_host: str
182
+ ) -> tuple[Optional[str], Optional[str]]:
183
+ """
184
+ Grab the cached credentials
185
+ :param desired_host: FTP hostname
186
+ :return: username, password
187
+ """
188
+ for host, user, passwd in self.cache:
189
+ if desired_host == host:
190
+ return user, passwd
191
+ return None, None
192
+
193
+ def size(self, fn: str) -> Optional[int]:
194
+ """
195
+ Get the size of an FTP object
196
+ :param fn: FTP url
197
+ :return: Size of object
198
+ """
199
+ ftp = self._connect(fn)
200
+ if ftp:
201
+ host, port, user, passwd, path = self._parse_url(fn)
202
+ try:
203
+ return ftp.size(path)
204
+ except ftplib.all_errors as e:
205
+ if str(e) == "550 SIZE not allowed in ASCII mode":
206
+ # some servers don't allow grabbing size in ascii mode
207
+ # https://stackoverflow.com/questions/22090001/get-folder-size-using-ftplib/22093848#22093848
208
+ ftp.voidcmd("TYPE I")
209
+ return ftp.size(path)
210
+ handle = urlopen("ftp://{}:{}@{}:{}/{}".format(user, passwd, host, port, path))
211
+ info = handle.info()
212
+ handle.close()
213
+ if "Content-length" in info:
214
+ return int(info["Content-length"])
215
+ return None
216
+
217
+ return None