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.
- vortex/__init__.py +75 -47
- vortex/algo/__init__.py +3 -2
- vortex/algo/components.py +944 -618
- vortex/algo/mpitools.py +802 -497
- vortex/algo/mpitools_templates/__init__.py +1 -0
- vortex/algo/serversynctools.py +34 -33
- vortex/config.py +19 -22
- vortex/data/__init__.py +9 -3
- vortex/data/abstractstores.py +593 -655
- vortex/data/containers.py +217 -162
- vortex/data/contents.py +65 -39
- vortex/data/executables.py +93 -102
- vortex/data/flow.py +40 -34
- vortex/data/geometries.py +228 -132
- vortex/data/handlers.py +436 -227
- vortex/data/outflow.py +15 -15
- vortex/data/providers.py +185 -163
- vortex/data/resources.py +48 -42
- vortex/data/stores.py +540 -417
- vortex/data/sync_templates/__init__.py +0 -0
- vortex/gloves.py +114 -87
- vortex/layout/__init__.py +1 -8
- vortex/layout/contexts.py +150 -84
- vortex/layout/dataflow.py +353 -202
- vortex/layout/monitor.py +264 -128
- vortex/nwp/__init__.py +5 -2
- vortex/nwp/algo/__init__.py +14 -5
- vortex/nwp/algo/assim.py +205 -151
- vortex/nwp/algo/clim.py +683 -517
- vortex/nwp/algo/coupling.py +447 -225
- vortex/nwp/algo/eda.py +437 -229
- vortex/nwp/algo/eps.py +403 -231
- vortex/nwp/algo/forecasts.py +416 -275
- vortex/nwp/algo/fpserver.py +683 -307
- vortex/nwp/algo/ifsnaming.py +205 -145
- vortex/nwp/algo/ifsroot.py +215 -122
- vortex/nwp/algo/monitoring.py +137 -76
- vortex/nwp/algo/mpitools.py +330 -190
- vortex/nwp/algo/odbtools.py +637 -353
- vortex/nwp/algo/oopsroot.py +454 -273
- vortex/nwp/algo/oopstests.py +90 -56
- vortex/nwp/algo/request.py +287 -206
- vortex/nwp/algo/stdpost.py +878 -522
- vortex/nwp/data/__init__.py +22 -4
- vortex/nwp/data/assim.py +125 -137
- vortex/nwp/data/boundaries.py +121 -68
- vortex/nwp/data/climfiles.py +193 -211
- vortex/nwp/data/configfiles.py +73 -69
- vortex/nwp/data/consts.py +426 -401
- vortex/nwp/data/ctpini.py +59 -43
- vortex/nwp/data/diagnostics.py +94 -66
- vortex/nwp/data/eda.py +50 -51
- vortex/nwp/data/eps.py +195 -146
- vortex/nwp/data/executables.py +440 -434
- vortex/nwp/data/fields.py +63 -48
- vortex/nwp/data/gridfiles.py +183 -111
- vortex/nwp/data/logs.py +250 -217
- vortex/nwp/data/modelstates.py +180 -151
- vortex/nwp/data/monitoring.py +72 -99
- vortex/nwp/data/namelists.py +254 -202
- vortex/nwp/data/obs.py +400 -308
- vortex/nwp/data/oopsexec.py +22 -20
- vortex/nwp/data/providers.py +90 -65
- vortex/nwp/data/query.py +71 -82
- vortex/nwp/data/stores.py +49 -36
- vortex/nwp/data/surfex.py +136 -137
- vortex/nwp/syntax/__init__.py +1 -1
- vortex/nwp/syntax/stdattrs.py +173 -111
- vortex/nwp/tools/__init__.py +2 -2
- vortex/nwp/tools/addons.py +22 -17
- vortex/nwp/tools/agt.py +24 -12
- vortex/nwp/tools/bdap.py +16 -5
- vortex/nwp/tools/bdcp.py +4 -1
- vortex/nwp/tools/bdm.py +3 -0
- vortex/nwp/tools/bdmp.py +14 -9
- vortex/nwp/tools/conftools.py +728 -378
- vortex/nwp/tools/drhook.py +12 -8
- vortex/nwp/tools/grib.py +65 -39
- vortex/nwp/tools/gribdiff.py +22 -17
- vortex/nwp/tools/ifstools.py +82 -42
- vortex/nwp/tools/igastuff.py +167 -143
- vortex/nwp/tools/mars.py +14 -2
- vortex/nwp/tools/odb.py +234 -125
- vortex/nwp/tools/partitioning.py +61 -37
- vortex/nwp/tools/satrad.py +27 -12
- vortex/nwp/util/async.py +83 -55
- vortex/nwp/util/beacon.py +10 -10
- vortex/nwp/util/diffpygram.py +174 -86
- vortex/nwp/util/ens.py +144 -63
- vortex/nwp/util/hooks.py +30 -19
- vortex/nwp/util/taskdeco.py +28 -24
- vortex/nwp/util/usepygram.py +278 -172
- vortex/nwp/util/usetnt.py +31 -17
- vortex/sessions.py +72 -39
- vortex/syntax/__init__.py +1 -1
- vortex/syntax/stdattrs.py +410 -171
- vortex/syntax/stddeco.py +31 -22
- vortex/toolbox.py +327 -192
- vortex/tools/__init__.py +11 -2
- vortex/tools/actions.py +110 -121
- vortex/tools/addons.py +111 -92
- vortex/tools/arm.py +42 -22
- vortex/tools/compression.py +72 -69
- vortex/tools/date.py +11 -4
- vortex/tools/delayedactions.py +242 -132
- vortex/tools/env.py +75 -47
- vortex/tools/folder.py +342 -171
- vortex/tools/grib.py +341 -162
- vortex/tools/lfi.py +423 -216
- vortex/tools/listings.py +109 -40
- vortex/tools/names.py +218 -156
- vortex/tools/net.py +655 -299
- vortex/tools/parallelism.py +93 -61
- vortex/tools/prestaging.py +55 -31
- vortex/tools/schedulers.py +172 -105
- vortex/tools/services.py +403 -334
- vortex/tools/storage.py +293 -358
- vortex/tools/surfex.py +24 -24
- vortex/tools/systems.py +1234 -643
- vortex/tools/targets.py +156 -100
- vortex/util/__init__.py +1 -1
- vortex/util/config.py +378 -327
- vortex/util/empty.py +2 -2
- vortex/util/helpers.py +56 -24
- vortex/util/introspection.py +18 -12
- vortex/util/iosponge.py +8 -4
- vortex/util/roles.py +4 -6
- vortex/util/storefunctions.py +39 -13
- vortex/util/structs.py +3 -3
- vortex/util/worker.py +29 -17
- vortex_nwp-2.1.0.dist-info/METADATA +67 -0
- vortex_nwp-2.1.0.dist-info/RECORD +144 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/WHEEL +1 -1
- vortex/layout/appconf.py +0 -109
- vortex/layout/jobs.py +0 -1276
- vortex/layout/nodes.py +0 -1424
- vortex/layout/subjobs.py +0 -464
- vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
- vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info/licenses}/LICENSE +0 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/top_level.txt +0 -0
vortex/tools/delayedactions.py
CHANGED
|
@@ -74,14 +74,17 @@ __all__ = []
|
|
|
74
74
|
logger = loggers.getLogger(__name__)
|
|
75
75
|
|
|
76
76
|
#: Definition of a named tuple DelayedActionStatusTuple
|
|
77
|
-
DelayedActionStatusTuple = namedtuple(
|
|
78
|
-
|
|
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(
|
|
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(
|
|
124
|
-
|
|
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(
|
|
142
|
+
self._obsboard.notify_upd(
|
|
143
|
+
self, info=dict(changed="result", prev=oldres)
|
|
144
|
+
)
|
|
138
145
|
|
|
139
|
-
result = property(
|
|
140
|
-
|
|
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(
|
|
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(
|
|
154
|
-
|
|
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(
|
|
160
|
-
|
|
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(
|
|
166
|
-
|
|
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
|
|
187
|
+
return "id={0._id}: {0.statustext:6s} result={0.result!s}".format(self)
|
|
171
188
|
|
|
172
189
|
|
|
173
|
-
class AbstractDelayedActionsHandler(
|
|
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 = (
|
|
196
|
+
_collector = ("delayedactionshandler",)
|
|
178
197
|
_footprint = dict(
|
|
179
|
-
info
|
|
180
|
-
attr
|
|
181
|
-
system
|
|
182
|
-
|
|
183
|
-
|
|
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(
|
|
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[
|
|
220
|
-
newval = getattr(item, info.get(
|
|
221
|
-
oldval = info[
|
|
222
|
-
self._history.append(
|
|
223
|
-
|
|
224
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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 =
|
|
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 +=
|
|
328
|
+
res += " * {:s}: {!s}\n".format(k, v)
|
|
301
329
|
if fulldump:
|
|
302
|
-
res +=
|
|
303
|
-
res +=
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
res +=
|
|
311
|
-
res +=
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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(
|
|
338
|
-
|
|
339
|
-
|
|
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
|
|
360
|
-
attr
|
|
361
|
-
kind
|
|
362
|
-
values
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
407
|
-
attr
|
|
408
|
-
kind
|
|
409
|
-
values
|
|
461
|
+
info="Fetch multiple files using an FTP archive.",
|
|
462
|
+
attr=dict(
|
|
463
|
+
kind=dict(
|
|
464
|
+
values=[
|
|
465
|
+
"archive",
|
|
466
|
+
],
|
|
410
467
|
),
|
|
411
|
-
storage
|
|
468
|
+
storage=dict(),
|
|
469
|
+
goal=dict(
|
|
470
|
+
values=[
|
|
471
|
+
"get",
|
|
472
|
+
]
|
|
412
473
|
),
|
|
413
|
-
|
|
414
|
-
values
|
|
474
|
+
tube=dict(
|
|
475
|
+
values=[
|
|
476
|
+
"ftp",
|
|
477
|
+
],
|
|
415
478
|
),
|
|
416
|
-
|
|
417
|
-
|
|
479
|
+
raw=dict(
|
|
480
|
+
type=bool,
|
|
481
|
+
optional=True,
|
|
482
|
+
default=False,
|
|
418
483
|
),
|
|
419
|
-
|
|
420
|
-
|
|
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 =
|
|
433
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
475
|
-
attr
|
|
476
|
-
raw
|
|
477
|
-
optional
|
|
478
|
-
values
|
|
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 = (
|
|
489
|
-
|
|
490
|
-
|
|
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[
|
|
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(
|
|
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(
|
|
507
|
-
|
|
508
|
-
|
|
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 = [
|
|
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(
|
|
560
|
-
|
|
561
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
590
|
-
|
|
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(
|
|
596
|
-
|
|
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(
|
|
692
|
+
myhandler = fpx.delayedactionshandler(
|
|
693
|
+
_emptywarning=False, **myhandler_desc
|
|
694
|
+
)
|
|
602
695
|
if myhandler is not None:
|
|
603
|
-
logger.debug(
|
|
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(
|
|
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(*
|
|
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(
|
|
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
|
|
650
|
-
|
|
651
|
-
|
|
750
|
+
return "{:s} | n_delayedactionshandlers={:d}>".format(
|
|
751
|
+
super().__repr__().rstrip(">"), len(self._delayedactionshandlers)
|
|
752
|
+
)
|
|
652
753
|
|
|
653
754
|
def __str__(self):
|
|
654
|
-
return (
|
|
655
|
-
|
|
656
|
-
|
|
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__ ==
|
|
779
|
+
if __name__ == "__main__":
|
|
671
780
|
import doctest
|
|
781
|
+
|
|
672
782
|
doctest.testmod()
|