Repository: pallets/click
Pull request #1091 (2018-08-15 01:09:45)

Rebase of #629; allow use of page break to split docstring-based helptext
Since the branch for #629 doesn't allow pushes from maintainers, I'm just duplicating it in a separate PR to get this closed out.

@dsully did the original review, so this is just an amended version of that work which has the comment he requested.

I've kept my modification in a separate commit.


Patch:
diff --git a/click/core.py b/click/core.py
index 525b091..9d1065e 100644
--- a/click/core.py
+++ b/click/core.py
@@ -778,6 +778,10 @@ class Command(BaseCommand):
         #: should show up in the help page and execute.  Eager parameters
         #: will automatically be handled before non eager ones.
         self.params = params or []
+        # if a form feed (page break) is found in the help text, truncate help
+        # text to the content preceding the first form feed
+        if help and '\f' in help:
+            help = help.split('\f', 1)[0]
         self.help = help
         self.epilog = epilog
         self.options_metavar = options_metavar
diff --git a/click/decorators.py b/click/decorators.py
index c57c530..bfc7a05 100644
--- a/click/decorators.py
+++ b/click/decorators.py
@@ -61,7 +61,7 @@ def make_pass_decorator(object_type, ensure=False):
                 raise RuntimeError('Managed to invoke callback without a '
                                    'context object of type %r existing'
                                    % object_type.__name__)
-            return ctx.invoke(f, obj, *args, **kwargs)
+            return ctx.invoke(f, obj, *args[1:], **kwargs)
         return update_wrapper(new_func, f)
     return decorator
 
diff --git a/click/types.py b/click/types.py
index b882df7..e1fe54b 100644
--- a/click/types.py
+++ b/click/types.py
@@ -331,12 +331,9 @@ class File(ParamType):
     opened in binary mode or for writing.  The encoding parameter can be used
     to force a specific encoding.
 
-    The `lazy` flag controls if the file should be opened immediately or upon
-    first IO. The default is to be non-lazy for standard input and output
-    streams as well as files opened for reading, `lazy` otherwise. When opening a
-    file lazily for reading, it is still opened temporarily for validation, but
-    will not be held open until first IO. lazy is mainly useful when opening
-    for writing to avoid creating the file until it is needed.
+    The `lazy` flag controls if the file should be opened immediately or
+    upon first IO.  The default is to be non lazy for standard input and
+    output streams as well as files opened for reading, lazy otherwise.
 
     Starting with Click 2.0, files can also be opened atomically in which
     case all writes go into a separate file in the same folder and upon
diff --git a/docs/documentation.rst b/docs/documentation.rst
index c9788b2..6d582e0 100644
--- a/docs/documentation.rst
+++ b/docs/documentation.rst
@@ -78,6 +78,40 @@ And what it looks like:
 
 .. _doc-meta-variables:
 
+Truncating Help Texts
+---------------------
+
+Click gets command help text from function docstrings.  However if you
+already use docstrings to document function arguments you may not want
+to see :param: and :return: lines in your help text.
+
+You can use the ``\f`` escape marker to have Click truncate the help text
+after the marker.
+
+Example:
+
+.. click:example::
+
+    @click.command()
+    @click.pass_context
+    def cli(ctx):
+        """First paragraph.
+
+        This is a very long second
+        paragraph and not correctly
+        wrapped but it will be rewrapped.
+        \f
+
+        :param click.core.Context ctx: Click context.
+        """
+
+And what it looks like:
+
+.. click:run::
+
+    invoke(cli, args=['--help'])
+
+
 Meta Variables
 --------------
 


Test patch:
diff --git a/tests/test_context.py b/tests/test_context.py
index 3b07cc8..cbf9b98 100644
--- a/tests/test_context.py
+++ b/tests/test_context.py
@@ -203,39 +203,3 @@ def test_close_before_pop(runner):
     assert not result.exception
     assert result.output == 'aha!\n'
     assert called == [True]
-
-
-def test_make_pass_decorator_args(runner):
-    """
-    Test to check that make_pass_decorator doesn't consume arguments based on
-    invocation order.
-    """
-    class Foo(object):
-        title = 'foocmd'
-
-    pass_foo = click.make_pass_decorator(Foo)
-
-    @click.group()
-    @click.pass_context
-    def cli(ctx):
-        ctx.obj = Foo()
-
-    @cli.command()
-    @click.pass_context
-    @pass_foo
-    def test1(foo, ctx):
-        click.echo(foo.title)
-
-    @cli.command()
-    @pass_foo
-    @click.pass_context
-    def test2(ctx, foo):
-        click.echo(foo.title)
-
-    result = runner.invoke(cli, ['test1'])
-    assert not result.exception
-    assert result.output == 'foocmd\n'
-
-    result = runner.invoke(cli, ['test2'])
-    assert not result.exception
-    assert result.output == 'foocmd\n'
diff --git a/tests/test_formatting.py b/tests/test_formatting.py
index 0c06073..2005f98 100644
--- a/tests/test_formatting.py
+++ b/tests/test_formatting.py
@@ -268,3 +268,32 @@ def test_formatting_custom_type_metavar(runner):
         'Options:',
         '  --help  Show this message and exit.'
     ]
+
+
+def test_truncating_docstring(runner):
+    @click.command()
+    @click.pass_context
+    def cli(ctx):
+        """First paragraph.
+
+        This is a very long second
+        paragraph and not correctly
+        wrapped but it will be rewrapped.
+        \f
+
+        :param click.core.Context ctx: Click context.
+        """
+
+    result = runner.invoke(cli, ['--help'], terminal_width=60)
+    assert not result.exception
+    assert result.output.splitlines() == [
+        'Usage: cli [OPTIONS]',
+        '',
+        '  First paragraph.',
+        '',
+        '  This is a very long second paragraph and not correctly',
+        '  wrapped but it will be rewrapped.',
+        '',
+        'Options:',
+        '  --help  Show this message and exit.',
+    ]