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
@@ -46,10 +46,10 @@ class JobServiceTest(ToilTest):
46
46
  """
47
47
  job = Job()
48
48
  service = ToySerializableService("woot")
49
- startValue = job.addService(service) # Add a first service to job
50
- subService = ToySerializableService(startValue) # Now create a child of
49
+ startValue = job.addService(service) # Add a first service to job
50
+ subService = ToySerializableService(startValue) # Now create a child of
51
51
  # that service that takes the start value promise from the parent service
52
- job.addService(subService, parentService=service) # This should work if
52
+ job.addService(subService, parentService=service) # This should work if
53
53
  # serialization on services is working correctly.
54
54
 
55
55
  self.runToil(job)
@@ -60,11 +60,13 @@ class JobServiceTest(ToilTest):
60
60
  Tests the creation of a Job.Service with random failures of the worker.
61
61
  """
62
62
  for test in range(2):
63
- outFile = get_temp_file(rootDir=self._createTempDir()) # Temporary file
63
+ outFile = get_temp_file(rootDir=self._createTempDir()) # Temporary file
64
64
  messageInt = random.randint(1, sys.maxsize)
65
65
  try:
66
66
  # Wire up the services/jobs
67
- t = Job.wrapJobFn(serviceTest, outFile, messageInt, checkpoint=checkpoint)
67
+ t = Job.wrapJobFn(
68
+ serviceTest, outFile, messageInt, checkpoint=checkpoint
69
+ )
68
70
 
69
71
  # Run the workflow repeatedly until success
70
72
  self.runToil(t)
@@ -75,24 +77,30 @@ class JobServiceTest(ToilTest):
75
77
  os.remove(outFile)
76
78
 
77
79
  @slow
78
- @skipIf(SingleMachineBatchSystem.numCores < 4, 'Need at least four cores to run this test')
80
+ @skipIf(
81
+ SingleMachineBatchSystem.numCores < 4,
82
+ "Need at least four cores to run this test",
83
+ )
79
84
  def testServiceDeadlock(self):
80
85
  """
81
86
  Creates a job with more services than maxServices, checks that deadlock is detected.
82
87
  """
83
88
  outFile = get_temp_file(rootDir=self._createTempDir())
84
89
  try:
90
+
85
91
  def makeWorkflow():
86
92
  job = Job()
87
93
  r1 = job.addService(ToySerializableService("woot1"))
88
94
  r2 = job.addService(ToySerializableService("woot2"))
89
95
  r3 = job.addService(ToySerializableService("woot3"))
90
- job.addChildFn(fnTest, [ r1, r2, r3 ], outFile)
96
+ job.addChildFn(fnTest, [r1, r2, r3], outFile)
91
97
  return job
92
98
 
93
99
  # This should fail as too few services available
94
100
  try:
95
- self.runToil(makeWorkflow(), badWorker=0.0, maxServiceJobs=2, deadlockWait=5)
101
+ self.runToil(
102
+ makeWorkflow(), badWorker=0.0, maxServiceJobs=2, deadlockWait=5
103
+ )
96
104
  except DeadlockException:
97
105
  print("Got expected deadlock exception")
98
106
  else:
@@ -113,7 +121,10 @@ class JobServiceTest(ToilTest):
113
121
  self.testService(checkpoint=True)
114
122
 
115
123
  @slow
116
- @skipIf(SingleMachineBatchSystem.numCores < 4, 'Need at least four cores to run this test')
124
+ @skipIf(
125
+ SingleMachineBatchSystem.numCores < 4,
126
+ "Need at least four cores to run this test",
127
+ )
117
128
  def testServiceRecursive(self, checkpoint=True):
118
129
  """
119
130
  Tests the creation of a Job.Service, creating a chain of services and accessing jobs.
@@ -122,10 +133,12 @@ class JobServiceTest(ToilTest):
122
133
  for test in range(1):
123
134
  # Temporary file
124
135
  outFile = get_temp_file(rootDir=self._createTempDir())
125
- messages = [ random.randint(1, sys.maxsize) for i in range(3) ]
136
+ messages = [random.randint(1, sys.maxsize) for i in range(3)]
126
137
  try:
127
138
  # Wire up the services/jobs
128
- t = Job.wrapJobFn(serviceTestRecursive, outFile, messages, checkpoint=checkpoint)
139
+ t = Job.wrapJobFn(
140
+ serviceTestRecursive, outFile, messages, checkpoint=checkpoint
141
+ )
129
142
 
130
143
  # Run the workflow repeatedly until success
131
144
  self.runToil(t)
@@ -136,32 +149,76 @@ class JobServiceTest(ToilTest):
136
149
  os.remove(outFile)
137
150
 
138
151
  @slow
139
- @skipIf(SingleMachineBatchSystem.numCores < 4, 'Need at least four cores to run this test')
140
- @retry_flaky_test(prepare=[ToilTest.tearDown, ToilTest.setUp])
152
+ @skipIf(
153
+ SingleMachineBatchSystem.numCores < 4,
154
+ "Need at least four cores to run this test",
155
+ )
141
156
  @pytest.mark.timeout(1200)
142
157
  def testServiceParallelRecursive(self, checkpoint=True):
143
158
  """
144
159
  Tests the creation of a Job.Service, creating parallel chains of services and accessing jobs.
145
160
  Randomly fails the worker.
146
161
  """
162
+
163
+ # This test needs to have something like 10 jobs succeed
164
+
165
+ BUNDLE_SIZE = 3
166
+ BUNDLE_COUNT = 2
167
+ RETRY_COUNT = 4
168
+ FAIL_FRACTION = 0.5
169
+ MAX_ATTEMPTS = 10
170
+
171
+ total_jobs = BUNDLE_SIZE * BUNDLE_COUNT * 2 + 1
172
+ p_complete_job_failure = FAIL_FRACTION ** (RETRY_COUNT + 1)
173
+ p_workflow_success = (1 - p_complete_job_failure) ** total_jobs
174
+ logger.info("Going to run %s total jobs, each of which completely fails %s of the time, so the workflow will succeed with probability %s", total_jobs, p_complete_job_failure, p_workflow_success)
175
+ p_test_failure = (1 - p_workflow_success) ** MAX_ATTEMPTS
176
+ logger.info("This test will fail spuriously with probability %s", p_test_failure)
177
+
178
+ # We want to run the workflow through several times to test restarting, so we need it to often fail but reliably sometimes succeed, and almost always succeed when repeated.
179
+
180
+ self.assertGreater(0.8, p_workflow_success)
181
+ self.assertGreater(p_workflow_success, 0.2)
182
+ self.assertGreater(0.001, p_test_failure)
183
+
184
+
147
185
  for test in range(1):
148
186
  # Temporary file
149
- outFiles = [get_temp_file(rootDir=self._createTempDir()) for j in range(2)]
150
- messageBundles = [ [ random.randint(1, sys.maxsize) for i in range(3) ] for j in range(2) ]
187
+ outFiles = [get_temp_file(rootDir=self._createTempDir()) for j in range(BUNDLE_COUNT)]
188
+ # We send 3 messages each in 2 sets, each of which needs a service and a client
189
+ messageBundles = [
190
+ [random.randint(1, sys.maxsize) for i in range(BUNDLE_SIZE)] for j in range(BUNDLE_COUNT)
191
+ ]
151
192
  try:
152
193
  # Wire up the services/jobs
153
- t = Job.wrapJobFn(serviceTestParallelRecursive, outFiles, messageBundles, checkpoint=True)
194
+ t = Job.wrapJobFn(
195
+ serviceTestParallelRecursive,
196
+ outFiles,
197
+ messageBundles,
198
+ checkpoint=True,
199
+ )
154
200
 
155
201
  # Run the workflow repeatedly until success
156
- self.runToil(t, retryCount=2)
202
+ self.runToil(t, retryCount=RETRY_COUNT, badWorker=FAIL_FRACTION, max_attempts=MAX_ATTEMPTS)
157
203
 
158
204
  # Check output
159
- for (messages, outFile) in zip(messageBundles, outFiles):
160
- self.assertEqual(list(map(int, open(outFile).readlines())), messages)
205
+ for messages, outFile in zip(messageBundles, outFiles):
206
+ self.assertEqual(
207
+ list(map(int, open(outFile).readlines())), messages
208
+ )
161
209
  finally:
162
210
  list(map(os.remove, outFiles))
163
211
 
164
- def runToil(self, rootJob, retryCount=1, badWorker=0.5, badWorkedFailInterval=0.1, maxServiceJobs=sys.maxsize, deadlockWait=60):
212
+ def runToil(
213
+ self,
214
+ rootJob,
215
+ retryCount=1,
216
+ badWorker=0.5,
217
+ badWorkedFailInterval=0.1,
218
+ maxServiceJobs=sys.maxsize,
219
+ deadlockWait=60,
220
+ max_attempts=50
221
+ ):
165
222
  # Create the runner for the workflow.
166
223
  options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
167
224
  options.logLevel = "DEBUG"
@@ -171,27 +228,38 @@ class JobServiceTest(ToilTest):
171
228
  options.badWorkerFailInterval = badWorkedFailInterval
172
229
  options.servicePollingInterval = 1
173
230
  options.maxServiceJobs = maxServiceJobs
174
- options.deadlockWait=deadlockWait
231
+ options.deadlockWait = deadlockWait
175
232
 
176
233
  # Run the workflow
177
- totalTrys = 0
234
+ total_tries = 1
178
235
  while True:
179
236
  try:
180
237
  Job.Runner.startToil(rootJob, options)
181
238
  break
182
239
  except FailedJobsException as e:
183
240
  i = e.numberOfFailedJobs
184
- if totalTrys > 50: #p(fail after this many restarts) = 0.5**32
185
- self.fail() #Exceeded a reasonable number of restarts
186
- totalTrys += 1
241
+ logger.info("Workflow attempt %s/%s failed with %s failed jobs", total_tries, max_attempts, i)
242
+ if total_tries == max_attempts:
243
+ self.fail() # Exceeded a reasonable number of restarts
244
+ total_tries += 1
187
245
  options.restart = True
246
+ logger.info("Succeeded after %s/%s attempts", total_tries, max_attempts)
247
+
188
248
 
189
249
  class PerfectServiceTest(JobServiceTest):
190
- def runToil(self, rootJob, retryCount=1, badWorker=0, badWorkedFailInterval=1000, maxServiceJobs=sys.maxsize, deadlockWait=60):
250
+ def runToil(
251
+ self,
252
+ *args,
253
+ **kwargs
254
+ ):
191
255
  """
192
256
  Let us run all the tests in the other service test class, but without worker failures.
193
257
  """
194
- super().runToil(rootJob, retryCount, badWorker, badWorkedFailInterval, maxServiceJobs, deadlockWait)
258
+ kwargs["badWorker"] = 0
259
+ super().runToil(
260
+ *args,
261
+ **kwargs
262
+ )
195
263
 
196
264
 
197
265
  def serviceTest(job, outFile, messageInt):
@@ -199,51 +267,76 @@ def serviceTest(job, outFile, messageInt):
199
267
  Creates one service and one accessing job, which communicate with two files to establish
200
268
  that both run concurrently.
201
269
  """
202
- #Clean out out-file
203
- open(outFile, 'w').close()
204
- randInt = random.randint(1, sys.maxsize) # We create a random number that is added to messageInt and subtracted by the serviceAccessor, to prove that
205
- # when service test is checkpointed and restarted there is never a connection made between an earlier service and later serviceAccessor, or vice versa.
206
- job.addChildJobFn(serviceAccessor, job.addService(ToyService(messageInt + randInt)), outFile, randInt)
270
+ # Clean out out-file
271
+ open(outFile, "w").close()
272
+ # We create a random number that is added to messageInt and subtracted by
273
+ # the serviceAccessor, to prove that when service test is checkpointed and
274
+ # restarted there is never a connection made between an earlier service and
275
+ # later serviceAccessor, or vice versa.
276
+ to_subtract = random.randint(
277
+ 1, sys.maxsize
278
+ )
279
+ job.addChildJobFn(
280
+ serviceAccessor,
281
+ job.addService(ToyService(messageInt + to_subtract)),
282
+ outFile,
283
+ to_subtract,
284
+ )
285
+
207
286
 
208
287
  def serviceTestRecursive(job, outFile, messages):
209
288
  """
210
289
  Creates a chain of services and accessing jobs, each paired together.
211
290
  """
212
291
  if len(messages) > 0:
213
- #Clean out out-file
214
- open(outFile, 'w').close()
215
- randInt = random.randint(1, sys.maxsize)
216
- service = ToyService(messages[0] + randInt)
217
- child = job.addChildJobFn(serviceAccessor, job.addService(service), outFile, randInt)
292
+ # Clean out out-file
293
+ open(outFile, "w").close()
294
+ to_add = random.randint(1, sys.maxsize)
295
+ service = ToyService(messages[0] + to_add)
296
+ child = job.addChildJobFn(
297
+ serviceAccessor, job.addService(service), outFile, to_add
298
+ )
218
299
 
219
300
  for i in range(1, len(messages)):
220
- randInt = random.randint(1, sys.maxsize)
221
- service2 = ToyService(messages[i] + randInt, cores=0.1)
222
- child = child.addChildJobFn(serviceAccessor,
223
- job.addService(service2, parentService=service),
224
- outFile, randInt, cores=0.1)
301
+ to_add = random.randint(1, sys.maxsize)
302
+ service2 = ToyService(messages[i] + to_add, cores=0.1)
303
+ child = child.addChildJobFn(
304
+ serviceAccessor,
305
+ job.addService(service2, parentService=service),
306
+ outFile,
307
+ to_add,
308
+ cores=0.1,
309
+ )
225
310
  service = service2
226
311
 
312
+
227
313
  def serviceTestParallelRecursive(job, outFiles, messageBundles):
228
314
  """
229
315
  Creates multiple chains of services and accessing jobs.
230
316
  """
231
317
  for messages, outFile in zip(messageBundles, outFiles):
232
- #Clean out out-file
233
- open(outFile, 'w').close()
318
+ # Clean out out-file
319
+ open(outFile, "w").close()
234
320
  if len(messages) > 0:
235
- randInt = random.randint(1, sys.maxsize)
236
- service = ToyService(messages[0] + randInt)
237
- child = job.addChildJobFn(serviceAccessor, job.addService(service), outFile, randInt)
321
+ to_add = random.randint(1, sys.maxsize)
322
+ service = ToyService(messages[0] + to_add)
323
+ child = job.addChildJobFn(
324
+ serviceAccessor, job.addService(service), outFile, to_add
325
+ )
238
326
 
239
327
  for i in range(1, len(messages)):
240
- randInt = random.randint(1, sys.maxsize)
241
- service2 = ToyService(messages[i] + randInt, cores=0.1)
242
- child = child.addChildJobFn(serviceAccessor,
243
- job.addService(service2, parentService=service),
244
- outFile, randInt, cores=0.1)
328
+ to_add = random.randint(1, sys.maxsize)
329
+ service2 = ToyService(messages[i] + to_add, cores=0.1)
330
+ child = child.addChildJobFn(
331
+ serviceAccessor,
332
+ job.addService(service2, parentService=service),
333
+ outFile,
334
+ to_add,
335
+ cores=0.1,
336
+ )
245
337
  service = service2
246
338
 
339
+
247
340
  class ToyService(Job.Service):
248
341
  def __init__(self, messageInt, *args, **kwargs):
249
342
  """
@@ -264,10 +357,17 @@ class ToyService(Job.Service):
264
357
  # So we don't associate these files with this job.
265
358
  inJobStoreID = job.fileStore.jobStore.get_empty_file_store_id()
266
359
  outJobStoreID = job.fileStore.jobStore.get_empty_file_store_id()
267
- self.serviceThread = Thread(target=self.serviceWorker,
268
- args=(job.fileStore.jobStore, self.terminate, self.error,
269
- inJobStoreID, outJobStoreID,
270
- self.messageInt))
360
+ self.serviceThread = Thread(
361
+ target=self.serviceWorker,
362
+ args=(
363
+ job.fileStore.jobStore,
364
+ self.terminate,
365
+ self.error,
366
+ inJobStoreID,
367
+ outJobStoreID,
368
+ self.messageInt,
369
+ ),
370
+ )
271
371
  self.serviceThread.start()
272
372
  return (inJobStoreID, outJobStoreID)
273
373
 
@@ -281,22 +381,27 @@ class ToyService(Job.Service):
281
381
  return True
282
382
 
283
383
  @staticmethod
284
- def serviceWorker(jobStore, terminate, error, inJobStoreID, outJobStoreID, messageInt):
384
+ def serviceWorker(
385
+ jobStore, terminate, error, inJobStoreID, outJobStoreID, messageInt
386
+ ):
285
387
  try:
286
388
  while True:
287
- if terminate.isSet(): # Quit if we've got the terminate signal
389
+ if terminate.isSet(): # Quit if we've got the terminate signal
288
390
  logger.debug("Service worker being told to quit")
289
391
  return
290
392
 
291
- time.sleep(0.2) # Sleep to avoid thrashing
393
+ time.sleep(0.2) # Sleep to avoid thrashing
292
394
 
293
395
  # Try reading a line from the input file
294
396
  try:
295
397
  with jobStore.read_file_stream(inJobStoreID) as f:
296
- f = codecs.getreader('utf-8')(f)
398
+ f = codecs.getreader("utf-8")(f)
297
399
  line = f.readline()
298
400
  except:
299
- logger.debug("Something went wrong reading a line: %s", traceback.format_exc())
401
+ logger.debug(
402
+ "Something went wrong reading a line: %s",
403
+ traceback.format_exc(),
404
+ )
300
405
  raise
301
406
 
302
407
  if len(line.strip()) == 0:
@@ -307,7 +412,11 @@ class ToyService(Job.Service):
307
412
  try:
308
413
  inputInt = int(line)
309
414
  except ValueError:
310
- logger.debug("Tried casting input line '%s' to integer but got error: %s", line, traceback.format_exc())
415
+ logger.debug(
416
+ "Tried casting input line '%s' to integer but got error: %s",
417
+ line,
418
+ traceback.format_exc(),
419
+ )
311
420
  continue
312
421
 
313
422
  # Write out the resulting read integer and the message
@@ -318,28 +427,29 @@ class ToyService(Job.Service):
318
427
  error.set()
319
428
  raise
320
429
 
321
- def serviceAccessor(job, communicationFiles, outFile, randInt):
430
+
431
+ def serviceAccessor(job, communicationFiles, outFile, to_subtract):
322
432
  """
323
433
  Writes a random integer iinto the inJobStoreFileID file, then tries 10 times reading
324
434
  from outJobStoreFileID to get a pair of integers, the first equal to i the second written into the outputFile.
325
435
  """
326
436
  inJobStoreFileID, outJobStoreFileID = communicationFiles
327
437
 
328
- # Get a random integer
438
+ # Get a random integer to advertise ourselves
329
439
  key = random.randint(1, sys.maxsize)
330
440
 
331
441
  # Write the integer into the file
332
442
  logger.debug("Writing key to inJobStoreFileID")
333
443
  with job.fileStore.jobStore.update_file_stream(inJobStoreFileID) as fH:
334
- fH.write(("%s\n" % key).encode('utf-8'))
444
+ fH.write(("%s\n" % key).encode("utf-8"))
335
445
 
336
446
  logger.debug("Trying to read key and message from outJobStoreFileID")
337
- for i in range(10): # Try 10 times over
338
- time.sleep(0.2) #Avoid thrashing
447
+ for i in range(10): # Try 10 times over
448
+ time.sleep(0.2) # Avoid thrashing
339
449
 
340
450
  # Try reading an integer from the input file and writing out the message
341
451
  with job.fileStore.jobStore.read_file_stream(outJobStoreFileID) as fH:
342
- fH = codecs.getreader('utf-8')(fH)
452
+ fH = codecs.getreader("utf-8")(fH)
343
453
  line = fH.readline()
344
454
 
345
455
  tokens = line.split()
@@ -349,12 +459,15 @@ def serviceAccessor(job, communicationFiles, outFile, randInt):
349
459
  key2, message = tokens
350
460
 
351
461
  if int(key2) == key:
352
- logger.debug(f"Matched key's: {key}, writing message: {int(message) - randInt} with randInt: {randInt}")
353
- with open(outFile, 'a') as fH:
354
- fH.write("%s\n" % (int(message) - randInt))
462
+ logger.debug(
463
+ f"Matched key's: {key}, writing message: {int(message) - to_subtract} with to_subtract: {to_subtract}"
464
+ )
465
+ with open(outFile, "a") as fH:
466
+ fH.write("%s\n" % (int(message) - to_subtract))
355
467
  return
356
468
 
357
- assert 0 # Job failed to get info from the service
469
+ assert 0 # Job failed to get info from the service
470
+
358
471
 
359
472
  class ToySerializableService(Job.Service):
360
473
  def __init__(self, messageInt, *args, **kwargs):
@@ -373,9 +486,10 @@ class ToySerializableService(Job.Service):
373
486
  def check(self):
374
487
  return True
375
488
 
489
+
376
490
  def fnTest(strings, outputFile):
377
491
  """
378
492
  Function concatenates the strings together and writes them to the output file
379
493
  """
380
- with open(outputFile, 'w') as fH:
494
+ with open(outputFile, "w") as fH:
381
495
  fH.write(" ".join(strings))