# Taken from https://github.com/scikit-learn/scikit-learn/blob/main/doc/sphinxext/github_link.py import inspect import os import subprocess import sys from functools import partial from operator import attrgetter REVISION_CMD = "git rev-parse --short HEAD" def _get_git_revision(): try: revision = subprocess.check_output(REVISION_CMD.split()).strip() except (subprocess.CalledProcessError, OSError): print("Failed to execute git to get revision") return None return revision.decode("utf-8") def _linkcode_resolve(domain, info, package, url_fmt, revision): """ Determine a link to online source for a class/method/function This is called by sphinx.ext.linkcode """ if revision is None: return if domain not in ("py", "pyx"): return if not info.get("module") or not info.get("fullname"): return class_name = info["fullname"].split(".")[0] try: module = __import__(info["module"], fromlist=[class_name]) except ImportError as e: raise ImportError( f"Unable to find {info['module']!r} wich class={class_name!r}." ) from e obj = attrgetter(info["fullname"])(module) # Unwrap the object to get the correct source # file in case that is wrapped by a decorator obj = inspect.unwrap(obj) try: fn = inspect.getsourcefile(obj) except Exception: fn = None if not fn: try: fn = inspect.getsourcefile(sys.modules[obj.__module__]) except Exception: fn = None if not fn: return fn = os.path.relpath(fn, start=os.path.dirname(__import__(package).__file__)) try: lineno = inspect.getsourcelines(obj)[1] except Exception: lineno = "" return url_fmt.format(revision=revision, package=package, path=fn, lineno=lineno) def make_linkcode_resolve(package, url_fmt): """ Returns a linkcode_resolve function for the given URL format revision is a git commit reference (hash or name) package is the name of the root module of the package url_fmt is along the lines of:: 'https://github.com/USER/PROJECT/blob/{revision}/{package}/{path}#L{lineno}' """ revision = _get_git_revision() return partial( _linkcode_resolve, revision=revision, package=package, url_fmt=url_fmt )