diff options
Diffstat (limited to 'sphinx/ext/intersphinx.py')
-rw-r--r-- | sphinx/ext/intersphinx.py | 94 |
1 files changed, 54 insertions, 40 deletions
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index c3adf563..6f3d44eb 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -27,27 +27,28 @@ import time import zlib import codecs -import urllib2 import posixpath from os import path import re +from six import iteritems +from six.moves.urllib import request from docutils import nodes from docutils.utils import relative_path +import sphinx from sphinx.locale import _ from sphinx.builders.html import INVENTORY_FILENAME -from sphinx.util.pycompat import b -handlers = [urllib2.ProxyHandler(), urllib2.HTTPRedirectHandler(), - urllib2.HTTPHandler()] +handlers = [request.ProxyHandler(), request.HTTPRedirectHandler(), + request.HTTPHandler()] try: - handlers.append(urllib2.HTTPSHandler) + handlers.append(request.HTTPSHandler) except AttributeError: pass -urllib2.install_opener(urllib2.build_opener(*handlers)) +request.install_opener(request.build_opener(*handlers)) UTF8StreamReader = codecs.lookup('utf-8')[2] @@ -55,9 +56,9 @@ UTF8StreamReader = codecs.lookup('utf-8')[2] def read_inventory_v1(f, uri, join): f = UTF8StreamReader(f) invdata = {} - line = f.next() + line = next(f) projname = line.rstrip()[11:] - line = f.next() + line = next(f) version = line.rstrip()[11:] for line in f: name, type, location = line.rstrip().split(None, 2) @@ -85,19 +86,19 @@ def read_inventory_v2(f, uri, join, bufsize=16*1024): def read_chunks(): decompressor = zlib.decompressobj() - for chunk in iter(lambda: f.read(bufsize), b('')): + for chunk in iter(lambda: f.read(bufsize), b''): yield decompressor.decompress(chunk) yield decompressor.flush() def split_lines(iter): - buf = b('') + buf = b'' for chunk in iter: buf += chunk - lineend = buf.find(b('\n')) + lineend = buf.find(b'\n') while lineend != -1: yield buf[:lineend].decode('utf-8') buf = buf[lineend+1:] - lineend = buf.find(b('\n')) + lineend = buf.find(b'\n') assert not buf for line in split_lines(read_chunks()): @@ -129,10 +130,10 @@ def fetch_inventory(app, uri, inv): join = localuri and path.join or posixpath.join try: if inv.find('://') != -1: - f = urllib2.urlopen(inv) + f = request.urlopen(inv) else: f = open(path.join(app.srcdir, inv), 'rb') - except Exception, err: + except Exception as err: app.warn('intersphinx inventory %r not fetchable due to ' '%s: %s' % (inv, err.__class__, err)) return @@ -149,7 +150,7 @@ def fetch_inventory(app, uri, inv): except ValueError: f.close() raise ValueError('unknown or unsupported inventory version') - except Exception, err: + except Exception as err: app.warn('intersphinx inventory %r not readable due to ' '%s: %s' % (inv, err.__class__.__name__, err)) else: @@ -167,7 +168,7 @@ def load_mappings(app): env.intersphinx_named_inventory = {} cache = env.intersphinx_cache update = False - for key, value in app.config.intersphinx_mapping.iteritems(): + for key, value in iteritems(app.config.intersphinx_mapping): if isinstance(value, tuple): # new format name, (uri, inv) = key, value @@ -179,19 +180,25 @@ def load_mappings(app): # 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][1] < cache_time: - app.info('loading intersphinx inventory from %s...' % inv) - invdata = fetch_inventory(app, uri, inv) - if invdata: - cache[uri] = (name, now, invdata) - else: - cache.pop(uri, None) - update = True + if not isinstance(inv, tuple): + invs = (inv, ) + else: + invs = inv + + for inv in invs: + 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][1] < cache_time: + app.info('loading intersphinx inventory from %s...' % inv) + invdata = fetch_inventory(app, uri, inv) + if invdata: + cache[uri] = (name, now, invdata) + update = True + break + if update: env.intersphinx_inventory = {} env.intersphinx_named_inventory = {} @@ -202,28 +209,34 @@ def load_mappings(app): # add the unnamed inventories last. This means that the # unnamed inventories will shadow the named ones but the named # ones can still be accessed when the name is specified. - cached_vals = list(cache.itervalues()) + cached_vals = list(cache.values()) named_vals = sorted(v for v in cached_vals if v[0]) unnamed_vals = [v for v in cached_vals if not v[0]] for name, _, invdata in named_vals + unnamed_vals: if name: env.intersphinx_named_inventory[name] = invdata - for type, objects in invdata.iteritems(): + for type, objects in iteritems(invdata): env.intersphinx_inventory.setdefault( type, {}).update(objects) def missing_reference(app, env, node, contnode): """Attempt to resolve a missing reference via intersphinx references.""" - domain = node.get('refdomain') - if not domain: - # only objects in domains are in the inventory - return target = node['reftarget'] - objtypes = env.domains[domain].objtypes_for_role(node['reftype']) - if not objtypes: - return - objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes] + if node['reftype'] == 'any': + # we search anything! + objtypes = ['%s:%s' % (domain.name, objtype) + for domain in env.domains.values() + for objtype in domain.object_types] + else: + domain = node.get('refdomain') + if not domain: + # only objects in domains are in the inventory + return + objtypes = env.domains[domain].objtypes_for_role(node['reftype']) + if not objtypes: + return + objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes] to_try = [(env.intersphinx_inventory, target)] in_set = None if ':' in target: @@ -241,7 +254,7 @@ def missing_reference(app, env, node, contnode): # get correct path in case of subdirectories uri = path.join(relative_path(node['refdoc'], env.srcdir), uri) newnode = nodes.reference('', '', internal=False, refuri=uri, - reftitle=_('(in %s v%s)') % (proj, version)) + reftitle=_('(in %s v%s)') % (proj, version)) if node.get('refexplicit'): # use whatever title was given newnode.append(contnode) @@ -269,3 +282,4 @@ def setup(app): app.add_config_value('intersphinx_cache_limit', 5, False) app.connect('missing-reference', missing_reference) app.connect('builder-inited', load_mappings) + return {'version': sphinx.__version__, 'parallel_read_safe': True} |