Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: sphinx customisation #1165

Merged
merged 16 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

* Use "integrate with" rather than "relate to" (#1145)
* Updated code examples in the docstring of `ops.testing` from unittest to pytest style (#1157)
* Update Read the Docs Sphinx Furo theme to use Canonical's latest styling (#1163, #1164, #1165)

# 2.11.0 - 29 Feb 2024

Expand Down
27 changes: 27 additions & 0 deletions HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,33 @@ tox -e docs
open docs/_build/html/index.html
```

## How to Pull in Style Changes

The documentation uses Canonical styling which is customised on top of the [Furo Sphinx theme](https://github.com/pradyunsg/furo). The easiest way to pull in Canonical style changes is by using the Canonical documentation starter pack, see [docs](https://canonical-starter-pack.readthedocs-hosted.com/) and [repository](https://github.com/canonical/sphinx-docs-starter-pack).

TL;DR:

- Clone the starter pack repository to a local directory: `git clone git@github.com:canonical/sphinx-docs-starter-pack`.
- Copy the folder `.sphinx` under the starter pack repo to the operator repo `docs/.sphinx`.

## How to Customise Configurations

There are two configuration files: [`docs/conf.py`](./docs/conf.py) and [`docs/custom_conf.py`](./docs/custom_conf.py), copied and customised from the starter pack repo.

To customise, change the file [`docs/custom_conf.py`](./docs/custom_conf.py) only, and theoretically, we should not change [`docs/conf.py`](./docs/conf.py) (however, some changes are made to [`docs/conf.py`](./docs/conf.py), such as adding autodoc, PATH, fixing issues, etc.)

## How to Pull in Dependency Changes

The Canonical documentation starter pack uses Make to build the documentation, which will run the script [`docs/.sphinx/build_requirements.py`](./docs/.sphinx/build_requirements.py) and generate a requirement file `requirements.txt` under `docs/.sphinx/`.
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

To pull in new dependency changes from the starter pack, change to the starter pack repository directory, and build with the following command. This will create a virtual environment, generate a dependency file, install the software dependencies, and build the documentation:

```bash
make html
```

Then, compare the generated file `.sphinx/requirements.txt`and the `project.optional-dependencies.docs` section of [`pyproject.toml`](./pyproject.toml) and adjust the `pyproject.toml` file accordingly.

# Dependencies

The Python dependencies of `ops` are kept as minimal as possible, to avoid
Expand Down
7 changes: 1 addition & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ruff: noqa
import sys
import os

Expand Down Expand Up @@ -98,12 +99,6 @@
]
exclude_patterns.extend(custom_excludes)

rst_epilog = '''
.. include:: /reuse/links.txt
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved
'''
if 'custom_rst_epilog' in locals():
rst_epilog = custom_rst_epilog

source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
Expand Down
150 changes: 141 additions & 9 deletions docs/custom_conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
import datetime
# ruff: noqa
import datetime
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved
import pathlib
import sys

import furo
import furo.navigation

sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))

# Furo patch to get local TOC to show in sidebar (as sphinx-rtd-theme did)
# See https://github.com/pradyunsg/furo/blob/490527b2aef00b1198770c3389a1979911ee1fcb/src/furo/__init__.py#L115-L128

_old_compute_navigation_tree = furo._compute_navigation_tree


def _compute_navigation_tree(context):
tree_html = _old_compute_navigation_tree(context)
if not tree_html and context.get("toc"):
tree_html = furo.navigation.get_navigation_tree(context["toc"])
return tree_html


furo._compute_navigation_tree = _compute_navigation_tree

# Pull in fix from https://github.com/sphinx-doc/sphinx/pull/11222/files to fix
# "invalid signature for autoattribute ('ops.pebble::ServiceDict.backoff-delay')"
import re # noqa: E402
import sphinx.ext.autodoc # noqa: E402
sphinx.ext.autodoc.py_ext_sig_re = re.compile(
r'''^ ([\w.]+::)? # explicit module name
([\w.]+\.)? # module and/or class name(s)
([^.()]+) \s* # thing name
(?: \((.*)\) # optional: arguments
(?:\s* -> \s* (.*))? # return annotation
)? $ # and nothing more
''', re.VERBOSE)

# Custom configuration for the Sphinx documentation builder.
# All configuration specific to your project should be done in this file.
Expand All @@ -19,8 +55,8 @@
############################################################

# Product name
project = 'Documentation starter pack'
author = 'Canonical Group Ltd'
project = 'The ops library'
author = 'Canonical Ltd.'

# The title you want to display for the documentation in the sidebar.
# You might want to include a version number here.
Expand Down Expand Up @@ -67,7 +103,7 @@
# For example: "ubuntu.com/lxd" or "microcloud.is"
# If there is no product website, edit the header template to remove the
# link (see the readme for instructions).
'product_page': 'documentation.ubuntu.com',
'product_page': 'juju.is/docs/sdk',

# Add your product tag (the orange part of your logo, will be used in the
# header) to ".sphinx/_static" and change the path here (start with "_static")
Expand All @@ -77,21 +113,25 @@
# Change to the discourse instance you want to be able to link to
# using the :discourse: metadata at the top of a file
# (use an empty value if you don't want to link)
'discourse': 'https://discourse.ubuntu.com',
'discourse': 'https://discourse.charmhub.io/',

# Change to the Mattermost channel you want to link to
# (use an empty value if you don't want to link)
'mattermost': 'https://chat.canonical.com/canonical/channels/documentation',
'mattermost': '',

# Change to the Matrix channel you want to link to
# (use an empty value if you don't want to link)
'matrix': 'https://matrix.to/#/#charmhub-charmdev:ubuntu.com',

# Change to the GitHub URL for your project
'github_url': 'https://github.com/canonical/starter-pack',
'github_url': 'https://github.com/canonical/operator',

# Change to the branch for this version of the documentation
'github_version': 'main',

# Change to the folder that contains the documentation
# (usually "/" or "/docs/")
'github_folder': '/',
'github_folder': '/docs/',

# Change to an empty value if your GitHub repo doesn't have issues enabled.
# This will disable the feedback button and the issue link in the footer.
Expand Down Expand Up @@ -151,7 +191,12 @@
'canonical.related-links',
'canonical.custom-rst-roles',
'canonical.terminal-output',
'notfound.extension'
'notfound.extension',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
]

# Add custom required Python modules that must be added to the
Expand Down Expand Up @@ -200,3 +245,90 @@
.. role:: center
:class: align-center
'''


# -- Options for sphinx.ext.todo ---------------------------------------------

IronCore864 marked this conversation as resolved.
Show resolved Hide resolved
# If this is True, todo and todolist produce output, else they
# produce nothing. The default is False.
todo_include_todos = False


# -- Options for sphinx.ext.autodoc ------------------------------------------

# This value controls how to represents typehints. The setting takes the
# following values:
# 'signature' – Show typehints as its signature (default)
# 'description' – Show typehints as content of function or method
# 'none' – Do not show typehints
autodoc_typehints = 'signature'

# This value selects what content will be inserted into the main body of an
# autoclass directive. The possible values are:
# 'class' - Only the class’ docstring is inserted. This is the
# default. You can still document __init__ as a separate method
# using automethod or the members option to autoclass.
# 'both' - Both the class’ and the __init__ method’s docstring are
# concatenated and inserted.
# 'init' - Only the __init__ method’s docstring is inserted.
autoclass_content = 'class'

# This value selects if automatically documented members are sorted
# alphabetical (value 'alphabetical'), by member type (value
# 'groupwise') or by source order (value 'bysource'). The default is
# alphabetical.
autodoc_member_order = 'alphabetical'

autodoc_default_options = {
'members': None, # None here means "yes"
'undoc-members': None,
'show-inheritance': None,
}

# -- Options for sphinx.ext.intersphinx --------------------------------------

# This config value contains the locations and names of other projects
# that should be linked to in this documentation.
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}

# -- General configuration ---------------------------------------------------

# If true, Sphinx will warn about all references where the target
# cannot be found.
nitpicky = True

# A list of (type, target) tuples (by default empty) that should be ignored when
# generating warnings in “nitpicky mode”. Note that type should include the
# domain name if present. Example entries would be ('py:func', 'int') or
# ('envvar', 'LD_LIBRARY_PATH').
nitpick_ignore = [
# Please keep this list sorted alphabetically.
('py:class', '_ChangeDict'),
('py:class', '_CheckInfoDict'),
('py:class', '_FileInfoDict'),
('py:class', '_NoticeDict'),
('py:class', '_ProgressDict'),
('py:class', '_Readable'),
('py:class', '_RelationMetaDict'),
('py:class', '_ResourceMetaDict'),
('py:class', '_StorageMetaDict'),
('py:class', '_TaskDict'),
('py:class', '_TextOrBinaryIO'),
('py:class', '_WarningDict'),
('py:class', '_Writeable'),
('py:class', 'ops.charm._ContainerBaseDict'),
('py:class', 'ops.model._AddressDict'),
('py:class', 'ops.model._ConfigOption'),
('py:class', 'ops.model._ModelBackend'),
('py:class', 'ops.model._ModelCache'),
('py:class', 'ops.model._NetworkDict'),
('py:class', 'ops.pebble._FileLikeIO'),
('py:class', 'ops.pebble._IOSource'),
('py:class', 'ops.pebble._ServiceInfoDict'),
('py:class', 'ops.pebble._SystemInfoDict'),
('py:class', 'ops.pebble._WebSocket'),
('py:class', 'ops.storage.JujuStorage'),
('py:class', 'ops.storage.SQLiteStorage'),
('py:class', 'ops.testing.CharmType'),
('py:obj', 'ops.testing.CharmType'),
]
Loading
Loading