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
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, schedulers, services, systems, targets, date, env, names
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__ = 'VORTEX generic tools (system interfaces, format handling, ...)'
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__(self, kind='foo', service=None, active=False, permanent=False):
29
+ def __init__(
30
+ self, kind="foo", service=None, active=False, permanent=False
31
+ ):
31
32
  if service is None:
32
- service = 'send' + kind
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 '{} Action {} (kind={})'.format(
85
- 'ON ' if self.status() else 'OFF',
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('kind', self.service_kind(**kw))
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('Could not find any service for action %s', self.kind)
118
+ logger.warning(
119
+ "Could not find any service for action %s", self.kind
120
+ )
118
121
  else:
119
- logger.warning('Action %s is not active', self.kind)
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('No section "{}" in "{}"'.format(self._conf_section,
166
- self._shtarget.config.file))
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() + ' - tunable\n'
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['++ ' + k] = '{} (was: {})'.format(v, str(
202
- self._conf_items[k]) if k in self._conf_items else '<not set>')
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[' ' + k] = v
214
+ prt[" " + k] = v
205
215
  if self._conf_section is not None:
206
- s += ' ' * 4 + 'configuration: ' + self._conf_section + '\n'
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(key=self._conf_section + ':' + key, *args, **kw)
226
+ return self._shtarget.getx(
227
+ key=self._conf_section + ":" + key, *args, **kw
228
+ )
217
229
 
218
- if 'default' in kw:
219
- return kw['default']
230
+ if "default" in kw:
231
+ return kw["default"]
220
232
 
221
- raise KeyError('The "{:s}" entry was not found in any configuration'.format(key))
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__(self, kind='mail', service='sendmail', active=True, quoteprintable=True):
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
- charset.add_charset('utf-8', charset.QP, charset.QP, 'utf-8')
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
- def __init__(self, kind='templatedmail', service='templatedmail', active=True,
242
- catalog=None, inputs_charset=None):
243
- super().__init__(configuration=None, kind=kind, active=active,
244
- service=service)
245
- self.catalog = catalog or GenericConfigParser('@{:s}-inventory.ini'.format(kind),
246
- encoding=inputs_charset)
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('catalog', self.catalog)
252
- kw.setdefault('inputs_charset', self.inputs_charset)
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 = {k: v for k, v in kw.items() if k not in service.footprint_attributes}
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='report', service='sendreport', active=True):
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='ssh', service='ssh', active=True):
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='jeeves', service='askjeeves', active=True):
293
- super().__init__(configuration=None, kind=kind, active=active, service=service)
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 'kind' in kw:
299
- kw['fwd_kind'] = kw.pop('kind')
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 = {k: v for k, v in kw.items() if k not in service.footprint_attributes}
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='prompt', service='prompt', active=True):
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['kind'] = self.kind
351
+ kw["kind"] = self.kind
319
352
  service = self.get_active_service(**kw)
320
353
  rc = False
321
354
  if service:
322
- options = {k: v for k, v in kw.items() if k not in service.footprint_attributes}
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('#FOO', self.kind, '/ args:', args, '/ kw:', kw)
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(sms=['abort', 'complete', 'event', 'init', 'label', 'meter', 'msg', 'variable', 'fix'],
338
- ecflow=['abort', 'complete', 'event', 'init', 'label', 'meter', 'msg'])
339
-
340
- def __init__(self, kind='flow', service=None, active=True, permanent=True):
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('The service name must be provided')
346
- super().__init__(kind=kind, active=active, service=service, permanent=permanent)
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 ('critical',)}
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 (['conf', 'info', 'clear', 'mute', 'play', 'path', ] +
362
- self._KNOWN_CMD[self.service]):
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='sms', service='sms', active=True, permanent=True):
374
- super().__init__(kind=kind, active=active, service=service, permanent=permanent)
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__(self, kind='ecflow', service='ecflow', active=True, permanent=True):
381
- super().__init__(kind=kind, active=active, service=service, permanent=permanent)
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('Action dispatcher init %s', self)
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 = 'execute'
517
+ a_method = "execute"
452
518
  return SpooledActions(a_kind, a_method, self.candidates(a_kind))
453
519
 
454
520