summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Lykke Andersen <Jakob@caput.dk>2021-10-02 11:12:49 +0200
committerJakob Lykke Andersen <Jakob@caput.dk>2021-10-31 13:15:47 +0100
commit0d9f4cd469b3664319bc2d5da74cfae4bc0da9ec (patch)
treea34f4572be78576928c66bd394d6eeb85cd16836
parent84238dfd391c2c6a0fd79f993f1bf5d512ba8410 (diff)
downloadsphinx-git-0d9f4cd469b3664319bc2d5da74cfae4bc0da9ec.tar.gz
Generalize to disable specific refs as well.
-rw-r--r--CHANGES5
-rw-r--r--doc/usage/extensions/intersphinx.rst31
-rw-r--r--sphinx/ext/intersphinx.py39
-rw-r--r--tests/test_ext_intersphinx.py38
4 files changed, 73 insertions, 40 deletions
diff --git a/CHANGES b/CHANGES
index b43d19604..ed64716c4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -50,6 +50,11 @@ Features added
* #2068, add :confval:`intersphinx_disabled_domains` for disabling
interphinx resolution of cross-references in specific domains when they
do not have an explicit inventory specification.
+* #2068, add :confval:`intersphinx_disabled_refs` for disabling
+ interphinx resolution of cross-references that do not have an explicit
+ inventory specification. Specific types of cross-references can be disabled,
+ e.g., ``std:doc`` or all cross-references in a specific domain,
+ e.g., ``std``.
Bugs fixed
----------
diff --git a/doc/usage/extensions/intersphinx.rst b/doc/usage/extensions/intersphinx.rst
index fb00dc667..c9075a42d 100644
--- a/doc/usage/extensions/intersphinx.rst
+++ b/doc/usage/extensions/intersphinx.rst
@@ -148,21 +148,28 @@ linking:
exception is raised if the server has not issued a response for timeout
seconds.
-.. confval:: intersphinx_disabled_domains
+.. confval:: intersphinx_disabled_refs
- .. versionadded:: 4.2
+ .. versionadded:: 4.3
+
+ A list of strings being either:
+
+ - the name of a specific reference type,
+ e.g., ``std:doc``, ``py:func``, or ``cpp:class``,
+ - the name of a whole domain, e.g., ``std``, ``py``, or ``cpp``, or
+ - the special name ``all``.
- A list of strings being the name of a domain, or the special name ``all``.
When a cross-reference without an explicit inventory specification is being
- resolved by intersphinx, skip resolution if either the domain of the
- cross-reference is in this list or the special name ``all`` is in the list.
-
- For example, with ``intersphinx_disabled_domains = ['std']`` a cross-reference
- ``:doc:`installation``` will not be attempted to be resolved by intersphinx, but
- ``:doc:`otherbook:installation``` will be attempted to be resolved in the
- inventory named ``otherbook`` in :confval:`intersphinx_mapping`.
- At the same time, all cross-references generated in, e.g., Python, declarations
- will still be attempted to be resolved by intersphinx.
+ resolved by intersphinx, skip resolution it matches one of the
+ specifications in this list.
+
+ For example, with ``intersphinx_disabled_refs = ['std:doc']``
+ a cross-reference ``:doc:`installation``` will not be attempted to be
+ resolved by intersphinx, but ``:doc:`otherbook:installation``` will be
+ attempted to be resolved in the inventory named ``otherbook`` in
+ :confval:`intersphinx_mapping`.
+ At the same time, all cross-references generated in, e.g., Python,
+ declarations will still be attempted to be resolved by intersphinx.
If ``all`` is in the list of domains, then no references without an explicit
inventory will be resolved by intersphinx.
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py
index 7764390ee..9a41421ea 100644
--- a/sphinx/ext/intersphinx.py
+++ b/sphinx/ext/intersphinx.py
@@ -321,7 +321,9 @@ def _resolve_reference_in_domain_by_target(
return None
-def _resolve_reference_in_domain(inv_name: Optional[str], inventory: Inventory,
+def _resolve_reference_in_domain(env: BuildEnvironment,
+ inv_name: Optional[str], inventory: Inventory,
+ honor_disabled_refs: bool,
domain: Domain, objtypes: List[str],
node: pending_xref, contnode: TextElement
) -> Optional[Element]:
@@ -336,6 +338,11 @@ def _resolve_reference_in_domain(inv_name: Optional[str], inventory: Inventory,
# the inventory contains domain:type as objtype
objtypes = ["{}:{}".format(domain.name, t) for t in objtypes]
+ # now that the objtypes list is complete we can remove the disabled ones
+ if honor_disabled_refs:
+ disabled = env.config.intersphinx_disabled_refs
+ objtypes = [o for o in objtypes if o not in disabled]
+
# without qualification
res = _resolve_reference_in_domain_by_target(inv_name, inventory, domain, objtypes,
node['reftarget'], node, contnode)
@@ -351,22 +358,23 @@ def _resolve_reference_in_domain(inv_name: Optional[str], inventory: Inventory,
def _resolve_reference(env: BuildEnvironment, inv_name: Optional[str], inventory: Inventory,
- honor_disabled_domains: bool,
+ honor_disabled_refs: bool,
node: pending_xref, contnode: TextElement) -> Optional[Element]:
# disabling should only be done if no inventory is given
- honor_disabled_domains = honor_disabled_domains and inv_name is None
+ honor_disabled_refs = honor_disabled_refs and inv_name is None
- if honor_disabled_domains and 'all' in env.config.intersphinx_disabled_domains:
+ if honor_disabled_refs and 'all' in env.config.intersphinx_disabled_refs:
return None
typ = node['reftype']
if typ == 'any':
for domain_name, domain in env.domains.items():
- if honor_disabled_domains \
- and domain_name in env.config.intersphinx_disabled_domains:
+ if honor_disabled_refs \
+ and domain_name in env.config.intersphinx_disabled_refs:
continue
objtypes = list(domain.object_types)
- res = _resolve_reference_in_domain(inv_name, inventory,
+ res = _resolve_reference_in_domain(env, inv_name, inventory,
+ honor_disabled_refs,
domain, objtypes,
node, contnode)
if res is not None:
@@ -377,14 +385,15 @@ def _resolve_reference(env: BuildEnvironment, inv_name: Optional[str], inventory
if not domain_name:
# only objects in domains are in the inventory
return None
- if honor_disabled_domains \
- and domain_name in env.config.intersphinx_disabled_domains:
+ if honor_disabled_refs \
+ and domain_name in env.config.intersphinx_disabled_refs:
return None
domain = env.get_domain(domain_name)
objtypes = domain.objtypes_for_role(typ)
if not objtypes:
return None
- return _resolve_reference_in_domain(inv_name, inventory,
+ return _resolve_reference_in_domain(env, inv_name, inventory,
+ honor_disabled_refs,
domain, objtypes,
node, contnode)
@@ -409,7 +418,7 @@ def resolve_reference_in_inventory(env: BuildEnvironment,
def resolve_reference_any_inventory(env: BuildEnvironment,
- honor_disabled_domains: bool,
+ honor_disabled_refs: bool,
node: pending_xref, contnode: TextElement
) -> Optional[Element]:
"""Attempt to resolve a missing reference via intersphinx references.
@@ -417,12 +426,12 @@ def resolve_reference_any_inventory(env: BuildEnvironment,
Resolution is tried with the target as is in any inventory.
"""
return _resolve_reference(env, None, InventoryAdapter(env).main_inventory,
- honor_disabled_domains,
+ honor_disabled_refs,
node, contnode)
def resolve_reference_detect_inventory(env: BuildEnvironment,
- honor_disabled_domains: bool,
+ honor_disabled_refs: bool,
node: pending_xref, contnode: TextElement
) -> Optional[Element]:
"""Attempt to resolve a missing reference via intersphinx references.
@@ -434,7 +443,7 @@ def resolve_reference_detect_inventory(env: BuildEnvironment,
"""
# ordinary direct lookup, use data as is
- res = resolve_reference_any_inventory(env, honor_disabled_domains, node, contnode)
+ res = resolve_reference_any_inventory(env, honor_disabled_refs, node, contnode)
if res is not None:
return res
@@ -486,7 +495,7 @@ def setup(app: 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.add_config_value('intersphinx_disabled_domains', [], True)
+ app.add_config_value('intersphinx_disabled_refs', [], True)
app.connect('config-inited', normalize_intersphinx_mapping, priority=800)
app.connect('builder-inited', load_mappings)
app.connect('missing-reference', missing_reference)
diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py
index 6856c6e62..0ffea0d5f 100644
--- a/tests/test_ext_intersphinx.py
+++ b/tests/test_ext_intersphinx.py
@@ -45,7 +45,7 @@ def reference_check(app, *args, **kwds):
def set_config(app, mapping):
app.config.intersphinx_mapping = mapping
app.config.intersphinx_cache_limit = 0
- app.config.intersphinx_disabled_domains = []
+ app.config.intersphinx_disabled_refs = []
@mock.patch('sphinx.ext.intersphinx.InventoryFile')
@@ -303,7 +303,7 @@ def test_missing_reference_disabled_domain(tempdir, app, status, warning):
normalize_intersphinx_mapping(app, app.config)
load_mappings(app)
- def case(std_without, std_with, py_without, py_with):
+ def case(*, term, doc, py):
def assert_(rn, expected):
if expected is None:
assert rn is None
@@ -312,34 +312,46 @@ def test_missing_reference_disabled_domain(tempdir, app, status, warning):
kwargs = {}
+ node, contnode = fake_node('std', 'term', 'a term', 'a term', **kwargs)
+ rn = missing_reference(app, app.env, node, contnode)
+ assert_(rn, 'a term' if term else None)
+
+ node, contnode = fake_node('std', 'term', 'inv:a term', 'a term', **kwargs)
+ rn = missing_reference(app, app.env, node, contnode)
+ assert_(rn, 'a term')
+
node, contnode = fake_node('std', 'doc', 'docname', 'docname', **kwargs)
rn = missing_reference(app, app.env, node, contnode)
- assert_(rn, std_without)
+ assert_(rn, 'docname' if doc else None)
node, contnode = fake_node('std', 'doc', 'inv:docname', 'docname', **kwargs)
rn = missing_reference(app, app.env, node, contnode)
- assert_(rn, std_with)
+ assert_(rn, 'docname')
# an arbitrary ref in another domain
node, contnode = fake_node('py', 'func', 'module1.func', 'func()', **kwargs)
rn = missing_reference(app, app.env, node, contnode)
- assert_(rn, py_without)
+ assert_(rn, 'func()' if py else None)
node, contnode = fake_node('py', 'func', 'inv:module1.func', 'func()', **kwargs)
rn = missing_reference(app, app.env, node, contnode)
- assert_(rn, py_with)
+ assert_(rn, 'func()')
# the base case, everything should resolve
- assert app.config.intersphinx_disabled_domains == []
- case('docname', 'docname', 'func()', 'func()')
+ assert app.config.intersphinx_disabled_refs == []
+ case(term=True, doc=True, py=True)
+
+ # disabled a single ref type
+ app.config.intersphinx_disabled_refs = ['std:doc']
+ case(term=True, doc=False, py=True)
- # disabled one domain
- app.config.intersphinx_disabled_domains = ['std']
- case(None, 'docname', 'func()', 'func()')
+ # disabled a whole domain
+ app.config.intersphinx_disabled_refs = ['std']
+ case(term=False, doc=False, py=True)
# disabled all domains
- app.config.intersphinx_disabled_domains = ['all']
- case(None, 'docname', None, 'func()')
+ app.config.intersphinx_disabled_refs = ['all']
+ case(term=False, doc=False, py=False)
@pytest.mark.xfail(os.name != 'posix', reason="Path separator mismatch issue")