Skip to content
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
13 changes: 13 additions & 0 deletions src/lob_hlpr/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

_LOGGER = logging.getLogger(__name__)

# Actions whose value DeprecatedAliasAction can store the same way. Others such
# as append or count build on the previous value, which the alias would lose.
_ALIASABLE_ACTIONS = (None, "store", "store_true", "store_false", "store_const")


class DeprecatedAliasAction(argparse.Action):
"""Store a value like the option it replaces, but say it is out of date.
Expand Down Expand Up @@ -55,6 +59,11 @@ def add_renamed_argument(
Returns:
The action for the current option.

Raises:
ValueError: For ``required=True``, which argparse checks per spelling
so the old one could never satisfy it, and for actions other than
the store ones, such as ``append`` or ``count``.

Example:
>>> parser = argparse.ArgumentParser()
>>> _ = add_renamed_argument(
Expand All @@ -63,6 +72,10 @@ def add_renamed_argument(
>>> parser.parse_args(["--loglevel", "DEBUG"]).log_level
'DEBUG'
"""
if kwargs.get("required"):
raise ValueError("A renamed option cannot be required")
if kwargs.get("action") not in _ALIASABLE_ACTIONS:
raise ValueError(f"A renamed option cannot use action={kwargs['action']!r}")
action = parser.add_argument(*flags, **kwargs)
# argparse's own default for these is not None, so only forward the ones the
# current option actually set.
Expand Down
12 changes: 12 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ def test_a_flag_without_a_value_can_be_renamed():
assert parser.parse_args(["--nogui"]).no_gui is True


@pytest.mark.parametrize(
"kwargs",
[{"required": True}, {"action": "append"}, {"action": "count"}],
ids=["required", "append", "count"],
)
def test_unsupported_options_are_rejected(kwargs):
"""Options the alias cannot mirror fail when added, not when parsed."""
parser = argparse.ArgumentParser("test")
with pytest.raises(ValueError):
add_renamed_argument(parser, "--new", deprecated="--old", **kwargs)


def test_several_old_spellings_can_be_kept_alive():
"""An option renamed twice should not need two helpers."""
parser = argparse.ArgumentParser("test")
Expand Down