From 39029f56f3851f703eafc77dd83c3d51136c9471 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sun, 11 Mar 2012 18:19:36 +0100 Subject: DOC: generate links to source code --- doc/source/conf.py | 64 ++++++++++++++++++++++++++++++++++++++ doc/sphinxext/linkcode.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 doc/sphinxext/linkcode.py (limited to 'doc') diff --git a/doc/source/conf.py b/doc/source/conf.py index 72083cc95..de9f6adf3 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -286,3 +286,67 @@ plot_rcparams = { if not use_matplotlib_plot_directive: import matplotlib matplotlib.rcParams.update(plot_rcparams) + +# ----------------------------------------------------------------------------- +# Source code links +# ----------------------------------------------------------------------------- + +import inspect +from os.path import relpath, dirname + +for name in ['sphinx.ext.linkcode', 'linkcode', 'numpydoc.linkcode']: + try: + __import__(name) + extensions.append(name) + break + except ImportError: + pass +else: + print "NOTE: linkcode extension not found -- no links to source generated" + +def linkcode_resolve(domain, info): + """ + Determine the URL corresponding to Python object + """ + if domain != 'py': + return None + + modname = info['module'] + fullname = info['fullname'] + + submod = sys.modules.get(modname) + if submod is None: + return None + + obj = submod + for part in fullname.split('.'): + try: + obj = getattr(obj, part) + except: + return None + + try: + fn = inspect.getsourcefile(obj) + except: + fn = None + if not fn: + return None + + try: + source, lineno = inspect.findsource(obj) + except: + lineno = None + + if lineno: + linespec = "#L%d" % (lineno + 1) + else: + linespec = "" + + fn = relpath(fn, start=dirname(numpy.__file__)) + + if 'dev' in numpy.__version__: + return "http://github.com/numpy/numpy/blob/master/numpy/%s%s" % ( + fn, linespec) + else: + return "http://github.com/numpy/numpy/blob/v%s/numpy/%s%s" % ( + numpy.__version__, fn, linespec) diff --git a/doc/sphinxext/linkcode.py b/doc/sphinxext/linkcode.py new file mode 100644 index 000000000..1b1ef4a77 --- /dev/null +++ b/doc/sphinxext/linkcode.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +""" + linkcode + ~~~~~~~~ + + Add external links to module code in Python object descriptions. + + :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import warnings +warnings.warn("This extension has been submitted to Sphinx upstream. " + "Use the version from there if it is accepted " + "https://bitbucket.org/birkenfeld/sphinx/pull-request/47/sphinxextlinkcode", + FutureWarning, stacklevel=1) + + +from docutils import nodes + +from sphinx import addnodes +from sphinx.locale import _ +from sphinx.errors import SphinxError + +class LinkcodeError(SphinxError): + category = "linkcode error" + +def doctree_read(app, doctree): + env = app.builder.env + + resolve_target = getattr(env.config, 'linkcode_resolve', None) + if not callable(env.config.linkcode_resolve): + raise LinkcodeError( + "Function `linkcode_resolve` is not given in conf.py") + + domain_keys = dict( + py=['module', 'fullname'], + c=['names'], + cpp=['names'], + js=['object', 'fullname'], + ) + + for objnode in doctree.traverse(addnodes.desc): + domain = objnode.get('domain') + uris = set() + for signode in objnode: + if not isinstance(signode, addnodes.desc_signature): + continue + + # Convert signode to a specified format + info = {} + for key in domain_keys.get(domain, []): + value = signode.get(key) + if not value: + value = '' + info[key] = value + if not info: + continue + + # Call user code to resolve the link + uri = resolve_target(domain, info) + if not uri: + # no source + continue + + if uri in uris or not uri: + # only one link per name, please + continue + uris.add(uri) + + onlynode = addnodes.only(expr='html') + onlynode += nodes.reference('', '', internal=False, refuri=uri) + onlynode[0] += nodes.inline('', _('[source]'), + classes=['viewcode-link']) + signode += onlynode + +def setup(app): + app.connect('doctree-read', doctree_read) + app.add_config_value('linkcode_resolve', None, 'env') -- cgit v1.2.1