Developer Guide¶
Setup Development Environment¶
Install
pip
andtox
:sudo apt-get install python-pip sudo pip install tox
Configure git pre-commit hook:
sudo pip install flake8 pep8-naming flake8 --install-hook git config flake8.strict true
Building Documentation¶
tox -e doc
Output will be available at .tox/doc/tmp/html
. It is recommended to install
the webdev
package:
sudo pip install webdev
So a development web server can serve any location like this:
$ webdev .tox/doc/tmp/html
Running Test Suite¶
tox -e py27,py34
autoapi
¶
Module that provides the module tree node APINode
.
This class will load the module identified by name
and recursively build a
tree with all it’s submodules and subpackages. In the process, each node
analyze and fetch the public API of that module.
name
can be any node, like the root package, or any subpackage or submodule
and a tree will be built from there. name
must follow the standard
“dot notation” for importing a module.
This class will not assume any special naming, or perform any complex analysis to determine what must be in the public interface. This is because it is not only a difficult problem, but it involves analyzing deeply the namespace of the module which can be quite expensive.
In general it is very difficult to determine in a module namespace what
elements are private or public declared locally, private or public but declared
in another module and brought into the module local namespace
(from x import y
), third party library, Python standard library, etc. At
the end, any algorithm that tries to determine this will eventually fail to
meet the requirements or expectations of the developer, leaving false positives
or removing elements expected to be present in the public API.
For example, a common scenario is that some modules, specially package entry
points __init__.py
, can be setup to expose the public API of their sibling
modules, possible causing several objects to be identified as part of the
public API of both modules.
Because of this the approach taken by this module follows the rule in PEP20
“Explicit is better than implicit”. In consequence, the node will consider
elements as public if they are explicitly listed in the __api__
or
__all__
variables. It is up to the developer to list the elements that must
be published in the public API.
__api__
is a special variable introduced by this module, and it exists for
situation were for whatever reason the developer don’t want to list in the
__all__
variable an element that needs to be published in the public API.
This class will extract all elements identified in ONE of those listings (not
the union), with __api__
having the precedence. If none of those variables
exists in the module then it will be assumed that no public API exists for that
module and no futher actions will be taken.
If any of those variables exists this class will iterate all elements listed in them and will catalog them in four categories:
- Functions.
- Exceptions.
- Classes.
- Variables.
Being Variables the default if it cannot be determined that an element belongs to any of other categories.
Submodules¶
autoapi.sphinx
¶
Glue for Sphinx API.
Functions¶
builder_inited()
: autoapi Sphinx extension hook for thebuilder-inited
event.setup()
: autoapi Sphinx extension setup.
-
autoapi.sphinx.
builder_inited
(app)¶ autoapi Sphinx extension hook for the
builder-inited
event.This hook will read the configuration value
autoapi_modules
and render the modules described in it.See http://sphinx-doc.org/extdev/appapi.html#event-builder-inited
-
autoapi.sphinx.
setup
(app)¶ autoapi Sphinx extension setup.
See http://sphinx-doc.org/extdev/tutorial.html#the-setup-function
Classes¶
APINode
: Tree node class for module instrospection.
-
class
autoapi.
APINode
(name, directory=None)¶ Tree node class for module instrospection.
Parameters: Attributes:
Variables: - name – Name of the current module.
- subname – Last part of the name of this module. For example if name is
my.module.another
the subname will beanother
. - directory – Directory of the tree. This is a
OrderedDict
that will register all modules name with it’s associated nodeAPINode
. All nodes of a tree share this index and thus the whole tree can be queried from any node. - module – The loaded module.
- subnodes – A list of
APINode
with all child submodules and subpackages. - subnodes_failed – A list of submodules and subpackages names that failed to import.
Public API categories:
Variables: - functions – A
OrderedDict
of all functions found in the public API of the module. - classes – A
OrderedDict
of all classes found in the public API of the module. - exceptions – A
OrderedDict
of all exceptions found in the public API of the module. - variables – A
OrderedDict
of all other elements found in the public API of the module.
In all categories the order on which the elements are listed is preserved.
Inheritance
-
depth
()¶ Get the depth of the current node in the tree.
Return type: int Returns: The depth of the node. For example, for node my.add.foo
the depth is 3.
-
get_module
(name)¶ Get a module node by it’s name.
This is just a helper that does lookup on the directory index.
Return type: APINode
or NoneReturns: The module node identified by name
in the tree.None
if the name doesn’t exists.
-
has_public_api
()¶ Check if this node has a public API.
Return type: bool Returns: True if any category has at least one element.
-
is_leaf
()¶ Check if the current node is a leaf in the tree.
A leaf node not necessarily is a module, it can be a package without modules (just the entry point
__init__.py
).Return type: bool Returns: True if no other subnodes exists for this node.
-
is_relevant
()¶ Check if this branch of the tree is relevant.
A branch is relevant if the current node has a public API or if any of its subnodes is relevant (in order to reach relevant nodes).
Relevancy is determined at initialization by the root node.
Return type: bool Returns: True if the current node is relevant.
-
is_root
()¶ Check if the current node is the root node.
Return type: bool Returns: True if the current node is the root node.
-
tree
(level=0, fullname=True)¶ Pretty print the subtree at the current node.
For example, for the module
confspec
:confspec confspec.manager [c] confspec.options [c] confspec.providers [c, v] confspec.providers.dict [c] confspec.providers.ini [c] confspec.providers.json [c] confspec.utils [f] confspec.validation [f]
The tags at the right of the name shows what kind of elements are present in the public interfaces of those modules.
Parameters:
-
walk
()¶ Traverse the tree top-down.
Returns: This method will yield tuples (node, [leaves])
for each node in the tree.
documented
¶
This is my module brief line.
This is a more complete paragraph documenting my module.
- A list item.
- Another list item.
This section can use any reST syntax.
Functions¶
a_function()
: This is the brief description of my function.
-
documented.
a_function
(my_arg, another)¶ This is the brief description of my function.
This is a more complete example of my function. It can include doctest, code blocks or any other reST structure.
>>> a_function(10, [MyClass('a'), MyClass('b')]) 20
Parameters: Returns: The length of the second argument times the first argument.
Return type:
Classes¶
MyClass
: This is the brief of my main class.AnotherClass
: This another class.
-
class
documented.
MyClass
(param1, param2=None)¶ This is the brief of my main class.
A more general description of what the class does.
Parameters: Variables: my_attribute – Just an instance attribute.
Raises: TypeError – if param2 is not None.
Inheritance
-
class_attribute
= 625¶ This is a class attribute.
-
Exceptions¶
MyException
: This is my custom exception.
-
exception
documented.
MyException
¶ This is my custom exception.
This is a more complete description of what my exception does. Again, you can be as verbose as you want here.
Inheritance
AutoAPI¶
Automatic Python API reference documentation generator for Sphinx, inspired by Doxygen.
AutoAPI is a Sphinx extension that allows to automatically generate API reference documentation for Python packages (example), recursively, without any intervention from the developer. It will discover all the package modules and their public objects and document them.
Usage¶
Install:
pip install autoapi
Or if using Virtualenv or Tox (and you should) add it to your requirements.txt (or requirements.dev.txt if you want to separate your package requirements from the development requirements).
Add AutoAPI to your extensions:
In your Sphinx
conf.py
configuration file addautoapi.sphinx
:extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.inheritance_diagram', 'autoapi.sphinx' ]
Make sure to have
autodoc
andinheritance_diagram
too because the default generation template will use them.Configure AutoAPI with the root modules you want to generate documentation for:
In your project
conf.py
file define theautoapi_modules
dictionary variable with the module names as keys:autoapi_modules = {'mymodule': None}
This dictionary maps the module names with the options for generation for that module:
prune: bool [False]
The package to document is modeled as a tree, and each submodule is a node of that tree. A node is considered relevant if it has a public interface that needs to be documented or it is required to reach a node that has a public interface. Ifprune
is set toTrue
, all branches that aren’t relevant will be silently ignored. IfFalse
, all branches will be generated, even for those modules that do not possess a public interface.override: bool [True]
Regenerate the reference pages even if they exists. AutoAPI by default is automatic, but if you prefer to use it like autosummary_generate and create stub pages for later manual edition set theoverride
flag toFalse
and commit the generated pages to your version control. On the other hand, if fully automatic reference documentation generation is preferred put the output folder of this module in your version control ignore file.template: str ['module']
Template name to use. This option can be changed to use different templates for different modules. See the section Using different templates.output: str [module]
Output folder to generate the documentation for this module relative to the folder where yourconf.py
is located. By default the output folder is the same as the module key. For example, formymodule
the following could be generated:. |-- conf.py `-- mymodule |-- mymodule.rst |-- mymodule.submodule.rst `-- mymodule.another.rst
For example, a custom configuration could be:
autoapi_modules = { 'mymodule': { 'override': False, 'output': 'auto' } }
Reference your documentation in your Sphinx project:
Add in one of your reST source files a reference to the documentation.
.. toctree:: :hidden: mymodule/mymodule
And, optionally, you can link to it like this:
See the :doc:`reference documentation <mymodule/mymodule>`.
Prepare your codebase:
Now in your modules, put all the elements you want to document in the
__all__
or the__api__
listings. See the section Documenting the code.
Documenting the code¶
The strict minimum:
- List all public objects in your
__all__
(preferred) or__api__
. - Put at least a docstring with a brief in your module, in all your public classes, methods, functions and variables.
Even better:
- Use the autodoc syntax in your docstrings (or use other that autodoc supports).
Use the following example as a guide. Check corresponding documentation produced by AutoAPI.
# -*- coding: utf-8 -*-
"""
This is my module brief line.
This is a more complete paragraph documenting my module.
- A list item.
- Another list item.
This section can use any reST syntax.
"""
A_CONSTANT = 1000
"""This is an important constant."""
YET_ANOTHER = {
'this': 'that',
'jam': 'eggs',
'yet': {
'things': [1, 2, 3, 'a'],
'tuples': (A_CONSTANT, 4)
}
}
"""Yet another public constant variable"""
def a_function(my_arg, another):
"""
This is the brief description of my function.
This is a more complete example of my function. It can include doctest,
code blocks or any other reST structure.
>>> a_function(10, [MyClass('a'), MyClass('b')])
20
:param int my_arg: The first argument of the function. Just a number.
:param another: The other argument of the important function.
:type another: A list of :class:`MyClass`
:return: The length of the second argument times the first argument.
:rtype: int
"""
return my_arg * len(another)
class MyClass(object):
"""
This is the brief of my main class.
A more general description of what the class does.
:param int param1: The first parameter of my class.
:param param2: The second one.
:type param2: int or float
:var my_attribute: Just an instance attribute.
:raises TypeError: if param2 is not None.
"""
class_attribute = 625
"""This is a class attribute."""
def __init__(self, param1, param2=None):
self.param1 = param1
if param2 is not None:
raise TypeError()
self.param2 = param2
self.my_attribute = 100
def my_method(self, param1, param2):
"""
The brief of this method.
This method does many many important things.
:param int param1: A parameter.
:param list param2: Another parameter.
:return: A list of the first parameter as long a the length of the
second parameter.
:rtype: list of int
"""
return [param1] * len(param2)
class AnotherClass(MyClass):
"""
This another class.
Check the nice inheritance diagram. See :class:`MyClass`.
"""
class MyException(Exception):
"""
This is my custom exception.
This is a more complete description of what my exception does. Again, you
can be as verbose as you want here.
"""
__all__ = [
'A_CONSTANT',
'YET_ANOTHER',
'a_function',
'MyClass',
'AnotherClass',
'MyException'
]
Customizing¶
AutoAPI provides several ways to customize the output generated by the tool. AutoAPI uses the Jinja2 template engine for page generation.
Overriding the default template¶
The default template used by autoapi
can be customized to meet your
needs. To do so, copy the default template and put it in your
templates_path
(usually _templates
) folder under:
<templates_path>/autoapi/module.rst
The next run Sphinx will use it for all your modules documentation generation.
Using different templates¶
Instead of providing a single template for all your modules you can also setup
different templates for different modules. For example, for you module
mymod
you choose to use the template mymodtemplate
. In your conf.py
the following is setup:
# autoapi configuration
autoapi_modules = {
'mymod': {'template': 'mymodtemplate'}
}
Now you need to place your template in:
<templates_path>/autoapi/mymodtemplate.rst
And AutoAPI will use it for documenting mymod
only.
Improvements¶
This is a list of possible improvements, its doesn’t mean they are good idea or that they should be implemented.
- Automatically hook the auto-generated files to the index document
toctree
. - Extend the
__api__
key to support a dictionary so each element that requires documentation can provide attributes individually (like show special members). - Generate an optional module index page with a different template (called index.rst at the module generation folder).
License¶
Copyright (C) 2015-2018 KuraLabs S.R.L
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.