Skip to content

Commit 350ef53

Browse files
committed
intersphinx: Allow strict prefix matching
Strictly using prefix for intersphinx links gives a better control on external links - only links explicitely declared will point to the external documentation. Fixes #2068
1 parent c817c20 commit 350ef53

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

doc/usage/extensions/intersphinx.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ linking:
148148
exception is raised if the server has not issued a response for timeout
149149
seconds.
150150

151+
.. confval:: intersphinx_strict_prefix
152+
153+
.. versionadded:: 4.0.0
154+
155+
Turn on strict matching of references in Sphinx - all intersphinx links
156+
needs to have a prefix. This disables looking up the non-prefixed targets in
157+
intersphinx and will fail the build if such target is not present.
158+
159+
.. hint::
160+
161+
Strictly using prefix for intersphinx links gives a better control on
162+
external links - only links explicitely declared will point to the
163+
external documentation.
164+
151165

152166
Showing all links of an Intersphinx mapping file
153167
------------------------------------------------

sphinx/ext/intersphinx.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ def missing_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref,
314314
full_qualified_name = env.get_domain(domain).get_full_qualified_name(node)
315315
if full_qualified_name:
316316
to_try.append((inventories.named_inventory[setname], full_qualified_name))
317+
elif app.config.intersphinx_strict_prefix:
318+
return None
317319
for inventory, target in to_try:
318320
for objtype in objtypes:
319321
if objtype not in inventory or target not in inventory[objtype]:
@@ -379,6 +381,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
379381
app.add_config_value('intersphinx_mapping', {}, True)
380382
app.add_config_value('intersphinx_cache_limit', 5, False)
381383
app.add_config_value('intersphinx_timeout', None, False)
384+
app.add_config_value('intersphinx_strict_prefix', False, True)
382385
app.connect('config-inited', normalize_intersphinx_mapping, priority=800)
383386
app.connect('builder-inited', load_mappings)
384387
app.connect('missing-reference', missing_reference)
@@ -399,6 +402,7 @@ def inspect_main(argv: List[str]) -> None:
399402

400403
class MockConfig:
401404
intersphinx_timeout = None # type: int
405+
intersphinx_strict_prefix = False
402406
tls_verify = False
403407
user_agent = None
404408

tests/test_ext_intersphinx.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def test_missing_reference(tempdir, app, status, warning):
9797
'py3krelparent': ('../../py3k', inv_file), # relative path, parent dir
9898
}
9999
app.config.intersphinx_cache_limit = 0
100+
app.config.intersphinx_strict_prefix = False
100101

101102
# load the inventory and check if it's done correctly
102103
normalize_intersphinx_mapping(app, app.config)
@@ -165,6 +166,13 @@ def test_missing_reference(tempdir, app, status, warning):
165166
rn = reference_check(app, 'std', 'doc', 'docname', 'docname')
166167
assert rn['refuri'] == 'https://docs.python.org/docname.html'
167168

169+
# check resolution when strict prefix is enabled
170+
app.config.intersphinx_strict_prefix = True
171+
rn = reference_check(app, 'py', 'func', 'module1.func', 'foo')
172+
assert rn is None
173+
rn = reference_check(app, 'py', 'func', 'py3k:module1.func', 'foo')
174+
assert rn is not None
175+
168176

169177
def test_missing_reference_pydomain(tempdir, app, status, warning):
170178
inv_file = tempdir / 'inventory'
@@ -173,6 +181,7 @@ def test_missing_reference_pydomain(tempdir, app, status, warning):
173181
'https://docs.python.org/': inv_file,
174182
}
175183
app.config.intersphinx_cache_limit = 0
184+
app.config.intersphinx_strict_prefix = False
176185

177186
# load the inventory and check if it's done correctly
178187
normalize_intersphinx_mapping(app, app.config)
@@ -212,6 +221,7 @@ def test_missing_reference_stddomain(tempdir, app, status, warning):
212221
'cmd': ('https://docs.python.org/', inv_file),
213222
}
214223
app.config.intersphinx_cache_limit = 0
224+
app.config.intersphinx_strict_prefix = False
215225

216226
# load the inventory and check if it's done correctly
217227
normalize_intersphinx_mapping(app, app.config)
@@ -244,6 +254,7 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning):
244254
'https://docs.python.org/': inv_file,
245255
}
246256
app.config.intersphinx_cache_limit = 0
257+
app.config.intersphinx_strict_prefix = False
247258

248259
# load the inventory and check if it's done correctly
249260
normalize_intersphinx_mapping(app, app.config)
@@ -271,6 +282,7 @@ def test_missing_reference_jsdomain(tempdir, app, status, warning):
271282
'https://docs.python.org/': inv_file,
272283
}
273284
app.config.intersphinx_cache_limit = 0
285+
app.config.intersphinx_strict_prefix = False
274286

275287
# load the inventory and check if it's done correctly
276288
normalize_intersphinx_mapping(app, app.config)
@@ -297,6 +309,7 @@ def test_inventory_not_having_version(tempdir, app, status, warning):
297309
'https://docs.python.org/': inv_file,
298310
}
299311
app.config.intersphinx_cache_limit = 0
312+
app.config.intersphinx_strict_prefix = False
300313

301314
# load the inventory and check if it's done correctly
302315
normalize_intersphinx_mapping(app, app.config)
@@ -326,6 +339,7 @@ def test_load_mappings_warnings(tempdir, app, status, warning):
326339
}
327340

328341
app.config.intersphinx_cache_limit = 0
342+
app.config.intersphinx_strict_prefix = False
329343
# load the inventory and check if it's done correctly
330344
normalize_intersphinx_mapping(app, app.config)
331345
load_mappings(app)
@@ -336,6 +350,7 @@ def test_load_mappings_fallback(tempdir, app, status, warning):
336350
inv_file = tempdir / 'inventory'
337351
inv_file.write_bytes(inventory_v2)
338352
app.config.intersphinx_cache_limit = 0
353+
app.config.intersphinx_strict_prefix = False
339354

340355
# connect to invalid path
341356
app.config.intersphinx_mapping = {

0 commit comments

Comments
 (0)