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

Fix intersphinx cache handling #12087

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
e50c662
fix intersphinx cache loading in incremental builds
picnixz Oct 4, 2023
ca545a3
fix lint0
picnixz Oct 4, 2023
cfcb4f5
Remove debug print
picnixz Oct 5, 2023
9d436b3
Merge branch 'sphinx-doc:master' into fix/11466-intersphinx-inventory…
picnixz Oct 5, 2023
92243a4
save
picnixz Oct 5, 2023
37250f9
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Oct 9, 2023
4b1ac3f
Merge branch 'fix/11466-intersphinx-inventory-consistency' of github.…
picnixz Feb 3, 2024
4f8bb9e
Merge remote-tracking branch 'upstream/master' into fix/11466-intersp…
picnixz Feb 3, 2024
56f5533
update implementation and comments
picnixz Feb 3, 2024
5ef7919
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Feb 3, 2024
8bbcd83
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Feb 12, 2024
333886a
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Feb 13, 2024
ac22d65
update logic and refactor
picnixz Feb 13, 2024
822aa88
remove CHANGELOG entry until 8.x
picnixz Feb 14, 2024
6d60665
implement intersphinx new format
picnixz Feb 14, 2024
1e2b875
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Feb 14, 2024
760e4fc
cleanup
picnixz Feb 14, 2024
eea6a9d
cleanup 3.9
picnixz Feb 14, 2024
9cdd373
remove typing_extensions dependency
picnixz Feb 14, 2024
ae80634
cleanup comment
picnixz Feb 14, 2024
14836d4
Add typing
picnixz Mar 11, 2024
bb09f20
apply formatter
picnixz Mar 11, 2024
3466db0
deprecate intersphinx alpha format
picnixz Mar 11, 2024
7277f71
deprecate intersphinx alpha format
picnixz Mar 11, 2024
a6fdcec
upgrade tests
picnixz Mar 11, 2024
479a3fe
Update doc
picnixz Mar 11, 2024
a9dd038
Merge branch 'sphinx-doc:master' into core/deprecate-intersphinx-1-0
picnixz Mar 14, 2024
5e7c383
Merge branch 'sphinx-doc:master' into core/deprecate-intersphinx-1-0
picnixz Mar 14, 2024
f906314
fixup
picnixz Mar 14, 2024
ca22f10
Merge branch 'master' into core/deprecate-intersphinx-1-0
picnixz Mar 14, 2024
bdfb3e8
Merge branch 'sphinx-doc:master' into core/deprecate-intersphinx-1-0
picnixz Mar 14, 2024
d4b4227
Merge branch 'sphinx-doc:master' into fix/11466-intersphinx-inventory…
picnixz Mar 14, 2024
8c7894b
Update doc
picnixz Mar 11, 2024
128c324
fixup
picnixz Mar 14, 2024
1821d17
fixup
picnixz Mar 14, 2024
d95d046
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Mar 17, 2024
f824dc2
deprecate intersphinx alpha format
picnixz Mar 11, 2024
55effd8
upgrade tests
picnixz Mar 11, 2024
472eeab
Update doc
picnixz Mar 11, 2024
f98b47a
Merge branch 'master' into core/deprecate-intersphinx-1-0
picnixz Apr 27, 2024
7d3749d
Merge branch 'master' into core/deprecate-intersphinx-1-0
picnixz May 1, 2024
50c3988
Merge branch 'master' into core/deprecate-intersphinx-1-0
picnixz May 21, 2024
0dd0262
Merge remote-tracking branch 'upstream/master' into core/deprecate-in…
picnixz Jul 20, 2024
902016d
Merge remote-tracking branch 'upstream/master' into fix/11466-intersp…
picnixz Jul 20, 2024
7655ba5
Merge remote-tracking branch 'upstream/master' into fix/11466-intersp…
picnixz Jul 20, 2024
47c3383
remove debug
picnixz Jul 20, 2024
ddee17e
Merge branch 'core/deprecate-intersphinx-1-0' into fix/11466-intersph…
picnixz Jul 20, 2024
ad86c96
fixups
picnixz Jul 20, 2024
ba53d83
Merge branch 'master' into core/deprecate-intersphinx-1-0
AA-Turner Jul 21, 2024
3912820
raise a ConfigError
AA-Turner Jul 21, 2024
a28674a
Update test_ext_inheritance_diagram.py
picnixz Jul 21, 2024
864713b
Update sphinx/ext/intersphinx/_load.py
picnixz Jul 21, 2024
cfe69ba
Update sphinx/ext/intersphinx/_load.py
picnixz Jul 21, 2024
bea91dc
Update tests/test_extensions/test_ext_inheritance_diagram.py
picnixz Jul 21, 2024
8ada5cd
Better error messages
AA-Turner Jul 21, 2024
9dd36d1
Formatting
AA-Turner Jul 22, 2024
c33db5c
Explicit copy
AA-Turner Jul 22, 2024
35144c8
update ENV_VERSION
picnixz Jul 22, 2024
487099c
update ENV_VERSION
picnixz Jul 22, 2024
398ad43
Merge branch 'core/deprecate-intersphinx-1-0' into fix/11466-intersph…
picnixz Jul 22, 2024
7b4b3c5
Merge remote-tracking branch 'upstream/master' into fix/11466-intersp…
picnixz Jul 22, 2024
b0b25de
fixup
picnixz Jul 22, 2024
3b1126d
remove duplicated test
picnixz Jul 22, 2024
e1e6a11
update tests
picnixz Jul 22, 2024
91f1aa7
Merge remote-tracking branch 'upstream/master' into fix/11466-intersp…
picnixz Jul 22, 2024
5b9693e
update typing
picnixz Jul 22, 2024
bd423ff
fix some error messages
picnixz Jul 22, 2024
9d1f331
address Jay's review
picnixz Jul 22, 2024
1a1bee6
Merge remote-tracking branch 'upstream/master' into fix/11466-intersp…
picnixz Jul 22, 2024
ea91173
.
picnixz Jul 22, 2024
fe0c63a
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
picnixz Jul 22, 2024
f5c075b
revert style changes
picnixz Jul 22, 2024
bfe45f5
revert style changes
picnixz Jul 22, 2024
a90be51
address review
picnixz Jul 22, 2024
af2e689
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
AA-Turner Jul 22, 2024
124f1c1
Updates
AA-Turner Jul 22, 2024
7f9b7b0
Update sphinx/ext/intersphinx/_load.py
AA-Turner Jul 22, 2024
d77eaad
fix CI/CD
picnixz Jul 22, 2024
2ed2497
split tests
picnixz Jul 22, 2024
124e6b3
Merge branch 'master' into fix/11466-intersphinx-inventory-consistency
AA-Turner Jul 22, 2024
fab0e89
Update tests
AA-Turner Jul 22, 2024
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
120 changes: 65 additions & 55 deletions sphinx/ext/intersphinx/_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import functools
import posixpath
import time
from operator import itemgetter
from os import path
from typing import TYPE_CHECKING
from urllib.parse import urlsplit, urlunsplit
Expand Down Expand Up @@ -138,36 +139,41 @@ def load_mappings(app: Sphinx) -> None:
intersphinx_cache: dict[InventoryURI, InventoryCacheEntry] = inventories.cache
intersphinx_mapping: IntersphinxMapping = app.config.intersphinx_mapping

expected_uris = {uri for _name, (uri, _invs) in intersphinx_mapping.values()}

for uri in frozenset(intersphinx_cache):
if intersphinx_cache[uri][0] not in intersphinx_mapping:
# Remove all cached entries that are no longer in `intersphinx_mapping`.
del intersphinx_cache[uri]
elif uri not in expected_uris:
# Remove cached entries with a different target URI
# than the one in `intersphinx_mapping`.
# This happens when the URI in `intersphinx_mapping` is changed.
del intersphinx_cache[uri]

with concurrent.futures.ThreadPoolExecutor() as pool:
futures = []
for name, (uri, invs) in intersphinx_mapping.values():
futures.append(pool.submit(
fetch_inventory_group, name, uri, invs, intersphinx_cache, app, now,
))
futures = [
pool.submit(fetch_inventory_group, name, uri, invs, intersphinx_cache, app, now)
for name, (uri, invs) in app.config.intersphinx_mapping.values()
]
updated = [f.result() for f in concurrent.futures.as_completed(futures)]

if any(updated):
# clear the local inventories
inventories.clear()

# Duplicate values in different inventories will shadow each
# other; which one will override which can vary between builds
# since they are specified using an unordered dict. To make
# it more consistent, we sort the named inventories and then
# add the unnamed inventories last. This means that the
# unnamed inventories will shadow the named ones but the named
# ones can still be accessed when the name is specified.
named_vals = []
unnamed_vals = []
for name, _expiry, invdata in intersphinx_cache.values():
if name:
named_vals.append((name, invdata))
else:
unnamed_vals.append((name, invdata))
for name, invdata in sorted(named_vals) + unnamed_vals:
if name:
inventories.named_inventory[name] = invdata
for type, objects in invdata.items():
inventories.main_inventory.setdefault(type, {}).update(objects)
# other; which one will override which can vary between builds.
#
# In an attempt to make this more consistent,
# we sort the named inventories in the cache
# by their name and expiry time ``(NAME, EXPIRY)``.
by_name_and_time = itemgetter(0, 1) # 0: name, 1: expiry
cache_values = sorted(intersphinx_cache.values(), key=by_name_and_time)
picnixz marked this conversation as resolved.
Show resolved Hide resolved
for name, _expiry, invdata in cache_values:
picnixz marked this conversation as resolved.
Show resolved Hide resolved
inventories.named_inventory[name] = invdata
for objtype, objects in invdata.items():
inventories.main_inventory.setdefault(objtype, {}).update(objects)


def fetch_inventory_group(
Expand All @@ -179,39 +185,43 @@ def fetch_inventory_group(
now: int,
) -> bool:
cache_time = now - app.config.intersphinx_cache_limit * 86400

updated = False
failures = []
try:
for inv in invs:
if not inv:
inv = posixpath.join(uri, INVENTORY_FILENAME)
# decide whether the inventory must be read: always read local
# files; remote ones only if the cache time is expired
if '://' not in inv or uri not in cache or cache[uri][1] < cache_time:
safe_inv_url = _get_safe_url(inv)
inv_descriptor = name or 'main_inventory'
LOGGER.info(__("loading intersphinx inventory '%s' from %s..."),
inv_descriptor, safe_inv_url)
try:
invdata = fetch_inventory(app, uri, inv)
except Exception as err:
failures.append(err.args)
continue
if invdata:
cache[uri] = name, now, invdata
return True
return False
finally:
if not failures:
pass
elif len(failures) < len(invs):
LOGGER.info(__('encountered some issues with some of the inventories,'
' but they had working alternatives:'))
for fail in failures:
LOGGER.info(*fail)
else:
issues = '\n'.join(f[0] % f[1:] for f in failures)
LOGGER.warning(__('failed to reach any of the inventories '
'with the following issues:') + '\n' + issues)

for location in invs:
# location is either None or a non-empty string
inv = f'{uri}/{INVENTORY_FILENAME}' if location is None else location

# decide whether the inventory must be read: always read local
# files; remote ones only if the cache time is expired
if '://' not in inv or uri not in cache or cache[uri][1] < cache_time:
LOGGER.info(__("loading intersphinx inventory '%s' from %s ..."),
name, _get_safe_url(inv))

try:
invdata = fetch_inventory(app, uri, inv)
except Exception as err:
failures.append(err.args)
continue

if invdata:
cache[uri] = name, now, invdata
updated = True
break

if not failures:
pass
elif len(failures) < len(invs):
LOGGER.info(__('encountered some issues with some of the inventories,'
' but they had working alternatives:'))
for fail in failures:
LOGGER.info(*fail)
else:
issues = '\n'.join(f[0] % f[1:] for f in failures)
LOGGER.warning(__('failed to reach any of the inventories '
'with the following issues:') + '\n' + issues)
return updated


def fetch_inventory(app: Sphinx, uri: InventoryURI, inv: str) -> Inventory:
Expand Down
Loading