Skip to content

Commit 5d8a8b2

Browse files
authored
switch to book theme (#73)
1 parent 9bed0f1 commit 5d8a8b2

File tree

15 files changed

+267
-272
lines changed

15 files changed

+267
-272
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ jobs:
2828
- name: dependencies
2929
run: |
3030
pip install --upgrade pip wheel
31-
pip install .[test,typehints]
31+
pip install -e .[test,typehints]
3232
- name: tests
3333
run: pytest --color=yes

.pre-commit-config.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ repos:
1717
rev: v3.0.0
1818
hooks:
1919
- id: prettier
20+
additional_dependencies:
21+
- [email protected] # plugin not yet 3.0 compatible
22+
- prettier-plugin-jinja-template

.prettierrc

-13
This file was deleted.

.prettierrc.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
plugins:
2+
- prettier-plugin-jinja-template
3+
overrides:
4+
- files: [settings.json]
5+
options:
6+
parser: json5
7+
quoteProps: preserve
8+
singleQuote: false
9+
trailingComma: all
10+
- files: ["*.html"]
11+
options:
12+
parser: jinja-template

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"editor.formatOnSave": true,
88
"editor.codeActionsOnSave": {
99
"source.fixAll": true,
10+
"source.organizeImports": true,
1011
},
1112
},
1213
}

docs/conf.py

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
11
import sys
22
from datetime import datetime
3+
from importlib.metadata import metadata
34
from pathlib import Path
45

56
from sphinx.application import Sphinx
67

78

8-
# Allow importing scanpydoc itself
99
HERE = Path(__file__).parent
10-
sys.path.insert(0, str(HERE.parent))
11-
import scanpydoc # noqa
1210

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

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

18-
19-
needs_sphinx = "1.7" # autosummary bugfix
2018
extensions = [
2119
"sphinx.ext.intersphinx",
2220
"sphinx.ext.napoleon",
2321
"sphinx_autodoc_typehints", # needs to be after napoleon
2422
"sphinx.ext.autodoc",
2523
"sphinx.ext.autosummary",
2624
"scanpydoc",
25+
"sphinx.ext.linkcode", # needs to be after scanpydoc
2726
]
2827

2928
intersphinx_mapping = dict(
3029
python=("https://docs.python.org/3", None),
3130
jinja=("https://jinja.palletsprojects.com/en/2.10.x/", None),
3231
sphinx=("https://www.sphinx-doc.org/en/master/", None),
33-
sphinx_rtd_theme=("https://sphinx-rtd-theme.readthedocs.io/en/stable/", None),
32+
sphinx_book_theme=("https://sphinx-book-theme.readthedocs.io/en/stable/", None),
3433
# examples
3534
numpy=("https://numpy.org/doc/stable/", None),
3635
anndata=("https://anndata.readthedocs.io/en/latest/", None),
@@ -39,10 +38,11 @@
3938
)
4039

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

4747
master_doc = "index"
4848
templates_path = ["_templates"]
@@ -54,11 +54,13 @@
5454

5555
html_theme = "scanpydoc"
5656
html_context = dict(
57-
github_user="theislab", github_repo="scanpydoc", github_version="main"
57+
repository_url="https://github.com/theislab/scanpydoc",
58+
repository_branch="main",
59+
use_repository_button=True,
5860
)
5961

60-
# proj/doc/conf.py/../.. → proj
61-
project_dir = Path(__file__).parent.parent
62+
# proj/doc/.. → proj
63+
project_dir = HERE.parent
6264

6365

6466
def setup(app: Sphinx):

pyproject.toml

+4-5
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,11 @@ test = [
3030
'pytest-cov',
3131
]
3232
doc = [
33-
'scanpydoc[typehints]',
34-
'sphinx<7', # https://github.com/readthedocs/sphinx_rtd_theme/issues/1463
35-
'sphinx-rtd-theme',
33+
'scanpydoc[typehints,theme]',
34+
'sphinx',
3635
]
3736
typehints = ['sphinx-autodoc-typehints>=1.15.2']
38-
theme = ['sphinx-rtd-theme']
37+
theme = ['sphinx-book-theme>=1.0.1']
3938

4039
[project.entry-points.'sphinx.html_themes']
4140
scanpydoc = 'scanpydoc.theme'
@@ -72,7 +71,7 @@ python = ['3.8', '3.9', '3.10', '3.11']
7271
[tool.hatch.envs.test]
7372
features = ['test', 'typehints']
7473
[tool.hatch.envs.test.scripts]
75-
test = 'pytest -vv'
74+
run = 'pytest -vv {args}'
7675

7776
[tool.pytest.ini_options]
7877
addopts = [

src/scanpydoc/rtd_github_links.py renamed to src/scanpydoc/rtd_github_links/__init__.py

+64-23
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,40 @@
11
"""GitHub URLs for class and method pages.
22
3-
This extension registers a :ref:`Jinja filter <jinja:filters>` called :func:`github_url`
4-
that you can use to convert a module path into a GitHub URL
3+
This extension does two things:
4+
5+
#. It registers a :ref:`Jinja filter <jinja:filters>` called :func:`github_url`
6+
that you can use to convert a module path into a GitHub URL.
7+
#. It configures :mod:`sphinx.ext.linkcode` for you if loaded after it in ``conf.py``:
8+
9+
.. code:: python
10+
11+
import sys
12+
from pathlib import Path
13+
14+
HERE = Path(__file__).parent
15+
# make sure modules are import from the right place
16+
sys.path.insert(0, HERE.parent / "src")
17+
18+
extensions = [
19+
"scanpydoc",
20+
"sphinx.ext.linkcode",
21+
]
22+
23+
# no need to define `linkcode_resolve`
524
625
Configuration
726
-------------
827
928
Uses the following config values in ``conf.py``::
1029
1130
project_dir: Path = ... # default: Path.cwd()
31+
32+
# sphinx book theme style
33+
html_context = dict(
34+
repository_url=...,
35+
repository_branch=...,
36+
)
37+
# or RTD theme style:
1238
html_context = dict(
1339
github_user=...,
1440
github_repo=...,
@@ -18,13 +44,14 @@
1844
The ``project_dir`` is used to figure out the .py file path relative to the git root,
1945
that is to construct the path in the github URL.
2046
21-
The ``html_context`` is e.g. also used like this in the sphinx_rtd_theme_.
47+
Which ``html_context`` style you want to use depends on your theme, e.g.
48+
:doc:`Sphinx Book Theme <sphinx_book_theme:index>`.
2249
23-
Usage
24-
-----
50+
``:github_url:`` usage
51+
----------------------
2552
2653
You can use the filter e.g. in `autosummary templates`_.
27-
To configure the sphinx_rtd_theme_,
54+
To configure the :doc:`Sphinx Book Theme <sphinx_book_theme:index>`,
2855
override the ``autosummary/base.rst`` template like this:
2956
3057
.. code:: restructuredtext
@@ -35,7 +62,6 @@
3562
3663
.. _autosummary templates: \
3764
http://www.sphinx-doc.org/en/master/usage/extensions/autosummary.html#customizing-templates
38-
.. _sphinx_rtd_theme: https://sphinx-rtd-theme.readthedocs.io/en/latest/
3965
"""
4066
from __future__ import annotations
4167

@@ -49,7 +75,7 @@
4975
from sphinx.application import Sphinx
5076
from sphinx.config import Config
5177

52-
from . import _setup_sig, metadata
78+
from .. import _setup_sig, metadata
5379

5480

5581
project_dir = None # type: Path
@@ -60,9 +86,14 @@ def _init_vars(app: Sphinx, config: Config):
6086
"""Called when ``conf.py`` has been loaded."""
6187
global github_base_url, project_dir
6288
_check_html_context(config)
63-
github_base_url = "https://github.com/{github_user}/{github_repo}/tree/{github_version}".format_map(
64-
config.html_context
65-
)
89+
try:
90+
github_base_url = "https://github.com/{github_user}/{github_repo}/tree/{github_version}".format_map(
91+
config.html_context
92+
)
93+
except KeyError:
94+
github_base_url = "{repository_url}/tree/{repository_branch}".format_map(
95+
config.html_context
96+
)
6697
project_dir = Path(config.project_dir)
6798

6899

@@ -120,32 +151,36 @@ def github_url(qualname: str) -> str:
120151
except Exception:
121152
print(f"Error in github_url({qualname!r}):", file=sys.stderr)
122153
raise
123-
try:
154+
try: # only works when installed in dev mode
124155
path = PurePosixPath(Path(module.__file__).resolve().relative_to(project_dir))
125156
except ValueError:
126-
# trying to document something from another package
127-
path = "/".join(module.__file__.split("/")[-2:])
157+
# no dev mode or something from another package
158+
path = PurePosixPath(*module.__file__.split("/")[-2:])
159+
if (project_dir / "src").is_dir():
160+
path = "src" / path
128161
start, end = _get_linenos(obj)
129162
fragment = f"#L{start}-L{end}" if start and end else ""
130163
return f"{github_base_url}/{path}{fragment}"
131164

132165

133166
def _check_html_context(config: Config):
134167
try:
135-
html_context = config.html_context
168+
html_context: dict[str, Any] = config.html_context
136169
except AttributeError:
137170
raise ValueError(
138171
f"Extension {__name__} needs “html_context” to be defined in conf.py"
139172
)
140-
missing_values = {
141-
"github_user",
142-
"github_repo",
143-
"github_version",
144-
} - html_context.keys()
145-
if missing_values:
146-
mvs = ", ".join([f"html_context[{mv!r}]" for mv in missing_values])
173+
options = [
174+
{"github_user", "github_repo", "github_version"},
175+
{"repository_url", "repository_branch"},
176+
]
177+
missing_value_sets = [opt - html_context.keys() for opt in options]
178+
if all(missing_value_sets):
179+
mvs = " or ".join(
180+
", ".join(repr(mv) for mv in mvs) for mvs in missing_value_sets
181+
)
147182
raise ValueError(
148-
f"Extension {__name__} needs {mvs} to be defined in conf.py.\n"
183+
f"Extension {__name__} needs html_context {mvs} to be defined in conf.py.\n"
149184
f"html_context = {html_context!r}"
150185
)
151186

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

201+
# if linkcode config not set
202+
if "linkcode_resolve" not in app.config or app.config["linkcode_resolve"] is None:
203+
from ._linkcode import linkcode_resolve
204+
205+
app.config["linkcode_resolve"] = linkcode_resolve
206+
166207
# html_context doesn’t apply to autosummary templates ☹
167208
# and there’s no way to insert filters into those templates
168209
# so we have to modify the default filters
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import annotations
2+
3+
from typing import Literal, TypedDict
4+
5+
6+
class PyInfo(TypedDict):
7+
module: str
8+
fullname: str
9+
10+
11+
class CInfo(TypedDict):
12+
"""C / C++ info."""
13+
14+
names: list[str]
15+
16+
17+
class JSInfo(TypedDict):
18+
object: str
19+
fullname: str
20+
21+
22+
def linkcode_resolve(
23+
domain: Literal["py", "c", "cpp", "javascript"], info: PyInfo | CInfo | JSInfo
24+
) -> str | None:
25+
from . import github_url
26+
27+
if domain != "py":
28+
return None
29+
if not info["module"]:
30+
return None
31+
return github_url(f'{info["module"]}.{info["fullname"]}')

src/scanpydoc/theme/__init__.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""A widescreen extension for :doc:`sphinx_rtd_theme:index`.
1+
"""A widescreen extension for :doc:`sphinx_book_theme:index`.
22
33
Add to ``conf.py``:
44
@@ -19,14 +19,14 @@
1919
2020
The CSS color used for the mobile header background and the project name text.
2121
22-
See ``sphinx_rtd_theme``’s :doc:`sphinx_rtd_theme:configuring`, e.g.:
22+
See ``sphinx_book_theme``’s :doc:`sphinx_book_theme:reference`, e.g.:
2323
2424
.. code:: python
2525
2626
html_theme_options = dict(
27-
logo_only=False,
28-
accent_color='rebeccapurple',
29-
display_version=False,
27+
repository_url="https://github.com/theislab/scanpydoc",
28+
repository_branch="main",
29+
use_repository_button=True,
3030
)
3131
3232
Docsearch options

0 commit comments

Comments
 (0)