Skip to content

Commit

Permalink
list subclass to indicate unassigned list values in expanded config
Browse files Browse the repository at this point in the history
  • Loading branch information
TomekTrzeciak committed Dec 6, 2024
1 parent 3b8a7df commit 0761f1a
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 26 deletions.
6 changes: 5 additions & 1 deletion cylc/flow/parsec/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
from optparse import Values


class DefaultList(list):
"""List subclass to indicate unassigned list values in expanded config."""


class ParsecConfig:
"""Object wrapper for parsec functions."""

Expand Down Expand Up @@ -112,7 +116,7 @@ def expand(self) -> None:
else:
if node.default == ConfigNode.UNSET:
if node.vdr and node.vdr.endswith('_LIST'):
defs[node.name] = []
defs[node.name] = DefaultList()
else:
defs[node.name] = None
else:
Expand Down
34 changes: 19 additions & 15 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] = type(val)(val)
target[key] = 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, type(val)(val))
setitem(key, val[:])
else:
setitem(key, val)

Expand Down Expand Up @@ -290,21 +290,25 @@ def m_override(target, sparse):
stack.append(
(val, dest[key], keylist + [key], child_many_defaults))
else:
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 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 isinstance(val, list):
dest[key] = type(val)(val)
dest[key] = val[:]
else:
dest[key] = val
for dest_dict, defaults in defaults_list:
Expand Down
7 changes: 1 addition & 6 deletions 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 UserList(values)
return values

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


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


class CylcConfigValidator(ParsecValidator):
"""Type validator and coercer for Cylc configurations.
Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/workflow_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +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.parsec.config import DefaultList
from cylc.flow.subprocctx import SubProcContext

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

Expand Down
3 changes: 1 addition & 2 deletions tests/unit/test_workflow_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

from types import SimpleNamespace

from cylc.flow.parsec.validate import UserList
from cylc.flow.workflow_events import (
WorkflowEventHandler,
get_template_variables,
Expand Down Expand Up @@ -66,7 +65,7 @@ def test_get_events_handler(
config = SimpleNamespace()
config.cfg = {
'scheduler': {
'events': {'handlers': ['stall'], 'mail events': UserList()},
'events': {'handlers': ['stall'], 'mail events': []},
'mail': {'from': 'docklands@railway'},
} if workflow_cfg else {'events': {}}
}
Expand Down

0 comments on commit 0761f1a

Please sign in to comment.