Skip to content

Commit

Permalink
UserList to tell apart user set empty list from undefined value
Browse files Browse the repository at this point in the history
  • Loading branch information
TomekTrzeciak committed Dec 6, 2024
1 parent 4949998 commit 3b8a7df
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 25 deletions.
34 changes: 15 additions & 19 deletions cylc/flow/parsec/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def replicate(target, source):
target[key].defaults_ = pdeepcopy(val.defaults_)
replicate(target[key], val)
elif isinstance(val, list):
target[key] = val[:]
target[key] = type(val)(val)
else:
target[key] = val

Expand Down Expand Up @@ -247,7 +247,7 @@ def poverride(target, sparse, prepend=False):
# Override in-place in the target ordered dict.
setitem = target.__setitem__
if isinstance(val, list):
setitem(key, val[:])
setitem(key, type(val)(val))
else:
setitem(key, val)

Expand Down Expand Up @@ -290,25 +290,21 @@ def m_override(target, sparse):
stack.append(
(val, dest[key], keylist + [key], child_many_defaults))
else:
if key not in dest:
if not (
'__MANY__' in dest
or key in many_defaults
or '__MANY__' in many_defaults
):
# TODO - validation prevents this, but handle properly
# for completeness.
raise Exception(
"parsec dict override: no __MANY__ placeholder" +
"%s" % (keylist + [key])
)
if isinstance(val, list):
dest[key] = val[:]
else:
dest[key] = val
if not (
key in dest
or '__MANY__' in dest
or key in many_defaults
or '__MANY__' in many_defaults
):
# TODO - validation prevents this, but handle properly
# for completeness.
raise Exception(
"parsec dict override: no __MANY__ placeholder" +
"%s" % (keylist + [key])
)

if isinstance(val, list):
dest[key] = val[:]
dest[key] = type(val)(val)
else:
dest[key] = val
for dest_dict, defaults in defaults_list:
Expand Down
7 changes: 6 additions & 1 deletion cylc/flow/parsec/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ def strip_and_unquote_list(cls, keys, value):
# allow trailing commas
if values[-1] == '':
values = values[0:-1]
return values
return UserList(values)

@classmethod
def _unquoted_list_parse(cls, keys, value):
Expand Down Expand Up @@ -647,6 +647,11 @@ def __str__(self):
return f'{self[0]} .. {self[1]}'


class UserList(list):
# distinguish user defined, possibly empty list from automatic defaults

Check warning on line 651 in cylc/flow/parsec/validate.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/parsec/validate.py#L651

Added line #L651 was not covered by tests
pass


class CylcConfigValidator(ParsecValidator):
"""Type validator and coercer for Cylc configurations.
Expand Down
3 changes: 2 additions & 1 deletion cylc/flow/workflow_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
from cylc.flow.hostuserutil import get_host, get_user
from cylc.flow.log_diagnosis import run_reftest
from cylc.flow.parsec.validate import UserList
from cylc.flow.subprocctx import SubProcContext

if TYPE_CHECKING:
Expand Down Expand Up @@ -235,7 +236,7 @@ def get_events_conf(
glbl_cfg().get(['scheduler', 'mail'])
):
value = getter.get(key)
if value is not None:
if value not in (None, []) or isinstance(value, UserList):
return value
return default

Expand Down
9 changes: 5 additions & 4 deletions tests/unit/test_workflow_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from types import SimpleNamespace

from cylc.flow.parsec.validate import UserList
from cylc.flow.workflow_events import (
WorkflowEventHandler,
get_template_variables,
Expand All @@ -32,11 +33,11 @@
'key, workflow_cfg, glbl_cfg, expected',
[
('handlers', True, True, ['stall']),
('handlers', False, True, []),
('handlers', False, False, []),
('handlers', False, True, None),
('handlers', False, False, None),
('mail events', True, True, []),
('mail events', False, True, ['abort']),
('mail events', False, False, []),
('mail events', False, False, None),
('from', True, True, 'docklands@railway'),
('from', False, True, 'highway@mixture'),
('from', False, False, None),
Expand Down Expand Up @@ -65,7 +66,7 @@ def test_get_events_handler(
config = SimpleNamespace()
config.cfg = {
'scheduler': {
'events': {'handlers': ['stall'], 'mail events': []},
'events': {'handlers': ['stall'], 'mail events': UserList()},
'mail': {'from': 'docklands@railway'},
} if workflow_cfg else {'events': {}}
}
Expand Down

0 comments on commit 3b8a7df

Please sign in to comment.