diff options
Diffstat (limited to 'sphinx/ext/intersphinx.py')
-rw-r--r-- | sphinx/ext/intersphinx.py | 114 |
1 files changed, 51 insertions, 63 deletions
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index e190cf0f1..859eacf13 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ sphinx.ext.intersphinx ~~~~~~~~~~~~~~~~~~~~~~ @@ -24,23 +23,18 @@ :license: BSD, see LICENSE for details. """ -from __future__ import print_function - import functools import posixpath import sys import time -import warnings from os import path +from urllib.parse import urlsplit, urlunsplit from docutils import nodes from docutils.utils import relative_path -from six import PY3, iteritems, string_types -from six.moves.urllib.parse import urlsplit, urlunsplit import sphinx from sphinx.builders.html import INVENTORY_FILENAME -from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.locale import _, __ from sphinx.util import requests, logging from sphinx.util.inventory import InventoryFile @@ -51,16 +45,12 @@ if False: from sphinx.application import Sphinx # NOQA from sphinx.config import Config # NOQA from sphinx.environment import BuildEnvironment # NOQA - - if PY3: - unicode = str - - Inventory = Dict[unicode, Dict[unicode, Tuple[unicode, unicode, unicode, unicode]]] + from sphinx.util.typing import Inventory # NOQA logger = logging.getLogger(__name__) -class InventoryAdapter(object): +class InventoryAdapter: """Inventory adapter for environment""" def __init__(self, env): @@ -74,7 +64,7 @@ class InventoryAdapter(object): @property def cache(self): - # type: () -> Dict[unicode, Tuple[unicode, int, Inventory]] + # type: () -> Dict[str, Tuple[str, int, Inventory]] return self.env.intersphinx_cache # type: ignore @property @@ -84,7 +74,7 @@ class InventoryAdapter(object): @property def named_inventory(self): - # type: () -> Dict[unicode, Inventory] + # type: () -> Dict[str, Inventory] return self.env.intersphinx_named_inventory # type: ignore def clear(self): @@ -94,7 +84,7 @@ class InventoryAdapter(object): def _strip_basic_auth(url): - # type: (unicode) -> unicode + # type: (str) -> str """Returns *url* with basic auth credentials removed. Also returns the basic auth username and password if they're present in *url*. @@ -116,7 +106,7 @@ def _strip_basic_auth(url): def _read_from_url(url, config=None): - # type: (unicode, Config) -> IO + # type: (str, Config) -> IO """Reads data from *url* with an HTTP *GET*. This function supports fetching from resources which use basic HTTP auth as @@ -142,7 +132,7 @@ def _read_from_url(url, config=None): def _get_safe_url(url): - # type: (unicode) -> unicode + # type: (str) -> str """Gets version of *url* with basic auth passwords obscured. This function returns results suitable for printing and logging. @@ -168,7 +158,7 @@ def _get_safe_url(url): def fetch_inventory(app, uri, inv): - # type: (Sphinx, unicode, Any) -> Any + # type: (Sphinx, str, Any) -> Any """Fetch, parse and return an intersphinx inventory file.""" # both *uri* (base URI of the links to generate) and *inv* (actual # location of the inventory file) can be local or remote URIs @@ -214,28 +204,7 @@ def load_mappings(app): cache_time = now - app.config.intersphinx_cache_limit * 86400 inventories = InventoryAdapter(app.builder.env) update = False - for key, value in iteritems(app.config.intersphinx_mapping): - name = None # type: unicode - uri = None # type: unicode - inv = None # type: Union[unicode, Tuple[unicode, ...]] - - if isinstance(value, (list, tuple)): - # new format - name, (uri, inv) = key, value - if not isinstance(name, string_types): - logger.warning(__('intersphinx identifier %r is not string. Ignored'), name) - continue - else: - # old format, no name - name, uri, inv = None, key, value - # 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 isinstance(inv, tuple): - invs = (inv, ) - else: - invs = inv # type: ignore - + for key, (name, (uri, invs)) in app.config.intersphinx_mapping.items(): failures = [] for inv in invs: if not inv: @@ -244,7 +213,7 @@ def load_mappings(app): # files; remote ones only if the cache time is expired if '://' not in inv or uri not in inventories.cache \ or inventories.cache[uri][1] < cache_time: - safe_inv_url = _get_safe_url(inv) # type: ignore + safe_inv_url = _get_safe_url(inv) logger.info('loading intersphinx inventory from %s...', safe_inv_url) try: invdata = fetch_inventory(app, uri, inv) @@ -286,16 +255,16 @@ def load_mappings(app): for name, _x, invdata in named_vals + unnamed_vals: if name: inventories.named_inventory[name] = invdata - for type, objects in iteritems(invdata): + for type, objects in invdata.items(): inventories.main_inventory.setdefault(type, {}).update(objects) def missing_reference(app, env, node, contnode): - # type: (Sphinx, BuildEnvironment, nodes.Node, nodes.Node) -> None + # type: (Sphinx, BuildEnvironment, nodes.Element, nodes.TextElement) -> nodes.reference """Attempt to resolve a missing reference via intersphinx references.""" target = node['reftarget'] inventories = InventoryAdapter(env) - objtypes = None # type: List[unicode] + objtypes = None # type: List[str] if node['reftype'] == 'any': # we search anything! objtypes = ['%s:%s' % (domain.name, objtype) @@ -306,10 +275,10 @@ def missing_reference(app, env, node, contnode): domain = node.get('refdomain') if not domain: # only objects in domains are in the inventory - return + return None objtypes = env.get_domain(domain).objtypes_for_role(node['reftype']) if not objtypes: - return + return None objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes] if 'std:cmdoption' in objtypes: # until Sphinx-1.6, cmdoptions are stored as std:option @@ -365,14 +334,42 @@ def missing_reference(app, env, node, contnode): if len(contnode) and isinstance(contnode[0], nodes.Text): contnode[0] = nodes.Text(newtarget, contnode[0].rawsource) + return None + + +def normalize_intersphinx_mapping(app, config): + # type: (Sphinx, Config) -> None + for key, value in config.intersphinx_mapping.copy().items(): + try: + if isinstance(value, (list, tuple)): + # new format + name, (uri, inv) = key, value + if not isinstance(name, str): + logger.warning(__('intersphinx identifier %r is not string. Ignored'), + name) + config.intersphinx_mapping.pop(key) + continue + else: + # old format, no name + name, uri, inv = None, key, value + + if not isinstance(inv, tuple): + config.intersphinx_mapping[key] = (name, (uri, (inv,))) + else: + config.intersphinx_mapping[key] = (name, (uri, inv)) + except Exception as exc: + logger.warning(__('Fail to read intersphinx_mapping[%s], Ignored: %r'), key, exc) + config.intersphinx_mapping.pop(key) + def setup(app): - # type: (Sphinx) -> Dict[unicode, Any] + # type: (Sphinx) -> Dict[str, Any] app.add_config_value('intersphinx_mapping', {}, True) app.add_config_value('intersphinx_cache_limit', 5, False) app.add_config_value('intersphinx_timeout', None, False) - app.connect('missing-reference', missing_reference) + app.connect('config-inited', normalize_intersphinx_mapping) app.connect('builder-inited', load_mappings) + app.connect('missing-reference', missing_reference) return { 'version': sphinx.__display_version__, 'env_version': 1, @@ -380,17 +377,8 @@ def setup(app): } -def debug(argv): - # type: (List[unicode]) -> None - """Debug functionality to print out an inventory""" - warnings.warn('sphinx.ext.intersphinx.debug() is deprecated. ' - 'Please use inspect_main() instead', - RemovedInSphinx20Warning, stacklevel=2) - inspect_main(argv[1:]) - - def inspect_main(argv): - # type: (List[unicode]) -> None + # type: (List[str]) -> None """Debug functionality to print out an inventory""" if len(argv) < 1: print("Print out an inventory file.\n" @@ -398,16 +386,16 @@ def inspect_main(argv): file=sys.stderr) sys.exit(1) - class MockConfig(object): + class MockConfig: intersphinx_timeout = None # type: int tls_verify = False - class MockApp(object): + class MockApp: srcdir = '' config = MockConfig() def warn(self, msg): - # type: (unicode) -> None + # type: (str) -> None print(msg, file=sys.stderr) try: @@ -429,4 +417,4 @@ if __name__ == '__main__': import logging # type: ignore logging.basicConfig() # type: ignore - inspect_main(argv=sys.argv[1:]) # type: ignore + inspect_main(argv=sys.argv[1:]) |