diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index c3cf0eec7..ce10f1228 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -495,20 +495,11 @@ class IntersphinxRole(SphinxRole): location=(self.env.docname, self.lineno)) return [], [] - # extract inventory specification - inventory = None - if self.text.startswith('\\:'): - # escaped :, so not a real inventory specification - self.text = self.text[1:] - elif self.text[0] == ':': # format: :inv:normalRoleArg - inventory = self.text.split(':')[1] - self.text = self.text[(len(inventory) + 2):] - result, messages = self.invoke_role(role_name) for node in result: if isinstance(node, pending_xref): node['intersphinx'] = True - node['inventory'] = inventory + node['inventory'] = None return result, messages @@ -574,8 +565,11 @@ class IntersphinxRoleResolver(ReferencesResolver): else: newnode = resolve_reference_any_inventory(self.env, False, node, contnode) if newnode is None: - # no warning, the normal missing_reference handler will do that - pass + typ = node['reftype'] + msg = (__('external %s:%s reference target not found: %s') % + (node['refdomain'], typ, node['reftarget'])) + logger.warning(msg, location=node, type='ref', subtype=typ) + node.replace_self(contnode) else: node.replace_self(newnode) diff --git a/tests/roots/test-ext-intersphinx-role/index.rst b/tests/roots/test-ext-intersphinx-role/index.rst index 164f2cfd4..bb7a6c4f1 100644 --- a/tests/roots/test-ext-intersphinx-role/index.rst +++ b/tests/roots/test-ext-intersphinx-role/index.rst @@ -1,26 +1,21 @@ -:external:py:mod:`module1` -:external:py:mod:`inv:module2` +- ``module1`` is only defined in ``inv``: + :external:py:mod:`module1` -.. py:module:: module1 +.. py:module:: module2 -:external:py:func:`func` -:external:py:func:`inv:func` -:external:py:meth:`Foo.bar` -:external:py:meth:`inv:Foo.bar` +- ``module2`` is defined here and also in ``inv``, but should resolve to inv: + :external:py:mod:`module2` -:external:c:func:`CFunc` -:external:c:func:`inv:CFunc` -:external:doc:`docname` -:external:doc:`inv:docname` -:external:option:`ls -l` -:external:option:`inv:ls -l` +- ``module3`` is not defined anywhere, so should warn: + :external:py:mod:`module3` -.. cpp:type:: std::uint8_t -.. cpp:class:: foo::Bar +.. py:module:: module10 -:external:cpp:type:`std::uint8_t` -:external:cpp:class:`inv:foo::Bar` -:external:cpp:func:`:inv2:foo::Bar::baz` +- ``module10`` is only defined here, but should still not be resolved to: + :external:py:mod:`module10` -:external:cpp:type:`FoonsTitle ` -:external:cpp:type:`inv:BarType ` \ No newline at end of file + +- a function in inv: + :external:py:func:`module1.func` +- a method, but with old style inventory prefix, which shouldn't work: + :external:py:meth:`inv:Foo.bar` diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index a1118e48d..ec2aad440 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -527,7 +527,7 @@ def test_inspect_main_url(capsys): @pytest.mark.sphinx('html', testroot='ext-intersphinx-role') -def test_intersphinx_role(app): +def test_intersphinx_role(app, warning): inv_file = app.srcdir / 'inventory' inv_file.write_bytes(inventory_v2) app.config.intersphinx_mapping = { @@ -542,21 +542,13 @@ def test_intersphinx_role(app): app.build() content = (app.outdir / 'index.html').read_text() + wStr = warning.getvalue() - targets = ( - 'foo.html#module-module1', - 'foo.html#module-module2', - 'sub/foo.html#module1.func', - 'index.html#foo.Bar.baz', - 'cfunc.html#CFunc', - 'docname.html', - 'index.html#cmdoption-ls-l', - 'index.html#std_uint8_t', - 'index.html#foons', - 'index.html#foons_bartype', - ) html = '' - for t in targets: - assert html.format(t) in content + assert html.format('foo.html#module-module1') in content + assert html.format('foo.html#module-module2') in content + assert "WARNING: external py:mod reference target not found: module3" in wStr + assert "WARNING: external py:mod reference target not found: module10" in wStr - assert html.format('index.html#cpp_foo_bar_baz') not in content + assert html.format('sub/foo.html#module1.func') in content + assert "WARNING: external py:meth reference target not found: inv:Foo.bar" in wStr