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.
Files changed (139) hide show
  1. vortex/__init__.py +59 -45
  2. vortex/algo/__init__.py +3 -2
  3. vortex/algo/components.py +940 -614
  4. vortex/algo/mpitools.py +802 -497
  5. vortex/algo/serversynctools.py +34 -33
  6. vortex/config.py +19 -22
  7. vortex/data/__init__.py +9 -3
  8. vortex/data/abstractstores.py +593 -655
  9. vortex/data/containers.py +217 -162
  10. vortex/data/contents.py +65 -39
  11. vortex/data/executables.py +93 -102
  12. vortex/data/flow.py +40 -34
  13. vortex/data/geometries.py +228 -132
  14. vortex/data/handlers.py +428 -225
  15. vortex/data/outflow.py +15 -15
  16. vortex/data/providers.py +185 -163
  17. vortex/data/resources.py +48 -42
  18. vortex/data/stores.py +544 -413
  19. vortex/gloves.py +114 -87
  20. vortex/layout/__init__.py +1 -8
  21. vortex/layout/contexts.py +150 -84
  22. vortex/layout/dataflow.py +353 -202
  23. vortex/layout/monitor.py +264 -128
  24. vortex/nwp/__init__.py +5 -2
  25. vortex/nwp/algo/__init__.py +14 -5
  26. vortex/nwp/algo/assim.py +205 -151
  27. vortex/nwp/algo/clim.py +683 -517
  28. vortex/nwp/algo/coupling.py +447 -225
  29. vortex/nwp/algo/eda.py +437 -229
  30. vortex/nwp/algo/eps.py +403 -231
  31. vortex/nwp/algo/forecasts.py +420 -271
  32. vortex/nwp/algo/fpserver.py +683 -307
  33. vortex/nwp/algo/ifsnaming.py +205 -145
  34. vortex/nwp/algo/ifsroot.py +210 -122
  35. vortex/nwp/algo/monitoring.py +132 -76
  36. vortex/nwp/algo/mpitools.py +321 -191
  37. vortex/nwp/algo/odbtools.py +617 -353
  38. vortex/nwp/algo/oopsroot.py +449 -273
  39. vortex/nwp/algo/oopstests.py +90 -56
  40. vortex/nwp/algo/request.py +287 -206
  41. vortex/nwp/algo/stdpost.py +878 -522
  42. vortex/nwp/data/__init__.py +22 -4
  43. vortex/nwp/data/assim.py +125 -137
  44. vortex/nwp/data/boundaries.py +121 -68
  45. vortex/nwp/data/climfiles.py +193 -211
  46. vortex/nwp/data/configfiles.py +73 -69
  47. vortex/nwp/data/consts.py +426 -401
  48. vortex/nwp/data/ctpini.py +59 -43
  49. vortex/nwp/data/diagnostics.py +94 -66
  50. vortex/nwp/data/eda.py +50 -51
  51. vortex/nwp/data/eps.py +195 -146
  52. vortex/nwp/data/executables.py +440 -434
  53. vortex/nwp/data/fields.py +63 -48
  54. vortex/nwp/data/gridfiles.py +183 -111
  55. vortex/nwp/data/logs.py +250 -217
  56. vortex/nwp/data/modelstates.py +180 -151
  57. vortex/nwp/data/monitoring.py +72 -99
  58. vortex/nwp/data/namelists.py +254 -202
  59. vortex/nwp/data/obs.py +400 -308
  60. vortex/nwp/data/oopsexec.py +22 -20
  61. vortex/nwp/data/providers.py +90 -65
  62. vortex/nwp/data/query.py +71 -82
  63. vortex/nwp/data/stores.py +49 -36
  64. vortex/nwp/data/surfex.py +136 -137
  65. vortex/nwp/syntax/__init__.py +1 -1
  66. vortex/nwp/syntax/stdattrs.py +173 -111
  67. vortex/nwp/tools/__init__.py +2 -2
  68. vortex/nwp/tools/addons.py +22 -17
  69. vortex/nwp/tools/agt.py +24 -12
  70. vortex/nwp/tools/bdap.py +16 -5
  71. vortex/nwp/tools/bdcp.py +4 -1
  72. vortex/nwp/tools/bdm.py +3 -0
  73. vortex/nwp/tools/bdmp.py +14 -9
  74. vortex/nwp/tools/conftools.py +728 -378
  75. vortex/nwp/tools/drhook.py +12 -8
  76. vortex/nwp/tools/grib.py +65 -39
  77. vortex/nwp/tools/gribdiff.py +22 -17
  78. vortex/nwp/tools/ifstools.py +82 -42
  79. vortex/nwp/tools/igastuff.py +167 -143
  80. vortex/nwp/tools/mars.py +14 -2
  81. vortex/nwp/tools/odb.py +234 -125
  82. vortex/nwp/tools/partitioning.py +61 -37
  83. vortex/nwp/tools/satrad.py +27 -12
  84. vortex/nwp/util/async.py +83 -55
  85. vortex/nwp/util/beacon.py +10 -10
  86. vortex/nwp/util/diffpygram.py +174 -86
  87. vortex/nwp/util/ens.py +144 -63
  88. vortex/nwp/util/hooks.py +30 -19
  89. vortex/nwp/util/taskdeco.py +28 -24
  90. vortex/nwp/util/usepygram.py +278 -172
  91. vortex/nwp/util/usetnt.py +31 -17
  92. vortex/sessions.py +72 -39
  93. vortex/syntax/__init__.py +1 -1
  94. vortex/syntax/stdattrs.py +410 -171
  95. vortex/syntax/stddeco.py +31 -22
  96. vortex/toolbox.py +327 -192
  97. vortex/tools/__init__.py +11 -2
  98. vortex/tools/actions.py +125 -59
  99. vortex/tools/addons.py +111 -92
  100. vortex/tools/arm.py +42 -22
  101. vortex/tools/compression.py +72 -69
  102. vortex/tools/date.py +11 -4
  103. vortex/tools/delayedactions.py +242 -132
  104. vortex/tools/env.py +75 -47
  105. vortex/tools/folder.py +342 -171
  106. vortex/tools/grib.py +311 -149
  107. vortex/tools/lfi.py +423 -216
  108. vortex/tools/listings.py +109 -40
  109. vortex/tools/names.py +218 -156
  110. vortex/tools/net.py +632 -298
  111. vortex/tools/parallelism.py +93 -61
  112. vortex/tools/prestaging.py +55 -31
  113. vortex/tools/schedulers.py +172 -105
  114. vortex/tools/services.py +402 -333
  115. vortex/tools/storage.py +293 -358
  116. vortex/tools/surfex.py +24 -24
  117. vortex/tools/systems.py +1211 -631
  118. vortex/tools/targets.py +156 -100
  119. vortex/util/__init__.py +1 -1
  120. vortex/util/config.py +377 -327
  121. vortex/util/empty.py +2 -2
  122. vortex/util/helpers.py +56 -24
  123. vortex/util/introspection.py +18 -12
  124. vortex/util/iosponge.py +8 -4
  125. vortex/util/roles.py +4 -6
  126. vortex/util/storefunctions.py +39 -13
  127. vortex/util/structs.py +3 -3
  128. vortex/util/worker.py +29 -17
  129. vortex_nwp-2.0.0b2.dist-info/METADATA +66 -0
  130. vortex_nwp-2.0.0b2.dist-info/RECORD +142 -0
  131. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/WHEEL +1 -1
  132. vortex/layout/appconf.py +0 -109
  133. vortex/layout/jobs.py +0 -1276
  134. vortex/layout/nodes.py +0 -1424
  135. vortex/layout/subjobs.py +0 -464
  136. vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
  137. vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
  138. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/LICENSE +0 -0
  139. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.0.0b2.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ import functools
8
8
  from bronx.fancies import loggers
9
9
  import footprints
10
10
 
11
+ from vortex import config
11
12
  from .services import Service
12
13
 
13
14
  __all__ = []
@@ -20,18 +21,18 @@ class Scheduler(Service):
20
21
 
21
22
  _abstract = True
22
23
  _footprint = dict(
23
- info = 'Scheduling service class',
24
- attr = dict(
25
- muteset = dict(
26
- optional = True,
27
- default = footprints.FPSet(),
28
- type = footprints.FPSet,
24
+ info="Scheduling service class",
25
+ attr=dict(
26
+ muteset=dict(
27
+ optional=True,
28
+ default=footprints.FPSet(),
29
+ type=footprints.FPSet,
29
30
  )
30
- )
31
+ ),
31
32
  )
32
33
 
33
34
  def __init__(self, *args, **kw):
34
- logger.debug('Scheduler init %s', self.__class__)
35
+ logger.debug("Scheduler init %s", self.__class__)
35
36
  super().__init__(*args, **kw)
36
37
 
37
38
  @property
@@ -61,15 +62,15 @@ class EcmwfLikeScheduler(Scheduler):
61
62
 
62
63
  _abstract = True
63
64
  _footprint = dict(
64
- attr = dict(
65
- env_pattern = dict(
66
- info = 'Scheduler configuration variables start with...',
65
+ attr=dict(
66
+ env_pattern=dict(
67
+ info="Scheduler configuration variables start with...",
67
68
  ),
68
- non_critical_timeout = dict(
69
- info = 'Timeout in seconds for non-critical commands',
70
- type = int,
71
- default = 5,
72
- optional = True,
69
+ non_critical_timeout=dict(
70
+ info="Timeout in seconds for non-critical commands",
71
+ type=int,
72
+ default=5,
73
+ optional=True,
73
74
  ),
74
75
  )
75
76
  )
@@ -77,17 +78,23 @@ class EcmwfLikeScheduler(Scheduler):
77
78
  _KNOWN_CMD = ()
78
79
 
79
80
  def __init__(self, *args, **kw):
80
- logger.debug('Scheduler init %s', self.__class__)
81
+ logger.debug("Scheduler init %s", self.__class__)
81
82
  super(Scheduler, self).__init__(*args, **kw)
82
83
  self._inside_child_session = False
83
84
 
84
85
  def conf(self, kwenv):
85
86
  """Possibly export the provided variables and return a dictionary of positioned variables."""
86
87
  if kwenv:
87
- for schedvar in [x.upper() for x in kwenv.keys() if x.upper().startswith(self.env_pattern)]:
88
+ for schedvar in [
89
+ x.upper()
90
+ for x in kwenv.keys()
91
+ if x.upper().startswith(self.env_pattern)
92
+ ]:
88
93
  self.env[schedvar] = str(kwenv[schedvar])
89
94
  subenv = dict()
90
- for schedvar in [x for x in self.env.keys() if x.startswith(self.env_pattern)]:
95
+ for schedvar in [
96
+ x for x in self.env.keys() if x.startswith(self.env_pattern)
97
+ ]:
91
98
  subenv[schedvar] = self.env.get(schedvar)
92
99
  return subenv
93
100
 
@@ -141,27 +148,45 @@ class EcmwfLikeScheduler(Scheduler):
141
148
  rc = None
142
149
  cmd = self.cmd_rename(cmd)
143
150
  if cmd in self.muteset:
144
- logger.warning('%s mute command [%s]', self.kind, cmd)
151
+ logger.warning("%s mute command [%s]", self.kind, cmd)
145
152
  else:
146
153
  with self.child_session() as session_rc:
147
154
  if session_rc:
148
- if getattr(self, 'setup_' + cmd, self.setup_default)(*options):
155
+ if getattr(self, "setup_" + cmd, self.setup_default)(
156
+ *options
157
+ ):
149
158
  wrapp_rc = False
150
159
  try:
151
- with self.wrap_actual_child_command(kwoptions) as wrapp_rc:
160
+ with self.wrap_actual_child_command(
161
+ kwoptions
162
+ ) as wrapp_rc:
152
163
  if wrapp_rc:
153
- rc = self._actual_child(cmd, options, **kwoptions)
164
+ rc = self._actual_child(
165
+ cmd, options, **kwoptions
166
+ )
154
167
  else:
155
- logger.warning('Actual [%s %s] command wrap failed', self.kind, cmd)
168
+ logger.warning(
169
+ "Actual [%s %s] command wrap failed",
170
+ self.kind,
171
+ cmd,
172
+ )
156
173
  finally:
157
174
  if wrapp_rc:
158
- getattr(self, 'close_' + cmd, self.close_default)(*options)
175
+ getattr(
176
+ self, "close_" + cmd, self.close_default
177
+ )(*options)
159
178
  else:
160
- logger.warning('Actual [%s %s] command skipped due to setup action',
161
- self.kind, cmd)
179
+ logger.warning(
180
+ "Actual [%s %s] command skipped due to setup action",
181
+ self.kind,
182
+ cmd,
183
+ )
162
184
  else:
163
- logger.warning('Actual [%s %s] command skipped session setup failure',
164
- self.kind, cmd)
185
+ logger.warning(
186
+ "Actual [%s %s] command skipped session setup failure",
187
+ self.kind,
188
+ cmd,
189
+ )
165
190
  return rc
166
191
 
167
192
  def _actual_child(self, cmd, options, critical=True):
@@ -182,58 +207,62 @@ class SMS(EcmwfLikeScheduler):
182
207
  """
183
208
 
184
209
  _footprint = dict(
185
- info = 'SMS client service',
186
- attr = dict(
187
- kind = dict(
188
- values = ['sms'],
210
+ info="SMS client service",
211
+ attr=dict(
212
+ kind=dict(
213
+ values=["sms"],
189
214
  ),
190
- rootdir = dict(
191
- optional = True,
192
- default = None,
193
- alias = ('install',),
215
+ rootdir=dict(
216
+ optional=True,
217
+ default=None,
218
+ alias=("install",),
194
219
  ),
195
- env_pattern = dict(
196
- default = 'SMS',
197
- optional = True,
198
- )
199
- )
220
+ env_pattern=dict(
221
+ default="SMS",
222
+ optional=True,
223
+ ),
224
+ ),
200
225
  )
201
226
 
202
- _KNOWN_CMD = ('abort', 'complete', 'event', 'init', 'label', 'meter',
203
- 'msg', 'variable', 'fix')
227
+ _KNOWN_CMD = (
228
+ "abort",
229
+ "complete",
230
+ "event",
231
+ "init",
232
+ "label",
233
+ "meter",
234
+ "msg",
235
+ "variable",
236
+ "fix",
237
+ )
204
238
 
205
239
  def __init__(self, *args, **kw):
206
- logger.debug('SMS scheduler client init %s', self)
240
+ logger.debug("SMS scheduler client init %s", self)
207
241
  super().__init__(*args, **kw)
208
242
  self._actual_rootdir = self.rootdir
209
243
  if self._actual_rootdir is None:
210
244
  self._actual_rootdir = (
211
- self.env.SMS_INSTALL_ROOT or
212
- from_config(section="sms", key="rootdir")
245
+ self.env.SMS_INSTALL_ROOT
246
+ or config.from_config(section="sms", key="rootdir")
213
247
  )
214
- if self._actual_rootdir is None:
215
- logger.warning(
216
- 'SMS service could not guess install location [%s]',
217
- str(guesspath)
218
- )
219
- if self.sh.path.exists(self.cmdpath('init')):
248
+ if self.sh.path.exists(self.cmdpath("init")):
220
249
  self.env.setbinpath(self._actual_rootdir)
221
250
  else:
222
251
  logger.warning(
223
- 'No SMS client found at init time [rootdir:%s]>',
224
- self._actual_rootdir
252
+ "No SMS client found at init time [rootdir:%s]>",
253
+ self._actual_rootdir,
225
254
  )
226
255
 
227
256
  def cmd_rename(self, cmd):
228
257
  """Remap command name. Strip any sms prefix."""
229
258
  cmd = super().cmd_rename(cmd)
230
- while cmd.startswith('sms'):
259
+ while cmd.startswith("sms"):
231
260
  cmd = cmd[3:]
232
261
  return cmd
233
262
 
234
263
  def cmdpath(self, cmd):
235
264
  """Return a complete binary path to cmd."""
236
- cmd = 'sms' + self.cmd_rename(cmd)
265
+ cmd = "sms" + self.cmd_rename(cmd)
237
266
  if self._actual_rootdir:
238
267
  return self.sh.path.join(self._actual_rootdir, cmd)
239
268
  else:
@@ -255,12 +284,12 @@ class SMS(EcmwfLikeScheduler):
255
284
  """Last minute wrap before binary child command."""
256
285
  with super().wrap_actual_child_command(kwoptions) as wrapp_rc:
257
286
  upd_env = dict()
258
- if not kwoptions.get('critical', True):
259
- upd_env['SMSDENIED'] = 1
287
+ if not kwoptions.get("critical", True):
288
+ upd_env["SMSDENIED"] = 1
260
289
  if self.non_critical_timeout:
261
- upd_env['SMSTIMEOUT'] = self.non_critical_timeout
290
+ upd_env["SMSTIMEOUT"] = self.non_critical_timeout
262
291
  if upd_env:
263
- with self.env.delta_context(** upd_env):
292
+ with self.env.delta_context(**upd_env):
264
293
  yield wrapp_rc
265
294
  else:
266
295
  yield wrapp_rc
@@ -278,12 +307,12 @@ class SMSColor(SMS):
278
307
  """
279
308
 
280
309
  _footprint = dict(
281
- info = 'SMS color client service',
282
- attr = dict(
283
- kind = dict(
284
- values = ['smscolor'],
310
+ info="SMS color client service",
311
+ attr=dict(
312
+ kind=dict(
313
+ values=["smscolor"],
285
314
  ),
286
- )
315
+ ),
287
316
  )
288
317
 
289
318
  @contextlib.contextmanager
@@ -300,28 +329,39 @@ class EcFlow(EcmwfLikeScheduler):
300
329
  """
301
330
 
302
331
  _footprint = dict(
303
- info = 'SMS client service',
304
- attr = dict(
305
- kind = dict(
306
- values = ['ecflow'],
332
+ info="SMS client service",
333
+ attr=dict(
334
+ kind=dict(
335
+ values=["ecflow"],
307
336
  ),
308
- clientpath = dict(
309
- info = ("Path to the ecFlow client binary (if omitted, " +
310
- "it's read in the configuration file)"),
311
- optional = True,
312
- default = None,
337
+ clientpath=dict(
338
+ info=(
339
+ "Path to the ecFlow client binary (if omitted, "
340
+ + "it's read in the configuration file)"
341
+ ),
342
+ optional=True,
343
+ default=None,
313
344
  ),
314
- env_pattern = dict(
315
- default = 'ECF_',
316
- optional = True,
317
- )
318
- )
345
+ env_pattern=dict(
346
+ default="ECF_",
347
+ optional=True,
348
+ ),
349
+ ),
319
350
  )
320
351
 
321
- _KNOWN_CMD = ('abort', 'complete', 'event', 'init', 'label', 'meter', 'msg', 'alter')
352
+ _KNOWN_CMD = (
353
+ "abort",
354
+ "complete",
355
+ "event",
356
+ "init",
357
+ "label",
358
+ "meter",
359
+ "msg",
360
+ "alter",
361
+ )
322
362
 
323
363
  def __init__(self, *args, **kw):
324
- logger.debug('EcFlow scheduler client init %s', self)
364
+ logger.debug("EcFlow scheduler client init %s", self)
325
365
  super().__init__(*args, **kw)
326
366
  self._actual_clientpath = self.clientpath
327
367
 
@@ -329,15 +369,23 @@ class EcFlow(EcmwfLikeScheduler):
329
369
  """Return the actual binary path to the EcFlow client."""
330
370
  if self._actual_clientpath is None:
331
371
  thistarget = self.sh.default_target
332
- guesspath = self.env.ECF_CLIENT_PATH or thistarget.get('ecflow:clientpath')
333
- ecfversion = self.env.get('ECF_VERSION', 'default')
372
+ guesspath = self.env.ECF_CLIENT_PATH or thistarget.get(
373
+ "ecflow:clientpath"
374
+ )
375
+ ecfversion = self.env.get("ECF_VERSION", "default")
334
376
  guesspath = guesspath.format(version=ecfversion)
335
377
  if guesspath is None:
336
- logger.warning('ecFlow service could not guess the install location [%s]', str(guesspath))
378
+ logger.warning(
379
+ "ecFlow service could not guess the install location [%s]",
380
+ str(guesspath),
381
+ )
337
382
  else:
338
383
  self._actual_clientpath = guesspath
339
384
  if not self.sh.path.exists(self._actual_clientpath):
340
- logger.warning('No ecFlow client found at init time [path:%s]>', self._actual_clientpath)
385
+ logger.warning(
386
+ "No ecFlow client found at init time [path:%s]>",
387
+ self._actual_clientpath,
388
+ )
341
389
  return self._actual_clientpath
342
390
 
343
391
  @contextlib.contextmanager
@@ -348,24 +396,39 @@ class EcFlow(EcmwfLikeScheduler):
348
396
  tunnel = None
349
397
  # wait and retries from config
350
398
  thistarget = self.sh.default_target
351
- sshwait = float(thistarget.get('ecflow:sshproxy_wait', 6))
352
- sshretries = float(thistarget.get('ecflow:sshproxy_retries', 2))
353
- sshretrydelay = float(thistarget.get('ecflow:sshproxy_retrydelay', 1))
399
+ sshwait = float(thistarget.get("ecflow:sshproxy_wait", 6))
400
+ sshretries = float(
401
+ thistarget.get("ecflow:sshproxy_retries", 2)
402
+ )
403
+ sshretrydelay = float(
404
+ thistarget.get("ecflow:sshproxy_retrydelay", 1)
405
+ )
354
406
  # Build up an SSH tunnel to convey the EcFlow command
355
407
  ecconf = self.conf(dict())
356
- echost = ecconf.get('{:s}HOST'.format(self.env_pattern), None)
357
- ecport = ecconf.get('{:s}PORT'.format(self.env_pattern), None)
408
+ echost = ecconf.get("{:s}HOST".format(self.env_pattern), None)
409
+ ecport = ecconf.get("{:s}PORT".format(self.env_pattern), None)
358
410
  if not (echost and ecport):
359
411
  setup_rc = False
360
412
  else:
361
- sshobj = self.sh.ssh('network', virtualnode=True, mandatory_hostcheck=False,
362
- maxtries=sshretries, triesdelay=sshretrydelay)
363
- tunnel = sshobj.tunnel(echost, int(ecport), maxwait=sshwait)
413
+ sshobj = self.sh.ssh(
414
+ "network",
415
+ virtualnode=True,
416
+ mandatory_hostcheck=False,
417
+ maxtries=sshretries,
418
+ triesdelay=sshretrydelay,
419
+ )
420
+ tunnel = sshobj.tunnel(
421
+ echost, int(ecport), maxwait=sshwait
422
+ )
364
423
  if not tunnel:
365
424
  setup_rc = False
366
425
  else:
367
- newvars = {'{:s}HOST'.format(self.env_pattern): 'localhost',
368
- '{:s}PORT'.format(self.env_pattern): tunnel.entranceport}
426
+ newvars = {
427
+ "{:s}HOST".format(self.env_pattern): "localhost",
428
+ "{:s}PORT".format(
429
+ self.env_pattern
430
+ ): tunnel.entranceport,
431
+ }
369
432
  self.env.update(**newvars)
370
433
  try:
371
434
  yield setup_rc
@@ -381,27 +444,31 @@ class EcFlow(EcmwfLikeScheduler):
381
444
  """Last minute wrap before binary child command."""
382
445
  with super().wrap_actual_child_command(kwoptions) as wrapp_rc:
383
446
  upd_env = dict()
384
- if not kwoptions.get('critical', True):
385
- upd_env['{:s}DENIED'.format(self.env_pattern)] = 1
447
+ if not kwoptions.get("critical", True):
448
+ upd_env["{:s}DENIED".format(self.env_pattern)] = 1
386
449
  if self.non_critical_timeout:
387
- upd_env['{:s}TIMEOUT'.format(self.env_pattern)] = self.non_critical_timeout
450
+ upd_env["{:s}TIMEOUT".format(self.env_pattern)] = (
451
+ self.non_critical_timeout
452
+ )
388
453
  if upd_env:
389
- with self.env.delta_context(** upd_env):
454
+ with self.env.delta_context(**upd_env):
390
455
  yield wrapp_rc
391
456
  else:
392
457
  yield wrapp_rc
393
458
 
394
459
  def _actual_child(self, cmd, options, critical=True):
395
460
  """Miscellaneous ecFlow sub-command."""
396
- args = [self.path(), ]
461
+ args = [
462
+ self.path(),
463
+ ]
397
464
  if options:
398
- args.append('--{:s}={!s}'.format(cmd, options[0]))
465
+ args.append("--{:s}={!s}".format(cmd, options[0]))
399
466
  if len(options) > 1:
400
467
  args.extend(options[1:])
401
468
  else:
402
- args.append('--{:s}'.format(cmd))
469
+ args.append("--{:s}".format(cmd))
403
470
  args = [str(a) for a in args]
404
- logger.info('Issuing the ecFlow command: %s', ' '.join(args[1:]))
471
+ logger.info("Issuing the ecFlow command: %s", " ".join(args[1:]))
405
472
  return self.sh.spawn(args, output=False, fatal=critical)
406
473
 
407
474
  def abort(self, *opts):
@@ -410,4 +477,4 @@ class EcFlow(EcmwfLikeScheduler):
410
477
  if not actual_opts:
411
478
  # For backward compatibility with SMS
412
479
  actual_opts.append("No abort reason provided")
413
- return self.child('abort', *actual_opts)
480
+ return self.child("abort", *actual_opts)