|
#!/usr/bin/env python3 |
|
|
|
import sys |
|
import inspect |
|
from pathlib import Path |
|
|
|
master_doc = 'index' |
|
templates_path = ['_templates'] |
|
|
|
extensions = [ |
|
'sphinx.ext.autodoc', |
|
'sphinx.ext.autosummary', |
|
] |
|
|
|
autosummary_generate = True |
|
|
|
# RTD theme |
|
|
|
html_theme = 'sphinx_rtd_theme' |
|
html_context = dict( |
|
display_github=True, |
|
github_user=..., |
|
github_repo=..., |
|
github_version='master', |
|
conf_py_path='/docs/', |
|
) |
|
|
|
# module path filter |
|
|
|
def get_obj_module(qualname): |
|
"""Get a module/class/attribute and its original module by qualname""" |
|
modname = qualname |
|
classname = None |
|
attrname = None |
|
while modname not in sys.modules: |
|
attrname = classname |
|
modname, classname = modname.rsplit('.', 1) |
|
|
|
# retrieve object and find original module name |
|
if classname: |
|
cls = getattr(sys.modules[modname], classname) |
|
modname = cls.__module__ |
|
obj = getattr(cls, attrname) if attrname else cls |
|
else: |
|
obj = None |
|
|
|
return obj, sys.modules[modname] |
|
|
|
|
|
def get_linenos(obj): |
|
"""Get an object’s line numbers""" |
|
try: |
|
lines, start = inspect.getsourcelines(obj) |
|
except TypeError: # obj is an attribute or None |
|
return None, None |
|
else: |
|
return start, start + len(lines) - 1 |
|
|
|
|
|
project_dir = Path(__file__).parent.parent # project/docs/conf.py/../.. → project/ |
|
github_url = 'https://github.com/{github_user}/{github_repo}/tree/{github_version}'.format_map(html_context) |
|
def modurl(qualname): |
|
"""Get the full GitHub URL for some object’s qualname""" |
|
obj, module = get_obj_module(qualname) |
|
path = Path(module.__file__).relative_to(project_dir) |
|
start, end = get_linenos(obj) |
|
fragment = '#L{}-L{}'.format(start, end) if start and end else '' |
|
return '{}/{}{}'.format(github_url, path, fragment) |
|
|
|
|
|
# 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 |
|
from jinja2.defaults import DEFAULT_FILTERS |
|
|
|
DEFAULT_FILTERS['modurl'] = modurl |