From 42370b932aff6b38f738f82cbe567a07c9786024 Mon Sep 17 00:00:00 2001 From: Cory Johns Date: Tue, 13 Jun 2017 13:51:43 -0400 Subject: [PATCH] Improve API doc navigation and coverage (#141) * Remove unused requirements.txt * Clean up generated doc files * Improve API doc coverage and navigation Fixes #139 --- Makefile | 4 +- docs/_extensions/automembersummary.py | 114 ++++++++++++++++++ docs/_static/custom.css | 5 + docs/api/juju.action.rst | 13 ++ docs/api/juju.annotation.rst | 13 ++ docs/api/juju.application.rst | 13 ++ docs/api/juju.client.rst | 62 +++++++++- docs/api/juju.cloud.rst | 13 ++ docs/api/juju.constraints.rst | 13 ++ docs/api/juju.controller.rst | 13 ++ docs/api/juju.delta.rst | 13 ++ docs/api/juju.errors.rst | 13 ++ docs/api/juju.exceptions.rst | 13 ++ docs/api/juju.juju.rst | 13 ++ docs/api/juju.loop.rst | 13 ++ docs/api/juju.machine.rst | 13 ++ docs/api/juju.model.rst | 13 ++ docs/api/juju.placement.rst | 13 ++ docs/api/juju.relation.rst | 13 ++ docs/api/juju.rst | 165 -------------------------- docs/api/juju.tag.rst | 13 ++ docs/api/juju.unit.rst | 13 ++ docs/api/juju.utils.rst | 13 ++ docs/api/modules.rst | 28 ++++- docs/conf.py | 9 +- docs/index.rst | 1 + docs/requirements.txt | 1 + juju/model.py | 14 +++ requirements.txt | 3 - scripts/gendoc | 39 ++++++ 30 files changed, 504 insertions(+), 175 deletions(-) create mode 100644 docs/_extensions/automembersummary.py create mode 100644 docs/_static/custom.css create mode 100644 docs/api/juju.action.rst create mode 100644 docs/api/juju.annotation.rst create mode 100644 docs/api/juju.application.rst create mode 100644 docs/api/juju.cloud.rst create mode 100644 docs/api/juju.constraints.rst create mode 100644 docs/api/juju.controller.rst create mode 100644 docs/api/juju.delta.rst create mode 100644 docs/api/juju.errors.rst create mode 100644 docs/api/juju.exceptions.rst create mode 100644 docs/api/juju.juju.rst create mode 100644 docs/api/juju.loop.rst create mode 100644 docs/api/juju.machine.rst create mode 100644 docs/api/juju.model.rst create mode 100644 docs/api/juju.placement.rst create mode 100644 docs/api/juju.relation.rst delete mode 100644 docs/api/juju.rst create mode 100644 docs/api/juju.tag.rst create mode 100644 docs/api/juju.unit.rst create mode 100644 docs/api/juju.utils.rst delete mode 100644 requirements.txt create mode 100755 scripts/gendoc diff --git a/Makefile b/Makefile index 2a695bc..2418d1b 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ clean: find . -name __pycache__ -type d -exec rm -r {} + find . -name *.pyc -delete rm -rf .tox + rm -rf docs/_build/ .tox: tox -r --notest @@ -23,8 +24,7 @@ test: docs: .tox $(PIP) install -r docs/requirements.txt - rm -rf docs/api/* docs/_build/ - $(BIN)/sphinx-apidoc -o docs/api/ juju/ + rm -rf docs/_build/ $(BIN)/sphinx-build -b html docs/ docs/_build/ cd docs/_build/ && zip -r docs.zip * diff --git a/docs/_extensions/automembersummary.py b/docs/_extensions/automembersummary.py new file mode 100644 index 0000000..898da62 --- /dev/null +++ b/docs/_extensions/automembersummary.py @@ -0,0 +1,114 @@ +# Copyright 2014-2015 Canonical Limited. +# +# This file is part of charm-helpers. +# +# charm-helpers is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 as +# published by the Free Software Foundation. +# +# charm-helpers is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with charm-helpers. If not, see . + + +import importlib +import inspect +import textwrap + +from docutils import nodes +from docutils.statemachine import ViewList +from sphinx.errors import SphinxError +from sphinx.util.compat import Directive +from sphinx.util.nodes import nested_parse_with_titles + + +class AutoMemberSummary(Directive): + required_arguments = 1 + + def run(self): + module_name = self.arguments[0] + + try: + module = importlib.import_module(module_name) + except ImportError: + raise SphinxError("Unable to generate reference docs for %s, " + "could not import" % (module_name)) + + divider = '+{:-<80}+'.format('') + row = '| {:<78} |'.format + lines = [] + for member_name, member in inspect.getmembers(module): + if not self._filter(module_name, member_name, member): + continue + summary = textwrap.wrap(self._get_summary(member), 78) or [''] + link = '`{} <#{}>`_'.format(member_name, + '.'.join([module_name, + member_name])) + methods = ['* `{} <#{}>`_'.format(n, + '.'.join([module_name, + member_name, + n])) + for n, m in inspect.getmembers(member) + if not n.startswith('_') and inspect.isfunction(m)] + + lines.append(divider) + lines.append(row(link)) + lines.append(divider) + for line in summary: + lines.append(row(line)) + if methods: + lines.append(row('')) + lines.append(row('Methods:')) + lines.append(row('')) + for i, method in enumerate(methods): + lines.append(row(method)) + lines.append(divider) + content = '\n'.join(lines) + + result = self._parse(content, '') + return result + + def _get_summary(self, member): + doc = (member.__doc__ or '').splitlines() + + # strip any leading blank lines + while doc and not doc[0].strip(): + doc.pop(0) + + # strip anything after the first blank line + for i, piece in enumerate(doc): + if not piece.strip(): + doc = doc[:i] + break + + return " ".join(doc).strip() + + def _filter(self, module_name, member_name, member): + if member_name.startswith('_'): + return False + if hasattr(member, '__module__'): + # skip imported classes & functions + return member.__module__.startswith(module_name) + elif hasattr(member, '__name__'): + # skip imported modules + return member.__name__.startswith(module_name) + else: + return False # skip instances + return True + + def _parse(self, rst_text, annotation): + result = ViewList() + for line in rst_text.split("\n"): + result.append(line, annotation) + node = nodes.paragraph() + node.document = self.state.document + nested_parse_with_titles(self.state, result, node) + return node.children + + +def setup(app): + app.add_directive('automembersummary', AutoMemberSummary) diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..333cd74 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,5 @@ +.wy-table-responsive table td, +.wy-table-responsive table th +{ + white-space: normal !important; +} diff --git a/docs/api/juju.action.rst b/docs/api/juju.action.rst new file mode 100644 index 0000000..cc86af2 --- /dev/null +++ b/docs/api/juju.action.rst @@ -0,0 +1,13 @@ +juju.action +=========== + +.. rubric:: Summary + +.. automembersummary:: juju.action + +.. rubric:: Reference + +.. automodule:: juju.action + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.annotation.rst b/docs/api/juju.annotation.rst new file mode 100644 index 0000000..ec31344 --- /dev/null +++ b/docs/api/juju.annotation.rst @@ -0,0 +1,13 @@ +juju.annotation +=============== + +.. rubric:: Summary + +.. automembersummary:: juju.annotation + +.. rubric:: Reference + +.. automodule:: juju.annotation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.application.rst b/docs/api/juju.application.rst new file mode 100644 index 0000000..dba9177 --- /dev/null +++ b/docs/api/juju.application.rst @@ -0,0 +1,13 @@ +juju.application +================ + +.. rubric:: Summary + +.. automembersummary:: juju.application + +.. rubric:: Reference + +.. automodule:: juju.application + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.client.rst b/docs/api/juju.client.rst index 6f29d45..6a699c0 100644 --- a/docs/api/juju.client.rst +++ b/docs/api/juju.client.rst @@ -1,8 +1,10 @@ juju\.client package ==================== -Submodules ----------- +These packages are for internal use in communicating with the low-level +API. You should use the object oriented API instead. They are documented +here for developer reference. + juju\.client\.client module --------------------------- @@ -12,6 +14,62 @@ juju\.client\.client module :undoc-members: :show-inheritance: +juju\.client\._definitions module +--------------------------------- + +.. automodule:: juju.client._definitions + :members: + :undoc-members: + :show-inheritance: + +juju\.client\._client module +---------------------------- + +.. automodule:: juju.client._client + :members: + :undoc-members: + :show-inheritance: + +juju\.client\._client1 module +----------------------------- + +.. automodule:: juju.client._client1 + :members: + :undoc-members: + :show-inheritance: + +juju\.client\._client2 module +----------------------------- + +.. automodule:: juju.client._client2 + :members: + :undoc-members: + :show-inheritance: + +juju\.client\._client3 module +----------------------------- + +.. automodule:: juju.client._client3 + :members: + :undoc-members: + :show-inheritance: + +juju\.client\._client4 module +----------------------------- + +.. automodule:: juju.client._client4 + :members: + :undoc-members: + :show-inheritance: + +juju\.client\._client5 module +----------------------------- + +.. automodule:: juju.client._client5 + :members: + :undoc-members: + :show-inheritance: + juju\.client\.codegen module ---------------------------- diff --git a/docs/api/juju.cloud.rst b/docs/api/juju.cloud.rst new file mode 100644 index 0000000..39021e0 --- /dev/null +++ b/docs/api/juju.cloud.rst @@ -0,0 +1,13 @@ +juju.cloud +========== + +.. rubric:: Summary + +.. automembersummary:: juju.cloud + +.. rubric:: Reference + +.. automodule:: juju.cloud + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.constraints.rst b/docs/api/juju.constraints.rst new file mode 100644 index 0000000..5fcbd31 --- /dev/null +++ b/docs/api/juju.constraints.rst @@ -0,0 +1,13 @@ +juju.constraints +================ + +.. rubric:: Summary + +.. automembersummary:: juju.constraints + +.. rubric:: Reference + +.. automodule:: juju.constraints + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.controller.rst b/docs/api/juju.controller.rst new file mode 100644 index 0000000..4484fd5 --- /dev/null +++ b/docs/api/juju.controller.rst @@ -0,0 +1,13 @@ +juju.controller +=============== + +.. rubric:: Summary + +.. automembersummary:: juju.controller + +.. rubric:: Reference + +.. automodule:: juju.controller + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.delta.rst b/docs/api/juju.delta.rst new file mode 100644 index 0000000..9924f8c --- /dev/null +++ b/docs/api/juju.delta.rst @@ -0,0 +1,13 @@ +juju.delta +========== + +.. rubric:: Summary + +.. automembersummary:: juju.delta + +.. rubric:: Reference + +.. automodule:: juju.delta + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.errors.rst b/docs/api/juju.errors.rst new file mode 100644 index 0000000..7c77574 --- /dev/null +++ b/docs/api/juju.errors.rst @@ -0,0 +1,13 @@ +juju.errors +=========== + +.. rubric:: Summary + +.. automembersummary:: juju.errors + +.. rubric:: Reference + +.. automodule:: juju.errors + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.exceptions.rst b/docs/api/juju.exceptions.rst new file mode 100644 index 0000000..85be2fb --- /dev/null +++ b/docs/api/juju.exceptions.rst @@ -0,0 +1,13 @@ +juju.exceptions +=============== + +.. rubric:: Summary + +.. automembersummary:: juju.exceptions + +.. rubric:: Reference + +.. automodule:: juju.exceptions + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.juju.rst b/docs/api/juju.juju.rst new file mode 100644 index 0000000..68698c3 --- /dev/null +++ b/docs/api/juju.juju.rst @@ -0,0 +1,13 @@ +juju.juju +========= + +.. rubric:: Summary + +.. automembersummary:: juju.juju + +.. rubric:: Reference + +.. automodule:: juju.juju + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.loop.rst b/docs/api/juju.loop.rst new file mode 100644 index 0000000..4f175e9 --- /dev/null +++ b/docs/api/juju.loop.rst @@ -0,0 +1,13 @@ +juju.loop +========= + +.. rubric:: Summary + +.. automembersummary:: juju.loop + +.. rubric:: Reference + +.. automodule:: juju.loop + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.machine.rst b/docs/api/juju.machine.rst new file mode 100644 index 0000000..edb5b6c --- /dev/null +++ b/docs/api/juju.machine.rst @@ -0,0 +1,13 @@ +juju.machine +============ + +.. rubric:: Summary + +.. automembersummary:: juju.machine + +.. rubric:: Reference + +.. automodule:: juju.machine + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.model.rst b/docs/api/juju.model.rst new file mode 100644 index 0000000..dfb735d --- /dev/null +++ b/docs/api/juju.model.rst @@ -0,0 +1,13 @@ +juju.model +========== + +.. rubric:: Summary + +.. automembersummary:: juju.model + +.. rubric:: Reference + +.. automodule:: juju.model + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.placement.rst b/docs/api/juju.placement.rst new file mode 100644 index 0000000..67cde0c --- /dev/null +++ b/docs/api/juju.placement.rst @@ -0,0 +1,13 @@ +juju.placement +============== + +.. rubric:: Summary + +.. automembersummary:: juju.placement + +.. rubric:: Reference + +.. automodule:: juju.placement + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.relation.rst b/docs/api/juju.relation.rst new file mode 100644 index 0000000..90e3130 --- /dev/null +++ b/docs/api/juju.relation.rst @@ -0,0 +1,13 @@ +juju.relation +============= + +.. rubric:: Summary + +.. automembersummary:: juju.relation + +.. rubric:: Reference + +.. automodule:: juju.relation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.rst b/docs/api/juju.rst deleted file mode 100644 index e92db41..0000000 --- a/docs/api/juju.rst +++ /dev/null @@ -1,165 +0,0 @@ -juju package -============ - -Subpackages ------------ - -.. toctree:: - - juju.client - -Submodules ----------- - -juju\.action module -------------------- - -.. automodule:: juju.action - :members: - :undoc-members: - :show-inheritance: - -juju\.annotation module ------------------------ - -.. automodule:: juju.annotation - :members: - :undoc-members: - :show-inheritance: - -juju\.application module ------------------------- - -.. automodule:: juju.application - :members: - :undoc-members: - :show-inheritance: - -juju\.cloud module ------------------- - -.. automodule:: juju.cloud - :members: - :undoc-members: - :show-inheritance: - -juju\.constraints module ------------------------- - -.. automodule:: juju.constraints - :members: - :undoc-members: - :show-inheritance: - -juju\.controller module ------------------------ - -.. automodule:: juju.controller - :members: - :undoc-members: - :show-inheritance: - -juju\.delta module ------------------- - -.. automodule:: juju.delta - :members: - :undoc-members: - :show-inheritance: - -juju\.errors module -------------------- - -.. automodule:: juju.errors - :members: - :undoc-members: - :show-inheritance: - -juju\.exceptions module ------------------------ - -.. automodule:: juju.exceptions - :members: - :undoc-members: - :show-inheritance: - -juju\.juju module ------------------ - -.. automodule:: juju.juju - :members: - :undoc-members: - :show-inheritance: - -juju\.loop module ------------------ - -.. automodule:: juju.loop - :members: - :undoc-members: - :show-inheritance: - -juju\.machine module --------------------- - -.. automodule:: juju.machine - :members: - :undoc-members: - :show-inheritance: - -juju\.model module ------------------- - -.. automodule:: juju.model - :members: - :undoc-members: - :show-inheritance: - -juju\.placement module ----------------------- - -.. automodule:: juju.placement - :members: - :undoc-members: - :show-inheritance: - -juju\.relation module ---------------------- - -.. automodule:: juju.relation - :members: - :undoc-members: - :show-inheritance: - -juju\.tag module ----------------- - -.. automodule:: juju.tag - :members: - :undoc-members: - :show-inheritance: - -juju\.unit module ------------------ - -.. automodule:: juju.unit - :members: - :undoc-members: - :show-inheritance: - -juju\.utils module ------------------- - -.. automodule:: juju.utils - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: juju - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/api/juju.tag.rst b/docs/api/juju.tag.rst new file mode 100644 index 0000000..9b3a29f --- /dev/null +++ b/docs/api/juju.tag.rst @@ -0,0 +1,13 @@ +juju.tag +======== + +.. rubric:: Summary + +.. automembersummary:: juju.tag + +.. rubric:: Reference + +.. automodule:: juju.tag + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.unit.rst b/docs/api/juju.unit.rst new file mode 100644 index 0000000..4a7d167 --- /dev/null +++ b/docs/api/juju.unit.rst @@ -0,0 +1,13 @@ +juju.unit +========= + +.. rubric:: Summary + +.. automembersummary:: juju.unit + +.. rubric:: Reference + +.. automodule:: juju.unit + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/juju.utils.rst b/docs/api/juju.utils.rst new file mode 100644 index 0000000..9220a1b --- /dev/null +++ b/docs/api/juju.utils.rst @@ -0,0 +1,13 @@ +juju.utils +========== + +.. rubric:: Summary + +.. automembersummary:: juju.utils + +.. rubric:: Reference + +.. automodule:: juju.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/modules.rst b/docs/api/modules.rst index dbedff3..bf06f26 100644 --- a/docs/api/modules.rst +++ b/docs/api/modules.rst @@ -1,7 +1,31 @@ juju ==== +It is recommended that you start with :doc:`juju.model` or :doc:`juju.controller`. +If you need helpers to manage the asyncio loop, try :doc:`juju.loop`. + .. toctree:: - :maxdepth: 4 - juju + juju.action + juju.annotation + juju.application + juju.cloud + juju.constraints + juju.controller + juju.delta + juju.errors + juju.exceptions + juju.juju + juju.loop + juju.machine + juju.model + juju.placement + juju.relation + juju.tag + juju.unit + juju.utils + +.. automodule:: juju + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py index 973ef9a..a95ec04 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,11 +33,15 @@ sys.path.insert(0, os.path.abspath('..')) # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. +sys.path.append(os.path.abspath('_extensions/')) extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinxcontrib.asyncio', + 'automembersummary', ] # Add any paths that contain templates here, relative to this directory. @@ -118,7 +122,7 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # 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 @@ -294,3 +298,6 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +def setup(app): + app.add_stylesheet('custom.css') diff --git a/docs/index.rst b/docs/index.rst index 2e45311..b4b075f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,6 +16,7 @@ Table of Contents narrative/index API Docs + Internal API Docs upstream-updates/index diff --git a/docs/requirements.txt b/docs/requirements.txt index 3bd387e..334534d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ sphinx sphinxcontrib-asyncio +sphinx_rtd_theme diff --git a/juju/model.py b/juju/model.py index 4430dad..160707b 100644 --- a/juju/model.py +++ b/juju/model.py @@ -76,6 +76,9 @@ class _Observer(object): class ModelObserver(object): + """ + Base class for creating observers that react to changes in a model. + """ async def __call__(self, delta, old, new, model): handler_name = 'on_{}_{}'.format(delta.entity, delta.type) method = getattr(self, handler_name, self.on_change) @@ -84,6 +87,8 @@ class ModelObserver(object): async def on_change(self, delta, old, new, model): """Generic model-change handler. + This should be overridden in a subclass. + :param delta: :class:`juju.client.overrides.Delta` :param old: :class:`juju.model.ModelEntity` :param new: :class:`juju.model.ModelEntity` @@ -374,6 +379,9 @@ class ModelEntity(object): class Model(object): + """ + The main API for interacting with a Juju model. + """ def __init__(self, loop=None): """Instantiate a new connected Model. @@ -1890,6 +1898,12 @@ class CharmStore(object): class CharmArchiveGenerator(object): + """ + Create a Zip archive of a local charm directory for upload to a controller. + + This is used automatically by + `Model.add_local_charm_dir <#juju.model.Model.add_local_charm_dir>`_. + """ def __init__(self, path): self.path = os.path.abspath(os.path.expanduser(path)) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 6deadd5..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ ---index-url https://pypi.python.org/simple/ -dateutil --e . diff --git a/scripts/gendoc b/scripts/gendoc new file mode 100755 index 0000000..3ef628e --- /dev/null +++ b/scripts/gendoc @@ -0,0 +1,39 @@ +#!/bin/bash +packages=( + juju.action + juju.annotation + juju.application + juju.cloud + juju.constraints + juju.controller + juju.delta + juju.errors + juju.exceptions + juju.juju + juju.loop + juju.machine + juju.model + juju.placement + juju.relation + juju.tag + juju.unit + juju.utils +) + +for pkg in ${packages[@]}; do + cat < docs/api/$pkg.rst +$pkg +$(echo $pkg | sed -e 's/./=/g') + +.. rubric:: Summary + +.. automembersummary:: $pkg + +.. rubric:: Reference + +.. automodule:: $pkg + :members: + :undoc-members: + :show-inheritance: +EOD +done -- 2.25.1