Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intersphinx: Allow strict prefix matching #8981

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/usage/extensions/intersphinx.rst
Expand Up @@ -148,6 +148,20 @@ linking:
exception is raised if the server has not issued a response for timeout
seconds.

.. confval:: intersphinx_strict_prefix

.. versionadded:: 4.0.0

Turn on strict matching of references in Sphinx - all intersphinx links
needs to have a prefix. This disables looking up the non-prefixed targets in
intersphinx and will fail the build if such target is not present.

.. hint::

Strictly using prefix for intersphinx links gives a better control on
external links - only links explicitely declared will point to the
external documentation.


Showing all links of an Intersphinx mapping file
------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions sphinx/ext/intersphinx.py
Expand Up @@ -303,6 +303,8 @@ def missing_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref,
full_qualified_name = env.get_domain(domain).get_full_qualified_name(node)
if full_qualified_name:
to_try.append((inventories.named_inventory[setname], full_qualified_name))
elif app.config.intersphinx_strict_prefix:
return None
for inventory, target in to_try:
for objtype in objtypes:
if objtype not in inventory or target not in inventory[objtype]:
Expand Down Expand Up @@ -368,6 +370,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_strict_prefix', False, True)
app.connect('config-inited', normalize_intersphinx_mapping, priority=800)
app.connect('builder-inited', load_mappings)
app.connect('missing-reference', missing_reference)
Expand All @@ -388,6 +391,7 @@ def inspect_main(argv: List[str]) -> None:

class MockConfig:
intersphinx_timeout: int = None
intersphinx_strict_prefix: bool = False
tls_verify = False
user_agent = None

Expand Down
15 changes: 15 additions & 0 deletions tests/test_ext_intersphinx.py
Expand Up @@ -97,6 +97,7 @@ def test_missing_reference(tempdir, app, status, warning):
'py3krelparent': ('../../py3k', inv_file), # relative path, parent dir
}
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False

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

# check resolution when strict prefix is enabled
app.config.intersphinx_strict_prefix = True
rn = reference_check(app, 'py', 'func', 'module1.func', 'foo')
assert rn is None
rn = reference_check(app, 'py', 'func', 'py3k:module1.func', 'foo')
assert rn is not None


def test_missing_reference_pydomain(tempdir, app, status, warning):
inv_file = tempdir / 'inventory'
Expand All @@ -173,6 +181,7 @@ def test_missing_reference_pydomain(tempdir, app, status, warning):
'https://docs.python.org/': inv_file,
}
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this initialization needed? I think the configuration is initialized as False by default. So this assignment is not needed. I understand setting it up explicitly in test_missing_reference. But I don't understand why are they added in other cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't work without that. Unfortunately, I have no clue how this works in the tests...


# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
Expand Down Expand Up @@ -204,6 +213,7 @@ def test_missing_reference_stddomain(tempdir, app, status, warning):
'cmd': ('https://docs.python.org/', inv_file),
}
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
Expand Down Expand Up @@ -236,6 +246,7 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning):
'https://docs.python.org/': inv_file,
}
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
Expand Down Expand Up @@ -263,6 +274,7 @@ def test_missing_reference_jsdomain(tempdir, app, status, warning):
'https://docs.python.org/': inv_file,
}
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
Expand All @@ -289,6 +301,7 @@ def test_inventory_not_having_version(tempdir, app, status, warning):
'https://docs.python.org/': inv_file,
}
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
Expand Down Expand Up @@ -318,6 +331,7 @@ def test_load_mappings_warnings(tempdir, app, status, warning):
}

app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False
# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
load_mappings(app)
Expand All @@ -328,6 +342,7 @@ def test_load_mappings_fallback(tempdir, app, status, warning):
inv_file = tempdir / 'inventory'
inv_file.write_bytes(inventory_v2)
app.config.intersphinx_cache_limit = 0
app.config.intersphinx_strict_prefix = False

# connect to invalid path
app.config.intersphinx_mapping = {
Expand Down