chore(deprecation): retarget the 35 deprecations to 3.8.0 and add a usage scan (#681)

Moves the 35 @deprecated markers from 3.7.0 (already shipped with them in
place) to 3.8.0, and adds scripts/plugin_api_usage.py plus the generated
docs/DEPRECATIONS_3.8.md: who still calls or overrides each deprecated
method across core, the monorepo and third-party plugins. Removes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-30 09:11:36 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 9fe23af432
commit c8a0ddcf7b
15 changed files with 1168 additions and 64 deletions
+16 -14
View File
@@ -408,7 +408,7 @@ class CacheManager:
"""Get the cache directory path."""
return self.cache_dir
@deprecated("3.7.0")
@deprecated("3.8.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)
@@ -514,7 +514,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()")
@deprecated("3.8.0", "use set()")
def update_cache(self, data_type: str, data: Dict[str, Any]) -> bool:
"""Update cache with new data."""
cache_data = {
@@ -564,7 +564,7 @@ class CacheManager:
cache_data['data'] = data
self.save_cache(key, cache_data)
@deprecated("3.7.0")
@deprecated("3.8.0")
def setup_persistent_cache(self) -> bool:
"""
Set up a persistent cache directory with proper permissions.
@@ -776,7 +776,7 @@ class CacheManager:
else:
self.logger.info("Disk cache cleanup thread stopped successfully")
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_sport_live_interval(self, sport_key: str) -> int:
"""
Get the live_update_interval for a specific sport from config.
@@ -798,7 +798,7 @@ class CacheManager:
"""
return self._strategy_component.get_data_type_from_key(key)
@deprecated("3.7.0")
@deprecated("3.8.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.
@@ -838,7 +838,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()")
@deprecated("3.8.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.
@@ -876,7 +876,7 @@ class CacheManager:
self.record_cache_miss('background')
return None
@deprecated("3.7.0", "use get()")
@deprecated("3.8.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.
@@ -906,32 +906,32 @@ class CacheManager:
date_str = datetime.now(pytz.utc).strftime('%Y%m%d')
return f"{sport}_{date_str}"
@deprecated("3.7.0")
@deprecated("3.8.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")
@deprecated("3.8.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")
@deprecated("3.8.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")
@deprecated("3.8.0")
def get_cache_metrics(self) -> Dict[str, Any]:
"""Get current cache performance metrics."""
return self._metrics_component.get_metrics()
@deprecated("3.7.0")
@deprecated("3.8.0")
def log_cache_metrics(self) -> None:
"""Log current cache performance metrics."""
self._metrics_component.log_metrics()
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_memory_cache_stats(self) -> Dict[str, Any]:
"""
Get statistics about the memory cache.
@@ -943,7 +943,9 @@ class CacheManager:
def log_memory_cache_stats(self) -> None:
"""Log current memory cache statistics."""
stats = self.get_memory_cache_stats()
# Not get_memory_cache_stats(): that is deprecated, and core must not
# trip its own deprecation warning every time memory logging runs.
stats = self._memory_cache_component.get_stats()
self.logger.info(f"Memory Cache - Size: {stats['size']}/{stats['max_size']} "
f"({stats['usage_percent']:.1f}%), "
f"Last cleanup: {time.time() - stats['last_cleanup']:.1f}s ago")
+8
View File
@@ -6,6 +6,14 @@ still be called by a plugin nobody has checked. Such methods get
process logs a warning naming the method and the release that removes it
(visible in ``journalctl -u ledmatrix``), and emits a DeprecationWarning for
tooling.
Before a release removes anything, ``scripts/plugin_api_usage.py`` scans core,
the official plugin monorepo and the registry's third-party plugins for callers
and overriders of every marked method. Its latest output is
``docs/DEPRECATIONS_3.8.md``; remove only what it reports unused, and move the
rest to a later release. ``test/test_deprecation.py`` fails while any marker
names a release at or below ``src.__version__``, so a release cannot ship with
a removal date it has already passed.
"""
import functools
+7 -7
View File
@@ -1320,7 +1320,7 @@ class DisplayManager:
except Exception as e:
logger.error(f"Error drawing text: {e}", exc_info=True)
@deprecated("3.7.0")
@deprecated("3.8.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)
@@ -1341,7 +1341,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")
@deprecated("3.8.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
@@ -1349,7 +1349,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")
@deprecated("3.8.0")
def draw_rain(self, x: int, y: int, size: int = 16):
"""Draw rain icon with cloud and droplets."""
# Draw cloud
@@ -1364,7 +1364,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")
@deprecated("3.8.0")
def draw_snow(self, x: int, y: int, size: int = 16):
"""Draw snow icon with cloud and snowflakes."""
# Draw cloud
@@ -1485,7 +1485,7 @@ class DisplayManager:
]
self.draw.polygon(bolt_points, fill=bolt_color)
@deprecated("3.7.0")
@deprecated("3.8.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']:
@@ -1502,7 +1502,7 @@ class DisplayManager:
self._draw_sun(x, y, size)
# Note: No update_display() here - let the caller handle the update
@deprecated("3.7.0")
@deprecated("3.8.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."""
@@ -1828,7 +1828,7 @@ class DisplayManager:
if removed_count > 0:
logger.debug(f"Cleaned up {removed_count} expired deferred updates")
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_scrolling_stats(self) -> dict:
"""Get current scrolling statistics for debugging."""
return {
+14 -14
View File
@@ -187,7 +187,7 @@ class FontManager:
if removed:
self.manager_fonts_version += 1
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_manager_fonts(self, manager_id: Optional[str] = None) -> Dict[str, Any]:
"""
Get registered fonts for a specific manager or all managers.
@@ -202,7 +202,7 @@ class FontManager:
return self.manager_fonts.get(manager_id, {})
return self.manager_fonts.copy()
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_detected_fonts(self) -> Dict[str, Dict[str, Any]]:
"""Get all detected font usage across managers."""
return self.detected_fonts.copy()
@@ -433,7 +433,7 @@ class FontManager:
search_dirs = [Path(resolve_asset_path(configured)), Path(resolve_asset_path("plugins"))]
return resolve_plugin_dir(plugin_id, search_dirs, prefix=True)
@deprecated("3.7.0")
@deprecated("3.8.0")
def unregister_plugin_fonts(self, plugin_id: str) -> bool:
"""Unregister all fonts for a plugin."""
try:
@@ -471,7 +471,7 @@ class FontManager:
# Font objects someone may hold were dropped; see cache_generation.
self.cache_generation += 1
@deprecated("3.7.0")
@deprecated("3.8.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:
@@ -670,7 +670,7 @@ class FontManager:
# ==================== Override Management ====================
@deprecated("3.7.0")
@deprecated("3.8.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:
@@ -690,7 +690,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")
@deprecated("3.8.0")
def remove_override(self, element_key: str):
"""Remove font override for a specific element."""
if element_key in self.font_overrides:
@@ -699,7 +699,7 @@ class FontManager:
self.clear_cache()
logger.info(f"Font override removed for {element_key}")
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_overrides(self) -> Dict[str, Dict[str, str]]:
"""Get current font overrides."""
return self.font_overrides.copy()
@@ -787,17 +787,17 @@ class FontManager:
self.cache_generation += 1
logger.info("Font cache cleared")
@deprecated("3.7.0", "read font_catalog")
@deprecated("3.8.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")
@deprecated("3.8.0")
def get_size_tokens(self) -> Dict[str, int]:
"""Get available size tokens."""
return self.size_tokens.copy()
@deprecated("3.7.0")
@deprecated("3.8.0")
def get_performance_stats(self) -> Dict[str, Any]:
"""Get performance statistics."""
uptime = time.time() - self.performance_stats["start_time"]
@@ -819,12 +819,12 @@ class FontManager:
"detected_fonts": len(self.detected_fonts)
}
@deprecated("3.7.0", "read font_catalog")
@deprecated("3.8.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")
@deprecated("3.8.0")
def add_font(self, font_file_path: str, family_name: str) -> bool:
"""Add ``font_file_path`` to the catalog as ``family_name``. The file
stays where it is; only assets/fonts is created if it is missing."""
@@ -852,7 +852,7 @@ class FontManager:
logger.error(f"Error adding font {family_name}: {e}")
return False
@deprecated("3.7.0")
@deprecated("3.8.0")
def remove_font(self, family_name: str) -> bool:
"""Remove a font from the catalog."""
try:
@@ -880,7 +880,7 @@ class FontManager:
logger.error(f"Error removing font {family_name}: {e}")
return False
@deprecated("3.7.0")
@deprecated("3.8.0")
def validate_font(self, font_path: str) -> Dict[str, Any]:
"""Validate a font file."""
try:
+1 -1
View File
@@ -844,7 +844,7 @@ class PluginManager:
"""
return self.plugins.copy()
@deprecated("3.7.0", "check each plugin's enabled flag in plugins")
@deprecated("3.8.0", "check each plugin's enabled flag in plugins")
def get_enabled_plugins(self) -> List[str]:
"""
Get list of enabled plugin IDs.