pax_global_header00006660000000000000000000000064135475747600014534gustar00rootroot0000000000000052 comment=0e089e4e2a7e8138feafa7316c5a2090694c3dc6 sphinx-click-2.3.1/000077500000000000000000000000001354757476000141335ustar00rootroot00000000000000sphinx-click-2.3.1/.editorconfig000066400000000000000000000012001354757476000166010ustar00rootroot00000000000000# -*- coding: utf-8 -*- root = true [*] indent_style = space end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true charset = utf-8 # Python files [*.py] indent_size = 4 # isort plugin configuration known_first_party = sphinx_click multi_line_output = 2 default_section = THIRDPARTY skip = .eggs docs # RST files (used by sphinx) [*.rst] indent_size = 3 # CSS, HTML, JS, JSON, YML [*.{css,html,js,json,yml}] indent_size = 2 # Matches the exact files either package.json or .travis.yml [{package.json,.travis.yml}] indent_size = 2 # Dockerfile [Dockerfile] indent_size = 4 # Makefile [Makefile] indent_size = 4 sphinx-click-2.3.1/.gitignore000066400000000000000000000013201354757476000161170ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *,cover .hypothesis/ # Translations *.mo *.pot # Sphinx documentation docs/_build/ # pbr AUTHORS ChangeLog # virtualenv /.venv # vim *.swp sphinx-click-2.3.1/.pre-commit-config.yaml000066400000000000000000000002001354757476000204040ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.2.3 hooks: - id: flake8 - id: trailing-whitespace sphinx-click-2.3.1/.travis.yml000066400000000000000000000023041354757476000162430ustar00rootroot00000000000000language: python cache: pip python: - 2.7 - 3.5 - 3.6 - 3.7 install: - pip install tox-travis - pip install codecov script: - tox after_success: - codecov stages: - test - deploy jobs: include: - stage: test python: pypy dist: trusty - stage: deploy python: 3.6 install: skip # no tests, no depedencies needed script: skip # we're not running tests deploy: provider: pypi user: stephenfin password: secure: "VhbttK0qaGjz7ISIUEAVxPEn8Qo5vu0kRT97C9WykI7BkrkceuSj7c+neCFlXpsUm3VnyzmUgYzDMHBI/EbmzrsX48lTC0GKhDpEBV/gxVmWE+2tdSqYXC1yyBbMFhEm7ygCle8RQomAptWO2C7lcoYazvwT8kWngi15/KKzgUizC5lqiv2VyW8kzPg9qTSGft0IUAA8vVYjlCIlgYVcpk3tHSzOvedsrGd6XZEPQlGtDdeUiDHQ2usxpdOKWJ+Mq6nxpwqwOHvPUB2WvWoYFKfZZrESf9EpnuUrc5JFTbUN9k1RUnsW9DAcg/qNA37vFK1hyGT5RDNCQr90g+j7cUtYicOLA6nnzHE3ccH9oFVCx5gNs1IWEES7hpfMDIqHR5EQy6ez5mzjb8EDHZn+mxjHeSL45kECGiDwrrbqXsfFXIZtc+stX8RHRJupx6wSO+hjbkQvIDdWWeAw8nEhWqHq4LPNM/5S3ZUUx0/YyYME0tJ5nr6U1zNzVjQ3cumjq8bmQbZKd80/X/a9dc9hjFfD3gIyKL7mvwnb5/igBTdk+ymhyUMxAhX0Sx94eZpVd4nXCVSTLCwVMel+z2wRU/hWQurNUhtSv7lZ4Y1/88HsbQ+aB98j8EtwV59IsCSsUUQdTtiYOcwUKZqrVRm+cWD2heT5eBMyB1d+BYjLEWY=" on: tags: true distributions: sdist bdist_wheel sphinx-click-2.3.1/LICENSE000066400000000000000000000021071354757476000151400ustar00rootroot00000000000000The MIT License Copyright (c) 2017 Stephen Finucane http://that.guru/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sphinx-click-2.3.1/README.rst000066400000000000000000000026541354757476000156310ustar00rootroot00000000000000============ sphinx-click ============ .. image:: https://travis-ci.org/click-contrib/sphinx-click.svg?branch=master :target: https://travis-ci.org/click-contrib/sphinx-click :alt: CI Status .. image:: https://readthedocs.org/projects/sphinx-click/badge/?version=latest :target: https://sphinx-click.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status `sphinx-click` is a `Sphinx`__ plugin that allows you to automatically extract documentation from a `click-based`__ application and include it in your docs. __ http://www.sphinx-doc.org/ __ http://click.pocoo.org/ Installation ------------ Install the plugin using `pip`: .. code-block:: shell $ pip install sphinx-click Alternatively, install from source by cloning this repo then running `setup.py`: .. code-block:: shell $ python setup.py install Usage ----- .. important:: To document a click-based application, both the application itself and any additional dependencies required by that application **must be installed**. Enable the plugin in your Sphinx `conf.py` file: .. code-block:: python extensions = ['sphinx_click.ext'] Once enabled, you can now use the plugin wherever necessary in the documentation. .. code-block:: .. click:: module:parser :prog: hello-world :show-nested: Detailed information on the various options available is provided in the `documentation `_. sphinx-click-2.3.1/docs/000077500000000000000000000000001354757476000150635ustar00rootroot00000000000000sphinx-click-2.3.1/docs/changelog.rst000066400000000000000000000000751354757476000175460ustar00rootroot00000000000000Changes ======= .. include:: ../ChangeLog :start-line: 2 sphinx-click-2.3.1/docs/conf.py000066400000000000000000000053311354757476000163640ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # sphinx-click documentation build configuration file # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.5' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = [] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'sphinx-click' copyright = u'2017, Stephen Finucane' author = u'Stephen Finucane' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = u'' # The full version, including alpha/beta/rc tags. release = u'' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [] sphinx-click-2.3.1/docs/contributing.rst000066400000000000000000000022601354757476000203240ustar00rootroot00000000000000Contribution ============ We welcome all contributions to `sphinx-click`. Support ------- Open and issue in the `issue tracker`_ for all support requests. `StackOverflow`_ is also worth considering. Reporting Issues ---------------- Report all issues in the `issue tracker`_. When doing so, please include version information for: - Python - `click` - `sphinx-click` Submitting Patches ------------------ All patches should be submitted as pull requests on the `GitHub project`_. - Include tests if fixing a bug - Clearly explain what you're trying to accomplish - Follow :pep:`8`. You can use the `pep8` tox target for this Testing ------- `sphinx-click` uses `tox` and `unittest` for testing. To run all tests, run: .. code-block:: shell $ tox We support a number of Python versions. To list available environments, run: .. code-block:: shell $ tox --list To run one of these environments, such as `py27` which runs tests under Python 2.7, run: .. code-block:: shell $ tox -e py27 .. _issue tracker: https://github.com/click-contrib/sphinx-click/issues .. _StackOverflow: https://stackoverflow.com .. _GitHub project: https://github.com/click-contrib/sphinx-click sphinx-click-2.3.1/docs/index.rst000066400000000000000000000011201354757476000167160ustar00rootroot00000000000000sphinx-click ============ :mod:`sphinx-click ` is a `Sphinx`__ plugin that allows you to automatically extract documentation from a `click-based`__ application and include it in your docs. __ http://www.sphinx-doc.org/ __ http://click.pocoo.org/ .. toctree:: :maxdepth: 2 installation usage contributing changelog .. seealso:: Module :mod:`click` This extension assumes you are using :mod:`click` to create your command line application. Module :mod:`sphinxcontrib.autoprogram` An equivalent library for use with :mod:`argparse`. sphinx-click-2.3.1/docs/installation.rst000066400000000000000000000005371354757476000203230ustar00rootroot00000000000000Installation ============ Install the plugin using `pip`: .. code-block:: shell $ pip install sphinx-click Alternatively, install from source by cloning this repo then running `setup.py`: .. code-block:: shell $ python setup.py install .. important:: Both the package you're referencing and any dependencies **must be installed**. sphinx-click-2.3.1/docs/usage.rst000066400000000000000000000103211354757476000167160ustar00rootroot00000000000000Usage ===== To enable the plugin, add the extension to the list of extensions in your Sphinx `conf.py` file: .. code-block:: python extensions = ['sphinx_click.ext'] Once enabled, *sphinx-click* enables automatic documentation for `click-based`_ applications by way of a `Sphinx directive`_. .. rst:directive:: .. click:: module:parser Automatically extract documentation from a `click-based`_ application and include it in your docs. .. code-block:: rst .. click:: module:parser :prog: hello-world :show-nested: 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 ``click.Command``, ``click.Group``, ``click.MultiCommand``, etc. In addition, the following options are required: ``:prog:`` The name of your tool (or how it should appear in your documentation). For example, if you run your script as ``./boo --opts args`` then ``:prog:`` will be ``boo``. If this is not given, the module name is used. The following options are optional: ``:show-nested:`` Enable full documentation for sub-commands. ``:commands:`` Document only listed commands. The generated documentation includes anchors for the generated commands, their options and their environment variables using the `Sphinx standard domain`_. .. _Sphinx directive: http://www.sphinx-doc.org/en/stable/extdev/markupapi.html .. _click-based: http://click.pocoo.org/6/ .. _Sphinx standard domain: http://www.sphinx-doc.org/en/stable/domains.html#the-standard-domain .. |click.core.BaseCommand| replace:: ``click.core.BaseCommand`` .. _click.core.BaseCommand: http://click.pocoo.org/6/api/#click.BaseCommand Example ------- Take the below ``click`` application, which is defined in the ``hello_world`` module: .. code-block:: python import click @click.group() def greet(): """A sample command group.""" pass @greet.command() @click.argument('user', envvar='USER') def hello(user): """Greet a user.""" click.echo('Hello %s' % user) @greet.command() def world(): """Greet the world.""" click.echo('Hello world!') To document this, use the following: .. code-block:: rst .. 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. .. code-block:: rst .. click:: hello_world:greet :prog: hello-world :show-nested: You can also document only selected commands by using ``:commands:`` option. .. code-block:: rst .. click:: hello_world:greet :prog: hello-world :commands: hello You can cross-reference the commands, option and environment variables using the roles provided by the `Sphinx standard domain`_. .. code-block:: rst .. click:: hello_world:greet :prog: hello-world The :program:`hello` command accepts a :option:`user` argument. If this is not provided, the :envvar:`USER` environment variable will be used. .. note:: Cross-referencing using the ``:program:`` directive is not currently supported by Sphinx. Refer to the `Sphinx issue`__ for more information. __ https://github.com/sphinx-doc/sphinx/issues/880 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 to modify ``sys.path``. For example, given the following application:: git |- git | |- __init__.py | \- git.py \- docs |- git.rst |- index.rst \- conf.py then it would be necessary to add the following to ``git/docs/conf.py``: .. code-block:: python import os import sys sys.path.insert(0, os.path.abspath('..')) Once done, you could include the following in ``git/docs/git.rst`` to document the application: .. code-block:: rst .. click:: git.git:cli :prog: git :show-nested: assuming the group or command in ``git.git`` is named ``cli``. Refer to `issue #2 `__ for more information. sphinx-click-2.3.1/requirements.txt000066400000000000000000000000321354757476000174120ustar00rootroot00000000000000pbr>=2.0 sphinx>=1.5,<3.0 sphinx-click-2.3.1/setup.cfg000066400000000000000000000013611354757476000157550ustar00rootroot00000000000000[metadata] name = sphinx-click summary = Sphinx extension that automatically documents click applications description-file = README.rst license = MIT License classifiers = Programming Language :: Python :: 2 Programming Language :: Python :: 3 Programming Language :: Python Development Status :: 5 - Production/Stable Environment :: Console Intended Audience :: Developers Intended Audience :: Information Technology License :: OSI Approved :: MIT License Operating System :: OS Independent keywords = sphinx author = Stephen Finucane author-email = stephen@that.guru home-page = https://github.com/stephenfin/sphinx-click project-url = https://that.guru/ [files] packages = sphinx_click [wheel] universal = 1 sphinx-click-2.3.1/setup.py000066400000000000000000000001551354757476000156460ustar00rootroot00000000000000#!/usr/bin/env python from setuptools import setup setup( setup_requires=['pbr>=2.0'], pbr=True, ) sphinx-click-2.3.1/sphinx_click/000077500000000000000000000000001354757476000166115ustar00rootroot00000000000000sphinx-click-2.3.1/sphinx_click/__init__.py000066400000000000000000000000001354757476000207100ustar00rootroot00000000000000sphinx-click-2.3.1/sphinx_click/ext.py000066400000000000000000000305401354757476000177650ustar00rootroot00000000000000import traceback import click from docutils import nodes, statemachine from docutils.parsers import rst from docutils.parsers.rst import directives from sphinx.util import logging LOG = logging.getLogger(__name__) CLICK_VERSION = tuple(int(x) for x in click.__version__.split('.')[0:2]) def _indent(text, level=1): prefix = ' ' * (4 * level) def prefixed_lines(): for line in text.splitlines(True): yield (prefix + line if line.strip() else line) return ''.join(prefixed_lines()) def _get_usage(ctx): """Alternative, non-prefixed version of 'get_usage'.""" formatter = ctx.make_formatter() pieces = ctx.command.collect_usage_pieces(ctx) formatter.write_usage(ctx.command_path, ' '.join(pieces), prefix='') return formatter.getvalue().rstrip('\n') def _get_help_record(opt): """Re-implementation of click.Opt.get_help_record. The variant of 'get_help_record' found in Click makes uses of slashes to separate multiple opts, and formats option arguments using upper case. This is not compatible with Sphinx's 'option' directive, which expects comma-separated opts and option arguments surrounded by angle brackets [1]. [1] http://www.sphinx-doc.org/en/stable/domains.html#directive-option """ def _write_opts(opts): rv, _ = click.formatting.join_options(opts) if not opt.is_flag and not opt.count: rv += ' <{}>'.format(opt.name) return rv rv = [_write_opts(opt.opts)] if opt.secondary_opts: rv.append(_write_opts(opt.secondary_opts)) help = opt.help or '' extra = [] if opt.default is not None and opt.show_default: if isinstance(opt.show_default, str): # Starting from Click 7.0 this can be a string as well. This is # mostly useful when the default is not a constant and # documentation thus needs a manually written string. extra.append('default: %s' % opt.show_default) else: extra.append('default: %s' % (', '.join('%s' % d for d in opt.default) if isinstance( opt.default, (list, tuple)) else opt.default, )) if opt.required: extra.append('required') if extra: help = '%s[%s]' % (help and help + ' ' or '', '; '.join(extra)) if isinstance(opt.type, click.Choice): help = "%s\n\n:options: %s" % ( help and help + " " or "", "|".join(opt.type.choices), ) return ', '.join(rv), help def _format_description(ctx): """Format the description for a given `click.Command`. We parse this as reStructuredText, allowing users to embed rich information in their help messages if they so choose. """ help_string = ctx.command.help or ctx.command.short_help if not help_string: return bar_enabled = False for line in statemachine.string2lines(help_string, tab_width=4, convert_whitespace=True): if line == '\b': bar_enabled = True continue if line == '': bar_enabled = False line = '| ' + line if bar_enabled else line yield line yield '' def _format_usage(ctx): """Format the usage for a `click.Command`.""" yield '.. code-block:: shell' yield '' for line in _get_usage(ctx).splitlines(): yield _indent(line) yield '' def _format_option(opt): """Format the output for a `click.Option`.""" opt = _get_help_record(opt) yield '.. option:: {}'.format(opt[0]) if opt[1]: yield '' for line in statemachine.string2lines(opt[1], tab_width=4, convert_whitespace=True): yield _indent(line) def _format_options(ctx): """Format all `click.Option` for a `click.Command`.""" # the hidden attribute is part of click 7.x only hence use of getattr params = [ x for x in ctx.command.params if isinstance(x, click.Option) and not getattr(x, 'hidden', False) ] for param in params: for line in _format_option(param): yield line yield '' def _format_argument(arg): """Format the output of a `click.Argument`.""" yield '.. option:: {}'.format(arg.human_readable_name) yield '' yield _indent('{} argument{}'.format( 'Required' if arg.required else 'Optional', '(s)' if arg.nargs != 1 else '')) def _format_arguments(ctx): """Format all `click.Argument` for a `click.Command`.""" params = [x for x in ctx.command.params if isinstance(x, click.Argument)] for param in params: for line in _format_argument(param): yield line yield '' def _format_envvar(param): """Format the envvars of a `click.Option` or `click.Argument`.""" yield '.. envvar:: {}'.format(param.envvar) yield ' :noindex:' yield '' if isinstance(param, click.Argument): param_ref = param.human_readable_name else: # if a user has defined an opt with multiple "aliases", always use the # first. For example, if '--foo' or '-f' are possible, use '--foo'. param_ref = param.opts[0] yield _indent('Provide a default for :option:`{}`'.format(param_ref)) def _format_envvars(ctx): """Format all envvars for a `click.Command`.""" params = [x for x in ctx.command.params if getattr(x, 'envvar')] for param in params: yield '.. _{command_name}-{param_name}-{envvar}:'.format( command_name=ctx.command_path.replace(' ', '-'), param_name=param.name, envvar=param.envvar, ) yield '' for line in _format_envvar(param): yield line yield '' def _format_subcommand(command): """Format a sub-command of a `click.Command` or `click.Group`.""" yield '.. object:: {}'.format(command.name) # click 7.0 stopped setting short_help by default if CLICK_VERSION < (7, 0): short_help = command.short_help else: short_help = command.get_short_help_str() if short_help: yield '' for line in statemachine.string2lines(short_help, tab_width=4, convert_whitespace=True): yield _indent(line) def _get_lazyload_commands(multicommand): commands = {} for command in multicommand.list_commands(multicommand): commands[command] = multicommand.get_command(multicommand, command) return commands def _filter_commands(ctx, commands=None): """Return list of used commands.""" lookup = getattr(ctx.command, 'commands', {}) if not lookup and isinstance(ctx.command, click.MultiCommand): lookup = _get_lazyload_commands(ctx.command) if commands is None: return sorted(lookup.values(), key=lambda item: item.name) names = [name.strip() for name in commands.split(',')] return [lookup[name] for name in names if name in lookup] def _format_command(ctx, show_nested, commands=None): """Format the output of `click.Command`.""" if CLICK_VERSION >= (7, 0) and ctx.command.hidden: return # description for line in _format_description(ctx): yield line yield '.. program:: {}'.format(ctx.command_path) # usage for line in _format_usage(ctx): yield line # options lines = list(_format_options(ctx)) if lines: # we use rubric to provide some separation without exploding the table # of contents yield '.. rubric:: Options' yield '' for line in lines: yield line # arguments lines = list(_format_arguments(ctx)) if lines: yield '.. rubric:: Arguments' yield '' for line in lines: yield line # environment variables lines = list(_format_envvars(ctx)) if lines: yield '.. rubric:: Environment variables' yield '' for line in lines: yield line # if we're nesting commands, we need to do this slightly differently if show_nested: return commands = _filter_commands(ctx, commands) if commands: yield '.. rubric:: Commands' yield '' for command in commands: # Don't show hidden subcommands if CLICK_VERSION >= (7, 0) and command.hidden: continue for line in _format_subcommand(command): yield line yield '' class ClickDirective(rst.Directive): has_content = False required_arguments = 1 option_spec = { 'prog': directives.unchanged_required, 'show-nested': directives.flag, 'commands': directives.unchanged, } def _load_module(self, module_path): """Load the module.""" # __import__ will fail on unicode, # so we ensure module path is a string here. module_path = str(module_path) try: module_name, attr_name = module_path.split(':', 1) except ValueError: # noqa raise self.error( '"{}" is not of format "module:parser"'.format(module_path)) try: mod = __import__(module_name, globals(), locals(), [attr_name]) except (Exception, SystemExit) as exc: # noqa err_msg = 'Failed to import "{}" from "{}". '.format( attr_name, module_name) if isinstance(exc, SystemExit): err_msg += 'The module appeared to call sys.exit()' else: err_msg += 'The following exception was raised:\n{}'.format( traceback.format_exc()) raise self.error(err_msg) if not hasattr(mod, attr_name): raise self.error('Module "{}" has no attribute "{}"'.format( module_name, attr_name)) parser = getattr(mod, attr_name) if not isinstance(parser, click.BaseCommand): raise self.error('"{}" of type "{}" is not derived from ' '"click.BaseCommand"'.format( type(parser), module_path)) return parser def _generate_nodes(self, name, command, parent=None, show_nested=False, 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 commands: Display only listed commands or skip the section if empty :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() lines = _format_command(ctx, show_nested, commands) for line in lines: LOG.debug(line) result.append(line, source_name) self.state.nested_parse(result, 0, section) # Subcommands if show_nested: commands = _filter_commands(ctx, commands) for command in commands: section.extend( self._generate_nodes(command.name, command, ctx, show_nested)) return [section] def run(self): self.env = self.state.document.settings.env command = self._load_module(self.arguments[0]) if 'prog' not in self.options: raise self.error(':prog: must be specified') prog_name = self.options.get('prog') show_nested = 'show-nested' in self.options commands = self.options.get('commands') return self._generate_nodes(prog_name, command, None, show_nested, commands) def setup(app): app.add_directive('click', ClickDirective) sphinx-click-2.3.1/test-requirements.txt000066400000000000000000000000421354757476000203700ustar00rootroot00000000000000click>=5.0,<8.0 coverage>4.3,<5.0 sphinx-click-2.3.1/tests/000077500000000000000000000000001354757476000152755ustar00rootroot00000000000000sphinx-click-2.3.1/tests/__init__.py000066400000000000000000000000001354757476000173740ustar00rootroot00000000000000sphinx-click-2.3.1/tests/test_formatter.py000066400000000000000000000303161354757476000207140ustar00rootroot00000000000000import textwrap import unittest import click from sphinx_click import ext class CommandTestCase(unittest.TestCase): 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, show_nested=False)) self.assertEqual( textwrap.dedent(""" A sample command. .. program:: foobar .. code-block:: shell foobar [OPTIONS] """).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('--choice', help='A sample option with choices', type=click.Choice(['Option1', 'Option2'])) @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 A sample option .. option:: --choice A sample option with choices :options: Option1|Option2 .. 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)) @unittest.skipIf(ext.CLICK_VERSION < (7, 0), 'Allowing show_default to be a string was added in Click 7.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 [default: 42] .. option:: --param [default: Something computed at runtime] """).lstrip(), '\n'.join(output)) @unittest.skipIf(ext.CLICK_VERSION < (7, 0), 'The hidden flag was added in Click 7.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)) class GroupTestCase(unittest.TestCase): 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_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 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_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, show_nested=False)) 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)) class NestedCommandsTestCase(unittest.TestCase): @staticmethod def _get_ctx(): @click.group() def cli(): """A sample command group.""" pass @cli.command() def hello(): """A sample command.""" pass return click.Context(cli, info_name='cli') 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 test_show_nested(self): """Validate a nested command with 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)) class CommandFilterTestCase(unittest.TestCase): @staticmethod def _get_ctx(): @click.group() def cli(): """A sample command group.""" @cli.command() def hello(): """A sample command.""" @cli.command() def world(): """A world command.""" return click.Context(cli, info_name='cli') 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_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)) class CustomMultiCommandTestCase(unittest.TestCase): 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)) @unittest.skipIf(ext.CLICK_VERSION < (7, 0), 'The hidden flag was added in Click 7.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, show_nested=False)) # 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)) sphinx-click-2.3.1/tox.ini000066400000000000000000000014131354757476000154450ustar00rootroot00000000000000[tox] minversion = 2.0 envlist = py{27,35,36,37,36-pre,37-pre,py}-click{6,7},style,docs [testenv] deps = coverage>4.3,<5.0 click6: click>=6.0,<7.0 click7: click>=7.0,<8.0 commands = coverage run --source={toxinidir}/sphinx_click -m unittest discover -s tests/ coverage report pip_pre = pre: true [testenv:coverage] commands = {[testenv]commands} coverage {posargs:html} [testenv:style] deps = isort yapf flake8 commands = isort -rc -c -df {toxinidir}/sphinx_click/ yapf -ri {toxinidir}/sphinx_click/ flake8 {toxinidir}/sphinx_click/ [coverage:run] branch = True [testenv:docs] commands = sphinx-build -W -b html -d docs/_build/doctrees docs docs/_build/html [travis] python = 2.7: py27, docs 3.7: py37, style