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
@@ -12,19 +12,18 @@
12
12
  # See the License for the specific language governing permissions and
13
13
 
14
14
  import logging
15
- import os
16
15
  import sys
17
16
  from argparse import ArgumentParser, _ArgumentGroup
18
- from typing import Any, Callable, List, Optional, TypeVar, Union, cast
17
+ from typing import Any, Callable, List, Optional, TypeVar, Union
19
18
 
20
19
  if sys.version_info >= (3, 8):
21
20
  from typing import Protocol
22
21
  else:
23
22
  from typing_extensions import Protocol
24
23
 
25
- from toil.batchSystems.registry import (BATCH_SYSTEM_FACTORY_REGISTRY,
26
- BATCH_SYSTEMS,
27
- DEFAULT_BATCH_SYSTEM)
24
+ from toil.batchSystems.registry import (DEFAULT_BATCH_SYSTEM,
25
+ get_batch_system,
26
+ get_batch_systems)
28
27
  from toil.lib.threading import cpu_count
29
28
 
30
29
  logger = logging.getLogger(__name__)
@@ -56,60 +55,62 @@ def set_batchsystem_options(batch_system: Optional[str], set_option: OptionSette
56
55
  """
57
56
  if batch_system is not None:
58
57
  # Use this batch system
59
- batch_system_type = BATCH_SYSTEM_FACTORY_REGISTRY[batch_system]()
58
+ batch_system_type = get_batch_system(batch_system)
60
59
  batch_system_type.setOptions(set_option)
61
60
  else:
62
- for factory in BATCH_SYSTEM_FACTORY_REGISTRY.values():
61
+ for name in get_batch_systems():
63
62
  # All the batch systems are responsible for setting their own options
64
63
  # with their setOptions() class methods.
65
64
  try:
66
- batch_system_type = factory()
65
+ batch_system_type = get_batch_system(name)
67
66
  except ImportError:
68
67
  # Skip anything we can't import
69
68
  continue
70
69
  # Ask the batch system to tell us all its options.
71
70
  batch_system_type.setOptions(set_option)
72
71
  # Options shared between multiple batch systems
73
- set_option("disableAutoDeployment", bool, default=False)
72
+ set_option("disableAutoDeployment")
74
73
  # Make limits maximum if set to 0
75
- set_option("max_jobs", lambda x: int(x) or sys.maxsize)
76
- set_option("max_local_jobs", lambda x: int(x) or sys.maxsize)
74
+ set_option("max_jobs")
75
+ set_option("max_local_jobs")
77
76
  set_option("manualMemArgs")
78
- set_option("run_local_jobs_on_workers", bool, default=False)
77
+ set_option("run_local_jobs_on_workers")
79
78
  set_option("statePollingWait")
80
- set_option("batch_logs_dir", env=["TOIL_BATCH_LOGS_DIR"])
79
+ set_option("batch_logs_dir")
81
80
 
82
81
 
83
82
  def add_all_batchsystem_options(parser: Union[ArgumentParser, _ArgumentGroup]) -> None:
83
+ from toil.options.common import SYS_MAX_SIZE
84
+
84
85
  # Do the global cross-batch-system arguments
85
86
  parser.add_argument(
86
87
  "--batchSystem",
87
88
  dest="batchSystem",
88
89
  default=DEFAULT_BATCH_SYSTEM,
89
- choices=BATCH_SYSTEMS,
90
+ choices=get_batch_systems(),
90
91
  help=f"The type of batch system to run the job(s) with, currently can be one "
91
- f"of {', '.join(BATCH_SYSTEMS)}. default={DEFAULT_BATCH_SYSTEM}",
92
+ f"of {', '.join(get_batch_systems())}. Default = {DEFAULT_BATCH_SYSTEM}",
92
93
  )
93
94
  parser.add_argument(
94
95
  "--disableHotDeployment",
95
96
  dest="disableAutoDeployment",
97
+ default=False,
96
98
  action="store_true",
97
- default=None,
98
99
  help="Hot-deployment was renamed to auto-deployment. Option now redirects to "
99
- "--disableAutoDeployment. Left in for backwards compatibility.",
100
+ "--disableAutoDeployment. Left in for backwards compatibility.",
100
101
  )
101
102
  parser.add_argument(
102
103
  "--disableAutoDeployment",
103
104
  dest="disableAutoDeployment",
104
- action="store_true",
105
- default=None,
106
- help="Should auto-deployment of the user script be deactivated? If True, the user "
107
- "script/package should be present at the same location on all workers. Default = False.",
105
+ default=False,
106
+ help="Should auto-deployment of Toil Python workflows be deactivated? If True, the workflow's "
107
+ "Python code should be present at the same location on all workers. Default = False.",
108
108
  )
109
109
  parser.add_argument(
110
110
  "--maxJobs",
111
111
  dest="max_jobs",
112
- default=sys.maxsize, # This is *basically* unlimited and saves a lot of Optional[]
112
+ default=SYS_MAX_SIZE, # This is *basically* unlimited and saves a lot of Optional[]
113
+ type=lambda x: int(x) or SYS_MAX_SIZE,
113
114
  help="Specifies the maximum number of jobs to submit to the "
114
115
  "backing scheduler at once. Not supported on Mesos or "
115
116
  "AWS Batch. Use 0 for unlimited. Defaults to unlimited.",
@@ -117,7 +118,8 @@ def add_all_batchsystem_options(parser: Union[ArgumentParser, _ArgumentGroup]) -
117
118
  parser.add_argument(
118
119
  "--maxLocalJobs",
119
120
  dest="max_local_jobs",
120
- default=cpu_count(),
121
+ default=None,
122
+ type=lambda x: int(x) or 0,
121
123
  help=f"Specifies the maximum number of housekeeping jobs to "
122
124
  f"run sumultaneously on the local system. Use 0 for "
123
125
  f"unlimited. Defaults to the number of local cores ({cpu_count()}).",
@@ -125,18 +127,18 @@ def add_all_batchsystem_options(parser: Union[ArgumentParser, _ArgumentGroup]) -
125
127
  parser.add_argument(
126
128
  "--manualMemArgs",
127
129
  default=False,
128
- action="store_true",
129
130
  dest="manualMemArgs",
131
+ action="store_true",
130
132
  help="Do not add the default arguments: 'hv=MEMORY' & 'h_vmem=MEMORY' to the qsub "
131
133
  "call, and instead rely on TOIL_GRIDGENGINE_ARGS to supply alternative arguments. "
132
134
  "Requires that TOIL_GRIDGENGINE_ARGS be set.",
133
135
  )
134
136
  parser.add_argument(
135
- "--runLocalJobsOnWorkers"
137
+ "--runLocalJobsOnWorkers",
136
138
  "--runCwlInternalJobsOnWorkers",
137
139
  dest="run_local_jobs_on_workers",
140
+ default=False,
138
141
  action="store_true",
139
- default=None,
140
142
  help="Whether to run jobs marked as local (e.g. CWLScatter) on the worker nodes "
141
143
  "instead of the leader node. If false (default), then all such jobs are run on "
142
144
  "the leader node. Setting this to true can speed up CWL pipelines for very large "
@@ -166,6 +168,7 @@ def add_all_batchsystem_options(parser: Union[ArgumentParser, _ArgumentGroup]) -
166
168
  "--batchLogsDir",
167
169
  dest="batch_logs_dir",
168
170
  default=None,
171
+ env_var="TOIL_BATCH_LOGS_DIR",
169
172
  help="Directory to tell the backing batch system to log into. Should be available "
170
173
  "on both the leader and the workers, if the backing batch system writes logs "
171
174
  "to the worker machines' filesystems, as many HPC schedulers do. If unset, "
@@ -173,68 +176,14 @@ def add_all_batchsystem_options(parser: Union[ArgumentParser, _ArgumentGroup]) -
173
176
  "systems such as gridengine, htcondor, torque, slurm, and lsf."
174
177
  )
175
178
 
176
- for factory in BATCH_SYSTEM_FACTORY_REGISTRY.values():
179
+ for name in get_batch_systems():
177
180
  # All the batch systems are responsible for adding their own options
178
181
  # with the add_options class method.
179
182
  try:
180
- batch_system_type = factory()
183
+ batch_system_type = get_batch_system(name)
181
184
  except ImportError:
182
185
  # Skip anything we can't import
183
186
  continue
184
187
  # Ask the batch system to create its options in the parser
185
- logger.debug('Add options for %s', batch_system_type)
188
+ logger.debug('Add options for %s batch system', name)
186
189
  batch_system_type.add_options(parser)
187
-
188
- def set_batchsystem_config_defaults(config) -> None:
189
- """
190
- Set default and environment-based options for builtin batch systems. This
191
- is required if a Config object is not constructed from an Options object.
192
- """
193
-
194
- # Do the global options across batch systems
195
- config.batchSystem = "single_machine"
196
- config.disableAutoDeployment = False
197
- config.max_jobs = sys.maxsize
198
- config.max_local_jobs = cpu_count()
199
- config.manualMemArgs = False
200
- config.statePollingWait: Optional[Union[float, int]] = None # Number of seconds to wait before querying job state
201
-
202
- OptionType = TypeVar('OptionType')
203
- def set_option(option_name: str,
204
- parsing_function: Optional[Callable[[Any], OptionType]] = None,
205
- check_function: Optional[Callable[[OptionType], None]] = None,
206
- default: Optional[OptionType] = None,
207
- env: Optional[List[str]] = None,
208
- old_names: Optional[List[str]] = None) -> None:
209
- """
210
- Function to set a batch-system-defined option to its default value, or
211
- one from the environment.
212
- """
213
-
214
- # TODO: deduplicate with Config
215
-
216
- option_value = default
217
-
218
- if env is not None:
219
- for env_var in env:
220
- # Try all the environment variables
221
- if option_value != default:
222
- break
223
- option_value = os.environ.get(env_var, default)
224
-
225
- if option_value is not None or not hasattr(config, option_name):
226
- if parsing_function is not None:
227
- # Parse whatever it is (string, argparse-made list, etc.)
228
- option_value = parsing_function(option_value)
229
- if check_function is not None:
230
- try:
231
- check_function(option_value)
232
- except AssertionError:
233
- raise RuntimeError(f"The {option_name} option has an invalid value: {option_value}")
234
- setattr(config, option_name, option_value)
235
-
236
- # Set up defaults from all the batch systems
237
- set_batchsystem_options(None, cast(OptionSetter, set_option))
238
-
239
-
240
-
@@ -12,14 +12,58 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import importlib
15
16
  import logging
16
- from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Type
17
+ import pkgutil
18
+ import warnings
19
+ from typing import TYPE_CHECKING, Callable, Dict, List, Sequence, Tuple, Type
20
+
21
+ from toil.lib.compatibility import deprecated
22
+ from toil.lib.memoize import memoize
17
23
 
18
24
  if TYPE_CHECKING:
19
25
  from toil.batchSystems.abstractBatchSystem import AbstractBatchSystem
20
26
 
21
27
  logger = logging.getLogger(__name__)
22
28
 
29
+ #####
30
+ # Plugin system/API
31
+ #####
32
+
33
+ def add_batch_system_factory(key: str, class_factory: Callable[[], Type['AbstractBatchSystem']]):
34
+ """
35
+ Adds a batch system to the registry for workflow or plugin-supplied batch systems.
36
+
37
+ :param class_factory: A function that returns a batch system class (NOT an instance), which implements :class:`toil.batchSystems.abstractBatchSystem.AbstractBatchSystem`.
38
+ """
39
+ _registry_keys.append(key)
40
+ _registry[key] = class_factory
41
+
42
+ def get_batch_systems() -> Sequence[str]:
43
+ """
44
+ Get the names of all the availsble batch systems.
45
+ """
46
+ _load_all_plugins()
47
+
48
+ return _registry_keys
49
+
50
+ def get_batch_system(key: str) -> Type['AbstractBatchSystem']:
51
+ """
52
+ Get a batch system class by name.
53
+
54
+ :raises: KeyError if the key is not the name of a batch system, and
55
+ ImportError if the batch system's class cannot be loaded.
56
+ """
57
+
58
+ return _registry[key]()
59
+
60
+
61
+ DEFAULT_BATCH_SYSTEM = 'single_machine'
62
+
63
+ #####
64
+ # Built-in batch systems
65
+ #####
66
+
23
67
  def aws_batch_batch_system_factory():
24
68
  from toil.batchSystems.awsBatch import AWSBatchBatchSystem
25
69
  return AWSBatchBatchSystem
@@ -29,11 +73,6 @@ def gridengine_batch_system_factory():
29
73
  return GridEngineBatchSystem
30
74
 
31
75
 
32
- def parasol_batch_system_factory():
33
- from toil.batchSystems.parasol import ParasolBatchSystem
34
- return ParasolBatchSystem
35
-
36
-
37
76
  def lsf_batch_system_factory():
38
77
  from toil.batchSystems.lsf import LSFBatchSystem
39
78
  return LSFBatchSystem
@@ -53,10 +92,6 @@ def slurm_batch_system_factory():
53
92
  from toil.batchSystems.slurm import SlurmBatchSystem
54
93
  return SlurmBatchSystem
55
94
 
56
- def tes_batch_system_factory():
57
- from toil.batchSystems.tes import TESBatchSystem
58
- return TESBatchSystem
59
-
60
95
  def torque_batch_system_factory():
61
96
  from toil.batchSystems.torque import TorqueBatchSystem
62
97
  return TorqueBatchSystem
@@ -71,29 +106,75 @@ def kubernetes_batch_system_factory():
71
106
  from toil.batchSystems.kubernetes import KubernetesBatchSystem
72
107
  return KubernetesBatchSystem
73
108
 
109
+ #####
110
+ # Registry implementation
111
+ #####
74
112
 
75
- BATCH_SYSTEM_FACTORY_REGISTRY: Dict[str, Callable[[], Type["AbstractBatchSystem"]]] = {
113
+ _registry: Dict[str, Callable[[], Type["AbstractBatchSystem"]]] = {
76
114
  'aws_batch' : aws_batch_batch_system_factory,
77
- 'parasol' : parasol_batch_system_factory,
78
115
  'single_machine' : single_machine_batch_system_factory,
79
116
  'grid_engine' : gridengine_batch_system_factory,
80
117
  'lsf' : lsf_batch_system_factory,
81
118
  'mesos' : mesos_batch_system_factory,
82
119
  'slurm' : slurm_batch_system_factory,
83
- 'tes' : tes_batch_system_factory,
84
120
  'torque' : torque_batch_system_factory,
85
121
  'htcondor' : htcondor_batch_system_factory,
86
122
  'kubernetes' : kubernetes_batch_system_factory
87
123
  }
88
- BATCH_SYSTEMS = list(BATCH_SYSTEM_FACTORY_REGISTRY.keys())
89
- DEFAULT_BATCH_SYSTEM = 'single_machine'
124
+ _registry_keys = list(_registry.keys())
125
+
126
+ # We will load any packages starting with this prefix and let them call
127
+ # add_batch_system_factory()
128
+ _PLUGIN_NAME_PREFIX = "toil_batch_system_"
129
+
130
+ @memoize
131
+ def _load_all_plugins() -> None:
132
+ """
133
+ Load all the batch system plugins that are installed.
134
+ """
135
+
136
+ for finder, name, is_pkg in pkgutil.iter_modules():
137
+ # For all installed packages
138
+ if name.startswith(_PLUGIN_NAME_PREFIX):
139
+ # If it is a Toil batch system plugin, import it
140
+ importlib.import_module(name)
141
+
142
+ #####
143
+ # Deprecated API
144
+ #####
90
145
 
146
+ # We used to directly access these constants, but now the Right Way to use this
147
+ # module is add_batch_system_factory() to register and get_batch_systems() to
148
+ # get the list/get_batch_system() to get a class by name.
149
+
150
+
151
+ def __getattr__(name):
152
+ """
153
+ Implement a fallback attribute getter to handle deprecated constants.
154
+
155
+ See <https://stackoverflow.com/a/48242860>.
156
+ """
157
+ if name == "BATCH_SYSTEM_FACTORY_REGISTRY":
158
+ warnings.warn("BATCH_SYSTEM_FACTORY_REGISTRY is deprecated; use get_batch_system() or add_batch_system_factory()", DeprecationWarning)
159
+ return _registry
160
+ elif name == "BATCH_SYSTEMS":
161
+ warnings.warn("BATCH_SYSTEMS is deprecated; use get_batch_systems()", DeprecationWarning)
162
+ return _registry_keys
163
+ else:
164
+ raise AttributeError(f"Module {__name__} ahs no attribute {name}")
165
+
166
+
167
+ @deprecated(new_function_name="add_batch_system_factory")
91
168
  def addBatchSystemFactory(key: str, batchSystemFactory: Callable[[], Type['AbstractBatchSystem']]):
92
169
  """
93
- Adds a batch system to the registry for workflow-supplied batch systems.
170
+ Deprecated method to add a batch system.
94
171
  """
95
- BATCH_SYSTEMS.append(key)
96
- BATCH_SYSTEM_FACTORY_REGISTRY[key] = batchSystemFactory
172
+ return add_batch_system_factory(key, batchSystemFactory)
173
+
174
+
175
+ #####
176
+ # Testing utilities
177
+ #####
97
178
 
98
179
  # We need a snapshot save/restore system for testing. We can't just tamper with
99
180
  # the globals because module-level globals are their own references, so we
@@ -106,7 +187,7 @@ def save_batch_system_plugin_state() -> Tuple[List[str], Dict[str, Callable[[],
106
187
  tests.
107
188
  """
108
189
 
109
- snapshot = (list(BATCH_SYSTEMS), dict(BATCH_SYSTEM_FACTORY_REGISTRY))
190
+ snapshot = (list(_registry_keys), dict(_registry))
110
191
  return snapshot
111
192
 
112
193
  def restore_batch_system_plugin_state(snapshot: Tuple[List[str], Dict[str, Callable[[], Type['AbstractBatchSystem']]]]):
@@ -118,7 +199,7 @@ def restore_batch_system_plugin_state(snapshot: Tuple[List[str], Dict[str, Calla
118
199
  # We need to apply the snapshot without rebinding the names, because that
119
200
  # won't affect modules that imported the names.
120
201
  wanted_batch_systems, wanted_registry = snapshot
121
- BATCH_SYSTEMS.clear()
122
- BATCH_SYSTEMS.extend(wanted_batch_systems)
123
- BATCH_SYSTEM_FACTORY_REGISTRY.clear()
124
- BATCH_SYSTEM_FACTORY_REGISTRY.update(wanted_registry)
202
+ _registry_keys.clear()
203
+ _registry_keys.extend(wanted_batch_systems)
204
+ _registry.clear()
205
+ _registry.update(wanted_registry)
@@ -22,23 +22,26 @@ import traceback
22
22
  from argparse import ArgumentParser, _ArgumentGroup
23
23
  from queue import Empty, Queue
24
24
  from threading import Event, Lock, Thread
25
- from typing import Dict, List, Optional, Set, Sequence, Tuple, Union
25
+ from typing import Dict, List, Optional, Sequence, Set, Tuple, Union
26
26
 
27
27
  import toil
28
28
  from toil import worker as toil_worker
29
29
  from toil.batchSystems.abstractBatchSystem import (EXIT_STATUS_UNAVAILABLE_VALUE,
30
30
  BatchSystemSupport,
31
+ InsufficientSystemResources,
31
32
  ResourcePool,
32
33
  ResourceSet,
33
- UpdatedBatchJobInfo,
34
- InsufficientSystemResources)
35
-
36
- from toil.bus import ExternalBatchIdMessage
34
+ UpdatedBatchJobInfo)
37
35
  from toil.batchSystems.options import OptionSetter
38
-
39
- from toil.common import SYS_MAX_SIZE, Config, Toil, fC
40
- from toil.job import JobDescription, AcceleratorRequirement, accelerator_satisfies, Requirer
41
- from toil.lib.accelerators import get_individual_local_accelerators, get_restrictive_environment_for_local_accelerators
36
+ from toil.bus import ExternalBatchIdMessage
37
+ from toil.common import Config, Toil
38
+ from toil.options.common import SYS_MAX_SIZE, make_open_interval_action
39
+ from toil.job import (AcceleratorRequirement,
40
+ JobDescription,
41
+ Requirer,
42
+ accelerator_satisfies)
43
+ from toil.lib.accelerators import (get_individual_local_accelerators,
44
+ get_restrictive_environment_for_local_accelerators)
42
45
  from toil.lib.threading import cpu_count
43
46
 
44
47
  logger = logging.getLogger(__name__)
@@ -104,7 +107,7 @@ class SingleMachineBatchSystem(BatchSystemSupport):
104
107
  logger.warning('Not enough cores! User limited to %i but we only have %i.', maxCores, self.numCores)
105
108
  maxCores = self.numCores
106
109
  if maxMemory > self.physicalMemory:
107
- if maxMemory != SYS_MAX_SIZE:
110
+ if maxMemory < SYS_MAX_SIZE: # todo: looks like humans2bytes converts SYS_MAX_SIZE to SYS_MAX_SIZE+1
108
111
  # We have an actually specified limit and not the default
109
112
  logger.warning('Not enough memory! User limited to %i bytes but we only have %i bytes.', maxMemory, self.physicalMemory)
110
113
  maxMemory = self.physicalMemory
@@ -112,7 +115,7 @@ class SingleMachineBatchSystem(BatchSystemSupport):
112
115
  workdir = Toil.getLocalWorkflowDir(config.workflowID, config.workDir) # config.workDir may be None; this sets a real directory
113
116
  self.physicalDisk = toil.physicalDisk(workdir)
114
117
  if maxDisk > self.physicalDisk:
115
- if maxDisk != SYS_MAX_SIZE:
118
+ if maxDisk < SYS_MAX_SIZE: # same as maxMemory logger.warning
116
119
  # We have an actually specified limit and not the default
117
120
  logger.warning('Not enough disk space! User limited to %i bytes but we only have %i bytes.', maxDisk, self.physicalDisk)
118
121
  maxDisk = self.physicalDisk
@@ -843,7 +846,7 @@ class SingleMachineBatchSystem(BatchSystemSupport):
843
846
 
844
847
  @classmethod
845
848
  def add_options(cls, parser: Union[ArgumentParser, _ArgumentGroup]) -> None:
846
- parser.add_argument("--scale", dest="scale", default=1,
849
+ parser.add_argument("--scale", dest="scale", type=float, default=1, action=make_open_interval_action(0.0),
847
850
  help="A scaling factor to change the value of all submitted tasks's submitted cores. "
848
851
  "Used in the single_machine batch system. Useful for running workflows on "
849
852
  "smaller machines than they were designed for, by setting a value less than 1. "
@@ -851,7 +854,7 @@ class SingleMachineBatchSystem(BatchSystemSupport):
851
854
 
852
855
  @classmethod
853
856
  def setOptions(cls, setOption: OptionSetter):
854
- setOption("scale", float, fC(0.0), default=1)
857
+ setOption("scale")
855
858
 
856
859
 
857
860
  class Info:
@@ -16,13 +16,13 @@ import math
16
16
  import os
17
17
  from argparse import ArgumentParser, _ArgumentGroup
18
18
  from shlex import quote
19
- from typing import Callable, Dict, List, Optional, TypeVar, Union
19
+ from typing import Dict, List, Optional, TypeVar, Union
20
20
 
21
21
  from toil.batchSystems.abstractGridEngineBatchSystem import \
22
22
  AbstractGridEngineBatchSystem
23
23
  from toil.batchSystems.options import OptionSetter
24
- from toil.lib.misc import CalledProcessErrorStderr, call_command
25
24
  from toil.job import Requirer
25
+ from toil.lib.misc import CalledProcessErrorStderr, call_command
26
26
 
27
27
  logger = logging.getLogger(__name__)
28
28
 
@@ -387,5 +387,5 @@ class SlurmBatchSystem(AbstractGridEngineBatchSystem):
387
387
  OptionType = TypeVar('OptionType')
388
388
  @classmethod
389
389
  def setOptions(cls, setOption: OptionSetter) -> None:
390
- setOption("allocate_mem", bool, default=False)
390
+ setOption("allocate_mem")
391
391
 
@@ -16,7 +16,6 @@ import math
16
16
  import os
17
17
  import shlex
18
18
  import tempfile
19
- import time
20
19
  from queue import Empty
21
20
  from shlex import quote
22
21
  from typing import Dict, List, Optional
toil/bus.py CHANGED
@@ -61,15 +61,13 @@ MessageBus.connect_output_file() and MessageBus.scan_bus_messages().
61
61
  """
62
62
 
63
63
  import collections
64
- from dataclasses import dataclass
65
- import inspect
64
+ import json
66
65
  import logging
67
-
68
66
  import os
69
67
  import queue
70
- import json
71
68
  import tempfile
72
69
  import threading
70
+ from dataclasses import dataclass
73
71
  from typing import (IO,
74
72
  Any,
75
73
  Callable,
@@ -80,7 +78,6 @@ from typing import (IO,
80
78
  Optional,
81
79
  Type,
82
80
  TypeVar,
83
- Union,
84
81
  cast)
85
82
 
86
83
  from pubsub.core import Publisher
@@ -396,8 +393,8 @@ class MessageBus:
396
393
  given topic.
397
394
  """
398
395
  # There should always be a "message"
399
- assert len(message_data) == 1
400
- assert 'message' in message_data
396
+ if len(message_data) != 1 or 'message' not in message_data:
397
+ raise RuntimeError("Cannot log the bus message. The message is either empty/malformed or there are too many messages provided.")
401
398
  message = message_data['message']
402
399
  topic = topic_object.getName()
403
400
  stream.write(topic.encode('utf-8'))
@@ -572,7 +569,8 @@ class MessageInbox(MessageBusClient):
572
569
  handled = False
573
570
  try:
574
571
  # Emit the message
575
- assert isinstance(message, message_type), f"Unacceptable message type {type(message)} in list for type {message_type}"
572
+ if not isinstance(message, message_type):
573
+ raise RuntimeError(f"Unacceptable message type {type(message)} in list for type {message_type}")
576
574
  yield message
577
575
  # If we get here it was handled without error.
578
576
  handled = True