From 0db91e220517c767e1e81fd37d1dd7ce83fa77b7 Mon Sep 17 00:00:00 2001 From: David Lord Date: Wed, 19 May 2021 10:39:53 -0700 Subject: [PATCH] return resolved name, not original name --- CHANGES.rst | 5 +++++ docs/advanced.rst | 6 +++++- examples/aliases/aliases.py | 5 +++++ src/click/core.py | 2 +- tests/test_commands.py | 14 ++++++++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index b59fc443f..6d807d18d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -20,6 +20,11 @@ Unreleased regular options do from ``default``. :issue:`1886` - Added documentation that custom parameter types may be passed already valid values in addition to strings. :issue:`1898` +- Resolving commands returns the name that was given, not + ``command.name``, fixing an unintended change to help text and + ``default_map`` lookups. When using patterns like ``AliasedGroup``, + override ``resolve_command`` to change the name that is returned if + needed. :issue:`1895` Version 8.0.0 diff --git a/docs/advanced.rst b/docs/advanced.rst index 7f17e0ca8..3df492a77 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -35,7 +35,6 @@ it would accept ``pus`` as an alias (so long as it was unique): .. click:example:: class AliasedGroup(click.Group): - def get_command(self, ctx, cmd_name): rv = click.Group.get_command(self, ctx, cmd_name) if rv is not None: @@ -48,6 +47,11 @@ it would accept ``pus`` as an alias (so long as it was unique): return click.Group.get_command(self, ctx, matches[0]) ctx.fail(f"Too many matches: {', '.join(sorted(matches))}") + def resolve_command(self, ctx, args): + # always return the full command name + _, cmd, args = super().resolve_command(ctx, args) + return cmd.name, cmd, args + And it can then be used like this: .. click:example:: diff --git a/examples/aliases/aliases.py b/examples/aliases/aliases.py index c3da657fd..af3caa60b 100644 --- a/examples/aliases/aliases.py +++ b/examples/aliases/aliases.py @@ -67,6 +67,11 @@ def get_command(self, ctx, cmd_name): return click.Group.get_command(self, ctx, matches[0]) ctx.fail(f"Too many matches: {', '.join(sorted(matches))}") + def resolve_command(self, ctx, args): + # always return the command's name, not the alias + _, cmd, args = super().resolve_command(ctx, args) + return cmd.name, cmd, args + def read_config(ctx, param, value): """Callback that is used whenever --config is passed. We use this to diff --git a/src/click/core.py b/src/click/core.py index 63506bab9..3a7533bea 100644 --- a/src/click/core.py +++ b/src/click/core.py @@ -1717,7 +1717,7 @@ def resolve_command( if split_opt(cmd_name)[0]: self.parse_args(ctx, ctx.args) ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) - return cmd.name if cmd else None, cmd, args[1:] + return cmd_name if cmd else None, cmd, args[1:] def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: """Given a context and a command name, this returns a diff --git a/tests/test_commands.py b/tests/test_commands.py index 79f87faa9..9ebf6121c 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -285,6 +285,10 @@ class AliasedGroup(click.Group): def get_command(self, ctx, cmd_name): return push + def resolve_command(self, ctx, args): + _, command, args = super().resolve_command(ctx, args) + return command.name, command, args + cli = AliasedGroup() @cli.command() @@ -296,6 +300,16 @@ def push(): assert result.output.startswith("Usage: root push [OPTIONS]") +def test_group_add_command_name(runner): + cli = click.Group("cli") + cmd = click.Command("a", params=[click.Option(["-x"], required=True)]) + cli.add_command(cmd, "b") + # Check that the command is accessed through the registered name, + # not the original name. + result = runner.invoke(cli, ["b"], default_map={"b": {"x": 3}}) + assert result.exit_code == 0 + + def test_unprocessed_options(runner): @click.command(context_settings=dict(ignore_unknown_options=True)) @click.argument("args", nargs=-1, type=click.UNPROCESSED)