diff options
author | Jakob Lykke Andersen <Jakob@caput.dk> | 2021-11-06 14:02:37 +0100 |
---|---|---|
committer | Jakob Lykke Andersen <Jakob@caput.dk> | 2022-01-16 09:48:06 +0100 |
commit | 029d0e5b1837de4e33ee92cbb88d650e9afb8a3d (patch) | |
tree | 9679b10175ee3dfd5bac87eab743b4d818e95b11 | |
parent | ce5512e3afc5d4a4af084aef8f622b01ffee5c2b (diff) | |
download | sphinx-git-029d0e5b1837de4e33ee92cbb88d650e9afb8a3d.tar.gz |
intersphinx role: new inventory parsing from role name
-rw-r--r-- | sphinx/ext/intersphinx.py | 42 | ||||
-rw-r--r-- | tests/roots/test-ext-intersphinx-role/index.rst | 25 | ||||
-rw-r--r-- | tests/test_ext_intersphinx.py | 17 |
3 files changed, 71 insertions, 13 deletions
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index ce10f1228..2c640925b 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -489,9 +489,15 @@ class IntersphinxDispatcher(CustomReSTDispatcher): class IntersphinxRole(SphinxRole): def run(self) -> Tuple[List[Node], List[system_message]]: - role_name = self.get_role_name(self.name) + inventory, name_suffix = self.get_inventory_and_name_suffix(self.name) + if inventory and not inventory_exists(self.env, inventory): + logger.warning(__('inventory for external cross-reference not found: %s'), inventory, + location=(self.env.docname, self.lineno)) + return [], [] + + role_name = self.get_role_name(name_suffix) if role_name is None: - logger.warning(__('role not found: %s'), self.name, + logger.warning(__('role for external cross-reference not found: %s'), name_suffix, location=(self.env.docname, self.lineno)) return [], [] @@ -499,20 +505,33 @@ class IntersphinxRole(SphinxRole): for node in result: if isinstance(node, pending_xref): node['intersphinx'] = True - node['inventory'] = None + node['inventory'] = inventory return result, messages + def get_inventory_and_name_suffix(self, name: str) -> Tuple[Optional[str], Optional[str]]: + assert name.startswith('external:'), name + name = name[9:] + inv_names = name.split('+') + inventory = None + if len(inv_names) > 1: + # inv+role + # inv+domain:role + inventory = inv_names[0] + name = name[len(inventory)+1:] + return inventory, name + def get_role_name(self, name: str) -> Optional[Tuple[str, str]]: names = name.split(':') - if len(names) == 2: - # :external:role: - domain = self.env.temp_data.get('default_domain') + if len(names) == 1: + # role + default_domain = self.env.temp_data.get('default_domain') + domain = default_domain.name if default_domain else None + role = names[0] + elif len(names) == 2: + # domain:role: + domain = names[0] role = names[1] - elif len(names) == 3: - # :external:domain:role: - domain = names[1] - role = names[2] else: return None @@ -559,8 +578,7 @@ class IntersphinxRoleResolver(ReferencesResolver): contnode = cast(nodes.TextElement, node[0].deepcopy()) inv_name = node['inventory'] if inv_name is not None: - if not inventory_exists(self.env, inv_name): - continue + assert inventory_exists(self.env, inv_name) newnode = resolve_reference_in_inventory(self.env, inv_name, node, contnode) else: newnode = resolve_reference_any_inventory(self.env, False, node, contnode) diff --git a/tests/roots/test-ext-intersphinx-role/index.rst b/tests/roots/test-ext-intersphinx-role/index.rst index bb7a6c4f1..5c2cdbd00 100644 --- a/tests/roots/test-ext-intersphinx-role/index.rst +++ b/tests/roots/test-ext-intersphinx-role/index.rst @@ -14,8 +14,31 @@ - ``module10`` is only defined here, but should still not be resolved to: :external:py:mod:`module10` - - 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` +- a non-existing role: + :external:py:nope:`something` + +.. default-domain:: cpp + +- a type where the default domain is used to find the role: + :external:type:`std::uint8_t` +- a non-existing role in default domain: + :external:nope:`somethingElse` + +- two roles in ``std`` which can be found without a default domain: + + - :external:doc:`docname` + - :external:option:`ls -l` + + +- a function with explicit inventory: + :external:inv+c:func:`CFunc` +- a class with explicit non-existing inventory, which also has upper-case in name: + :external:invNope+cpp:class:`foo::Bar` + + +- explicit title: + :external:cpp:type:`FoonsTitle <foons>` diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index ec2aad440..11450e2c3 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -552,3 +552,20 @@ def test_intersphinx_role(app, warning): assert html.format('sub/foo.html#module1.func') in content assert "WARNING: external py:meth reference target not found: inv:Foo.bar" in wStr + + assert "WARNING: role for external cross-reference not found: py:nope" in wStr + + # default domain + assert html.format('index.html#std_uint8_t') in content + assert "WARNING: role for external cross-reference not found: nope" in wStr + + # std roles without domain prefix + assert html.format('docname.html') in content + assert html.format('index.html#cmdoption-ls-l') in content + + # explicit inventory + assert html.format('cfunc.html#CFunc') in content + #assert "WARNING: inventory for external cross-reference not found: invNope" in wStr + + # explicit title + assert html.format('index.html#foons') in content |