Skip to content

Commit

Permalink
Merge pull request #5769 from oliver-sanders/id_key
Browse files Browse the repository at this point in the history
undefined
  • Loading branch information
oliver-sanders authored Jan 17, 2024
2 parents 97e5e3d + 615013b commit 90cba23
Show file tree
Hide file tree
Showing 17 changed files with 452 additions and 221 deletions.
1 change: 1 addition & 0 deletions changes.d/5769.feat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Include task messages and workflow port as appropriate in emails configured by "mail events".
89 changes: 34 additions & 55 deletions cylc/flow/id.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class Tokens(dict):
<id: w//c>
>>> Tokens(workflow='w', cycle='c')['job']
# Make a copy (note Tokens are mutable):
# Make a copy (note Tokens are immutable):
>>> tokens.duplicate()
<id: ~u/w//c/t/01>
>>> tokens.duplicate(job='02') # make changes at the same time
Expand Down Expand Up @@ -118,9 +118,10 @@ def __init__(
dict.__init__(self, **kwargs)

def __setitem__(self, key, value):
if key not in self._KEYS:
raise ValueError(f'Invalid token: {key}')
dict.__setitem__(self, key, value)
raise Exception('Tokens objects are not mutable')

def update(self, other):
raise Exception('Tokens objects are not mutable')

def __getitem__(self, key):
try:
Expand Down Expand Up @@ -151,6 +152,9 @@ def __repr__(self):
id_ = self.id
return f'<id: {id_}>'

def __hash__(self):
return hash(tuple(self.values()))

def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
Expand All @@ -159,6 +163,12 @@ def __eq__(self, other):
for key in self._KEYS
)

def __lt__(self, other):
return self.id < other.id

def __gt__(self, other):
return self.id > other.id

def __ne__(self, other):
if not isinstance(other, self.__class__):
return True
Expand Down Expand Up @@ -336,62 +346,20 @@ def is_null(self) -> bool:
>>> tokens = Tokens()
>>> tokens.is_null
True
>>> tokens['job_sel'] = 'x'
>>> tokens.is_null
>>> tokens.duplicate(job_sel='x').is_null
True
>>> tokens['job'] = '01'
>>> tokens.is_null
>>> tokens.duplicate(job='01').is_null
False
"""
return not any(
self[key] for key in self._REGULAR_KEYS
)

def update_tokens(
self,
tokens: 'Optional[Tokens]' = None,
**kwargs
) -> None:
"""Update the tokens dictionary.
Similar to dict.update but with an optional Tokens argument.
Examples:
>>> tokens = Tokens('x')
>>> tokens.update_tokens(workflow='y')
>>> tokens
<id: y>
>>> tokens.update_tokens(Tokens('z'))
>>> tokens
<id: z>
>>> tokens.update_tokens(Tokens('a'), cycle='b')
>>> tokens
<id: a//b>
"""
if tokens:
for key, value in tokens.items():
self[key] = value
for key, value in kwargs.items():
self[key] = value

def update(self, other):
"""dict.update.
Example:
>>> tokens = Tokens(workflow='w')
>>> tokens.update({'cycle': 'c'})
>>> tokens.id
'w//c'
"""
return self.update_tokens(**other)

def duplicate(
self,
tokens: 'Optional[Tokens]' = None,
**kwargs
*tokens_list,
**kwargs,
) -> 'Tokens':
"""Duplicate a tokens object.
Expand All @@ -408,17 +376,28 @@ def duplicate(
>>> id(tokens1) == id(tokens2)
False
Make a copy and modify it:
Make a copy with a modification:
>>> tokens1.duplicate(cycle='1').id
'~u/w//1'
Original not changed
The Original is not changed:
>>> tokens1.id
'~u/w'
Arguments override in definition order:
>>> Tokens.duplicate(
... tokens1,
... Tokens(cycle='c', task='a', job='01'),
... task='b'
... ).id
'~u/w//c/b/01'
"""
ret = Tokens(self)
ret.update_tokens(tokens, **kwargs)
return ret
_kwargs = {}
for tokens in (self, *tokens_list):
_kwargs.update(tokens)
_kwargs.update(kwargs)
return Tokens(**_kwargs)


# //cycle[:sel][/task[:sel][/job[:sel]]]
Expand Down
8 changes: 5 additions & 3 deletions cylc/flow/id_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ async def parse_ids_async(

# infer the run number if not specified the ID (and if possible)
if infer_latest_runs:
_infer_latest_runs(*tokens_list, src_path=src_path)
_infer_latest_runs(tokens_list, src_path=src_path)

_validate_number(
*tokens_list,
Expand Down Expand Up @@ -409,12 +409,14 @@ def _validate_workflow_ids(*tokens_list, src_path):
detect_both_flow_and_suite(src_path)


def _infer_latest_runs(*tokens_list, src_path):
def _infer_latest_runs(tokens_list, src_path):
for ind, tokens in enumerate(tokens_list):
if ind == 0 and src_path:
# source workflow passed in as a path
continue
tokens['workflow'] = infer_latest_run_from_id(tokens['workflow'])
tokens_list[ind] = tokens.duplicate(
workflow=infer_latest_run_from_id(tokens['workflow'])
)
pass


Expand Down
1 change: 0 additions & 1 deletion cylc/flow/scripts/completion_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,6 @@ async def list_in_workflow(tokens: Tokens, infer_run=True) -> t.List[str]:
# list possible IDs
cli_detokenise(
tokens.duplicate(
tokens=None,
# use the workflow ID provided on the CLI to allow
# run name inference
workflow=input_workflow,
Expand Down
Loading

0 comments on commit 90cba23

Please sign in to comment.