Skip to content

Commit

Permalink
Clear up terminology (#66)
Browse files Browse the repository at this point in the history
* f

* f

* Clear up terminology

---------

Co-authored-by: Tim Pillinger <[email protected]>
  • Loading branch information
MetRonnie and wxtim authored Nov 14, 2024
1 parent 995ab27 commit 60a75b3
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 27 deletions.
7 changes: 4 additions & 3 deletions cylc/flow/run_modes/skip.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ def process_outputs(itask: 'TaskProxy', rtconfig: Dict) -> List[str]:
# which we hold back, to prevent warnings about pre-requisites being
# unmet being shown because a "finished" output happens to come first.
for message in itask.state.outputs.iter_required_messages(
exclude=(
TASK_OUTPUT_SUCCEEDED if TASK_OUTPUT_FAILED
in conf_outputs else TASK_OUTPUT_FAILED
disable=(
TASK_OUTPUT_SUCCEEDED
if TASK_OUTPUT_FAILED in conf_outputs
else TASK_OUTPUT_FAILED
)
):
trigger = itask.state.outputs._message_to_trigger[message]
Expand Down
28 changes: 18 additions & 10 deletions cylc/flow/task_outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def get_completion_expression(tdef: 'TaskDef') -> str:
def get_optional_outputs(
expression: str,
outputs: Iterable[str],
force_optional: "Optional[str]" = None
disable: "Optional[str]" = None
) -> Dict[str, Optional[bool]]:
"""Determine which outputs in an expression are optional.
Expand All @@ -204,8 +204,9 @@ def get_optional_outputs(
The completion expression.
outputs:
All outputs that apply to this task.
force_optional:
Don't have the CompletionEvaluator consider this output.
disable:
Disable this output and any others it is joined with by `and`
(which will mean they are necessarily optional).
Returns:
dict: compvar: is_optional
Expand Down Expand Up @@ -236,7 +237,14 @@ def get_optional_outputs(
>>> sorted(get_optional_outputs(
... '(succeeded and towel) or (failed and bugblatter)',
... {'succeeded', 'towel', 'failed', 'bugblatter'},
... 'failed'
... ).items())
[('bugblatter', True), ('failed', True),
('succeeded', True), ('towel', True)]
>>> sorted(get_optional_outputs(
... '(succeeded and towel) or (failed and bugblatter)',
... {'succeeded', 'towel', 'failed', 'bugblatter'},
... disable='failed'
... ).items())
[('bugblatter', True), ('failed', True),
('succeeded', False), ('towel', False)]
Expand All @@ -249,7 +257,7 @@ def get_optional_outputs(
all_compvars = {trigger_to_completion_variable(out) for out in outputs}

# Allows exclusion of additional outcomes:
extra_excludes = {force_optional: False} if force_optional else {}
extra_excludes = {disable: False} if disable else {}

return { # output: is_optional
# the outputs that are used in the expression
Expand Down Expand Up @@ -627,22 +635,22 @@ def _is_compvar_complete(self, compvar: str) -> Optional[bool]:

def iter_required_messages(
self,
exclude: 'Optional[Literal["succeeded", "failed"]]' = None
disable: 'Optional[Literal["succeeded", "failed"]]' = None
) -> Iterator[str]:
"""Yield task messages that are required for this task to be complete.
Note, in some cases tasks might not have any required messages,
e.g. "completion = succeeded or failed".
Args:
exclude: Don't check wether this output is required for
completion - in skip mode we only want to check either
succeeded or failed, but not both.
disable: Consider this output and any others it is joined with by
`and` to not exist. In skip mode we only want to check either
succeeded or failed, but not both.
"""
for compvar, is_optional in get_optional_outputs(
self._completion_expression,
set(self._message_to_compvar.values()),
force_optional=exclude
disable=disable
).items():
if is_optional is False:
for message, _compvar in self._message_to_compvar.items():
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/run_modes/test_skip_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def test_process_outputs(outputs, required, expect):
rtconfig=rtconf),
state=SimpleNamespace(
outputs=SimpleNamespace(
iter_required_messages=lambda exclude: iter(required),
iter_required_messages=lambda *a, **k: iter(required),
_message_to_trigger={v: v for v in required}
)))

Expand All @@ -115,7 +115,7 @@ def test_skip_mode_validate(caplog, log_filter):
https://github.com/cylc/cylc-admin/blob/master/docs/proposal-skip-mode.md
| If the run mode is set to simulation or skip in the workflow
| configuration, then cylc validate and cylc lint should produce
| configuration, then cylc validate and cylc lint should produce
| warning (similar to development features in other languages / systems).
"""
taskdefs = {
Expand Down
36 changes: 24 additions & 12 deletions tests/unit/test_task_outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ def test_iter_required_outputs():
'y',
}


def test_iter_required_outputs__disable():
# Get all outputs required for success path (excluding failure, what
# is still required):
outputs = TaskOutputs(
Expand All @@ -298,21 +300,31 @@ def test_iter_required_outputs():
)
)

# Excluding succeeded leaves us with failure required outputs:
assert set(outputs.iter_required_messages(
exclude=TASK_OUTPUT_SUCCEEDED)) == {
TASK_OUTPUT_FAILED, 'x', 'y',}
assert set(outputs.iter_required_messages()) == set()

# Excluding failed leaves us with succeeded required outputs:
assert set(outputs.iter_required_messages(
exclude=TASK_OUTPUT_FAILED)) == {
TASK_OUTPUT_SUCCEEDED, 'a', 'b',}
# Disabling succeeded leaves us with failure required outputs:
assert set(
outputs.iter_required_messages(disable=TASK_OUTPUT_SUCCEEDED)
) == {
TASK_OUTPUT_FAILED,
'x',
'y',
}

# Excluding an abitrary output leaves us with required outputs
# Disabling failed leaves us with succeeded required outputs:
assert set(outputs.iter_required_messages(disable=TASK_OUTPUT_FAILED)) == {
TASK_OUTPUT_SUCCEEDED,
'a',
'b',
}

# Disabling an abitrary output leaves us with required outputs
# from another branch:
assert set(outputs.iter_required_messages(
exclude='a')) == {
TASK_OUTPUT_FAILED, 'x', 'y',}
assert set(outputs.iter_required_messages(disable='a')) == {
TASK_OUTPUT_FAILED,
'x',
'y',
}


def test_get_trigger_completion_variable_maps():
Expand Down

0 comments on commit 60a75b3

Please sign in to comment.