toil 6.1.0a1__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 (193) hide show
  1. toil/__init__.py +122 -315
  2. toil/batchSystems/__init__.py +1 -0
  3. toil/batchSystems/abstractBatchSystem.py +173 -89
  4. toil/batchSystems/abstractGridEngineBatchSystem.py +272 -148
  5. toil/batchSystems/awsBatch.py +244 -135
  6. toil/batchSystems/cleanup_support.py +26 -16
  7. toil/batchSystems/contained_executor.py +31 -28
  8. toil/batchSystems/gridengine.py +86 -50
  9. toil/batchSystems/htcondor.py +166 -89
  10. toil/batchSystems/kubernetes.py +632 -382
  11. toil/batchSystems/local_support.py +20 -15
  12. toil/batchSystems/lsf.py +134 -81
  13. toil/batchSystems/lsfHelper.py +13 -11
  14. toil/batchSystems/mesos/__init__.py +41 -29
  15. toil/batchSystems/mesos/batchSystem.py +290 -151
  16. toil/batchSystems/mesos/executor.py +79 -50
  17. toil/batchSystems/mesos/test/__init__.py +31 -23
  18. toil/batchSystems/options.py +46 -28
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +296 -125
  21. toil/batchSystems/slurm.py +603 -138
  22. toil/batchSystems/torque.py +47 -33
  23. toil/bus.py +186 -76
  24. toil/common.py +664 -368
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1136 -483
  27. toil/cwl/utils.py +17 -22
  28. toil/deferred.py +63 -42
  29. toil/exceptions.py +5 -3
  30. toil/fileStores/__init__.py +5 -5
  31. toil/fileStores/abstractFileStore.py +140 -60
  32. toil/fileStores/cachingFileStore.py +717 -269
  33. toil/fileStores/nonCachingFileStore.py +116 -87
  34. toil/job.py +1225 -368
  35. toil/jobStores/abstractJobStore.py +416 -266
  36. toil/jobStores/aws/jobStore.py +863 -477
  37. toil/jobStores/aws/utils.py +201 -120
  38. toil/jobStores/conftest.py +3 -2
  39. toil/jobStores/fileJobStore.py +292 -154
  40. toil/jobStores/googleJobStore.py +140 -74
  41. toil/jobStores/utils.py +36 -15
  42. toil/leader.py +668 -272
  43. toil/lib/accelerators.py +115 -18
  44. toil/lib/aws/__init__.py +74 -31
  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 +214 -39
  49. toil/lib/aws/utils.py +287 -231
  50. toil/lib/bioio.py +13 -5
  51. toil/lib/compatibility.py +11 -6
  52. toil/lib/conversions.py +104 -47
  53. toil/lib/docker.py +131 -103
  54. toil/lib/ec2.py +361 -199
  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 +5 -3
  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 +141 -15
  66. toil/lib/iterables.py +4 -2
  67. toil/lib/memoize.py +12 -8
  68. toil/lib/misc.py +66 -21
  69. toil/lib/objects.py +2 -2
  70. toil/lib/resources.py +68 -15
  71. toil/lib/retry.py +126 -81
  72. toil/lib/threading.py +299 -82
  73. toil/lib/throttle.py +16 -15
  74. toil/options/common.py +843 -409
  75. toil/options/cwl.py +175 -90
  76. toil/options/runner.py +50 -0
  77. toil/options/wdl.py +73 -17
  78. toil/provisioners/__init__.py +117 -46
  79. toil/provisioners/abstractProvisioner.py +332 -157
  80. toil/provisioners/aws/__init__.py +70 -33
  81. toil/provisioners/aws/awsProvisioner.py +1145 -715
  82. toil/provisioners/clusterScaler.py +541 -279
  83. toil/provisioners/gceProvisioner.py +282 -179
  84. toil/provisioners/node.py +155 -79
  85. toil/realtimeLogger.py +34 -22
  86. toil/resource.py +137 -75
  87. toil/server/app.py +128 -62
  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 +224 -70
  98. toil/test/__init__.py +282 -183
  99. toil/test/batchSystems/batchSystemTest.py +460 -210
  100. toil/test/batchSystems/batch_system_plugin_test.py +90 -0
  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 +110 -49
  104. toil/test/cactus/__init__.py +0 -0
  105. toil/test/cactus/test_cactus_integration.py +56 -0
  106. toil/test/cwl/cwlTest.py +496 -287
  107. toil/test/cwl/measure_default_memory.cwl +12 -0
  108. toil/test/cwl/not_run_required_input.cwl +29 -0
  109. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  110. toil/test/cwl/seqtk_seq.cwl +1 -1
  111. toil/test/docs/scriptsTest.py +69 -46
  112. toil/test/jobStores/jobStoreTest.py +427 -264
  113. toil/test/lib/aws/test_iam.py +118 -50
  114. toil/test/lib/aws/test_s3.py +16 -9
  115. toil/test/lib/aws/test_utils.py +5 -6
  116. toil/test/lib/dockerTest.py +118 -141
  117. toil/test/lib/test_conversions.py +113 -115
  118. toil/test/lib/test_ec2.py +58 -50
  119. toil/test/lib/test_integration.py +104 -0
  120. toil/test/lib/test_misc.py +12 -5
  121. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  122. toil/test/mesos/helloWorld.py +7 -6
  123. toil/test/mesos/stress.py +25 -20
  124. toil/test/options/__init__.py +13 -0
  125. toil/test/options/options.py +42 -0
  126. toil/test/provisioners/aws/awsProvisionerTest.py +320 -150
  127. toil/test/provisioners/clusterScalerTest.py +440 -250
  128. toil/test/provisioners/clusterTest.py +166 -44
  129. toil/test/provisioners/gceProvisionerTest.py +174 -100
  130. toil/test/provisioners/provisionerTest.py +25 -13
  131. toil/test/provisioners/restartScript.py +5 -4
  132. toil/test/server/serverTest.py +188 -141
  133. toil/test/sort/restart_sort.py +137 -68
  134. toil/test/sort/sort.py +134 -66
  135. toil/test/sort/sortTest.py +91 -49
  136. toil/test/src/autoDeploymentTest.py +141 -101
  137. toil/test/src/busTest.py +20 -18
  138. toil/test/src/checkpointTest.py +8 -2
  139. toil/test/src/deferredFunctionTest.py +49 -35
  140. toil/test/src/dockerCheckTest.py +32 -24
  141. toil/test/src/environmentTest.py +135 -0
  142. toil/test/src/fileStoreTest.py +539 -272
  143. toil/test/src/helloWorldTest.py +7 -4
  144. toil/test/src/importExportFileTest.py +61 -31
  145. toil/test/src/jobDescriptionTest.py +46 -21
  146. toil/test/src/jobEncapsulationTest.py +2 -0
  147. toil/test/src/jobFileStoreTest.py +74 -50
  148. toil/test/src/jobServiceTest.py +187 -73
  149. toil/test/src/jobTest.py +121 -71
  150. toil/test/src/miscTests.py +19 -18
  151. toil/test/src/promisedRequirementTest.py +82 -36
  152. toil/test/src/promisesTest.py +7 -6
  153. toil/test/src/realtimeLoggerTest.py +10 -6
  154. toil/test/src/regularLogTest.py +71 -37
  155. toil/test/src/resourceTest.py +80 -49
  156. toil/test/src/restartDAGTest.py +36 -22
  157. toil/test/src/resumabilityTest.py +9 -2
  158. toil/test/src/retainTempDirTest.py +45 -14
  159. toil/test/src/systemTest.py +12 -8
  160. toil/test/src/threadingTest.py +44 -25
  161. toil/test/src/toilContextManagerTest.py +10 -7
  162. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  163. toil/test/src/workerTest.py +73 -23
  164. toil/test/utils/toilDebugTest.py +103 -33
  165. toil/test/utils/toilKillTest.py +4 -5
  166. toil/test/utils/utilsTest.py +245 -106
  167. toil/test/wdl/wdltoil_test.py +818 -149
  168. toil/test/wdl/wdltoil_test_kubernetes.py +91 -0
  169. toil/toilState.py +120 -35
  170. toil/utils/toilConfig.py +13 -4
  171. toil/utils/toilDebugFile.py +44 -27
  172. toil/utils/toilDebugJob.py +214 -27
  173. toil/utils/toilDestroyCluster.py +11 -6
  174. toil/utils/toilKill.py +8 -3
  175. toil/utils/toilLaunchCluster.py +256 -140
  176. toil/utils/toilMain.py +37 -16
  177. toil/utils/toilRsyncCluster.py +32 -14
  178. toil/utils/toilSshCluster.py +49 -22
  179. toil/utils/toilStats.py +356 -273
  180. toil/utils/toilStatus.py +292 -139
  181. toil/utils/toilUpdateEC2Instances.py +3 -1
  182. toil/version.py +12 -12
  183. toil/wdl/utils.py +5 -5
  184. toil/wdl/wdltoil.py +3913 -1033
  185. toil/worker.py +367 -184
  186. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/LICENSE +25 -0
  187. toil-8.0.0.dist-info/METADATA +173 -0
  188. toil-8.0.0.dist-info/RECORD +253 -0
  189. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
  190. toil-6.1.0a1.dist-info/METADATA +0 -125
  191. toil-6.1.0a1.dist-info/RECORD +0 -237
  192. {toil-6.1.0a1.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
  193. {toil-6.1.0a1.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