vortex-nwp 2.0.0b2__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 CHANGED
@@ -21,7 +21,18 @@ strongly advised.
21
21
  """
22
22
 
23
23
  import atexit
24
- import importlib.metadata
24
+ import sys
25
+ import os
26
+
27
+ # importlib.metadata included in stdlib from 3.8 onwards.
28
+ # For older versions, import third-party importlib_metadata
29
+ if sys.version_info < (3, 8):
30
+ import importlib_metadata
31
+ import importlib
32
+
33
+ importlib.metadata = importlib_metadata
34
+ else:
35
+ import importlib.metadata
25
36
 
26
37
  from bronx.fancies import loggers as bloggers
27
38
  import bronx.stdtypes.date
@@ -42,10 +53,10 @@ from .toolbox import algo as task
42
53
 
43
54
  from . import nwp as nwp # footprints import
44
55
 
45
- __version__ = "2.0.0b2"
56
+ __version__ = "2.1.0"
46
57
  __prompt__ = "Vortex v-" + __version__ + ":"
47
58
 
48
- __nextversion__ = "2.0.0b3"
59
+ __nextversion__ = "2.1.1"
49
60
  __tocinfoline__ = "VORTEX core package"
50
61
 
51
62
  __all__ = [
@@ -100,8 +111,11 @@ footprints.setup.callback = vortexfpdefaults
100
111
  ticket = sessions.get
101
112
  sh = sessions.system
102
113
 
103
- # If a config file can be found in current dir, load it
104
- config.load_config()
114
+ # If a config file can be found in current dir, load it else load .vortex.d/vortex.toml
115
+ if os.path.isfile("vortex.toml"):
116
+ config.load_config("vortex.toml")
117
+ else:
118
+ config.load_config(os.environ["HOME"] + "/.vortex.d/vortex.toml")
105
119
 
106
120
  # Load some superstars sub-packages
107
121
 
vortex/algo/components.py CHANGED
@@ -50,7 +50,7 @@ from bronx.syntax.decorators import nicedeco
50
50
  import footprints
51
51
  from taylorism import Boss
52
52
  import vortex
53
- from vortex.config import from_config
53
+ import vortex.config as config
54
54
  from vortex.algo import mpitools
55
55
  from vortex.syntax.stdattrs import DelayedEnvValue
56
56
  from vortex.tools.parallelism import ParallelResultParser
@@ -704,15 +704,15 @@ class AlgoComponent(footprints.FootprintBase, metaclass=AlgoComponentMeta):
704
704
 
705
705
  def export(self, packenv):
706
706
  """Export environment variables in given pack."""
707
- for k, v in from_config(section=packenv).items():
707
+ for k, v in config.from_config(section=packenv).items():
708
708
  if k not in self.env:
709
709
  logger.info("Setting %s env %s = %s", packenv.upper(), k, v)
710
710
  self.env[k] = v
711
711
 
712
712
  def prepare(self, rh, opts):
713
713
  """Set some defaults env values."""
714
- if opts.get("fortran", True):
715
- self.export("fortran")
714
+ if config.is_defined(section="env"):
715
+ self.export("env")
716
716
 
717
717
  def absexcutable(self, xfile):
718
718
  """Retuns the absolute pathname of the ``xfile`` executable."""
@@ -1841,7 +1841,7 @@ class Parallel(xExecutableAlgoComponent):
1841
1841
  def _mpitool_attributes(self, opts):
1842
1842
  """Return the dictionary of attributes needed to create the mpitool object."""
1843
1843
  # Read the appropriate configuration in the target file
1844
- conf_dict = from_config(section="mpitool")
1844
+ conf_dict = config.from_config(section="mpitool")
1845
1845
  if self.mpiname:
1846
1846
  conf_dict["mpiname"] = self.mpiname
1847
1847
  # Make "mpirun" the default mpi command name
@@ -1850,7 +1850,7 @@ class Parallel(xExecutableAlgoComponent):
1850
1850
  possible_attrs = functools.reduce(
1851
1851
  lambda s, t: s | t,
1852
1852
  [
1853
- set(cls._footprint.attr.keys())
1853
+ set(cls.footprint_retrieve().attr.keys())
1854
1854
  for cls in footprints.proxy.mpitools
1855
1855
  ],
1856
1856
  )
vortex/algo/mpitools.py CHANGED
@@ -182,8 +182,8 @@ class MpiTool(footprints.FootprintBase):
182
182
  )
183
183
 
184
184
  _envelope_bit_kind = "basicenvelopebit"
185
- _envelope_wrapper_tpl = "@envelope_wrapper_default.tpl"
186
- _wrapstd_wrapper_tpl = "@wrapstd_wrapper_default.tpl"
185
+ _envelope_wrapper_tpl = "envelope_wrapper_default.tpl"
186
+ _wrapstd_wrapper_tpl = "wrapstd_wrapper_default.tpl"
187
187
  _envelope_wrapper_name = "./global_envelope_wrapper.py"
188
188
  _wrapstd_wrapper_name = "./global_wrapstd_wrapper.py"
189
189
  _envelope_rank_var = "MPIRANK"
@@ -700,11 +700,11 @@ class MpiTool(footprints.FootprintBase):
700
700
  if not self.mpiwrapstd:
701
701
  return None
702
702
  # Create the launchwrapper
703
- with importlib.resources.as_file(
704
- importlib.resources.files("vortex.algo")
705
- ) as path:
706
- tplpath = path / "mpitools_templates" / self._wrapstd_wrapper_tpl
707
- wtpl = config.load_template(tplpath, encoding="utf-8")
703
+ with importlib.resources.path(
704
+ "vortex.algo.mpitools_templates",
705
+ self._wrapstd_wrapper_tpl,
706
+ ) as tplpath:
707
+ wtpl = config.load_template(tplpath, encoding="utf-8")
708
708
  with open(self._wrapstd_wrapper_name, "w", encoding="utf-8") as fhw:
709
709
  fhw.write(
710
710
  wtpl.substitute(
@@ -911,11 +911,11 @@ class MpiTool(footprints.FootprintBase):
911
911
  "Here are the envelope details:\n%s", "\n".join(binding_str)
912
912
  )
913
913
  # Create the launchwrapper
914
- with importlib.resources.as_file(
915
- importlib.resources.files("vortex.algo")
916
- ) as path:
917
- tplpath = path / "mpitools_templates" / self._envelope_wrapper_tpl
918
- wtpl = config.load_template(tplpath, encoding="utf-8")
914
+ with importlib.resources.path(
915
+ "vortex.algo.mpitools_templates",
916
+ self._envelope_wrapper_tpl,
917
+ ) as tplpath:
918
+ wtpl = config.load_template(tplpath, encoding="utf-8")
919
919
  with open(self._envelope_wrapper_name, "w", encoding="utf-8") as fhw:
920
920
  fhw.write(
921
921
  wtpl.substitute(
@@ -0,0 +1 @@
1
+ # Empty init file
vortex/data/handlers.py CHANGED
@@ -5,6 +5,7 @@ the various caches or archives".
5
5
  """
6
6
 
7
7
  import functools
8
+ import importlib
8
9
  import re
9
10
  import sys
10
11
 
@@ -1116,18 +1117,23 @@ class Handler:
1116
1117
  self,
1117
1118
  pr_getter=None,
1118
1119
  tplfile=None,
1119
- tplskip="@sync-skip.tpl",
1120
- tplfetch="@sync-fetch.tpl",
1121
1120
  py_exec=sys.executable,
1122
1121
  py_opts="",
1123
1122
  ):
1124
1123
  """Build a getter for the expected resource."""
1125
1124
  if tplfile is None:
1126
- tplfile = tplfetch if self.is_expected() else tplskip
1125
+ tplfile = (
1126
+ "sync-" + ("fetch" if self.is_expected() else "skip") + ".tpl"
1127
+ )
1128
+ with importlib.resources.path(
1129
+ "vortex.data.sync_templates",
1130
+ tplfile,
1131
+ ) as tplpath:
1132
+ tpl = config.load_template(tplpath)
1127
1133
  if pr_getter is None:
1128
1134
  pr_getter = self.container.localpath() + ".getpr"
1129
1135
  t = self._cur_session
1130
- tpl = config.load_template(t, tplfile)
1136
+
1131
1137
  with open(pr_getter, "w", encoding="utf-8") as fd:
1132
1138
  fd.write(
1133
1139
  tpl.substitute(
vortex/data/stores.py CHANGED
@@ -527,6 +527,10 @@ class _VortexBaseArchiveStore(ArchiveStore, _VortexStackedStorageMixin):
527
527
  """Remap actual remote path to distant store path for intrusive actions."""
528
528
  raise NotImplementedError
529
529
 
530
+ def remap_write(self, remote, options):
531
+ """Remap actual remote path to distant store path for intrusive actions."""
532
+ raise NotImplementedError
533
+
530
534
  def remap_list(self, remote, options):
531
535
  """Reformulates the remote path to compatible vortex namespace."""
532
536
  if len(remote["path"].split("/")) >= 4:
@@ -537,8 +541,6 @@ class _VortexBaseArchiveStore(ArchiveStore, _VortexStackedStorageMixin):
537
541
  )
538
542
  return None
539
543
 
540
- remap_write = remap_read
541
-
542
544
  @property
543
545
  def stacks_autorefill(self):
544
546
  """Where to refill a stack retrieved from the archive."""
@@ -755,6 +757,8 @@ class VortexStdBaseArchiveStore(_VortexBaseArchiveStore):
755
757
  raise e
756
758
  return remote
757
759
 
760
+ remap_write = remap_read
761
+
758
762
 
759
763
  class VortexStdStackedArchiveStore(VortexStdBaseArchiveStore):
760
764
  """Archive for casual VORTEX experiments: Support for legacy/Olive XPIDs.
@@ -1105,16 +1109,10 @@ class VortexCacheStore(_AbstractVortexCacheMultiStore):
1105
1109
 
1106
1110
  def alternates_netloc(self):
1107
1111
  """For Non-Op users, Op caches may be accessed in read-only mode."""
1108
- netloc_m = re.match(
1109
- r"(?P<base>vortex.*)\.cache\.(?P<country>\w+)", self.netloc
1110
- )
1111
- mt_netloc = "{base:s}.cache-mt.{country:s}".format(
1112
- **netloc_m.groupdict()
1113
- )
1114
- s_mt_netloc = "{base:s}.stacked-cache-mt.{country:s}".format(
1115
- **netloc_m.groupdict()
1116
- )
1117
- return [mt_netloc, s_mt_netloc]
1112
+ return [
1113
+ f"{self.netloc.firstname}.cache-mt.fr",
1114
+ f"{self.netloc.firstname}.stacked-cache-mt.fr",
1115
+ ]
1118
1116
 
1119
1117
 
1120
1118
  class VortexVsopCacheStore(_AbstractVortexCacheMultiStore):
@@ -1219,13 +1217,7 @@ class VortexStackStore(_AbstractVortexStackMultiStore):
1219
1217
 
1220
1218
  def alternates_netloc(self):
1221
1219
  """Go through the various stacked stores."""
1222
- netloc_m = re.match(
1223
- r"(?P<base>vortex.*)\.stack\.(?P<country>\w+)", self.netloc
1224
- )
1225
- s_mt_netloc = "{base:s}.stacked-cache-mt.{country:s}".format(
1226
- **netloc_m.groupdict()
1227
- )
1228
- return [s_mt_netloc]
1220
+ return [f"{self.netloc.firstname}.stacked-cache-mt.fr"]
1229
1221
 
1230
1222
 
1231
1223
  class VortexVsopStackStore(_AbstractVortexStackMultiStore):
File without changes
@@ -283,21 +283,12 @@ class LAMForecast(Forecast):
283
283
  values=["lamfc", "lamforecast"],
284
284
  remap=dict(lamforecast="lamfc"),
285
285
  ),
286
- synctool=dict(
287
- info="The name of the script called when waiting for coupling files",
288
- optional=True,
289
- default="atcp.alad",
290
- doc_visibility=footprints.doc.visibility.ADVANCED,
291
- ),
292
- synctpl=dict(
293
- info="The template used to generate the *synctool* script",
294
- optional=True,
295
- default="@sync-fetch.tpl",
296
- doc_visibility=footprints.doc.visibility.ADVANCED,
297
- ),
298
286
  ),
299
287
  )
300
288
 
289
+ synctool = "atcp.alad"
290
+ synctpl = "sync-fetch.tpl"
291
+
301
292
  def spawn_command_options(self):
302
293
  """Dictionary provided for command line factory."""
303
294
  return dict(
@@ -341,10 +332,11 @@ class LAMForecast(Forecast):
341
332
  )
342
333
  sh.softlink(thisbound, lbcnc(number=i))
343
334
  if self.mksync:
344
- thistool = self.synctool + ".{:03d}".format(i)
345
- bound.mkgetpr(pr_getter=thistool, tplfetch=self.synctpl)
335
+ bound.mkgetpr(
336
+ pr_getter=self.synctool + ".{:03d}".format(i),
337
+ )
346
338
  if firstsync is None:
347
- firstsync = thistool
339
+ firstsync = self.synctool + ".{:03d}".format(i)
348
340
 
349
341
  # Set up the first synchronization step
350
342
  if firstsync is not None:
@@ -120,6 +120,11 @@ class IFSParallel(
120
120
  """Extend default tag with ``kind`` value."""
121
121
  return super().fstag() + "." + self.kind
122
122
 
123
+ def _mpitool_attributes(self, opts):
124
+ conf_dict = super()._mpitool_attributes(opts)
125
+ conf_dict.update({"mplbased": True})
126
+ return conf_dict
127
+
123
128
  def valid_executable(self, rh):
124
129
  """Be sure that the specifed executable is ifsmodel compatible."""
125
130
  valid = super().valid_executable(rh)
@@ -57,6 +57,11 @@ class OdbMonitoring(
57
57
  )
58
58
  )
59
59
 
60
+ def _mpitool_attributes(self, opts):
61
+ conf_dict = super()._mpitool_attributes(opts)
62
+ conf_dict.update({"mplbased": True})
63
+ return conf_dict
64
+
60
65
  def _fix_nam_macro(self, rh, macro, value):
61
66
  """Set a given namelist macro and issue a log message."""
62
67
  rh.contents.setmacro(macro, value)
@@ -64,18 +64,28 @@ class MpiAuto(mpitools.MpiTool):
64
64
  ),
65
65
  bindingmethod=dict(
66
66
  info="How to bind the MPI processes",
67
- values=["arch", "launcherspecific", "vortex"],
67
+ values=["vortex", "arch", "launcherspecific"],
68
68
  optional=True,
69
69
  doc_visibility=footprints.doc.visibility.ADVANCED,
70
70
  doc_zorder=-90,
71
71
  ),
72
+ mplbased=dict(
73
+ info="Is the executable based on MPL?",
74
+ type=bool,
75
+ optional=True,
76
+ default=False,
77
+ ),
72
78
  )
73
79
  )
74
80
 
75
- _envelope_wrapper_tpl = "@envelope_wrapper_mpiauto.tpl"
81
+ _envelope_wrapper_tpl = "envelope_wrapper_mpiauto.tpl"
76
82
  _envelope_rank_var = "MPIAUTORANK"
77
83
  _needs_mpilib_specific_mpienv = False
78
84
 
85
+ def __init__(self, *args, **kwargs):
86
+ super().__init__(*args, **kwargs)
87
+ self.bindingmethod = "arch" if self.mplbased else "vortex"
88
+
79
89
  def _reshaped_mpiopts(self):
80
90
  """Raw list of mpi tool command line options."""
81
91
  options = super()._reshaped_mpiopts()
@@ -850,6 +850,11 @@ class OdbAverage(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin):
850
850
  )
851
851
  )
852
852
 
853
+ def _mpitool_attributes(self, opts):
854
+ conf_dict = super()._mpitool_attributes(opts)
855
+ conf_dict.update({"mplbased": True})
856
+ return conf_dict
857
+
853
858
  def prepare(self, rh, opts):
854
859
  """Find any ODB candidate in input files."""
855
860
 
@@ -962,6 +967,11 @@ class OdbCompress(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin):
962
967
  )
963
968
  )
964
969
 
970
+ def _mpitool_attributes(self, opts):
971
+ conf_dict = super()._mpitool_attributes(opts)
972
+ conf_dict.update({"mplbased": True})
973
+ return conf_dict
974
+
965
975
  def prepare(self, rh, opts):
966
976
  """Find any ODB candidate in input files and fox ODB env accordingly."""
967
977
 
@@ -1027,6 +1037,11 @@ class OdbMatchup(Parallel, odb.OdbComponentDecoMixin, drhook.DrHookDecoMixin):
1027
1037
  )
1028
1038
  )
1029
1039
 
1040
+ def _mpitool_attributes(self, opts):
1041
+ conf_dict = super()._mpitool_attributes(opts)
1042
+ conf_dict.update({"mplbased": True})
1043
+ return conf_dict
1044
+
1030
1045
  def prepare(self, rh, opts):
1031
1046
  """Find ODB candidates in input files."""
1032
1047
 
@@ -1116,6 +1131,11 @@ class OdbReshuffle(
1116
1131
  _OUT_DIRECTORY = "reshuffled"
1117
1132
  _BARE_OUT_LAYOUT = "ccma"
1118
1133
 
1134
+ def _mpitool_attributes(self, opts):
1135
+ conf_dict = super()._mpitool_attributes(opts)
1136
+ conf_dict.update({"mplbased": True})
1137
+ return conf_dict
1138
+
1119
1139
  def prepare(self, rh, opts):
1120
1140
  """Find ODB candidates in input files."""
1121
1141
 
@@ -619,6 +619,11 @@ class OOPSParallel(
619
619
  logger.error("The binary < %s > has no cycle attribute", repr(rh))
620
620
  return False
621
621
 
622
+ def _mpitool_attributes(self, opts):
623
+ conf_dict = super()._mpitool_attributes(opts)
624
+ conf_dict.update({"mplbased": True})
625
+ return conf_dict
626
+
622
627
  def prepare(self, rh, opts):
623
628
  """Preliminary setups."""
624
629
  super().prepare(rh, opts)
vortex/tools/actions.py CHANGED
@@ -10,8 +10,6 @@ to be processed: e.g. mail, routing, alarm.
10
10
  import bronx.stdtypes.catalog
11
11
  import footprints
12
12
  from bronx.fancies import loggers
13
- from bronx.fancies.display import dict_as_str
14
- from vortex import sessions
15
13
 
16
14
  #: Export nothing
17
15
  __all__ = []
@@ -134,105 +132,30 @@ class Action:
134
132
  class TunableAction(Action):
135
133
  """An Action that may be tuned
136
134
 
137
- - may have it's own section in the target configuration files
138
- - accepts the syntax `ad.action_tune(key=value)` (which has priority)
135
+ accepts the syntax `ad.action_tune(key=value)` (which has priority)
139
136
  """
140
137
 
141
138
  def __init__(self, configuration=None, **kwargs):
142
139
  super().__init__(**kwargs)
143
140
  self._tuning = dict()
144
- self._conf_section = configuration
145
- self._conf_dict = None
146
-
147
- @property
148
- def _shtarget(self):
149
- """Warning: this may be a `vortex.syntax.stdattrs.DelayedInit` object
150
- during Vortex initialization and may not have a `sections()` method
151
- nor a `config` property.
152
- """
153
- return sessions.current().sh.default_target
154
-
155
- @property
156
- def _conf_items(self):
157
- """Check and return the configuration: a section in the target-xxx.ini file.
158
-
159
- If the configuration is None, an attempt is made to use the Action's kind.
160
- Don't use before Vortex initialization is done (see `_shtarget`).
161
- """
162
- if self._conf_dict is None:
163
- if self._conf_section is None:
164
- if self.kind in self._shtarget.sections():
165
- self._conf_section = self.kind
166
- else:
167
- if self._conf_section not in self._shtarget.sections():
168
- raise KeyError(
169
- 'No section "{}" in "{}"'.format(
170
- self._conf_section, self._shtarget.config.file
171
- )
172
- )
173
- if self._conf_section is None:
174
- self._conf_dict = dict()
175
- else:
176
- self._conf_dict = self._shtarget.items(self._conf_section)
177
- return self._conf_dict
178
141
 
179
142
  def service_info(self, **kw):
180
- for k, v in self._get_config_dict().items():
143
+ for k, v in self._tuning.items():
181
144
  kw.setdefault(k, v)
182
145
  return super().service_info(**kw)
183
146
 
184
- def tune(self, section=None, **kw):
185
- """Add options to override the .ini file configuration.
186
-
187
- ``section`` is a specific section name, or ``None`` for all.
188
- """
189
- if section is None or section == self._conf_section:
190
- self._tuning.update(kw)
191
-
192
- def _get_config_dict(self):
193
- final_dict = dict()
194
- final_dict.update(self._conf_items)
195
- final_dict.update(self._tuning)
196
- return final_dict
197
-
198
- def info(self):
199
- """Informative string (may serve debugging purposes)."""
200
- s = super().info() + " - tunable\n"
201
- mix = dict()
202
- mix.update(self._conf_items)
203
- mix.update(self._tuning)
204
- prt = dict()
205
- for k, v in mix.items():
206
- if k in self._tuning:
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
- )
213
- else:
214
- prt[" " + k] = v
215
- if self._conf_section is not None:
216
- s += " " * 4 + "configuration: " + self._conf_section + "\n"
217
- s += dict_as_str(prt, prefix=4)
218
- return s.strip()
147
+ def tune(self, **kw):
148
+ self._tuning.update(kw)
219
149
 
220
150
  def getx(self, key, *args, **kw):
221
151
  """Shortcut to access the configuration overridden by the tuning."""
222
152
  if key in self._tuning:
223
153
  return self._tuning[key]
224
154
 
225
- if self._conf_section is not None:
226
- return self._shtarget.getx(
227
- key=self._conf_section + ":" + key, *args, **kw
228
- )
229
-
230
155
  if "default" in kw:
231
156
  return kw["default"]
232
157
 
233
- raise KeyError(
234
- 'The "{:s}" entry was not found in any configuration'.format(key)
235
- )
158
+ raise KeyError('The "{:s}" entry was not found'.format(key))
236
159
 
237
160
 
238
161
  class SendMail(Action):
vortex/tools/grib.py CHANGED
@@ -10,6 +10,7 @@ It also provdes an AlgoComponent's Mixin to properly setup the environment
10
10
  when using the grib_api or ecCodes libraries.
11
11
  """
12
12
 
13
+ from pathlib import Path
13
14
  from urllib import parse as urlparse
14
15
 
15
16
  import re
@@ -563,37 +564,41 @@ class EcGribDecoMixin(AlgoComponentDecoMixin):
563
564
  "After gribapi_setup %s = %s", a_var, self.env.getvar(a_var)
564
565
  )
565
566
 
566
- def _eccodes_envsetup(self, eccodes_lib):
567
- """Setup environment variables for ecCodes."""
568
- dep_warn = (
569
- "%s is left unconfigured because the old grib_api's variable is defined."
570
- + "Please remove that !"
567
+ def _eccodes_envsetup(
568
+ self,
569
+ eccodes_lib,
570
+ envvar="ECCODES_DEFINITIONS_PATH",
571
+ tgt_path="definitions",
572
+ ):
573
+ """Export envirionment variables required by ECCODES
574
+
575
+ Value is
576
+
577
+ /path/to/eccodes-X.Y.Z/share/eccodes/<target_path>
578
+
579
+ eccodes_lib: Absolute path to the eccodes so file
580
+ envvar: Name of the environment variable to export
581
+ tgt_path: Name of the eccodes install subdirectory to appear
582
+ in the value
583
+ """
584
+ if envvar in self.env:
585
+ return envvar
586
+ if envvar.replace("ECCODES", "GRIB") in self.env:
587
+ logger.warning(
588
+ (
589
+ "%s is left unconfigured because the old grib_api's"
590
+ "variable is defined. ",
591
+ "Please remove that!",
592
+ ),
593
+ envvar,
594
+ )
595
+ return envvar.replace("ECCODES", "GRIB")
596
+ eccodes_root = Path(eccodes_lib).parent.parent
597
+ self.env.setgenericpath(
598
+ envvar,
599
+ str(eccodes_root / "share" / "eccodes" / tgt_path),
571
600
  )
572
- eccodes_root = self.system.path.dirname(eccodes_lib)
573
- eccodes_root = self.system.path.split(eccodes_root)[0]
574
- eccodes_share = self.system.path.join(eccodes_root, "share", "eccodes")
575
- defvar = "ECCODES_DEFINITION_PATH"
576
- if defvar not in self.env:
577
- if "GRIB_DEFINITION_PATH" in self.env:
578
- logger.warning(dep_warn, defvar)
579
- defvar = "GRIB_DEFINITION_PATH"
580
- else:
581
- self.env.setgenericpath(
582
- defvar, self.system.path.join(eccodes_share, "definitions")
583
- )
584
- samplevar = "ECCODES_SAMPLES_PATH"
585
- if samplevar not in self.env:
586
- if "GRIB_SAMPLES_PATH" in self.env:
587
- logger.warning(dep_warn, samplevar)
588
- samplevar = "GRIB_SAMPLES_PATH"
589
- else:
590
- self.env.setgenericpath(
591
- samplevar,
592
- self.system.path.join(
593
- eccodes_share, "ifs_samples", "grib1"
594
- ),
595
- )
596
- return defvar, samplevar
601
+ return envvar
597
602
 
598
603
  def eccodes_setup(self, rh, opts, compat=False, fatal=True):
599
604
  """Setup the grib_api related stuff.
@@ -605,7 +610,19 @@ class EcGribDecoMixin(AlgoComponentDecoMixin):
605
610
  # Detect the library's path and setup appropriate variables
606
611
  eccodes_lib, gribapi_lib = self._ecgrib_libs_detext(rh)
607
612
  if eccodes_lib is not None:
608
- defvar, samplevar = self._eccodes_envsetup(eccodes_lib)
613
+ defvar = self._eccodes_envsetup(
614
+ eccodes_lib,
615
+ envvar="ECCODES_DEFINITIONS_PATH",
616
+ tgt_path="definitions",
617
+ )
618
+ subdir = Path("ifs_samples") / (
619
+ "grib1" if rh.resource.cycle < "cy49" else "grib1_mlgrib2"
620
+ )
621
+ samplevar = self._eccodes_envsetup(
622
+ eccodes_lib,
623
+ envvar="ECCODES_SAMPLES_PATH",
624
+ tgt_path=subdir,
625
+ )
609
626
  elif compat:
610
627
  defvar, samplevar = self._gribapi_envsetup(gribapi_lib)
611
628
  else:
vortex/tools/net.py CHANGED
@@ -26,6 +26,8 @@ from bronx.fancies import loggers
26
26
  from bronx.net.netrc import netrc
27
27
  from bronx.syntax.decorators import nicedeco, secure_getattr
28
28
 
29
+ from vortex.config import get_from_config_w_default, ConfigurationError
30
+
29
31
  #: No automatic export
30
32
  __all__ = []
31
33
 
@@ -1192,15 +1194,35 @@ class Ssh:
1192
1194
  self._logname = logname
1193
1195
  self._remote = hostname
1194
1196
 
1195
- target = sh.default_target
1196
- self._sshcmd = target.get(key="services:sshcmd", default="ssh")
1197
- self._scpcmd = target.get(key="services:scpcmd", default="scp")
1197
+ def _get_ssh_config(key, default):
1198
+ config = get_from_config_w_default(
1199
+ section="ssh", key=key, default=default
1200
+ )
1201
+ try:
1202
+ val = config.pop("default")
1203
+ except AttributeError:
1204
+ assert isinstance(config, str)
1205
+ return config
1206
+ except KeyError:
1207
+ msg = (
1208
+ "A default value must be specified for configuration option"
1209
+ f" {key}. See vortex-nwp.readthedocs.io/en/latest/user-guide/configuration.html#ssh"
1210
+ )
1211
+ raise ConfigurationError(msg)
1212
+
1213
+ for k, v in config.items():
1214
+ if re.match(k, socket.gethostname()):
1215
+ val = v
1216
+ return val
1217
+
1218
+ self._sshcmd = _get_ssh_config(key="sshcmd", default="ssh")
1219
+ self._scpcmd = _get_ssh_config(key="scpcmd", default="scp")
1198
1220
  self._sshopts = (
1199
- target.get(key="services:sshopts", default="-x").split()
1221
+ _get_ssh_config(key="sshopts", default="").split()
1200
1222
  + (sshopts or "").split()
1201
1223
  )
1202
1224
  self._scpopts = (
1203
- target.get(key="services:scpopts", default="-Bp").split()
1225
+ _get_ssh_config(key="scpopts", default="").split()
1204
1226
  + (scpopts or "").split()
1205
1227
  )
1206
1228
 
vortex/tools/services.py CHANGED
@@ -20,7 +20,6 @@ from bronx.stdtypes.dictionaries import UpperCaseDict
20
20
  from bronx.syntax.pretty import EncodedPrettyPrinter
21
21
  from vortex import sessions
22
22
  from vortex.util.config import (
23
- GenericConfigParser,
24
23
  load_template,
25
24
  LegacyTemplatingAdapter,
26
25
  )
@@ -563,7 +562,8 @@ class Directory:
563
562
 
564
563
  def __init__(self, inifile, domain="meteo.fr", encoding=None):
565
564
  """Keep aliases in memory, as a dict of sets."""
566
- config = GenericConfigParser(inifile, encoding=encoding)
565
+ config = configparser.ConfigParser()
566
+ config.read(inifile, encoding=encoding)
567
567
  try:
568
568
  self.domain = config.get("general", "default_domain")
569
569
  except configparser.NoOptionError:
vortex/tools/systems.py CHANGED
@@ -68,6 +68,7 @@ from vortex.tools.env import Environment
68
68
  from vortex.tools.net import AssistedSsh, AutoRetriesFtp, DEFAULT_FTP_PORT
69
69
  from vortex.tools.net import FtpConnectionPool, LinuxNetstats, StdFtp
70
70
  import vortex.tools.storage
71
+ from vortex import config
71
72
 
72
73
  #: No automatic export
73
74
  __all__ = []
@@ -800,7 +801,7 @@ class OSExtended(System):
800
801
 
801
802
  * **rmtreemin** - as the minimal depth needed for a :meth:`rmsafe`.
802
803
  * **cmpaftercp** - as a boolean for activating full comparison after plain cp (default: *True*).
803
- * **ftraw** - allows ``smartft*`` methods to use the raw FTP commands
804
+ * **ftserv** - allows ``smartft*`` methods to use the raw FTP commands
804
805
  (e.g. ftget, ftput) instead of the internal Vortex's FTP client
805
806
  (default: *False*).
806
807
  * **ftputcmd** - The name of the raw FTP command for the "put" action
@@ -815,7 +816,7 @@ class OSExtended(System):
815
816
  self._rmtreemin = kw.pop("rmtreemin", 3)
816
817
  self._cmpaftercp = kw.pop("cmpaftercp", True)
817
818
  # Switches for rawft* methods
818
- self._ftraw = kw.pop("ftraw", None)
819
+ self._ftserv = kw.pop("ftserv", None)
819
820
  self.ftputcmd = kw.pop("ftputcmd", None)
820
821
  self.ftgetcmd = kw.pop("ftgetcmd", None)
821
822
  # FTP stuff again
@@ -838,23 +839,33 @@ class OSExtended(System):
838
839
  self._signal_intercept_init()
839
840
 
840
841
  @property
841
- def ftraw(self):
842
+ def ftserv(self):
842
843
  """Use the system's FTP service (e.g. ftserv)."""
843
- if self._ftraw is None:
844
- return self.default_target.ftraw_default
844
+ if self._ftserv is None:
845
+ return self._use_ftserv()
845
846
  else:
846
- return self._ftraw
847
+ return self._ftserv
847
848
 
848
- @ftraw.setter
849
- def ftraw(self, value):
849
+ @ftserv.setter
850
+ def ftserv(self, value):
850
851
  """Use the system's FTP service (e.g. ftserv)."""
851
852
  self._ftraw = bool(value)
852
853
 
853
- @ftraw.deleter
854
- def ftraw(self):
854
+ @ftserv.deleter
855
+ def ftserv(self):
855
856
  """Use the system's FTP service (e.g. ftserv)."""
856
857
  self._ftraw = None
857
858
 
859
+ def _use_ftserv(self):
860
+ if not config.is_defined(section="ftserv"):
861
+ return False
862
+ for rgxp in config.from_config(
863
+ section="ftserv", key="hostname_patterns"
864
+ ):
865
+ if re.match(rgxp, self.hostname):
866
+ return True
867
+ return False
868
+
858
869
  def target(self, **kw):
859
870
  """
860
871
  Provide a default :class:`~vortex.tools.targets.Target` according
@@ -2064,7 +2075,7 @@ class OSExtended(System):
2064
2075
 
2065
2076
  def rawftput_worthy(self, source, destination):
2066
2077
  """Is it allowed to use FtServ given **source** and **destination**."""
2067
- return self.ftraw and self.ftserv_allowed(source, destination)
2078
+ return self.ftserv and self.ftserv_allowed(source, destination)
2068
2079
 
2069
2080
  @fmtshcmd
2070
2081
  def rawftput(
@@ -2145,7 +2156,7 @@ class OSExtended(System):
2145
2156
 
2146
2157
  ``rawftput`` will be used if all of the following conditions are met:
2147
2158
 
2148
- * ``self.ftraw`` is *True*
2159
+ * ``self.ftserv`` is *True*
2149
2160
  * **source** is a string (as opposed to a File like object)
2150
2161
  * **destination** is a string (as opposed to a File like object)
2151
2162
  """
@@ -2177,7 +2188,7 @@ class OSExtended(System):
2177
2188
  def rawftget_worthy(self, source, destination, cpipeline=None):
2178
2189
  """Is it allowed to use FtServ given **source** and **destination**."""
2179
2190
  return (
2180
- self.ftraw
2191
+ self.ftserv
2181
2192
  and cpipeline is None
2182
2193
  and self.ftserv_allowed(source, destination)
2183
2194
  )
@@ -2259,7 +2270,7 @@ class OSExtended(System):
2259
2270
 
2260
2271
  ``rawftget`` will be used if all of the following conditions are met:
2261
2272
 
2262
- * ``self.ftraw`` is *True*
2273
+ * ``self.ftserv`` is *True*
2263
2274
  * **cpipeline** is None
2264
2275
  * **source** is a string (as opposed to a File like object)
2265
2276
  * **destination** is a string (as opposed to a File like object)
vortex/util/config.py CHANGED
@@ -164,7 +164,8 @@ def load_template(tplpath, encoding=None, default_templating="legacy"):
164
164
  """
165
165
  tplpath = Path(tplpath).absolute()
166
166
  if not tplpath.exists():
167
- raise FileNotFoundError
167
+ msg = f"Template file {tplpath} not found"
168
+ raise FileNotFoundError(msg)
168
169
  ignored_lines = set()
169
170
  actual_encoding = None if encoding == "script" else encoding
170
171
  actual_templating = default_templating
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: vortex-nwp
3
- Version: 2.0.0b2
3
+ Version: 2.1.0
4
4
  Summary: A Python library to write Numerical Weather Prediction pipelines components
5
5
  Author-email: The Vortex Team <vortex.support@meteo.fr>
6
6
  License: CECILL-C
@@ -21,6 +21,7 @@ Requires-Dist: sphinx-copybutton; extra == "docs"
21
21
  Provides-Extra: dev
22
22
  Requires-Dist: ruff==0.9.1; extra == "dev"
23
23
  Requires-Dist: pytest; extra == "dev"
24
+ Dynamic: license-file
24
25
 
25
26
  ## vortex
26
27
 
@@ -1,13 +1,14 @@
1
- vortex/__init__.py,sha256=EqLyspeGun2xW4een6ezLsh2APXX8DHphhGnu6TdMcQ,3921
1
+ vortex/__init__.py,sha256=2D7c4cUOF2Eb4m2rCKxhttmBy5R_7Xb3iBCLcy51vkw,4352
2
2
  vortex/config.py,sha256=E7feBIG22POq5TyUN3MNXH-ZU7q08alF5nrJ1aUftG0,2815
3
3
  vortex/gloves.py,sha256=GKz27S8eLfRlk8fNqVL_z1gsQ8zvEj73p5uVi11ou00,8487
4
4
  vortex/proxy.py,sha256=OlPrVUJS5FoKt5pX8ApN1crFFDj8RJAqhDEilwvfrYU,127
5
5
  vortex/sessions.py,sha256=l_ZUUFS-l0J2Mg6KEXaUQiDhbIABrWCfcY-9ExazKEg,9988
6
6
  vortex/toolbox.py,sha256=h2QE5BoXWWEcQwK21D9YPda6t4rmCtLB5F9WeJrqT14,41379
7
7
  vortex/algo/__init__.py,sha256=I_9COn_QBRbwvbqhs0X3CdHeR97NZhBacIqwKjnVBTg,359
8
- vortex/algo/components.py,sha256=pD_-Lyhl8iVy3ERK7QTCkq00tHIblImofxYVv8C1LH4,89342
9
- vortex/algo/mpitools.py,sha256=kxq9sjvC8bt7RDxNEi7lvpByXhtPEg3Rr4xaADbeipw,74063
8
+ vortex/algo/components.py,sha256=zs_DaKHFEHX9GQ-pn1HheAo4JvNusQi3D4u3ZhqVqe4,89362
9
+ vortex/algo/mpitools.py,sha256=EffZ4Ok934tvEYyUjKpVA-lEUVA29FwUVBtUQ8xWnDI,73977
10
10
  vortex/algo/serversynctools.py,sha256=fPel0txVHsrUfk6VFaeKa0D6i21fOskIAR_BbByBv9g,5601
11
+ vortex/algo/mpitools_templates/__init__.py,sha256=Jbw903aPqVKF-AaSoB-mGMxthSvm88O_yqGoGmf_S_U,18
11
12
  vortex/algo/mpitools_templates/envelope_wrapper_default.tpl,sha256=4VhkDx_YbOYywKQ82HIxRJXGcDpLuOgqcY7Edx9Rxyw,453
12
13
  vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl,sha256=iB4_4jz-7QDqpl6AxrlCACsotJnEMG75dtazuGfkCb4,514
13
14
  vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl,sha256=hh1Um95FIuvXAhUTMifAfixtfGgyjF1vEaF1nmbqMLw,502
@@ -19,11 +20,12 @@ vortex/data/executables.py,sha256=FeR3SA2wW97zAQXwWVecZ0v6VYT5L_3K1Czuv33Bk74,67
19
20
  vortex/data/flow.py,sha256=P1itBnA8jaoCWnVQjqbD_Pf26rpzud1JdwSLECDnDl4,3008
20
21
  vortex/data/geometries.ini,sha256=J7hX5hYWqwBjdUAul6q8j10U6b3I-QEHrFJ98LBTQXM,52805
21
22
  vortex/data/geometries.py,sha256=SjCF-74zDkbpt3qQujJU_UpeoBtgS7-xrEhbC4ywyRE,27429
22
- vortex/data/handlers.py,sha256=9TIu6wjuN2X64AOprqVc_uSkzRfyOvym6MHG2l1QOAQ,47426
23
+ vortex/data/handlers.py,sha256=6tRfCw9yzQCndVhRjz3ia0dyYhV3F7_rWeXjoxBtbvs,47550
23
24
  vortex/data/outflow.py,sha256=IPKJkn75lRvhSqN5969TuhRAPnsZKlrWR4Cmw6VBFDs,1475
24
25
  vortex/data/providers.py,sha256=kLHJI3F9mkRjRcQzs0xaH_cdfvXd9H4x5h1Lm4PGSFk,15652
25
26
  vortex/data/resources.py,sha256=UOwvQDTJxS9z66Aa7JM2nWM3IxrMWvY3L2J9D5w3sZw,6348
26
- vortex/data/stores.py,sha256=YIRl0YgpslR7IFUasX3NWzy-Q3oswZ_EcyzGYVampyE,44777
27
+ vortex/data/stores.py,sha256=5svCgpE8WuuAWCnOrrHOBw30EOt0cvDoxrlq9rIWKOw,44517
28
+ vortex/data/sync_templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
29
  vortex/layout/__init__.py,sha256=aZsDhVJrd3-648vw-UESI_2BLxyGl71sHdyrg9cL638,826
28
30
  vortex/layout/contexts.py,sha256=GkysEtOOUj3nQvGUWrFjOOjzv7SmWFPUSLTH_pMMycI,20363
29
31
  vortex/layout/dataflow.py,sha256=SKOUJKbtftW4POStjyBqNrqjvfbutsNHnWQ-p_75l_8,44792
@@ -35,14 +37,14 @@ vortex/nwp/algo/clim.py,sha256=Z9QwUfosH0X_xTg6mam68qWIvw6Ts6CZIpc7Nb0NO1s,37511
35
37
  vortex/nwp/algo/coupling.py,sha256=6KQ_YB7PCvVbt6c2VEtpCzwIyWRTjLfu54mNpKnXL9Q,29755
36
38
  vortex/nwp/algo/eda.py,sha256=Wf2mt1r6v_ZYDz4BFyt-4JP1XAsO8sZW3O1UAOSRzmU,30746
37
39
  vortex/nwp/algo/eps.py,sha256=JCBFiaFF9TQ-x7Szgw44Cd39tRD9184UXqOtoT6aRCs,26812
38
- vortex/nwp/algo/forecasts.py,sha256=vI6NOH8-RciIz47LlzEK1u-jvA2LHJHAULVlu8vcxb0,30518
40
+ vortex/nwp/algo/forecasts.py,sha256=sqs0IETanpfS8q1f1Pl3mQZtSNbfOIUOidmcduGp8EU,30063
39
41
  vortex/nwp/algo/fpserver.py,sha256=98HQZsdQE22spy_mIE1G-NORQMMjfA5grEjeIMSlP9w,50163
40
42
  vortex/nwp/algo/ifsnaming.py,sha256=WfpSpRJ7ua3ihqv8Y4UkrvE4pb0CkNWKIlW9EjY-2ao,11188
41
- vortex/nwp/algo/ifsroot.py,sha256=j8uu3pMt9GF5od6DuocXvjugVFs1ovuJrwFuFgXx99E,14064
42
- vortex/nwp/algo/monitoring.py,sha256=QwmE9wuyNi0tpAWig3X6Z1uGg-h5k4VZ9v4BdajH344,8727
43
- vortex/nwp/algo/mpitools.py,sha256=TRnOwb2yzp7mGT4Sw5elSwJVpADnAISGlRSSlK_Rf9I,24539
44
- vortex/nwp/algo/odbtools.py,sha256=RZwxn8HNZ17qqsgvPSlWjW5cF6hnClUC_iv43XQRFXc,43430
45
- vortex/nwp/algo/oopsroot.py,sha256=03SCYVbaDo-ydwpJl97yHWGkIYxduZEGphLgvc9DEoU,33640
43
+ vortex/nwp/algo/ifsroot.py,sha256=Mmp0sZtexP5ob3iUFTiVbgVWog7ubAYPut0cAB0vbbg,14230
44
+ vortex/nwp/algo/monitoring.py,sha256=JVPZPw_I5QRVtYvvSYpJpBy5RRPhqBQjcAFfIkvKuHA,8893
45
+ vortex/nwp/algo/mpitools.py,sha256=QO3I9iMdY69znnA6hJy8XUAzBoejDpsVMQFRo3YzXro,24876
46
+ vortex/nwp/algo/odbtools.py,sha256=xltXS1lpxeeJXeCGnFiqFUhGqMI6BlZzKcSLhsnd2cs,44094
47
+ vortex/nwp/algo/oopsroot.py,sha256=es3p7RPOixQT74TcglJX1q8MswxveVnLZa84kyhu3uM,33806
46
48
  vortex/nwp/algo/oopstests.py,sha256=owQAS7_fGbUGZGzMsJek32dbb3JQ6dafSVBrdmveQ-Q,6654
47
49
  vortex/nwp/algo/request.py,sha256=y5N9RUfKoPXR6EbSely37Zz6d-2HYyfV3UCvvoenqbY,22809
48
50
  vortex/nwp/algo/stdpost.py,sha256=kpZrP6s92PrrAWyLrf61bSidwkJzC3M6sxrmpete3S0,54824
@@ -101,7 +103,7 @@ vortex/syntax/__init__.py,sha256=q0eJcJ1gRbSrALTC8UaORRrHNmRxVUpbTNB1_uQbJi0,288
101
103
  vortex/syntax/stdattrs.py,sha256=OosTS6hdGGh1r5rwZNngmMb6zFj0NUrFZmYs7lDbysY,20927
102
104
  vortex/syntax/stddeco.py,sha256=Y94wAf-zEQr8RUmF_OUZkBKO1fPZnx3ju2g3DnPl9cw,6411
103
105
  vortex/tools/__init__.py,sha256=KPsj7iqvy-vlo3WEIx8PmbqJYVDXCzZZdDSbMlqDq0k,482
104
- vortex/tools/actions.py,sha256=BrPDuYXKiGChRVtjXVhLyEGls0-AP6C8TaeTMiQwPyo,16001
106
+ vortex/tools/actions.py,sha256=yPzKccxHqtTI67SaYLIWJeo0s302WSXEJVpfxt6hAAU,13113
105
107
  vortex/tools/addons.py,sha256=vTfAXEz0zrFDGUbrFxwgBO67enrE2mmLbKKlakLSNpI,10439
106
108
  vortex/tools/arm.py,sha256=jl--2QOkhHkRXlxpZgo4E3Zw7Z_Gnr4z1fjPnPNyuyc,3112
107
109
  vortex/tools/compression.py,sha256=dTXX1VrzxEj1qoBDKbB_T-_8X9iGHOlPaseczfu8cuw,11221
@@ -110,23 +112,23 @@ vortex/tools/ddhpack.py,sha256=tOcQ5XQ7yTFBlisyjANDPMPQPijvHwz8yWY1eBfZMAs,206
110
112
  vortex/tools/delayedactions.py,sha256=miw6q5L5eOaxtLXhPIJlVs5Mi8vMXuIx55dY2TtU8BU,27126
111
113
  vortex/tools/env.py,sha256=ka7VaM3D5XuMRxja7oWA-eLgsUFqtWOmPvfbyHBi8Ps,18460
112
114
  vortex/tools/folder.py,sha256=R3bQtwnyn01WzkF3NdzJKb2tCkAPWYB61Bb90r0B09I,27992
113
- vortex/tools/grib.py,sha256=wReKDpWpTCrbiVUZKZaQdo8_YBzRLIJp0GvpEtkiHTw,25458
115
+ vortex/tools/grib.py,sha256=aH1y2LZDRBn3TywXsVZlxTRk6kdShMVgbHJTpGcfMGU,25700
114
116
  vortex/tools/lfi.py,sha256=9mvXL-R5PQtTut7gsSMGJa0iNqpNgOFp7yuEMqYGIBA,29681
115
117
  vortex/tools/listings.py,sha256=LTfQHjT0XlK3Hxewbi06HZQjKhALmg0Gvz69UooOFog,15123
116
118
  vortex/tools/names.py,sha256=Knb2YsUsEjGpODBva1kEOBXRM2d_H0ylHwp-OoO3mnY,21644
117
- vortex/tools/net.py,sha256=MWamIGwm52qDpRhpxMP1BihsyZW4SwoPl6hg0GgX7WA,73734
119
+ vortex/tools/net.py,sha256=jLablaFdAy80BybYT4Ki-LWgbpqpzMj4SG8m4CLvuN8,74535
118
120
  vortex/tools/odb.py,sha256=TZ1Qq8QmFIh3OP-bsgnwPuHPdfMKNXUAfhc-KSx9tZQ,193
119
121
  vortex/tools/parallelism.py,sha256=f4uBp37Q3BG71Qn1yy_YSTPdk-2ZZ7zoGRQsGm6pT1Y,12345
120
122
  vortex/tools/prestaging.py,sha256=lGJIo4SA8pDziF1nbBogsrK1bgwDQA6tj9Wg9VUFt6Q,7078
121
123
  vortex/tools/rawfiles.py,sha256=keUI6QtEZQrWQ7H_Sg_TY9SY32anfb-suqJkrDmdXN0,215
122
124
  vortex/tools/schedulers.py,sha256=XduOQab1dRiHwz7Mnt3mxXByGzAHMsDLCwlUOpMdXEk,15828
123
- vortex/tools/services.py,sha256=_cVaHQmwknJmSny6y20BL2M2K68MKN-ydOFtxWn9lPs,29228
125
+ vortex/tools/services.py,sha256=v0uqAOXR9PsXJwv4-_yWpGzFniD7WghXW4p6WwaNtPA,29231
124
126
  vortex/tools/storage.py,sha256=YBhq00j39NipaK1EDovr0VF7EArdpp5AuFx0lqB0_p4,34411
125
127
  vortex/tools/surfex.py,sha256=qbCIGt-dmfIRWRRMjOQnzc9sGNnt8PIFSqQYT77trhw,1408
126
- vortex/tools/systems.py,sha256=yIs-Qy7roVdOAeWas20grfhiw-aeJVZ9JyIvTyu8mro,148751
128
+ vortex/tools/systems.py,sha256=Zu04yTVIZU0hCiRH_STmdGuknjVd8dNsxXWr87k_5aE,149081
127
129
  vortex/tools/targets.py,sha256=-n2uMoEFdz3AeoSd1IGhlr7dYYb8xantUeh9_ggk9iI,14896
128
130
  vortex/util/__init__.py,sha256=Zt0OASbKbNnnwUqFHFoq5Mk13sGYSQhxqh7bUvJH6Y8,198
129
- vortex/util/config.py,sha256=-9fP9ZIJODHBfGE08UhwFB-VyVFstTscgKWibKEUmh0,39989
131
+ vortex/util/config.py,sha256=KJHq0GMNRlwzh2WUdpwn1FIKCuAXla7nPRe7j3IZGcI,40045
130
132
  vortex/util/empty.py,sha256=EYcltpsjGxATAPPAVK2QRq_Bc5tcFLfF34dE1KO1tvk,535
131
133
  vortex/util/helpers.py,sha256=vmz2h3MCL1FElZpn-MX3MX6L_RCQfyqMXTcYWpcYyr4,7492
132
134
  vortex/util/introspection.py,sha256=VWZ6Ntr4fMJD4Xr_q-F7_lMHTSjDpHptnZ3SckBtuYY,2146
@@ -135,8 +137,8 @@ vortex/util/roles.py,sha256=9un_QAijaMn5iTS7PrdoWI5_NNw7uHxMWTnyhc5aNzg,1150
135
137
  vortex/util/storefunctions.py,sha256=uSfG-G_A88iJf3DwFBd-j0rw6eJta8opfRT39aQHsHM,3615
136
138
  vortex/util/structs.py,sha256=vapErq0MNhiKlsnjrv_a5M0Rn29KbP3WE_oiy4Hfwb8,683
137
139
  vortex/util/worker.py,sha256=zp8f2tx4SXwf1v55XMdYLAx7n3vSlg8PRGrkHgnfdmg,4721
138
- vortex_nwp-2.0.0b2.dist-info/LICENSE,sha256=ewBJPmWAcQqtBPrydH10tt6ECkcYP3b1o2RfH85pJF0,21863
139
- vortex_nwp-2.0.0b2.dist-info/METADATA,sha256=bRlOmQfR7sB8u7P5XYTrIHRVWuzCnaG6Zi9ZaoW6Cys,2165
140
- vortex_nwp-2.0.0b2.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
141
- vortex_nwp-2.0.0b2.dist-info/top_level.txt,sha256=3xfbSD7kw8xKl0jk4GNHsOPKbhubstfWHPl6bxHciRQ,7
142
- vortex_nwp-2.0.0b2.dist-info/RECORD,,
140
+ vortex_nwp-2.1.0.dist-info/licenses/LICENSE,sha256=ewBJPmWAcQqtBPrydH10tt6ECkcYP3b1o2RfH85pJF0,21863
141
+ vortex_nwp-2.1.0.dist-info/METADATA,sha256=58Aw65WFk1YubrWljPIRAPiGdMGfjo7JW4DYHEngbBg,2185
142
+ vortex_nwp-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
143
+ vortex_nwp-2.1.0.dist-info/top_level.txt,sha256=3xfbSD7kw8xKl0jk4GNHsOPKbhubstfWHPl6bxHciRQ,7
144
+ vortex_nwp-2.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5