Skip to content

Commit d2a4f42

Browse files
committed
Add support for Rocoto <hangdependency> element (#778)
1 parent 1bd1bcc commit d2a4f42

File tree

5 files changed

+64
-1
lines changed

5 files changed

+64
-1
lines changed

docs/sections/user_guide/yaml/rocoto.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ Let's dissect the following task example:
172172
envars:
173173
person: siri
174174
dependency:
175+
hangdependency:
175176
176177
Each task is named by its UW YAML key. Blocks under ``tasks:`` prefixed with ``task_`` will be named with what follows the prefix. In the example above the task will be named ``hello`` and will appear in the XML like this:
177178

@@ -197,7 +198,7 @@ The name of the task can be any string accepted by Rocoto as a task name (includ
197198
<value>siri</value>
198199
</envar>
199200
200-
``dependency:`` -- [Optional] Any number of dependencies accepted by Rocoto. This section is described in more detail below.
201+
``dependency:`` and ``hangdependency`` -- [Optional] Any number of dependencies accepted by Rocoto. This section is described in more detail below.
201202

202203
The other keys not specifically mentioned here follow the same conventions as described in the :rocoto:`Rocoto<>` documentation.
203204

@@ -274,6 +275,11 @@ The ``datadep_foo:`` and ``datadep_bar:`` UW YAML keys were named arbitrarily af
274275

275276
This example also demonstrates the use of Rocoto's **boolean operator tags** in the structured UW YAML, e.g., ``<or>``, ``<not>``, etc. The structure follows the tree in the Rocoto XML language in that each of the subelements of the ``<and>`` tag translates to a subtree in UW YAML. Multiple boolean operator tags can be set at the same level, just as with any other tag type, by adding a descriptive suffix starting with an underscore. In the above example, the ``and:`` key could have equivalently been named ``and_data_files:`` to achieve an identical Rocoto XML result.
276277

278+
``hangdependency:``
279+
^^^^^^^^^^^^^^^^^^^
280+
281+
A ``hangdependency:`` block supports syntax identical to a ``dependency:`` block. Rocoto will interpret the resulting ``<hangdependency>`` XML element as specifying one or more conditions that, when satisfied, indicate that the task is hung and should be killed.
282+
277283
Defining Metatasks
278284
------------------
279285

src/uwtools/resources/jsonschema/rocoto.jsonschema

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@
401401
"exclusive": {
402402
"type": "string"
403403
},
404+
"hangdependency": {
405+
"$ref": "#/$defs/dependency"
406+
},
404407
"jobname": {
405408
"$ref": "#/$defs/compoundTimeString"
406409
},

src/uwtools/rocoto.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ def _add_task(self, e: _Element, config: dict, name_attr: str) -> None:
183183
self._add_task_envar(e, name, value)
184184
if STR.dependency in config:
185185
self._add_task_dependency(e, config[STR.dependency])
186+
if STR.hangdependency in config:
187+
self._add_task_hangdependency(e, config[STR.hangdependency])
186188

187189
def _add_task_dependency(self, e: _Element, config: dict) -> None:
188190
"""
@@ -308,6 +310,17 @@ def _add_task_envar(self, e: _Element, name: str, value: str) -> None:
308310

309311
self._add_compound_time_string(e, value, STR.value)
310312

313+
def _add_task_hangdependency(self, e: _Element, config: dict) -> None:
314+
"""
315+
Add a <hangdependency> element to the <task>.
316+
317+
:param e: The parent element to add the new element to.
318+
:param config: Configuration data for this element.
319+
"""
320+
e = SubElement(e, STR.hangdependency)
321+
for tag, subconfig in config.items():
322+
self._add_task_dependency_child(e, subconfig, tag)
323+
311324
def _add_workflow(self, config: dict) -> None:
312325
"""
313326
Create the root <workflow> element.
@@ -452,6 +465,7 @@ class STR:
452465
envar: str = "envar"
453466
envars: str = "envars"
454467
exclusive: str = "exclusive"
468+
hangdependency: str = "hangdependency"
455469
jobname: str = "jobname"
456470
join: str = "join"
457471
log: str = "log"

src/uwtools/tests/fixtures/hello_workflow.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ workflow:
2121
maxtries: 2
2222
account: "&ACCOUNT;"
2323
command: "echo account for $person is &ACCOUNT; && true"
24+
hangdependency:
25+
sh_false:
26+
command: /bin/false
2427
jobname:
2528
cyclestr:
2629
attrs:
@@ -46,3 +49,6 @@ workflow:
4649
taskdep:
4750
attrs:
4851
task: hello
52+
hangdependency:
53+
sh_false:
54+
command: /bin/false

src/uwtools/tests/test_schemas.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,40 @@ def test_schema_rocoto_metatask_attrs():
18091809
assert "'foo' is not of type 'integer'\n" in errors({"throttle": "foo"})
18101810

18111811

1812+
def test_schema_rocoto_task_dependency():
1813+
errors = schema_validator("rocoto", "properties", "workflow", "properties", "tasks")
1814+
config = {
1815+
"task_foo": {
1816+
"command": "/bin/true",
1817+
"dependency": {
1818+
"sh_true": {
1819+
"command": "/bin/true",
1820+
},
1821+
},
1822+
"cores": 1,
1823+
"walltime": "00:01:00",
1824+
}
1825+
}
1826+
assert not errors(config)
1827+
1828+
1829+
def test_schema_rocoto_task_hangdependency():
1830+
errors = schema_validator("rocoto", "properties", "workflow", "properties", "tasks")
1831+
config = {
1832+
"task_foo": {
1833+
"command": "/bin/true",
1834+
"hangdependency": {
1835+
"sh_false": {
1836+
"command": "/bin/false",
1837+
},
1838+
},
1839+
"cores": 1,
1840+
"walltime": "00:01:00",
1841+
}
1842+
}
1843+
assert not errors(config)
1844+
1845+
18121846
def test_schema_rocoto_workflow_cycledef():
18131847
errors = schema_validator("rocoto", "properties", "workflow", "properties", "cycledef")
18141848
# Basic spec:

0 commit comments

Comments
 (0)