How to Write a Book with Python and Sphinx

Photo by Theme Inn on Unsplash

Want to write a technical book or document your project?

Here I'll walk you through how you can do that with python and sphinx. You can build content of tables that can contain sections to the chapters of your book. I will show you a case study to know how to insert images, hyperlinks, mathematical formulas, syntax highlighting for your favorite programming languages, and more.

Assuming you have some basic knowledge of python, let's dive in and see what sphinx can do for us.

What is Sphinx?

Sphinx is a documentation generator library which can be useful to generate documentation for your project and can also be used for creating a content (e.g. a book) in a LaTeX and then can be converted to PDF format.

Sphinx Installation

Whether you use macOS, Linux, or Windows you can install it with this command:

 pip install -U sphinx 

or you can refer to sphinx doc if you want more options.

Sphinx Quickstart

Let's first make sure sphinx is installed by showing its version:

 sphinx-quickstart --version 

If we have the version number, we're good to go and make our project directory that should contain the documentation that we want:

mkdir sphinx-tutorial && cd sphinx-tutorial

Now, a bunch of files will be generated by sphinx's side including a makefile .. we need to separate the other files into source directory and build directory. The source dir contains the configurations of our project while the build dir contains nothing now but when we build our project we should see the rendered documentation built there.

Sphinx Configuration

Let's see the configurations we've done so far by opening in the source directory:

You can change any of the variables in the configuration file but let's stick to the project information for now that you can change in this file or at the beginning when we did the sphinx-quickstart command.

Building Sphinx

Let's build the documentation and see what we can get in the build directory and what our sphinx quickstart boilerplate look like in the web

sphinx-build source/ build/

And here is the output at the command line:

Running Sphinx v3.2.1
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 1 source files that are out of date
updating environment: [new config] 1 added, 0 changed, 0 removed
reading sources... [100%] index                                                                                                                               
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] index                                                                                                                                
generating indices...  genindexdone
writing additional pages...  searchdone
copying static files... ... done
copying extra files... done
dumping search index in English (code: en)... done
dumping object inventory... done
build succeeded.

The HTML pages are in build.

So the second argument of sphinx-build is the source directory which contains and index.rst and the third argument is the build directory which should contain the exported files and folders. Let's explore what's in the build dir now:

├── build
│   ├── _sources
│   │   └── index.rst.txt
│   ├── _static
│   │   ├── alabaster.css
│   │   ├── basic.css
│   │   ├── custom.css
│   │   ├── doctools.js
│   │   ├── documentation_options.js
│   │   ├── file.png
│   │   ├── jquery-3.5.1.js
│   │   ├── jquery.js
│   │   ├── language_data.js
│   │   ├── minus.png
│   │   ├── plus.png
│   │   ├── pygments.css
│   │   ├── searchtools.js
│   │   ├── underscore-1.3.1.js
│   │   └── underscore.js
│   ├── genindex.html
│   ├── index.html
│   ├── objects.inv
│   ├── search.html
│   └── searchindex.js

It has two directories and some files in its own path, let's focus now on index.html because this is the rendered HTML file that you can see on the web showing the quickstart document. How can we see it? by simply copying its path and then pasting it on the URL.

Or you can do it through the terminal; a command and then the path to that index file

For macOS users:

open build/index.html

For Linux users:

xdg-open build/index.html

For Windows users:

start build/index.html

This is what you can see on the web (locally):

sphinx quickstart webpage

As you can see, the URL is the full path of my index file residing locally locally. Let's see how we can edit the content of this webpage and what textual language we can use for that.

Editing reStructuredText

reStructuredText is a markup language designed to be simple and unobtrusive. It uses consistent patterns interpreted by an HTML converter to produce 'Very Structured Text' that can be used by a web browser. Its format is .rst

Let's edit the main file index.rst which exists in the source directory

.. myproject documentation master file, created by
   sphinx-quickstart on Sat Aug 29 14:31:34 2020.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to myproject's documentation!

.. toctree::
   :maxdepth: 2
   :caption: Contents:

Indices and tables

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

Let's say, I'd like to keep the Search Page titles and get rid of the Index and Module Index titles. We can do so by deleting these two lines: 

* :ref:`genindex`
* :ref:`modindex`

Let's build again and see what if that solved our problem:

sphinx-build source/ build/

Looks like it did

sphinx documentation without indexes

Let's say, we'd like to replicate what's  in my previous watermelon problem solving blog post and do it using reStructuredText. How can we make a hyperlink and how to construct the small headers and at the end we want to write the python and javascript code with a syntax highlighter. Let's do it

First, we should make rst know that there is a folder that can contain such blog post and is considered in the table of contents. In the index.rst we realize there is a structure for the table of contents starting with toctree which is a sphinx directive meaning it can add relations between the single files the document is made of. In our case, we want to add a file called codeforces which contains the watermelon blog post:

.. toctree::
   :maxdepth: 2
   :caption: Contents:


But where is the codeforces file? It should exist in the source directory (at the same level of the main RST file) so now the source directory tree should look like this:

└── source
    ├── _static
    ├── _templates
    ├── codeforces.rst
    └── index.rst

Rendering Math Equations

If you happen to see happy number, a medium leetcode problem that I put on my blog .. you'll see it has some mathematical formulas there -- simple ones .. let's see how we can render math equations in reStructuredText.

First we need to let the configuration file know that we want to put some math there and that's in the by enable MathJax in Sphinx which allow us to write LaTeX. In order to do that, we will add this sphinx.ext.mathjax to the list of extensions

extensions = ['sphinx.ext.mathjax']

We'd like to add leetcode in the contents after codeforces, so we should add that in the index.rst so this file now looks like

.. myproject documentation master file, created by
   sphinx-quickstart on Sat Aug 29 14:31:34 2020.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to myproject's documentation!

.. toctree::
   :maxdepth: 2
   :caption: Contents:


Indices and tables

* :ref:`search`

Adding leetcode RST script you can see the raw script from clicking raw at the bottom:

Now we can see that we can write mathematical formulas, code-blocks, and more

sphinx documentation with mathematical formulas and code-blocks

Converting reStructuredText to PDF

At some point, we would like to convert that RST documentation into PDF. Before we build, we need to configure that in the extension so we add rst2pdf.pdfbuilder so now the extension list look like this:

extensions = ['sphinx.ext.mathjax', 'rst2pdf.pdfbuilder']

One thing then you need to change is the builder type by the option -b in sphinx-build command line

sphinx-build -b pdf source/ build/

you'll see an error because it's not installed yet, do so with pip and then try again

pip install rst2pdf


Now, you can use python and sphinx to build a documentation for your project with table of contents and you can use hyperlinks, headings, images, mathematical formulas, syntax highlighting for whatever programming languages you like, and more.

And not just a documentation, you can also write a technical book.

Thank you for reaching here!