Sample Sphinx project page¶
This project showcases a few things you can do with Sphinx.
For the complete documentation see the official Sphinx documentation.
For some interesting extensions see this list.
To run Sphinx, install it with pip: pip install sphinx.
On the commandline run sphinx-quickstart : This will prompt you to answer a couple of questions.
It will produce all the basic files you need to run Sphinx.
Run make html and open the HTML page (located in the build directory) in your browser.
firefox build/html/index.html
Sphinx uses the concept of directives and roles to create the various markup and functionality.
You can write your documents in either reStructured Text or Markdown (MyST parser).
Restructured Text
.. directive_name:: arguments
:option: value
Content here
For inline markup we use :role_name:`role content`
Markdown
```{directive_name} arguments
:option: value
Content here
```
For inline markup we use {role_name}`role content`
An image example¶
You can include figures and images. No extensions are needed.
Syntax:
.. figure:: _static/sloth.jpg
A baby sloth
Output:
A baby sloth¶
A math example¶
For math formulas, you can add the mathjax extension. In conf.py, add "sphinx.ext.mathjax" to
your list of extensions.
Write your math formulas in LaTeX and mathjax will render the HTML output
Syntax:
.. math::
\frac{dV_\text{m}}{dt} = -\frac{V_{\text{m}} - E_\text{L}}{\tau_{\text{m}}} + \\
\frac{I_{\text{syn}} + I_\text{e}}{C_{\text{m}}}
Output:
Syntax:
Roles are use for inline markup like in the case of :math:`x >= 10`
Output:
Roles are use for inline markup like in the case of \(x >= 10\)
An API example¶
If you have an API you would like to document you can use the autodoc and autosummary
extensions. In conf.py, add "sphinx.ext.autodoc" or "sphinx.ext.autosummary" to your list
of extensions, along with the path to your Python files.
Syntax:
.. automodule:: templating_example
:members:
Output:
- templating_example.setup(app)¶
Sets up the Sphinx extension by connecting the template_renderer function to the source-read event.
Parameters:
app (Sphinx): The Sphinx application object.
Returns:
dict: A dictionary containing the version and parallel processing information for the Sphinx extension.
- templating_example.template_renderer(app, docname, source)¶
Renders a Sphinx documentation page using a Jinja template with custom data.
This function is connected to the Sphinx source-read event and modifies the source content of a documentation page before it is rendered. It loads data from a JSON file and injects it into the context of the Jinja template, allowing for dynamic content generation.
Parameters:
app (Sphinx): The Sphinx application object.
docname (str): The name of the document currently being processed.
source (list): A list containing the source of the document as a single string.
Returns: None
Sphinx gallery example¶
You can generate HTML gallery from Python scripts with sphinx-gallery.
By providing the path to your examples in conf.py, sphinx-gallery will render the
script in reStructured Text, with an optionally executable Python script and Jupyter Notebook.
You can see an example here My first Python example.
Advanced¶
A custom role and directive¶
You can create your own extensions in Sphinx.
Here is the code in _ext/helloworld.py for creating a hello world custom directive and role.
See the Sphinx documentation for extending Sphinx
from __future__ import annotations
from docutils import nodes
from sphinx.application import Sphinx
from sphinx.util.docutils import SphinxDirective, SphinxRole
from sphinx.util.typing import ExtensionMetadata
class HelloRole(SphinxRole):
"""
A custom Sphinx role that outputs a greeting.
This class extends the SphinxRole class, which defines custom roles for Sphinx.
The main logic is implemented in the `run` method, which returns a tuple consisting of:
- A list of inline-level docutils nodes that represent the processed content.
- An optional list of system messages, which are typically used for warnings or errors.
Returns:
tuple: A tuple containing:
- list[nodes.Node]: A list of nodes to be processed, representing the inline content.
- list[nodes.system_message]: An optional list of system messages.
"""
def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
node = nodes.inline(text=f"Hello {self.text}!")
return [node], []
class HelloDirective(SphinxDirective):
"""
A custom Sphinx directive that outputs a greeting.
This class extends the SphinxDirective class and defines a custom directive that
generates a paragraph node with a greeting message.
Attributes:
required_arguments (int): Specifies the number of arguments the directive requires.
The main logic is implemented in the `run` method, which returns a list of block-level
docutils nodes that represent the processed content.
Returns:
list: A list of nodes to be processed, representing the block content.
"""
required_arguments = 1
def run(self) -> list[nodes.Node]:
paragraph_node = nodes.paragraph(text=f"hello {self.arguments[0]}!")
return [paragraph_node]
def setup(app: Sphinx) -> ExtensionMetadata:
"""
Set up the custom Sphinx extension by adding the new role and directive.
This function registers the custom role and directive with the Sphinx application,
allowing them to be used within Sphinx documents. This function is a requirement
for any Sphinx extension.
Args:
app (Sphinx): The Sphinx application object.
Returns:
ExtensionMetadata: Metadata about the extension, including version and parallel safety.
"""
app.add_role("hello", HelloRole())
app.add_directive("hello", HelloDirective)
return {
"version": "0.1",
"parallel_read_safe": True,
"parallel_write_safe": True,
}
Syntax:
My custom greeting:
.. hello:: world
This can also be done as a role in line like so :hello:`my baby`.
Output:
My custom greeting:
hello world!
This can also be done as a role in line like so Hello my baby!.
Jinja template in documentation¶
Say you have external dataset that you want to show in your documentation. We can use Jinja template syntax in our docs with a little Python code to render the data. Sphinx uses Jinja templates internally so it is not an external dependency. See this blog post from Eric Holscher (developer at Read the Docs and Write the Docs) for details.
We need a JSON formatted data set, and in this case we create a sample file in our _ext folder
called my_data.json.
[
{
"pet": "dog",
"breeds": ["shih tzu", "yorkiepoo", "newfoundland"]
},
{
"pet": "cat",
"breeds": ["cornish rex", "manx", "himalayan"]
},
{
"pet": "dinosaur",
"breeds": ["parakeet", "stegosaurus", "canary", "triceratops"]
}
]
We then need to write a script (_ext/templating_example.py). This script will connect the Jinja template provided
in the document with the dataset. The script is triggered at a specific event source-read during the Sphinx build process.
Make sure to add that script filename to our list of extensions in conf.py.
And ensure that the path to extensions is also in the conf.py
(e.g., sys.path.append(os.path.abspath("./_ext")).
from pathlib import Path
import json
def template_renderer(app, docname, source):
"""
Renders a Sphinx documentation page using a Jinja template with custom data.
This function is connected to the Sphinx `source-read` event and modifies the
source content of a documentation page before it is rendered. It loads data
from a JSON file and injects it into the context of the Jinja template, allowing
for dynamic content generation.
Parameters:
- app (Sphinx): The Sphinx application object.
- docname (str): The name of the document currently being processed.
- source (list): A list containing the source of the document as a single string.
Returns:
None
"""
if app.builder.format != "html":
return
with open(Path(__file__).parent / "my_data.json") as file:
my_data = json.load(file)
if docname == "sample_sphinx":
# Render the specified page using the Jinja template with custom data
html_context = {"pet_data": my_data}
src = source[0]
rendered = app.builder.templates.render_string(src, html_context)
source[0] = rendered
def setup(app):
"""
Sets up the Sphinx extension by connecting the `template_renderer` function
to the `source-read` event.
Parameters:
- app (Sphinx): The Sphinx application object.
Returns:
- dict: A dictionary containing the version and parallel processing information for the Sphinx extension.
"""
app.connect("source-read", template_renderer)
return {
"version": "0.1",
"parallel_read_safe": True,
"parallel_write_safe": True,
}
In our document (sample_sphinx.rst), we need to use Jinja template syntax to generate the desired output.
We want to display a subselection of the data as lists. Jinja is similar to Python, but has some differences. See the Jinja templating documentation for details.
Syntax:
{% for items in pet_data %}
{% if items.pet == "dog" %}
Show available dog breeds:
{% for item in items.breeds | sort %}
* {{ item }}
{% endfor %}
{% endif %}
{% if items.pet == "dinosaur" %}
Show available dinosaur breeds:
{% for item in items.breeds | sort %}
* {{ item }}
{% endfor %}
{% endif %}
{% endfor %}
Note
Note that the variable name “pet_data” must match the name given in html_context in the extension
script (templating_example.py)
Output:
Show available dog breeds:
newfoundland
shih tzu
yorkiepoo
Show available dinosaur breeds:
canary
parakeet
stegosaurus
triceratops
Deploy Sphinx on Pages¶
Here is an example CI workflow if you want to trigger a Sphinx build and deploy the output on GitHub or GitLab Pages.
Gitlab:
# The Docker image that will be used to build your app
# See details here: https://gitlab.com/pages/sphinx
---
image: python:3.11
# Functions that should be executed before the build script is run
before_script:
- pip install -r requirements.txt
pages:
script:
- sphinx-build -b html source public
artifacts:
paths:
# The folder that contains the files to be exposed at the Page URL
- public
rules:
# This ensures that only pushes to the default branch will trigger
# a pages deploy
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
GitHub:
# Using GitHub actions
# See details here:
# https://github.com/marketplace/actions/sphinx-to-github-pages
---
name: Deploy Sphinx documentation to Pages
on:
push:
branches: [master] # branch to trigger deployment
jobs:
pages:
runs-on: ubuntu-20.04
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
pages: write
id-token: write
steps:
- id: deployment
# See https://sphinx.silverrainz.me/pages/ for details
uses: sphinx-notes/pages@v3