Improve API doc navigation and coverage (#141)
authorCory Johns <johnsca@gmail.com>
Tue, 13 Jun 2017 17:51:43 +0000 (13:51 -0400)
committerGitHub <noreply@github.com>
Tue, 13 Jun 2017 17:51:43 +0000 (13:51 -0400)
* Remove unused requirements.txt

* Clean up generated doc files

* Improve API doc coverage and navigation

Fixes #139

30 files changed:
Makefile
docs/_extensions/automembersummary.py [new file with mode: 0644]
docs/_static/custom.css [new file with mode: 0644]
docs/api/juju.action.rst [new file with mode: 0644]
docs/api/juju.annotation.rst [new file with mode: 0644]
docs/api/juju.application.rst [new file with mode: 0644]
docs/api/juju.client.rst
docs/api/juju.cloud.rst [new file with mode: 0644]
docs/api/juju.constraints.rst [new file with mode: 0644]
docs/api/juju.controller.rst [new file with mode: 0644]
docs/api/juju.delta.rst [new file with mode: 0644]
docs/api/juju.errors.rst [new file with mode: 0644]
docs/api/juju.exceptions.rst [new file with mode: 0644]
docs/api/juju.juju.rst [new file with mode: 0644]
docs/api/juju.loop.rst [new file with mode: 0644]
docs/api/juju.machine.rst [new file with mode: 0644]
docs/api/juju.model.rst [new file with mode: 0644]
docs/api/juju.placement.rst [new file with mode: 0644]
docs/api/juju.relation.rst [new file with mode: 0644]
docs/api/juju.rst [deleted file]
docs/api/juju.tag.rst [new file with mode: 0644]
docs/api/juju.unit.rst [new file with mode: 0644]
docs/api/juju.utils.rst [new file with mode: 0644]
docs/api/modules.rst
docs/conf.py
docs/index.rst
docs/requirements.txt
juju/model.py
requirements.txt [deleted file]
scripts/gendoc [new file with mode: 0755]

index 2a695bc..2418d1b 100644 (file)
--- 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 (file)
index 0000000..898da62
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+
+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, '<automembersummary>')
+        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 (file)
index 0000000..333cd74
--- /dev/null
@@ -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 (file)
index 0000000..cc86af2
--- /dev/null
@@ -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 (file)
index 0000000..ec31344
--- /dev/null
@@ -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 (file)
index 0000000..dba9177
--- /dev/null
@@ -0,0 +1,13 @@
+juju.application
+================
+
+.. rubric:: Summary
+
+.. automembersummary:: juju.application
+
+.. rubric:: Reference
+
+.. automodule:: juju.application
+    :members:
+    :undoc-members:
+    :show-inheritance:
index 6f29d45..6a699c0 100644 (file)
@@ -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 (file)
index 0000000..39021e0
--- /dev/null
@@ -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 (file)
index 0000000..5fcbd31
--- /dev/null
@@ -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 (file)
index 0000000..4484fd5
--- /dev/null
@@ -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 (file)
index 0000000..9924f8c
--- /dev/null
@@ -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 (file)
index 0000000..7c77574
--- /dev/null
@@ -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 (file)
index 0000000..85be2fb
--- /dev/null
@@ -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 (file)
index 0000000..68698c3
--- /dev/null
@@ -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 (file)
index 0000000..4f175e9
--- /dev/null
@@ -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 (file)
index 0000000..edb5b6c
--- /dev/null
@@ -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 (file)
index 0000000..dfb735d
--- /dev/null
@@ -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 (file)
index 0000000..67cde0c
--- /dev/null
@@ -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 (file)
index 0000000..90e3130
--- /dev/null
@@ -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 (file)
index e92db41..0000000
+++ /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 (file)
index 0000000..9b3a29f
--- /dev/null
@@ -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 (file)
index 0000000..4a7d167
--- /dev/null
@@ -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 (file)
index 0000000..9220a1b
--- /dev/null
@@ -0,0 +1,13 @@
+juju.utils
+==========
+
+.. rubric:: Summary
+
+.. automembersummary:: juju.utils
+
+.. rubric:: Reference
+
+.. automodule:: juju.utils
+    :members:
+    :undoc-members:
+    :show-inheritance:
index dbedff3..bf06f26 100644 (file)
@@ -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:
index 973ef9a..a95ec04 100644 (file)
@@ -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')
index 2e45311..b4b075f 100644 (file)
@@ -16,6 +16,7 @@ Table of Contents
 
    narrative/index
    API Docs <api/modules>
+   Internal API Docs <api/juju.client>
    upstream-updates/index
 
 
index 3bd387e..334534d 100644 (file)
@@ -1,2 +1,3 @@
 sphinx
 sphinxcontrib-asyncio
+sphinx_rtd_theme
index 4430dad..160707b 100644 (file)
@@ -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 (file)
index 6deadd5..0000000
+++ /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 (executable)
index 0000000..3ef628e
--- /dev/null
@@ -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 <<EOD > 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