Skip to content

Commit

Permalink
Merge pull request #135 from lsst-sqre/tickets/DM-36190
Browse files Browse the repository at this point in the history
DM-36190: Enable additional features and configurations for user guides
  • Loading branch information
jonathansick authored Sep 13, 2022
2 parents ca75c83 + 154eca3 commit 914adca
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 13 deletions.
6 changes: 2 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from documenteer.conf.guide import *
# See the documenteer.toml for overrides of the Rubin user guide presets

# Automodapi
# https://sphinx-automodapi.readthedocs.io/en/latest/automodapi.html
automodapi_toctreedirnm = "dev/api/contents"
from documenteer.conf.guide import *
2 changes: 2 additions & 0 deletions docs/documenteer.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extensions = [
"sphinx_click.ext",
"sphinxcontrib.autoprogram",
]
disable_primary_sidebars = ["index", "changelog"]
rst_epilog_file = "_rst_epilog.rst"
nitpicky = true
nitpick_ignore = [
Expand All @@ -22,6 +23,7 @@ nitpick_ignore_regex = [
['py:.*', 'docutils.*'],
['py:.*', 'pydantic.*'],
]
python_api_dir = "dev/api/contents"

[sphinx.intersphinx.projects]
python = "https://docs.python.org/3/"
Expand Down
80 changes: 80 additions & 0 deletions docs/project-guides/guides/toml-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ When set, a link to the repository is included in the site's header.
[project]
github_url = "https://github.com/lsst-sqre/documenteer"
.. _guide-project-github-default-branch:

github_default_branch
---------------------

|optional|

The default branch on GitHub.
Default is ``main``.
Used in conjunction with the "Edit on GitHub" link, see :ref:`sphinx.show_github_edit_link <guide-project-show-github-edit-link>`.

.. _guide-project-version:

version
Expand Down Expand Up @@ -131,6 +142,29 @@ If your GitHub repository's URL is associated with a different field label, set

This ``[sphinx]`` table allows you to set a number of Sphinx configurations that you would normally set through the :file:`conf.py` file.

disable_primary_sidebars
------------------------

|optional|

On some pages the default sidebar (on the left) is inappropriate, such as index pages that already contain a table of contents as their main content.
In that case, you can set individual pages or globs (without extensions) of pages that are shown without
the primary sidebar.
The default is ``["index"]`` to remove the sidebar from the homepage.

.. code-block:: toml
[sphinx]
disable_primary_sidebars = [
"**/index",
"changelog"
]
.. note::

This configuration is for the **primary** sidebar, on the left side, containing side or section-level navigation links.
To remove the page-level contents sidebar, on the right side, add ``:html_theme.sidebar_secondary.remove:`` to the *page's* file metadata.

extensions
----------

Expand Down Expand Up @@ -227,6 +261,52 @@ If set, the file is also included in the Sphinx source ignore list to prevent it
.. |required| replace:: :bdg-primary-line:`Required`
.. |optional| replace:: :bdg-secondary-line:`Optional`
python_api_dir
--------------

|optional|

Set this to the directory where Python API documentation is generated, through automodapi_.
The default value is ``api``, which is a good standard for Python projects with a public API.

If the Python API is oriented towards contributors, such as in an application or service, you can change the default:

.. code-block:: toml
[sphinx]
python_api_dir = "dev/api/contents"
[sphinx.theme]
==============

|optional|

Configurations related to the Sphinx HTML theme.

header_links_before_dropdown
----------------------------

|optional|

Number of links to show in the navigation head before folding extra items into a "More" dropdown.
The default is 5.

If the section titles are long you may need to reduce this number.

.. _guide-project-show-github-edit-link:

show_github_edit_link
---------------------

|optional|

Default is ``true``, so that each page contains a link to edit its source on GitHub.

This configuration requires information about the GitHub repository from these other configurations:

- :ref:`project.github_url <guide-project-github-url>`
- :ref:`project.github_default_branch <guide-project-github-default-branch>`

[sphinx.intersphinx]
====================

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ guide = [
"pydata-sphinx-theme>=0.10.0",
"sphinx-autodoc-typehints",
"sphinx-automodapi",
"sphinx-copybutton",
"sphinx-prompt",
"myst-parser",
"markdown-it-py[linkify]",
Expand Down
130 changes: 129 additions & 1 deletion src/documenteer/conf/_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@
import sys
from dataclasses import dataclass
from email.message import Message
from typing import Dict, List, MutableMapping, Optional, Tuple, Union, cast
from typing import (
Any,
Dict,
List,
MutableMapping,
Optional,
Tuple,
Union,
cast,
)
from urllib.parse import urlparse

if sys.version_info < (3, 8):
from importlib_metadata import PackageNotFoundError, metadata
Expand All @@ -33,6 +43,8 @@
)
from sphinx.errors import ConfigError

from ._utils import GitRepository

__all__ = ["ProjectModel", "ConfigRoot", "DocumenteerConfig"]


Expand Down Expand Up @@ -95,6 +107,11 @@ class ProjectModel(BaseModel):
description="The URL of the project's GitHub repository."
)

github_default_branch: str = Field(
"main",
description="The project's default development branch on GitHub.",
)

version: Optional[str] = Field(description="Version string.")

python: Optional[PythonPackageModel]
Expand All @@ -117,6 +134,22 @@ class LinkCheckModel(BaseModel):
)


class ThemeModel(BaseModel):
"""Model for theme configurations in documenteer.toml."""

show_github_edit_link: bool = Field(
True, description="Show a link to edit on GitHub if True"
)

header_links_before_dropdown: int = Field(
5,
description=(
"Number of links in the header nav before showing a 'More' "
"dropdown."
),
)


class SphinxModel(BaseModel):
"""Model for Sphinx configurations in documenteer.toml."""

Expand Down Expand Up @@ -152,6 +185,25 @@ class SphinxModel(BaseModel):
default_factory=list,
)

disable_primary_sidebars: Optional[List[str]] = Field(
None,
description=(
"Pages that should not have a primary sidebar. Can be the page's "
"path (without extension) or a glob of pages. By default the "
"homepage and change logs do not have a primary sidebar."
),
)

python_api_dir: Optional[str] = Field(
None,
description=(
"Directory path where the Python API reference documentation "
"is created."
),
)

theme: ThemeModel = Field(default_factory=lambda: ThemeModel())

intersphinx: Optional[IntersphinxModel]

linkcheck: Optional[LinkCheckModel]
Expand Down Expand Up @@ -353,3 +405,79 @@ def nitpicky(self) -> bool:
return self.conf.sphinx.nitpicky
else:
return False

def disable_primary_sidebars(
self, html_sidebars: MutableMapping[str, List[str]]
) -> None:
if self.conf.sphinx and self.conf.sphinx.disable_primary_sidebars:
pages = self.conf.sphinx.disable_primary_sidebars
else:
pages = ["index"] # default
html_sidebars.update({name: list() for name in pages})

@property
def automodapi_toctreedirm(self) -> str:
if self.conf.sphinx and self.conf.sphinx.python_api_dir is not None:
return self.conf.sphinx.python_api_dir
else:
return "api"

def set_edit_on_github(
self,
html_theme_options: MutableMapping[str, Any],
html_context: MutableMapping[str, Any],
) -> None:
"""Configures the Edit on GitHub functionality, if possible."""
if (
self.conf.sphinx
and self.conf.sphinx.theme.show_github_edit_link is False
):
return

if self.github_url is None:
raise ConfigError(
"sphinx.show_github_edit_link is True by the "
"project.github_url is not set."
)

parsed_url = urlparse(self.github_url)
path_parts = parsed_url.path.split("/")
try:
# first part is "/"
github_owner = path_parts[1]
github_repo = path_parts[2].split(".")[0] # drop .git if present
except IndexError:
raise ConfigError(
f"Could not parse GitHub repo URL: {self.github_url}"
)

repo = GitRepository(Path.cwd())
try:
# the current working directory for sphinx config is always
# the same as the directory containing the conf.py file.
doc_dir = str(Path.cwd().relative_to(repo.working_tree_dir))
except ValueError:
raise ConfigError(
"Cannot determine the path of the documentation directory "
"relative to the Git repository root. Set "
"sphinx.show_github_edit_link to false if this is not a "
"git repository."
)

html_theme_options["use_edit_page_button"] = True
html_context["github_user"] = github_owner
html_context["github_repo"] = github_repo
html_context[
"github_version"
] = self.conf.project.github_default_branch
html_context["doc_path"] = doc_dir

@property
def header_links_before_dropdown(self) -> int:
"""Number of links to show in the nav head before folding extra items
into a More dropdown.
"""
if self.conf.sphinx:
return self.conf.sphinx.theme.header_links_before_dropdown
else:
return 5
20 changes: 19 additions & 1 deletion src/documenteer/conf/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

from pathlib import Path

from git import Repo
from sphinx.errors import ConfigError

__all__ = ["get_asset_path", "get_template_dir"]
__all__ = ["get_asset_path", "get_template_dir", "GitRepository"]


def get_asset_path(name: str) -> str:
Expand Down Expand Up @@ -75,3 +76,20 @@ def get_template_dir(root: str) -> str:
"Documenteer package."
)
return str(dirname)


class GitRepository:
"""Access to to metadata about the Git repository of the documentation
project.
"""

def __init__(self, dirname: Path) -> None:
self._repo = Repo(dirname, search_parent_directories=True)

@property
def working_tree_dir(self) -> Path:
"""The root directory of the Git repository."""
path = self._repo.working_tree_dir
if path is None:
raise RuntimeError("Git repository is not available.")
return Path(path)
21 changes: 15 additions & 6 deletions src/documenteer/conf/guide.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"linkcheck_timeout",
# HTML
"html_theme",
"html_context",
"html_theme_options",
"html_sidebars",
"html_title",
Expand Down Expand Up @@ -101,6 +102,7 @@

extensions = [
"myst_parser",
"sphinx_copybutton",
"sphinx_design",
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
Expand Down Expand Up @@ -201,11 +203,14 @@

html_theme = "pydata_sphinx_theme"

# Context available to Jinja templates
html_context: Dict[str, Any] = {}

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {
"header_links_before_dropdown": 5,
"header_links_before_dropdown": _conf.header_links_before_dropdown,
"external_links": [{"name": "Rubin docs", "url": "https://www.lsst.io"}],
"icon_links": [],
"logo": {
Expand Down Expand Up @@ -236,10 +241,14 @@
}
)

# in pydata-sphinx-theme 0.10.0 it'll be possible to use
# :html_theme.sidebar_secondary.remove: metadata to remove the sidebar
# for a specific page instead
html_sidebars: Dict[str, List[Any]] = {"index": [], "changelog": []}
# Configure the "Edit this page" link
_conf.set_edit_on_github(html_theme_options, html_context)

# Specifies templates to put in the primary (left) sidebars of
# specific pages (by their docname or pattern). An empty list results in the
# sidebar being dropped altogether.
html_sidebars: Dict[str, List[str]] = {"index": [], "changelog": []}
_conf.disable_primary_sidebars(html_sidebars)

# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
Expand Down Expand Up @@ -274,7 +283,7 @@

# Automodapi
# https://sphinx-automodapi.readthedocs.io/en/latest/automodapi.html
automodapi_toctreedirnm = "api"
automodapi_toctreedirnm = _conf.automodapi_toctreedirm

# sphinx_autodoc_typehints
always_document_param_types = True
Expand Down
Loading

0 comments on commit 914adca

Please sign in to comment.