Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tidy & homogenise usage of CylcOptionParser #4809

Merged
merged 1 commit into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 37 additions & 22 deletions cylc/flow/option_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
setup_segregated_log_streams,
)

WORKFLOW_ID_ARG_DOC = ('WORKFLOW', 'Workflow ID')
WORKFLOW_ID_MULTI_ARG_DOC = ('WORKFLOW ...', 'Workflow ID(s)')
WORKFLOW_ID_OR_PATH_ARG_DOC = ('WORKFLOW | PATH', 'Workflow ID or path')
ID_MULTI_ARG_DOC = ('ID ...', 'Workflow/Cycle/Family/Task ID(s)')
FULL_ID_MULTI_ARG_DOC = ('ID ...', 'Cycle/Family/Task ID(s)')

icp_option = Option(
"--initial-cycle-point", "--icp",
Expand Down Expand Up @@ -227,21 +232,29 @@ def __init__(
jset: bool = False,
multitask: bool = False,
multiworkflow: bool = False,
prep: bool = False,
auto_add: bool = True,
color: bool = True,
segregated_log: bool = False
) -> None:

"""
Args:
usage: Usage instructions. Typically this will be the __doc__ of
the script module.
argdoc: The args for the command, to be inserted into the usage
instructions. Optional list of tuples of (name, description).
comms: If True, allow the --comms-timeout option.
jset: If True, allow the Jinja2 --set option.
multitask: If True, insert the multitask text into the
usage instructions.
multiworkflow: If True, insert the multiworkflow text into the
usage instructions.
auto_add: If True, allow the standard options.
color: If True, allow the --color option.
segregated_log: If False, write all logging entries to stderr.
If True, write entries at level < WARNING to stdout and
entries at level >= WARNING to stderr.
"""
self.auto_add = auto_add
if argdoc is None:
if prep:

# TODO

argdoc = [('WORKFLOW | PATH', 'Workflow ID or path')]
else:
argdoc = [('WORKFLOW', 'Workflow ID')]

if multiworkflow:
usage += self.MULTIWORKFLOW_USAGE
Expand All @@ -255,31 +268,26 @@ def __init__(
self.unlimited_args = False
self.comms = comms
self.jset = jset
self.prep = prep
self.color = color
# Whether to log messages that are below warning level to stdout
# instead of stderr:
self.segregated_log = segregated_log

maxlen = 0
for arg in argdoc:
if len(arg[0]) > maxlen:
maxlen = len(arg[0])

if argdoc:
maxlen = max(len(arg) for arg, _ in argdoc)
usage += "\n\nArguments:"
for arg in argdoc:
if arg[0].startswith('['):
for arg, descr in argdoc:
if arg.startswith('['):
self.n_optional_args += 1
else:
self.n_compulsory_args += 1
if arg[0].endswith('...]'):
if arg.rstrip(']').endswith('...'):
self.unlimited_args = True

args += arg[0] + " "
args += arg + " "

pad = (maxlen - len(arg[0])) * ' ' + ' '
usage += "\n " + arg[0] + pad + arg[1]
pad = (maxlen - len(arg)) * ' ' + ' '
usage += "\n " + arg + pad + descr
usage = usage.replace('ARGS', args)

OptionParser.__init__(
Expand Down Expand Up @@ -479,6 +487,13 @@ def parse_args(self, api_args, remove_opts=None):

return (options, args)

@staticmethod
def optional(arg: Tuple[str, str]) -> Tuple[str, str]:
"""Make an argdoc tuple display as an optional arg with
square brackets."""
name, doc = arg
return (f'[{name}]', doc)
Comment on lines +490 to +495
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is actually helpful but don't mind it that much.



class Options:
"""Wrapper to allow Python API access to optparse CLI functionality.
Expand Down
8 changes: 4 additions & 4 deletions cylc/flow/scheduler_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
)
from cylc.flow.network.client import WorkflowRuntimeClient
from cylc.flow.option_parsers import (
WORKFLOW_ID_ARG_DOC,
CylcOptionParser as COP,
Options,
icp_option,
Expand Down Expand Up @@ -95,8 +96,6 @@
"""


WORKFLOW_NAME_ARG_DOC = ("WORKFLOW", "Workflow name or ID")

RESUME_MUTATION = '''
mutation (
$wFlows: [WorkflowID]!
Expand All @@ -111,13 +110,14 @@


@lru_cache()
def get_option_parser(add_std_opts=False):
def get_option_parser(add_std_opts: bool = False) -> COP:
"""Parse CLI for "cylc play"."""
parser = COP(
PLAY_DOC,
jset=True,
comms=True,
argdoc=[WORKFLOW_NAME_ARG_DOC])
argdoc=[WORKFLOW_ID_ARG_DOC]
)

parser.add_option(
"-n", "--no-detach", "--non-daemon",
Expand Down
9 changes: 6 additions & 3 deletions cylc/flow/scripts/broadcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@
from cylc.flow.exceptions import InputError
from cylc.flow.network.client_factory import get_client
from cylc.flow.network.multi import call_multi
from cylc.flow.option_parsers import CylcOptionParser as COP
from cylc.flow.option_parsers import (
WORKFLOW_ID_MULTI_ARG_DOC,
CylcOptionParser as COP,
)
from cylc.flow.parsec.config import ParsecConfig
from cylc.flow.parsec.validate import cylc_config_validate
from cylc.flow.print_tree import get_tree
Expand Down Expand Up @@ -225,13 +228,13 @@ def report_bad_options(bad_options, is_set=False):
return bad_opts


def get_option_parser():
def get_option_parser() -> COP:
"""CLI for "cylc broadcast"."""
parser = COP(
__doc__,
comms=True,
multiworkflow=True,
argdoc=[('WORKFLOW_ID [WORKFLOW_ID ...]', 'Workflow ID(s)')],
argdoc=[WORKFLOW_ID_MULTI_ARG_DOC],
)

parser.add_option(
Expand Down
5 changes: 3 additions & 2 deletions cylc/flow/scripts/cat_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
from cylc.flow.hostuserutil import is_remote_platform
from cylc.flow.id_cli import parse_id
from cylc.flow.option_parsers import (
ID_MULTI_ARG_DOC,
CylcOptionParser as COP,
verbosity_to_opts,
)
Expand Down Expand Up @@ -219,12 +220,12 @@ def view_log(logpath, mode, tailer_tmpl, batchview_cmd=None, remote=False,
return proc.wait()


def get_option_parser():
def get_option_parser() -> COP:
"""Set up the CLI option parser."""
parser = COP(
__doc__,
argdoc=[
("ID [...]", "Workflow/Cycle/Task ID"),
ID_MULTI_ARG_DOC,
]
)

Expand Down
18 changes: 12 additions & 6 deletions cylc/flow/scripts/check_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@
from typing import TYPE_CHECKING

import cylc.flow.flags
from cylc.flow.option_parsers import CylcOptionParser as COP
from cylc.flow.option_parsers import (
WORKFLOW_ID_OR_PATH_ARG_DOC,
CylcOptionParser as COP,
)
from cylc.flow.cylc_subproc import procopen, PIPE, DEVNULL
from cylc.flow import __version__ as CYLC_VERSION
from cylc.flow.config import WorkflowConfig
Expand All @@ -54,15 +57,18 @@
def get_option_parser():
parser = COP(
__doc__,
prep=True,
jset=True,
argdoc=[('WORKFLOW_ID', 'Workflow ID or path to source')],
argdoc=[WORKFLOW_ID_OR_PATH_ARG_DOC],
)

parser.add_option(
"-e", "--error", help="Exit with error status "
"if " + CYLC_VERSION + " is not available on all remote platforms.",
action="store_true", default=False, dest="error")
"-e", "--error",
help=(
f"Exit with error status if {CYLC_VERSION} is not available "
"on all remote platforms."
),
action="store_true", default=False, dest="error"
)

return parser

Expand Down
8 changes: 6 additions & 2 deletions cylc/flow/scripts/clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@
import cylc.flow.flags
from cylc.flow.id_cli import parse_ids_async
from cylc.flow.loggingutil import disable_timestamps
from cylc.flow.option_parsers import CylcOptionParser as COP, Options
from cylc.flow.option_parsers import (
WORKFLOW_ID_MULTI_ARG_DOC,
CylcOptionParser as COP,
Options,
)
from cylc.flow.terminal import cli_function, is_terminal
from cylc.flow.workflow_files import init_clean, get_contained_workflows

Expand All @@ -78,7 +82,7 @@ def get_option_parser():
parser = COP(
__doc__,
multiworkflow=True,
argdoc=[('WORKFLOW_ID [WORKFLOW_ID ...]', 'Workflow IDs')],
argdoc=[WORKFLOW_ID_MULTI_ARG_DOC],
segregated_log=True,
)

Expand Down
15 changes: 11 additions & 4 deletions cylc/flow/scripts/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
from typing import TYPE_CHECKING

from cylc.flow.id_cli import parse_id
from cylc.flow.option_parsers import CylcOptionParser as COP
from cylc.flow.option_parsers import (
WORKFLOW_ID_ARG_DOC,
CylcOptionParser as COP,
)
from cylc.flow.network.client import WorkflowRuntimeClient
from cylc.flow.network.server import PB_METHOD_MAP
from cylc.flow.terminal import cli_function
Expand All @@ -43,9 +46,13 @@


def get_option_parser():
parser = COP(__doc__, comms=True, argdoc=[
('WORKFLOW_ID', 'Workflow ID'),
('METHOD', 'Network API function name')])
parser = COP(
__doc__, comms=True,
argdoc=[
WORKFLOW_ID_ARG_DOC,
('METHOD', 'Network API function name')
]
)

parser.add_option(
'-n', '--no-input',
Expand Down
10 changes: 7 additions & 3 deletions cylc/flow/scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@
from cylc.flow.config import WorkflowConfig
from cylc.flow.id_cli import parse_id
from cylc.flow.exceptions import InputError
from cylc.flow.option_parsers import CylcOptionParser as COP, icp_option
from cylc.flow.option_parsers import (
WORKFLOW_ID_OR_PATH_ARG_DOC,
CylcOptionParser as COP,
icp_option,
)
from cylc.flow.pathutil import get_workflow_run_dir
from cylc.flow.templatevars import get_template_vars
from cylc.flow.terminal import cli_function
Expand All @@ -66,10 +70,10 @@
from optparse import Values


def get_option_parser():
def get_option_parser() -> COP:
parser = COP(
__doc__,
argdoc=[("[WORKFLOW_ID]", "Workflow ID or path to source")],
argdoc=[COP.optional(WORKFLOW_ID_OR_PATH_ARG_DOC)],
jset=True,
)

Expand Down
8 changes: 6 additions & 2 deletions cylc/flow/scripts/cycle_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,16 @@
from metomi.isodatetime.exceptions import IsodatetimeError


def get_option_parser():
def get_option_parser() -> COP:
parser = COP(
__doc__,
color=False,
argdoc=[
('[POINT]', 'ISO8601 date-time, default=$CYLC_TASK_CYCLE_POINT')])
COP.optional(
('POINT', 'ISO8601 date-time, default=$CYLC_TASK_CYCLE_POINT')
)
]
)

parser.add_option(
"--offset-hours", metavar="HOURS",
Expand Down
15 changes: 10 additions & 5 deletions cylc/flow/scripts/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
from typing import TYPE_CHECKING

from cylc.flow.id_cli import parse_id
from cylc.flow.option_parsers import CylcOptionParser as COP, icp_option
from cylc.flow.option_parsers import (
WORKFLOW_ID_OR_PATH_ARG_DOC,
CylcOptionParser as COP,
icp_option,
)
from cylc.flow.config import WorkflowConfig
from cylc.flow.templatevars import load_template_vars
from cylc.flow.terminal import cli_function
Expand Down Expand Up @@ -114,12 +118,13 @@ def prdict(dct, arrow='<', section='', level=0, diff=False, nested=False):
print(' ' + arrow + ' ', key, '=', dct[key])


def get_option_parser():
def get_option_parser() -> COP:
parser = COP(
__doc__, jset=True, prep=True,
__doc__,
jset=True,
argdoc=[
('WORKFLOW_ID_1', 'Workflow ID or path to source'),
('WORKFLOW_ID_2', 'Workflow ID or path to source')
(f'WORKFLOW_{n}', WORKFLOW_ID_OR_PATH_ARG_DOC[1])
for n in (1, 2)
]
)

Expand Down
7 changes: 5 additions & 2 deletions cylc/flow/scripts/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@

from cylc.flow.exceptions import CylcError
from cylc.flow.id_cli import parse_id
from cylc.flow.option_parsers import CylcOptionParser as COP
from cylc.flow.option_parsers import (
WORKFLOW_ID_ARG_DOC,
CylcOptionParser as COP,
)
from cylc.flow.network.client_factory import get_client
from cylc.flow.terminal import cli_function

Expand Down Expand Up @@ -147,7 +150,7 @@ def get_option_parser():
parser = COP(
__doc__,
comms=True,
argdoc=[('WORKFLOW_ID', 'Workflow ID')],
argdoc=[WORKFLOW_ID_ARG_DOC],
)
parser.add_option(
"-g", "--global", help="Global information only.",
Expand Down
Loading