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), )
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), )
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), )
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), )
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))
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))
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), )
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))
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), )
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), )
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), )
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))
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))
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), )
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))
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))
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))
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))
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), )
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))
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), )
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), )
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), )
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), )
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))
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))
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]
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), )
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), )
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), )