vortex-nwp 2.0.0b1__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 (146) hide show
  1. vortex/__init__.py +135 -0
  2. vortex/algo/__init__.py +12 -0
  3. vortex/algo/components.py +2136 -0
  4. vortex/algo/mpitools.py +1648 -0
  5. vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
  6. vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
  7. vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
  8. vortex/algo/serversynctools.py +170 -0
  9. vortex/config.py +115 -0
  10. vortex/data/__init__.py +13 -0
  11. vortex/data/abstractstores.py +1572 -0
  12. vortex/data/containers.py +780 -0
  13. vortex/data/contents.py +596 -0
  14. vortex/data/executables.py +284 -0
  15. vortex/data/flow.py +113 -0
  16. vortex/data/geometries.ini +2689 -0
  17. vortex/data/geometries.py +703 -0
  18. vortex/data/handlers.py +1021 -0
  19. vortex/data/outflow.py +67 -0
  20. vortex/data/providers.py +465 -0
  21. vortex/data/resources.py +201 -0
  22. vortex/data/stores.py +1271 -0
  23. vortex/gloves.py +282 -0
  24. vortex/layout/__init__.py +27 -0
  25. vortex/layout/appconf.py +109 -0
  26. vortex/layout/contexts.py +511 -0
  27. vortex/layout/dataflow.py +1069 -0
  28. vortex/layout/jobs.py +1276 -0
  29. vortex/layout/monitor.py +833 -0
  30. vortex/layout/nodes.py +1424 -0
  31. vortex/layout/subjobs.py +464 -0
  32. vortex/nwp/__init__.py +11 -0
  33. vortex/nwp/algo/__init__.py +12 -0
  34. vortex/nwp/algo/assim.py +483 -0
  35. vortex/nwp/algo/clim.py +920 -0
  36. vortex/nwp/algo/coupling.py +609 -0
  37. vortex/nwp/algo/eda.py +632 -0
  38. vortex/nwp/algo/eps.py +613 -0
  39. vortex/nwp/algo/forecasts.py +745 -0
  40. vortex/nwp/algo/fpserver.py +927 -0
  41. vortex/nwp/algo/ifsnaming.py +403 -0
  42. vortex/nwp/algo/ifsroot.py +311 -0
  43. vortex/nwp/algo/monitoring.py +202 -0
  44. vortex/nwp/algo/mpitools.py +554 -0
  45. vortex/nwp/algo/odbtools.py +974 -0
  46. vortex/nwp/algo/oopsroot.py +735 -0
  47. vortex/nwp/algo/oopstests.py +186 -0
  48. vortex/nwp/algo/request.py +579 -0
  49. vortex/nwp/algo/stdpost.py +1285 -0
  50. vortex/nwp/data/__init__.py +12 -0
  51. vortex/nwp/data/assim.py +392 -0
  52. vortex/nwp/data/boundaries.py +261 -0
  53. vortex/nwp/data/climfiles.py +539 -0
  54. vortex/nwp/data/configfiles.py +149 -0
  55. vortex/nwp/data/consts.py +929 -0
  56. vortex/nwp/data/ctpini.py +133 -0
  57. vortex/nwp/data/diagnostics.py +181 -0
  58. vortex/nwp/data/eda.py +148 -0
  59. vortex/nwp/data/eps.py +383 -0
  60. vortex/nwp/data/executables.py +1039 -0
  61. vortex/nwp/data/fields.py +96 -0
  62. vortex/nwp/data/gridfiles.py +308 -0
  63. vortex/nwp/data/logs.py +551 -0
  64. vortex/nwp/data/modelstates.py +334 -0
  65. vortex/nwp/data/monitoring.py +220 -0
  66. vortex/nwp/data/namelists.py +644 -0
  67. vortex/nwp/data/obs.py +748 -0
  68. vortex/nwp/data/oopsexec.py +72 -0
  69. vortex/nwp/data/providers.py +182 -0
  70. vortex/nwp/data/query.py +217 -0
  71. vortex/nwp/data/stores.py +147 -0
  72. vortex/nwp/data/surfex.py +338 -0
  73. vortex/nwp/syntax/__init__.py +9 -0
  74. vortex/nwp/syntax/stdattrs.py +375 -0
  75. vortex/nwp/tools/__init__.py +10 -0
  76. vortex/nwp/tools/addons.py +35 -0
  77. vortex/nwp/tools/agt.py +55 -0
  78. vortex/nwp/tools/bdap.py +48 -0
  79. vortex/nwp/tools/bdcp.py +38 -0
  80. vortex/nwp/tools/bdm.py +21 -0
  81. vortex/nwp/tools/bdmp.py +49 -0
  82. vortex/nwp/tools/conftools.py +1311 -0
  83. vortex/nwp/tools/drhook.py +62 -0
  84. vortex/nwp/tools/grib.py +268 -0
  85. vortex/nwp/tools/gribdiff.py +99 -0
  86. vortex/nwp/tools/ifstools.py +163 -0
  87. vortex/nwp/tools/igastuff.py +249 -0
  88. vortex/nwp/tools/mars.py +56 -0
  89. vortex/nwp/tools/odb.py +548 -0
  90. vortex/nwp/tools/partitioning.py +234 -0
  91. vortex/nwp/tools/satrad.py +56 -0
  92. vortex/nwp/util/__init__.py +6 -0
  93. vortex/nwp/util/async.py +184 -0
  94. vortex/nwp/util/beacon.py +40 -0
  95. vortex/nwp/util/diffpygram.py +359 -0
  96. vortex/nwp/util/ens.py +198 -0
  97. vortex/nwp/util/hooks.py +128 -0
  98. vortex/nwp/util/taskdeco.py +81 -0
  99. vortex/nwp/util/usepygram.py +591 -0
  100. vortex/nwp/util/usetnt.py +87 -0
  101. vortex/proxy.py +6 -0
  102. vortex/sessions.py +341 -0
  103. vortex/syntax/__init__.py +9 -0
  104. vortex/syntax/stdattrs.py +628 -0
  105. vortex/syntax/stddeco.py +176 -0
  106. vortex/toolbox.py +982 -0
  107. vortex/tools/__init__.py +11 -0
  108. vortex/tools/actions.py +457 -0
  109. vortex/tools/addons.py +297 -0
  110. vortex/tools/arm.py +76 -0
  111. vortex/tools/compression.py +322 -0
  112. vortex/tools/date.py +20 -0
  113. vortex/tools/ddhpack.py +10 -0
  114. vortex/tools/delayedactions.py +672 -0
  115. vortex/tools/env.py +513 -0
  116. vortex/tools/folder.py +663 -0
  117. vortex/tools/grib.py +559 -0
  118. vortex/tools/lfi.py +746 -0
  119. vortex/tools/listings.py +354 -0
  120. vortex/tools/names.py +575 -0
  121. vortex/tools/net.py +1790 -0
  122. vortex/tools/odb.py +10 -0
  123. vortex/tools/parallelism.py +336 -0
  124. vortex/tools/prestaging.py +186 -0
  125. vortex/tools/rawfiles.py +10 -0
  126. vortex/tools/schedulers.py +413 -0
  127. vortex/tools/services.py +871 -0
  128. vortex/tools/storage.py +1061 -0
  129. vortex/tools/surfex.py +61 -0
  130. vortex/tools/systems.py +3396 -0
  131. vortex/tools/targets.py +384 -0
  132. vortex/util/__init__.py +9 -0
  133. vortex/util/config.py +1071 -0
  134. vortex/util/empty.py +24 -0
  135. vortex/util/helpers.py +184 -0
  136. vortex/util/introspection.py +63 -0
  137. vortex/util/iosponge.py +76 -0
  138. vortex/util/roles.py +51 -0
  139. vortex/util/storefunctions.py +103 -0
  140. vortex/util/structs.py +26 -0
  141. vortex/util/worker.py +150 -0
  142. vortex_nwp-2.0.0b1.dist-info/LICENSE +517 -0
  143. vortex_nwp-2.0.0b1.dist-info/METADATA +50 -0
  144. vortex_nwp-2.0.0b1.dist-info/RECORD +146 -0
  145. vortex_nwp-2.0.0b1.dist-info/WHEEL +5 -0
  146. vortex_nwp-2.0.0b1.dist-info/top_level.txt +1 -0
vortex/data/outflow.py ADDED
@@ -0,0 +1,67 @@
1
+ """
2
+ Abstract class for any model specific and/or domain specific "Resource".
3
+
4
+ * :class:`StaticGeoResource`: Specific to an horizontal geometry;
5
+ * :class:`ModelResource`: Specific to a a given model;
6
+ * :class:`ModelGeoResource`: Specific to a a given model and horizontal geometry.
7
+
8
+ """
9
+
10
+ from .resources import Resource
11
+ from .geometries import hgeometry_deco
12
+ from .contents import FormatAdapter
13
+ from vortex.syntax.stdattrs import model_deco
14
+
15
+ #: No automatic export
16
+ __all__ = []
17
+
18
+
19
+ class StaticResource(Resource):
20
+
21
+ _abstract = True
22
+ _footprint = dict(
23
+ attr = dict(
24
+ kind = dict(
25
+ info = "The resource's kind.",
26
+ doc_zorder = 90,
27
+ ),
28
+ )
29
+ )
30
+
31
+
32
+ class StaticGeoResource(StaticResource):
33
+ """A :class:`ModelResource` bound to a geometry."""
34
+
35
+ _abstract = True
36
+ _footprint = [
37
+ hgeometry_deco,
38
+ dict(
39
+ attr = dict(
40
+ clscontents = dict(
41
+ default = FormatAdapter,
42
+ ),
43
+ )
44
+ )
45
+ ]
46
+
47
+
48
+ class ModelResource(StaticResource):
49
+
50
+ _abstract = True
51
+ _footprint = [model_deco, ]
52
+
53
+
54
+ class ModelGeoResource(ModelResource):
55
+ """A :class:`ModelResource` bound to a geometry."""
56
+
57
+ _abstract = True
58
+ _footprint = [
59
+ hgeometry_deco,
60
+ dict(
61
+ attr = dict(
62
+ clscontents = dict(
63
+ default = FormatAdapter,
64
+ ),
65
+ )
66
+ )
67
+ ]
@@ -0,0 +1,465 @@
1
+ """
2
+ Abstract and generic classes provider for any "Provider". "Provider" objects,
3
+ describe where are stored the data.
4
+
5
+ Of course, the :class:`Vortex` abstract provider is a must see. It has three
6
+ declinations depending on the experiment indentifier type.
7
+ """
8
+
9
+ import collections
10
+ import operator
11
+ import os.path
12
+ import re
13
+ from urllib import parse as urlparse
14
+ import warnings
15
+
16
+ from bronx.fancies import loggers
17
+ from bronx.syntax.parsing import StringDecoder
18
+ import footprints
19
+ from footprints import proxy as fpx
20
+ from footprints.stdtypes import FPDict
21
+
22
+ from vortex import sessions
23
+ from vortex import config
24
+ from vortex.syntax.stdattrs import xpid, legacy_xpid, free_xpid, opsuites, \
25
+ demosuites, scenario, member, block
26
+ from vortex.syntax.stdattrs import LegacyXPid, any_vortex_xpid
27
+ from vortex.syntax.stdattrs import namespacefp, Namespace, FmtInt
28
+ from vortex.tools import net, names
29
+ from vortex.util.config import GenericConfigParser
30
+
31
+ #: No automatic export
32
+ __all__ = ['Provider']
33
+
34
+ logger = loggers.getLogger(__name__)
35
+
36
+
37
+ class Provider(footprints.FootprintBase):
38
+ """Abstract class for any Provider."""
39
+
40
+ _abstract = True
41
+ _collector = ('provider',)
42
+ _footprint = dict(
43
+ info = 'Abstract root provider',
44
+ attr = dict(
45
+ vapp = dict(
46
+ info = "The application's identifier.",
47
+ alias = ('application',),
48
+ optional = True,
49
+ default = '[glove::vapp]',
50
+ doc_zorder = -10
51
+ ),
52
+ vconf = dict(
53
+ info = "The configuration's identifier.",
54
+ alias = ('configuration',),
55
+ optional = True,
56
+ default = '[glove::vconf]',
57
+ doc_zorder = -10
58
+ ),
59
+ username = dict(
60
+ info = "The username that will be used whenever necessary.",
61
+ optional = True,
62
+ default = None,
63
+ alias = ('user', 'logname')
64
+ ),
65
+ ),
66
+ fastkeys = {'namespace'},
67
+ )
68
+
69
+ def __init__(self, *args, **kw):
70
+ logger.debug('Abstract provider init %s', self.__class__)
71
+ super().__init__(*args, **kw)
72
+
73
+ def _str_more(self):
74
+ """Additional information to print representation."""
75
+ try:
76
+ return 'namespace=\'{:s}\''.format(self.namespace)
77
+ except AttributeError:
78
+ return super()._str_more()
79
+
80
+ @property
81
+ def realkind(self):
82
+ return 'provider'
83
+
84
+ def scheme(self, resource):
85
+ """Abstract method."""
86
+ pass
87
+
88
+ def netloc(self, resource):
89
+ """Abstract method."""
90
+ pass
91
+
92
+ def netuser_name(self, resource): # @UnusedVariable
93
+ """Abstract method."""
94
+ return self.username
95
+
96
+ def pathname(self, resource):
97
+ """Abstract method."""
98
+ pass
99
+
100
+ def pathinfo(self, resource):
101
+ """Delegates to resource eponym method."""
102
+ return resource.pathinfo(self.realkind)
103
+
104
+ def basename(self, resource):
105
+ """Delegates to resource eponym method."""
106
+ return resource.basename(self.realkind)
107
+
108
+ def urlquery(self, resource):
109
+ """Delegates to resource eponym method."""
110
+ return resource.urlquery(self.realkind)
111
+
112
+ def uri(self, resource):
113
+ """
114
+ Create an uri adapted to a vortex resource so as to allow the element
115
+ in charge of retrieving the real resource to be able to locate and
116
+ retreive it. The method used to achieve this action:
117
+
118
+ * obtain the proto information,
119
+ * ask for the netloc,
120
+ * get the pathname,
121
+ * get the basename.
122
+
123
+ The different operations of the algorithm can be redefined by subclasses.
124
+ """
125
+ username = self.netuser_name(resource)
126
+ fullnetloc = ('{:s}@{:s}'.format(username, self.netloc(resource)) if username
127
+ else self.netloc(resource))
128
+ logger.debug(
129
+ 'scheme %s netloc %s normpath %s urlquery %s',
130
+ self.scheme(resource),
131
+ fullnetloc,
132
+ os.path.normpath(self.pathname(resource) + '/' + self.basename(resource)),
133
+ self.urlquery(resource)
134
+ )
135
+
136
+ return net.uriunparse((
137
+ self.scheme(resource),
138
+ fullnetloc,
139
+ os.path.normpath(self.pathname(resource) + '/' + self.basename(resource)),
140
+ None,
141
+ self.urlquery(resource),
142
+ None
143
+ ))
144
+
145
+
146
+ class Magic(Provider):
147
+
148
+ _footprint = [
149
+ xpid,
150
+ dict(
151
+ info = 'Magic provider that always returns the same URI.',
152
+ attr = dict(
153
+ fake = dict(
154
+ info = "Enable this magic provider.",
155
+ alias = ('nowhere', 'noprovider'),
156
+ type = bool,
157
+ optional = True,
158
+ default = True,
159
+ ),
160
+ magic = dict(
161
+ info = "The URI returned by this provider."
162
+ ),
163
+ experiment = dict(
164
+ optional = True,
165
+ doc_visibility = footprints.doc.visibility.ADVANCED,
166
+ ),
167
+ vapp = dict(
168
+ doc_visibility = footprints.doc.visibility.GURU,
169
+ ),
170
+ vconf = dict(
171
+ doc_visibility = footprints.doc.visibility.GURU,
172
+ ),
173
+ ),
174
+ fastkeys = {'magic'},
175
+ )
176
+ ]
177
+
178
+ @property
179
+ def realkind(self):
180
+ return 'magic'
181
+
182
+ def uri(self, resource):
183
+ """URI is supposed to be the magic value !"""
184
+ return self.magic
185
+
186
+
187
+ class Remote(Provider):
188
+
189
+ _footprint = dict(
190
+ info = 'Provider that manipulates data given a real path',
191
+ attr = dict(
192
+ remote = dict(
193
+ info = 'The path to the data.',
194
+ alias = ('remfile', 'rempath'),
195
+ doc_zorder = 50
196
+ ),
197
+ hostname = dict(
198
+ info = 'The hostname that holds the data.',
199
+ optional = True,
200
+ default = 'localhost'
201
+ ),
202
+ tube = dict(
203
+ info = "The protocol used to access the data.",
204
+ optional = True,
205
+ values = ['scp', 'ftp', 'rcp', 'file', 'symlink'],
206
+ default = 'file',
207
+ ),
208
+ vapp = dict(
209
+ doc_visibility = footprints.doc.visibility.GURU,
210
+ ),
211
+ vconf = dict(
212
+ doc_visibility = footprints.doc.visibility.GURU,
213
+ ),
214
+ ),
215
+ fastkeys = {'remote'},
216
+ )
217
+
218
+ def __init__(self, *args, **kw):
219
+ logger.debug('Remote provider init %s', self.__class__)
220
+ super().__init__(*args, **kw)
221
+
222
+ @property
223
+ def realkind(self):
224
+ return 'remote'
225
+
226
+ def _str_more(self):
227
+ """Additional information to print representation."""
228
+ return 'path=\'{:s}\''.format(self.remote)
229
+
230
+ def scheme(self, resource):
231
+ """The Remote scheme is its tube."""
232
+ return self.tube
233
+
234
+ def netloc(self, resource):
235
+ """Fully qualified network location."""
236
+ return self.hostname
237
+
238
+ def pathname(self, resource):
239
+ """OS dirname of the ``remote`` attribute."""
240
+ return os.path.dirname(self.remote)
241
+
242
+ def basename(self, resource):
243
+ """OS basename of the ``remote`` attribute."""
244
+ return os.path.basename(self.remote)
245
+
246
+ def urlquery(self, resource):
247
+ """Check for relative path or not."""
248
+ if self.remote.startswith('/'):
249
+ return None
250
+ else:
251
+ return 'relative=1'
252
+
253
+
254
+ def set_namespace_from_cache_settings(usecache, usearchive):
255
+ usecache = True if (usecache is None) else usecache
256
+ usearchive = True if (usearchive is None) else usearchive
257
+
258
+ # Default usearchive to False is no storage section is defined in
259
+ # the configuration file
260
+ if not config.is_defined(section="storage"):
261
+ usearchive = False
262
+
263
+ if not (usecache or usearchive):
264
+ # Let caller raise appropriate exception
265
+ return None
266
+
267
+ if usecache and usearchive:
268
+ domain = "multi"
269
+ if usecache and not usearchive:
270
+ domain = "cache"
271
+ if not usecache and usearchive:
272
+ domain = "archive"
273
+ return ".".join(("vortex", domain, "fr"))
274
+
275
+
276
+ class Vortex(Provider):
277
+ """Main provider of the toolbox, using a fix-size path and a dedicated name factory."""
278
+
279
+ _DEFAULT_NAME_BUILDER = names.VortexNameBuilder()
280
+ _CUSTOM_NAME_BUILDERS = dict()
281
+
282
+ _footprint = [
283
+ block,
284
+ member,
285
+ scenario,
286
+ namespacefp,
287
+ dict(
288
+ info = 'Vortex provider',
289
+ attr = dict(
290
+ experiment = dict(
291
+ info = "Provider experiment id",
292
+ type = str,
293
+ optional = False,
294
+ access = "rwx",
295
+ ),
296
+ member = dict(
297
+ type = FmtInt,
298
+ args = dict(fmt = '03'),
299
+ ),
300
+ namespace = dict(
301
+ values = [
302
+ 'vortex.cache.fr', 'vortex.archive.fr', 'vortex.multi.fr', 'vortex.stack.fr',
303
+ 'open.cache.fr', 'open.archive.fr', 'open.multi.fr', 'open.stack.fr',
304
+ ],
305
+ remap = {
306
+ 'open.cache.fr': 'vortex.cache.fr',
307
+ 'open.archive.fr': 'vortex.archive.fr',
308
+ 'open.multi.fr': 'vortex.multi.fr',
309
+ 'open.stack.fr': 'vortex.stack.fr',
310
+ },
311
+ optional = True,
312
+ default = None,
313
+ access = "rwx",
314
+ ),
315
+ cache = dict(
316
+ info = "Whether or not to use the cache",
317
+ type = bool,
318
+ optional = True,
319
+ default = None,
320
+ ),
321
+ archive = dict(
322
+ info = "Whether or not to use the archive",
323
+ type = bool,
324
+ optional = True,
325
+ default = None,
326
+ ),
327
+ namebuild = dict(
328
+ info = "The object responsible for building filenames.",
329
+ optional = True,
330
+ doc_visibility = footprints.doc.visibility.ADVANCED,
331
+ ),
332
+ expected = dict(
333
+ info = "Is the resource expected ?",
334
+ alias = ('promised',),
335
+ type = bool,
336
+ optional = True,
337
+ default = False,
338
+ doc_zorder = -5,
339
+ ),
340
+ ),
341
+ fastkeys = {'block', 'experiment'},
342
+ )
343
+ ]
344
+
345
+ def __init__(self, *args, **kw):
346
+ logger.debug('Vortex experiment provider init %s', self.__class__)
347
+ super().__init__(*args, **kw)
348
+ if self.namebuild is not None:
349
+ if self.namebuild not in self._CUSTOM_NAME_BUILDERS:
350
+ builder = fpx.vortexnamebuilder(name=self.namebuild)
351
+ if builder is None:
352
+ raise ValueError("The << {:s} >> name builder does not exists."
353
+ .format(self.namebuild))
354
+ self._CUSTOM_NAME_BUILDERS[self.namebuild] = builder
355
+ self._namebuilder = self._CUSTOM_NAME_BUILDERS[self.namebuild]
356
+ else:
357
+ self._namebuilder = self._DEFAULT_NAME_BUILDER
358
+ if self.experiment in ("oper", "dble"):
359
+ self.experiment = self.experiment.upper()
360
+
361
+ # Ensure compatibility with deprecated namespace attribute
362
+ # Under the hood the namespace attribute is still used to
363
+ # define caching behaviour -- it's passed to the store __init__ --
364
+ # but it's value is set from the value of the newly introduced
365
+ # attributes 'cache' and 'archive'.
366
+
367
+ # If 'namespace' is specified and either 'cache' and/or 'archive'
368
+ # are specified, 'namespace' is ignored
369
+ if self.namespace and (self.cache or self.archive):
370
+ logger.warning(
371
+ f"Ignoring attribute \"namespace\" set to {self.namespace} "
372
+ "as attribute(s) cache and/or archive are specified"
373
+ )
374
+ if self.namespace and ((self.cache is None) and (self.archive is None)):
375
+ warnings.warn(
376
+ "Using attribute \"namespace\" is deprecated, use \"cache\""
377
+ "and/or \"archive\" instead.",
378
+ category=DeprecationWarning,
379
+ )
380
+ else:
381
+ self.namespace = set_namespace_from_cache_settings(
382
+ self.cache, self.archive,
383
+ )
384
+ if not self.namespace:
385
+ raise ValueError(
386
+ "Attributes \"cache\" and \"archive\" cannot be "
387
+ "both specified as \"False\"."
388
+ )
389
+
390
+ @property
391
+ def namebuilder(self):
392
+ return self._namebuilder
393
+
394
+ @property
395
+ def realkind(self):
396
+ return 'vortex'
397
+
398
+ def actual_experiment(self, resource):
399
+ return self.experiment
400
+
401
+ def _str_more(self):
402
+ """Additional information to print representation."""
403
+ try:
404
+ return 'namespace=\'{:s}\' block=\'{:s}\''.format(self.namespace, self.block)
405
+ except AttributeError:
406
+ return super()._str_more()
407
+
408
+ def scheme(self, resource):
409
+ """Default: ``vortex``."""
410
+ return 'x' + self.realkind if self.expected else self.realkind
411
+
412
+ def netloc(self, resource):
413
+ """Returns the current ``namespace``."""
414
+ if self.experiment in ("OPER", "DBLE"):
415
+ return "vsop." + self.namespace.domain
416
+ return self.namespace.netloc
417
+
418
+ def _pathname_info(self, resource):
419
+ """Return all the necessary informations to build a pathname."""
420
+ rinfo = resource.namebuilding_info()
421
+ rinfo.update(
422
+ vapp=self.vapp,
423
+ vconf=self.vconf,
424
+ experiment=self.actual_experiment(resource),
425
+ block=self.block,
426
+ member=self.member,
427
+ scenario=self.scenario,
428
+ )
429
+ return rinfo
430
+
431
+ def pathname(self, resource):
432
+ """Constructs pathname of the ``resource`` according to :func:`namebuilding_info`."""
433
+ return self.namebuilder.pack_pathname(self._pathname_info(resource))
434
+
435
+ def basename(self, resource):
436
+ """
437
+ Constructs basename according to current ``namebuild`` factory
438
+ and resource :func:`~vortex.data.resources.Resource.namebuilding_info`.
439
+ """
440
+ return self.namebuilder.pack_basename(resource.namebuilding_info())
441
+
442
+ def urlquery(self, resource):
443
+ """Construct the urlquery (taking into account stacked storage)."""
444
+ s_urlquery = super().urlquery(resource)
445
+ if s_urlquery:
446
+ uqs = urlparse.parse_qs(super().urlquery(resource))
447
+ else:
448
+ uqs = dict()
449
+ # Deal with stacked storage
450
+ stackres, keepmember = resource.stackedstorage_resource()
451
+ if stackres:
452
+ stackpathinfo = self._pathname_info(stackres)
453
+ stackpathinfo['block'] = 'stacks'
454
+ if not keepmember:
455
+ stackpathinfo['member'] = None
456
+ uqs['stackpath'] = [(self.namebuilder.pack_pathname(stackpathinfo) + '/' +
457
+ self.basename(stackres)), ]
458
+ uqs['stackfmt'] = [stackres.nativefmt, ]
459
+ return urlparse.urlencode(sorted(uqs.items()), doseq=True)
460
+
461
+
462
+ # Activate the footprint's fasttrack on the resources collector
463
+ fcollect = footprints.collectors.get(tag='provider')
464
+ fcollect.fasttrack = ('namespace', )
465
+ del fcollect