pv avatar pv committed 6b13bcd

ENH: add a linkcode extension

Comments (0)

Files changed (5)

doc/ext/linkcode.rst

+:mod:`sphinx.ext.linkcode` -- Add external links to source code
+===============================================================
+
+.. module:: sphinx.ext.linkcode
+   :synopsis: Add external links to source code.
+.. moduleauthor:: Pauli Virtanen
+
+.. versionadded:: 1.1
+
+This extension looks at your Python object descriptions
+(``.. class::``, ``.. function::`` etc.) and adds external links to
+code hosted somewhere on the web. The intent is similar to the
+``sphinx.ext.viewcode`` extension, but assumes the source code can be
+found somewhere on the Internet.
+
+In your configuration, you need to specify a :confval:`linkcode_resolve` 
+function that returns an URL based on the name of a module and 
+the full name of the object.
+
+.. confval:: linkcode_resolve
+
+   This is a function ``linkcode_resolve(domain, info)``,
+   which should return the URL to source code corresponding to
+   the object in given domain with given information. 
+
+   The function should return ``None`` if no link is to be added.
+
+   The argument ``domain`` specifies the language domain the object is
+   in. ``info`` is a dictionary with the following keys guaranteed to
+   be present (dependent on the domain):
+
+   - ``c``: ``names`` (list of names for the object)
+   - ``cpp``: ``names`` (list of names for the object)
+   - ``py``: ``module`` (name of the module), ``fullname`` (name of the object)
+   - ``javascript``: ``object`` (name of the object), ``fullname`` (name of the item)
+
+   Example:
+
+   .. code-block:: python
+
+      def linkcode_resolve(domain, info):
+          if domain != 'py':
+              return None
+	  if not info['module']:
+	      return None
+	  filename = info['module'].replace('.', '/')
+          return "http://somesite/sourcerepo/%s.py" % filename

doc/extensions.rst

    ext/todo
    ext/extlinks
    ext/viewcode
+   ext/linkcode
    ext/oldcmarkup
 
 

sphinx/ext/linkcode.py

+# -*- coding: utf-8 -*-
+"""
+    sphinx.ext.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.
+"""
+
+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')

tests/root/conf.py

 # modify tags from conf.py
 tags.add('confpytag')
 
+# -- linkcode
+
+if 'test_linkcode' in tags:
+    import glob
+
+    extensions.remove('sphinx.ext.viewcode')
+    extensions.append('sphinx.ext.linkcode')
+
+    exclude_patterns.extend(glob.glob('*.txt') + glob.glob('*/*.txt'))
+    exclude_patterns.remove('contents.txt')
+    exclude_patterns.remove('objects.txt')
+
+    def linkcode_resolve(domain, info):
+        if domain == 'py':
+            fn = info['module'].replace('.', '/')
+            return "http://foobar/source/%s.py" % fn
+        elif domain == "js":
+            return "http://foobar/js/" + info['fullname']
+        elif domain in ("c", "cpp"):
+            return "http://foobar/%s/%s" % (domain,  "".join(info['names']))
+        else:
+            raise AssertionError()
 
 # -- extension API
 

tests/test_linkcode.py

+# -*- coding: utf-8 -*-
+"""
+    test_linkcode
+    ~~~~~~~~~~~~~
+
+    Test the sphinx.ext.linkcode extension.
+
+    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import os
+from util import *
+
+@with_app(srcdir='(temp)', buildername='html', tags=['test_linkcode'])
+def test_html(app):
+    app.builder.build_all()
+
+    fp = open(os.path.join(app.outdir, 'objects.html'), 'rb')
+    try:
+        stuff = fp.read()
+    finally:
+        fp.close()
+
+    assert 'http://foobar/source/foolib.py' in stuff
+    assert 'http://foobar/js/' in stuff
+    assert 'http://foobar/c/' in stuff
+    assert 'http://foobar/cpp/' in stuff
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.