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.
- vortex/__init__.py +135 -0
- vortex/algo/__init__.py +12 -0
- vortex/algo/components.py +2136 -0
- vortex/algo/mpitools.py +1648 -0
- vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
- vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
- vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
- vortex/algo/serversynctools.py +170 -0
- vortex/config.py +115 -0
- vortex/data/__init__.py +13 -0
- vortex/data/abstractstores.py +1572 -0
- vortex/data/containers.py +780 -0
- vortex/data/contents.py +596 -0
- vortex/data/executables.py +284 -0
- vortex/data/flow.py +113 -0
- vortex/data/geometries.ini +2689 -0
- vortex/data/geometries.py +703 -0
- vortex/data/handlers.py +1021 -0
- vortex/data/outflow.py +67 -0
- vortex/data/providers.py +465 -0
- vortex/data/resources.py +201 -0
- vortex/data/stores.py +1271 -0
- vortex/gloves.py +282 -0
- vortex/layout/__init__.py +27 -0
- vortex/layout/appconf.py +109 -0
- vortex/layout/contexts.py +511 -0
- vortex/layout/dataflow.py +1069 -0
- vortex/layout/jobs.py +1276 -0
- vortex/layout/monitor.py +833 -0
- vortex/layout/nodes.py +1424 -0
- vortex/layout/subjobs.py +464 -0
- vortex/nwp/__init__.py +11 -0
- vortex/nwp/algo/__init__.py +12 -0
- vortex/nwp/algo/assim.py +483 -0
- vortex/nwp/algo/clim.py +920 -0
- vortex/nwp/algo/coupling.py +609 -0
- vortex/nwp/algo/eda.py +632 -0
- vortex/nwp/algo/eps.py +613 -0
- vortex/nwp/algo/forecasts.py +745 -0
- vortex/nwp/algo/fpserver.py +927 -0
- vortex/nwp/algo/ifsnaming.py +403 -0
- vortex/nwp/algo/ifsroot.py +311 -0
- vortex/nwp/algo/monitoring.py +202 -0
- vortex/nwp/algo/mpitools.py +554 -0
- vortex/nwp/algo/odbtools.py +974 -0
- vortex/nwp/algo/oopsroot.py +735 -0
- vortex/nwp/algo/oopstests.py +186 -0
- vortex/nwp/algo/request.py +579 -0
- vortex/nwp/algo/stdpost.py +1285 -0
- vortex/nwp/data/__init__.py +12 -0
- vortex/nwp/data/assim.py +392 -0
- vortex/nwp/data/boundaries.py +261 -0
- vortex/nwp/data/climfiles.py +539 -0
- vortex/nwp/data/configfiles.py +149 -0
- vortex/nwp/data/consts.py +929 -0
- vortex/nwp/data/ctpini.py +133 -0
- vortex/nwp/data/diagnostics.py +181 -0
- vortex/nwp/data/eda.py +148 -0
- vortex/nwp/data/eps.py +383 -0
- vortex/nwp/data/executables.py +1039 -0
- vortex/nwp/data/fields.py +96 -0
- vortex/nwp/data/gridfiles.py +308 -0
- vortex/nwp/data/logs.py +551 -0
- vortex/nwp/data/modelstates.py +334 -0
- vortex/nwp/data/monitoring.py +220 -0
- vortex/nwp/data/namelists.py +644 -0
- vortex/nwp/data/obs.py +748 -0
- vortex/nwp/data/oopsexec.py +72 -0
- vortex/nwp/data/providers.py +182 -0
- vortex/nwp/data/query.py +217 -0
- vortex/nwp/data/stores.py +147 -0
- vortex/nwp/data/surfex.py +338 -0
- vortex/nwp/syntax/__init__.py +9 -0
- vortex/nwp/syntax/stdattrs.py +375 -0
- vortex/nwp/tools/__init__.py +10 -0
- vortex/nwp/tools/addons.py +35 -0
- vortex/nwp/tools/agt.py +55 -0
- vortex/nwp/tools/bdap.py +48 -0
- vortex/nwp/tools/bdcp.py +38 -0
- vortex/nwp/tools/bdm.py +21 -0
- vortex/nwp/tools/bdmp.py +49 -0
- vortex/nwp/tools/conftools.py +1311 -0
- vortex/nwp/tools/drhook.py +62 -0
- vortex/nwp/tools/grib.py +268 -0
- vortex/nwp/tools/gribdiff.py +99 -0
- vortex/nwp/tools/ifstools.py +163 -0
- vortex/nwp/tools/igastuff.py +249 -0
- vortex/nwp/tools/mars.py +56 -0
- vortex/nwp/tools/odb.py +548 -0
- vortex/nwp/tools/partitioning.py +234 -0
- vortex/nwp/tools/satrad.py +56 -0
- vortex/nwp/util/__init__.py +6 -0
- vortex/nwp/util/async.py +184 -0
- vortex/nwp/util/beacon.py +40 -0
- vortex/nwp/util/diffpygram.py +359 -0
- vortex/nwp/util/ens.py +198 -0
- vortex/nwp/util/hooks.py +128 -0
- vortex/nwp/util/taskdeco.py +81 -0
- vortex/nwp/util/usepygram.py +591 -0
- vortex/nwp/util/usetnt.py +87 -0
- vortex/proxy.py +6 -0
- vortex/sessions.py +341 -0
- vortex/syntax/__init__.py +9 -0
- vortex/syntax/stdattrs.py +628 -0
- vortex/syntax/stddeco.py +176 -0
- vortex/toolbox.py +982 -0
- vortex/tools/__init__.py +11 -0
- vortex/tools/actions.py +457 -0
- vortex/tools/addons.py +297 -0
- vortex/tools/arm.py +76 -0
- vortex/tools/compression.py +322 -0
- vortex/tools/date.py +20 -0
- vortex/tools/ddhpack.py +10 -0
- vortex/tools/delayedactions.py +672 -0
- vortex/tools/env.py +513 -0
- vortex/tools/folder.py +663 -0
- vortex/tools/grib.py +559 -0
- vortex/tools/lfi.py +746 -0
- vortex/tools/listings.py +354 -0
- vortex/tools/names.py +575 -0
- vortex/tools/net.py +1790 -0
- vortex/tools/odb.py +10 -0
- vortex/tools/parallelism.py +336 -0
- vortex/tools/prestaging.py +186 -0
- vortex/tools/rawfiles.py +10 -0
- vortex/tools/schedulers.py +413 -0
- vortex/tools/services.py +871 -0
- vortex/tools/storage.py +1061 -0
- vortex/tools/surfex.py +61 -0
- vortex/tools/systems.py +3396 -0
- vortex/tools/targets.py +384 -0
- vortex/util/__init__.py +9 -0
- vortex/util/config.py +1071 -0
- vortex/util/empty.py +24 -0
- vortex/util/helpers.py +184 -0
- vortex/util/introspection.py +63 -0
- vortex/util/iosponge.py +76 -0
- vortex/util/roles.py +51 -0
- vortex/util/storefunctions.py +103 -0
- vortex/util/structs.py +26 -0
- vortex/util/worker.py +150 -0
- vortex_nwp-2.0.0b1.dist-info/LICENSE +517 -0
- vortex_nwp-2.0.0b1.dist-info/METADATA +50 -0
- vortex_nwp-2.0.0b1.dist-info/RECORD +146 -0
- vortex_nwp-2.0.0b1.dist-info/WHEEL +5 -0
- 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
|
+
]
|
vortex/data/providers.py
ADDED
|
@@ -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
|