vortex-nwp 2.0.0b1__py3-none-any.whl → 2.0.0b2__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 +59 -45
- vortex/algo/__init__.py +3 -2
- vortex/algo/components.py +940 -614
- vortex/algo/mpitools.py +802 -497
- 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 +428 -225
- vortex/data/outflow.py +15 -15
- vortex/data/providers.py +185 -163
- vortex/data/resources.py +48 -42
- vortex/data/stores.py +544 -413
- 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 +420 -271
- vortex/nwp/algo/fpserver.py +683 -307
- vortex/nwp/algo/ifsnaming.py +205 -145
- vortex/nwp/algo/ifsroot.py +210 -122
- vortex/nwp/algo/monitoring.py +132 -76
- vortex/nwp/algo/mpitools.py +321 -191
- vortex/nwp/algo/odbtools.py +617 -353
- vortex/nwp/algo/oopsroot.py +449 -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 +125 -59
- 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 +311 -149
- vortex/tools/lfi.py +423 -216
- vortex/tools/listings.py +109 -40
- vortex/tools/names.py +218 -156
- vortex/tools/net.py +632 -298
- vortex/tools/parallelism.py +93 -61
- vortex/tools/prestaging.py +55 -31
- vortex/tools/schedulers.py +172 -105
- vortex/tools/services.py +402 -333
- vortex/tools/storage.py +293 -358
- vortex/tools/surfex.py +24 -24
- vortex/tools/systems.py +1211 -631
- vortex/tools/targets.py +156 -100
- vortex/util/__init__.py +1 -1
- vortex/util/config.py +377 -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.0.0b2.dist-info/METADATA +66 -0
- vortex_nwp-2.0.0b2.dist-info/RECORD +142 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.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.0.0b2.dist-info}/LICENSE +0 -0
- {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/top_level.txt +0 -0
vortex/tools/__init__.py
CHANGED
|
@@ -3,9 +3,18 @@ This is a pure package containing several modules that could be used
|
|
|
3
3
|
as standalone tools.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from . import storage
|
|
6
|
+
from . import storage as storage
|
|
7
|
+
from . import schedulers as schedulers
|
|
8
|
+
from . import services as services
|
|
9
|
+
from . import systems as systems
|
|
10
|
+
from . import targets as targets
|
|
11
|
+
from . import date as date
|
|
12
|
+
from . import env as env
|
|
13
|
+
from . import names as names
|
|
7
14
|
|
|
8
15
|
#: No automatic export
|
|
9
16
|
__all__ = []
|
|
10
17
|
|
|
11
|
-
__tocinfoline__ =
|
|
18
|
+
__tocinfoline__ = (
|
|
19
|
+
"VORTEX generic tools (system interfaces, format handling, ...)"
|
|
20
|
+
)
|
vortex/tools/actions.py
CHANGED
|
@@ -12,7 +12,6 @@ import footprints
|
|
|
12
12
|
from bronx.fancies import loggers
|
|
13
13
|
from bronx.fancies.display import dict_as_str
|
|
14
14
|
from vortex import sessions
|
|
15
|
-
from vortex.util.config import GenericConfigParser
|
|
16
15
|
|
|
17
16
|
#: Export nothing
|
|
18
17
|
__all__ = []
|
|
@@ -27,9 +26,11 @@ class Action:
|
|
|
27
26
|
Such an action could be activated or not, and is basically driven by permissions settings.
|
|
28
27
|
"""
|
|
29
28
|
|
|
30
|
-
def __init__(
|
|
29
|
+
def __init__(
|
|
30
|
+
self, kind="foo", service=None, active=False, permanent=False
|
|
31
|
+
):
|
|
31
32
|
if service is None:
|
|
32
|
-
service =
|
|
33
|
+
service = "send" + kind
|
|
33
34
|
self._service = service
|
|
34
35
|
self._kind = kind
|
|
35
36
|
self._active = active
|
|
@@ -81,8 +82,8 @@ class Action:
|
|
|
81
82
|
|
|
82
83
|
def info(self):
|
|
83
84
|
"""Informative string (may serve debugging purposes)."""
|
|
84
|
-
return
|
|
85
|
-
|
|
85
|
+
return "{} Action {} (kind={})".format(
|
|
86
|
+
"ON " if self.status() else "OFF",
|
|
86
87
|
self.__class__.__name__,
|
|
87
88
|
self.kind,
|
|
88
89
|
)
|
|
@@ -94,7 +95,7 @@ class Action:
|
|
|
94
95
|
def service_info(self, **kw):
|
|
95
96
|
"""On the fly remapping of the expected footprint."""
|
|
96
97
|
info = dict(kw)
|
|
97
|
-
info.setdefault(
|
|
98
|
+
info.setdefault("kind", self.service_kind(**kw))
|
|
98
99
|
return info
|
|
99
100
|
|
|
100
101
|
def get_actual_service(self, **kw):
|
|
@@ -114,9 +115,11 @@ class Action:
|
|
|
114
115
|
if self.active:
|
|
115
116
|
a_service = self.get_actual_service(**kw)
|
|
116
117
|
if a_service is None:
|
|
117
|
-
logger.warning(
|
|
118
|
+
logger.warning(
|
|
119
|
+
"Could not find any service for action %s", self.kind
|
|
120
|
+
)
|
|
118
121
|
else:
|
|
119
|
-
logger.warning(
|
|
122
|
+
logger.warning("Action %s is not active", self.kind)
|
|
120
123
|
return a_service
|
|
121
124
|
|
|
122
125
|
def execute(self, *args, **kw):
|
|
@@ -162,8 +165,11 @@ class TunableAction(Action):
|
|
|
162
165
|
self._conf_section = self.kind
|
|
163
166
|
else:
|
|
164
167
|
if self._conf_section not in self._shtarget.sections():
|
|
165
|
-
raise KeyError(
|
|
166
|
-
|
|
168
|
+
raise KeyError(
|
|
169
|
+
'No section "{}" in "{}"'.format(
|
|
170
|
+
self._conf_section, self._shtarget.config.file
|
|
171
|
+
)
|
|
172
|
+
)
|
|
167
173
|
if self._conf_section is None:
|
|
168
174
|
self._conf_dict = dict()
|
|
169
175
|
else:
|
|
@@ -191,19 +197,23 @@ class TunableAction(Action):
|
|
|
191
197
|
|
|
192
198
|
def info(self):
|
|
193
199
|
"""Informative string (may serve debugging purposes)."""
|
|
194
|
-
s = super().info() +
|
|
200
|
+
s = super().info() + " - tunable\n"
|
|
195
201
|
mix = dict()
|
|
196
202
|
mix.update(self._conf_items)
|
|
197
203
|
mix.update(self._tuning)
|
|
198
204
|
prt = dict()
|
|
199
205
|
for k, v in mix.items():
|
|
200
206
|
if k in self._tuning:
|
|
201
|
-
prt[
|
|
202
|
-
|
|
207
|
+
prt["++ " + k] = "{} (was: {})".format(
|
|
208
|
+
v,
|
|
209
|
+
str(self._conf_items[k])
|
|
210
|
+
if k in self._conf_items
|
|
211
|
+
else "<not set>",
|
|
212
|
+
)
|
|
203
213
|
else:
|
|
204
|
-
prt[
|
|
214
|
+
prt[" " + k] = v
|
|
205
215
|
if self._conf_section is not None:
|
|
206
|
-
s +=
|
|
216
|
+
s += " " * 4 + "configuration: " + self._conf_section + "\n"
|
|
207
217
|
s += dict_as_str(prt, prefix=4)
|
|
208
218
|
return s.strip()
|
|
209
219
|
|
|
@@ -213,12 +223,16 @@ class TunableAction(Action):
|
|
|
213
223
|
return self._tuning[key]
|
|
214
224
|
|
|
215
225
|
if self._conf_section is not None:
|
|
216
|
-
return self._shtarget.getx(
|
|
226
|
+
return self._shtarget.getx(
|
|
227
|
+
key=self._conf_section + ":" + key, *args, **kw
|
|
228
|
+
)
|
|
217
229
|
|
|
218
|
-
if
|
|
219
|
-
return kw[
|
|
230
|
+
if "default" in kw:
|
|
231
|
+
return kw["default"]
|
|
220
232
|
|
|
221
|
-
raise KeyError(
|
|
233
|
+
raise KeyError(
|
|
234
|
+
'The "{:s}" entry was not found in any configuration'.format(key)
|
|
235
|
+
)
|
|
222
236
|
|
|
223
237
|
|
|
224
238
|
class SendMail(Action):
|
|
@@ -226,11 +240,14 @@ class SendMail(Action):
|
|
|
226
240
|
Class responsible for sending emails.
|
|
227
241
|
"""
|
|
228
242
|
|
|
229
|
-
def __init__(
|
|
243
|
+
def __init__(
|
|
244
|
+
self, kind="mail", service="sendmail", active=True, quoteprintable=True
|
|
245
|
+
):
|
|
230
246
|
super().__init__(kind=kind, active=active, service=service)
|
|
231
247
|
if quoteprintable:
|
|
232
248
|
from email import charset
|
|
233
|
-
|
|
249
|
+
|
|
250
|
+
charset.add_charset("utf-8", charset.QP, charset.QP, "utf-8")
|
|
234
251
|
|
|
235
252
|
|
|
236
253
|
class TemplatedMail(TunableAction):
|
|
@@ -238,18 +255,24 @@ class TemplatedMail(TunableAction):
|
|
|
238
255
|
|
|
239
256
|
Do not use directly !
|
|
240
257
|
"""
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
258
|
+
|
|
259
|
+
def __init__(
|
|
260
|
+
self,
|
|
261
|
+
catalog,
|
|
262
|
+
kind="templatedmail",
|
|
263
|
+
service="templatedmail",
|
|
264
|
+
active=True,
|
|
265
|
+
inputs_charset=None,
|
|
266
|
+
):
|
|
267
|
+
super().__init__(
|
|
268
|
+
configuration=None, kind=kind, active=active, service=service
|
|
269
|
+
)
|
|
247
270
|
self.inputs_charset = inputs_charset
|
|
248
271
|
|
|
249
272
|
def service_info(self, **kw):
|
|
250
273
|
"""Kindly propose the permanent directory and catalog to the final service"""
|
|
251
|
-
kw.setdefault(
|
|
252
|
-
kw.setdefault(
|
|
274
|
+
kw.setdefault("catalog", self.catalog)
|
|
275
|
+
kw.setdefault("inputs_charset", self.inputs_charset)
|
|
253
276
|
return super().service_info(**kw)
|
|
254
277
|
|
|
255
278
|
def execute(self, *args, **kw):
|
|
@@ -261,7 +284,11 @@ class TemplatedMail(TunableAction):
|
|
|
261
284
|
rc = None
|
|
262
285
|
service = self.get_active_service(**kw)
|
|
263
286
|
if service:
|
|
264
|
-
options = {
|
|
287
|
+
options = {
|
|
288
|
+
k: v
|
|
289
|
+
for k, v in kw.items()
|
|
290
|
+
if k not in service.footprint_attributes
|
|
291
|
+
}
|
|
265
292
|
rc = service(options)
|
|
266
293
|
return rc
|
|
267
294
|
|
|
@@ -271,7 +298,7 @@ class Report(TunableAction):
|
|
|
271
298
|
Class responsible for sending reports.
|
|
272
299
|
"""
|
|
273
300
|
|
|
274
|
-
def __init__(self, kind=
|
|
301
|
+
def __init__(self, kind="report", service="sendreport", active=True):
|
|
275
302
|
super().__init__(kind=kind, active=active, service=service)
|
|
276
303
|
|
|
277
304
|
|
|
@@ -280,7 +307,7 @@ class SSH(Action):
|
|
|
280
307
|
Class responsible for sending commands to an SSH proxy.
|
|
281
308
|
"""
|
|
282
309
|
|
|
283
|
-
def __init__(self, kind=
|
|
310
|
+
def __init__(self, kind="ssh", service="ssh", active=True):
|
|
284
311
|
super().__init__(kind=kind, active=active, service=service)
|
|
285
312
|
|
|
286
313
|
|
|
@@ -289,17 +316,23 @@ class AskJeeves(TunableAction):
|
|
|
289
316
|
Class responsible for posting requests to Jeeves daemon.
|
|
290
317
|
"""
|
|
291
318
|
|
|
292
|
-
def __init__(self, kind=
|
|
293
|
-
super().__init__(
|
|
319
|
+
def __init__(self, kind="jeeves", service="askjeeves", active=True):
|
|
320
|
+
super().__init__(
|
|
321
|
+
configuration=None, kind=kind, active=active, service=service
|
|
322
|
+
)
|
|
294
323
|
|
|
295
324
|
def execute(self, *args, **kw):
|
|
296
325
|
"""Generic method to perform the action through a service."""
|
|
297
326
|
rc = None
|
|
298
|
-
if
|
|
299
|
-
kw[
|
|
327
|
+
if "kind" in kw:
|
|
328
|
+
kw["fwd_kind"] = kw.pop("kind")
|
|
300
329
|
service = self.get_active_service(**kw)
|
|
301
330
|
if service:
|
|
302
|
-
talk = {
|
|
331
|
+
talk = {
|
|
332
|
+
k: v
|
|
333
|
+
for k, v in kw.items()
|
|
334
|
+
if k not in service.footprint_attributes
|
|
335
|
+
}
|
|
303
336
|
rc = service(talk)
|
|
304
337
|
return rc
|
|
305
338
|
|
|
@@ -309,23 +342,27 @@ class Prompt(Action):
|
|
|
309
342
|
Fake action that could be used for any real action.
|
|
310
343
|
"""
|
|
311
344
|
|
|
312
|
-
def __init__(self, kind=
|
|
345
|
+
def __init__(self, kind="prompt", service="prompt", active=True):
|
|
313
346
|
super().__init__(kind=kind, active=active, service=service)
|
|
314
347
|
|
|
315
348
|
def execute(self, *args, **kw):
|
|
316
349
|
"""Do nothing but prompt the actual arguments."""
|
|
317
350
|
# kind could be unintentionally given, force it back
|
|
318
|
-
kw[
|
|
351
|
+
kw["kind"] = self.kind
|
|
319
352
|
service = self.get_active_service(**kw)
|
|
320
353
|
rc = False
|
|
321
354
|
if service:
|
|
322
|
-
options = {
|
|
355
|
+
options = {
|
|
356
|
+
k: v
|
|
357
|
+
for k, v in kw.items()
|
|
358
|
+
if k not in service.footprint_attributes
|
|
359
|
+
}
|
|
323
360
|
rc = service(options)
|
|
324
361
|
return rc
|
|
325
362
|
|
|
326
363
|
def foo(self, *args, **kw):
|
|
327
364
|
"""Yet an other foo method."""
|
|
328
|
-
print(
|
|
365
|
+
print("#FOO", self.kind, "/ args:", args, "/ kw:", kw)
|
|
329
366
|
return True
|
|
330
367
|
|
|
331
368
|
|
|
@@ -334,32 +371,55 @@ class FlowSchedulerGateway(Action):
|
|
|
334
371
|
Send a child command to any ECMWF's workfow scheduler.
|
|
335
372
|
"""
|
|
336
373
|
|
|
337
|
-
_KNOWN_CMD = dict(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
374
|
+
_KNOWN_CMD = dict(
|
|
375
|
+
sms=[
|
|
376
|
+
"abort",
|
|
377
|
+
"complete",
|
|
378
|
+
"event",
|
|
379
|
+
"init",
|
|
380
|
+
"label",
|
|
381
|
+
"meter",
|
|
382
|
+
"msg",
|
|
383
|
+
"variable",
|
|
384
|
+
"fix",
|
|
385
|
+
],
|
|
386
|
+
ecflow=["abort", "complete", "event", "init", "label", "meter", "msg"],
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
def __init__(self, kind="flow", service=None, active=True, permanent=True):
|
|
341
390
|
"""
|
|
342
391
|
The `service` attribute must be specified (it can be either sms or ecflow).
|
|
343
392
|
"""
|
|
344
393
|
if service is None:
|
|
345
|
-
raise ValueError(
|
|
346
|
-
super().__init__(
|
|
394
|
+
raise ValueError("The service name must be provided")
|
|
395
|
+
super().__init__(
|
|
396
|
+
kind=kind, active=active, service=service, permanent=permanent
|
|
397
|
+
)
|
|
347
398
|
|
|
348
399
|
def gateway(self, *args, **kw):
|
|
349
400
|
"""Ask the Scheduler to run any (but known) command."""
|
|
350
401
|
rc = None
|
|
351
402
|
service = self.get_active_service(**kw)
|
|
352
403
|
if service and self._schedcmd is not None:
|
|
353
|
-
kwbis = {k: v for k, v in kw.items() if k in (
|
|
404
|
+
kwbis = {k: v for k, v in kw.items() if k in ("critical",)}
|
|
354
405
|
rc = getattr(service, self._schedcmd)(*args, **kwbis)
|
|
355
406
|
self._schedcmd = None
|
|
356
407
|
return rc
|
|
357
408
|
|
|
358
409
|
def __getattr__(self, attr):
|
|
359
|
-
if attr.startswith(
|
|
410
|
+
if attr.startswith("_"):
|
|
360
411
|
raise AttributeError
|
|
361
|
-
if attr in (
|
|
362
|
-
|
|
412
|
+
if attr in (
|
|
413
|
+
[
|
|
414
|
+
"conf",
|
|
415
|
+
"info",
|
|
416
|
+
"clear",
|
|
417
|
+
"mute",
|
|
418
|
+
"play",
|
|
419
|
+
"path",
|
|
420
|
+
]
|
|
421
|
+
+ self._KNOWN_CMD[self.service]
|
|
422
|
+
):
|
|
363
423
|
self._schedcmd = attr
|
|
364
424
|
return self.gateway
|
|
365
425
|
else:
|
|
@@ -370,15 +430,21 @@ class FlowSchedulerGateway(Action):
|
|
|
370
430
|
class SmsGateway(FlowSchedulerGateway):
|
|
371
431
|
"""Send a child command to an SMS server."""
|
|
372
432
|
|
|
373
|
-
def __init__(self, kind=
|
|
374
|
-
super().__init__(
|
|
433
|
+
def __init__(self, kind="sms", service="sms", active=True, permanent=True):
|
|
434
|
+
super().__init__(
|
|
435
|
+
kind=kind, active=active, service=service, permanent=permanent
|
|
436
|
+
)
|
|
375
437
|
|
|
376
438
|
|
|
377
439
|
class EcflowGateway(FlowSchedulerGateway):
|
|
378
440
|
"""Send a child command to an Ecflow server."""
|
|
379
441
|
|
|
380
|
-
def __init__(
|
|
381
|
-
|
|
442
|
+
def __init__(
|
|
443
|
+
self, kind="ecflow", service="ecflow", active=True, permanent=True
|
|
444
|
+
):
|
|
445
|
+
super().__init__(
|
|
446
|
+
kind=kind, active=active, service=service, permanent=permanent
|
|
447
|
+
)
|
|
382
448
|
|
|
383
449
|
|
|
384
450
|
class SpooledActions:
|
|
@@ -425,7 +491,7 @@ class Dispatcher(bronx.stdtypes.catalog.Catalog):
|
|
|
425
491
|
"""
|
|
426
492
|
|
|
427
493
|
def __init__(self, **kw):
|
|
428
|
-
logger.debug(
|
|
494
|
+
logger.debug("Action dispatcher init %s", self)
|
|
429
495
|
super().__init__(**kw)
|
|
430
496
|
|
|
431
497
|
@property
|
|
@@ -444,11 +510,11 @@ class Dispatcher(bronx.stdtypes.catalog.Catalog):
|
|
|
444
510
|
self.discard(item)
|
|
445
511
|
|
|
446
512
|
def __getattr__(self, attr):
|
|
447
|
-
if attr.startswith(
|
|
513
|
+
if attr.startswith("_"):
|
|
448
514
|
raise AttributeError
|
|
449
|
-
a_kind, u_sep, a_method = attr.partition(
|
|
515
|
+
a_kind, u_sep, a_method = attr.partition("_")
|
|
450
516
|
if not a_method:
|
|
451
|
-
a_method =
|
|
517
|
+
a_method = "execute"
|
|
452
518
|
return SpooledActions(a_kind, a_method, self.candidates(a_kind))
|
|
453
519
|
|
|
454
520
|
|