Skip to content

Commit 88a338a

Browse files
committed
Intersphinx inventories: add loading-time warning when ambiguous name definitions exist.
1 parent ab78182 commit 88a338a

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

sphinx/util/inventory.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import zlib
77
from typing import IO, TYPE_CHECKING, Callable
88

9+
from sphinx.locale import __
910
from sphinx.util import logging
1011

1112
BUFSIZE = 16 * 1024
@@ -86,19 +87,23 @@ def load(
8687
reader = InventoryFileReader(stream)
8788
line = reader.readline().rstrip()
8889
if line == '# Sphinx inventory version 1':
89-
return cls.load_v1(reader, uri, joinfunc)
90+
invdata, ambiguities = cls.load_v1(reader, uri, joinfunc)
9091
elif line == '# Sphinx inventory version 2':
91-
return cls.load_v2(reader, uri, joinfunc)
92+
invdata, ambiguities = cls.load_v2(reader, uri, joinfunc)
9293
else:
9394
raise ValueError('invalid inventory header: %s' % line)
95+
for ambiguity in ambiguities:
96+
logger.warning(__("inventory <%s> contains multiple definitions for %s"),
97+
uri, ambiguity, type='intersphinx', subtype='external')
98+
return invdata
9499

95100
@classmethod
96101
def load_v1(
97102
cls: type[InventoryFile],
98103
stream: InventoryFileReader,
99104
uri: str,
100105
join: Callable[[str, str], str],
101-
) -> Inventory:
106+
) -> tuple[Inventory, set]:
102107
invdata: Inventory = {}
103108
projname = stream.readline().rstrip()[11:]
104109
version = stream.readline().rstrip()[11:]
@@ -113,18 +118,20 @@ def load_v1(
113118
type = 'py:' + type
114119
location += '#' + name
115120
invdata.setdefault(type, {})[name] = (projname, version, location, '-')
116-
return invdata
121+
return invdata, frozenset()
117122

118123
@classmethod
119124
def load_v2(
120125
cls: type[InventoryFile],
121126
stream: InventoryFileReader,
122127
uri: str,
123128
join: Callable[[str, str], str],
124-
) -> Inventory:
129+
) -> tuple[Inventory, set]:
125130
invdata: Inventory = {}
126131
projname = stream.readline().rstrip()[11:]
127132
version = stream.readline().rstrip()[11:]
133+
potential_ambiguities = set()
134+
actual_ambiguities = set()
128135
line = stream.readline()
129136
if 'zlib' not in line:
130137
raise ValueError('invalid inventory header (not compressed): %s' % line)
@@ -147,12 +154,20 @@ def load_v2(
147154
# for Python modules, and the first
148155
# one is correct
149156
continue
157+
if type in {'std:label', 'std:term'}:
158+
# Some types require case insensitive matches:
159+
# * 'term': https://github.com/sphinx-doc/sphinx/issues/9291
160+
# * 'label': https://github.com/sphinx-doc/sphinx/issues/12008
161+
if name.lower() in potential_ambiguities:
162+
actual_ambiguities.add(f"{type}:{name}")
163+
else:
164+
potential_ambiguities.add(name.lower())
150165
if location.endswith('$'):
151166
location = location[:-1] + name
152167
location = join(uri, location)
153168
inv_item: InventoryItem = projname, version, location, dispname
154169
invdata.setdefault(type, {})[name] = inv_item
155-
return invdata
170+
return invdata, actual_ambiguities
156171

157172
@classmethod
158173
def dump(

tests/test_util/test_util_inventory.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from tests.test_util.intersphinx_data import (
1111
INVENTORY_V1,
1212
INVENTORY_V2,
13+
INVENTORY_V2_AMBIGUOUS_TERMS,
1314
INVENTORY_V2_NO_VERSION,
1415
)
1516

@@ -48,6 +49,13 @@ def test_read_inventory_v2_not_having_version():
4849
('foo', '', '/util/foo.html#module-module1', 'Long Module desc')
4950

5051

52+
def test_ambiguous_definition_warning(warning):
53+
f = BytesIO(INVENTORY_V2_AMBIGUOUS_TERMS)
54+
invdata = InventoryFile.load(f, '/util', posixpath.join)
55+
56+
assert 'contains multiple definitions for std:term:a' in warning.getvalue().lower()
57+
58+
5159
def _write_appconfig(dir, language, prefix=None):
5260
prefix = prefix or language
5361
os.makedirs(dir / prefix, exist_ok=True)

0 commit comments

Comments
 (0)