toil 7.0.0__py3-none-any.whl → 8.1.0b1__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 (197) hide show
  1. toil/__init__.py +124 -86
  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 +39 -29
  19. toil/batchSystems/registry.py +53 -19
  20. toil/batchSystems/singleMachine.py +293 -123
  21. toil/batchSystems/slurm.py +651 -155
  22. toil/batchSystems/torque.py +46 -32
  23. toil/bus.py +141 -73
  24. toil/common.py +784 -397
  25. toil/cwl/__init__.py +1 -1
  26. toil/cwl/cwltoil.py +1137 -534
  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 +1031 -349
  35. toil/jobStores/abstractJobStore.py +387 -243
  36. toil/jobStores/aws/jobStore.py +772 -412
  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 +204 -58
  49. toil/lib/aws/utils.py +290 -213
  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/dockstore.py +379 -0
  55. toil/lib/ec2.py +322 -209
  56. toil/lib/ec2nodes.py +174 -105
  57. toil/lib/encryption/_dummy.py +5 -3
  58. toil/lib/encryption/_nacl.py +10 -6
  59. toil/lib/encryption/conftest.py +1 -0
  60. toil/lib/exceptions.py +26 -7
  61. toil/lib/expando.py +4 -2
  62. toil/lib/ftp_utils.py +217 -0
  63. toil/lib/generatedEC2Lists.py +127 -19
  64. toil/lib/history.py +1271 -0
  65. toil/lib/history_submission.py +681 -0
  66. toil/lib/humanize.py +6 -2
  67. toil/lib/io.py +121 -12
  68. toil/lib/iterables.py +4 -2
  69. toil/lib/memoize.py +12 -8
  70. toil/lib/misc.py +83 -18
  71. toil/lib/objects.py +2 -2
  72. toil/lib/resources.py +19 -7
  73. toil/lib/retry.py +125 -87
  74. toil/lib/threading.py +282 -80
  75. toil/lib/throttle.py +15 -14
  76. toil/lib/trs.py +390 -0
  77. toil/lib/web.py +38 -0
  78. toil/options/common.py +850 -402
  79. toil/options/cwl.py +185 -90
  80. toil/options/runner.py +50 -0
  81. toil/options/wdl.py +70 -19
  82. toil/provisioners/__init__.py +111 -46
  83. toil/provisioners/abstractProvisioner.py +322 -157
  84. toil/provisioners/aws/__init__.py +62 -30
  85. toil/provisioners/aws/awsProvisioner.py +980 -627
  86. toil/provisioners/clusterScaler.py +541 -279
  87. toil/provisioners/gceProvisioner.py +283 -180
  88. toil/provisioners/node.py +147 -79
  89. toil/realtimeLogger.py +34 -22
  90. toil/resource.py +137 -75
  91. toil/server/app.py +127 -61
  92. toil/server/celery_app.py +3 -1
  93. toil/server/cli/wes_cwl_runner.py +84 -55
  94. toil/server/utils.py +56 -31
  95. toil/server/wes/abstract_backend.py +64 -26
  96. toil/server/wes/amazon_wes_utils.py +21 -15
  97. toil/server/wes/tasks.py +121 -63
  98. toil/server/wes/toil_backend.py +142 -107
  99. toil/server/wsgi_app.py +4 -3
  100. toil/serviceManager.py +58 -22
  101. toil/statsAndLogging.py +183 -65
  102. toil/test/__init__.py +263 -179
  103. toil/test/batchSystems/batchSystemTest.py +438 -195
  104. toil/test/batchSystems/batch_system_plugin_test.py +18 -7
  105. toil/test/batchSystems/test_gridengine.py +173 -0
  106. toil/test/batchSystems/test_lsf_helper.py +67 -58
  107. toil/test/batchSystems/test_slurm.py +265 -49
  108. toil/test/cactus/test_cactus_integration.py +20 -22
  109. toil/test/cwl/conftest.py +39 -0
  110. toil/test/cwl/cwlTest.py +375 -72
  111. toil/test/cwl/measure_default_memory.cwl +12 -0
  112. toil/test/cwl/not_run_required_input.cwl +29 -0
  113. toil/test/cwl/optional-file.cwl +18 -0
  114. toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
  115. toil/test/docs/scriptsTest.py +60 -34
  116. toil/test/jobStores/jobStoreTest.py +412 -235
  117. toil/test/lib/aws/test_iam.py +116 -48
  118. toil/test/lib/aws/test_s3.py +16 -9
  119. toil/test/lib/aws/test_utils.py +5 -6
  120. toil/test/lib/dockerTest.py +118 -141
  121. toil/test/lib/test_conversions.py +113 -115
  122. toil/test/lib/test_ec2.py +57 -49
  123. toil/test/lib/test_history.py +212 -0
  124. toil/test/lib/test_misc.py +12 -5
  125. toil/test/lib/test_trs.py +161 -0
  126. toil/test/mesos/MesosDataStructuresTest.py +23 -10
  127. toil/test/mesos/helloWorld.py +7 -6
  128. toil/test/mesos/stress.py +25 -20
  129. toil/test/options/options.py +7 -2
  130. toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
  131. toil/test/provisioners/clusterScalerTest.py +440 -250
  132. toil/test/provisioners/clusterTest.py +81 -42
  133. toil/test/provisioners/gceProvisionerTest.py +174 -100
  134. toil/test/provisioners/provisionerTest.py +25 -13
  135. toil/test/provisioners/restartScript.py +5 -4
  136. toil/test/server/serverTest.py +188 -141
  137. toil/test/sort/restart_sort.py +137 -68
  138. toil/test/sort/sort.py +134 -66
  139. toil/test/sort/sortTest.py +91 -49
  140. toil/test/src/autoDeploymentTest.py +140 -100
  141. toil/test/src/busTest.py +20 -18
  142. toil/test/src/checkpointTest.py +8 -2
  143. toil/test/src/deferredFunctionTest.py +49 -35
  144. toil/test/src/dockerCheckTest.py +33 -26
  145. toil/test/src/environmentTest.py +20 -10
  146. toil/test/src/fileStoreTest.py +538 -271
  147. toil/test/src/helloWorldTest.py +7 -4
  148. toil/test/src/importExportFileTest.py +61 -31
  149. toil/test/src/jobDescriptionTest.py +32 -17
  150. toil/test/src/jobEncapsulationTest.py +2 -0
  151. toil/test/src/jobFileStoreTest.py +74 -50
  152. toil/test/src/jobServiceTest.py +187 -73
  153. toil/test/src/jobTest.py +120 -70
  154. toil/test/src/miscTests.py +19 -18
  155. toil/test/src/promisedRequirementTest.py +82 -36
  156. toil/test/src/promisesTest.py +7 -6
  157. toil/test/src/realtimeLoggerTest.py +6 -6
  158. toil/test/src/regularLogTest.py +71 -37
  159. toil/test/src/resourceTest.py +80 -49
  160. toil/test/src/restartDAGTest.py +36 -22
  161. toil/test/src/resumabilityTest.py +9 -2
  162. toil/test/src/retainTempDirTest.py +45 -14
  163. toil/test/src/systemTest.py +12 -8
  164. toil/test/src/threadingTest.py +44 -25
  165. toil/test/src/toilContextManagerTest.py +10 -7
  166. toil/test/src/userDefinedJobArgTypeTest.py +8 -5
  167. toil/test/src/workerTest.py +33 -16
  168. toil/test/utils/toilDebugTest.py +70 -58
  169. toil/test/utils/toilKillTest.py +4 -5
  170. toil/test/utils/utilsTest.py +239 -102
  171. toil/test/wdl/wdltoil_test.py +789 -148
  172. toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
  173. toil/toilState.py +52 -26
  174. toil/utils/toilConfig.py +13 -4
  175. toil/utils/toilDebugFile.py +44 -27
  176. toil/utils/toilDebugJob.py +85 -25
  177. toil/utils/toilDestroyCluster.py +11 -6
  178. toil/utils/toilKill.py +8 -3
  179. toil/utils/toilLaunchCluster.py +251 -145
  180. toil/utils/toilMain.py +37 -16
  181. toil/utils/toilRsyncCluster.py +27 -14
  182. toil/utils/toilSshCluster.py +45 -22
  183. toil/utils/toilStats.py +75 -36
  184. toil/utils/toilStatus.py +226 -119
  185. toil/utils/toilUpdateEC2Instances.py +3 -1
  186. toil/version.py +6 -6
  187. toil/wdl/utils.py +5 -5
  188. toil/wdl/wdltoil.py +3528 -1053
  189. toil/worker.py +370 -149
  190. toil-8.1.0b1.dist-info/METADATA +178 -0
  191. toil-8.1.0b1.dist-info/RECORD +259 -0
  192. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/WHEEL +1 -1
  193. toil-7.0.0.dist-info/METADATA +0 -158
  194. toil-7.0.0.dist-info/RECORD +0 -244
  195. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/LICENSE +0 -0
  196. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/entry_points.txt +0 -0
  197. {toil-7.0.0.dist-info → toil-8.1.0b1.dist-info}/top_level.txt +0 -0
@@ -15,25 +15,27 @@
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
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]
23
27
  from toil.lib.conversions import opt_strtobool
24
- from toil.provisioners import (check_valid_node_types,
25
- cluster_factory,
26
- parse_node_types)
28
+ from toil.provisioners import check_valid_node_types, cluster_factory, parse_node_types
27
29
  from toil.statsAndLogging import set_logging_from_options
28
30
 
29
31
  logger = logging.getLogger(__name__)
30
32
 
31
33
 
32
- def create_tags_dict(tags: List[str]) -> Dict[str, str]:
34
+ def create_tags_dict(tags: list[str]) -> dict[str, str]:
33
35
  tags_dict = dict()
34
36
  for tag in tags:
35
37
  try:
36
- key, value = tag.split('=')
38
+ key, value = tag.split("=")
37
39
  except ValueError:
38
40
  logger.error("Tag specification '%s' must contain '='", tag)
39
41
  raise
@@ -42,88 +44,160 @@ def create_tags_dict(tags: List[str]) -> Dict[str, str]:
42
44
 
43
45
 
44
46
  def main() -> None:
45
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil launch-cluster")
46
- parser.add_argument("-T", "--clusterType", dest="clusterType",
47
- choices=['mesos', 'kubernetes'],
48
- default=None, # TODO: change default to "kubernetes" when we are ready.
49
- help="Cluster scheduler to use.")
50
- parser.add_argument("--leaderNodeType", dest="leaderNodeType", required=True,
51
- help="Non-preemptible node type to use for the cluster leader.")
52
- parser.add_argument("--keyPairName", dest='keyPairName',
53
- help="On AWS, the name of the AWS key pair to include on the instance."
54
- " On Google/GCE, this is the ssh key pair.")
55
- parser.add_argument("--owner", dest='owner',
56
- help="The owner tag for all instances. If not given, the value in"
57
- "TOIL_OWNER_TAG will be used, or else the value of --keyPairName.")
58
- parser.add_argument("--boto", dest='botoPath',
59
- help="The path to the boto credentials directory. This is transferred "
60
- "to all nodes in order to access the AWS jobStore from non-AWS instances.")
61
- parser.add_argument("-t", "--tag", metavar='NAME=VALUE', dest='tags',
62
- default=[], action='append',
63
- help="Tags are added to the AWS cluster for this node and all of its "
64
- "children. Tags are of the form:\n"
65
- " -t key1=value1 --tag key2=value2\n"
66
- "Multiple tags are allowed and each tag needs its own flag. By "
67
- "default the cluster is tagged with "
68
- " {\n"
69
- " \"Name\": clusterName,\n"
70
- " \"Owner\": IAM username\n"
71
- " }. ")
72
-
73
- parser.add_argument("--network",
74
- help="GCE cloud network to use. default: 'default'")
75
- parser.add_argument("--vpcSubnet",
76
- help="VPC subnet ID to launch cluster leader in. Uses default subnet "
77
- "if not specified. This subnet needs to have auto assign IPs turned on.")
78
- parser.add_argument("--use_private_ip", dest="use_private_ip", action='store_true', default=False,
79
- help="if specified, ignore the public ip of the nodes")
80
- parser.add_argument("--nodeTypes", dest='nodeTypes', default=None, type=str,
81
- help="Specifies a list of comma-separated node types, each of which is "
82
- "composed of slash-separated instance types, and an optional spot "
83
- "bid set off by a colon, making the node type preemptible. Instance "
84
- "types may appear in multiple node types, and the same node type "
85
- "may appear as both preemptible and non-preemptible.\n"
86
- "Valid argument specifying two node types:\n"
87
- "\tc5.4xlarge/c5a.4xlarge:0.42,t2.large\n"
88
- "Node types:\n"
89
- "\tc5.4xlarge/c5a.4xlarge:0.42 and t2.large\n"
90
- "Instance types:\n"
91
- "\tc5.4xlarge, c5a.4xlarge, and t2.large\n"
92
- "Semantics:\n"
93
- "\tBid $0.42/hour for either c5.4xlarge or c5a.4xlarge instances,\n"
94
- "\ttreated interchangeably, while they are available at that price,\n"
95
- "\tand buy t2.large instances at full price\n"
96
- "Must also provide the --workers argument to specify how many "
97
- "workers of each node type to create.")
98
- parser.add_argument("-w", "--workers", dest='workers', default=None, type=str,
99
- help="Comma-separated list of the ranges of numbers of workers of each "
100
- "node type to launch, such as '0-2,5,1-3'. If a range is given, "
101
- "workers will automatically be launched and terminated by the cluster "
102
- "to auto-scale to the workload.")
103
- parser.add_argument("--leaderStorage", dest='leaderStorage', type=int, default=50,
104
- help="Specify the size (in gigabytes) of the root volume for the leader "
105
- "instance. This is an EBS volume.")
106
- parser.add_argument("--nodeStorage", dest='nodeStorage', type=int, default=50,
107
- help="Specify the size (in gigabytes) of the root volume for any worker "
108
- "instances created when using the -w flag. This is an EBS volume.")
109
- parser.add_argument('--forceDockerAppliance', dest='forceDockerAppliance', action='store_true',
110
- default=False,
111
- help="Disables sanity checking the existence of the docker image specified "
112
- "by TOIL_APPLIANCE_SELF, which Toil uses to provision mesos for "
113
- "autoscaling.")
114
- parser.add_argument('--awsEc2ProfileArn', dest='awsEc2ProfileArn', default=None, type=str,
115
- help="If provided, the specified ARN is used as the instance profile for EC2 instances."
116
- "Useful for setting custom IAM profiles. If not specified, a new IAM role is created "
117
- "by default with sufficient access to perform basic cluster operations.")
118
- parser.add_argument('--awsEc2ExtraSecurityGroupId', dest='awsEc2ExtraSecurityGroupIds', default=[], action='append',
119
- help="Any additional security groups to attach to EC2 instances. Note that a security group "
120
- "with its name equal to the cluster name will always be created, thus ensure that "
121
- "the extra security groups do not have the same name as the cluster name.")
122
- parser.add_argument("--allowFuse", type=opt_strtobool, default=True,
123
- help="Enable both the leader and worker nodes to be able to run Singularity with FUSE. For "
124
- "Kubernetes, this will make the leader privileged and ask workers to run as privileged. "
125
- "(default: %(default)s)")
126
- #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
127
201
  options = parser.parse_args()
128
202
  set_logging_from_options(options)
129
203
 
@@ -131,75 +205,94 @@ def main() -> None:
131
205
 
132
206
  # Get worker node types
133
207
  worker_node_types = parse_node_types(options.nodeTypes)
134
- 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
+ )
135
211
 
136
212
  # Holds string ranges, like "5", or "3-10"
137
- worker_node_ranges = options.workers.split(',') if options.workers else []
213
+ worker_node_ranges = options.workers.split(",") if options.workers else []
138
214
 
139
215
  # checks the validity of TOIL_APPLIANCE_SELF before proceeding
140
216
  applianceSelf(forceDockerAppliance=options.forceDockerAppliance)
141
217
 
142
218
  # This holds either ints to launch static nodes, or tuples of ints
143
219
  # specifying ranges to launch managed auto-scaling nodes, for each type.
144
- nodeCounts: List[Union[int, Tuple[int, int]]] = []
220
+ nodeCounts: list[Union[int, tuple[int, int]]] = []
145
221
 
146
- if ((worker_node_types != [] or worker_node_ranges != []) and not
147
- (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
+ ):
148
225
  raise RuntimeError("The --nodeTypes option requires --workers, and visa versa.")
149
226
  if worker_node_types and worker_node_ranges:
150
- if not len(worker_node_types) == len(worker_node_ranges):
151
- raise RuntimeError("List of worker count ranges must be the same length as the list of node types.")
152
-
153
- for spec in worker_node_ranges:
154
- if '-' in spec:
155
- # Provision via autoscaling
156
- parts = spec.split('-')
157
- if len(parts) != 2:
158
- raise RuntimeError("Unacceptable range: " + spec)
159
- nodeCounts.append((int(parts[0]), int(parts[1])))
160
- else:
161
- # Provision fixed nodes
162
- nodeCounts.append(int(spec))
163
-
164
- 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
+ )
165
246
 
166
247
  # Check to see if the user specified a zone. If not, see if one is stored in an environment variable.
167
- 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
+ )
168
251
 
169
252
  if not options.zone:
170
- raise RuntimeError(f'Please provide a value for --zone or set a default in the '
171
- 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
+ )
172
257
 
173
258
  if options.clusterType == "mesos":
174
- logger.warning('You are using a Mesos cluster, which is no longer recommended as Toil is '
175
- 'transitioning to Kubernetes-based clusters. Consider switching to '
176
- '--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
+ )
177
264
 
178
265
  if options.clusterType is None:
179
- logger.warning('Argument --clusterType is not set... using "mesos". '
180
- 'In future versions of Toil, the default cluster scheduler will be '
181
- '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
+ )
182
271
  options.clusterType = "mesos"
183
272
 
184
- logger.info('Creating cluster %s...', options.clusterName)
185
-
186
- cluster = cluster_factory(provisioner=options.provisioner,
187
- clusterName=options.clusterName,
188
- clusterType=options.clusterType,
189
- zone=options.zone,
190
- nodeStorage=options.nodeStorage,
191
- enable_fuse=options.allowFuse)
192
-
193
- cluster.launchCluster(leaderNodeType=options.leaderNodeType,
194
- leaderStorage=options.leaderStorage,
195
- owner=owner,
196
- keyName=options.keyPairName,
197
- botoPath=options.botoPath,
198
- userTags=tags,
199
- network=options.network,
200
- vpcSubnet=options.vpcSubnet,
201
- awsEc2ProfileArn=options.awsEc2ProfileArn,
202
- 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
+ )
203
296
 
204
297
  for typeNum, spec in enumerate(nodeCounts):
205
298
  # For each batch of workers to make
@@ -217,8 +310,12 @@ def main() -> None:
217
310
  cluster.addNodes(nodeTypes=wanted[0], numNodes=spec, preemptible=False)
218
311
  else:
219
312
  # We have a spot bid
220
- cluster.addNodes(nodeTypes=wanted[0], numNodes=spec, preemptible=True,
221
- spotBid=wanted[1])
313
+ cluster.addNodes(
314
+ nodeTypes=wanted[0],
315
+ numNodes=spec,
316
+ preemptible=True,
317
+ spotBid=wanted[1],
318
+ )
222
319
 
223
320
  elif isinstance(spec, tuple):
224
321
  # Make a range of auto-scaling nodes
@@ -235,11 +332,20 @@ def main() -> None:
235
332
 
236
333
  if wanted[1] is None:
237
334
  # Make non-spot instances
238
- cluster.addManagedNodes(nodeTypes=wanted[0], minNodes=min_count, maxNodes=max_count,
239
- preemptible=False)
335
+ cluster.addManagedNodes(
336
+ nodeTypes=wanted[0],
337
+ minNodes=min_count,
338
+ maxNodes=max_count,
339
+ preemptible=False,
340
+ )
240
341
  else:
241
342
  # Bid at the given price.
242
- cluster.addManagedNodes(nodeTypes=wanted[0], minNodes=min_count, maxNodes=max_count,
243
- preemptible=True, spotBid=wanted[1])
244
-
245
- 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}")
@@ -17,29 +17,42 @@ import logging
17
17
  import sys
18
18
 
19
19
  from toil.common import parser_with_common_options
20
- from toil.provisioners import cluster_factory, NoSuchClusterException
20
+ from toil.provisioners import NoSuchClusterException, cluster_factory
21
21
  from toil.statsAndLogging import set_logging_from_options
22
22
 
23
23
  logger = logging.getLogger(__name__)
24
24
 
25
25
 
26
26
  def main() -> None:
27
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil rsync-cluster")
28
- parser.add_argument("--insecure", dest='insecure', action='store_true', required=False,
29
- help="Temporarily disable strict host key checking.")
30
- parser.add_argument("args", nargs=argparse.REMAINDER, help="Arguments to pass to"
31
- "`rsync`. Takes any arguments that rsync accepts. Specify the"
32
- " remote with a colon. For example, to upload `example.py`,"
33
- " specify `toil rsync-cluster -p aws test-cluster example.py :`."
34
- "\nOr, to download a file from the remote:, `toil rsync-cluster"
35
- " -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
+ )
36
47
  options = parser.parse_args()
37
48
  set_logging_from_options(options)
38
- cluster = cluster_factory(provisioner=options.provisioner,
39
- clusterName=options.clusterName,
40
- zone=options.zone)
49
+ cluster = cluster_factory(
50
+ provisioner=options.provisioner,
51
+ clusterName=options.clusterName,
52
+ zone=options.zone,
53
+ )
41
54
  try:
42
55
  cluster.getLeader().coreRsync(args=options.args, strict=not options.insecure)
43
56
  except NoSuchClusterException as e:
44
57
  logger.error(e)
45
- sys.exit(1)
58
+ sys.exit(1)