|
| 1 | +""" |
| 2 | +This script comes from scikit-learn: |
| 3 | +https://github.com/scikit-learn/scikit-learn/blob/master/doc/sphinxext/github_link.py |
| 4 | +""" |
| 5 | +from operator import attrgetter |
| 6 | +import inspect |
| 7 | +import subprocess |
| 8 | +import os |
| 9 | +import sys |
| 10 | +from functools import partial |
| 11 | + |
| 12 | +REVISION_CMD = 'git rev-parse --short HEAD' |
| 13 | + |
| 14 | + |
| 15 | +def _get_git_revision(): |
| 16 | + try: |
| 17 | + revision = subprocess.check_output(REVISION_CMD.split()).strip() |
| 18 | + except (subprocess.CalledProcessError, OSError): |
| 19 | + print('Failed to execute git to get revision') |
| 20 | + return None |
| 21 | + return revision.decode('utf-8') |
| 22 | + |
| 23 | + |
| 24 | +def _linkcode_resolve(domain, info, package, url_fmt, revision): |
| 25 | + """Determine a link to online source for a class/method/function |
| 26 | +
|
| 27 | + This is called by sphinx.ext.linkcode |
| 28 | +
|
| 29 | + An example with a long-untouched module that everyone has |
| 30 | + >>> _linkcode_resolve('py', {'module': 'tty', |
| 31 | + ... 'fullname': 'setraw'}, |
| 32 | + ... package='tty', |
| 33 | + ... url_fmt='http://hg.python.org/cpython/file/' |
| 34 | + ... '{revision}/Lib/{package}/{path}#L{lineno}', |
| 35 | + ... revision='xxxx') |
| 36 | + 'http://hg.python.org/cpython/file/xxxx/Lib/tty/tty.py#L18' |
| 37 | + """ |
| 38 | + |
| 39 | + if revision is None: |
| 40 | + return |
| 41 | + if domain not in ('py', 'pyx'): |
| 42 | + return |
| 43 | + if not info.get('module') or not info.get('fullname'): |
| 44 | + return |
| 45 | + |
| 46 | + class_name = info['fullname'].split('.')[0] |
| 47 | + if type(class_name) != str: |
| 48 | + # Python 2 only |
| 49 | + class_name = class_name.encode('utf-8') |
| 50 | + module = __import__(info['module'], fromlist=[class_name]) |
| 51 | + obj = attrgetter(info['fullname'])(module) |
| 52 | + |
| 53 | + try: |
| 54 | + fn = inspect.getsourcefile(obj) |
| 55 | + except Exception: |
| 56 | + fn = None |
| 57 | + if not fn: |
| 58 | + try: |
| 59 | + fn = inspect.getsourcefile(sys.modules[obj.__module__]) |
| 60 | + except Exception: |
| 61 | + fn = None |
| 62 | + if not fn: |
| 63 | + return |
| 64 | + |
| 65 | + fn = os.path.relpath(fn, |
| 66 | + start=os.path.dirname(__import__(package).__file__)) |
| 67 | + try: |
| 68 | + lineno = inspect.getsourcelines(obj)[1] |
| 69 | + except Exception: |
| 70 | + lineno = '' |
| 71 | + return url_fmt.format(revision=revision, package=package, |
| 72 | + path=fn, lineno=lineno) |
| 73 | + |
| 74 | + |
| 75 | +def make_linkcode_resolve(package, url_fmt): |
| 76 | + """Returns a linkcode_resolve function for the given URL format |
| 77 | +
|
| 78 | + revision is a git commit reference (hash or name) |
| 79 | +
|
| 80 | + package is the name of the root module of the package |
| 81 | +
|
| 82 | + url_fmt is along the lines of ('https://github.com/USER/PROJECT/' |
| 83 | + 'blob/{revision}/{package}/' |
| 84 | + '{path}#L{lineno}') |
| 85 | + """ |
| 86 | + revision = _get_git_revision() |
| 87 | + return partial(_linkcode_resolve, revision=revision, package=package, |
| 88 | + url_fmt=url_fmt) |
0 commit comments