diff --git a/docker/pyproject.deps.toml b/docker/pyproject.deps.toml index 0dccc92..9e7a579 100644 --- a/docker/pyproject.deps.toml +++ b/docker/pyproject.deps.toml @@ -1,6 +1,6 @@ [project] name = "mcp-plex" -version = "1.0.10" +version = "1.0.12" requires-python = ">=3.11,<3.13" dependencies = [ "fastmcp>=2.11.2", diff --git a/mcp_plex/loader/imdb_cache.py b/mcp_plex/loader/imdb_cache.py index c923dde..ece06ba 100644 --- a/mcp_plex/loader/imdb_cache.py +++ b/mcp_plex/loader/imdb_cache.py @@ -1,23 +1,37 @@ from __future__ import annotations import json +import logging from pathlib import Path -from typing import Any, Dict +from typing import Any class IMDbCache: """Simple persistent cache for IMDb API responses.""" + _logger = logging.getLogger(__name__) + def __init__(self, path: Path) -> None: self.path = path - self._data: Dict[str, Any] + self._data: dict[str, Any] = {} if path.exists(): try: - self._data = json.loads(path.read_text()) - except Exception: - self._data = {} - else: - self._data = {} + raw_contents = path.read_text(encoding="utf-8") + except Exception as exc: # noqa: BLE001 - ensure any read failure is surfaced + self._logger.warning( + "Failed to read IMDb cache from %s; starting with empty cache.", + path, + exc_info=exc, + ) + else: + try: + self._data = json.loads(raw_contents) + except (json.JSONDecodeError, UnicodeError) as exc: + self._logger.warning( + "Failed to decode IMDb cache JSON from %s; starting with empty cache.", + path, + exc_info=exc, + ) def get(self, imdb_id: str) -> dict[str, Any] | None: """Return cached data for ``imdb_id`` if present.""" diff --git a/pyproject.toml b/pyproject.toml index 021ec8e..875ccc3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mcp-plex" -version = "1.0.10" +version = "1.0.12" description = "Plex-Oriented Model Context Protocol Server" requires-python = ">=3.11,<3.13" diff --git a/tests/test_imdb_cache.py b/tests/test_imdb_cache.py index 7921f78..a6fb72f 100644 --- a/tests/test_imdb_cache.py +++ b/tests/test_imdb_cache.py @@ -37,10 +37,31 @@ def test_imdb_cache_loads_existing_and_persists(tmp_path: Path): } -def test_imdb_cache_invalid_file(tmp_path: Path): +def test_imdb_cache_invalid_file_logs_warning(tmp_path: Path, caplog): path = tmp_path / "cache.json" path.write_text("not json") - cache = IMDbCache(path) + with caplog.at_level("WARNING"): + cache = IMDbCache(path) + assert any( + record.name == "mcp_plex.loader.imdb_cache" + and "Failed to decode IMDb cache JSON" in record.getMessage() + for record in caplog.records + ) + assert cache.get("tt0111161") is None + cache.set("tt0111161", {"id": "tt0111161"}) + assert cache.get("tt0111161") == {"id": "tt0111161"} + + +def test_imdb_cache_invalid_encoding_logs_warning(tmp_path: Path, caplog): + path = tmp_path / "cache.json" + path.write_bytes(b"\xff\xff") + with caplog.at_level("WARNING"): + cache = IMDbCache(path) + assert any( + record.name == "mcp_plex.loader.imdb_cache" + and "Failed to read IMDb cache" in record.getMessage() + for record in caplog.records + ) assert cache.get("tt0111161") is None cache.set("tt0111161", {"id": "tt0111161"}) assert cache.get("tt0111161") == {"id": "tt0111161"} diff --git a/uv.lock b/uv.lock index f406974..bca5f78 100644 --- a/uv.lock +++ b/uv.lock @@ -730,7 +730,7 @@ wheels = [ [[package]] name = "mcp-plex" -version = "1.0.10" +version = "1.0.12" source = { editable = "." } dependencies = [ { name = "fastapi" },