Skip to content

Commit

Permalink
Make show-nested more granualar
Browse files Browse the repository at this point in the history
I want to entirely hide commands (and render them elsewhere) because of
how my documentation is structured.

This change allows a more flexible show-nested, but retains
backwards-compatibility to avoid breaking any existing integrations.

Co-authored-by: Stephen Finucane <[email protected]>
  • Loading branch information
Hugo Osvaldo Barrera and stephenfin committed Jul 23, 2020
1 parent ef86b06 commit 43ae645
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 45 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ documentation.
.. click:: module:parser
:prog: hello-world
:show-nested:
:nested: full
Detailed information on the various options available is provided in the
`documentation <https://sphinx-click.readthedocs.io>`_.
44 changes: 36 additions & 8 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Once enabled, *sphinx-click* enables automatic documentation for
.. click:: module:parser
:prog: hello-world
:show-nested:
:nested: full
The directive takes the import name of a *click* object as its sole
argument. This should be a subclass of |click.core.BaseCommand|_, such as
Expand All @@ -35,12 +35,26 @@ Once enabled, *sphinx-click* enables automatic documentation for

The following options are optional:

``:show-nested:``
Enable full documentation for sub-commands.
``:nested:``
Whether subcommands should also be shown. One of:

``full``
List sub-commands with full documentation.

``short``
List sub-commands with short documentation.

``none``
Do not list sub-commands.

Defaults to ``short`` unless ``show-nested`` (deprecated) is set.

``:commands:``
Document only listed commands.

``:show-nested:``
This option is deprecated; use ``nested`` instead.

The generated documentation includes anchors for the generated commands,
their options and their environment variables using the `Sphinx standard
domain`_.
Expand Down Expand Up @@ -84,14 +98,28 @@ To document this, use the following:
.. click:: hello_world:greet
:prog: hello-world
If you wish to include full documentation for the subcommand, ``hello``, in the
output, add the ``show-nested`` flag.
By default, the subcommand, ``hello``, is listed but no documentation provided.
If you wish to include full documentation for the subcommand in the output,
configure the ``nested`` flag to ``full``.

.. code-block:: rst
.. click:: hello_world:greet
:prog: hello-world
:nested: full
.. note::

The ``nested`` flag replaces the deprecated ``show-nested`` flag.

Conversely, if you do not wish to list these subcommands or wish to handle them
separately, configure the ``nested`` flag to ``none``.

.. code-block:: rst
.. click:: hello_world:greet
:prog: hello-world
:show-nested:
:nested: none
You can also document only selected commands by using ``:commands:`` option.

Expand Down Expand Up @@ -123,7 +151,7 @@ Modifying ``sys.path``
----------------------

If the application or script you wish to document is not installed (i.e. you
have not installed it with `pip` or run ``python setup.py``), then you may need
have not installed it with *pip* or run ``python setup.py``), then you may need
to modify ``sys.path``. For example, given the following application::

git
Expand All @@ -150,7 +178,7 @@ the application:
.. click:: git.git:cli
:prog: git
:show-nested:
:nested: full
assuming the group or command in ``git.git`` is named ``cli``.

Expand Down
56 changes: 43 additions & 13 deletions sphinx_click/ext.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import traceback
import warnings

import click
from docutils import nodes
Expand All @@ -11,6 +12,10 @@
LOG = logging.getLogger(__name__)
CLICK_VERSION = tuple(int(x) for x in click.__version__.split('.')[0:2])

NESTED_FULL = 'full'
NESTED_SHORT = 'short'
NESTED_NONE = 'none'


def _indent(text, level=1):
prefix = ' ' * (4 * level)
Expand Down Expand Up @@ -263,7 +268,7 @@ def _filter_commands(ctx, commands=None):
return [lookup[name] for name in names if name in lookup]


def _format_command(ctx, show_nested, commands=None):
def _format_command(ctx, nested, commands=None):
"""Format the output of `click.Command`."""
if CLICK_VERSION >= (7, 0) and ctx.command.hidden:
return
Expand Down Expand Up @@ -318,7 +323,7 @@ def _format_command(ctx, show_nested, commands=None):
yield line

# if we're nesting commands, we need to do this slightly differently
if show_nested:
if nested in (NESTED_FULL, NESTED_NONE):
return

commands = _filter_commands(ctx, commands)
Expand All @@ -337,14 +342,29 @@ def _format_command(ctx, show_nested, commands=None):
yield ''


def nested(argument):
values = (NESTED_FULL, NESTED_SHORT, NESTED_NONE)
if not argument:
return None

if argument not in values:
raise ValueError(
"%s is not a valid value for ':nested:'; allowed values: %s"
% directives.format_values(values)
)

return argument


class ClickDirective(rst.Directive):

has_content = False
required_arguments = 1
option_spec = {
'prog': directives.unchanged_required,
'show-nested': directives.flag,
'nested': nested,
'commands': directives.unchanged,
'show-nested': directives.flag,
}

def _load_module(self, module_path):
Expand Down Expand Up @@ -387,17 +407,15 @@ def _load_module(self, module_path):
)
return parser

def _generate_nodes(
self, name, command, parent=None, show_nested=False, commands=None
):
def _generate_nodes(self, name, command, parent, nested, commands=None):
"""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 show_nested: Whether subcommands should be included in output
:param nested: The granularity of subcommand details.
:param commands: Display only listed commands or skip the section if
empty
:returns: A list of nested docutil nodes
Expand All @@ -421,7 +439,7 @@ def _generate_nodes(
source_name = ctx.command_path
result = statemachine.ViewList()

lines = _format_command(ctx, show_nested, commands)
lines = _format_command(ctx, nested, commands)
for line in lines:
LOG.debug(line)
result.append(line, source_name)
Expand All @@ -430,12 +448,10 @@ def _generate_nodes(

# Subcommands

if show_nested:
if nested == NESTED_FULL:
commands = _filter_commands(ctx, commands)
for command in commands:
section.extend(
self._generate_nodes(command.name, command, ctx, show_nested)
)
section.extend(self._generate_nodes(command.name, command, ctx, nested))

return [section]

Expand All @@ -449,9 +465,23 @@ def run(self):

prog_name = self.options.get('prog')
show_nested = 'show-nested' in self.options
nested = self.options.get('nested')

if show_nested:
if nested:
raise self.error(
"':nested:' and ':show-nested:' are mutually exclusive"
)
else:
warnings.warn(
"':show-nested:' is deprecated; use ':nested: full'",
DeprecationWarning,
)
nested = NESTED_FULL if show_nested else NESTED_SHORT

commands = self.options.get('commands')

return self._generate_nodes(prog_name, command, None, show_nested, commands)
return self._generate_nodes(prog_name, command, None, nested, commands)


def setup(app):
Expand Down
Loading

0 comments on commit 43ae645

Please sign in to comment.