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 6 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
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 [here](https://canonical-starter-pack.readthedocs-hosted.com/) and repository [here](https://github.com/canonical/sphinx-docs-starter-pack).
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

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, check out the generated file `.sphinx/requirements.txt`, and make changes to [`pyproject.toml`](./pyproject.toml) accordingly.
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

# Dependencies

The Python dependencies of `ops` are kept as minimal as possible, to avoid
Expand Down
21 changes: 13 additions & 8 deletions docs/.sphinx/_static/furo_colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ body {
--color-foreground-secondary: var(--color-foreground-primary);
--color-foreground-muted: #333;
--color-background-secondary: #FFF;
--color-background-hover: #f2f2f2;
--color-background-hover: #CDCDCD;
--color-brand-primary: #111;
--color-brand-content: #06C;
--color-api-background: #cdcdcd;
--color-api-background: #f2f2f2;
--color-api-background-hover: #cdcdcd;
--color-inline-code-background: rgba(0,0,0,.03);
--color-sidebar-link-text: #111;
--color-sidebar-item-background--current: #ebebeb;
Expand All @@ -26,8 +27,8 @@ body {
--color-admonition-title--important: #C7162B;
--color-admonition-title--caution: #F99B11;
--color-highlighted-background: #EBEBEB;
--color-link-underline: var(--color-background-primary);
--color-link-underline--hover: var(--color-background-primary);
--color-link-underline: var(--color-link);
--color-link-underline--hover: var(--color-link);
--color-version-popup: #772953;
}

Expand All @@ -41,6 +42,8 @@ body {
--color-background-hover: #666;
--color-brand-primary: #fff;
--color-brand-content: #06C;
--color-api-background: #333;
--color-api-background-hover: #666;
--color-sidebar-link-text: #f7f7f7;
--color-sidebar-item-background--current: #666;
--color-sidebar-item-background--hover: #333;
Expand All @@ -54,8 +57,8 @@ body {
--color-admonition-title--important: #C7162B;
--color-admonition-title--caution: #F99B11;
--color-highlighted-background: #666;
--color-link-underline: var(--color-background-primary);
--color-link-underline--hover: var(--color-background-primary);
--color-link-underline: var(--color-link);
--color-link-underline--hover: var(--color-link);
--color-version-popup: #F29879;
}
@media (prefers-color-scheme: dark) {
Expand All @@ -68,6 +71,8 @@ body {
--color-background-hover: #666;
--color-brand-primary: #fff;
--color-brand-content: #06C;
--color-api-background: #333;
--color-api-background-hover: #666;
--color-sidebar-link-text: #f7f7f7;
--color-sidebar-item-background--current: #666;
--color-sidebar-item-background--hover: #333;
Expand All @@ -81,8 +86,8 @@ body {
--color-admonition-title--important: #C7162B;
--color-admonition-title--caution: #F99B11;
--color-highlighted-background: #666;
--color-link-underline: var(--color-background-primary);
--color-link-underline--hover: var(--color-background-primary);
--color-link-underline: var(--color-link);
--color-link-underline--hover: var(--color-link);
--color-version-popup: #F29879;
}
}
Expand Down
49 changes: 38 additions & 11 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
import sys
import os
import pathlib
import sys

import furo
import furo.navigation

sys.path.append('./')
from custom_conf import *
sys.path.append('.sphinx/')
from build_requirements import *
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

IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

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)

# Configuration file for the Sphinx documentation builder.
# You should not do any modifications to this file. Put your custom
Expand Down Expand Up @@ -50,7 +83,7 @@
### Configuration for extensions

# Used for related links
if not 'discourse_prefix' in html_context and 'discourse' in html_context:
if 'discourse_prefix' not in html_context and 'discourse' in html_context:
html_context['discourse_prefix'] = html_context['discourse'] + '/t/'
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

# The URL prefix for the notfound extension depends on whether the documentation uses versions.
Expand All @@ -70,7 +103,7 @@

# Set notfound_urls_prefix to the slug (if defined) and the version/language affix
if slug:
notfound_urls_prefix = '/' + slug + '/' + url_lang + url_version
notfound_urls_prefix = '/' + slug + '/' + url_lang + url_version
elif len(url_lang + url_version) > 0:
notfound_urls_prefix = '/' + url_lang + url_version
else:
Expand All @@ -83,7 +116,7 @@

# Default image for OGP (to prevent font errors, see
# https://github.com/canonical/sphinx-docs-starter-pack/pull/54 )
if not 'ogp_image' in locals():
if 'ogp_image' not in locals():
ogp_image = 'https://assets.ubuntu.com/v1/253da317-image-document-ubuntudocs.svg'

############################################################
Expand All @@ -98,18 +131,12 @@
]
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',
}

if not 'conf_py_path' in html_context and 'github_folder' in html_context:
if 'conf_py_path' not in html_context and 'github_folder' in html_context:
html_context['conf_py_path'] = html_context['github_folder']

# For ignoring specific links
Expand Down
157 changes: 148 additions & 9 deletions docs/custom_conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
# ruff: noqa
import datetime
IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

# Custom configuration for the Sphinx documentation builder.
# All configuration specific to your project should be done in this file.
Expand All @@ -19,8 +20,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 +68,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 +78,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 +156,13 @@
'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 +211,131 @@
.. 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,
}


# -- 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'),
]


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

# 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,
}

IronCore864 marked this conversation as resolved.
Show resolved Hide resolved

# -- 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)}
Loading
Loading