diff --git a/docs/sphinx/source/_templates/breadcrumbs.html b/docs/sphinx/source/_templates/breadcrumbs.html new file mode 100644 index 0000000000..b2078c9119 --- /dev/null +++ b/docs/sphinx/source/_templates/breadcrumbs.html @@ -0,0 +1,26 @@ +{# + +Modify the "Edit on Github" links to handle auto-generated pages in the +example gallery and the API reference listings. The GH links that sphinx +generates by default make the assumption that an HTML file comes from an RST +file with the same filepath, which isn't the case for autogenerated files. + +We need to generate the target URL differently based on the type +of page. We use the built-in `pagename` variable to determine what +kind of page this is. `pagename` is the path at the end of the +URL, without the extension. For instance, +https://pvlib-python.rtfd.org/en/stable/auto_examples/plot_singlediode.html +will have pagename = "auto_examples/plot_singlediode". + +Note: make_github_url is defined in conf.py +#} + +{% extends "!breadcrumbs.html" %} +{% block breadcrumbs_aside %} +
  • + {# Get the appropriate GH link based on this page's name: #} + {% set target_url = make_github_url(pagename) %} + {# Create the HTML element with our custom GH link: #} + View on Github +
  • +{% endblock %} diff --git a/docs/sphinx/source/conf.py b/docs/sphinx/source/conf.py index 7e050726e8..413c2b94b6 100644 --- a/docs/sphinx/source/conf.py +++ b/docs/sphinx/source/conf.py @@ -21,6 +21,9 @@ # for warning suppression import warnings +# for generating GH links with linenumbers +import inspect + class Mock(MagicMock): @classmethod @@ -231,7 +234,6 @@ def setup(app): # Override footnote callout CSS to be normal text instead of superscript app.add_stylesheet("no_reference_superscript.css") - # -- Options for LaTeX output --------------------------------------------- latex_elements = { @@ -345,3 +347,95 @@ def setup(app): warnings.filterwarnings("ignore", category=UserWarning, message='Matplotlib is currently using agg, which is a' ' non-GUI backend, so cannot show the figure.') + +# %% helper functions for intelligent "View on Github" linking +# based on +# https://gist.github.com/flying-sheep/b65875c0ce965fbdd1d9e5d0b9851ef1 + + +def get_obj_module(qualname): + """ + Get a module/class/attribute and its original module by qualname. + Useful for looking up the original location when a function is imported + into an __init__.py + + Examples + -------- + >>> func, mod = get_obj_module("pvlib.iotools.read_midc") + >>> mod.__name__ + 'pvlib.iotools.midc' + """ + 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 in its source code file""" + try: + lines, start = inspect.getsourcelines(obj) + except TypeError: # obj is an attribute or None + return None, None + else: + return start, start + len(lines) - 1 + + +def make_github_url(pagename): + """ + Generate the appropriate GH link for a given docs page. This function + is intended for use in sphinx template files. + + The target URL is built differently based on the type of page. Sphinx + provides templates with a built-in `pagename` variable that is the path + at the end of the URL, without the extension. For instance, + https://pvlib-python.rtfd.org/en/stable/auto_examples/plot_singlediode.html + will have pagename = "auto_examples/plot_singlediode". + """ + + URL_BASE = "https://github.com/pvlib/pvlib-python/blob/master/" + + # is it a gallery page? + if any(d in pagename for d in sphinx_gallery_conf['gallery_dirs']): + if pagename.split("/")[-1] == "index": + example_file = "README.rst" + else: + example_file = pagename.split("/")[-1] + ".py" + target_url = URL_BASE + "docs/examples/" + example_file + + # is it an API autogen page? + elif "generated" in pagename: + # pagename looks like "generated/pvlib.location.Location" + qualname = pagename.split("/")[-1] + obj, module = get_obj_module(qualname) + path = module.__name__.replace(".", "/") + ".py" + target_url = URL_BASE + path + # add line numbers if possible: + start, end = get_linenos(obj) + if start and end: + target_url += '#L{}-L{}'.format(start, end) + + # Just a normal source RST page + else: + target_url = URL_BASE + "docs/sphinx/source/" + pagename + ".rst" + + return target_url + + +# variables to pass into the HTML templating engine; these are accessible from +# _templates/breadcrumbs.html +html_context = { + 'make_github_url': make_github_url, +}