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

switch to book theme #73

Merged
merged 18 commits into from
Jul 18, 2023
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ jobs:
- name: dependencies
run: |
pip install --upgrade pip wheel
pip install .[test,typehints]
pip install -e .[test,typehints]
- name: tests
run: pytest --color=yes
3 changes: 3 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ repos:
rev: v3.0.0
hooks:
- id: prettier
additional_dependencies:
- prettier@2.8.1 # plugin not yet 3.0 compatible
- prettier-plugin-jinja-template
13 changes: 0 additions & 13 deletions .prettierrc

This file was deleted.

12 changes: 12 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins:
- prettier-plugin-jinja-template
overrides:
- files: [settings.json]
options:
parser: json5
quoteProps: preserve
singleQuote: false
trailingComma: all
- files: ["*.html"]
options:
parser: jinja-template
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true,
},
},
}
26 changes: 14 additions & 12 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import sys
from datetime import datetime
from importlib.metadata import metadata
from pathlib import Path

from sphinx.application import Sphinx


# Allow importing scanpydoc itself
HERE = Path(__file__).parent
sys.path.insert(0, str(HERE.parent))
import scanpydoc # noqa

# necessary for rtd_gh_links’ linkcode support
sys.path.insert(0, HERE.parent / "src")

# Clean build env
for file in HERE.glob("scanpydoc.*.rst"):
file.unlink()


needs_sphinx = "1.7" # autosummary bugfix
extensions = [
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx_autodoc_typehints", # needs to be after napoleon
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"scanpydoc",
"sphinx.ext.linkcode", # needs to be after scanpydoc
]

intersphinx_mapping = dict(
python=("https://docs.python.org/3", None),
jinja=("https://jinja.palletsprojects.com/en/2.10.x/", None),
sphinx=("https://www.sphinx-doc.org/en/master/", None),
sphinx_rtd_theme=("https://sphinx-rtd-theme.readthedocs.io/en/stable/", None),
sphinx_book_theme=("https://sphinx-book-theme.readthedocs.io/en/stable/", None),
# examples
numpy=("https://numpy.org/doc/stable/", None),
anndata=("https://anndata.readthedocs.io/en/latest/", None),
Expand All @@ -39,10 +38,11 @@
)

# general information
project = scanpydoc.__name__
author = "Philipp Angerer"
meta = metadata("scanpydoc")
project = meta["name"]
author = meta["author-email"].split(" <")[0]
copyright = f"{datetime.now():%Y}, {author}."
version = release = scanpydoc.__version__
version = release = meta["version"]

master_doc = "index"
templates_path = ["_templates"]
Expand All @@ -54,11 +54,13 @@

html_theme = "scanpydoc"
html_context = dict(
github_user="theislab", github_repo="scanpydoc", github_version="main"
repository_url="https://github.com/theislab/scanpydoc",
repository_branch="main",
use_repository_button=True,
)

# proj/doc/conf.py/../.. → proj
project_dir = Path(__file__).parent.parent
# proj/doc/.. → proj
project_dir = HERE.parent


def setup(app: Sphinx):
Expand Down
9 changes: 4 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ test = [
'pytest-cov',
]
doc = [
'scanpydoc[typehints]',
'sphinx<7', # https://github.com/readthedocs/sphinx_rtd_theme/issues/1463
'sphinx-rtd-theme',
'scanpydoc[typehints,theme]',
'sphinx',
]
typehints = ['sphinx-autodoc-typehints>=1.15.2']
theme = ['sphinx-rtd-theme']
theme = ['sphinx-book-theme>=1.0.1']

[project.entry-points.'sphinx.html_themes']
scanpydoc = 'scanpydoc.theme'
Expand Down Expand Up @@ -72,7 +71,7 @@ python = ['3.8', '3.9', '3.10', '3.11']
[tool.hatch.envs.test]
features = ['test', 'typehints']
[tool.hatch.envs.test.scripts]
test = 'pytest -vv'
run = 'pytest -vv {args}'

[tool.pytest.ini_options]
addopts = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
"""GitHub URLs for class and method pages.

This extension registers a :ref:`Jinja filter <jinja:filters>` called :func:`github_url`
that you can use to convert a module path into a GitHub URL
This extension does two things:

#. It registers a :ref:`Jinja filter <jinja:filters>` called :func:`github_url`
that you can use to convert a module path into a GitHub URL.
#. It configures :mod:`sphinx.ext.linkcode` for you if loaded after it in ``conf.py``:

.. code:: python

import sys
from pathlib import Path

HERE = Path(__file__).parent
# make sure modules are import from the right place
sys.path.insert(0, HERE.parent / "src")

extensions = [
"scanpydoc",
"sphinx.ext.linkcode",
]

# no need to define `linkcode_resolve`

Configuration
-------------

Uses the following config values in ``conf.py``::

project_dir: Path = ... # default: Path.cwd()

# sphinx book theme style
html_context = dict(
repository_url=...,
repository_branch=...,
)
# or RTD theme style:
html_context = dict(
github_user=...,
github_repo=...,
Expand All @@ -18,13 +44,14 @@
The ``project_dir`` is used to figure out the .py file path relative to the git root,
that is to construct the path in the github URL.

The ``html_context`` is e.g. also used like this in the sphinx_rtd_theme_.
Which ``html_context`` style you want to use depends on your theme, e.g.
:doc:`Sphinx Book Theme <sphinx_book_theme:index>`.

Usage
-----
``:github_url:`` usage
----------------------

You can use the filter e.g. in `autosummary templates`_.
To configure the sphinx_rtd_theme_,
To configure the :doc:`Sphinx Book Theme <sphinx_book_theme:index>`,
override the ``autosummary/base.rst`` template like this:

.. code:: restructuredtext
Expand All @@ -35,7 +62,6 @@

.. _autosummary templates: \
http://www.sphinx-doc.org/en/master/usage/extensions/autosummary.html#customizing-templates
.. _sphinx_rtd_theme: https://sphinx-rtd-theme.readthedocs.io/en/latest/
"""
from __future__ import annotations

Expand All @@ -49,7 +75,7 @@
from sphinx.application import Sphinx
from sphinx.config import Config

from . import _setup_sig, metadata
from .. import _setup_sig, metadata


project_dir = None # type: Path
Expand All @@ -60,9 +86,14 @@ def _init_vars(app: Sphinx, config: Config):
"""Called when ``conf.py`` has been loaded."""
global github_base_url, project_dir
_check_html_context(config)
github_base_url = "https://github.com/{github_user}/{github_repo}/tree/{github_version}".format_map(
config.html_context
)
try:
github_base_url = "https://github.com/{github_user}/{github_repo}/tree/{github_version}".format_map(
config.html_context
)
except KeyError:
github_base_url = "{repository_url}/tree/{repository_branch}".format_map(
config.html_context
)
project_dir = Path(config.project_dir)


Expand Down Expand Up @@ -120,32 +151,36 @@ def github_url(qualname: str) -> str:
except Exception:
print(f"Error in github_url({qualname!r}):", file=sys.stderr)
raise
try:
try: # only works when installed in dev mode
path = PurePosixPath(Path(module.__file__).resolve().relative_to(project_dir))
except ValueError:
# trying to document something from another package
path = "/".join(module.__file__.split("/")[-2:])
# no dev mode or something from another package
path = PurePosixPath(*module.__file__.split("/")[-2:])
if (project_dir / "src").is_dir():
path = "src" / path
start, end = _get_linenos(obj)
fragment = f"#L{start}-L{end}" if start and end else ""
return f"{github_base_url}/{path}{fragment}"


def _check_html_context(config: Config):
try:
html_context = config.html_context
html_context: dict[str, Any] = config.html_context
except AttributeError:
raise ValueError(
f"Extension {__name__} needs “html_context” to be defined in conf.py"
)
missing_values = {
"github_user",
"github_repo",
"github_version",
} - html_context.keys()
if missing_values:
mvs = ", ".join([f"html_context[{mv!r}]" for mv in missing_values])
options = [
{"github_user", "github_repo", "github_version"},
{"repository_url", "repository_branch"},
]
missing_value_sets = [opt - html_context.keys() for opt in options]
if all(missing_value_sets):
mvs = " or ".join(
", ".join(repr(mv) for mv in mvs) for mvs in missing_value_sets
)
raise ValueError(
f"Extension {__name__} needs {mvs} to be defined in conf.py.\n"
f"Extension {__name__} needs html_context {mvs} to be defined in conf.py.\n"
f"html_context = {html_context!r}"
)

Expand All @@ -163,6 +198,12 @@ def setup(app: Sphinx) -> dict[str, Any]:
app.add_config_value("project_dir", proj_dir, "")
app.connect("config-inited", _init_vars)

# if linkcode config not set
if "linkcode_resolve" not in app.config or app.config["linkcode_resolve"] is None:
from ._linkcode import linkcode_resolve

app.config["linkcode_resolve"] = linkcode_resolve

# html_context doesn’t apply to autosummary templates ☹
# and there’s no way to insert filters into those templates
# so we have to modify the default filters
Expand Down
31 changes: 31 additions & 0 deletions src/scanpydoc/rtd_github_links/_linkcode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from typing import Literal, TypedDict


class PyInfo(TypedDict):
module: str
fullname: str


class CInfo(TypedDict):
"""C / C++ info."""

names: list[str]


class JSInfo(TypedDict):
object: str
fullname: str


def linkcode_resolve(
domain: Literal["py", "c", "cpp", "javascript"], info: PyInfo | CInfo | JSInfo
) -> str | None:
from . import github_url

if domain != "py":
return None
if not info["module"]:
return None
return github_url(f'{info["module"]}.{info["fullname"]}')
10 changes: 5 additions & 5 deletions src/scanpydoc/theme/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""A widescreen extension for :doc:`sphinx_rtd_theme:index`.
"""A widescreen extension for :doc:`sphinx_book_theme:index`.

Add to ``conf.py``:

Expand All @@ -19,14 +19,14 @@

The CSS color used for the mobile header background and the project name text.

See ``sphinx_rtd_theme``’s :doc:`sphinx_rtd_theme:configuring`, e.g.:
See ``sphinx_book_theme``’s :doc:`sphinx_book_theme:reference`, e.g.:

.. code:: python

html_theme_options = dict(
logo_only=False,
accent_color='rebeccapurple',
display_version=False,
repository_url="https://github.com/theislab/scanpydoc",
repository_branch="main",
use_repository_button=True,
)

Docsearch options
Expand Down
Loading