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.
- vortex/__init__.py +159 -0
- vortex/algo/__init__.py +13 -0
- vortex/algo/components.py +2462 -0
- vortex/algo/mpitools.py +1953 -0
- vortex/algo/mpitools_templates/__init__.py +1 -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 +171 -0
- vortex/config.py +112 -0
- vortex/data/__init__.py +19 -0
- vortex/data/abstractstores.py +1510 -0
- vortex/data/containers.py +835 -0
- vortex/data/contents.py +622 -0
- vortex/data/executables.py +275 -0
- vortex/data/flow.py +119 -0
- vortex/data/geometries.ini +2689 -0
- vortex/data/geometries.py +799 -0
- vortex/data/handlers.py +1230 -0
- vortex/data/outflow.py +67 -0
- vortex/data/providers.py +487 -0
- vortex/data/resources.py +207 -0
- vortex/data/stores.py +1390 -0
- vortex/data/sync_templates/__init__.py +0 -0
- vortex/gloves.py +309 -0
- vortex/layout/__init__.py +20 -0
- vortex/layout/contexts.py +577 -0
- vortex/layout/dataflow.py +1220 -0
- vortex/layout/monitor.py +969 -0
- vortex/nwp/__init__.py +14 -0
- vortex/nwp/algo/__init__.py +21 -0
- vortex/nwp/algo/assim.py +537 -0
- vortex/nwp/algo/clim.py +1086 -0
- vortex/nwp/algo/coupling.py +831 -0
- vortex/nwp/algo/eda.py +840 -0
- vortex/nwp/algo/eps.py +785 -0
- vortex/nwp/algo/forecasts.py +886 -0
- vortex/nwp/algo/fpserver.py +1303 -0
- vortex/nwp/algo/ifsnaming.py +463 -0
- vortex/nwp/algo/ifsroot.py +404 -0
- vortex/nwp/algo/monitoring.py +263 -0
- vortex/nwp/algo/mpitools.py +694 -0
- vortex/nwp/algo/odbtools.py +1258 -0
- vortex/nwp/algo/oopsroot.py +916 -0
- vortex/nwp/algo/oopstests.py +220 -0
- vortex/nwp/algo/request.py +660 -0
- vortex/nwp/algo/stdpost.py +1641 -0
- vortex/nwp/data/__init__.py +30 -0
- vortex/nwp/data/assim.py +380 -0
- vortex/nwp/data/boundaries.py +314 -0
- vortex/nwp/data/climfiles.py +521 -0
- vortex/nwp/data/configfiles.py +153 -0
- vortex/nwp/data/consts.py +954 -0
- vortex/nwp/data/ctpini.py +149 -0
- vortex/nwp/data/diagnostics.py +209 -0
- vortex/nwp/data/eda.py +147 -0
- vortex/nwp/data/eps.py +432 -0
- vortex/nwp/data/executables.py +1045 -0
- vortex/nwp/data/fields.py +111 -0
- vortex/nwp/data/gridfiles.py +380 -0
- vortex/nwp/data/logs.py +584 -0
- vortex/nwp/data/modelstates.py +363 -0
- vortex/nwp/data/monitoring.py +193 -0
- vortex/nwp/data/namelists.py +696 -0
- vortex/nwp/data/obs.py +840 -0
- vortex/nwp/data/oopsexec.py +74 -0
- vortex/nwp/data/providers.py +207 -0
- vortex/nwp/data/query.py +206 -0
- vortex/nwp/data/stores.py +160 -0
- vortex/nwp/data/surfex.py +337 -0
- vortex/nwp/syntax/__init__.py +9 -0
- vortex/nwp/syntax/stdattrs.py +437 -0
- vortex/nwp/tools/__init__.py +10 -0
- vortex/nwp/tools/addons.py +40 -0
- vortex/nwp/tools/agt.py +67 -0
- vortex/nwp/tools/bdap.py +59 -0
- vortex/nwp/tools/bdcp.py +41 -0
- vortex/nwp/tools/bdm.py +24 -0
- vortex/nwp/tools/bdmp.py +54 -0
- vortex/nwp/tools/conftools.py +1661 -0
- vortex/nwp/tools/drhook.py +66 -0
- vortex/nwp/tools/grib.py +294 -0
- vortex/nwp/tools/gribdiff.py +104 -0
- vortex/nwp/tools/ifstools.py +203 -0
- vortex/nwp/tools/igastuff.py +273 -0
- vortex/nwp/tools/mars.py +68 -0
- vortex/nwp/tools/odb.py +657 -0
- vortex/nwp/tools/partitioning.py +258 -0
- vortex/nwp/tools/satrad.py +71 -0
- vortex/nwp/util/__init__.py +6 -0
- vortex/nwp/util/async.py +212 -0
- vortex/nwp/util/beacon.py +40 -0
- vortex/nwp/util/diffpygram.py +447 -0
- vortex/nwp/util/ens.py +279 -0
- vortex/nwp/util/hooks.py +139 -0
- vortex/nwp/util/taskdeco.py +85 -0
- vortex/nwp/util/usepygram.py +697 -0
- vortex/nwp/util/usetnt.py +101 -0
- vortex/proxy.py +6 -0
- vortex/sessions.py +374 -0
- vortex/syntax/__init__.py +9 -0
- vortex/syntax/stdattrs.py +867 -0
- vortex/syntax/stddeco.py +185 -0
- vortex/toolbox.py +1117 -0
- vortex/tools/__init__.py +20 -0
- vortex/tools/actions.py +523 -0
- vortex/tools/addons.py +316 -0
- vortex/tools/arm.py +96 -0
- vortex/tools/compression.py +325 -0
- vortex/tools/date.py +27 -0
- vortex/tools/ddhpack.py +10 -0
- vortex/tools/delayedactions.py +782 -0
- vortex/tools/env.py +541 -0
- vortex/tools/folder.py +834 -0
- vortex/tools/grib.py +738 -0
- vortex/tools/lfi.py +953 -0
- vortex/tools/listings.py +423 -0
- vortex/tools/names.py +637 -0
- vortex/tools/net.py +2124 -0
- vortex/tools/odb.py +10 -0
- vortex/tools/parallelism.py +368 -0
- vortex/tools/prestaging.py +210 -0
- vortex/tools/rawfiles.py +10 -0
- vortex/tools/schedulers.py +480 -0
- vortex/tools/services.py +940 -0
- vortex/tools/storage.py +996 -0
- vortex/tools/surfex.py +61 -0
- vortex/tools/systems.py +3976 -0
- vortex/tools/targets.py +440 -0
- vortex/util/__init__.py +9 -0
- vortex/util/config.py +1122 -0
- vortex/util/empty.py +24 -0
- vortex/util/helpers.py +216 -0
- vortex/util/introspection.py +69 -0
- vortex/util/iosponge.py +80 -0
- vortex/util/roles.py +49 -0
- vortex/util/storefunctions.py +129 -0
- vortex/util/structs.py +26 -0
- vortex/util/worker.py +162 -0
- vortex_nwp-2.0.0.dist-info/METADATA +67 -0
- vortex_nwp-2.0.0.dist-info/RECORD +144 -0
- vortex_nwp-2.0.0.dist-info/WHEEL +5 -0
- vortex_nwp-2.0.0.dist-info/licenses/LICENSE +517 -0
- vortex_nwp-2.0.0.dist-info/top_level.txt +1 -0
vortex/tools/env.py
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Advanced environment variables management tools.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import collections
|
|
6
|
+
import collections.abc
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
import traceback
|
|
11
|
+
|
|
12
|
+
from bronx.fancies import loggers
|
|
13
|
+
from bronx.stdtypes.history import PrivateHistory
|
|
14
|
+
from vortex.util.structs import ShellEncoder
|
|
15
|
+
|
|
16
|
+
#: No automatic export
|
|
17
|
+
__all__ = []
|
|
18
|
+
|
|
19
|
+
logger = loggers.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
#: Pre-compiled evaluation mostly used by :class:`Environment` method (true).
|
|
22
|
+
vartrue = re.compile(
|
|
23
|
+
r"^\s*(?:[1-9]\d*|ok|on|true|yes|y)\s*$", flags=re.IGNORECASE
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
#: Pre-compiled evaluation mostly used by :class:`Environment` method (false).
|
|
27
|
+
varfalse = re.compile(r"^\s*(?:0|ko|off|false|no|n)\s*$", flags=re.IGNORECASE)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def current():
|
|
31
|
+
"""Return the current active :class:`Environment` object."""
|
|
32
|
+
return Environment.current()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Environment:
|
|
36
|
+
"""
|
|
37
|
+
Advanced handling of environment features. Either for binding to the system
|
|
38
|
+
or to store and broadcast parameters. Activating an environment results
|
|
39
|
+
in the fact that this new environment is binded to the system environment.
|
|
40
|
+
|
|
41
|
+
New objects could be instantiated from an already existing ``env`` and could be
|
|
42
|
+
active or not according to the ``active`` flag given at initialisation time.
|
|
43
|
+
|
|
44
|
+
An :class:`Environment` could be manipulated as an dictionary for the following
|
|
45
|
+
mechanisms:
|
|
46
|
+
|
|
47
|
+
* key access / contains
|
|
48
|
+
* len / keys / values
|
|
49
|
+
* iteration
|
|
50
|
+
* callable
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
_current_active = None
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
env=None,
|
|
59
|
+
active=False,
|
|
60
|
+
clear=False,
|
|
61
|
+
verbose=False,
|
|
62
|
+
noexport=[],
|
|
63
|
+
contextlock=None,
|
|
64
|
+
history=True,
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
:param Environment env: An existing Environment used to initialise this object.
|
|
68
|
+
:param bool active: Is this new environment activated when created.
|
|
69
|
+
:param bool clear: To create an empty environment. (In
|
|
70
|
+
that case the new environment is by default not active).
|
|
71
|
+
:param verbose clear: Activate the verbose mode (every variable exported
|
|
72
|
+
to the system environment will be signalled on stderr).
|
|
73
|
+
:param list[str] noexport: A list of variable names that will never be
|
|
74
|
+
broadcasted to the system environment variables list.
|
|
75
|
+
:param ~vortex.layout.contexts.Context contextlock: The Context
|
|
76
|
+
this environment is associated to. This implies that the
|
|
77
|
+
environment won't activate unless this associated Context is active.
|
|
78
|
+
:param bool history: Record every changes in an
|
|
79
|
+
:class:`~bronx.stdtypes.history.PrivateHistory` object that will be
|
|
80
|
+
accessible through the :attr:`history` property.
|
|
81
|
+
"""
|
|
82
|
+
self.__dict__["_history"] = PrivateHistory() if history else None
|
|
83
|
+
self.__dict__["_verbose"] = verbose
|
|
84
|
+
self.__dict__["_frozen"] = collections.deque()
|
|
85
|
+
self.__dict__["_pool"] = dict()
|
|
86
|
+
self.__dict__["_mods"] = set()
|
|
87
|
+
self.__dict__["_sh"] = None
|
|
88
|
+
self.__dict__["_os"] = list()
|
|
89
|
+
if env is not None and isinstance(env, Environment):
|
|
90
|
+
self._env_clone_internals(env, contextlock)
|
|
91
|
+
if verbose:
|
|
92
|
+
try:
|
|
93
|
+
self.__dict__["_sh"] = env._sh
|
|
94
|
+
except AttributeError:
|
|
95
|
+
pass
|
|
96
|
+
else:
|
|
97
|
+
if clear:
|
|
98
|
+
active = False
|
|
99
|
+
else:
|
|
100
|
+
if self._current_active is not None:
|
|
101
|
+
self._env_clone_internals(
|
|
102
|
+
self._current_active, contextlock
|
|
103
|
+
)
|
|
104
|
+
else:
|
|
105
|
+
self._pool.update(os.environ)
|
|
106
|
+
self.__dict__["_noexport"] = [x.upper() for x in noexport]
|
|
107
|
+
self.active(active)
|
|
108
|
+
|
|
109
|
+
def _env_clone_internals(self, env, contextlock):
|
|
110
|
+
self.__dict__["_os"] = env.osstack()
|
|
111
|
+
self.__dict__["_os"].append(env)
|
|
112
|
+
self._pool.update(env.items())
|
|
113
|
+
if contextlock is not None:
|
|
114
|
+
self.__dict__["_contextlock"] = contextlock
|
|
115
|
+
else:
|
|
116
|
+
self.__dict__["_contextlock"] = env.contextlock
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def history(self):
|
|
120
|
+
"""
|
|
121
|
+
This environment's :class:`~bronx.stdtypes.history.PrivateHistory`
|
|
122
|
+
object (may be ``None``).
|
|
123
|
+
"""
|
|
124
|
+
return self._history
|
|
125
|
+
|
|
126
|
+
def _record(self, var, value):
|
|
127
|
+
if self.history is not None:
|
|
128
|
+
self.history.append(var, value, traceback.format_stack()[:-1])
|
|
129
|
+
|
|
130
|
+
def __str__(self):
|
|
131
|
+
return "{:s} | including {:d} variables>".format(
|
|
132
|
+
repr(self).rstrip(">"), len(self)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
@classmethod
|
|
136
|
+
def current(cls):
|
|
137
|
+
"""Return the current active environment object."""
|
|
138
|
+
return cls._current_active
|
|
139
|
+
|
|
140
|
+
def osstack(self):
|
|
141
|
+
"""Return a list of the environment binding stack."""
|
|
142
|
+
return self._os[:]
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def contextlock(self):
|
|
146
|
+
"""
|
|
147
|
+
The :class:`~vortex.layout.contexts.Context` this environment is bound
|
|
148
|
+
to (this might return None).
|
|
149
|
+
"""
|
|
150
|
+
return self._contextlock
|
|
151
|
+
|
|
152
|
+
def dumps(self, value):
|
|
153
|
+
"""Dump the specified ``value`` as a string (utility function)."""
|
|
154
|
+
if isinstance(value, str):
|
|
155
|
+
obj = str(value)
|
|
156
|
+
elif hasattr(value, "export_dict"):
|
|
157
|
+
obj = value.export_dict()
|
|
158
|
+
elif hasattr(value, "footprint_export"):
|
|
159
|
+
obj = value.footprint_export()
|
|
160
|
+
elif hasattr(value, "__dict__"):
|
|
161
|
+
obj = vars(value)
|
|
162
|
+
else:
|
|
163
|
+
obj = value
|
|
164
|
+
return str(obj)
|
|
165
|
+
|
|
166
|
+
def setvar(self, varname, value, enforce_uppercase=True):
|
|
167
|
+
"""Set uppercase ``varname`` to ``value``.
|
|
168
|
+
|
|
169
|
+
:param bool enforce_uppercase: All variable names are changed to upper case (default).
|
|
170
|
+
|
|
171
|
+
Also used as internal for attribute access or dictionary access.
|
|
172
|
+
"""
|
|
173
|
+
upvar = varname.upper() if enforce_uppercase else varname
|
|
174
|
+
upvar = str(upvar)
|
|
175
|
+
self._pool[upvar] = value
|
|
176
|
+
self._mods.add(upvar)
|
|
177
|
+
self._record(upvar, value)
|
|
178
|
+
if self.osbound():
|
|
179
|
+
if isinstance(value, str):
|
|
180
|
+
actualvalue = str(value)
|
|
181
|
+
else:
|
|
182
|
+
actualvalue = json.dumps(value, cls=ShellEncoder)
|
|
183
|
+
os.environ[upvar] = actualvalue
|
|
184
|
+
if self.verbose():
|
|
185
|
+
if self.osbound() and self._sh:
|
|
186
|
+
self._sh.stderr(
|
|
187
|
+
"export", "{:s}={:s}".format(upvar, actualvalue)
|
|
188
|
+
)
|
|
189
|
+
logger.debug('Env export %s="%s"', upvar, actualvalue)
|
|
190
|
+
|
|
191
|
+
def __setitem__(self, varname, value):
|
|
192
|
+
return self.setvar(varname, value)
|
|
193
|
+
|
|
194
|
+
def __setattr__(self, varname, value):
|
|
195
|
+
return self.setvar(varname, value)
|
|
196
|
+
|
|
197
|
+
def getvar(self, varname):
|
|
198
|
+
"""Get ``varname`` value (this is not case sensitive).
|
|
199
|
+
|
|
200
|
+
Also used as internal for attribute access or dictionary access.
|
|
201
|
+
"""
|
|
202
|
+
varname = str(varname)
|
|
203
|
+
if varname in self._pool:
|
|
204
|
+
return self._pool[varname]
|
|
205
|
+
elif varname.upper() in self._pool:
|
|
206
|
+
return self._pool[varname.upper()]
|
|
207
|
+
else:
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
def __getitem__(self, varname):
|
|
211
|
+
return self.getvar(varname)
|
|
212
|
+
|
|
213
|
+
def __getattr__(self, varname):
|
|
214
|
+
if varname.startswith("_"):
|
|
215
|
+
raise AttributeError
|
|
216
|
+
else:
|
|
217
|
+
return self.getvar(varname)
|
|
218
|
+
|
|
219
|
+
def delvar(self, varname):
|
|
220
|
+
"""
|
|
221
|
+
Delete ``varname`` from current environment (this is not case sensitive).
|
|
222
|
+
|
|
223
|
+
Also used as internal for attribute access or dictionary access.
|
|
224
|
+
"""
|
|
225
|
+
seen = 0
|
|
226
|
+
varname = str(varname)
|
|
227
|
+
if varname in self._pool:
|
|
228
|
+
seen = 1
|
|
229
|
+
del self._pool[varname]
|
|
230
|
+
if varname.upper() in self._pool:
|
|
231
|
+
seen = 1
|
|
232
|
+
del self._pool[varname.upper()]
|
|
233
|
+
if seen and self.osbound():
|
|
234
|
+
del os.environ[varname.upper()]
|
|
235
|
+
if self.verbose() and self._sh:
|
|
236
|
+
self._sh.stderr("unset", "{:s}".format(varname.upper()))
|
|
237
|
+
if seen:
|
|
238
|
+
self._record(varname.upper(), "!!deleted!!")
|
|
239
|
+
|
|
240
|
+
def __delitem__(self, varname):
|
|
241
|
+
self.delvar(varname)
|
|
242
|
+
|
|
243
|
+
def __delattr__(self, varname):
|
|
244
|
+
self.delvar(varname)
|
|
245
|
+
|
|
246
|
+
def __len__(self):
|
|
247
|
+
return len(self._pool)
|
|
248
|
+
|
|
249
|
+
def __iter__(self):
|
|
250
|
+
yield from self._pool.keys()
|
|
251
|
+
|
|
252
|
+
def __contains__(self, item):
|
|
253
|
+
item = str(item)
|
|
254
|
+
return item in self._pool or item.upper() in self._pool
|
|
255
|
+
|
|
256
|
+
def has_key(self, item):
|
|
257
|
+
"""Returns whether ``item`` is defined or not.
|
|
258
|
+
|
|
259
|
+
Also used as internal for dictionary access.
|
|
260
|
+
"""
|
|
261
|
+
return item in self
|
|
262
|
+
|
|
263
|
+
def keys(self):
|
|
264
|
+
"""Returns the keys of the internal pool of variables."""
|
|
265
|
+
return self._pool.keys()
|
|
266
|
+
|
|
267
|
+
def __call__(self):
|
|
268
|
+
return self.pool()
|
|
269
|
+
|
|
270
|
+
def values(self):
|
|
271
|
+
"""Returns the values of the internal pool of variables."""
|
|
272
|
+
return self._pool.values()
|
|
273
|
+
|
|
274
|
+
def pool(self):
|
|
275
|
+
"""Returns the reference of the internal pool of variables."""
|
|
276
|
+
return self._pool
|
|
277
|
+
|
|
278
|
+
def get(self, *args):
|
|
279
|
+
"""Proxy to the dictionary ``get`` mechanism on the internal pool of variables."""
|
|
280
|
+
return self._pool.get(str(args[0]).upper(), *args[1:])
|
|
281
|
+
|
|
282
|
+
def items(self):
|
|
283
|
+
"""Proxy to the dictionary ``items`` method on the internal pool of variables."""
|
|
284
|
+
return self._pool.items()
|
|
285
|
+
|
|
286
|
+
def __eq__(self, other):
|
|
287
|
+
return (
|
|
288
|
+
isinstance(other, type(self))
|
|
289
|
+
and set(self.keys()) == set(other.keys)
|
|
290
|
+
and all([self[k] == other[k] for k in self.keys])
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def __ne__(self, other):
|
|
294
|
+
return not self == other
|
|
295
|
+
|
|
296
|
+
def update(self, *args, **kw):
|
|
297
|
+
"""Set a collection of variables given as a list of iterable items or key-values pairs."""
|
|
298
|
+
argd = list(args)
|
|
299
|
+
argd.append(kw)
|
|
300
|
+
for dico in argd:
|
|
301
|
+
for var, value in dico.items():
|
|
302
|
+
self.setvar(var, value)
|
|
303
|
+
|
|
304
|
+
def delta(self, **kw):
|
|
305
|
+
"""
|
|
306
|
+
Temporarily set a collection of variables that could be reversed using
|
|
307
|
+
the :meth:`rewind` method.
|
|
308
|
+
"""
|
|
309
|
+
upditems, newitems = (dict(), collections.deque())
|
|
310
|
+
for var, value in kw.items():
|
|
311
|
+
var = str(var)
|
|
312
|
+
if var in self:
|
|
313
|
+
upditems[var] = self.get(var)
|
|
314
|
+
else:
|
|
315
|
+
newitems.append(var)
|
|
316
|
+
self.setvar(var, value)
|
|
317
|
+
self._frozen.append((upditems, newitems))
|
|
318
|
+
|
|
319
|
+
def rewind(self):
|
|
320
|
+
"""Come back on last environment delta changes (see the :meth:`delta` method)."""
|
|
321
|
+
if self._frozen:
|
|
322
|
+
upditems, newitems = self._frozen.pop()
|
|
323
|
+
while newitems:
|
|
324
|
+
self.delvar(newitems.pop())
|
|
325
|
+
for var, value in upditems.items():
|
|
326
|
+
self.setvar(var, value)
|
|
327
|
+
else:
|
|
328
|
+
raise RuntimeError("No more delta to be rewinded...")
|
|
329
|
+
|
|
330
|
+
def delta_context(self, **kw):
|
|
331
|
+
"""
|
|
332
|
+
Create a context that will automatically create a delta then rewind it
|
|
333
|
+
when exiting.
|
|
334
|
+
"""
|
|
335
|
+
return EnvironmentDeltaContext(self, **kw)
|
|
336
|
+
|
|
337
|
+
def default(self, *args, **kw):
|
|
338
|
+
"""Set a collection of non defined variables given as a list of iterable items or key-values pairs."""
|
|
339
|
+
argd = list(args)
|
|
340
|
+
argd.append(kw)
|
|
341
|
+
for dico in argd:
|
|
342
|
+
for var, value in dico.items():
|
|
343
|
+
if var not in self:
|
|
344
|
+
self.setvar(var, value)
|
|
345
|
+
|
|
346
|
+
def merge(self, mergenv):
|
|
347
|
+
"""Incorporates key-values from ``mergenv`` into current environment.
|
|
348
|
+
|
|
349
|
+
:param Environment mergeenv: The object to be merged in.
|
|
350
|
+
"""
|
|
351
|
+
self.update(mergenv.pool())
|
|
352
|
+
|
|
353
|
+
def clear(self):
|
|
354
|
+
"""Flush the current pool of variables."""
|
|
355
|
+
return self._pool.clear()
|
|
356
|
+
|
|
357
|
+
def clone(self):
|
|
358
|
+
"""Return a non-active copy of the current env."""
|
|
359
|
+
eclone = self.__class__(env=self, active=False)
|
|
360
|
+
try:
|
|
361
|
+
eclone.verbose(self._verbose, self._sh)
|
|
362
|
+
except AttributeError:
|
|
363
|
+
logger.debug(
|
|
364
|
+
"Could not find verbose attributes while cloning env..."
|
|
365
|
+
)
|
|
366
|
+
return eclone
|
|
367
|
+
|
|
368
|
+
def __enter__(self):
|
|
369
|
+
"""Activate the environment when entering a context."""
|
|
370
|
+
self.active(True)
|
|
371
|
+
return self
|
|
372
|
+
|
|
373
|
+
def __exit__(self, exc_type, exc_value, traceback): # @UnusedVariable
|
|
374
|
+
"""De-activate the environment on context's exit."""
|
|
375
|
+
self.active(False)
|
|
376
|
+
|
|
377
|
+
def native(self, varname):
|
|
378
|
+
"""Returns the native form this variable could have in a shell environment."""
|
|
379
|
+
value = self._pool[varname]
|
|
380
|
+
if isinstance(value, str):
|
|
381
|
+
return str(value)
|
|
382
|
+
else:
|
|
383
|
+
return json.dumps(value, cls=ShellEncoder)
|
|
384
|
+
|
|
385
|
+
def verbose(self, switch=None, sh=None, fromenv=None):
|
|
386
|
+
"""Switch on or off the verbose mode. Returns actual value."""
|
|
387
|
+
if switch is not None:
|
|
388
|
+
self.__dict__["_verbose"] = bool(switch)
|
|
389
|
+
if sh is not None:
|
|
390
|
+
self.__dict__["_sh"] = sh
|
|
391
|
+
return self.__dict__["_verbose"]
|
|
392
|
+
|
|
393
|
+
def active(self, *args):
|
|
394
|
+
"""
|
|
395
|
+
Bind or unbind current environment to the shell environment according to
|
|
396
|
+
a boolean flag given as first argument.
|
|
397
|
+
|
|
398
|
+
Returns current active status after update.
|
|
399
|
+
"""
|
|
400
|
+
previous_act = self.osbound()
|
|
401
|
+
osrewind = None
|
|
402
|
+
active = previous_act
|
|
403
|
+
if args and type(args[0]) is bool:
|
|
404
|
+
active = args[0]
|
|
405
|
+
if previous_act and not active and self._os:
|
|
406
|
+
self._record("!!OS_BINDING!!", "Broken...")
|
|
407
|
+
self.__class__._current_active = self._os[-1]
|
|
408
|
+
osrewind = self.__class__._current_active
|
|
409
|
+
if not previous_act and active:
|
|
410
|
+
if self.contextlock is not None and not self.contextlock.active:
|
|
411
|
+
raise RuntimeError(
|
|
412
|
+
"It's not allowed to switch to an Environment "
|
|
413
|
+
+ "that belongs to an inactive context"
|
|
414
|
+
)
|
|
415
|
+
self._record("!!OS_BINDING!!", "Acquiring...")
|
|
416
|
+
self.__class__._current_active = self
|
|
417
|
+
osrewind = self.__class__._current_active
|
|
418
|
+
if osrewind:
|
|
419
|
+
os.environ.clear()
|
|
420
|
+
for k in filter(
|
|
421
|
+
lambda x: x not in osrewind._noexport, osrewind._pool.keys()
|
|
422
|
+
):
|
|
423
|
+
os.environ[k] = osrewind.native(k)
|
|
424
|
+
return active
|
|
425
|
+
|
|
426
|
+
def naked(self):
|
|
427
|
+
"""Return ``True`` when the pool of variables is empty."""
|
|
428
|
+
return not bool(self._pool)
|
|
429
|
+
|
|
430
|
+
def modified(self):
|
|
431
|
+
"""Return ``True`` when some variables have been modified."""
|
|
432
|
+
return bool(self._mods)
|
|
433
|
+
|
|
434
|
+
def varupdates(self):
|
|
435
|
+
"""Return the list of variables names that have been modified so far."""
|
|
436
|
+
return self._mods
|
|
437
|
+
|
|
438
|
+
def osbound(self):
|
|
439
|
+
"""Returns whether this current environment is bound to the os.environ."""
|
|
440
|
+
return self is self.__class__._current_active
|
|
441
|
+
|
|
442
|
+
def tracebacks(self):
|
|
443
|
+
"""Dump the stack of manipulations of the current environment."""
|
|
444
|
+
if self.history is not None:
|
|
445
|
+
for u_count, stamp, action in self.history:
|
|
446
|
+
varname, value, stack = action
|
|
447
|
+
print("[", stamp, "]", varname, "=", value, "\n")
|
|
448
|
+
for xs in stack:
|
|
449
|
+
print(xs)
|
|
450
|
+
|
|
451
|
+
def osdump(self):
|
|
452
|
+
"""Dump the actual values of the OS environment."""
|
|
453
|
+
for k in sorted(os.environ.keys()):
|
|
454
|
+
print('{:s}="{:s}"'.format(k, os.environ[k]))
|
|
455
|
+
|
|
456
|
+
def mydump(self):
|
|
457
|
+
"""Dump the actual values of the current environment."""
|
|
458
|
+
for k in sorted(self._pool.keys()):
|
|
459
|
+
print('{:s}="{:s}"'.format(k, str(self._pool[k])))
|
|
460
|
+
|
|
461
|
+
def mkautolist(self, prefix):
|
|
462
|
+
"""Return a list of variable starting with the ``prefix`` string."""
|
|
463
|
+
return [
|
|
464
|
+
var + '="' + self.get(var, "") + '"'
|
|
465
|
+
for var in self.keys()
|
|
466
|
+
if var.startswith(prefix)
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
def trueshell(self):
|
|
470
|
+
"""Extract the actual shell name according to env variable SHELL."""
|
|
471
|
+
return re.sub("^.*/", "", self.getvar("shell"))
|
|
472
|
+
|
|
473
|
+
def true(self, varname):
|
|
474
|
+
"""Extended boolean positive test of the variable given as argument."""
|
|
475
|
+
return bool(vartrue.match(str(self.getvar(varname))))
|
|
476
|
+
|
|
477
|
+
def false(self, varname):
|
|
478
|
+
"""Extended boolean negative test of the variable given as argument."""
|
|
479
|
+
xvar = self.getvar(varname)
|
|
480
|
+
if xvar is None:
|
|
481
|
+
return True
|
|
482
|
+
else:
|
|
483
|
+
return bool(varfalse.match(str(xvar)))
|
|
484
|
+
|
|
485
|
+
def setgenericpath(self, var, value, pos=None):
|
|
486
|
+
"""Insert a new path value to a PATH like variable at a given position.
|
|
487
|
+
|
|
488
|
+
:param str var: The environment's variable to modify (case insensitive)
|
|
489
|
+
:param str value: The value that will be inserted in the path
|
|
490
|
+
:param int pos: Where in the path, to insert ``value`` (by default, at the end)
|
|
491
|
+
"""
|
|
492
|
+
mypath = self.getvar(var).split(":") if self.getvar(var) else []
|
|
493
|
+
value = str(value)
|
|
494
|
+
while value in mypath:
|
|
495
|
+
mypath.remove(value)
|
|
496
|
+
if pos is None:
|
|
497
|
+
pos = len(mypath)
|
|
498
|
+
mypath.insert(pos, value)
|
|
499
|
+
self.setvar(var, ":".join(mypath))
|
|
500
|
+
|
|
501
|
+
def rmgenericpath(self, var, value):
|
|
502
|
+
"""Remove the specified ``value`` from a PATH like variable."""
|
|
503
|
+
mypath = self.getvar(var).split(":") if self.getvar(var) else []
|
|
504
|
+
while value in mypath:
|
|
505
|
+
mypath.remove(value)
|
|
506
|
+
self.setvar(var, ":".join(mypath))
|
|
507
|
+
|
|
508
|
+
def setbinpath(self, value, pos=None):
|
|
509
|
+
"""
|
|
510
|
+
Insert a new path ``value`` to the bin search path (i.e. the PATH
|
|
511
|
+
environment variable) at given position.
|
|
512
|
+
"""
|
|
513
|
+
self.setgenericpath("PATH", value, pos)
|
|
514
|
+
|
|
515
|
+
def rmbinpath(self, value):
|
|
516
|
+
"""
|
|
517
|
+
Remove the specified ``value`` from the bin path (i.e. the PATH
|
|
518
|
+
environment variable).
|
|
519
|
+
"""
|
|
520
|
+
self.rmgenericpath("PATH", value)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
collections.abc.Mapping.register(Environment)
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
class EnvironmentDeltaContext:
|
|
527
|
+
"""Context that will apply a delta on the Environment and rewind it on exit."""
|
|
528
|
+
|
|
529
|
+
def __init__(self, env, **kw):
|
|
530
|
+
"""
|
|
531
|
+
This object should not be created manually (use the
|
|
532
|
+
:meth:`Environment.delta_context` method instead).
|
|
533
|
+
"""
|
|
534
|
+
self._env = env
|
|
535
|
+
self._delta = kw
|
|
536
|
+
|
|
537
|
+
def __enter__(self):
|
|
538
|
+
self._env.delta(**self._delta)
|
|
539
|
+
|
|
540
|
+
def __exit__(self, exc_type, exc_value, traceback): # @UnusedVariable
|
|
541
|
+
self._env.rewind()
|