With Sphinx is easy to generate documentation of your python project, as long as you don't require some custom code. This is a tutorial of how to create a quick & dirty Sphinx extension to personalize the docs of your project.
In our open-source project, Devicehub, we have some Schemas that configures our API (like a User schema), and we want to generate documentation for those. The documentation takes variables from the schemas and prints them nicely. This is the code, this is where our extension is called in a .rst file, and this is the outcome.
In this tutorial we use our extension as an example of a simple Sphinx custom extension. We assume you already know the basics of Sphinx and reStructured text.
A minimalist Sphinx extension requires two things:
- A class that extends from
docutils.parsers.rst.Directive
that has our code. - A function called
setup
that manually adds our class to Sphinx.
Both things can be in our project's sphinx'sconf.py
. If you check our
code, you see our class
and our setup function.
Readthis Sphinx page that explains this class and setup function
and then come back here :-). The following sections explore parts not covered by the sphinx's
tutorial.
Extension class skeleton and arguments
Our extension has only one parameter (called too "argument"): a string with the path where our Schema is, and we want our extension to print some variables of the schema and its subschemas.
The first portion of our extension class is about configurations of our directive, passed-in as
class variables (here you have
the full list of configurations
of the directive). Leave has_content
as False
.option_spec
is a dictionary of the parameters of
your directive and their type. Sphinx coerces the type for each argument, and the safest one to use
isdirectives.unchanged
, which returns the argument as a string, just as the user writes it. In
our case we define a parameter called module, and the user has to write it like this in a .rst
file:
And our directive gets the value "ereuse_devicehub.resources.device.schemas"
inself.options['module']
:
run
is the main method of our extension. It is executed every time the user writes ..dhlist::
in
a_.rst_ file. In our case we use the string of self.options['module']
as a path to import the
Schema is referencing at.
Docutil's elements
The objective of our extension is to return_something_ to Sphinx so that it can translate it to HTML or to a PDF file. This something is a list of Docutil's element, and they define a link, a bullet list, a section of a document, etc. Here you have the reference docs. In fact, when reading a_rst_ file, we can think that Sphinx parses the rst syntax into Docutil's elements, and then tranforms them to HTML, PDF...
So, we have that a_section_ element in_rst_is the same as the Docutil's_section_ element.
Element hierarchy
These elements have a strong hierarchy that you always have to have in mind when using them, otherwise it fails:
In our extension we return a list of section
elements, as we create full blocks of content. If we
do something like this in our .rst file:
Note that the header Schema is a subsection (HTML's <h2>
), our module is inserted inside Schema's
subsection, so our module ends up being a subsubsection (HTML's <h3>
), which means that our
module plays nice with the rest of content.
In the following sections we learn how to use docutil's elements by showing the ones that appear in our project.
Base: section, title, link
The following example of run
returns a list of elements (which is what Sphinx expects). There is
only one element, asection
.
The section can have an id, which is the anchor used in HTML/PDF for linking. In this case we add a
title (we need to add its value twice for some strange reason), and any other element that we want
inside the section (note the section += ...
)
The following code shows ho to generate the hyperlink that takes you to the section (this generates
the <a>
HTML tag, for example):
Lists (bullet points)
Fields
Parse rst strings to docutil's elements
In our project we end up reading string variables with rst syntax. The following code allows us to transform those strings into docutil's elements that we can add, for example, in our sections(check the source code here):
Further info
The following tutorials can help you dive deeper into Sphinx extension development: