2019-02-08 10:51:06 -06:00
|
|
|
|
Developing a "Hello world" extension
|
2018-11-28 10:27:22 -06:00
|
|
|
|
====================================
|
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
The objective of this tutorial is to create a very basic extension that adds a
|
2019-02-11 04:44:49 -06:00
|
|
|
|
new directive. This directive will output a paragraph containing "hello world".
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Only basic information is provided in this tutorial. For more information, refer
|
|
|
|
|
to the :doc:`other tutorials <index>` that go into more details.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. warning::
|
2019-02-11 04:44:49 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
For this extension, you will need some basic understanding of docutils_
|
2018-11-28 10:27:22 -06:00
|
|
|
|
and Python.
|
|
|
|
|
|
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Overview
|
|
|
|
|
--------
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
We want the extension to add the following to Sphinx:
|
|
|
|
|
|
2019-02-11 04:44:49 -06:00
|
|
|
|
* A ``helloworld`` directive, that will simply output the text "hello world".
|
2019-02-08 10:51:06 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Prerequisites
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
We will not be distributing this plugin via `PyPI`_ and will instead include it
|
|
|
|
|
as part of an existing project. This means you will need to use an existing
|
|
|
|
|
project or create a new one using :program:`sphinx-quickstart`.
|
|
|
|
|
|
|
|
|
|
We assume you are using separate source (:file:`source`) and build
|
|
|
|
|
(:file:`build`) folders. Your extension file could be in any folder of your
|
|
|
|
|
project. In our case, let's do the following:
|
|
|
|
|
|
|
|
|
|
#. Create an :file:`_ext` folder in :file:`source`
|
2018-11-28 10:27:22 -06:00
|
|
|
|
#. Create a new Python file in the :file:`_ext` folder called
|
2019-02-08 10:51:06 -06:00
|
|
|
|
:file:`helloworld.py`
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Here is an example of the folder structure you might obtain:
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. code-block:: text
|
|
|
|
|
|
|
|
|
|
└── source
|
|
|
|
|
├── _ext
|
|
|
|
|
│ └── helloworld.py
|
|
|
|
|
├── _static
|
|
|
|
|
├── conf.py
|
|
|
|
|
├── somefolder
|
|
|
|
|
├── index.rst
|
|
|
|
|
├── somefile.rst
|
|
|
|
|
└── someotherfile.rst
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Writing the extension
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
Open :file:`helloworld.py` and paste the following code in it:
|
|
|
|
|
|
2019-02-08 11:03:09 -06:00
|
|
|
|
.. literalinclude:: examples/helloworld.py
|
|
|
|
|
:language: python
|
|
|
|
|
:linenos:
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Some essential things are happening in this example, and you will see them for
|
|
|
|
|
all directives.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. rubric:: The directive class
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Our new directive is declared in the ``HelloWorld`` class.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 11:03:09 -06:00
|
|
|
|
.. literalinclude:: examples/helloworld.py
|
|
|
|
|
:language: python
|
|
|
|
|
:linenos:
|
|
|
|
|
:lines: 5-9
|
2018-12-19 09:45:15 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
This class extends the docutils_' ``Directive`` class. All extensions that
|
|
|
|
|
create directives should extend this class.
|
|
|
|
|
|
|
|
|
|
.. seealso::
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
`The docutils documentation on creating directives <docutils directives>`_
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
This class contains a ``run`` method. This method is a requirement and it is
|
|
|
|
|
part of every directive. It contains the main logic of the directive and it
|
|
|
|
|
returns a list of docutils nodes to be processed by Sphinx. These nodes are
|
|
|
|
|
docutils' way of representing the content of a document. There are many types of
|
|
|
|
|
nodes available: text, paragraph, reference, table, etc.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2018-12-19 10:33:22 -06:00
|
|
|
|
.. seealso::
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2018-12-22 04:13:35 -06:00
|
|
|
|
`The docutils documentation on nodes <docutils nodes>`_
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2018-12-19 10:33:22 -06:00
|
|
|
|
The ``nodes.paragraph`` class creates a new paragraph node. A paragraph
|
2018-11-28 10:27:22 -06:00
|
|
|
|
node typically contains some text that we can set during instantiation using
|
|
|
|
|
the ``text`` parameter.
|
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. rubric:: The ``setup`` function
|
|
|
|
|
|
|
|
|
|
.. currentmodule:: sphinx.application
|
2018-12-19 10:33:22 -06:00
|
|
|
|
|
|
|
|
|
This function is a requirement. We use it to plug our new directive into
|
|
|
|
|
Sphinx.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 11:03:09 -06:00
|
|
|
|
.. literalinclude:: examples/helloworld.py
|
|
|
|
|
:language: python
|
|
|
|
|
:linenos:
|
|
|
|
|
:lines: 12-
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-11 04:44:49 -06:00
|
|
|
|
The simplest thing you can do it call the :meth:`~Sphinx.add_directive` method,
|
|
|
|
|
which is what we've done here. For this particular call, the first argument is
|
|
|
|
|
the name of the directive itself as used in a reST file. In this case, we would
|
|
|
|
|
use ``helloworld``. For example:
|
2018-12-19 10:33:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. code-block:: rst
|
2018-12-19 10:33:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Some intro text here...
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. helloworld::
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Some more text here...
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-11 04:44:49 -06:00
|
|
|
|
We also return the :ref:`extension metadata <ext-metadata>` that indicates the
|
|
|
|
|
version of our extension, along with the fact that it is safe to use the
|
|
|
|
|
extension for both parallel reading and writing.
|
|
|
|
|
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Using the extension
|
|
|
|
|
-------------------
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
The extension has to be declared in your :file:`conf.py` file to make Sphinx
|
|
|
|
|
aware of it. There are two steps necessary here:
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
#. Add the :file:`_ext` directory to the `Python path`_ using
|
|
|
|
|
``sys.path.append``. This should be placed at the top of the file.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
#. Update or create the :confval:`extensions` list and add the extension file
|
|
|
|
|
name to the list
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
For example:
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. code-block:: python
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
import os
|
|
|
|
|
import sys
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
sys.path.append(os.path.abspath("./_ext"))
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
extensions = ['helloworld']
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. tip::
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
We're not distributing this extension as a `Python package`_, we need to
|
|
|
|
|
modify the `Python path`_ so Sphinx can find our extension. This is why we
|
|
|
|
|
need the call to ``sys.path.append``.
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
You can now use the extension in a file. For example:
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. code-block:: rst
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Some intro text here...
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. helloworld::
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
Some more text here...
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
The sample above would generate:
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. code-block:: text
|
|
|
|
|
|
|
|
|
|
Some intro text here...
|
|
|
|
|
|
|
|
|
|
Hello World!
|
|
|
|
|
|
|
|
|
|
Some more text here...
|
2018-11-28 10:27:22 -06:00
|
|
|
|
|
|
|
|
|
|
2018-12-19 10:33:22 -06:00
|
|
|
|
Further reading
|
|
|
|
|
---------------
|
|
|
|
|
|
2019-02-08 10:51:06 -06:00
|
|
|
|
This is the very basic principle of an extension that creates a new directive.
|
|
|
|
|
|
|
|
|
|
For a more advanced example, refer to :doc:`todo`.
|
|
|
|
|
|
2018-12-19 10:33:22 -06:00
|
|
|
|
|
2018-11-28 10:27:22 -06:00
|
|
|
|
.. _docutils: http://docutils.sourceforge.net/
|
2019-02-08 10:51:06 -06:00
|
|
|
|
.. _docutils directives: http://docutils.sourceforge.net/docs/howto/rst-directives.html
|
|
|
|
|
.. _docutils nodes: http://docutils.sourceforge.net/docs/ref/doctree.html
|
|
|
|
|
.. _PyPI: https://pypi.org/
|
|
|
|
|
.. _Python package: https://packaging.python.org/
|
|
|
|
|
.. _Python path: https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH
|