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,
+}