fix: address CodeRabbit review findings

Verified each finding against the code; fixes for the valid ones:

- install_dependencies_apt.py: the installer listed 'freetype', but the
  declared dependency is freetype-py — an apt miss would pip-install the
  wrong PyPI package. Now installs freetype-py with an import-name
  mapping (pre-existing bug, surfaced by the review).
- api_v3.py: pixel_mapper_config is validated as a string before being
  saved to display.hardware (JSON callers could previously store an
  object/list the matrix library can't use).
- .cursorrules: the Plugin Loading Process and File Organization
  sections still said discovery scans plugins/ — now consistent with the
  corrected overview (configured directory, default plugin-repos/).
- README.md: removed the stale '(except the core calendar)' claim — no
  core calendar exists in src/ — and qualified the plugin inventory
  (official plugins in the monorepo; third-party from their own repos).
- CONFIG_REFERENCE.md: hardware_mapping now shows the code fallback
  (adafruit-hat-pwm) alongside the template value.
- PLUGIN_REGISTRY_SETUP_GUIDE.md: check_plugin.py takes --plugin, not a
  positional id.
- scripts/fix_perms/fix_*.sh: exec bits set so the documented
  'sudo ./...' invocations work.
- Guard tests hardened: template guard now catches multi-line
  render_template() calls; widget guard parses actual <script> src
  values and fails if the widgets dir goes missing; type hints and
  docstrings added per repo coding guidelines.

Skipped with reasons (noted on the PR): limit_refresh_rate_hz 100-vs-90
is documented as intentional in CONFIG_REFERENCE.md; the psutil comment
already names the enforcing manifest; docs/archive/ findings are out of
scope per the docs policy (archive may rot).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr
This commit is contained in:
Claude
2026-08-06 01:32:23 +00:00
parent 66336fe160
commit b428ae3eae
14 changed files with 82 additions and 42 deletions
+15 -7
View File
@@ -1,36 +1,44 @@
"""Tests for the web interface's in-memory cache helpers."""
from typing import Iterator
import pytest
from web_interface.cache import delete_cached, get_cached, invalidate_cache, set_cached
@pytest.fixture(autouse=True)
def clean_cache():
def clean_cache() -> Iterator[None]:
"""Start and finish every test with an empty cache."""
invalidate_cache()
yield
invalidate_cache()
def test_set_and_get():
def test_set_and_get() -> None:
"""A cached value is returned before its TTL expires."""
set_cached('key', 'value')
assert get_cached('key') == 'value'
def test_get_missing_returns_none():
def test_get_missing_returns_none() -> None:
"""Reading an unknown key returns None."""
assert get_cached('missing') is None
def test_delete_cached_removes_key():
def test_delete_cached_removes_key() -> None:
"""delete_cached removes exactly the named 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_delete_cached_missing_key_is_noop() -> None:
"""Deleting a key that was never set must not raise."""
delete_cached('never-set')
def test_invalidate_cache_pattern():
def test_invalidate_cache_pattern() -> None:
"""Pattern invalidation removes matching keys and keeps the rest."""
set_cached('fonts_catalog', 1)
set_cached('plugins_list', 2)
invalidate_cache('fonts')