mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-05 06:45:09 +00:00
A plugin takes part in Vegas mode in one declared way: 'scroll', 'pause' or 'exclude', resolved from the user's vegas_participation setting, the manifest field, then the legacy hooks, so no plugin changes behaviour. The stream manager decides inclusion and pauses through it; the installed plugins API and the Vegas plugin-order list report it. Deprecates get_supported_vegas_modes, get_vegas_segment_width and vegas_panel_count for removal in 3.9.0, and regenerates docs/DEPRECATIONS_3.8.md to include them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.0 KiB
Python
80 lines
3.0 KiB
Python
"""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.
|
|
|
|
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
|
|
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 # type: ignore[attr-defined] # functools' _Wrapped doesn't declare it
|
|
return wrapper # type: ignore[return-value]
|
|
|
|
return decorate
|
|
|
|
|
|
def warn_deprecated(what: str, removal: str, alternative: Optional[str] = None,
|
|
once_key: Optional[str] = None) -> bool:
|
|
"""Warn that ``what`` will be removed in ``removal``, once per process.
|
|
|
|
For what ``@deprecated`` cannot decorate: a config key, a manifest field,
|
|
a value a hook returns. Same message, log line and DeprecationWarning as
|
|
the decorator. ``once_key`` (default: ``what``) is what "once" counts
|
|
against, so one deprecated key can warn once for each plugin that sets it.
|
|
|
|
Returns whether this call warned.
|
|
"""
|
|
message = f"{what} is deprecated and will be removed in LEDMatrix {removal}"
|
|
if alternative:
|
|
message += f"; {alternative}"
|
|
key = once_key or what
|
|
with _warned_lock:
|
|
if key in _warned:
|
|
return False
|
|
_warned.add(key)
|
|
logger.warning(message)
|
|
warnings.warn(message, DeprecationWarning, stacklevel=2)
|
|
return True
|