Repository: pallets/click (python)

Issue:
Spurious empty lines in the help output (regression)
Click since version 8.1.0 doesn't properly account for a scenario that the callback's docstring can have no "help text" part, like so:

```python
@click.command()
def callback():
    """
    \f
    More stuff.
    """
```
This results in empty lines in the output:

```
% python3 test --help
Usage: test [OPTIONS]



Options:
  --help  Show this message and exit.
```

Before 8.1.0:
```
% python3 test --help
Usage: test [OPTIONS]

Options:
  --help  Show this message and exit.
```

Environment:

- Python version: 3.9.2
- Click version: 8.1.3


Pull request:
Don't output spurious lines if the truncated help text is actually empty
Regression in 92b30e47cb013433190f40d75239c98c77aa9d2d (8.1.0). This change brings back the original logic along with the comment.

Improve the tests to catch further regressions.

Fixes #2368

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [ ] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 66808a8..76c234f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -16,6 +16,7 @@ Unreleased
 -   Improve type annotations for pyright type checker. :issue:`2268`
 -   Improve responsiveness of ``click.clear()``. :issue:`2284`
 -   Improve command name detection when using Shiv or PEX. :issue:`2332`
+-   Avoid showing empty lines if command help text is empty. :issue:`2368`
 
 
 Version 8.1.3
diff --git a/src/click/core.py b/src/click/core.py
index d61f7ba..9a5f88a 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -1360,13 +1360,16 @@ class Command(BaseCommand):
 
     def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None:
         """Writes the help text to the formatter if it exists."""
-        text = self.help if self.help is not None else ""
+        if self.help is not None:
+            # truncate the help text to the first form feed
+            text = inspect.cleandoc(self.help).partition("\f")[0]
+        else:
+            text = ""
 
         if self.deprecated:
             text = _("(Deprecated) {text}").format(text=text)
 
         if text:
-            text = inspect.cleandoc(text).partition("\f")[0]
             formatter.write_paragraph()
 
             with formatter.indentation():


Test patch:
diff --git a/tests/test_commands.py b/tests/test_commands.py
index 3a0d4b9..d72a182 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -95,20 +95,6 @@ def test_auto_shorthelp(runner):
     )
 
 
-def test_help_truncation(runner):
-    @click.command()
-    def cli():
-        """This is a command with truncated help.
-        \f
-
-        This text should be truncated.
-        """
-
-    result = runner.invoke(cli, ["--help"])
-    assert result.exit_code == 0
-    assert "This is a command with truncated help." in result.output
-
-
 def test_no_args_is_help(runner):
     @click.command(no_args_is_help=True)
     def cli():
diff --git a/tests/test_formatting.py b/tests/test_formatting.py
index 1cbf32b..fe7e7ba 100644
--- a/tests/test_formatting.py
+++ b/tests/test_formatting.py
@@ -296,6 +296,26 @@ def test_truncating_docstring(runner):
     ]
 
 
+def test_truncating_docstring_no_help(runner):
+    @click.command()
+    @click.pass_context
+    def cli(ctx):
+        """
+        \f
+
+        This text should be truncated.
+        """
+
+    result = runner.invoke(cli, ["--help"], terminal_width=60)
+    assert not result.exception
+    assert result.output.splitlines() == [
+        "Usage: cli [OPTIONS]",
+        "",
+        "Options:",
+        "  --help  Show this message and exit.",
+    ]
+
+
 def test_removing_multiline_marker(runner):
     @click.group()
     def cli():