def test_ansi_escape_sequences(self):
        """Validate that ANSI escape sequences are stripped."""

        @click.command()
        def foobar():
            """A sample command with **sparkles**.

            We've got \033[31mred text\033[0m, \033[104mblue backgrounds\033[0m, a
            dash of \033[1mbold\033[0m and even some \033[4munderlined words\033[0m.
            """
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command with **sparkles**.

        We've got red text, blue backgrounds, a
        dash of bold and even some underlined words.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #2
0
    def test_help_epilog(self):
        """Validate formatting of explicit help and epilog strings."""

        @click.command(help='A sample command.', epilog='A sample epilog.')
        @click.option('--param', help='A sample option')
        def foobar(bar):
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]

        .. rubric:: Options

        .. option:: --param <param>

            A sample option

        A sample epilog.
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #3
0
    def test_no_parameters(self):
        """Validate a `click.Group` with no parameters.

        This exercises the code paths for a group with *no* arguments, *no*
        options and *no* environment variables.
        """

        @click.group()
        def cli():
            """A sample command group."""
            pass

        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #4
0
    def test_nested_short(self):
        """Validate a nested command with 'nested' of 'short' (default).

        We should list minimal help texts for sub-commands since they're not
        being handled separately.
        """

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #5
0
    def test_order_of_commands(self):
        """Validate the order of commands."""

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, show_nested=False,
                                          commands='world, hello'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: world

            A world command.

        .. object:: hello

            A sample command.
        """).lstrip(), '\n'.join(output))
예제 #6
0
    def test_order_of_commands(self):
        """Validate the order of commands."""

        ctx = self._get_ctx()
        output = list(
            ext._format_command(ctx,
                                show_nested=False,
                                commands='world, hello'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: world

            A world command.

        .. object:: hello

            A sample command.
        """).lstrip(), '\n'.join(output))
예제 #7
0
    def test_no_parameters(self):
        """Validate a `click.Command` with no parameters.

        This exercises the code paths for a command with *no* arguments, *no*
        options and *no* environment variables.
        """

        @click.command()
        def foobar():
            """A sample command."""
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #8
0
    def test_defaults(self):
        """Validate formatting of user documented defaults.
        """
        @click.command()
        @click.option('--num-param', type=int, default=42, show_default=True)
        @click.option('--param',
                      default=lambda: None,
                      show_default='Something computed at runtime')
        def foobar(bar):
            """A sample command."""
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]

        .. rubric:: Options

        .. option:: --num-param <num_param>

            [default: 42]

        .. option:: --param <param>

            [default: Something computed at runtime]
        """).lstrip(), '\n'.join(output))
예제 #9
0
    def test_basic_parameters(self):
        """Validate a combination of parameters.

        This exercises the code paths for a group with arguments, options and
        environment variables.
        """

        @click.group()
        @click.option('--param', envvar='PARAM', help='A sample option')
        @click.argument('ARG', envvar='ARG')
        def cli():
            """A sample command group."""
            pass

        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] ARG COMMAND [ARGS]...

        .. rubric:: Options

        .. option:: --param <param>

            A sample option

        .. rubric:: Arguments

        .. option:: ARG

            Required argument

        .. rubric:: Environment variables

        .. _cli-param-PARAM:

        .. envvar:: PARAM
           :noindex:

            Provide a default for :option:`--param`

        .. _cli-arg-ARG:

        .. envvar:: ARG
           :noindex:

            Provide a default for :option:`ARG`
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #10
0
    def test_defaults(self):
        """Validate formatting of user documented defaults."""
        @click.command()
        @click.option('--num-param', type=int, default=42, show_default=True)
        @click.option(
            '--param',
            default=lambda: None,
            show_default='Something computed at runtime',
        )
        @click.option(
            '--group',
            default=[('foo', 'bar')],
            nargs=2,
            type=click.Tuple([str, str]),
            multiple=True,
            show_default=True,
        )
        @click.option(
            '--only-show-default',
            show_default="Some default computed at runtime!",
        )
        def foobar(bar):
            """A sample command."""
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]

        .. rubric:: Options

        .. option:: --num-param <num_param>

            :default: 42

        .. option:: --param <param>

            :default: Something computed at runtime

        .. option:: --group <group>

            :default: ('foo', 'bar')

        .. option:: --only-show-default <only_show_default>

            :default: Some default computed at runtime!
        """).lstrip(),
            '\n'.join(output),
        )
예제 #11
0
    def test_hidden(self):
        """Ensure 'hidden' subcommands are not shown."""

        @click.command()
        def hello():
            """A sample command."""

        @click.command()
        def world():
            """A world command."""

        @click.command(hidden=True)
        def hidden():
            """A hidden command."""

        class MyCLI(click.MultiCommand):
            _command_mapping = {
                'hello': hello,
                'world': world,
                'hidden': hidden,
            }

            def list_commands(self, ctx):
                return ['hello', 'world', 'hidden']

            def get_command(self, ctx, name):
                return self._command_mapping[name]

        cli = MyCLI(help='A sample custom multicommand.')
        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='short'))

        # Note that we do NOT expect this to show the 'hidden' command
        self.assertEqual(
            textwrap.dedent(
                """
        A sample custom multicommand.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.

        .. object:: world

            A world command.
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #12
0
    def test_hidden(self):
        """Validate a `click.Command` with the `hidden` flag."""
        @click.command(hidden=True)
        def foobar():
            """A sample command."""
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual('', '\n'.join(output))
예제 #13
0
    def test_basic_parameters(self):
        """Validate a combination of parameters.

        This exercises the code paths for a command with arguments, options and
        environment variables.
        """

        @click.command()
        @click.option('--param', envvar='PARAM', help='A sample option')
        @click.argument('ARG', envvar='ARG')
        def foobar(bar):
            """A sample command."""
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS] ARG

        .. rubric:: Options

        .. option:: --param <param>

            A sample option

        .. rubric:: Arguments

        .. option:: ARG

            Required argument

        .. rubric:: Environment variables

        .. _foobar-param-PARAM:

        .. envvar:: PARAM
           :noindex:

            Provide a default for :option:`--param`

        .. _foobar-arg-ARG:

        .. envvar:: ARG
           :noindex:

            Provide a default for :option:`ARG`
        """).lstrip(), '\n'.join(output))
예제 #14
0
    def test_basics(self):
        """Validate a custom ``click.MultiCommand`` with no parameters.

        This exercises the code paths to extract commands correctly from these
        commands.
        """

        @click.command()
        def hello():
            """A sample command."""

        @click.command()
        def world():
            """A world command."""

        class MyCLI(click.MultiCommand):
            _command_mapping = {
                'hello': hello,
                'world': world,
            }

            def list_commands(self, ctx):
                return ['hello', 'world']

            def get_command(self, ctx, name):
                return self._command_mapping[name]

        cli = MyCLI(help='A sample custom multicommand.')
        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample custom multicommand.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.

        .. object:: world

            A world command.
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #15
0
    def test_basics(self):
        """Validate a custom ``click.MultiCommand`` with no parameters.

        This exercises the code paths to extract commands correctly from these
        commands.
        """

        @click.command()
        def hello():
            """A sample command."""

        @click.command()
        def world():
            """A world command."""

        class MyCLI(click.MultiCommand):
            _command_mapping = {
                'hello': hello,
                'world': world,
            }
            def list_commands(self, ctx):
                return ['hello', 'world']

            def get_command(self, ctx, name):
                return self._command_mapping[name]

        cli = MyCLI(help='A sample custom multicommand.')
        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample custom multicommand.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.

        .. object:: world

            A world command.
        """).lstrip(), '\n'.join(output))
예제 #16
0
    def test_no_commands(self):
        """Validate an empty command group."""

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, show_nested=False, commands=''))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(), '\n'.join(output))
예제 #17
0
    def test_no_commands(self):
        """Validate an empty command group."""

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, show_nested=False, commands=''))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(), '\n'.join(output))
예제 #18
0
    def test_basic_parameters(self):
        """Validate a combination of parameters.

        This exercises the code paths for a group with arguments, options and
        environment variables.
        """

        @click.group()
        @click.option('--param', envvar='PARAM', help='A sample option')
        @click.argument('ARG', envvar='ARG')
        def cli():
            """A sample command group."""
            pass

        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] ARG COMMAND [ARGS]...

        .. rubric:: Options

        .. option:: --param <param>

            A sample option

        .. rubric:: Arguments

        .. option:: ARG

            Required argument

        .. rubric:: Environment variables

        .. envvar:: PARAM

            Provide a default for :option:`--param`

        .. envvar:: ARG

            Provide a default for :option:`ARG`
        """).lstrip(), '\n'.join(output))
예제 #19
0
    def test_show_nested(self):
        """Validate a nested command without show_nested.

        If we're not showing sub-commands separately, we should not list them.
        """

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, show_nested=True))

        self.assertEqual(
            textwrap.dedent("""
        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(), '\n'.join(output))
예제 #20
0
    def test_titles(self):
        """Validate a `click.Command` with nested titles."""

        @click.command()
        @click.option('--name', help='Name to say hello to.', required=True, type=str)
        def hello(name):
            """Prints hello to name given.

            Examples
            --------

            .. code:: bash

                my_cli hello --name "Jack"
            """

        ctx = click.Context(hello, info_name='hello')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        Prints hello to name given.

        Examples
        --------

        .. code:: bash

            my_cli hello --name "Jack"

        .. program:: hello
        .. code-block:: shell

            hello [OPTIONS]

        .. rubric:: Options

        .. option:: --name <name>

            **Required** Name to say hello to.
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #21
0
    def test_show_nested(self):
        """Validate a nested command without show_nested.

        If we're not showing sub-commands separately, we should not list them.
        """

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, show_nested=True))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(), '\n'.join(output))
예제 #22
0
    def test_no_line_wrapping(self):
        r"""Validate behavior when a \b character is present.

        https://click.palletsprojects.com/en/7.x/documentation/#preventing-rewrapping
        """

        @click.group()
        def cli():
            """A sample command group.

            \b
            This is
            a paragraph
            without rewrapping.

            And this is a paragraph
            that will be rewrapped again.
            """
            pass

        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent(
                """
        A sample command group.

        | This is
        | a paragraph
        | without rewrapping.

        And this is a paragraph
        that will be rewrapped again.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """
            ).lstrip(),
            '\n'.join(output),
        )
예제 #23
0
    def test_no_truncation(self):
        r"""Validate behavior when a \b character is present.

        https://click.palletsprojects.com/en/8.1.x/documentation/#truncating-help-texts
        """
        @click.group()
        def cli():
            """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.
            """
            pass

        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='short'))

        # note that we have an extra newline because we're using
        # docutils.statemachine.string2lines under the hood, which is
        # converting the form feed to a newline
        self.assertEqual(
            textwrap.dedent("""
        First paragraph.

        This is a very long second
        paragraph and not correctly
        wrapped but it will be rewrapped.


        :param click.core.Context ctx: Click context.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(),
            '\n'.join(output),
        )
예제 #24
0
    def test_nested_none(self):
        """Validate a nested command with 'nested' of 'none'.

        We should not list sub-commands.
        """

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, nested='none'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(),
            '\n'.join(output),
        )
예제 #25
0
    def test_no_line_wrapping_epilog(self):
        r"""Validate behavior of the \b character in an epilog."""
        @click.command(epilog="""
An epilog containing pre-wrapped text.

\b
This is
a paragraph
without rewrapping.

And this is a paragraph
that will be rewrapped again.
""")
        def foobar():
            """A sample command."""

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]

        An epilog containing pre-wrapped text.

        | This is
        | a paragraph
        | without rewrapping.

        And this is a paragraph
        that will be rewrapped again.
        """).lstrip(),
            '\n'.join(output),
        )
예제 #26
0
    def test_no_parameters(self):
        """Validate a `click.Group` with no parameters.

        This exercises the code paths for a group with *no* arguments, *no*
        options and *no* environment variables.
        """

        @click.group()
        def cli():
            """A sample command group."""
            pass

        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(), '\n'.join(output))
예제 #27
0
    def test_hide_nested(self):
        """Validate a nested command without show_nested.

        If we're not showing sub-commands separately, we should list them.
        """

        ctx = self._get_ctx()
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample command group.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.
        """).lstrip(), '\n'.join(output))
예제 #28
0
    def _generate_nodes(self,
                        name,
                        command,
                        parent,
                        nested,
                        commands=None,
                        semantic_group=False):
        """Generate the relevant Sphinx nodes.

        Format a `click.Group` or `click.Command`.

        :param name: Name of command, as used on the command line
        :param command: Instance of `click.Group` or `click.Command`
        :param parent: Instance of `click.Context`, or None
        :param nested: The granularity of subcommand details.
        :param commands: Display only listed commands or skip the section if
            empty
        :param semantic_group: Display command as title and description for
            CommandCollection.
        :returns: A list of nested docutil nodes
        """
        ctx = click.Context(command, info_name=name, parent=parent)

        if CLICK_VERSION >= (7, 0) and command.hidden:
            return []

        # Title
        section = nodes.section(
            '',
            nodes.title(text=name),
            ids=[nodes.make_id(ctx.command_path)],
            names=[nodes.fully_normalize_name(ctx.command_path)],
        )

        # Summary
        source_name = ctx.command_path
        result = statemachine.ViewList()

        if semantic_group:
            lines = _format_description(ctx)
        else:
            lines = _format_command(ctx, nested, commands)

        for line in lines:
            LOG.debug(line)
            result.append(line, source_name)

        sphinx_nodes.nested_parse_with_titles(self.state, result, section)

        # Subcommands

        if nested == NESTED_FULL:
            if isinstance(command, click.CommandCollection):
                for source in command.sources:
                    section.extend(
                        self._generate_nodes(source.name,
                                             source,
                                             ctx,
                                             nested,
                                             semantic_group=True))
            else:
                commands = _filter_commands(ctx, commands)
                for command in commands:
                    parent = ctx if not semantic_group else ctx.parent
                    section.extend(
                        self._generate_nodes(command.name, command, parent,
                                             nested))

        return [section]
예제 #29
0
    def test_ansi_escape_sequences(self):
        """Validate that ANSI escape sequences are stripped."""
        @click.command(epilog='\033[31mA sample epilog.\033[0m')
        @click.option(
            '--name',
            help='Name to say \033[94mhello\033[0m to.',
            required=True,
            type=str,
        )
        @click.option(
            '--choice',
            help='A sample option with choices',
            type=click.Choice(
                ['\033[94mOption1\033[0m', '\033[94mOption2\033[0m']),
        )
        @click.option(
            '--param',
            default=lambda: None,
            show_default='Something computed at \033[94mruntime\033[0m',
        )
        def foobar():
            """A sample command with **sparkles**.

            We've got \033[31mred text\033[0m, \033[104mblue backgrounds\033[0m, a
            dash of \033[1mbold\033[0m and even some \033[4munderlined words\033[0m.
            """
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command with **sparkles**.

        We've got red text, blue backgrounds, a
        dash of bold and even some underlined words.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS]

        .. rubric:: Options

        .. option:: --name <name>

            **Required** Name to say hello to.

        .. option:: --choice <choice>

            A sample option with choices

            :options: Option1 | Option2

        .. option:: --param <param>

            :default: Something computed at runtime

        A sample epilog.
        """).lstrip(),
            '\n'.join(output),
        )
예제 #30
0
    def test_basics(self):
        "Validate a ``click.CommandCollection`` with grouped outputs."

        @click.group()
        def grp1():
            """A first group."""
            pass

        @grp1.command()
        def hello():
            """A hello command."""

        @click.group()
        def grp2():
            """A second group."""
            pass

        @grp2.command()
        def world():
            """A world command."""

        cli = click.CommandCollection(name='cli',
                                      sources=[grp1, grp2],
                                      help='A simple CommandCollection.')
        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, nested='full'))

        self.assertEqual(
            textwrap.dedent("""
        A simple CommandCollection.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...
        """).lstrip(),
            '\n'.join(output),
        )

        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent("""
        A simple CommandCollection.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A hello command.

        .. object:: world

            A world command.
        """).lstrip(),
            '\n'.join(output),
        )
예제 #31
0
    def test_basic_parameters(self):
        """Validate a combination of parameters.

        This exercises the code paths for a command with arguments, options and
        environment variables.
        """
        @click.command()
        @click.option('--param', envvar='PARAM', help='A sample option')
        @click.option('--another', metavar='[FOO]', help='Another option')
        @click.option(
            '--choice',
            help='A sample option with choices',
            type=click.Choice(['Option1', 'Option2']),
        )
        @click.option(
            '--numeric-choice',
            metavar='<choice>',
            help='A sample option with numeric choices',
            type=click.Choice([1, 2, 3]),
        )
        @click.argument('ARG', envvar='ARG')
        def foobar(bar):
            """A sample command."""
            pass

        ctx = click.Context(foobar, info_name='foobar')
        output = list(ext._format_command(ctx, nested='short'))

        self.assertEqual(
            textwrap.dedent("""
        A sample command.

        .. program:: foobar
        .. code-block:: shell

            foobar [OPTIONS] ARG

        .. rubric:: Options

        .. option:: --param <param>

            A sample option

        .. option:: --another <FOO>

            Another option

        .. option:: --choice <choice>

            A sample option with choices

            :options: Option1 | Option2

        .. option:: --numeric-choice <choice>

            A sample option with numeric choices

            :options: 1 | 2 | 3

        .. rubric:: Arguments

        .. option:: ARG

            Required argument

        .. rubric:: Environment variables

        .. _foobar-param-PARAM:

        .. envvar:: PARAM
           :noindex:

            Provide a default for :option:`--param`

        .. _foobar-arg-ARG:

        .. envvar:: ARG
           :noindex:

            Provide a default for :option:`ARG`
        """).lstrip(),
            '\n'.join(output),
        )