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