Quellcode für vyra_base.com.feeder.registry
"""
Feeder registry for VYRA custom feeders.
``FeederRegistry`` is a thread-safe singleton that keeps track of all
registered :class:`~vyra_base.com.feeder.interfaces.IFeeder` subclasses.
Use the :func:`register_feeder` decorator to register a feeder class so the
framework (and downstream tooling) can discover it by name.
Usage::
from vyra_base.com.feeder.registry import register_feeder, FeederRegistry
from vyra_base.com.feeder.custom_feeder import CustomBaseFeeder
@register_feeder("TemperatureFeed")
class TemperatureFeeder(CustomBaseFeeder):
...
# Discover & instantiate
cls = FeederRegistry.get("TemperatureFeed")
feeder = cls(...)
"""
from __future__ import annotations
import logging
import threading
from typing import Optional, Type
from vyra_base.com.feeder.interfaces import IFeeder
logger = logging.getLogger(__name__)
_registry_lock = threading.Lock()
[Doku]
class FeederRegistry:
"""Thread-safe registry of :class:`~vyra_base.com.feeder.interfaces.IFeeder`
subclasses.
All built-in feeders (StateFeeder, NewsFeeder, ErrorFeeder) are NOT
pre-registered here — the registry is exclusively for user-defined
custom feeders added via :func:`register_feeder`.
"""
_instance: dict[str, Type[IFeeder]] = {}
[Doku]
@classmethod
def register(cls, name: str, feeder_class: Type[IFeeder]) -> None:
"""Register *feeder_class* under *name*.
:param name: Unique key (normally the ``functionname`` from the
interface config, e.g. ``"TemperatureFeed"``).
:type name: str
:param feeder_class: The feeder class to register. Must be a
subclass of :class:`~vyra_base.com.feeder.interfaces.IFeeder`.
:type feeder_class: Type[IFeeder]
:raises TypeError: If *feeder_class* does not subclass ``IFeeder``.
:raises ValueError: If *name* is already registered (use
``override=True`` to replace).
"""
if not (isinstance(feeder_class, type) and issubclass(feeder_class, IFeeder)):
raise TypeError(
f"FeederRegistry.register: '{feeder_class}' must be a subclass of IFeeder."
)
with _registry_lock:
if name in cls._instance:
logger.warning(
"FeederRegistry: '%s' is already registered (%s). Overwriting.",
name, cls._instance[name].__name__
)
cls._instance[name] = feeder_class
logger.debug("FeederRegistry: registered '%s' → %s", name, feeder_class.__name__)
[Doku]
@classmethod
def get(cls, name: str) -> Optional[Type[IFeeder]]:
"""Return the feeder class registered under *name*, or ``None``.
:param name: Feeder name to look up.
:type name: str
:rtype: Optional[Type[IFeeder]]
"""
return cls._instance.get(name)
[Doku]
@classmethod
def list_feeders(cls) -> list[str]:
"""Return a sorted list of all registered feeder names.
:rtype: list[str]
"""
with _registry_lock:
return sorted(cls._instance.keys())
[Doku]
@classmethod
def unregister(cls, name: str) -> bool:
"""Remove the feeder registered under *name*.
:param name: Feeder name to remove.
:type name: str
:return: ``True`` if the entry existed and was removed.
:rtype: bool
"""
with _registry_lock:
if name in cls._instance:
del cls._instance[name]
logger.debug("FeederRegistry: unregistered '%s'.", name)
return True
return False
[Doku]
def register_feeder(name: str):
"""Class decorator that registers a feeder in :class:`FeederRegistry`.
The decorated class must be a subclass of
:class:`~vyra_base.com.feeder.interfaces.IFeeder` (or
:class:`~vyra_base.com.feeder.custom_feeder.CustomBaseFeeder`).
:param name: The name under which this feeder is registered. Should
match the ``functionname`` in the module's interface config JSON so
that the framework can select the correct protocol automatically.
:type name: str
:raises TypeError: If the decorated class is not an ``IFeeder`` subclass.
Example::
@register_feeder("TemperatureFeed")
class TemperatureFeeder(CustomBaseFeeder):
pass
"""
def decorator(cls: Type[IFeeder]) -> Type[IFeeder]:
FeederRegistry.register(name, cls)
return cls
return decorator