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
@@ -15,106 +15,189 @@
15
15
 
16
16
  import logging
17
17
  import os
18
- from typing import Dict, List, Tuple, Union
18
+ from typing import Union
19
19
 
20
20
  from toil import applianceSelf
21
21
  from toil.common import parser_with_common_options
22
- from toil.lib.aws import build_tag_dict_from_env
23
- from toil.provisioners import (check_valid_node_types,
24
- cluster_factory,
25
- parse_node_types)
22
+
23
+ try:
24
+ from toil.lib.aws import build_tag_dict_from_env
25
+ except ModuleNotFoundError:
26
+ build_tag_dict_from_env: dict[str, str] = lambda _: {} # type: ignore[no-redef]
27
+ from toil.lib.conversions import opt_strtobool
28
+ from toil.provisioners import check_valid_node_types, cluster_factory, parse_node_types
26
29
  from toil.statsAndLogging import set_logging_from_options
27
30
 
28
31
  logger = logging.getLogger(__name__)
29
32
 
30
33
 
31
- def create_tags_dict(tags: List[str]) -> Dict[str, str]:
34
+ def create_tags_dict(tags: list[str]) -> dict[str, str]:
32
35
  tags_dict = dict()
33
36
  for tag in tags:
34
- key, value = tag.split('=')
37
+ try:
38
+ key, value = tag.split("=")
39
+ except ValueError:
40
+ logger.error("Tag specification '%s' must contain '='", tag)
41
+ raise
35
42
  tags_dict[key] = value
36
43
  return tags_dict
37
44
 
38
45
 
39
46
  def main() -> None:
40
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil launch-cluster")
41
- parser.add_argument("-T", "--clusterType", dest="clusterType",
42
- choices=['mesos', 'kubernetes'],
43
- default=None, # TODO: change default to "kubernetes" when we are ready.
44
- help="Cluster scheduler to use.")
45
- parser.add_argument("--leaderNodeType", dest="leaderNodeType", required=True,
46
- help="Non-preemptible node type to use for the cluster leader.")
47
- parser.add_argument("--keyPairName", dest='keyPairName',
48
- help="On AWS, the name of the AWS key pair to include on the instance."
49
- " On Google/GCE, this is the ssh key pair.")
50
- parser.add_argument("--owner", dest='owner',
51
- help="The owner tag for all instances. If not given, the value in"
52
- "TOIL_OWNER_TAG will be used, or else the value of --keyPairName.")
53
- parser.add_argument("--boto", dest='botoPath',
54
- help="The path to the boto credentials directory. This is transferred "
55
- "to all nodes in order to access the AWS jobStore from non-AWS instances.")
56
- parser.add_argument("-t", "--tag", metavar='NAME=VALUE', dest='tags',
57
- default=[], action='append',
58
- help="Tags are added to the AWS cluster for this node and all of its "
59
- "children. Tags are of the form:\n"
60
- " -t key1=value1 --tag key2=value2\n"
61
- "Multiple tags are allowed and each tag needs its own flag. By "
62
- "default the cluster is tagged with "
63
- " {\n"
64
- " \"Name\": clusterName,\n"
65
- " \"Owner\": IAM username\n"
66
- " }. ")
67
-
68
- parser.add_argument("--network",
69
- help="GCE cloud network to use. default: 'default'")
70
- parser.add_argument("--vpcSubnet",
71
- help="VPC subnet ID to launch cluster leader in. Uses default subnet "
72
- "if not specified. This subnet needs to have auto assign IPs turned on.")
73
- parser.add_argument("--use_private_ip", dest="use_private_ip", action='store_true', default=False,
74
- help="if specified, ignore the public ip of the nodes")
75
- parser.add_argument("--nodeTypes", dest='nodeTypes', default=None, type=str,
76
- help="Specifies a list of comma-separated node types, each of which is "
77
- "composed of slash-separated instance types, and an optional spot "
78
- "bid set off by a colon, making the node type preemptible. Instance "
79
- "types may appear in multiple node types, and the same node type "
80
- "may appear as both preemptible and non-preemptible.\n"
81
- "Valid argument specifying two node types:\n"
82
- "\tc5.4xlarge/c5a.4xlarge:0.42,t2.large\n"
83
- "Node types:\n"
84
- "\tc5.4xlarge/c5a.4xlarge:0.42 and t2.large\n"
85
- "Instance types:\n"
86
- "\tc5.4xlarge, c5a.4xlarge, and t2.large\n"
87
- "Semantics:\n"
88
- "\tBid $0.42/hour for either c5.4xlarge or c5a.4xlarge instances,\n"
89
- "\ttreated interchangeably, while they are available at that price,\n"
90
- "\tand buy t2.large instances at full price\n"
91
- "Must also provide the --workers argument to specify how many "
92
- "workers of each node type to create.")
93
- parser.add_argument("-w", "--workers", dest='workers', default=None, type=str,
94
- help="Comma-separated list of the ranges of numbers of workers of each "
95
- "node type to launch, such as '0-2,5,1-3'. If a range is given, "
96
- "workers will automatically be launched and terminated by the cluster "
97
- "to auto-scale to the workload.")
98
- parser.add_argument("--leaderStorage", dest='leaderStorage', type=int, default=50,
99
- help="Specify the size (in gigabytes) of the root volume for the leader "
100
- "instance. This is an EBS volume.")
101
- parser.add_argument("--nodeStorage", dest='nodeStorage', type=int, default=50,
102
- help="Specify the size (in gigabytes) of the root volume for any worker "
103
- "instances created when using the -w flag. This is an EBS volume.")
104
- parser.add_argument('--forceDockerAppliance', dest='forceDockerAppliance', action='store_true',
105
- default=False,
106
- help="Disables sanity checking the existence of the docker image specified "
107
- "by TOIL_APPLIANCE_SELF, which Toil uses to provision mesos for "
108
- "autoscaling.")
109
- parser.add_argument('--awsEc2ProfileArn', dest='awsEc2ProfileArn', default=None, type=str,
110
- help="If provided, the specified ARN is used as the instance profile for EC2 instances."
111
- "Useful for setting custom IAM profiles. If not specified, a new IAM role is created "
112
- "by default with sufficient access to perform basic cluster operations.")
113
- parser.add_argument('--awsEc2ExtraSecurityGroupId', dest='awsEc2ExtraSecurityGroupIds', default=[], action='append',
114
- help="Any additional security groups to attach to EC2 instances. Note that a security group "
115
- "with its name equal to the cluster name will always be created, thus ensure that "
116
- "the extra security groups do not have the same name as the cluster name.")
117
- #TODO Set Aws Profile in CLI options
47
+ parser = parser_with_common_options(
48
+ provisioner_options=True, jobstore_option=False, prog="toil launch-cluster"
49
+ )
50
+ parser.add_argument(
51
+ "-T",
52
+ "--clusterType",
53
+ dest="clusterType",
54
+ choices=["mesos", "kubernetes"],
55
+ default=None, # TODO: change default to "kubernetes" when we are ready.
56
+ help="Cluster scheduler to use.",
57
+ )
58
+ parser.add_argument(
59
+ "--leaderNodeType",
60
+ dest="leaderNodeType",
61
+ required=True,
62
+ help="Non-preemptible node type to use for the cluster leader.",
63
+ )
64
+ parser.add_argument(
65
+ "--keyPairName",
66
+ dest="keyPairName",
67
+ help="On AWS, the name of the AWS key pair to include on the instance."
68
+ " On Google/GCE, this is the ssh key pair.",
69
+ )
70
+ parser.add_argument(
71
+ "--owner",
72
+ dest="owner",
73
+ help="The owner tag for all instances. If not given, the value in"
74
+ "TOIL_OWNER_TAG will be used, or else the value of --keyPairName.",
75
+ )
76
+ parser.add_argument(
77
+ "--boto",
78
+ dest="botoPath",
79
+ help="The path to the boto credentials directory. This is transferred "
80
+ "to all nodes in order to access the AWS jobStore from non-AWS instances.",
81
+ )
82
+ parser.add_argument(
83
+ "-t",
84
+ "--tag",
85
+ metavar="NAME=VALUE",
86
+ dest="tags",
87
+ default=[],
88
+ action="append",
89
+ help="Tags are added to the AWS cluster for this node and all of its "
90
+ "children. Tags are of the form:\n"
91
+ " -t key1=value1 --tag key2=value2\n"
92
+ "Multiple tags are allowed and each tag needs its own flag. By "
93
+ "default the cluster is tagged with "
94
+ " {\n"
95
+ ' "Name": clusterName,\n'
96
+ ' "Owner": IAM username\n'
97
+ " }. ",
98
+ )
99
+
100
+ parser.add_argument(
101
+ "--network", help="GCE cloud network to use. default: 'default'"
102
+ )
103
+ parser.add_argument(
104
+ "--vpcSubnet",
105
+ help="VPC subnet ID to launch cluster leader in. Uses default subnet "
106
+ "if not specified. This subnet needs to have auto assign IPs turned on.",
107
+ )
108
+ parser.add_argument(
109
+ "--use_private_ip",
110
+ dest="use_private_ip",
111
+ action="store_true",
112
+ default=False,
113
+ help="if specified, ignore the public ip of the nodes",
114
+ )
115
+ parser.add_argument(
116
+ "--nodeTypes",
117
+ dest="nodeTypes",
118
+ default=None,
119
+ type=str,
120
+ help="Specifies a list of comma-separated node types, each of which is "
121
+ "composed of slash-separated instance types, and an optional spot "
122
+ "bid set off by a colon, making the node type preemptible. Instance "
123
+ "types may appear in multiple node types, and the same node type "
124
+ "may appear as both preemptible and non-preemptible.\n"
125
+ "Valid argument specifying two node types:\n"
126
+ "\tc5.4xlarge/c5a.4xlarge:0.42,t2.large\n"
127
+ "Node types:\n"
128
+ "\tc5.4xlarge/c5a.4xlarge:0.42 and t2.large\n"
129
+ "Instance types:\n"
130
+ "\tc5.4xlarge, c5a.4xlarge, and t2.large\n"
131
+ "Semantics:\n"
132
+ "\tBid $0.42/hour for either c5.4xlarge or c5a.4xlarge instances,\n"
133
+ "\ttreated interchangeably, while they are available at that price,\n"
134
+ "\tand buy t2.large instances at full price\n"
135
+ "Must also provide the --workers argument to specify how many "
136
+ "workers of each node type to create.",
137
+ )
138
+ parser.add_argument(
139
+ "-w",
140
+ "--workers",
141
+ dest="workers",
142
+ default=None,
143
+ type=str,
144
+ help="Comma-separated list of the ranges of numbers of workers of each "
145
+ "node type to launch, such as '0-2,5,1-3'. If a range is given, "
146
+ "workers will automatically be launched and terminated by the cluster "
147
+ "to auto-scale to the workload.",
148
+ )
149
+ parser.add_argument(
150
+ "--leaderStorage",
151
+ dest="leaderStorage",
152
+ type=int,
153
+ default=50,
154
+ help="Specify the size (in gigabytes) of the root volume for the leader "
155
+ "instance. This is an EBS volume.",
156
+ )
157
+ parser.add_argument(
158
+ "--nodeStorage",
159
+ dest="nodeStorage",
160
+ type=int,
161
+ default=50,
162
+ help="Specify the size (in gigabytes) of the root volume for any worker "
163
+ "instances created when using the -w flag. This is an EBS volume.",
164
+ )
165
+ parser.add_argument(
166
+ "--forceDockerAppliance",
167
+ dest="forceDockerAppliance",
168
+ action="store_true",
169
+ default=False,
170
+ help="Disables sanity checking the existence of the docker image specified "
171
+ "by TOIL_APPLIANCE_SELF, which Toil uses to provision mesos for "
172
+ "autoscaling.",
173
+ )
174
+ parser.add_argument(
175
+ "--awsEc2ProfileArn",
176
+ dest="awsEc2ProfileArn",
177
+ default=None,
178
+ type=str,
179
+ help="If provided, the specified ARN is used as the instance profile for EC2 instances."
180
+ "Useful for setting custom IAM profiles. If not specified, a new IAM role is created "
181
+ "by default with sufficient access to perform basic cluster operations.",
182
+ )
183
+ parser.add_argument(
184
+ "--awsEc2ExtraSecurityGroupId",
185
+ dest="awsEc2ExtraSecurityGroupIds",
186
+ default=[],
187
+ action="append",
188
+ help="Any additional security groups to attach to EC2 instances. Note that a security group "
189
+ "with its name equal to the cluster name will always be created, thus ensure that "
190
+ "the extra security groups do not have the same name as the cluster name.",
191
+ )
192
+ parser.add_argument(
193
+ "--allowFuse",
194
+ type=opt_strtobool,
195
+ default=True,
196
+ help="Enable both the leader and worker nodes to be able to run Singularity with FUSE. For "
197
+ "Kubernetes, this will make the leader privileged and ask workers to run as privileged. "
198
+ "(default: %(default)s)",
199
+ )
200
+ # TODO Set Aws Profile in CLI options
118
201
  options = parser.parse_args()
119
202
  set_logging_from_options(options)
120
203
 
@@ -122,74 +205,94 @@ def main() -> None:
122
205
 
123
206
  # Get worker node types
124
207
  worker_node_types = parse_node_types(options.nodeTypes)
125
- check_valid_node_types(options.provisioner, worker_node_types + [({options.leaderNodeType}, None)])
208
+ check_valid_node_types(
209
+ options.provisioner, worker_node_types + [({options.leaderNodeType}, None)]
210
+ )
126
211
 
127
212
  # Holds string ranges, like "5", or "3-10"
128
- worker_node_ranges = options.workers.split(',') if options.workers else []
213
+ worker_node_ranges = options.workers.split(",") if options.workers else []
129
214
 
130
215
  # checks the validity of TOIL_APPLIANCE_SELF before proceeding
131
216
  applianceSelf(forceDockerAppliance=options.forceDockerAppliance)
132
217
 
133
218
  # This holds either ints to launch static nodes, or tuples of ints
134
219
  # specifying ranges to launch managed auto-scaling nodes, for each type.
135
- nodeCounts: List[Union[int, Tuple[int, int]]] = []
220
+ nodeCounts: list[Union[int, tuple[int, int]]] = []
136
221
 
137
- if ((worker_node_types != [] or worker_node_ranges != []) and not
138
- (worker_node_types != [] and worker_node_ranges != [])):
222
+ if (worker_node_types != [] or worker_node_ranges != []) and not (
223
+ worker_node_types != [] and worker_node_ranges != []
224
+ ):
139
225
  raise RuntimeError("The --nodeTypes option requires --workers, and visa versa.")
140
226
  if worker_node_types and worker_node_ranges:
141
- if not len(worker_node_types) == len(worker_node_ranges):
142
- raise RuntimeError("List of worker count ranges must be the same length as the list of node types.")
143
-
144
- for spec in worker_node_ranges:
145
- if '-' in spec:
146
- # Provision via autoscaling
147
- parts = spec.split('-')
148
- if len(parts) != 2:
149
- raise RuntimeError("Unacceptable range: " + spec)
150
- nodeCounts.append((int(parts[0]), int(parts[1])))
151
- else:
152
- # Provision fixed nodes
153
- nodeCounts.append(int(spec))
154
-
155
- owner = options.owner or os.getenv('TOIL_OWNER_TAG') or options.keyPairName or 'toil'
227
+ if not len(worker_node_types) == len(worker_node_ranges):
228
+ raise RuntimeError(
229
+ "List of worker count ranges must be the same length as the list of node types."
230
+ )
231
+
232
+ for spec in worker_node_ranges:
233
+ if "-" in spec:
234
+ # Provision via autoscaling
235
+ parts = spec.split("-")
236
+ if len(parts) != 2:
237
+ raise RuntimeError("Unacceptable range: " + spec)
238
+ nodeCounts.append((int(parts[0]), int(parts[1])))
239
+ else:
240
+ # Provision fixed nodes
241
+ nodeCounts.append(int(spec))
242
+
243
+ owner = (
244
+ options.owner or os.getenv("TOIL_OWNER_TAG") or options.keyPairName or "toil"
245
+ )
156
246
 
157
247
  # Check to see if the user specified a zone. If not, see if one is stored in an environment variable.
158
- options.zone = options.zone or os.environ.get(f'TOIL_{options.provisioner.upper()}_ZONE')
248
+ options.zone = options.zone or os.environ.get(
249
+ f"TOIL_{options.provisioner.upper()}_ZONE"
250
+ )
159
251
 
160
252
  if not options.zone:
161
- raise RuntimeError(f'Please provide a value for --zone or set a default in the '
162
- f'TOIL_{options.provisioner.upper()}_ZONE environment variable.')
253
+ raise RuntimeError(
254
+ f"Please provide a value for --zone or set a default in the "
255
+ f"TOIL_{options.provisioner.upper()}_ZONE environment variable."
256
+ )
163
257
 
164
258
  if options.clusterType == "mesos":
165
- logger.warning('You are using a Mesos cluster, which is no longer recommended as Toil is '
166
- 'transitioning to Kubernetes-based clusters. Consider switching to '
167
- '--clusterType=kubernetes instead.')
259
+ logger.warning(
260
+ "You are using a Mesos cluster, which is no longer recommended as Toil is "
261
+ "transitioning to Kubernetes-based clusters. Consider switching to "
262
+ "--clusterType=kubernetes instead."
263
+ )
168
264
 
169
265
  if options.clusterType is None:
170
- logger.warning('Argument --clusterType is not set... using "mesos". '
171
- 'In future versions of Toil, the default cluster scheduler will be '
172
- 'set to "kubernetes" if the cluster type is not specified.')
266
+ logger.warning(
267
+ 'Argument --clusterType is not set... using "mesos". '
268
+ "In future versions of Toil, the default cluster scheduler will be "
269
+ 'set to "kubernetes" if the cluster type is not specified.'
270
+ )
173
271
  options.clusterType = "mesos"
174
272
 
175
- logger.info('Creating cluster %s...', options.clusterName)
176
-
177
- cluster = cluster_factory(provisioner=options.provisioner,
178
- clusterName=options.clusterName,
179
- clusterType=options.clusterType,
180
- zone=options.zone,
181
- nodeStorage=options.nodeStorage)
182
-
183
- cluster.launchCluster(leaderNodeType=options.leaderNodeType,
184
- leaderStorage=options.leaderStorage,
185
- owner=owner,
186
- keyName=options.keyPairName,
187
- botoPath=options.botoPath,
188
- userTags=tags,
189
- network=options.network,
190
- vpcSubnet=options.vpcSubnet,
191
- awsEc2ProfileArn=options.awsEc2ProfileArn,
192
- awsEc2ExtraSecurityGroupIds=options.awsEc2ExtraSecurityGroupIds)
273
+ logger.info("Creating cluster %s...", options.clusterName)
274
+
275
+ cluster = cluster_factory(
276
+ provisioner=options.provisioner,
277
+ clusterName=options.clusterName,
278
+ clusterType=options.clusterType,
279
+ zone=options.zone,
280
+ nodeStorage=options.nodeStorage,
281
+ enable_fuse=options.allowFuse,
282
+ )
283
+
284
+ cluster.launchCluster(
285
+ leaderNodeType=options.leaderNodeType,
286
+ leaderStorage=options.leaderStorage,
287
+ owner=owner,
288
+ keyName=options.keyPairName,
289
+ botoPath=options.botoPath,
290
+ userTags=tags,
291
+ network=options.network,
292
+ vpcSubnet=options.vpcSubnet,
293
+ awsEc2ProfileArn=options.awsEc2ProfileArn,
294
+ awsEc2ExtraSecurityGroupIds=options.awsEc2ExtraSecurityGroupIds,
295
+ )
193
296
 
194
297
  for typeNum, spec in enumerate(nodeCounts):
195
298
  # For each batch of workers to make
@@ -207,8 +310,12 @@ def main() -> None:
207
310
  cluster.addNodes(nodeTypes=wanted[0], numNodes=spec, preemptible=False)
208
311
  else:
209
312
  # We have a spot bid
210
- cluster.addNodes(nodeTypes=wanted[0], numNodes=spec, preemptible=True,
211
- spotBid=wanted[1])
313
+ cluster.addNodes(
314
+ nodeTypes=wanted[0],
315
+ numNodes=spec,
316
+ preemptible=True,
317
+ spotBid=wanted[1],
318
+ )
212
319
 
213
320
  elif isinstance(spec, tuple):
214
321
  # Make a range of auto-scaling nodes
@@ -225,11 +332,20 @@ def main() -> None:
225
332
 
226
333
  if wanted[1] is None:
227
334
  # Make non-spot instances
228
- cluster.addManagedNodes(nodeTypes=wanted[0], minNodes=min_count, maxNodes=max_count,
229
- preemptible=False)
335
+ cluster.addManagedNodes(
336
+ nodeTypes=wanted[0],
337
+ minNodes=min_count,
338
+ maxNodes=max_count,
339
+ preemptible=False,
340
+ )
230
341
  else:
231
342
  # Bid at the given price.
232
- cluster.addManagedNodes(nodeTypes=wanted[0], minNodes=min_count, maxNodes=max_count,
233
- preemptible=True, spotBid=wanted[1])
234
-
235
- logger.info('Cluster created successfully.')
343
+ cluster.addManagedNodes(
344
+ nodeTypes=wanted[0],
345
+ minNodes=min_count,
346
+ maxNodes=max_count,
347
+ preemptible=True,
348
+ spotBid=wanted[1],
349
+ )
350
+
351
+ logger.info("Cluster created successfully.")
toil/utils/toilMain.py CHANGED
@@ -3,9 +3,8 @@ import re
3
3
  import sys
4
4
  import textwrap
5
5
  import types
6
- from typing import Any, Dict
7
-
8
6
  from importlib.metadata import version as metadata_version
7
+ from typing import Any
9
8
 
10
9
  from toil.version import version
11
10
 
@@ -13,23 +12,25 @@ from toil.version import version
13
12
  def main() -> None:
14
13
  modules = loadModules()
15
14
 
16
- if len(sys.argv) < 2 or sys.argv[1] == '--help':
15
+ if len(sys.argv) < 2 or sys.argv[1] == "--help":
17
16
  printHelp(modules)
18
17
  sys.exit(0)
19
18
 
20
19
  cmd = sys.argv[1]
21
- if cmd == '--version':
20
+ if cmd == "--version":
22
21
  printVersion()
23
22
  sys.exit(0)
24
23
 
25
24
  try:
26
25
  module = modules[cmd]
27
26
  except KeyError:
28
- sys.stderr.write(f'Unknown option "{cmd}". Pass --help to display usage information.\n')
27
+ sys.stderr.write(
28
+ f'Unknown option "{cmd}". Pass --help to display usage information.\n'
29
+ )
29
30
  sys.exit(1)
30
31
 
31
32
  del sys.argv[1]
32
- get_or_die(module, 'main')()
33
+ get_or_die(module, "main")()
33
34
 
34
35
 
35
36
  def get_or_die(module: types.ModuleType, name: str) -> Any:
@@ -39,12 +40,14 @@ def get_or_die(module: types.ModuleType, name: str) -> Any:
39
40
  if hasattr(module, name):
40
41
  return getattr(module, name)
41
42
  else:
42
- sys.stderr.write(f'Internal Toil error!\nToil utility module '
43
- f'{module.__name__} is missing required attribute {name}\n')
43
+ sys.stderr.write(
44
+ f"Internal Toil error!\nToil utility module "
45
+ f"{module.__name__} is missing required attribute {name}\n"
46
+ )
44
47
  sys.exit(1)
45
48
 
46
49
 
47
- def loadModules() -> Dict[str, types.ModuleType]:
50
+ def loadModules() -> dict[str, types.ModuleType]:
48
51
  # noinspection PyUnresolvedReferences
49
52
  from toil.utils import toilClean # noqa
50
53
  from toil.utils import toilConfig # noqa
@@ -59,13 +62,22 @@ def loadModules() -> Dict[str, types.ModuleType]:
59
62
  from toil.utils import toilStats # noqa
60
63
  from toil.utils import toilStatus # noqa
61
64
 
62
- return {'-'.join([i.lower() for i in re.findall('[A-Z][^A-Z]*', name)]): module for name, module in locals().items()}
65
+ return {
66
+ "-".join([i.lower() for i in re.findall("[A-Z][^A-Z]*", name)]): module
67
+ for name, module in locals().items()
68
+ }
63
69
 
64
70
 
65
- def printHelp(modules: Dict[str, types.ModuleType]) -> None:
71
+ def printHelp(modules: dict[str, types.ModuleType]) -> None:
66
72
  name = os.path.basename(sys.argv[0])
67
- descriptions = '\n '.join(f'{cmd} - {get_or_die(mod, "__doc__").strip()}' for cmd, mod in modules.items() if mod)
68
- print(textwrap.dedent(f"""
73
+ descriptions = "\n ".join(
74
+ f'{cmd} - {get_or_die(mod, "__doc__").strip()}'
75
+ for cmd, mod in modules.items()
76
+ if mod
77
+ )
78
+ print(
79
+ textwrap.dedent(
80
+ f"""
69
81
  Usage: {name} COMMAND ...
70
82
  {name} --help
71
83
  {name} COMMAND --help
@@ -73,11 +85,20 @@ def printHelp(modules: Dict[str, types.ModuleType]) -> None:
73
85
  Where COMMAND is one of the following:
74
86
 
75
87
  {descriptions}
76
- """[1:]))
88
+ """[
89
+ 1:
90
+ ]
91
+ )
92
+ )
77
93
 
78
94
 
79
95
  def printVersion() -> None:
80
96
  try:
81
- print(metadata_version('toil'))
97
+ detected_version = metadata_version("toil")
98
+ if "a" in detected_version:
99
+ # This probably means Toil is installed as development
100
+ print(version)
101
+ else:
102
+ print(detected_version)
82
103
  except:
83
- print(f'Version gathered from toil.version: {version}')
104
+ print(f"Version gathered from toil.version: {version}")
@@ -14,27 +14,45 @@
14
14
  """Rsyncs into the toil appliance container running on the leader of the cluster."""
15
15
  import argparse
16
16
  import logging
17
+ import sys
17
18
 
18
19
  from toil.common import parser_with_common_options
19
- from toil.provisioners import cluster_factory
20
+ from toil.provisioners import NoSuchClusterException, cluster_factory
20
21
  from toil.statsAndLogging import set_logging_from_options
21
22
 
22
23
  logger = logging.getLogger(__name__)
23
24
 
24
25
 
25
26
  def main() -> None:
26
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil rsync-cluster")
27
- parser.add_argument("--insecure", dest='insecure', action='store_true', required=False,
28
- help="Temporarily disable strict host key checking.")
29
- parser.add_argument("args", nargs=argparse.REMAINDER, help="Arguments to pass to"
30
- "`rsync`. Takes any arguments that rsync accepts. Specify the"
31
- " remote with a colon. For example, to upload `example.py`,"
32
- " specify `toil rsync-cluster -p aws test-cluster example.py :`."
33
- "\nOr, to download a file from the remote:, `toil rsync-cluster"
34
- " -p aws test-cluster :example.py .`")
27
+ parser = parser_with_common_options(
28
+ provisioner_options=True, jobstore_option=False, prog="toil rsync-cluster"
29
+ )
30
+ parser.add_argument(
31
+ "--insecure",
32
+ dest="insecure",
33
+ action="store_true",
34
+ required=False,
35
+ help="Temporarily disable strict host key checking.",
36
+ )
37
+ parser.add_argument(
38
+ "args",
39
+ nargs=argparse.REMAINDER,
40
+ help="Arguments to pass to"
41
+ "`rsync`. Takes any arguments that rsync accepts. Specify the"
42
+ " remote with a colon. For example, to upload `example.py`,"
43
+ " specify `toil rsync-cluster -p aws test-cluster example.py :`."
44
+ "\nOr, to download a file from the remote:, `toil rsync-cluster"
45
+ " -p aws test-cluster :example.py .`",
46
+ )
35
47
  options = parser.parse_args()
36
48
  set_logging_from_options(options)
37
- cluster = cluster_factory(provisioner=options.provisioner,
38
- clusterName=options.clusterName,
39
- zone=options.zone)
40
- cluster.getLeader().coreRsync(args=options.args, strict=not options.insecure)
49
+ cluster = cluster_factory(
50
+ provisioner=options.provisioner,
51
+ clusterName=options.clusterName,
52
+ zone=options.zone,
53
+ )
54
+ try:
55
+ cluster.getLeader().coreRsync(args=options.args, strict=not options.insecure)
56
+ except NoSuchClusterException as e:
57
+ logger.error(e)
58
+ sys.exit(1)