diff --git a/CHANGES.rst b/CHANGES.rst index f63e68be8..2044927fc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -9,6 +9,8 @@ Unreleased tabs in option help text are now escaped, keeping the original completion format while still supporting multi-line help. :issue:`3502` :issue:`3043` :pr:`3504` :pr:`3508` +- Deprecated commands and options with empty or missing help text no longer + render a stray leading space before the ``(DEPRECATED)`` label. :pr:`3509` Version 8.4.1 diff --git a/src/click/core.py b/src/click/core.py index bc04f6426..f104fee74 100644 --- a/src/click/core.py +++ b/src/click/core.py @@ -1189,7 +1189,8 @@ def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: text = "" if self.deprecated: - text = f"{_(text)} {_format_deprecated_label(self.deprecated)}" + label = _format_deprecated_label(self.deprecated) + text = f"{_(text)} {label}" if text else label if text: formatter.write_paragraph() @@ -2826,7 +2827,7 @@ def __init__( if deprecated: label = _format_deprecated_label(deprecated) - help = f"{help} {label}" if help is not None else label + help = f"{help} {label}" if help else label self.prompt = prompt_text self.confirmation_prompt = confirmation_prompt diff --git a/tests/test_commands.py b/tests/test_commands.py index ddce905bf..c3f0020d3 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -491,6 +491,22 @@ def cli(): assert deprecated in result.output +@pytest.mark.parametrize("deprecated", [True, "USE OTHER COMMAND INSTEAD"]) +@pytest.mark.parametrize("doc", ["", None]) +def test_deprecated_empty_help_no_leading_space(runner, doc, deprecated): + """A command with empty or missing help text must render the deprecation + label at the normal indentation, without a stray leading space. + """ + + @click.command(deprecated=deprecated, help=doc) + def cli(): + pass + + out = runner.invoke(cli, ["--help"]).output + assert "\n (DEPRECATED" in out + assert "\n (DEPRECATED" not in out + + @pytest.mark.parametrize("deprecated", [True, "USE OTHER COMMAND INSTEAD"]) def test_deprecated_in_invocation(runner, deprecated): @click.command(deprecated=deprecated) diff --git a/tests/test_options.py b/tests/test_options.py index 44cb58f6d..1b93e136e 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -58,6 +58,20 @@ def cmd(foo): assert deprecated in result.output +@pytest.mark.parametrize( + ("deprecated", "expected"), + [(True, "(DEPRECATED)"), ("USE B INSTEAD", "(DEPRECATED: USE B INSTEAD)")], +) +@pytest.mark.parametrize("help_text", ["", None]) +def test_deprecated_empty_help_no_leading_space(help_text, deprecated, expected): + """An option with empty or missing help text must not gain a stray leading + space before the deprecation label. + """ + opt = click.Option(["--foo"], help=help_text, deprecated=deprecated) + ctx = click.Context(click.Command("cli")) + assert opt.get_help_record(ctx)[1] == expected + + @pytest.mark.parametrize("deprecated", [True, "USE B INSTEAD"]) def test_deprecated_warning(runner, deprecated): @click.command()