toil 5.12.0__py3-none-any.whl → 6.1.0a1__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 (157) hide show
  1. toil/__init__.py +18 -13
  2. toil/batchSystems/abstractBatchSystem.py +21 -10
  3. toil/batchSystems/abstractGridEngineBatchSystem.py +2 -2
  4. toil/batchSystems/awsBatch.py +14 -14
  5. toil/batchSystems/contained_executor.py +3 -3
  6. toil/batchSystems/htcondor.py +0 -1
  7. toil/batchSystems/kubernetes.py +34 -31
  8. toil/batchSystems/local_support.py +3 -1
  9. toil/batchSystems/mesos/batchSystem.py +7 -7
  10. toil/batchSystems/options.py +32 -83
  11. toil/batchSystems/registry.py +104 -23
  12. toil/batchSystems/singleMachine.py +16 -13
  13. toil/batchSystems/slurm.py +3 -3
  14. toil/batchSystems/torque.py +0 -1
  15. toil/bus.py +6 -8
  16. toil/common.py +532 -743
  17. toil/cwl/__init__.py +28 -32
  18. toil/cwl/cwltoil.py +523 -520
  19. toil/cwl/utils.py +55 -10
  20. toil/fileStores/__init__.py +2 -2
  21. toil/fileStores/abstractFileStore.py +36 -11
  22. toil/fileStores/cachingFileStore.py +607 -530
  23. toil/fileStores/nonCachingFileStore.py +43 -10
  24. toil/job.py +140 -75
  25. toil/jobStores/abstractJobStore.py +147 -79
  26. toil/jobStores/aws/jobStore.py +23 -9
  27. toil/jobStores/aws/utils.py +1 -2
  28. toil/jobStores/fileJobStore.py +117 -19
  29. toil/jobStores/googleJobStore.py +16 -7
  30. toil/jobStores/utils.py +5 -6
  31. toil/leader.py +71 -43
  32. toil/lib/accelerators.py +10 -5
  33. toil/lib/aws/__init__.py +3 -14
  34. toil/lib/aws/ami.py +22 -9
  35. toil/lib/aws/iam.py +21 -13
  36. toil/lib/aws/session.py +2 -16
  37. toil/lib/aws/utils.py +4 -5
  38. toil/lib/compatibility.py +1 -1
  39. toil/lib/conversions.py +7 -3
  40. toil/lib/docker.py +22 -23
  41. toil/lib/ec2.py +10 -6
  42. toil/lib/ec2nodes.py +106 -100
  43. toil/lib/encryption/_nacl.py +2 -1
  44. toil/lib/generatedEC2Lists.py +325 -18
  45. toil/lib/io.py +21 -0
  46. toil/lib/misc.py +1 -1
  47. toil/lib/resources.py +1 -1
  48. toil/lib/threading.py +74 -26
  49. toil/options/common.py +738 -0
  50. toil/options/cwl.py +336 -0
  51. toil/options/wdl.py +32 -0
  52. toil/provisioners/abstractProvisioner.py +1 -4
  53. toil/provisioners/aws/__init__.py +3 -6
  54. toil/provisioners/aws/awsProvisioner.py +6 -0
  55. toil/provisioners/clusterScaler.py +3 -2
  56. toil/provisioners/gceProvisioner.py +2 -2
  57. toil/realtimeLogger.py +2 -1
  58. toil/resource.py +24 -18
  59. toil/server/app.py +2 -3
  60. toil/server/cli/wes_cwl_runner.py +4 -4
  61. toil/server/utils.py +1 -1
  62. toil/server/wes/abstract_backend.py +3 -2
  63. toil/server/wes/amazon_wes_utils.py +5 -4
  64. toil/server/wes/tasks.py +2 -3
  65. toil/server/wes/toil_backend.py +2 -10
  66. toil/server/wsgi_app.py +2 -0
  67. toil/serviceManager.py +12 -10
  68. toil/statsAndLogging.py +5 -1
  69. toil/test/__init__.py +29 -54
  70. toil/test/batchSystems/batchSystemTest.py +11 -111
  71. toil/test/batchSystems/test_slurm.py +3 -2
  72. toil/test/cwl/cwlTest.py +213 -90
  73. toil/test/cwl/glob_dir.cwl +15 -0
  74. toil/test/cwl/preemptible.cwl +21 -0
  75. toil/test/cwl/preemptible_expression.cwl +28 -0
  76. toil/test/cwl/revsort.cwl +1 -1
  77. toil/test/cwl/revsort2.cwl +1 -1
  78. toil/test/docs/scriptsTest.py +0 -1
  79. toil/test/jobStores/jobStoreTest.py +27 -16
  80. toil/test/lib/aws/test_iam.py +4 -14
  81. toil/test/lib/aws/test_utils.py +0 -3
  82. toil/test/lib/dockerTest.py +4 -4
  83. toil/test/lib/test_ec2.py +11 -16
  84. toil/test/mesos/helloWorld.py +4 -5
  85. toil/test/mesos/stress.py +1 -1
  86. toil/test/provisioners/aws/awsProvisionerTest.py +9 -5
  87. toil/test/provisioners/clusterScalerTest.py +6 -4
  88. toil/test/provisioners/clusterTest.py +14 -3
  89. toil/test/provisioners/gceProvisionerTest.py +0 -6
  90. toil/test/provisioners/restartScript.py +3 -2
  91. toil/test/server/serverTest.py +1 -1
  92. toil/test/sort/restart_sort.py +2 -1
  93. toil/test/sort/sort.py +2 -1
  94. toil/test/sort/sortTest.py +2 -13
  95. toil/test/src/autoDeploymentTest.py +45 -45
  96. toil/test/src/busTest.py +5 -5
  97. toil/test/src/checkpointTest.py +2 -2
  98. toil/test/src/deferredFunctionTest.py +1 -1
  99. toil/test/src/fileStoreTest.py +32 -16
  100. toil/test/src/helloWorldTest.py +1 -1
  101. toil/test/src/importExportFileTest.py +1 -1
  102. toil/test/src/jobDescriptionTest.py +2 -1
  103. toil/test/src/jobServiceTest.py +1 -1
  104. toil/test/src/jobTest.py +18 -18
  105. toil/test/src/miscTests.py +5 -3
  106. toil/test/src/promisedRequirementTest.py +3 -3
  107. toil/test/src/realtimeLoggerTest.py +1 -1
  108. toil/test/src/resourceTest.py +2 -2
  109. toil/test/src/restartDAGTest.py +1 -1
  110. toil/test/src/resumabilityTest.py +36 -2
  111. toil/test/src/retainTempDirTest.py +1 -1
  112. toil/test/src/systemTest.py +2 -2
  113. toil/test/src/toilContextManagerTest.py +2 -2
  114. toil/test/src/userDefinedJobArgTypeTest.py +1 -1
  115. toil/test/utils/toilDebugTest.py +98 -32
  116. toil/test/utils/toilKillTest.py +2 -2
  117. toil/test/utils/utilsTest.py +20 -0
  118. toil/test/wdl/wdltoil_test.py +148 -45
  119. toil/toilState.py +7 -6
  120. toil/utils/toilClean.py +1 -1
  121. toil/utils/toilConfig.py +36 -0
  122. toil/utils/toilDebugFile.py +60 -33
  123. toil/utils/toilDebugJob.py +39 -12
  124. toil/utils/toilDestroyCluster.py +1 -1
  125. toil/utils/toilKill.py +1 -1
  126. toil/utils/toilLaunchCluster.py +13 -2
  127. toil/utils/toilMain.py +3 -2
  128. toil/utils/toilRsyncCluster.py +1 -1
  129. toil/utils/toilSshCluster.py +1 -1
  130. toil/utils/toilStats.py +240 -143
  131. toil/utils/toilStatus.py +1 -4
  132. toil/version.py +11 -11
  133. toil/wdl/utils.py +2 -122
  134. toil/wdl/wdltoil.py +999 -386
  135. toil/worker.py +25 -31
  136. {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/METADATA +60 -53
  137. toil-6.1.0a1.dist-info/RECORD +237 -0
  138. {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/WHEEL +1 -1
  139. {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/entry_points.txt +0 -1
  140. toil/batchSystems/parasol.py +0 -379
  141. toil/batchSystems/tes.py +0 -459
  142. toil/test/batchSystems/parasolTestSupport.py +0 -117
  143. toil/test/wdl/builtinTest.py +0 -506
  144. toil/test/wdl/conftest.py +0 -23
  145. toil/test/wdl/toilwdlTest.py +0 -522
  146. toil/wdl/toilwdl.py +0 -141
  147. toil/wdl/versions/dev.py +0 -107
  148. toil/wdl/versions/draft2.py +0 -980
  149. toil/wdl/versions/v1.py +0 -794
  150. toil/wdl/wdl_analysis.py +0 -116
  151. toil/wdl/wdl_functions.py +0 -997
  152. toil/wdl/wdl_synthesis.py +0 -1011
  153. toil/wdl/wdl_types.py +0 -243
  154. toil-5.12.0.dist-info/RECORD +0 -244
  155. /toil/{wdl/versions → options}/__init__.py +0 -0
  156. {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/LICENSE +0 -0
  157. {toil-5.12.0.dist-info → toil-6.1.0a1.dist-info}/top_level.txt +0 -0
@@ -15,17 +15,19 @@
15
15
  import argparse
16
16
  import logging
17
17
  import os.path
18
+ import sys
18
19
  from typing import Optional
20
+ from distutils.util import strtobool
19
21
 
20
22
  from toil.common import Config, Toil, parser_with_common_options
21
- from toil.jobStores.abstractJobStore import AbstractJobStore
23
+ from toil.jobStores.fileJobStore import FileJobStore
22
24
  from toil.lib.resources import glob
23
25
  from toil.statsAndLogging import set_logging_from_options
24
26
 
25
27
  logger = logging.getLogger(__name__)
26
28
 
27
29
 
28
- def fetchJobStoreFiles(jobStore: AbstractJobStore, options: argparse.Namespace) -> None:
30
+ def fetchJobStoreFiles(jobStore: FileJobStore, options: argparse.Namespace) -> None:
29
31
  """
30
32
  Takes a list of file names as glob patterns, searches for these within a
31
33
  given directory, and attempts to take all of the files found and copy them
@@ -37,6 +39,10 @@ def fetchJobStoreFiles(jobStore: AbstractJobStore, options: argparse.Namespace)
37
39
  :param options.localFilePath: Local directory to copy files into.
38
40
  :param options.jobStore: The path to the jobStore directory.
39
41
  """
42
+
43
+ # TODO: Implement the necessary methods in the job store class and stop
44
+ # globbing around inside it. Does this even work?
45
+
40
46
  for jobStoreFile in options.fetch:
41
47
  jobStoreHits = glob(directoryname=options.jobStore,
42
48
  glob_pattern=jobStoreFile)
@@ -48,40 +54,42 @@ def fetchJobStoreFiles(jobStore: AbstractJobStore, options: argparse.Namespace)
48
54
  symlink=options.useSymlinks)
49
55
 
50
56
 
51
- def printContentsOfJobStore(jobStorePath: str, nameOfJob: Optional[str] = None) -> None:
57
+ def printContentsOfJobStore(job_store: FileJobStore, job_id: Optional[str] = None) -> None:
52
58
  """
53
- Fetch a list of all files contained in the jobStore directory input if
54
- nameOfJob is not declared, otherwise it only prints out the names of files
55
- for that specific job for which it can find a match. Also creates a logFile
56
- containing this same record of job files in the working directory.
57
-
58
- :param jobStorePath: Directory path to recursively look for files.
59
- :param nameOfJob: Default is None, which prints out all files in the jobStore.
60
- If specified, it will print all jobStore files that have been written to the
61
- jobStore by that job.
59
+ Fetch a list of all files contained in the job store if nameOfJob is not
60
+ declared, otherwise it only prints out the names of files for that specific
61
+ job for which it can find a match. Also creates a log file of these file
62
+ names in the current directory.
63
+
64
+ :param job_store: Job store to ask for files from.
65
+ :param job_id: Default is None, which prints out all files in the jobStore.
66
+ If specified, it will print all jobStore files that have been written
67
+ to the jobStore by that job.
62
68
  """
63
69
 
64
- if nameOfJob:
65
- glob_pattern = "*" + nameOfJob + "*"
66
- logFile = nameOfJob + "_fileset.txt"
70
+ # TODO: Implement the necessary methods for job stores other than
71
+ # FileJobStore.
72
+
73
+ if job_id:
74
+ logFile = job_id.replace("/", "_") + "_fileset.txt"
67
75
  else:
68
- glob_pattern = "*"
69
76
  logFile = "jobstore_files.txt"
70
- nameOfJob = ""
71
77
 
72
- list_of_files = glob(directoryname=jobStorePath, glob_pattern=glob_pattern)
78
+ list_of_files = job_store.list_all_file_names(for_job=job_id)
73
79
  if os.path.exists(logFile):
74
80
  os.remove(logFile)
75
81
  for gfile in sorted(list_of_files):
76
- if not gfile.endswith('.new'):
77
- logger.debug(f"{nameOfJob} File: {os.path.basename(gfile)}")
78
- with open(logFile, "a+") as f:
79
- f.write(os.path.basename(gfile))
80
- f.write("\n")
82
+ if job_id:
83
+ logger.debug(f"{job_id} File: {os.path.basename(gfile)}")
84
+ else:
85
+ logger.debug(f"File: {os.path.basename(gfile)}")
86
+ with open(logFile, "a+") as f:
87
+ f.write(os.path.basename(gfile))
88
+ f.write("\n")
81
89
 
82
90
 
83
91
  def main() -> None:
84
- parser = parser_with_common_options(jobstore_option=True)
92
+ parser = parser_with_common_options(jobstore_option=True, prog="toil debug-file")
85
93
  parser.add_argument("--localFilePath",
86
94
  nargs=1,
87
95
  help="Location to which to copy job store files.")
@@ -90,11 +98,11 @@ def main() -> None:
90
98
  help="List of job-store files to be copied locally."
91
99
  "Use either explicit names (i.e. 'data.txt'), or "
92
100
  "specify glob patterns (i.e. '*.txt')")
93
- parser.add_argument("--listFilesInJobStore",
101
+ parser.add_argument("--listFilesInJobStore", type=strtobool,
94
102
  help="Prints a list of the current files in the jobStore.")
95
- parser.add_argument("--fetchEntireJobStore",
103
+ parser.add_argument("--fetchEntireJobStore", type=strtobool,
96
104
  help="Copy all job store files into a local directory.")
97
- parser.add_argument("--useSymlinks",
105
+ parser.add_argument("--useSymlinks", type=strtobool,
98
106
  help="Creates symlink 'shortcuts' of files in the localFilePath"
99
107
  " instead of hardlinking or copying, where possible. If this is"
100
108
  " not possible, it will copy the files (shutil.copyfile()).")
@@ -109,18 +117,37 @@ def main() -> None:
109
117
 
110
118
  if options.fetch:
111
119
  # Copy only the listed files locally
112
- logger.debug("Fetching local files: %s", options.fetch)
113
- fetchJobStoreFiles(jobStore=jobStore, options=options)
120
+
121
+ if isinstance(jobStore, FileJobStore):
122
+ logger.debug("Fetching local files: %s", options.fetch)
123
+ fetchJobStoreFiles(jobStore=jobStore, options=options)
124
+ else:
125
+ # The user asked for something we can't do yet.
126
+ # Tell them no but don't stack trace.
127
+ logger.critical("Can only fetch by name or glob from file-based job stores")
128
+ sys.exit(1)
114
129
 
115
130
  elif options.fetchEntireJobStore:
116
131
  # Copy all jobStore files locally
117
- logger.debug("Fetching all local files.")
118
- options.fetch = "*"
119
- fetchJobStoreFiles(jobStore=jobStore, options=options)
132
+
133
+ if isinstance(jobStore, FileJobStore):
134
+ logger.debug("Fetching all local files.")
135
+ options.fetch = "*"
136
+ fetchJobStoreFiles(jobStore=jobStore, options=options)
137
+ else:
138
+ logger.critical("Can only fetch by name or glob from file-based job stores")
139
+ sys.exit(1)
120
140
 
121
141
  if options.listFilesInJobStore:
122
142
  # Log filenames and create a file containing these names in cwd
123
- printContentsOfJobStore(jobStorePath=options.jobStore)
143
+
144
+ if isinstance(jobStore, FileJobStore):
145
+ printContentsOfJobStore(job_store=jobStore)
146
+ else:
147
+ logger.critical("Can only list files from file-based job stores")
148
+ sys.exit(1)
149
+
150
+ # TODO: We can't actually do *anything* for non-file job stores.
124
151
 
125
152
 
126
153
  if __name__ == "__main__":
@@ -14,7 +14,11 @@
14
14
  """Debug tool for running a toil job locally."""
15
15
  import logging
16
16
 
17
+ import pprint
18
+ import sys
19
+
17
20
  from toil.common import Config, Toil, parser_with_common_options
21
+ from toil.jobStores.fileJobStore import FileJobStore
18
22
  from toil.statsAndLogging import set_logging_from_options
19
23
  from toil.utils.toilDebugFile import printContentsOfJobStore
20
24
  from toil.worker import workerScript
@@ -23,28 +27,51 @@ logger = logging.getLogger(__name__)
23
27
 
24
28
 
25
29
  def main() -> None:
26
- parser = parser_with_common_options(jobstore_option=True)
27
- parser.add_argument("jobID", nargs=1,
30
+ parser = parser_with_common_options(jobstore_option=True, prog="toil debug-job")
31
+ parser.add_argument("jobID", type=str, nargs='?', default=None,
28
32
  help="The job store id of a job within the provided jobstore to run by itself.")
29
- parser.add_argument("--printJobInfo", nargs=1,
30
- help="Return information about this job to the user including preceding jobs, "
31
- "inputs, outputs, and runtime from the last known run.")
33
+ parser.add_argument("--printJobInfo", type=str,
34
+ help="Dump debugging info about this job ID")
32
35
 
33
36
  options = parser.parse_args()
34
37
  set_logging_from_options(options)
35
- config = Config()
38
+
39
+ jobStore = Toil.resumeJobStore(options.jobStore)
40
+ # Get the config with the workflow ID from the job store
41
+ config = jobStore.config
42
+ # But override its options
36
43
  config.setOptions(options)
37
44
 
38
- jobStore = Toil.resumeJobStore(config.jobStore)
45
+ did_something = False
39
46
 
40
47
  if options.printJobInfo:
41
- printContentsOfJobStore(jobStorePath=config.jobStore, nameOfJob=options.printJobInfo)
48
+ if isinstance(jobStore, FileJobStore):
49
+ # List all its files if we can
50
+ printContentsOfJobStore(job_store=jobStore, job_id=options.printJobInfo)
51
+ # Print the job description itself
52
+ job_desc = jobStore.load_job(options.printJobInfo)
53
+ print(f"Job: {job_desc}")
54
+ pprint.pprint(job_desc.__dict__)
55
+
56
+ did_something = True
42
57
 
43
58
  # TODO: Option to print list of successor jobs
44
59
  # TODO: Option to run job within python debugger, allowing step through of arguments
45
60
  # idea would be to have option to import pdb and set breakpoint at the start of the user's code
46
61
 
47
- jobID = options.jobID[0]
48
- logger.debug(f"Running the following job locally: {jobID}")
49
- workerScript(jobStore, config, jobID, jobID, redirectOutputToLogFile=False)
50
- logger.debug(f"Finished running: {jobID}")
62
+ if options.jobID is not None:
63
+ # We actually want to run a job.
64
+
65
+ jobID = options.jobID
66
+ logger.debug(f"Running the following job locally: {jobID}")
67
+ workerScript(jobStore, config, jobID, jobID, redirectOutputToLogFile=False)
68
+ logger.debug(f"Finished running: {jobID}")
69
+ # Even if the job fails, the worker script succeeds unless something goes wrong with it internally.
70
+
71
+ did_something = True
72
+
73
+ if not did_something:
74
+ # Somebody forgot to tell us to do anything.
75
+ # Show the usage instructions.
76
+ parser.print_help()
77
+ sys.exit(1)
@@ -21,7 +21,7 @@ from toil.statsAndLogging import set_logging_from_options
21
21
  logger = logging.getLogger(__name__)
22
22
 
23
23
  def main() -> None:
24
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False)
24
+ parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil destroy-cluster")
25
25
  options = parser.parse_args()
26
26
  set_logging_from_options(options)
27
27
 
toil/utils/toilKill.py CHANGED
@@ -25,7 +25,7 @@ logger = logging.getLogger(__name__)
25
25
 
26
26
 
27
27
  def main() -> None:
28
- parser = parser_with_common_options()
28
+ parser = parser_with_common_options(prog="toil kill")
29
29
  parser.add_argument('--force', action='store_true',
30
30
  help="Send SIGKILL to the leader process if local.")
31
31
  options = parser.parse_args()
@@ -37,9 +37,10 @@ def create_tags_dict(tags: List[str]) -> Dict[str, str]:
37
37
 
38
38
 
39
39
  def main() -> None:
40
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False)
40
+ parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil launch-cluster")
41
41
  parser.add_argument("-T", "--clusterType", dest="clusterType",
42
- choices=['mesos', 'kubernetes'], default='mesos',
42
+ choices=['mesos', 'kubernetes'],
43
+ default=None, # TODO: change default to "kubernetes" when we are ready.
43
44
  help="Cluster scheduler to use.")
44
45
  parser.add_argument("--leaderNodeType", dest="leaderNodeType", required=True,
45
46
  help="Non-preemptible node type to use for the cluster leader.")
@@ -160,6 +161,16 @@ def main() -> None:
160
161
  raise RuntimeError(f'Please provide a value for --zone or set a default in the '
161
162
  f'TOIL_{options.provisioner.upper()}_ZONE environment variable.')
162
163
 
164
+ 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.')
168
+
169
+ 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.')
173
+ options.clusterType = "mesos"
163
174
 
164
175
  logger.info('Creating cluster %s...', options.clusterName)
165
176
 
toil/utils/toilMain.py CHANGED
@@ -5,7 +5,7 @@ import textwrap
5
5
  import types
6
6
  from typing import Any, Dict
7
7
 
8
- import pkg_resources
8
+ from importlib.metadata import version as metadata_version
9
9
 
10
10
  from toil.version import version
11
11
 
@@ -47,6 +47,7 @@ def get_or_die(module: types.ModuleType, name: str) -> Any:
47
47
  def loadModules() -> Dict[str, types.ModuleType]:
48
48
  # noinspection PyUnresolvedReferences
49
49
  from toil.utils import toilClean # noqa
50
+ from toil.utils import toilConfig # noqa
50
51
  from toil.utils import toilDebugFile # noqa
51
52
  from toil.utils import toilDebugJob # noqa
52
53
  from toil.utils import toilDestroyCluster # noqa
@@ -77,6 +78,6 @@ def printHelp(modules: Dict[str, types.ModuleType]) -> None:
77
78
 
78
79
  def printVersion() -> None:
79
80
  try:
80
- print(pkg_resources.get_distribution('toil').version)
81
+ print(metadata_version('toil'))
81
82
  except:
82
83
  print(f'Version gathered from toil.version: {version}')
@@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
23
23
 
24
24
 
25
25
  def main() -> None:
26
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False)
26
+ parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil rsync-cluster")
27
27
  parser.add_argument("--insecure", dest='insecure', action='store_true', required=False,
28
28
  help="Temporarily disable strict host key checking.")
29
29
  parser.add_argument("args", nargs=argparse.REMAINDER, help="Arguments to pass to"
@@ -25,7 +25,7 @@ logger = logging.getLogger(__name__)
25
25
 
26
26
 
27
27
  def main() -> None:
28
- parser = parser_with_common_options(provisioner_options=True, jobstore_option=False)
28
+ parser = parser_with_common_options(provisioner_options=True, jobstore_option=False, prog="toil ssh-cluster")
29
29
  parser.add_argument("--insecure", action='store_true',
30
30
  help="Temporarily disable strict host key checking.")
31
31
  parser.add_argument("--sshOption", dest='sshOptions', default=[], action='append',