deps: cachetools 7 and the current web-vitals API (#771)

cachetools 6 removed cachetools.func.mru_cache; the Zim search estimate
cache was its only user, so it becomes an lru_cache and the pin moves
to 7.2.0 with the Dependabot ignore removed.

reportWebVitals still destructured the web-vitals 2.x names (getCLS,
getFID, ...) which no longer exist, so it silently did nothing.  Use
the on* names, replace FID with INP, return the import promise, and
accept any callable rather than instanceof Function.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
lrnselfreliance 2026-10-03 11:01:18 -06:00 • committed by Roland
parent c28a9e0078
commit 1c8bbf1f10
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
6 changed files with 50 additions and 12 deletions

View file

@ -15,9 +15,6 @@ updates:
versions: [">=1.4"]
- dependency-name: "alembic"
versions: [">=1.11"]
# cachetools 6 removed cachetools.func.mru_cache, still used by modules/zim.
- dependency-name: "cachetools"
update-types: ["version-update:semver-major"]
groups:
python-dependencies:
patterns:

View file

@ -1,11 +1,12 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({getCLS, getFID, getFCP, getLCP, getTTFB}) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
if (typeof onPerfEntry === 'function') {
// web-vitals 3+ renamed get* to on*; 5+ replaced FID with INP.
return import('web-vitals').then(({onCLS, onINP, onFCP, onLCP, onTTFB}) => {
onCLS(onPerfEntry);
onINP(onPerfEntry);
onFCP(onPerfEntry);
onLCP(onPerfEntry);
onTTFB(onPerfEntry);
});
}
};

View file

@ -0,0 +1,28 @@
jest.mock('web-vitals', () => ({
onCLS: jest.fn(),
onINP: jest.fn(),
onFCP: jest.fn(),
onLCP: jest.fn(),
onTTFB: jest.fn(),
}));
import reportWebVitals from './reportWebVitals';
import * as webVitals from 'web-vitals';
describe('reportWebVitals', () => {
test('subscribes the callback to every current web-vitals metric', async () => {
const callback = jest.fn();
const pending = reportWebVitals(callback);
expect(pending).toBeDefined();
await pending;
for (const name of ['onCLS', 'onINP', 'onFCP', 'onLCP', 'onTTFB']) {
expect(webVitals[name]).toHaveBeenCalledWith(callback);
}
});
test('does nothing without a function', async () => {
jest.clearAllMocks();
expect(reportWebVitals(undefined)).toBeUndefined();
expect(webVitals.onCLS).not.toHaveBeenCalled();
});
});

View file

@ -260,7 +260,7 @@ def search_all_zims(session: Session, search_str: str, tag_names: List[str] = No
return all_results
@cachetools.func.mru_cache(maxsize=1_000)
@cachetools.func.lru_cache(maxsize=1_000)
def get_estimates(search_str: str) -> List[int]:
zims = Zims.get_all()
estimates = [i.estimate(search_str) for i in zims]

View file

@ -411,3 +411,15 @@ def test_get_custom_zims_directory(async_client, test_directory, test_wrolpi_con
get_wrolpi_config().zims_destination = 'custom/zims'
assert lib.get_zim_directory() == (test_directory / 'custom/zims')
def test_get_estimates_is_cached():
"""Repeated estimates for the same search string do not re-query the Zims."""
from unittest import mock
from modules.zim import lib
lib.get_estimates.cache_clear()
with mock.patch.object(lib.Zims, 'get_all', return_value=[]) as get_all:
assert lib.get_estimates('cached search') == []
assert lib.get_estimates('cached search') == []
assert get_all.call_count == 1

View file

@ -4,7 +4,7 @@ SQLAlchemy[asyncio]==1.3.24
aiohttp==3.14.3
alembic==1.10.4
beautifulsoup4==4.15.0
cachetools==5.5.2
cachetools==7.2.0
cryptography==50.0.2
ebooklib==0.20
feedparser==6.0.14