mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 06:15:09 +00:00
feat: deprecate unused plugin-facing methods for removal in 3.7.0 (#610)
35 methods on CacheManager, DisplayManager, FontManager and PluginManager have no caller in core, the ledmatrix-plugins monorepo or the registry's third-party plugins, but plugins live elsewhere, so they stay for one release. src.deprecation.deprecated logs a warning (and emits a DeprecationWarning) the first time each is called in a process, naming the release that removes it. The list and replacements are in CHANGELOG and PLUGIN_API_REFERENCE's new Deprecated APIs section; a test pins the set. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,24 @@ accepts both, but the store flags the old spelling as deprecated
|
||||
- `src.wifi_manager.get_wifi_status_path()` — where WiFi status messages for
|
||||
the display are written (`config/wifi_status.json`).
|
||||
|
||||
Deprecated, removed in 3.7.0 (each logs a warning on first use; see
|
||||
`docs/PLUGIN_API_REFERENCE.md#deprecated-apis` for replacements). Nothing in
|
||||
core, the monorepo or the registry's third-party plugins calls them:
|
||||
|
||||
- `CacheManager`: `has_data_changed`, `update_cache`, `setup_persistent_cache`,
|
||||
`get_sport_live_interval`, `get_sport_key_from_cache_key`,
|
||||
`get_background_cached_data`, `is_background_data_available`,
|
||||
`record_cache_hit`, `record_cache_miss`, `record_fetch_time`,
|
||||
`get_cache_metrics`, `log_cache_metrics`, `get_memory_cache_stats`.
|
||||
- `DisplayManager`: `draw_weather_icon`, `draw_sun`, `draw_cloud`, `draw_rain`,
|
||||
`draw_snow`, `draw_text_with_icons`, `get_scrolling_stats`.
|
||||
- `FontManager`: `set_override`, `remove_override`, `get_overrides`,
|
||||
`add_font`, `remove_font`, `validate_font`, `get_font_catalog`,
|
||||
`get_available_fonts`, `get_size_tokens`, `get_performance_stats`,
|
||||
`get_manager_fonts`, `get_detected_fonts`, `get_plugin_fonts`,
|
||||
`unregister_plugin_fonts`.
|
||||
- `PluginManager.get_enabled_plugins`.
|
||||
|
||||
## 3.5.0
|
||||
|
||||
New modules a plugin may import via `src.*` (floor on 3.5.0):
|
||||
|
||||
@@ -13,6 +13,7 @@ Complete API reference for plugin developers. This document describes all method
|
||||
- [Display Manager](#display-manager)
|
||||
- [Cache Manager](#cache-manager)
|
||||
- [Plugin Manager](#plugin-manager)
|
||||
- [Deprecated APIs](#deprecated-apis)
|
||||
|
||||
---
|
||||
|
||||
@@ -1074,3 +1075,23 @@ if "weather" in enabled_plugins:
|
||||
- [Plugin Development Guide](PLUGIN_DEVELOPMENT_GUIDE.md) - Complete development guide
|
||||
- [Advanced Plugin Development](ADVANCED_PLUGIN_DEVELOPMENT.md) - Advanced patterns and examples
|
||||
|
||||
---
|
||||
|
||||
## Deprecated APIs
|
||||
|
||||
These still work in 3.6 but log a warning the first time they are called
|
||||
(`journalctl -u ledmatrix` shows which one), and are **removed in 3.7.0**.
|
||||
Nothing in core, the official plugins or the third-party plugins in the
|
||||
registry calls them.
|
||||
|
||||
| Object | Methods | Instead |
|
||||
|---|---|---|
|
||||
| `cache_manager` | `update_cache` | `set()` |
|
||||
| `cache_manager` | `get_background_cached_data`, `is_background_data_available` | `get()` |
|
||||
| `cache_manager` | `has_data_changed`, `setup_persistent_cache`, `get_sport_live_interval`, `get_sport_key_from_cache_key`, `record_cache_hit`, `record_cache_miss`, `record_fetch_time`, `get_cache_metrics`, `log_cache_metrics`, `get_memory_cache_stats` | no replacement |
|
||||
| `display_manager` | `draw_weather_icon`, `draw_sun`, `draw_cloud`, `draw_rain`, `draw_snow`, `draw_text_with_icons` | draw your own icons (the weather plugin ships `WeatherIcons`) |
|
||||
| `display_manager` | `get_scrolling_stats` | no replacement |
|
||||
| `font_manager` | `get_font_catalog`, `get_available_fonts` | read `font_catalog` |
|
||||
| `font_manager` | `set_override`, `remove_override`, `get_overrides`, `add_font`, `remove_font`, `validate_font`, `get_size_tokens`, `get_performance_stats`, `get_manager_fonts`, `get_detected_fonts`, `get_plugin_fonts`, `unregister_plugin_fonts` | no replacement |
|
||||
| `plugin_manager` | `get_enabled_plugins` | check `enabled` on the entries in `plugin_manager.plugins` |
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ from src.cache.disk_cache import DiskCache
|
||||
from src.cache.cache_strategy import CacheStrategy
|
||||
from src.cache.cache_metrics import CacheMetrics
|
||||
from src.logging_config import get_logger
|
||||
from src.deprecation import deprecated
|
||||
|
||||
# Canonical implementation lives in src.cache.disk_cache; re-exported here
|
||||
# because this module's docstring documents it and external code may import
|
||||
@@ -473,6 +474,7 @@ class CacheManager:
|
||||
"""Get the cache directory path."""
|
||||
return self.cache_dir
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def has_data_changed(self, data_type: str, new_data: Dict[str, Any]) -> bool:
|
||||
"""Check if data has changed from cached version."""
|
||||
cached_data = self.load_cache(data_type)
|
||||
@@ -578,6 +580,7 @@ class CacheManager:
|
||||
"""Check if the US stock market is currently open."""
|
||||
return self._strategy_component.is_market_open()
|
||||
|
||||
@deprecated("3.7.0", "use set()")
|
||||
def update_cache(self, data_type: str, data: Dict[str, Any]) -> bool:
|
||||
"""Update cache with new data."""
|
||||
cache_data = {
|
||||
@@ -623,6 +626,7 @@ class CacheManager:
|
||||
cache_data['ttl'] = ttl
|
||||
self.save_cache(key, cache_data)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def setup_persistent_cache(self) -> bool:
|
||||
"""
|
||||
Set up a persistent cache directory with proper permissions.
|
||||
@@ -834,6 +838,7 @@ class CacheManager:
|
||||
else:
|
||||
self.logger.info("Disk cache cleanup thread stopped successfully")
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_sport_live_interval(self, sport_key: str) -> int:
|
||||
"""
|
||||
Get the live_update_interval for a specific sport from config.
|
||||
@@ -855,6 +860,7 @@ class CacheManager:
|
||||
"""
|
||||
return self._strategy_component.get_data_type_from_key(key)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_sport_key_from_cache_key(self, key: str) -> Optional[str]:
|
||||
"""
|
||||
Extract sport key from cache key to determine appropriate live_update_interval.
|
||||
@@ -894,6 +900,7 @@ class CacheManager:
|
||||
data_type = self.get_data_type_from_key(key)
|
||||
return self.get_cached_data_with_strategy(key, data_type)
|
||||
|
||||
@deprecated("3.7.0", "use get()")
|
||||
def get_background_cached_data(self, key: str, sport_key: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Get data from background service cache with appropriate strategy.
|
||||
@@ -931,6 +938,7 @@ class CacheManager:
|
||||
self.record_cache_miss('background')
|
||||
return None
|
||||
|
||||
@deprecated("3.7.0", "use get()")
|
||||
def is_background_data_available(self, key: str, sport_key: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Check if background service has fresh data available.
|
||||
@@ -960,26 +968,32 @@ class CacheManager:
|
||||
date_str = datetime.now(pytz.utc).strftime('%Y%m%d')
|
||||
return f"{sport}_{date_str}"
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def record_cache_hit(self, cache_type: str = 'regular') -> None:
|
||||
"""Record a cache hit for performance monitoring."""
|
||||
self._metrics_component.record_hit(cache_type)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def record_cache_miss(self, cache_type: str = 'regular') -> None:
|
||||
"""Record a cache miss for performance monitoring."""
|
||||
self._metrics_component.record_miss(cache_type)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def record_fetch_time(self, duration: float) -> None:
|
||||
"""Record fetch operation duration for performance monitoring."""
|
||||
self._metrics_component.record_fetch_time(duration)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_cache_metrics(self) -> Dict[str, Any]:
|
||||
"""Get current cache performance metrics."""
|
||||
return self._metrics_component.get_metrics()
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def log_cache_metrics(self) -> None:
|
||||
"""Log current cache performance metrics."""
|
||||
self._metrics_component.log_metrics()
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_memory_cache_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get statistics about the memory cache.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""Marking plugin-facing core APIs for removal.
|
||||
|
||||
Plugins live in other repositories, so a method nothing in core calls may
|
||||
still be called by a plugin nobody has checked. Such methods get
|
||||
``@deprecated`` for one release before they are removed: the first call in a
|
||||
process logs a warning naming the method and the release that removes it
|
||||
(visible in ``journalctl -u ledmatrix``), and emits a DeprecationWarning for
|
||||
tooling.
|
||||
"""
|
||||
|
||||
import functools
|
||||
import threading
|
||||
import warnings
|
||||
from typing import Callable, Optional, TypeVar
|
||||
|
||||
from src.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
F = TypeVar("F", bound=Callable)
|
||||
|
||||
_warned = set()
|
||||
_warned_lock = threading.Lock()
|
||||
|
||||
|
||||
def deprecated(removal: str, alternative: Optional[str] = None) -> Callable[[F], F]:
|
||||
"""Decorate a function or method that will be removed in ``removal``."""
|
||||
|
||||
def decorate(func: F) -> F:
|
||||
message = f"{func.__qualname__}() is deprecated and will be removed in LEDMatrix {removal}"
|
||||
if alternative:
|
||||
message += f"; {alternative}"
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
with _warned_lock:
|
||||
first = func.__qualname__ not in _warned
|
||||
_warned.add(func.__qualname__)
|
||||
if first:
|
||||
logger.warning(message)
|
||||
warnings.warn(message, DeprecationWarning, stacklevel=2)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
wrapper.__deprecated__ = message
|
||||
return wrapper # type: ignore[return-value]
|
||||
|
||||
return decorate
|
||||
@@ -52,6 +52,7 @@ import zlib
|
||||
import freetype
|
||||
|
||||
from src.common import snapshot_policy
|
||||
from src.deprecation import deprecated
|
||||
from src.common.permission_utils import (
|
||||
ensure_directory_permissions,
|
||||
ensure_file_permissions,
|
||||
@@ -1139,6 +1140,7 @@ class DisplayManager:
|
||||
except Exception as e:
|
||||
logger.error(f"Error drawing text: {e}", exc_info=True)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def draw_sun(self, x: int, y: int, size: int = 16):
|
||||
"""Draw a sun icon using yellow circles and lines."""
|
||||
center = (x + size//2, y + size//2)
|
||||
@@ -1159,6 +1161,7 @@ class DisplayManager:
|
||||
end_y = center[1] + ((radius + ray_length) * math.sin(rad))
|
||||
self.draw.line([start_x, start_y, end_x, end_y], fill=(255, 255, 0), width=2)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def draw_cloud(self, x: int, y: int, size: int = 16, color=(200, 200, 200)):
|
||||
"""Draw a cloud icon."""
|
||||
# Draw multiple circles to form a cloud shape
|
||||
@@ -1166,6 +1169,7 @@ class DisplayManager:
|
||||
self.draw.ellipse([x+size//2, y+size//3, x+size//2+size//2, y+size//3+size//2], fill=color)
|
||||
self.draw.ellipse([x+size//3, y+size//6, x+size//3+size//2, y+size//6+size//2], fill=color)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def draw_rain(self, x: int, y: int, size: int = 16):
|
||||
"""Draw rain icon with cloud and droplets."""
|
||||
# Draw cloud
|
||||
@@ -1180,6 +1184,7 @@ class DisplayManager:
|
||||
self.draw.line([drop_x, drop_y, drop_x, drop_y+drop_size],
|
||||
fill=drop_color, width=2)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def draw_snow(self, x: int, y: int, size: int = 16):
|
||||
"""Draw snow icon with cloud and snowflakes."""
|
||||
# Draw cloud
|
||||
@@ -1300,6 +1305,7 @@ class DisplayManager:
|
||||
]
|
||||
self.draw.polygon(bolt_points, fill=bolt_color)
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def draw_weather_icon(self, condition: str, x: int, y: int, size: int = 16) -> None:
|
||||
"""Draw a weather icon based on the condition."""
|
||||
if condition.lower() in ['clear', 'sunny']:
|
||||
@@ -1316,6 +1322,7 @@ class DisplayManager:
|
||||
self._draw_sun(x, y, size)
|
||||
# Note: No update_display() here - let the caller handle the update
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def draw_text_with_icons(self, text: str, icons: List[tuple] = None, x: int = None, y: int = None,
|
||||
color: tuple = (255, 255, 255)):
|
||||
"""Draw text with weather icons at specified positions."""
|
||||
@@ -1600,6 +1607,7 @@ class DisplayManager:
|
||||
if removed_count > 0:
|
||||
logger.debug(f"Cleaned up {removed_count} expired deferred updates")
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_scrolling_stats(self) -> dict:
|
||||
"""Get current scrolling statistics for debugging."""
|
||||
return {
|
||||
|
||||
@@ -40,6 +40,7 @@ from pathlib import Path
|
||||
from PIL import ImageFont
|
||||
from src.common.font_layout import load_truetype, resolve_asset_path
|
||||
from typing import Dict, Tuple, Optional, Union, Any, List
|
||||
from src.deprecation import deprecated
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -167,6 +168,7 @@ class FontManager:
|
||||
|
||||
logger.debug(f"Registered font for {manager_id}.{element_key}: {family}@{size_px}px")
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_manager_fonts(self, manager_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Get registered fonts for a specific manager or all managers.
|
||||
@@ -181,6 +183,7 @@ class FontManager:
|
||||
return self.manager_fonts.get(manager_id, {})
|
||||
return self.manager_fonts.copy()
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_detected_fonts(self) -> Dict[str, Dict[str, Any]]:
|
||||
"""Get all detected font usage across managers."""
|
||||
return self.detected_fonts.copy()
|
||||
@@ -357,6 +360,7 @@ class FontManager:
|
||||
logger.error(f"Plugin font not found: {font_path}")
|
||||
return None
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def unregister_plugin_fonts(self, plugin_id: str) -> bool:
|
||||
"""Unregister all fonts for a plugin."""
|
||||
try:
|
||||
@@ -393,6 +397,7 @@ class FontManager:
|
||||
for key in keys_to_remove:
|
||||
del self.font_cache[key]
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_plugin_fonts(self, plugin_id: str) -> List[str]:
|
||||
"""Get list of font families registered by a plugin."""
|
||||
if plugin_id in self.plugin_font_catalogs:
|
||||
@@ -637,6 +642,7 @@ class FontManager:
|
||||
|
||||
# ==================== Override Management ====================
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def set_override(self, element_key: str, family: str = None, size_px: int = None):
|
||||
"""Set font override for a specific element."""
|
||||
if element_key not in self.font_overrides:
|
||||
@@ -656,6 +662,7 @@ class FontManager:
|
||||
self.clear_cache()
|
||||
logger.info(f"Font override set for {element_key}: {self.font_overrides.get(element_key, {})}")
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def remove_override(self, element_key: str):
|
||||
"""Remove font override for a specific element."""
|
||||
if element_key in self.font_overrides:
|
||||
@@ -664,6 +671,7 @@ class FontManager:
|
||||
self.clear_cache()
|
||||
logger.info(f"Font override removed for {element_key}")
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_overrides(self) -> Dict[str, Dict[str, str]]:
|
||||
"""Get current font overrides."""
|
||||
return self.font_overrides.copy()
|
||||
@@ -753,10 +761,12 @@ class FontManager:
|
||||
self.metrics_cache.clear()
|
||||
logger.info("Font cache cleared")
|
||||
|
||||
@deprecated("3.7.0", "read font_catalog")
|
||||
def get_available_fonts(self) -> Dict[str, str]:
|
||||
"""Get dictionary of available font families and their paths."""
|
||||
return self.font_catalog.copy()
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_size_tokens(self) -> Dict[str, int]:
|
||||
"""Get available size tokens."""
|
||||
return self.size_tokens.copy()
|
||||
@@ -767,6 +777,7 @@ class FontManager:
|
||||
self.performance_stats[operation] = {}
|
||||
self.performance_stats[operation][font_key] = duration
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def get_performance_stats(self) -> Dict[str, Any]:
|
||||
"""Get performance statistics."""
|
||||
uptime = time.time() - self.performance_stats["start_time"]
|
||||
@@ -788,10 +799,12 @@ class FontManager:
|
||||
"detected_fonts": len(self.detected_fonts)
|
||||
}
|
||||
|
||||
@deprecated("3.7.0", "read font_catalog")
|
||||
def get_font_catalog(self) -> Dict[str, str]:
|
||||
"""Get the current font catalog."""
|
||||
return self.font_catalog.copy()
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def add_font(self, font_file_path: str, family_name: str) -> bool:
|
||||
"""Add a new font to the catalog."""
|
||||
try:
|
||||
@@ -824,6 +837,7 @@ class FontManager:
|
||||
logger.error(f"Error adding font {family_name}: {e}")
|
||||
return False
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def remove_font(self, family_name: str) -> bool:
|
||||
"""Remove a font from the catalog."""
|
||||
try:
|
||||
@@ -851,6 +865,7 @@ class FontManager:
|
||||
logger.error(f"Error removing font {family_name}: {e}")
|
||||
return False
|
||||
|
||||
@deprecated("3.7.0")
|
||||
def validate_font(self, font_path: str) -> Dict[str, Any]:
|
||||
"""Validate a font file."""
|
||||
try:
|
||||
|
||||
@@ -26,6 +26,7 @@ from src.plugin_system.schema_manager import (
|
||||
CORE_VEGAS_TUNING_KEYS, SchemaManager, normalize_legacy_booleans,
|
||||
)
|
||||
from src.common.path_safety import safe_path_component
|
||||
from src.deprecation import deprecated
|
||||
from src.common.permission_utils import (
|
||||
ensure_directory_permissions,
|
||||
get_plugin_dir_mode
|
||||
@@ -698,6 +699,7 @@ class PluginManager:
|
||||
"""
|
||||
return self.plugins.copy()
|
||||
|
||||
@deprecated("3.7.0", "check each plugin's enabled flag in plugins")
|
||||
def get_enabled_plugins(self) -> List[str]:
|
||||
"""
|
||||
Get list of enabled plugin IDs.
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
"""@deprecated: plugin-facing APIs nothing in core, the monorepo or the
|
||||
registry's third-party plugins calls, kept for one release with a warning."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
os.environ.setdefault("EMULATOR", "true")
|
||||
|
||||
from src import deprecation
|
||||
from src.deprecation import deprecated
|
||||
|
||||
#: Everything deprecated for removal in 3.7.0. Removing one of these, or
|
||||
#: deprecating another, should be a deliberate edit here too.
|
||||
DEPRECATED = {
|
||||
"src.cache_manager.CacheManager": [
|
||||
"has_data_changed", "update_cache", "setup_persistent_cache",
|
||||
"get_sport_live_interval", "get_sport_key_from_cache_key",
|
||||
"get_background_cached_data", "is_background_data_available",
|
||||
"record_cache_hit", "record_cache_miss", "record_fetch_time",
|
||||
"get_cache_metrics", "log_cache_metrics", "get_memory_cache_stats",
|
||||
],
|
||||
"src.display_manager.DisplayManager": [
|
||||
"draw_sun", "draw_cloud", "draw_rain", "draw_snow", "draw_weather_icon",
|
||||
"draw_text_with_icons", "get_scrolling_stats",
|
||||
],
|
||||
"src.font_manager.FontManager": [
|
||||
"get_manager_fonts", "get_detected_fonts", "unregister_plugin_fonts",
|
||||
"get_plugin_fonts", "set_override", "remove_override", "get_overrides",
|
||||
"get_available_fonts", "get_size_tokens", "get_performance_stats",
|
||||
"get_font_catalog", "add_font", "remove_font", "validate_font",
|
||||
],
|
||||
"src.plugin_system.plugin_manager.PluginManager": ["get_enabled_plugins"],
|
||||
}
|
||||
|
||||
|
||||
def _cls(path):
|
||||
import importlib
|
||||
module, name = path.rsplit(".", 1)
|
||||
return getattr(importlib.import_module(module), name)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", sorted(DEPRECATED))
|
||||
def test_exactly_these_methods_are_deprecated(path):
|
||||
cls = _cls(path)
|
||||
marked = sorted(name for name, value in vars(cls).items()
|
||||
if hasattr(value, "__deprecated__"))
|
||||
assert marked == sorted(DEPRECATED[path])
|
||||
for name in marked:
|
||||
assert "3.7.0" in getattr(cls, name).__deprecated__
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fresh(monkeypatch):
|
||||
monkeypatch.setattr(deprecation, "_warned", set())
|
||||
|
||||
|
||||
def test_first_call_warns_and_logs_then_stays_quiet(fresh, caplog):
|
||||
@deprecated("9.9.9", "use other()")
|
||||
def old(x):
|
||||
"""Doc."""
|
||||
return x * 2
|
||||
|
||||
with warnings.catch_warnings(record=True) as caught, caplog.at_level(logging.WARNING):
|
||||
warnings.simplefilter("always")
|
||||
assert old(2) == 4
|
||||
assert old(3) == 6
|
||||
|
||||
assert [str(w.message) for w in caught] == [
|
||||
"test_first_call_warns_and_logs_then_stays_quiet.<locals>.old() is deprecated "
|
||||
"and will be removed in LEDMatrix 9.9.9; use other()"]
|
||||
assert caught[0].category is DeprecationWarning
|
||||
assert caught[0].filename == __file__ # points at the caller
|
||||
assert sum("will be removed in LEDMatrix 9.9.9" in r.message for r in caplog.records) == 1
|
||||
assert old.__name__ == "old" and old.__doc__ == "Doc."
|
||||
|
||||
|
||||
def test_decorated_methods_still_work(fresh):
|
||||
from src.font_manager import FontManager
|
||||
fm = FontManager({})
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
assert fm.get_font_catalog() == fm.font_catalog
|
||||
Reference in New Issue
Block a user