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

Rename normalize_intersphinx_mapping to validate_intersphinx_mapping #12643

Merged
merged 1 commit into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ Incompatible changes
Deprecated
----------

* #12643: Renamed ``sphinx.ext.intersphinx.normalize_intersphinx_mapping``
to ``sphinx.ext.intersphinx.validate_intersphinx_mapping``.
The old name will be removed in Sphinx 10.
Patch by Adam Turner.

Features added
--------------

Expand Down
5 changes: 5 additions & 0 deletions doc/extdev/deprecated.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ The following is a list of deprecated interfaces.
- Removed
- Alternatives

* - ``sphinx.ext.intersphinx.normalize_intersphinx_mapping``
- 8.0
- 10.0
- ``sphinx.ext.intersphinx.validate_intersphinx_mapping``

* - ``sphinx.testing.util.strip_escseq``
- 7.3
- 9.0
Expand Down
28 changes: 25 additions & 3 deletions sphinx/ext/intersphinx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
'fetch_inventory',
'fetch_inventory_group',
'load_mappings',
'normalize_intersphinx_mapping',
'validate_intersphinx_mapping',
'IntersphinxRoleResolver',
'inventory_exists',
'install_dispatcher',
Expand All @@ -44,7 +44,7 @@
fetch_inventory,
fetch_inventory_group,
load_mappings,
normalize_intersphinx_mapping,
validate_intersphinx_mapping,
)
from sphinx.ext.intersphinx._resolve import (
IntersphinxDispatcher,
Expand All @@ -69,7 +69,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
app.add_config_value('intersphinx_cache_limit', 5, '')
app.add_config_value('intersphinx_timeout', None, '')
app.add_config_value('intersphinx_disabled_reftypes', ['std:doc'], 'env')
app.connect('config-inited', normalize_intersphinx_mapping, priority=800)
app.connect('config-inited', validate_intersphinx_mapping, priority=800)
app.connect('builder-inited', load_mappings)
app.connect('source-read', install_dispatcher)
app.connect('missing-reference', missing_reference)
Expand All @@ -79,3 +79,25 @@ def setup(app: Sphinx) -> ExtensionMetadata:
'env_version': 1,
'parallel_read_safe': True,
}


# deprecated name -> (object to return, canonical path or empty string, removal version)
_DEPRECATED_OBJECTS: dict[str, tuple[object, str, tuple[int, int]]] = {
'normalize_intersphinx_mapping': (
validate_intersphinx_mapping,
'sphinx.ext.intersphinx.validate_intersphinx_mapping',
(10, 0),
),
}


def __getattr__(name: str) -> object:
if name not in _DEPRECATED_OBJECTS:
msg = f'module {__name__!r} has no attribute {name!r}'
raise AttributeError(msg)

from sphinx.deprecation import _deprecation_warning

deprecated_object, canonical_name, remove = _DEPRECATED_OBJECTS[name]
_deprecation_warning(__name__, name, canonical_name, remove=remove)
return deprecated_object
13 changes: 12 additions & 1 deletion sphinx/ext/intersphinx/_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,18 @@
from sphinx.util.typing import Inventory


def normalize_intersphinx_mapping(app: Sphinx, config: Config) -> None:
def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
"""Validate and normalise :confval:`intersphinx_mapping`.

Ensure that:

* Keys are non-empty strings.
* Values are two-element tuples or lists.
* The first element of each value pair (the target URI)
is a non-empty string.
* The second element of each value pair (inventory locations)
is a tuple of non-empty strings or None.
"""
# URIs should NOT be duplicated, otherwise different builds may use
# different project names (and thus, the build are no more reproducible)
# depending on which one is inserted last in the cache.
Expand Down
4 changes: 2 additions & 2 deletions tests/test_builders/test_build_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from sphinx.builders.latex import default_latex_documents
from sphinx.config import Config
from sphinx.errors import SphinxError
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.ext.intersphinx import load_mappings, validate_intersphinx_mapping
from sphinx.ext.intersphinx import setup as intersphinx_setup
from sphinx.util.osutil import ensuredir
from sphinx.writers.latex import LaTeXTranslator
Expand Down Expand Up @@ -133,7 +133,7 @@ def test_build_latex_doc(app, engine, docclass, python_maximum_signature_line_le
app.config.latex_table_style = ['booktabs']
elif engine == 'lualatex':
app.config.latex_table_style = ['colorrows']
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)
app.builder.init()
LaTeXTranslator.ignore_missing_images = True
Expand Down
4 changes: 2 additions & 2 deletions tests/test_domains/test_domain_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from sphinx.domains.c._ids import _id_prefix, _macroKeywords, _max_id
from sphinx.domains.c._parser import DefinitionParser
from sphinx.domains.c._symbol import Symbol
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.ext.intersphinx import load_mappings, validate_intersphinx_mapping
from sphinx.testing import restructuredtext
from sphinx.testing.util import assert_node
from sphinx.util.cfamily import DefinitionError
Expand Down Expand Up @@ -775,7 +775,7 @@ def test_domain_c_build_intersphinx(tmp_path, app, status, warning):
}
app.config.intersphinx_cache_limit = 0
# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build(force_all=True)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_domains/test_domain_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from sphinx.domains.cpp._ids import _id_prefix, _max_id
from sphinx.domains.cpp._parser import DefinitionParser
from sphinx.domains.cpp._symbol import Symbol
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.ext.intersphinx import load_mappings, validate_intersphinx_mapping
from sphinx.testing import restructuredtext
from sphinx.testing.util import assert_node
from sphinx.util.cfamily import DefinitionError, NoOldIdError
Expand Down Expand Up @@ -1428,7 +1428,7 @@ def test_domain_cpp_build_intersphinx(tmp_path, app, status, warning):
}
app.config.intersphinx_cache_limit = 0
# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build(force_all=True)
Expand Down
6 changes: 3 additions & 3 deletions tests/test_extensions/test_ext_inheritance_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
InheritanceException,
import_classes,
)
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.ext.intersphinx import load_mappings, validate_intersphinx_mapping


@pytest.mark.sphinx(buildername="html", testroot="inheritance")
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_inheritance_diagram_png_html(tmp_path, app):
'example': ('https://example.org', str(inv_file)),
}
app.config.intersphinx_cache_limit = 0
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build(force_all=True)
Expand Down Expand Up @@ -204,7 +204,7 @@ def test_inheritance_diagram_svg_html(tmp_path, app):
"subdir": ('https://example.org', str(inv_file)),
}
app.config.intersphinx_cache_limit = 0
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build(force_all=True)
Expand Down
30 changes: 15 additions & 15 deletions tests/test_extensions/test_ext_intersphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
inspect_main,
load_mappings,
missing_reference,
normalize_intersphinx_mapping,
validate_intersphinx_mapping,
)
from sphinx.ext.intersphinx import setup as intersphinx_setup
from sphinx.ext.intersphinx._load import _get_safe_url, _strip_basic_auth
Expand Down Expand Up @@ -117,7 +117,7 @@ def test_missing_reference(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)
inv = app.env.intersphinx_inventory

Expand Down Expand Up @@ -192,7 +192,7 @@ def test_missing_reference_pydomain(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

# no context data
Expand Down Expand Up @@ -222,7 +222,7 @@ def test_missing_reference_stddomain(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

# no context data
Expand Down Expand Up @@ -272,7 +272,7 @@ def test_ambiguous_reference_warning(tmp_path, app, warning):
})

# load the inventory
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

# term reference (case insensitive)
Expand All @@ -291,7 +291,7 @@ def test_missing_reference_cppdomain(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build()
Expand All @@ -317,7 +317,7 @@ def test_missing_reference_jsdomain(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

# no context data
Expand All @@ -341,7 +341,7 @@ def test_missing_reference_disabled_domain(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

def case(*, term, doc, py):
Expand Down Expand Up @@ -403,7 +403,7 @@ def test_inventory_not_having_version(tmp_path, app, status, warning):
})

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

rn = reference_check(app, 'py', 'mod', 'module1', 'foo')
Expand All @@ -413,8 +413,8 @@ def test_inventory_not_having_version(tmp_path, app, status, warning):
assert rn[0].astext() == 'Long Module desc'


def test_normalize_intersphinx_mapping_warnings(app, warning):
"""Check warnings in :func:`sphinx.ext.intersphinx.normalize_intersphinx_mapping`."""
def test_validate_intersphinx_mapping_warnings(app, warning):
"""Check warnings in :func:`sphinx.ext.intersphinx.validate_intersphinx_mapping`."""
bad_intersphinx_mapping = {
# fmt: off
'': ('789.example', None), # invalid project name (value)
Expand Down Expand Up @@ -445,7 +445,7 @@ def test_normalize_intersphinx_mapping_warnings(app, warning):
ConfigError,
match=r'^Invalid `intersphinx_mapping` configuration \(16 errors\).$',
):
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
warnings = strip_colors(warning.getvalue()).splitlines()
assert len(warnings) == len(bad_intersphinx_mapping) - 3
assert warnings == [
Expand Down Expand Up @@ -477,7 +477,7 @@ def test_load_mappings_fallback(tmp_path, app, status, warning):
app.config.intersphinx_mapping = {
'fallback': ('https://docs.python.org/py3k/', '/invalid/inventory/path'),
}
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)
assert "failed to reach any of the inventories" in warning.getvalue()

Expand All @@ -493,7 +493,7 @@ def test_load_mappings_fallback(tmp_path, app, status, warning):
'fallback': ('https://docs.python.org/py3k/', ('/invalid/inventory/path',
str(inv_file))),
}
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)
assert "encountered some issues with some of the inventories" in status.getvalue()
assert warning.getvalue() == ""
Expand Down Expand Up @@ -610,7 +610,7 @@ def test_intersphinx_role(app, warning):
app.config.nitpicky = True

# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_extensions/test_ext_napoleon_docstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import pytest

from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.ext.intersphinx import load_mappings, validate_intersphinx_mapping
from sphinx.ext.napoleon import Config
from sphinx.ext.napoleon.docstring import (
GoogleDocstring,
Expand Down Expand Up @@ -2679,7 +2679,7 @@ def test_napoleon_keyword_and_paramtype(app, tmp_path):
int py:class 1 int.html -
''')) # NoQA: W291
app.config.intersphinx_mapping = {'python': ('127.0.0.1:5555', str(inv_file))}
normalize_intersphinx_mapping(app, app.config)
validate_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build(force_all=True)
Expand Down