1
1
"""GitHub URLs for class and method pages.
2
2
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`
5
24
6
25
Configuration
7
26
-------------
8
27
9
28
Uses the following config values in ``conf.py``::
10
29
11
30
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:
12
38
html_context = dict(
13
39
github_user=...,
14
40
github_repo=...,
18
44
The ``project_dir`` is used to figure out the .py file path relative to the git root,
19
45
that is to construct the path in the github URL.
20
46
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>`.
22
49
23
- Usage
24
- -----
50
+ ``:github_url:`` usage
51
+ ----------------------
25
52
26
53
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>` ,
28
55
override the ``autosummary/base.rst`` template like this:
29
56
30
57
.. code:: restructuredtext
35
62
36
63
.. _autosummary templates: \
37
64
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/
39
65
"""
40
66
from __future__ import annotations
41
67
49
75
from sphinx .application import Sphinx
50
76
from sphinx .config import Config
51
77
52
- from . import _setup_sig , metadata
78
+ from .. import _setup_sig , metadata
53
79
54
80
55
81
project_dir = None # type: Path
@@ -60,9 +86,14 @@ def _init_vars(app: Sphinx, config: Config):
60
86
"""Called when ``conf.py`` has been loaded."""
61
87
global github_base_url , project_dir
62
88
_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
+ )
66
97
project_dir = Path (config .project_dir )
67
98
68
99
@@ -120,32 +151,36 @@ def github_url(qualname: str) -> str:
120
151
except Exception :
121
152
print (f"Error in github_url({ qualname !r} ):" , file = sys .stderr )
122
153
raise
123
- try :
154
+ try : # only works when installed in dev mode
124
155
path = PurePosixPath (Path (module .__file__ ).resolve ().relative_to (project_dir ))
125
156
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
128
161
start , end = _get_linenos (obj )
129
162
fragment = f"#L{ start } -L{ end } " if start and end else ""
130
163
return f"{ github_base_url } /{ path } { fragment } "
131
164
132
165
133
166
def _check_html_context (config : Config ):
134
167
try :
135
- html_context = config .html_context
168
+ html_context : dict [ str , Any ] = config .html_context
136
169
except AttributeError :
137
170
raise ValueError (
138
171
f"Extension { __name__ } needs “html_context” to be defined in conf.py"
139
172
)
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
+ )
147
182
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 "
149
184
f"html_context = { html_context !r} "
150
185
)
151
186
@@ -163,6 +198,12 @@ def setup(app: Sphinx) -> dict[str, Any]:
163
198
app .add_config_value ("project_dir" , proj_dir , "" )
164
199
app .connect ("config-inited" , _init_vars )
165
200
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
+
166
207
# html_context doesn’t apply to autosummary templates ☹
167
208
# and there’s no way to insert filters into those templates
168
209
# so we have to modify the default filters
0 commit comments