vortex-nwp 2.0.0b1__py3-none-any.whl → 2.1.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 (141) hide show
  1. vortex/__init__.py +75 -47
  2. vortex/algo/__init__.py +3 -2
  3. vortex/algo/components.py +944 -618
  4. vortex/algo/mpitools.py +802 -497
  5. vortex/algo/mpitools_templates/__init__.py +1 -0
  6. vortex/algo/serversynctools.py +34 -33
  7. vortex/config.py +19 -22
  8. vortex/data/__init__.py +9 -3
  9. vortex/data/abstractstores.py +593 -655
  10. vortex/data/containers.py +217 -162
  11. vortex/data/contents.py +65 -39
  12. vortex/data/executables.py +93 -102
  13. vortex/data/flow.py +40 -34
  14. vortex/data/geometries.py +228 -132
  15. vortex/data/handlers.py +436 -227
  16. vortex/data/outflow.py +15 -15
  17. vortex/data/providers.py +185 -163
  18. vortex/data/resources.py +48 -42
  19. vortex/data/stores.py +540 -417
  20. vortex/data/sync_templates/__init__.py +0 -0
  21. vortex/gloves.py +114 -87
  22. vortex/layout/__init__.py +1 -8
  23. vortex/layout/contexts.py +150 -84
  24. vortex/layout/dataflow.py +353 -202
  25. vortex/layout/monitor.py +264 -128
  26. vortex/nwp/__init__.py +5 -2
  27. vortex/nwp/algo/__init__.py +14 -5
  28. vortex/nwp/algo/assim.py +205 -151
  29. vortex/nwp/algo/clim.py +683 -517
  30. vortex/nwp/algo/coupling.py +447 -225
  31. vortex/nwp/algo/eda.py +437 -229
  32. vortex/nwp/algo/eps.py +403 -231
  33. vortex/nwp/algo/forecasts.py +416 -275
  34. vortex/nwp/algo/fpserver.py +683 -307
  35. vortex/nwp/algo/ifsnaming.py +205 -145
  36. vortex/nwp/algo/ifsroot.py +215 -122
  37. vortex/nwp/algo/monitoring.py +137 -76
  38. vortex/nwp/algo/mpitools.py +330 -190
  39. vortex/nwp/algo/odbtools.py +637 -353
  40. vortex/nwp/algo/oopsroot.py +454 -273
  41. vortex/nwp/algo/oopstests.py +90 -56
  42. vortex/nwp/algo/request.py +287 -206
  43. vortex/nwp/algo/stdpost.py +878 -522
  44. vortex/nwp/data/__init__.py +22 -4
  45. vortex/nwp/data/assim.py +125 -137
  46. vortex/nwp/data/boundaries.py +121 -68
  47. vortex/nwp/data/climfiles.py +193 -211
  48. vortex/nwp/data/configfiles.py +73 -69
  49. vortex/nwp/data/consts.py +426 -401
  50. vortex/nwp/data/ctpini.py +59 -43
  51. vortex/nwp/data/diagnostics.py +94 -66
  52. vortex/nwp/data/eda.py +50 -51
  53. vortex/nwp/data/eps.py +195 -146
  54. vortex/nwp/data/executables.py +440 -434
  55. vortex/nwp/data/fields.py +63 -48
  56. vortex/nwp/data/gridfiles.py +183 -111
  57. vortex/nwp/data/logs.py +250 -217
  58. vortex/nwp/data/modelstates.py +180 -151
  59. vortex/nwp/data/monitoring.py +72 -99
  60. vortex/nwp/data/namelists.py +254 -202
  61. vortex/nwp/data/obs.py +400 -308
  62. vortex/nwp/data/oopsexec.py +22 -20
  63. vortex/nwp/data/providers.py +90 -65
  64. vortex/nwp/data/query.py +71 -82
  65. vortex/nwp/data/stores.py +49 -36
  66. vortex/nwp/data/surfex.py +136 -137
  67. vortex/nwp/syntax/__init__.py +1 -1
  68. vortex/nwp/syntax/stdattrs.py +173 -111
  69. vortex/nwp/tools/__init__.py +2 -2
  70. vortex/nwp/tools/addons.py +22 -17
  71. vortex/nwp/tools/agt.py +24 -12
  72. vortex/nwp/tools/bdap.py +16 -5
  73. vortex/nwp/tools/bdcp.py +4 -1
  74. vortex/nwp/tools/bdm.py +3 -0
  75. vortex/nwp/tools/bdmp.py +14 -9
  76. vortex/nwp/tools/conftools.py +728 -378
  77. vortex/nwp/tools/drhook.py +12 -8
  78. vortex/nwp/tools/grib.py +65 -39
  79. vortex/nwp/tools/gribdiff.py +22 -17
  80. vortex/nwp/tools/ifstools.py +82 -42
  81. vortex/nwp/tools/igastuff.py +167 -143
  82. vortex/nwp/tools/mars.py +14 -2
  83. vortex/nwp/tools/odb.py +234 -125
  84. vortex/nwp/tools/partitioning.py +61 -37
  85. vortex/nwp/tools/satrad.py +27 -12
  86. vortex/nwp/util/async.py +83 -55
  87. vortex/nwp/util/beacon.py +10 -10
  88. vortex/nwp/util/diffpygram.py +174 -86
  89. vortex/nwp/util/ens.py +144 -63
  90. vortex/nwp/util/hooks.py +30 -19
  91. vortex/nwp/util/taskdeco.py +28 -24
  92. vortex/nwp/util/usepygram.py +278 -172
  93. vortex/nwp/util/usetnt.py +31 -17
  94. vortex/sessions.py +72 -39
  95. vortex/syntax/__init__.py +1 -1
  96. vortex/syntax/stdattrs.py +410 -171
  97. vortex/syntax/stddeco.py +31 -22
  98. vortex/toolbox.py +327 -192
  99. vortex/tools/__init__.py +11 -2
  100. vortex/tools/actions.py +110 -121
  101. vortex/tools/addons.py +111 -92
  102. vortex/tools/arm.py +42 -22
  103. vortex/tools/compression.py +72 -69
  104. vortex/tools/date.py +11 -4
  105. vortex/tools/delayedactions.py +242 -132
  106. vortex/tools/env.py +75 -47
  107. vortex/tools/folder.py +342 -171
  108. vortex/tools/grib.py +341 -162
  109. vortex/tools/lfi.py +423 -216
  110. vortex/tools/listings.py +109 -40
  111. vortex/tools/names.py +218 -156
  112. vortex/tools/net.py +655 -299
  113. vortex/tools/parallelism.py +93 -61
  114. vortex/tools/prestaging.py +55 -31
  115. vortex/tools/schedulers.py +172 -105
  116. vortex/tools/services.py +403 -334
  117. vortex/tools/storage.py +293 -358
  118. vortex/tools/surfex.py +24 -24
  119. vortex/tools/systems.py +1234 -643
  120. vortex/tools/targets.py +156 -100
  121. vortex/util/__init__.py +1 -1
  122. vortex/util/config.py +378 -327
  123. vortex/util/empty.py +2 -2
  124. vortex/util/helpers.py +56 -24
  125. vortex/util/introspection.py +18 -12
  126. vortex/util/iosponge.py +8 -4
  127. vortex/util/roles.py +4 -6
  128. vortex/util/storefunctions.py +39 -13
  129. vortex/util/structs.py +3 -3
  130. vortex/util/worker.py +29 -17
  131. vortex_nwp-2.1.0.dist-info/METADATA +67 -0
  132. vortex_nwp-2.1.0.dist-info/RECORD +144 -0
  133. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/WHEEL +1 -1
  134. vortex/layout/appconf.py +0 -109
  135. vortex/layout/jobs.py +0 -1276
  136. vortex/layout/nodes.py +0 -1424
  137. vortex/layout/subjobs.py +0 -464
  138. vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
  139. vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
  140. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info/licenses}/LICENSE +0 -0
  141. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/top_level.txt +0 -0
@@ -74,14 +74,17 @@ __all__ = []
74
74
  logger = loggers.getLogger(__name__)
75
75
 
76
76
  #: Definition of a named tuple DelayedActionStatusTuple
77
- DelayedActionStatusTuple = namedtuple('DelayedActionStatusTuple',
78
- ['void', 'failed', 'done', 'unclear'])
77
+ DelayedActionStatusTuple = namedtuple(
78
+ "DelayedActionStatusTuple", ["void", "failed", "done", "unclear"]
79
+ )
79
80
 
80
81
  #: Predefined DelayedActionStatus values (void=Not ready yet,
81
82
  # failed=processed but KO,
82
83
  # done=processed and OK,
83
84
  # unclear=processed but cannot tell whether it is KO or OK)
84
- d_action_status = DelayedActionStatusTuple(void=0, failed=-1, done=1, unclear=-2)
85
+ d_action_status = DelayedActionStatusTuple(
86
+ void=0, failed=-1, done=1, unclear=-2
87
+ )
85
88
 
86
89
 
87
90
  # Module Interface
@@ -120,8 +123,10 @@ class DelayedAction:
120
123
  def _set_status(self, value):
121
124
  oldres = self.statustext
122
125
  self._status = value
123
- self._obsboard.notify_upd(self, info=dict(changed='status', queryproxy='statustext',
124
- prev=oldres))
126
+ self._obsboard.notify_upd(
127
+ self,
128
+ info=dict(changed="status", queryproxy="statustext", prev=oldres),
129
+ )
125
130
 
126
131
  @property
127
132
  def status(self):
@@ -134,10 +139,15 @@ class DelayedAction:
134
139
  def _set_result(self, result):
135
140
  oldres = self._result
136
141
  self._result = result
137
- self._obsboard.notify_upd(self, info=dict(changed='result', prev=oldres))
142
+ self._obsboard.notify_upd(
143
+ self, info=dict(changed="result", prev=oldres)
144
+ )
138
145
 
139
- result = property(_get_result, _set_result,
140
- doc="Where to find the delayed action result.")
146
+ result = property(
147
+ _get_result,
148
+ _set_result,
149
+ doc="Where to find the delayed action result.",
150
+ )
141
151
 
142
152
  @property
143
153
  def statustext(self):
@@ -145,51 +155,55 @@ class DelayedAction:
145
155
  for k, v in d_action_status._asdict().items():
146
156
  if self._status == v:
147
157
  return k
148
- logger.warning('What is this idiotic status (%s) ???', self.status)
158
+ logger.warning("What is this idiotic status (%s) ???", self.status)
149
159
  return str(self.status)
150
160
 
151
161
  def mark_as_failed(self):
152
162
  """Change the status to ``failed``."""
153
- logger.info('Marking early-get %s as failed (request=%s)',
154
- self.id, self.request)
163
+ logger.info(
164
+ "Marking early-get %s as failed (request=%s)",
165
+ self.id,
166
+ self.request,
167
+ )
155
168
  self._set_status(d_action_status.failed)
156
169
 
157
170
  def mark_as_done(self):
158
171
  """Change the status to ``done``."""
159
- logger.debug('Marking early-get %s as done (request=%s)',
160
- self.id, self.request)
172
+ logger.debug(
173
+ "Marking early-get %s as done (request=%s)", self.id, self.request
174
+ )
161
175
  self._set_status(d_action_status.done)
162
176
 
163
177
  def mark_as_unclear(self):
164
178
  """Change the status to ``unclear``."""
165
- logger.info('Marking early-get %s as unclear/unconclusive (request=%s)',
166
- self.id, self.request)
179
+ logger.info(
180
+ "Marking early-get %s as unclear/unconclusive (request=%s)",
181
+ self.id,
182
+ self.request,
183
+ )
167
184
  self._set_status(d_action_status.unclear)
168
185
 
169
186
  def __str__(self):
170
- return 'id={0._id}: {0.statustext:6s} result={0.result!s}'.format(self)
187
+ return "id={0._id}: {0.statustext:6s} result={0.result!s}".format(self)
171
188
 
172
189
 
173
- class AbstractDelayedActionsHandler(footprints.FootprintBase, observer.Observer):
190
+ class AbstractDelayedActionsHandler(
191
+ footprints.FootprintBase, observer.Observer
192
+ ):
174
193
  """Abstract class that handles a bunch of similar delayed actions."""
175
194
 
176
195
  _abstract = True
177
- _collector = ('delayedactionshandler',)
196
+ _collector = ("delayedactionshandler",)
178
197
  _footprint = dict(
179
- info = "Abstract class that deal with delayed actions.",
180
- attr = dict(
181
- system = dict(
182
- info = "The current system object",
183
- type = OSExtended
184
- ),
185
- observerboard = dict(
186
- info = 'The observer board where delayed actions updates are published.',
187
- type = observer.SecludedObserverBoard,
188
- ),
189
- stagedir = dict(
190
- info = "The temporary directory (if need be)"
198
+ info="Abstract class that deal with delayed actions.",
199
+ attr=dict(
200
+ system=dict(info="The current system object", type=OSExtended),
201
+ observerboard=dict(
202
+ info="The observer board where delayed actions updates are published.",
203
+ type=observer.SecludedObserverBoard,
191
204
  ),
192
- )
205
+ stagedir=dict(info="The temporary directory (if need be)"),
206
+ ),
193
207
  )
194
208
 
195
209
  def __init__(self, *args, **kw):
@@ -211,17 +225,22 @@ class AbstractDelayedActionsHandler(footprints.FootprintBase, observer.Observer)
211
225
  def newobsitem(self, item, info): # @UnusedVariable
212
226
  """To get informed when a new :class:`DelayedAction` object is created."""
213
227
  if item.id in self._resultsmap:
214
- self._history.append('NEW ', 'id={0.id!s}: request={0.request!s}'.format(item))
228
+ self._history.append(
229
+ "NEW ", "id={0.id!s}: request={0.request!s}".format(item)
230
+ )
215
231
 
216
232
  def updobsitem(self, item, info):
217
233
  """To get informed when a new :class:`DelayedAction` object is updates."""
218
234
  if item.id in self._resultsmap:
219
- what = info['changed']
220
- newval = getattr(item, info.get('queryproxy', what))
221
- oldval = info['prev']
222
- self._history.append('UPD ',
223
- 'id={0.id!s}: {1:s}={2!s} (instead of: {3!s})'
224
- .format(item, what, newval, oldval))
235
+ what = info["changed"]
236
+ newval = getattr(item, info.get("queryproxy", what))
237
+ oldval = info["prev"]
238
+ self._history.append(
239
+ "UPD ",
240
+ "id={0.id!s}: {1:s}={2!s} (instead of: {3!s})".format(
241
+ item, what, newval, oldval
242
+ ),
243
+ )
225
244
 
226
245
  @property
227
246
  def history(self):
@@ -230,11 +249,11 @@ class AbstractDelayedActionsHandler(footprints.FootprintBase, observer.Observer)
230
249
 
231
250
  def grephistory(self, r_id):
232
251
  """Return the log lines matching the **r_id** delayed action ID."""
233
- return self.history.grep('id={!s}'.format(r_id))
252
+ return self.history.grep("id={!s}".format(r_id))
234
253
 
235
254
  def showhistory(self, r_id):
236
255
  """Print the log lines matching the **r_id** delayed action ID."""
237
- return self.history.showgrep('id={!s}'.format(r_id))
256
+ return self.history.showgrep("id={!s}".format(r_id))
238
257
 
239
258
  def __contains__(self, r_id):
240
259
  return r_id in self._resultsmap
@@ -263,7 +282,12 @@ class AbstractDelayedActionsHandler(footprints.FootprintBase, observer.Observer)
263
282
  @property
264
283
  def dirty(self):
265
284
  """Is there any of the object's delayed actions that needs finalising ?"""
266
- return any([a.status == d_action_status.void for a in self._resultsmap.values()])
285
+ return any(
286
+ [
287
+ a.status == d_action_status.void
288
+ for a in self._resultsmap.values()
289
+ ]
290
+ )
267
291
 
268
292
  def finalise(self, *r_ids):
269
293
  """Given a **r_ids** list of delayed action IDs, wait upon actions completion."""
@@ -278,10 +302,12 @@ class AbstractDelayedActionsHandler(footprints.FootprintBase, observer.Observer)
278
302
  try:
279
303
  if action.status == d_action_status.void:
280
304
  self.finalise(r_id)
281
- assert action.status != d_action_status.void, 'Finalise does not seem to work.'
305
+ assert action.status != d_action_status.void, (
306
+ "Finalise does not seem to work."
307
+ )
282
308
  finally:
283
309
  del self._resultsmap[r_id]
284
- self._history.append('USED', 'id={!s}'.format(action.id))
310
+ self._history.append("USED", "id={!s}".format(action.id))
285
311
  if bareobject:
286
312
  return action
287
313
  else:
@@ -295,26 +321,46 @@ class AbstractDelayedActionsHandler(footprints.FootprintBase, observer.Observer)
295
321
 
296
322
  def describe(self, fulldump=False):
297
323
  """Print the object's characteristics and content."""
298
- res = 'DelayedActionsHandler object of class: {:s}\n'.format(self.__class__)
324
+ res = "DelayedActionsHandler object of class: {:s}\n".format(
325
+ self.__class__
326
+ )
299
327
  for k, v in self.footprint_as_shallow_dict().items():
300
- res += ' * {:s}: {!s}\n'.format(k, v)
328
+ res += " * {:s}: {!s}\n".format(k, v)
301
329
  if fulldump:
302
- res += '\n * Todo list (i.e still to be processed):\n\n'
303
- res += '\n'.join(['{:48s}:\n request: {!s}'.format(r_id, a.request)
304
- for r_id, a in self._resultsmap.items()
305
- if a.status == d_action_status.void])
306
- res += '\n * Done (i.e the delayed action succeeded):\n\n'
307
- res += '\n'.join(['{:48s}:\n request: {!s}'.format(r_id, a.request)
308
- for r_id, a in self._resultsmap.items()
309
- if a.status == d_action_status.done])
310
- res += '\n * Failed (i.e the delayed action failed):\n\n'
311
- res += '\n'.join(['{:48s}:\n request: {!s}'.format(r_id, a.request)
312
- for r_id, a in self._resultsmap.items()
313
- if a.status == d_action_status.failed])
314
- res += '\n * Unclear (i.e processed but the result is unclear):\n\n'
315
- res += '\n'.join(['{:48s}:\n request: {!s}'.format(r_id, a.request)
316
- for r_id, a in self._resultsmap.items()
317
- if a.status == d_action_status.unclear])
330
+ res += "\n * Todo list (i.e still to be processed):\n\n"
331
+ res += "\n".join(
332
+ [
333
+ "{:48s}:\n request: {!s}".format(r_id, a.request)
334
+ for r_id, a in self._resultsmap.items()
335
+ if a.status == d_action_status.void
336
+ ]
337
+ )
338
+ res += "\n * Done (i.e the delayed action succeeded):\n\n"
339
+ res += "\n".join(
340
+ [
341
+ "{:48s}:\n request: {!s}".format(r_id, a.request)
342
+ for r_id, a in self._resultsmap.items()
343
+ if a.status == d_action_status.done
344
+ ]
345
+ )
346
+ res += "\n * Failed (i.e the delayed action failed):\n\n"
347
+ res += "\n".join(
348
+ [
349
+ "{:48s}:\n request: {!s}".format(r_id, a.request)
350
+ for r_id, a in self._resultsmap.items()
351
+ if a.status == d_action_status.failed
352
+ ]
353
+ )
354
+ res += (
355
+ "\n * Unclear (i.e processed but the result is unclear):\n\n"
356
+ )
357
+ res += "\n".join(
358
+ [
359
+ "{:48s}:\n request: {!s}".format(r_id, a.request)
360
+ for r_id, a in self._resultsmap.items()
361
+ if a.status == d_action_status.unclear
362
+ ]
363
+ )
318
364
  return res
319
365
 
320
366
 
@@ -334,9 +380,12 @@ class AbstractFileBasedDelayedActionsHandler(AbstractDelayedActionsHandler):
334
380
 
335
381
  def dispence_resultid(self):
336
382
  """Return a unique ID that will identify a new :class:`DelayedAction` object."""
337
- t_temp = tempfile.mkstemp(prefix='{:s}_{:d}'.format(self.resultid_stamp,
338
- self.system.getpid()),
339
- dir=self.stagedir)
383
+ t_temp = tempfile.mkstemp(
384
+ prefix="{:s}_{:d}".format(
385
+ self.resultid_stamp, self.system.getpid()
386
+ ),
387
+ dir=self.stagedir,
388
+ )
340
389
  os.close(t_temp[0])
341
390
  return self.system.path.basename(t_temp[1])
342
391
 
@@ -356,18 +405,20 @@ class DemoSleepDelayedActionHandler(AbstractDelayedActionsHandler):
356
405
  """A Sleeper delayed action handler (Demonstration purposes)."""
357
406
 
358
407
  _footprint = dict(
359
- info = "Demonstration purposes (sleep for a while).",
360
- attr = dict(
361
- kind = dict(
362
- values = ['sleep', ],
408
+ info="Demonstration purposes (sleep for a while).",
409
+ attr=dict(
410
+ kind=dict(
411
+ values=[
412
+ "sleep",
413
+ ],
363
414
  ),
364
- )
415
+ ),
365
416
  )
366
417
 
367
418
  def dispence_resultid(self):
368
419
  """Return a unique ID that will identify a new :class:`DelayedAction` object."""
369
420
  self._counter += 1
370
- return 'sleeper_action_{:016d}'.format(self._counter)
421
+ return "sleeper_action_{:016d}".format(self._counter)
371
422
 
372
423
  def _custom_init(self):
373
424
  """Create the multiprocessing pool."""
@@ -384,7 +435,9 @@ class DemoSleepDelayedActionHandler(AbstractDelayedActionsHandler):
384
435
  def _create_delayed_action(self, r_id, request):
385
436
  """Start the asynchronous processing."""
386
437
  daction = DelayedAction(self.observerboard, r_id, request)
387
- daction.result = self._ppool.apply_async(demo_sleeper_function, (request, ))
438
+ daction.result = self._ppool.apply_async(
439
+ demo_sleeper_function, (request,)
440
+ )
388
441
  return daction
389
442
 
390
443
  def finalise(self, *r_ids):
@@ -398,44 +451,52 @@ class DemoSleepDelayedActionHandler(AbstractDelayedActionsHandler):
398
451
  action.mark_as_failed()
399
452
 
400
453
 
401
- class AbstractFtpArchiveDelayedGetHandler(AbstractFileBasedDelayedActionsHandler):
454
+ class AbstractFtpArchiveDelayedGetHandler(
455
+ AbstractFileBasedDelayedActionsHandler
456
+ ):
402
457
  """Includes some FTP related methods"""
403
458
 
404
459
  _abstract = True
405
460
  _footprint = dict(
406
- info = "Fetch multiple files using an FTP archive.",
407
- attr = dict(
408
- kind = dict(
409
- values = ['archive', ],
461
+ info="Fetch multiple files using an FTP archive.",
462
+ attr=dict(
463
+ kind=dict(
464
+ values=[
465
+ "archive",
466
+ ],
410
467
  ),
411
- storage = dict(
468
+ storage=dict(),
469
+ goal=dict(
470
+ values=[
471
+ "get",
472
+ ]
412
473
  ),
413
- goal = dict(
414
- values = ['get', ]
474
+ tube=dict(
475
+ values=[
476
+ "ftp",
477
+ ],
415
478
  ),
416
- tube = dict(
417
- values = ['ftp', ],
479
+ raw=dict(
480
+ type=bool,
481
+ optional=True,
482
+ default=False,
418
483
  ),
419
- raw = dict(
420
- type = bool,
421
- optional = True,
422
- default = False,
423
- ),
424
- logname = dict(
425
- optional = True
426
- )
427
- )
484
+ logname=dict(optional=True),
485
+ ),
428
486
  )
429
487
 
430
488
  @property
431
489
  def resultid_stamp(self):
432
- bangfmt = '{0.logname:s}@{0.storage:s}' if self.logname else '{0.storage:s}'
433
- return ('rawftget_' + bangfmt).format(self)
490
+ bangfmt = (
491
+ "{0.logname:s}@{0.storage:s}" if self.logname else "{0.storage:s}"
492
+ )
493
+ return ("rawftget_" + bangfmt).format(self)
434
494
 
435
495
  def register(self, request):
436
496
  """Create a new :class:`DelayedAction` object from a user's **request**."""
437
- assert isinstance(request, (tuple, list)) and len(request) == 2, \
438
- 'Request needs to be a two element tuple or list (location, format)'
497
+ assert isinstance(request, (tuple, list)) and len(request) == 2, (
498
+ "Request needs to be a two element tuple or list (location, format)"
499
+ )
439
500
  # Check for duplicated entries...
440
501
  target = request[0]
441
502
  for v in self._resultsmap.values():
@@ -447,14 +508,16 @@ class AbstractFtpArchiveDelayedGetHandler(AbstractFileBasedDelayedActionsHandler
447
508
  @property
448
509
  def _ftp_hostinfos(self):
449
510
  """Return the FTP hostname end port number."""
450
- s_storage = self.storage.split(':', 1)
511
+ s_storage = self.storage.split(":", 1)
451
512
  hostname = s_storage[0]
452
513
  port = None
453
514
  if len(s_storage) > 1:
454
515
  try:
455
516
  port = int(s_storage[1])
456
517
  except ValueError:
457
- logger.error('Invalid port number < %s >. Ignoring it', s_storage[1])
518
+ logger.error(
519
+ "Invalid port number < %s >. Ignoring it", s_storage[1]
520
+ )
458
521
  return hostname, port
459
522
 
460
523
 
@@ -471,13 +534,15 @@ class RawFtpDelayedGetHandler(AbstractFtpArchiveDelayedGetHandler):
471
534
  """
472
535
 
473
536
  _footprint = dict(
474
- info = "Fetch multiple files using FtServ.",
475
- attr = dict(
476
- raw = dict(
477
- optional = False,
478
- values = [True, ],
537
+ info="Fetch multiple files using FtServ.",
538
+ attr=dict(
539
+ raw=dict(
540
+ optional=False,
541
+ values=[
542
+ True,
543
+ ],
479
544
  ),
480
- )
545
+ ),
481
546
  )
482
547
 
483
548
  def finalise(self, *r_ids): # @UnusedVariable
@@ -485,9 +550,13 @@ class RawFtpDelayedGetHandler(AbstractFtpArchiveDelayedGetHandler):
485
550
  todo = defaultdict(list)
486
551
  for k, v in self._resultsmap.items():
487
552
  if v.status == d_action_status.void:
488
- a_fmt = (v.request[1]
489
- if self.system.fmtspecific_mtd('batchrawftget', v.request[1])
490
- else None)
553
+ a_fmt = (
554
+ v.request[1]
555
+ if self.system.fmtspecific_mtd(
556
+ "batchrawftget", v.request[1]
557
+ )
558
+ else None
559
+ )
491
560
  todo[a_fmt].append(k)
492
561
  rc = True
493
562
  if todo:
@@ -496,18 +565,27 @@ class RawFtpDelayedGetHandler(AbstractFtpArchiveDelayedGetHandler):
496
565
  destinations = list()
497
566
  extras = dict()
498
567
  if a_fmt is not None:
499
- extras['fmt'] = a_fmt
568
+ extras["fmt"] = a_fmt
500
569
  for k in a_todolist:
501
570
  sources.append(self._resultsmap[k].request[0])
502
571
  destinations.append(self._resultsmap[k].result)
503
572
  try:
504
- logger.info('Running the ftserv command for format=%s.', str(a_fmt))
573
+ logger.info(
574
+ "Running the ftserv command for format=%s.", str(a_fmt)
575
+ )
505
576
  hostname, port = self._ftp_hostinfos
506
- rc = self.system.batchrawftget(sources, destinations,
507
- hostname=hostname, logname=self.logname, port=port,
508
- ** extras)
577
+ rc = self.system.batchrawftget(
578
+ sources,
579
+ destinations,
580
+ hostname=hostname,
581
+ logname=self.logname,
582
+ port=port,
583
+ **extras,
584
+ )
509
585
  except OSError:
510
- rc = [None, ] * len(sources)
586
+ rc = [
587
+ None,
588
+ ] * len(sources)
511
589
  for i, k in enumerate(a_todolist):
512
590
  if rc[i] is True:
513
591
  self._resultsmap[k].mark_as_done()
@@ -556,9 +634,14 @@ class PrivateDelayedActionsHub:
556
634
  def stagedir(self):
557
635
  """This Hub staging area/directory (i.e. where results can be stored)."""
558
636
  if self._stagedir is None:
559
- self._stagedir = tempfile.mkdtemp(prefix='dactions_staging_area_',
560
- dir=(self._contextrundir
561
- if self._contextrundir else self._sh.pwd()))
637
+ self._stagedir = tempfile.mkdtemp(
638
+ prefix="dactions_staging_area_",
639
+ dir=(
640
+ self._contextrundir
641
+ if self._contextrundir
642
+ else self._sh.pwd()
643
+ ),
644
+ )
562
645
  return self._stagedir
563
646
 
564
647
  def showhistory(self):
@@ -567,7 +650,7 @@ class PrivateDelayedActionsHub:
567
650
  objects leveraged by this Hub.
568
651
  """
569
652
  for handler in self._delayedactionshandlers:
570
- print('{!r} says:\n'.format(handler))
653
+ print("{!r} says:\n".format(handler))
571
654
  handler.history.show()
572
655
 
573
656
  def actionhistory(self, r_id):
@@ -575,7 +658,7 @@ class PrivateDelayedActionsHub:
575
658
  for handler in self._delayedactionshandlers:
576
659
  hst = handler.grephistory(r_id)
577
660
  if hst:
578
- print('{!r} says:'.format(handler))
661
+ print("{!r} says:".format(handler))
579
662
  handler.showhistory(r_id)
580
663
 
581
664
  def register(self, request, **kwargs):
@@ -586,25 +669,41 @@ class PrivateDelayedActionsHub:
586
669
  :class:`AbstractDelayedActionsHandler` object
587
670
  """
588
671
  # Prestaging tool descriptions
589
- myhandler_desc = dict(system=self._sh, observerboard=self._obsboard,
590
- stagedir=self.stagedir)
672
+ myhandler_desc = dict(
673
+ system=self._sh,
674
+ observerboard=self._obsboard,
675
+ stagedir=self.stagedir,
676
+ )
591
677
  myhandler_desc.update(kwargs)
592
678
  myhandler = None
593
679
  # Scan pre-existing prestaging tools to find a suitable one
594
680
  for ahandler in self._delayedactionshandlers:
595
- if ahandler.footprint_reusable() and ahandler.footprint_compatible(myhandler_desc):
596
- logger.debug("Re-usable Actions Handler found: %s", lightdump(myhandler_desc))
681
+ if ahandler.footprint_reusable() and ahandler.footprint_compatible(
682
+ myhandler_desc
683
+ ):
684
+ logger.debug(
685
+ "Re-usable Actions Handler found: %s",
686
+ lightdump(myhandler_desc),
687
+ )
597
688
  myhandler = ahandler
598
689
  break
599
690
  # If necessary, create a new one
600
691
  if myhandler is None:
601
- myhandler = fpx.delayedactionshandler(_emptywarning=False, **myhandler_desc)
692
+ myhandler = fpx.delayedactionshandler(
693
+ _emptywarning=False, **myhandler_desc
694
+ )
602
695
  if myhandler is not None:
603
- logger.debug("Fresh prestaging tool created: %s", lightdump(myhandler_desc))
696
+ logger.debug(
697
+ "Fresh prestaging tool created: %s",
698
+ lightdump(myhandler_desc),
699
+ )
604
700
  self._delayedactionshandlers.add(myhandler)
605
701
  # Let's role
606
702
  if myhandler is None:
607
- logger.debug("Unable to find a delayed actions handler with: %s", lightdump(myhandler_desc))
703
+ logger.debug(
704
+ "Unable to find a delayed actions handler with: %s",
705
+ lightdump(myhandler_desc),
706
+ )
608
707
  return None
609
708
  else:
610
709
  resultid = myhandler.register(request)
@@ -626,12 +725,14 @@ class PrivateDelayedActionsHub:
626
725
  for r_id in r_ids:
627
726
  todo[self._resultsmap[r_id]].add(r_id)
628
727
  for ahandler, r_ids in todo.items():
629
- ahandler.finalise(* list(r_ids))
728
+ ahandler.finalise(*list(r_ids))
630
729
 
631
730
  def retrieve(self, resultid, bareobject=False):
632
731
  """Given a **resultid** delayed action ID, returns the corresponding result."""
633
732
  try:
634
- res = self._resultsmap[resultid].retrieve(resultid, bareobject=bareobject)
733
+ res = self._resultsmap[resultid].retrieve(
734
+ resultid, bareobject=bareobject
735
+ )
635
736
  finally:
636
737
  del self._resultsmap[resultid]
637
738
  return res
@@ -646,14 +747,21 @@ class PrivateDelayedActionsHub:
646
747
  self._stagedir = None
647
748
 
648
749
  def __repr__(self):
649
- return ('{:s} | n_delayedactionshandlers={:d}>'
650
- .format(super().__repr__().rstrip('>'),
651
- len(self._delayedactionshandlers)))
750
+ return "{:s} | n_delayedactionshandlers={:d}>".format(
751
+ super().__repr__().rstrip(">"), len(self._delayedactionshandlers)
752
+ )
652
753
 
653
754
  def __str__(self):
654
- return (repr(self) + "\n\n" +
655
- "\n\n".join([ahandler.describe(fulldump=True)
656
- for ahandler in self._delayedactionshandlers]))
755
+ return (
756
+ repr(self)
757
+ + "\n\n"
758
+ + "\n\n".join(
759
+ [
760
+ ahandler.describe(fulldump=True)
761
+ for ahandler in self._delayedactionshandlers
762
+ ]
763
+ )
764
+ )
657
765
 
658
766
 
659
767
  class DelayedActionsHub(PrivateDelayedActionsHub, getbytag.GetByTag):
@@ -664,9 +772,11 @@ class DelayedActionsHub(PrivateDelayedActionsHub, getbytag.GetByTag):
664
772
  Therefore, a *tag* attribute needs to be specified when building/retrieving
665
773
  an object of this class.
666
774
  """
775
+
667
776
  pass
668
777
 
669
778
 
670
- if __name__ == '__main__':
779
+ if __name__ == "__main__":
671
780
  import doctest
781
+
672
782
  doctest.testmod()