Skip to content
Open
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
15 changes: 13 additions & 2 deletions linodecli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
from linodecli import plugins
from linodecli.exit_codes import ExitCodes

from .arg_helpers import register_args, register_plugin, remove_plugin
from .arg_helpers import (
help_subcommand_to_flag,
register_args,
register_plugin,
remove_plugin,
)
from .cli import CLI
from .completion import get_completions
from .configuration import ENV_TOKEN_NAME
Expand Down Expand Up @@ -68,7 +73,13 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
formatter_class=SortingHelpFormatter,
description="The Linode Command Line Interface.\n\nAliases: lin, linode",
)
parsed, args = register_args(parser).parse_known_args()
parser = register_args(parser)
parsed, args = parser.parse_known_args()

# argv is changed in place so that plugins, which read it directly,
# also see the --help flag
if help_subcommand_to_flag(argv, parsed):
parsed, args = parser.parse_known_args()

cli.output_handler.configure(parsed, cli.suppress_warnings)

Expand Down
30 changes: 28 additions & 2 deletions linodecli/arg_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
"""

import sys
from argparse import ArgumentParser
from argparse import ArgumentParser, Namespace
from configparser import ConfigParser
from importlib import import_module
from typing import Dict, Tuple
from typing import Dict, List, Tuple

from linodecli import plugins
from linodecli.helpers import (
Expand Down Expand Up @@ -100,6 +100,32 @@ def register_args(parser: ArgumentParser) -> ArgumentParser:


# TODO: maybe move to plugins/__init__.py
def help_subcommand_to_flag(args: List[str], parsed: Namespace) -> bool:
"""
Replaces `help` given as the command or the action with the --help flag,
modifying args in place, so `linode-cli help linodes` and
`linode-cli linodes help` work like `linode-cli linodes --help`.

`help` in any other position is left alone, since it can be a value,
such as a bucket name.

:param args: The full argument list, including the program name.
:param parsed: The arguments parsed from args.

:returns: Whether args was changed.
"""
if parsed.command == "help":
position = args.index("help")
elif parsed.command is not None and parsed.action == "help":
position = args.index("help", args.index(parsed.command) + 1)
else:
return False

del args[position]
args.append("--help")
return True


def register_plugin(
module: str, config: ConfigParser, ops: Dict[str, str]
) -> Tuple[str, int]:
Expand Down
63 changes: 63 additions & 0 deletions tests/unit/test_arg_helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/usr/local/bin/python3

import argparse

import pytest

from linodecli import arg_helpers


Expand Down Expand Up @@ -149,3 +153,62 @@ def test_remove_plugin_not_available(self, mocked_config):
msg, code = arg_helpers.remove_plugin("testing.plugin", mocked_config)
assert "not a registered plugin" in msg
assert code == 14


def _rewrite_help(args):
parser = arg_helpers.register_args(
argparse.ArgumentParser("linode-cli", add_help=False)
)
parsed, _ = parser.parse_known_args(args[1:])
changed = arg_helpers.help_subcommand_to_flag(args, parsed)
return args, changed


@pytest.mark.parametrize(
"args, expected",
[
(["linode-cli", "help"], ["linode-cli", "--help"]),
(
["linode-cli", "help", "linodes"],
["linode-cli", "linodes", "--help"],
),
(
["linode-cli", "help", "linodes", "create"],
["linode-cli", "linodes", "create", "--help"],
),
(
["linode-cli", "linodes", "help"],
["linode-cli", "linodes", "--help"],
),
(
["linode-cli", "--json", "linodes", "help"],
["linode-cli", "--json", "linodes", "--help"],
),
(["linode-cli", "obj", "help"], ["linode-cli", "obj", "--help"]),
],
)
def test_help_subcommand_to_flag(args, expected):
original = args
args, changed = _rewrite_help(args)

assert changed
assert args == expected
# argv must be changed in place, as linodecli holds a reference to it
assert args is original


@pytest.mark.parametrize(
"args",
[
["linode-cli", "linodes", "list"],
["linode-cli", "linodes", "view", "help"],
["linode-cli", "obj", "mb", "help"],
["linode-cli", "--help"],
],
)
def test_help_subcommand_to_flag_leaves_values_alone(args):
expected = list(args)
args, changed = _rewrite_help(args)

assert not changed
assert args == expected