Skip to content

Commit

Permalink
VIP implemented.
Browse files Browse the repository at this point in the history
written a functional test

written a functional test
  • Loading branch information
wxtim committed Aug 31, 2022
1 parent 8a991ee commit 5787a3a
Show file tree
Hide file tree
Showing 10 changed files with 592 additions and 217 deletions.
180 changes: 145 additions & 35 deletions cylc/flow/option_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@

SHORTLINK_TO_ICP_DOCS = "https://bit.ly/3MYHqVh"

ARGS = 'args'
KWARGS = 'kwargs'
HELP = 'help'
ACTION = 'action'
STORE = 'store'
DEFAULT = 'default'
DEST = 'dest'
METAVAR = 'metavar'
CHOICES = 'choices'
OPTS = 'opts'

icp_option = Option(
"--initial-cycle-point", "--icp",
metavar="CYCLE_POINT or OFFSET",
Expand All @@ -65,6 +76,21 @@
)


ICP_OPTION = {
'args': ["--initial-cycle-point", "--icp"],
'kwargs': {
"metavar": "CYCLE_POINT or OFFSET",
"help":
"Set the initial cycle point. "
"Required if not defined in flow.cylc."
"\nMay be either an absolute point or an offset: See "
f"{SHORTLINK_TO_ICP_DOCS} (Cylc documentation link).",
"action": "store",
"dest": "icp",
}
}


def format_shell_examples(string):
"""Put comments in the terminal "diminished" colour."""
return cparse(
Expand Down Expand Up @@ -416,44 +442,59 @@ def add_std_options(self):
),
action="store", default=None, dest="templatevars_file")

def add_cylc_rose_options(self) -> None:
"""Add extra options for cylc-rose plugin if it is installed."""
@staticmethod
def get_cylc_rose_options():
"""Returns a list of option dictionaries if Cylc Rose exists."""
try:
__import__('cylc.rose')
except ImportError:
return
self.add_option(
"--opt-conf-key", "-O",
help=(
"Use optional Rose Config Setting "
"(If Cylc-Rose is installed)"
),
action="append",
default=[],
dest="opt_conf_keys"
)
self.add_option(
"--define", '-D',
help=(
"Each of these overrides the `[SECTION]KEY` setting in a "
"`rose-suite.conf` file. "
"Can be used to disable a setting using the syntax "
"`--define=[SECTION]!KEY` or even `--define=[!SECTION]`."
),
action="append",
default=[],
dest="defines"
)
self.add_option(
"--rose-template-variable", '-S', '--define-suite',
help=(
"As `--define`, but with an implicit `[SECTION]` for "
"workflow variables."
),
action="append",
default=[],
dest="rose_template_vars"
)
return []
return [
{
ARGS: ["--opt-conf-key", "-O"],
KWARGS: {
HELP:
"Use optional Rose Config Setting "
"(If Cylc-Rose is installed)",
ACTION: "append",
DEFAULT: [],
DEST: "opt_conf_keys"
}
},
{
ARGS: ["--define", '-D'],
KWARGS: {
HELP:
"Each of these overrides the `[SECTION]KEY` setting"
"in a `rose-suite.conf` file. "
"Can be used to disable a setting using the syntax "
"`--define=[SECTION]!KEY` or "
"even `--define=[!SECTION]`.",
ACTION: "append",
DEFAULT: [],
DEST: "defines"
}
},
{
ARGS: ["--rose-template-variable", '-S', '--define-suite'],
KWARGS: {
HELP:
"As `--define`, but with an implicit `[SECTION]` for "
"workflow variables.",
ACTION: "append",
DEFAULT: [],
DEST: "rose_template_vars"
}
}
]

def add_cylc_rose_options(self) -> None:
"""Add extra options for cylc-rose plugin if it is installed.
Now a vestigal interface for get_cylc_rose_options.
"""
for option in self.get_cylc_rose_options():
self.add_option(*option[ARGS], **option[KWARGS])

def parse_args(self, api_args, remove_opts=None):
"""Parse options and arguments, overrides OptionParser.parse_args.
Expand Down Expand Up @@ -583,3 +624,72 @@ def __call__(self, **kwargs) -> Values:
setattr(opts, key, value)

return opts


from typing import Dict


def combine_options_pair(
first: List[Dict], second: List[Dict]
) -> List[Dict]:
"""Combine just two options lists
TODO: Record which list each option came from, so that you can tell
the user which component script is being referred to by each option.
"""
output = []
from itertools import product
for x, y in product(first, second):
if x.items() == y.items():
output.append(x)
if any([i == j for i, j in product(y[ARGS], x[ARGS])]) and x != y:
# Spot any clashing CLI options.
# TODO: Possibly re-write so as to have more useful error?
if x[ARGS] != y[ARGS]:
x[ARGS] = set(x[ARGS]) - set(y[ARGS])
y[ARGS] = set(y[ARGS]) - set(x[ARGS])
else:
raise Exception(f'Clashing Options \n{x}\n{y}')
if x not in output:
output.append(x)
if y not in output:
output.append(y)

return output


def combine_options(*args: List[Dict]) -> List[Dict]:
"""Combine a list of argument dicts in order
Examples:
>>> foo = [{'args': ['-i', '--inflammable'],
... 'opts': {'help': 'inflammable means the same as flammable!'}}]
>>> bar = [{'args': ['-f', '--flammable']
... 'opts': {'help': 'English is an odd language'}}]
>>> result = combine_options(foo, bar)
>>> result == [foo, bar]
True
"""
x = list(args)
while len(x) > 1:
x.insert(0, combine_options_pair(x.pop(0), x.pop(0)))
return x[0]


def cleanup_sysargv(
script_name: str, workflow_name: str, allowed_options: Dict[List, Dict]
)-> None:
"""Cylc Play needs sys.argv to be correct to work."""
allowed_option_names = [
option for allowed_option in allowed_options
for option in allowed_option[ARGS]
]
# Re-creates options filtering out non-cylc-play options.
opts = []
for opt in [y for x in sys.argv[3:] for y in x.split('=')]:
if opt.startswith('-'):
key = opt
if key in allowed_option_names:
opts.append(opt)

sys.argv = [sys.argv[0], script_name, workflow_name] + opts
Loading

0 comments on commit 5787a3a

Please sign in to comment.