From 2dae36a09453ddaf9e47cfb3fe1e2d5d660d6e48 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 23:52:15 +0000 Subject: [PATCH] fix(web): implement delete_cached so the font catalog cache actually invalidates api_v3.py's font upload/delete handlers import delete_cached from web_interface.cache, but the function was never defined. The surrounding except ImportError silently swallowed the failure, so the fonts_catalog cache entry survived uploads/deletes and newly uploaded fonts did not appear until the TTL expired or the service restarted. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr --- test/web_interface/test_cache.py | 38 ++++++++++++++++++++++++++++++++ web_interface/cache.py | 6 +++++ 2 files changed, 44 insertions(+) create mode 100644 test/web_interface/test_cache.py diff --git a/test/web_interface/test_cache.py b/test/web_interface/test_cache.py new file mode 100644 index 00000000..98986b0c --- /dev/null +++ b/test/web_interface/test_cache.py @@ -0,0 +1,38 @@ +"""Tests for the web interface's in-memory cache helpers.""" +import pytest + +from web_interface.cache import delete_cached, get_cached, invalidate_cache, set_cached + + +@pytest.fixture(autouse=True) +def clean_cache(): + invalidate_cache() + yield + invalidate_cache() + + +def test_set_and_get(): + set_cached('key', 'value') + assert get_cached('key') == 'value' + + +def test_get_missing_returns_none(): + assert get_cached('missing') is None + + +def test_delete_cached_removes_key(): + set_cached('fonts_catalog', ['a-font']) + delete_cached('fonts_catalog') + assert get_cached('fonts_catalog') is None + + +def test_delete_cached_missing_key_is_noop(): + delete_cached('never-set') # must not raise + + +def test_invalidate_cache_pattern(): + set_cached('fonts_catalog', 1) + set_cached('plugins_list', 2) + invalidate_cache('fonts') + assert get_cached('fonts_catalog') is None + assert get_cached('plugins_list') == 2 diff --git a/web_interface/cache.py b/web_interface/cache.py index c1b7d321..f7aad3ea 100644 --- a/web_interface/cache.py +++ b/web_interface/cache.py @@ -29,6 +29,12 @@ def set_cached(key: str, value: Any, ttl_seconds: int = 60) -> None: _cache_timestamps[key] = time.time() +def delete_cached(key: str) -> None: + """Remove a single key from the cache if present.""" + _cache.pop(key, None) + _cache_timestamps.pop(key, None) + + def invalidate_cache(pattern: Optional[str] = None) -> None: """Invalidate cache entries matching pattern, or all if pattern is None.""" if pattern is None: