vortex-nwp 2.0.0b1__py3-none-any.whl → 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. vortex/__init__.py +75 -47
  2. vortex/algo/__init__.py +3 -2
  3. vortex/algo/components.py +944 -618
  4. vortex/algo/mpitools.py +802 -497
  5. vortex/algo/mpitools_templates/__init__.py +1 -0
  6. vortex/algo/serversynctools.py +34 -33
  7. vortex/config.py +19 -22
  8. vortex/data/__init__.py +9 -3
  9. vortex/data/abstractstores.py +593 -655
  10. vortex/data/containers.py +217 -162
  11. vortex/data/contents.py +65 -39
  12. vortex/data/executables.py +93 -102
  13. vortex/data/flow.py +40 -34
  14. vortex/data/geometries.py +228 -132
  15. vortex/data/handlers.py +436 -227
  16. vortex/data/outflow.py +15 -15
  17. vortex/data/providers.py +185 -163
  18. vortex/data/resources.py +48 -42
  19. vortex/data/stores.py +540 -417
  20. vortex/data/sync_templates/__init__.py +0 -0
  21. vortex/gloves.py +114 -87
  22. vortex/layout/__init__.py +1 -8
  23. vortex/layout/contexts.py +150 -84
  24. vortex/layout/dataflow.py +353 -202
  25. vortex/layout/monitor.py +264 -128
  26. vortex/nwp/__init__.py +5 -2
  27. vortex/nwp/algo/__init__.py +14 -5
  28. vortex/nwp/algo/assim.py +205 -151
  29. vortex/nwp/algo/clim.py +683 -517
  30. vortex/nwp/algo/coupling.py +447 -225
  31. vortex/nwp/algo/eda.py +437 -229
  32. vortex/nwp/algo/eps.py +403 -231
  33. vortex/nwp/algo/forecasts.py +416 -275
  34. vortex/nwp/algo/fpserver.py +683 -307
  35. vortex/nwp/algo/ifsnaming.py +205 -145
  36. vortex/nwp/algo/ifsroot.py +215 -122
  37. vortex/nwp/algo/monitoring.py +137 -76
  38. vortex/nwp/algo/mpitools.py +330 -190
  39. vortex/nwp/algo/odbtools.py +637 -353
  40. vortex/nwp/algo/oopsroot.py +454 -273
  41. vortex/nwp/algo/oopstests.py +90 -56
  42. vortex/nwp/algo/request.py +287 -206
  43. vortex/nwp/algo/stdpost.py +878 -522
  44. vortex/nwp/data/__init__.py +22 -4
  45. vortex/nwp/data/assim.py +125 -137
  46. vortex/nwp/data/boundaries.py +121 -68
  47. vortex/nwp/data/climfiles.py +193 -211
  48. vortex/nwp/data/configfiles.py +73 -69
  49. vortex/nwp/data/consts.py +426 -401
  50. vortex/nwp/data/ctpini.py +59 -43
  51. vortex/nwp/data/diagnostics.py +94 -66
  52. vortex/nwp/data/eda.py +50 -51
  53. vortex/nwp/data/eps.py +195 -146
  54. vortex/nwp/data/executables.py +440 -434
  55. vortex/nwp/data/fields.py +63 -48
  56. vortex/nwp/data/gridfiles.py +183 -111
  57. vortex/nwp/data/logs.py +250 -217
  58. vortex/nwp/data/modelstates.py +180 -151
  59. vortex/nwp/data/monitoring.py +72 -99
  60. vortex/nwp/data/namelists.py +254 -202
  61. vortex/nwp/data/obs.py +400 -308
  62. vortex/nwp/data/oopsexec.py +22 -20
  63. vortex/nwp/data/providers.py +90 -65
  64. vortex/nwp/data/query.py +71 -82
  65. vortex/nwp/data/stores.py +49 -36
  66. vortex/nwp/data/surfex.py +136 -137
  67. vortex/nwp/syntax/__init__.py +1 -1
  68. vortex/nwp/syntax/stdattrs.py +173 -111
  69. vortex/nwp/tools/__init__.py +2 -2
  70. vortex/nwp/tools/addons.py +22 -17
  71. vortex/nwp/tools/agt.py +24 -12
  72. vortex/nwp/tools/bdap.py +16 -5
  73. vortex/nwp/tools/bdcp.py +4 -1
  74. vortex/nwp/tools/bdm.py +3 -0
  75. vortex/nwp/tools/bdmp.py +14 -9
  76. vortex/nwp/tools/conftools.py +728 -378
  77. vortex/nwp/tools/drhook.py +12 -8
  78. vortex/nwp/tools/grib.py +65 -39
  79. vortex/nwp/tools/gribdiff.py +22 -17
  80. vortex/nwp/tools/ifstools.py +82 -42
  81. vortex/nwp/tools/igastuff.py +167 -143
  82. vortex/nwp/tools/mars.py +14 -2
  83. vortex/nwp/tools/odb.py +234 -125
  84. vortex/nwp/tools/partitioning.py +61 -37
  85. vortex/nwp/tools/satrad.py +27 -12
  86. vortex/nwp/util/async.py +83 -55
  87. vortex/nwp/util/beacon.py +10 -10
  88. vortex/nwp/util/diffpygram.py +174 -86
  89. vortex/nwp/util/ens.py +144 -63
  90. vortex/nwp/util/hooks.py +30 -19
  91. vortex/nwp/util/taskdeco.py +28 -24
  92. vortex/nwp/util/usepygram.py +278 -172
  93. vortex/nwp/util/usetnt.py +31 -17
  94. vortex/sessions.py +72 -39
  95. vortex/syntax/__init__.py +1 -1
  96. vortex/syntax/stdattrs.py +410 -171
  97. vortex/syntax/stddeco.py +31 -22
  98. vortex/toolbox.py +327 -192
  99. vortex/tools/__init__.py +11 -2
  100. vortex/tools/actions.py +110 -121
  101. vortex/tools/addons.py +111 -92
  102. vortex/tools/arm.py +42 -22
  103. vortex/tools/compression.py +72 -69
  104. vortex/tools/date.py +11 -4
  105. vortex/tools/delayedactions.py +242 -132
  106. vortex/tools/env.py +75 -47
  107. vortex/tools/folder.py +342 -171
  108. vortex/tools/grib.py +341 -162
  109. vortex/tools/lfi.py +423 -216
  110. vortex/tools/listings.py +109 -40
  111. vortex/tools/names.py +218 -156
  112. vortex/tools/net.py +655 -299
  113. vortex/tools/parallelism.py +93 -61
  114. vortex/tools/prestaging.py +55 -31
  115. vortex/tools/schedulers.py +172 -105
  116. vortex/tools/services.py +403 -334
  117. vortex/tools/storage.py +293 -358
  118. vortex/tools/surfex.py +24 -24
  119. vortex/tools/systems.py +1234 -643
  120. vortex/tools/targets.py +156 -100
  121. vortex/util/__init__.py +1 -1
  122. vortex/util/config.py +378 -327
  123. vortex/util/empty.py +2 -2
  124. vortex/util/helpers.py +56 -24
  125. vortex/util/introspection.py +18 -12
  126. vortex/util/iosponge.py +8 -4
  127. vortex/util/roles.py +4 -6
  128. vortex/util/storefunctions.py +39 -13
  129. vortex/util/structs.py +3 -3
  130. vortex/util/worker.py +29 -17
  131. vortex_nwp-2.1.0.dist-info/METADATA +67 -0
  132. vortex_nwp-2.1.0.dist-info/RECORD +144 -0
  133. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/WHEEL +1 -1
  134. vortex/layout/appconf.py +0 -109
  135. vortex/layout/jobs.py +0 -1276
  136. vortex/layout/nodes.py +0 -1424
  137. vortex/layout/subjobs.py +0 -464
  138. vortex_nwp-2.0.0b1.dist-info/METADATA +0 -50
  139. vortex_nwp-2.0.0b1.dist-info/RECORD +0 -146
  140. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info/licenses}/LICENSE +0 -0
  141. {vortex_nwp-2.0.0b1.dist-info → vortex_nwp-2.1.0.dist-info}/top_level.txt +0 -0
vortex/tools/addons.py CHANGED
@@ -23,53 +23,50 @@ class Addon(footprints.FootprintBase):
23
23
  """Root class for any :class:`Addon` system subclasses."""
24
24
 
25
25
  _abstract = True
26
- _collector = ('addon',)
26
+ _collector = ("addon",)
27
27
  _footprint = dict(
28
- info = 'Default add-on',
29
- attr = dict(
30
- kind = dict(),
31
- sh = dict(
32
- type = OSExtended,
33
- alias = ('shell',),
34
- access = 'rwx-weak',
28
+ info="Default add-on",
29
+ attr=dict(
30
+ kind=dict(),
31
+ sh=dict(
32
+ type=OSExtended,
33
+ alias=("shell",),
34
+ access="rwx-weak",
35
35
  ),
36
- env = dict(
37
- type = Environment,
38
- optional = True,
39
- default = None,
40
- access = 'rwx',
41
- doc_visibility = footprints.doc.visibility.ADVANCED
36
+ env=dict(
37
+ type=Environment,
38
+ optional=True,
39
+ default=None,
40
+ access="rwx",
41
+ doc_visibility=footprints.doc.visibility.ADVANCED,
42
42
  ),
43
- cfginfo = dict(
44
- optional = True,
45
- default = '[kind]',
46
- doc_visibility = footprints.doc.visibility.ADVANCED
43
+ cfginfo=dict(
44
+ optional=True,
45
+ default="[kind]",
46
+ doc_visibility=footprints.doc.visibility.ADVANCED,
47
47
  ),
48
- cmd = dict(
49
- optional = True,
50
- default = None,
51
- access = 'rwx',
48
+ cmd=dict(
49
+ optional=True,
50
+ default=None,
51
+ access="rwx",
52
52
  ),
53
- path = dict(
54
- optional = True,
55
- default = None,
56
- access = 'rwx',
53
+ path=dict(
54
+ optional=True,
55
+ default=None,
56
+ access="rwx",
57
57
  ),
58
- cycle = dict(
59
- optional = True,
60
- default = None,
61
- access = 'rwx',
58
+ cycle=dict(
59
+ optional=True,
60
+ default=None,
61
+ access="rwx",
62
62
  ),
63
- toolkind = dict(
64
- optional = True,
65
- default = None
66
- ),
67
- )
63
+ toolkind=dict(optional=True, default=None),
64
+ ),
68
65
  )
69
66
 
70
67
  def __init__(self, *args, **kw):
71
68
  """Abstract Addon initialisation."""
72
- logger.debug('Abstract Addon init %s', self.__class__)
69
+ logger.debug("Abstract Addon init %s", self.__class__)
73
70
  super().__init__(*args, **kw)
74
71
  self.sh.extend(self)
75
72
  self._context_cache = defaultdict(dict)
@@ -81,7 +78,9 @@ class Addon(footprints.FootprintBase):
81
78
  self.env[k] = clsenv[k]
82
79
  if self.path is None:
83
80
  self.path = get_from_config_w_default(
84
- section="nwp-tools", key=self.kind, default=None,
81
+ section="nwp-tools",
82
+ key=self.kind,
83
+ default=None,
85
84
  )
86
85
 
87
86
  @classmethod
@@ -103,36 +102,44 @@ class Addon(footprints.FootprintBase):
103
102
  if ctxtag not in self._context_cache and self.toolkind is not None:
104
103
  ltrack = contexts.current().localtracker
105
104
  # NB: 'str' is important because local might be in unicode...
106
- candidates = [str(self.sh.path.realpath(local))
107
- for local, entry in ltrack.items()
108
- if (entry.latest_rhdict('get').get('resource', dict()).get('kind', '') ==
109
- self.toolkind)]
105
+ candidates = [
106
+ str(self.sh.path.realpath(local))
107
+ for local, entry in ltrack.items()
108
+ if (
109
+ entry.latest_rhdict("get")
110
+ .get("resource", dict())
111
+ .get("kind", "")
112
+ == self.toolkind
113
+ )
114
+ ]
110
115
  if candidates:
111
116
  realpath = candidates.pop()
112
- self._context_cache[ctxtag] = dict(path=self.sh.path.dirname(realpath),
113
- cmd=self.sh.path.basename(realpath))
117
+ self._context_cache[ctxtag] = dict(
118
+ path=self.sh.path.dirname(realpath),
119
+ cmd=self.sh.path.basename(realpath),
120
+ )
114
121
  return self._context_cache[ctxtag]
115
122
 
116
123
  @property
117
124
  def actual_path(self):
118
125
  """The path that should be used in the current context."""
119
126
  infos = self._query_context()
120
- ctxpath = infos.get('path', None)
127
+ ctxpath = infos.get("path", None)
121
128
  return self.path if ctxpath is None else ctxpath
122
129
 
123
130
  @property
124
131
  def actual_cmd(self):
125
132
  """The cmd that should be used in the current context."""
126
133
  infos = self._query_context()
127
- ctxcmd = infos.get('cmd', None)
134
+ ctxcmd = infos.get("cmd", None)
128
135
  return self.cmd if ctxcmd is None else ctxcmd
129
136
 
130
137
  def _spawn_commons(self, cmd, **kw):
131
138
  """Internal method setting local environment and calling standard shell spawn."""
132
139
 
133
140
  # Is there a need for an interpreter ?
134
- if 'interpreter' in kw:
135
- cmd.insert(0, kw.pop('interpreter'))
141
+ if "interpreter" in kw:
142
+ cmd.insert(0, kw.pop("interpreter"))
136
143
  else:
137
144
  # The first element of the command line needs to be executable
138
145
  if cmd[0] not in self._cmd_xperms_cache:
@@ -141,16 +148,15 @@ class Addon(footprints.FootprintBase):
141
148
 
142
149
  # Overwrite global module env values with specific ones
143
150
  with self.sh.env.clone() as localenv:
144
-
145
151
  localenv.verbose(True, self.sh)
146
152
  localenv.update(self.env)
147
153
 
148
154
  # Check if a pipe is requested
149
- inpipe = kw.pop('inpipe', False)
155
+ inpipe = kw.pop("inpipe", False)
150
156
 
151
157
  # Ask the attached shell to run the addon command
152
158
  if inpipe:
153
- kw.setdefault('stdout', True)
159
+ kw.setdefault("stdout", True)
154
160
  rc = self.sh.popen(cmd, **kw)
155
161
  else:
156
162
  rc = self.sh.spawn(cmd, **kw)
@@ -163,7 +169,7 @@ class Addon(footprints.FootprintBase):
163
169
  # Insert the actual tool command as first argument
164
170
  cmd.insert(0, self.actual_cmd)
165
171
  if self.actual_path is not None:
166
- cmd[0] = self.actual_path + '/' + cmd[0]
172
+ cmd[0] = self.actual_path + "/" + cmd[0]
167
173
 
168
174
  return self._spawn_commons(cmd, **kw)
169
175
 
@@ -172,7 +178,7 @@ class Addon(footprints.FootprintBase):
172
178
 
173
179
  # Insert the tool path before the first argument
174
180
  if self.actual_path is not None:
175
- cmd[0] = self.actual_path + '/' + cmd[0]
181
+ cmd[0] = self.actual_path + "/" + cmd[0]
176
182
 
177
183
  return self._spawn_commons(cmd, **kw)
178
184
 
@@ -182,26 +188,28 @@ class FtrawEnableAddon(Addon):
182
188
 
183
189
  _abstract = True
184
190
  _footprint = dict(
185
- info = 'Default add-on with rawftput support.',
186
- attr = dict(
187
- rawftshell = dict(
188
- info = "Path to ftserv's concatenation shell",
189
- optional = True,
190
- default = None,
191
- access = 'rwx',
192
- doc_visibility = footprints.doc.visibility.GURU,
191
+ info="Default add-on with rawftput support.",
192
+ attr=dict(
193
+ rawftshell=dict(
194
+ info="Path to ftserv's concatenation shell",
195
+ optional=True,
196
+ default=None,
197
+ access="rwx",
198
+ doc_visibility=footprints.doc.visibility.GURU,
193
199
  ),
194
- )
200
+ ),
195
201
  )
196
202
 
197
203
  def __init__(self, *args, **kw):
198
204
  """Abstract Addon initialisation."""
199
- logger.debug('Abstract Addon init %s', self.__class__)
205
+ logger.debug("Abstract Addon init %s", self.__class__)
200
206
  super().__init__(*args, **kw)
201
207
  # If needed, look in the config file for the rawftshell
202
208
  if self.rawftshell is None:
203
209
  self.rawftshell = get_from_config_w_default(
204
- section="rawftshell", key=self.kind, default=None,
210
+ section="rawftshell",
211
+ key=self.kind,
212
+ default=None,
205
213
  )
206
214
 
207
215
 
@@ -213,52 +221,59 @@ class AddonGroup(footprints.FootprintBase):
213
221
  """
214
222
 
215
223
  _abstract = True
216
- _collector = ('addon',)
224
+ _collector = ("addon",)
217
225
  _footprint = dict(
218
- info = 'Default add-on group',
219
- attr = dict(
220
- kind = dict(),
221
- sh = dict(
222
- type = OSExtended,
223
- alias = ('shell',),
226
+ info="Default add-on group",
227
+ attr=dict(
228
+ kind=dict(),
229
+ sh=dict(
230
+ type=OSExtended,
231
+ alias=("shell",),
224
232
  ),
225
- env = dict(
226
- type = Environment,
227
- optional = True,
228
- default = None,
229
- doc_visibility = footprints.doc.visibility.ADVANCED,
233
+ env=dict(
234
+ type=Environment,
235
+ optional=True,
236
+ default=None,
237
+ doc_visibility=footprints.doc.visibility.ADVANCED,
230
238
  ),
231
- cycle = dict(
232
- optional = True,
233
- default = None,
239
+ cycle=dict(
240
+ optional=True,
241
+ default=None,
234
242
  ),
235
- verboseload = dict(
236
- optional = True,
237
- default = True,
238
- type = bool,
243
+ verboseload=dict(
244
+ optional=True,
245
+ default=True,
246
+ type=bool,
239
247
  ),
240
- )
248
+ ),
241
249
  )
242
250
 
243
251
  _addonslist = None
244
252
 
245
253
  def __init__(self, *args, **kw):
246
254
  """Abstract Addon initialisation."""
247
- logger.debug('Abstract Addon init %s', self.__class__)
255
+ logger.debug("Abstract Addon init %s", self.__class__)
248
256
  super().__init__(*args, **kw)
249
257
  self._addons_load()
250
258
 
251
259
  def _addons_load(self):
252
260
  if self._addonslist is None:
253
- raise RuntimeError("the _addonslist classe variable must be overriden.")
261
+ raise RuntimeError(
262
+ "the _addonslist classe variable must be overriden."
263
+ )
254
264
  self._load_addons_from_list(self._addonslist)
255
265
 
256
266
  def _load_addons_from_list(self, addons):
257
267
  if self.verboseload:
258
268
  logger.info("Loading the %s Addons group.", self.kind)
259
269
  for addon in addons:
260
- _shadd = footprints.proxy.addon(kind=addon, sh=self.sh, env=self.env,
261
- cycle=self.cycle, verboseload=self.verboseload)
270
+ _shadd = footprints.proxy.addon(
271
+ kind=addon,
272
+ sh=self.sh,
273
+ env=self.env,
274
+ cycle=self.cycle,
275
+ verboseload=self.verboseload,
276
+ )
262
277
  if self.verboseload:
263
278
  logger.info("%s Addon is: %s", addon, repr(_shadd))
264
279
 
@@ -270,13 +285,13 @@ def require_external_addon(*addons):
270
285
 
271
286
  If not, a :class:`RuntimeError` exception will be raised.
272
287
  """
288
+
273
289
  @nicedeco
274
290
  def r_addon_decorator(method):
275
-
276
291
  def decorated(self, *kargs, **kwargs):
277
292
  # Create a cache in self... ugly but efficient !
278
- if not hasattr(self, '_require_external_addon_check_cache'):
279
- setattr(self, '_require_external_addon_check_cache', set())
293
+ if not hasattr(self, "_require_external_addon_check_cache"):
294
+ setattr(self, "_require_external_addon_check_cache", set())
280
295
  ko_addons = set()
281
296
  loaded_addons = None
282
297
  for addon in addons:
@@ -289,9 +304,13 @@ def require_external_addon(*addons):
289
304
  else:
290
305
  ko_addons.add(addon)
291
306
  if ko_addons:
292
- raise RuntimeError('The following addons are needed to use the {:s} method: {:s}'
293
- .format(method.__name__, ', '.join(ko_addons)))
307
+ raise RuntimeError(
308
+ "The following addons are needed to use the {:s} method: {:s}".format(
309
+ method.__name__, ", ".join(ko_addons)
310
+ )
311
+ )
294
312
  return method(self, *kargs, **kwargs)
295
313
 
296
314
  return decorated
315
+
297
316
  return r_addon_decorator
vortex/tools/arm.py CHANGED
@@ -7,7 +7,7 @@ from bronx.fancies import loggers
7
7
  from vortex.util.config import load_template
8
8
 
9
9
  #: No automatic export
10
- __all__ = ['ArmForgeTool']
10
+ __all__ = ["ArmForgeTool"]
11
11
 
12
12
  logger = loggers.getLogger(__name__)
13
13
 
@@ -21,18 +21,20 @@ class ArmForgeTool:
21
21
  """
22
22
  self._t = ticket
23
23
  self._sh = self._t.sh
24
- self._config = self._sh.default_target.items('armtools')
25
- self._ddtpath = self._sh.env.get('VORTEX_ARM_DDT_PATH', None)
26
- self._mappath = self._sh.env.get('VORTEX_ARM_MAP_PATH', None)
27
- self._forgedir = self._sh.env.get('VORTEX_ARM_FORGE_DIR',
28
- self.config.get('forgedir', None))
29
- self._forgeversion = self._sh.env.get('VORTEX_ARM_FORGE_VERSION',
30
- self.config.get('forgeversion', 999999))
24
+ self._config = self._sh.default_target.items("armtools")
25
+ self._ddtpath = self._sh.env.get("VORTEX_ARM_DDT_PATH", None)
26
+ self._mappath = self._sh.env.get("VORTEX_ARM_MAP_PATH", None)
27
+ self._forgedir = self._sh.env.get(
28
+ "VORTEX_ARM_FORGE_DIR", self.config.get("forgedir", None)
29
+ )
30
+ self._forgeversion = self._sh.env.get(
31
+ "VORTEX_ARM_FORGE_VERSION", self.config.get("forgeversion", 999999)
32
+ )
31
33
  self._forgeversion = int(self._forgeversion)
32
34
  if self._forgedir and self._ddtpath is None:
33
- self._ddtpath = self._sh.path.join(self._forgedir, 'bin', 'ddt')
35
+ self._ddtpath = self._sh.path.join(self._forgedir, "bin", "ddt")
34
36
  if self._forgedir and self._mappath is None:
35
- self._mappath = self._sh.path.join(self._forgedir, 'bin', 'map')
37
+ self._mappath = self._sh.path.join(self._forgedir, "bin", "map")
36
38
 
37
39
  @property
38
40
  def config(self):
@@ -43,34 +45,52 @@ class ArmForgeTool:
43
45
  def ddtpath(self):
44
46
  """The path to the DDT debuger executable."""
45
47
  if self._ddtpath is None:
46
- raise RuntimeError('DDT requested but the DDT path is not configured.')
48
+ raise RuntimeError(
49
+ "DDT requested but the DDT path is not configured."
50
+ )
47
51
  return self._ddtpath
48
52
 
49
53
  @property
50
54
  def mappath(self):
51
55
  """The path to the MAP profiler executable."""
52
56
  if self._mappath is None:
53
- raise RuntimeError('MAP requested but the MAP path is not configured.')
57
+ raise RuntimeError(
58
+ "MAP requested but the MAP path is not configured."
59
+ )
54
60
  return self._mappath
55
61
 
56
62
  def _dump_forge_session(self, sources=(), workdir=None):
57
63
  """Create the ARM Forge's session file to list source directories."""
58
- targetfile = 'armforge-vortex-session-file.ddt'
64
+ targetfile = "armforge-vortex-session-file.ddt"
59
65
  if workdir:
60
66
  targetfile = self._sh.path.join(workdir, targetfile)
61
- tpl = load_template(self._t, '@armforge-session-conf.tpl',
62
- encoding='utf-8', version=self._forgeversion)
63
- sconf = tpl.substitute(sourcedirs='\n'.join([' <directory>{:s}</directory>'.format(d)
64
- for d in sources]))
65
- with open(targetfile, 'w') as fhs:
67
+ tpl = load_template(
68
+ self._t,
69
+ "@armforge-session-conf.tpl",
70
+ encoding="utf-8",
71
+ version=self._forgeversion,
72
+ )
73
+ sconf = tpl.substitute(
74
+ sourcedirs="\n".join(
75
+ [
76
+ " <directory>{:s}</directory>".format(d)
77
+ for d in sources
78
+ ]
79
+ )
80
+ )
81
+ with open(targetfile, "w") as fhs:
66
82
  fhs.write(sconf)
67
83
  return targetfile
68
84
 
69
85
  def ddt_prefix_cmd(self, sources=(), workdir=None):
70
86
  """Generate the prefix command required to start DDT."""
71
87
  if sources:
72
- return [self.ddtpath,
73
- '--session={:s}'.format(self._dump_forge_session(sources, workdir=workdir)),
74
- '--connect']
88
+ return [
89
+ self.ddtpath,
90
+ "--session={:s}".format(
91
+ self._dump_forge_session(sources, workdir=workdir)
92
+ ),
93
+ "--connect",
94
+ ]
75
95
  else:
76
- return [self.ddtpath, '--connect']
96
+ return [self.ddtpath, "--connect"]