diff --git a/CHANGES b/CHANGES index 2e4cd7796..05a5874d6 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,8 @@ Bugs fixed * #3952: apidoc: module header is too escaped * #4275: Formats accepted by sphinx.util.i18n.format_date are limited * #4493: recommonmark raises AttributeError if AutoStructify enabled +* #4209: intersphinx: In link title, "v" should be optional if target has no + version Testing -------- diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index b5b955ae8..7ec89ab7f 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -315,8 +315,11 @@ def missing_reference(app, env, node, contnode): if '://' not in uri and node.get('refdoc'): # get correct path in case of subdirectories uri = path.join(relative_path(node['refdoc'], '.'), uri) - newnode = nodes.reference('', '', internal=False, refuri=uri, - reftitle=_('(in %s v%s)') % (proj, version)) + if version: + reftitle = _('(in %s v%s)') % (proj, version) + else: + reftitle = _('(in %s)') % (proj,) + newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle=reftitle) if node.get('refexplicit'): # use whatever title was given newnode.append(contnode) diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index aef495d30..91e21187b 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -24,7 +24,7 @@ from sphinx.ext.intersphinx import ( load_mappings, missing_reference, _strip_basic_auth, _get_safe_url, fetch_inventory, INVENTORY_FILENAME, debug ) -from test_util_inventory import inventory_v2 +from test_util_inventory import inventory_v2, inventory_v2_not_having_version def fake_node(domain, type, target, content, **attrs): @@ -271,6 +271,25 @@ def test_missing_reference_jsdomain(tempdir, app, status, warning): assert rn.astext() == 'baz()' +@pytest.mark.xfail(os.name != 'posix', reason="Path separator mismatch issue") +def test_inventory_not_having_version(tempdir, app, status, warning): + inv_file = tempdir / 'inventory' + inv_file.write_bytes(inventory_v2_not_having_version) + app.config.intersphinx_mapping = { + 'https://docs.python.org/': inv_file, + } + app.config.intersphinx_cache_limit = 0 + + # load the inventory and check if it's done correctly + load_mappings(app) + + rn = reference_check(app, 'py', 'mod', 'module1', 'foo') + assert isinstance(rn, nodes.reference) + assert rn['refuri'] == 'https://docs.python.org/foo.html#module-module1' + assert rn['reftitle'] == '(in foo)' + assert rn[0].astext() == 'Long Module desc' + + def test_load_mappings_warnings(tempdir, app, status, warning): """ load_mappings issues a warning if new-style mapping diff --git a/tests/test_util_inventory.py b/tests/test_util_inventory.py index 3829de9ef..3d6c9f402 100644 --- a/tests/test_util_inventory.py +++ b/tests/test_util_inventory.py @@ -50,6 +50,15 @@ foo.bar.qux js:data 1 index.html#foo.bar.qux - a term including:colon std:term -1 glossary.html#term-a-term-including-colon - '''.encode('utf-8')) +inventory_v2_not_having_version = '''\ +# Sphinx inventory version 2 +# Project: foo +# Version: +# The remainder of this file is compressed with zlib. +'''.encode('utf-8') + zlib.compress('''\ +module1 py:module 0 foo.html#module-module1 Long Module desc +'''.encode('utf-8')) + def test_read_inventory_v1(): f = BytesIO(inventory_v1) @@ -76,3 +85,10 @@ def test_read_inventory_v2(): '/util/glossary.html#term-a-term' assert invdata['std:term']['a term including:colon'][2] == \ '/util/glossary.html#term-a-term-including-colon' + + +def test_read_inventory_v2_not_having_version(): + f = BytesIO(inventory_v2_not_having_version) + invdata = InventoryFile.load(f, '/util', posixpath.join) + assert invdata['py:module']['module1'] == \ + ('foo', '', '/util/foo.html#module-module1', 'Long Module desc')