1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
"""Supporting functions for documentation build."""
from __future__ import annotations
import inspect
import os
import os.path as op
import sys
def linkcode_resolve(domain: str, info: dict[str, str], edit: bool = False) -> str | None:
"""Determine the URL corresponding to a Python object.
Parameters
----------
domain : str
Only useful when 'py'.
info : dict
With keys "module" and "fullname".
edit : bool, default=False
Jump right to the edit page.
Returns
-------
str
The code URL. Empty string if there is no valid link.
Notes
-----
This function is used by the `sphinx.ext.linkcode` extension to create the "[Source]"
button whose link is edited in this function.
This has been adapted to deal with our "verbose" decorator.
Adapted from mne (mne/utils/docs.py), which was adapted from SciPy (doc/source/conf.py).
"""
import pyvista
if domain != 'py':
return None
modname = info['module']
fullname = info['fullname']
# Little clean up to avoid pyvista.pyvista
if fullname.startswith(modname):
fullname = fullname[len(modname) + 1 :]
submod = sys.modules.get(modname)
if submod is None:
return None
obj = submod
for part in fullname.split('.'):
try:
obj = getattr(obj, part)
except Exception:
return None
# deal with our decorators properly
while hasattr(obj, 'fget'):
obj = obj.fget
try:
fn = inspect.getsourcefile(obj)
except Exception: # pragma: no cover
fn = None
if not fn: # pragma: no cover
try:
fn = inspect.getsourcefile(sys.modules[obj.__module__])
except Exception:
return None
return None
fn = op.relpath(fn, start=op.dirname(pyvista.__file__)) # noqa: PTH120
fn = '/'.join(op.normpath(fn).split(os.sep)) # in case on Windows # noqa: PTH206
try:
source, lineno = inspect.getsourcelines(obj)
except Exception: # pragma: no cover
lineno = None
linespec = f'#L{lineno}-L{lineno + len(source) - 1}' if lineno and not edit else ''
if 'dev' in pyvista.__version__:
kind = 'main'
else: # pragma: no cover
kind = 'release/%s' % ('.'.join(pyvista.__version__.split('.')[:2])) # noqa: UP031
blob_or_edit = 'edit' if edit else 'blob'
return f"http://github.com/pyvista/pyvista/{blob_or_edit}/{kind}/pyvista/{fn}{linespec}"
def pv_html_page_context(
app,
pagename: str,
templatename: str,
context,
doctree,
) -> None: # pragma: no cover
"""Add a function that jinja can access for returning an "edit this page" link pointing to `main`.
This is specific to PyVista to ensure that the "edit this page" link always
goes to the right page, specifically for:
- Gallery examples
- Autosummary examples (using _autosummary)
"""
def fix_edit_link_button(link: str) -> str | None:
"""Transform "edit on github" links to the correct url.
This is specific to PyVista to ensure that the "edit this page" link
always goes to the right page, specifically for:
- Gallery examples
- Autosummary examples (using _autosummary)
Parameters
----------
link : str
The link to the github edit interface.
Returns
-------
str
The link to the tip of the main branch for the same file.
"""
if pagename.startswith('examples') and 'index' not in pagename:
# This is a gallery example.
# We can get away with directly using the pagename since "examples"
# in the pagename is the same as the "examples" directory in the
# repo
return f"http://github.com/pyvista/pyvista/edit/main/{pagename}.py"
elif "_autosummary" in pagename:
# This is an API example
fullname = pagename.split('_autosummary')[1][1:]
return linkcode_resolve('py', {'module': 'pyvista', 'fullname': fullname}, edit=True)
else:
return link
context["fix_edit_link_button"] = fix_edit_link_button
|