mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add intersphinx extension.
This commit is contained in:
parent
b4f71aa642
commit
b4c78df0a2
4
CHANGES
4
CHANGES
@ -4,6 +4,10 @@ Release 0.5 (in development)
|
||||
New features added
|
||||
------------------
|
||||
|
||||
* The new extension ``sphinx.ext.intersphinx`` half-automatically
|
||||
creates links to Sphinx documentation of Python objects in other
|
||||
projects.
|
||||
|
||||
* Added a distutils command `build_sphinx`: When Sphinx is installed,
|
||||
you can call ``python setup.py build_sphinx`` for projects that
|
||||
have Sphinx documentation, which will build the docs and place them
|
||||
|
67
doc/ext/intersphinx.rst
Normal file
67
doc/ext/intersphinx.rst
Normal file
@ -0,0 +1,67 @@
|
||||
:mod:`sphinx.ext.intersphinx` -- Link to other projects' documentation
|
||||
======================================================================
|
||||
|
||||
.. module:: sphinx.ext.intersphinx
|
||||
:synopsis: Link to other Sphinx documentation.
|
||||
|
||||
.. index:: pair: automatic; linking
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
This extension can generate automatic links to the documentation of Python
|
||||
objects in other projects. This works as follows:
|
||||
|
||||
* Each Sphinx HTML build creates a file named :file:`objects.inv` that
|
||||
contains a mapping from Python identifiers to URIs relative to the HTML set's
|
||||
root.
|
||||
|
||||
* Projects using the Intersphinx extension can specify the location of such
|
||||
mapping files in the :confval:`intersphinx_mapping` config value. The mapping
|
||||
will then be used to resolve otherwise missing references to Python objects
|
||||
into links to the other documentation.
|
||||
|
||||
* By default, the mapping file is assumed to be at the same location as the rest
|
||||
of the documentation; however, the location of the mapping file can also be
|
||||
specified individually, e.g. if the docs should be buildable without Internet
|
||||
access.
|
||||
|
||||
To use intersphinx linking, add ``'sphinx.ext.intersphinx'`` to your
|
||||
:confval:`extensions` config value, and use these new config values to activate
|
||||
linking:
|
||||
|
||||
.. confval:: intersphinx_mapping
|
||||
|
||||
A dictionary mapping URIs to either ``None`` or an URI. The keys are the
|
||||
base URI of the foreign Sphinx documentation sets and can be local paths or
|
||||
HTTP URIs. The values indicate where the inventory file can be found: they
|
||||
can be ``None`` (at the same location as the base URI) or another local or
|
||||
HTTP URI.
|
||||
|
||||
Relative local paths in the keys are taken as relative to the base of the
|
||||
built documentation, while relative local paths in the values are taken as
|
||||
relative to the source directory.
|
||||
|
||||
An example, to add links to modules and objects in the Python standard
|
||||
library documentation::
|
||||
|
||||
intersphinx_mapping = {'http://docs.python.org/dev': None}
|
||||
|
||||
This will download the corresponding :file:`objects.inv` file from the
|
||||
Internet and generate links to the pages under the given URI. The downloaded
|
||||
inventory is cached in the Sphinx environment, so it must be redownloaded
|
||||
whenever you do a full rebuild.
|
||||
|
||||
A second example, showing the meaning of a non-``None`` value::
|
||||
|
||||
intersphinx_mapping = {'http://docs.python.org/dev': 'python-inv.txt'}
|
||||
|
||||
This will read the inventory from :file:`python.inv` in the source
|
||||
directory, but still generate links to the pages under
|
||||
``http://docs.python.org/dev``. It is up to you to update the inventory file
|
||||
as new objects are added to the Python documentation.
|
||||
|
||||
.. confval:: intersphinx_cache_limit
|
||||
|
||||
The maximum number of days to cache remote inventories. The default is
|
||||
``5``, meaning five days. Set this to a negative value to cache inventories
|
||||
for unlimited time.
|
@ -34,6 +34,7 @@ These extensions are built in and can be activated by respective entries in the
|
||||
|
||||
ext/autodoc
|
||||
ext/doctest
|
||||
ext/intersphinx
|
||||
ext/refcounting
|
||||
ext/ifconfig
|
||||
ext/coverage
|
||||
|
@ -40,7 +40,7 @@ from sphinx import directives
|
||||
|
||||
ENV_PICKLE_FILENAME = 'environment.pickle'
|
||||
LAST_BUILD_FILENAME = 'last_build'
|
||||
INVENTORY_FILENAME = 'inventory.txt'
|
||||
INVENTORY_FILENAME = 'objects.inv'
|
||||
|
||||
|
||||
class Builder(object):
|
||||
|
141
sphinx/ext/intersphinx.py
Normal file
141
sphinx/ext/intersphinx.py
Normal file
@ -0,0 +1,141 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.ext.intersphinx
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Insert links to Python objects documented in remote Sphinx documentation.
|
||||
|
||||
This works as follows:
|
||||
|
||||
* Each Sphinx HTML build creates a file named "objects.inv" that contains
|
||||
a mapping from Python identifiers to URIs relative to the HTML set's root.
|
||||
|
||||
* Projects using the Intersphinx extension can specify links to such mapping
|
||||
files in the `intersphinx_mapping` config value. The mapping will then be
|
||||
used to resolve otherwise missing references to Python objects into links
|
||||
to the other documentation.
|
||||
|
||||
* By default, the mapping file is assumed to be at the same location as the
|
||||
rest of the documentation; however, the location of the mapping file can
|
||||
also be specified individually, e.g. if the docs should be buildable
|
||||
without Internet access.
|
||||
|
||||
:copyright: 2008 by Georg Brandl.
|
||||
:license: BSD.
|
||||
"""
|
||||
|
||||
import time
|
||||
import urllib
|
||||
import posixpath
|
||||
from os import path
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.builder import INVENTORY_FILENAME
|
||||
|
||||
|
||||
def fetch_inventory(app, uri, inv):
|
||||
"""Fetch, parse and return an intersphinx inventory file."""
|
||||
invdata = {}
|
||||
# both *uri* (base URI of the links to generate) and *inv* (actual
|
||||
# location of the inventory file) can be local or remote URIs
|
||||
localuri = uri.find('://') == -1
|
||||
try:
|
||||
if inv.find('://') != -1:
|
||||
f = urllib.urlopen(inv)
|
||||
else:
|
||||
f = open(path.join(app.srcdir, inv))
|
||||
except Exception, err:
|
||||
app.warn('intersphinx inventory %r not fetchable due to '
|
||||
'%s: %s' % (inv, err.__class__, err))
|
||||
return
|
||||
try:
|
||||
line = f.next()
|
||||
if line.rstrip() != '# Sphinx inventory version 1':
|
||||
raise ValueError('unknown or unsupported inventory version')
|
||||
line = f.next()
|
||||
projname = line.rstrip()[11:].decode('utf-8')
|
||||
line = f.next()
|
||||
version = line.rstrip()[11:]
|
||||
for line in f:
|
||||
name, type, location = line.rstrip().split(None, 2)
|
||||
if localuri:
|
||||
location = path.join(uri, location)
|
||||
else:
|
||||
location = posixpath.join(uri, location)
|
||||
invdata[name] = (type, projname, version, location)
|
||||
f.close()
|
||||
except Exception, err:
|
||||
app.warn('intersphinx inventory %r not readable due to '
|
||||
'%s: %s' % (inv, err.__class__, err))
|
||||
else:
|
||||
return invdata
|
||||
|
||||
|
||||
def load_mappings(app):
|
||||
"""Load all intersphinx mappings into the environment."""
|
||||
now = int(time.time())
|
||||
cache_time = now - app.config.intersphinx_cache_limit * 86400
|
||||
env = app.builder.env
|
||||
if not hasattr(env, 'intersphinx_cache'):
|
||||
env.intersphinx_cache = {}
|
||||
cache = env.intersphinx_cache
|
||||
update = False
|
||||
for uri, inv in app.config.intersphinx_mapping.iteritems():
|
||||
# we can safely assume that the uri<->inv mapping is not changed
|
||||
# during partial rebuilds since a changed intersphinx_mapping
|
||||
# setting will cause a full environment reread
|
||||
if not inv:
|
||||
inv = posixpath.join(uri, INVENTORY_FILENAME)
|
||||
# decide whether the inventory must be read: always read local
|
||||
# files; remote ones only if the cache time is expired
|
||||
if '://' not in inv or uri not in cache \
|
||||
or cache[uri][0] < cache_time:
|
||||
invdata = fetch_inventory(app, uri, inv)
|
||||
cache[uri] = (now, invdata)
|
||||
update = True
|
||||
if update:
|
||||
env.intersphinx_inventory = {}
|
||||
for _, invdata in cache.itervalues():
|
||||
if invdata:
|
||||
env.intersphinx_inventory.update(invdata)
|
||||
|
||||
|
||||
def missing_reference(app, env, node, contnode):
|
||||
"""Attempt to resolve a missing reference via intersphinx references."""
|
||||
type = node['reftype']
|
||||
target = node['reftarget']
|
||||
if type == 'mod':
|
||||
type, proj, version, uri = env.intersphinx_inventory.get(target,
|
||||
('','','',''))
|
||||
if type != 'mod':
|
||||
return None
|
||||
target = 'module-' + target # for link anchor
|
||||
else:
|
||||
if target[-2:] == '()':
|
||||
target = target[:-2]
|
||||
target = target.rstrip(' *')
|
||||
# special case: exceptions and object methods
|
||||
if type == 'exc' and '.' not in target and \
|
||||
'exceptions.' + target in env.intersphinx_inventory:
|
||||
target = 'exceptions.' + target
|
||||
elif type in ('func', 'meth') and '.' not in target and \
|
||||
'object.' + target in env.intersphinx_inventory:
|
||||
target = 'object.' + target
|
||||
if target not in env.intersphinx_inventory:
|
||||
return None
|
||||
type, proj, version, uri = env.intersphinx_inventory[target]
|
||||
print "Intersphinx hit:", target, uri
|
||||
newnode = nodes.reference('', '')
|
||||
newnode['refuri'] = uri + '#' + target
|
||||
newnode['reftitle'] = '(in %s v%s)' % (proj, version)
|
||||
newnode['class'] = 'external-xref'
|
||||
newnode.append(contnode)
|
||||
return newnode
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_config_value('intersphinx_mapping', {}, True)
|
||||
app.add_config_value('intersphinx_cache_limit', 5, False)
|
||||
app.connect('missing-reference', missing_reference)
|
||||
app.connect('builder-inited', load_mappings)
|
Loading…
Reference in New Issue
Block a user