summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Lykke Andersen <Jakob@caput.dk>2021-11-06 14:02:37 +0100
committerJakob Lykke Andersen <Jakob@caput.dk>2022-01-16 09:48:06 +0100
commit029d0e5b1837de4e33ee92cbb88d650e9afb8a3d (patch)
tree9679b10175ee3dfd5bac87eab743b4d818e95b11
parentce5512e3afc5d4a4af084aef8f622b01ffee5c2b (diff)
downloadsphinx-git-029d0e5b1837de4e33ee92cbb88d650e9afb8a3d.tar.gz
intersphinx role: new inventory parsing from role name
-rw-r--r--sphinx/ext/intersphinx.py42
-rw-r--r--tests/roots/test-ext-intersphinx-role/index.rst25
-rw-r--r--tests/test_ext_intersphinx.py17
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