Files
LEDMatrix/test/test_template_targets.py
T
Claude b428ae3eae 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
2026-08-06 01:32:23 +00:00

38 lines
1.5 KiB
Python

"""Guard: every literal render_template() target must exist on disk.
Catches routes that reference templates deleted in a refactor (a real bug
class: the weather/stocks partials 500'd for months because their
templates were removed when those displays became plugins).
"""
import re
from pathlib import Path
from typing import Iterator
PROJECT_ROOT = Path(__file__).resolve().parent.parent
TEMPLATE_ROOT = PROJECT_ROOT / 'web_interface' / 'templates'
RENDER_RE = re.compile(r"""render_template\(\s*['"]([^'"]+)['"]""")
def _python_sources() -> Iterator[Path]:
"""Yield every Python source that can call render_template()."""
yield PROJECT_ROOT / 'web_interface' / 'app.py'
yield from (PROJECT_ROOT / 'web_interface' / 'blueprints').glob('*.py')
def test_all_literal_render_template_targets_exist() -> None:
"""Every string-literal render_template() target must exist on disk."""
missing = []
for source in _python_sources():
text = source.read_text(encoding='utf-8')
for match in RENDER_RE.finditer(text):
target = match.group(1)
if not (TEMPLATE_ROOT / target).is_file():
lineno = text.count('\n', 0, match.start()) + 1
missing.append(
f'{source.relative_to(PROJECT_ROOT)}:{lineno} -> {target}'
)
assert not missing, (
'render_template() references templates that do not exist under '
'web_interface/templates/:\n' + '\n'.join(missing)
)