github_url: | {{ fullname | modurl }} |
---|
{% extends "!autosummary/base.rst" %}
github_url: | {{ fullname | modurl }} |
---|
{% extends "!autosummary/base.rst" %}
#!/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 |