| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- # -*- coding: utf-8 -*-
- """
- Trainer-Registry: Erkennung und Verwaltung von Trainern.
- Sucht Core-Trainer in trixy_core/trainer/core/*.py und
- Plugin-Trainer in plugins/*/trainer.py.
- """
- from __future__ import annotations
- import importlib
- import importlib.util
- import inspect
- from pathlib import Path
- from trixy_core.trainer.itrainer import ITrainer
- from trixy_core.trainer.dataclasses import TrainerInfo
- from trixy_core.trainer.enums import TrainerType
- from trixy_core.utils.debug import pdebug, perror
- class TrainerRegistry:
- """Verwaltet alle verfuegbaren Trainer."""
- def __init__(self) -> None:
- self._trainers: dict[str, ITrainer] = {}
- @property
- def trainers(self) -> dict[str, ITrainer]:
- """Alle registrierten Trainer."""
- return dict(self._trainers)
- def register(self, trainer: ITrainer) -> None:
- """Registriert einen Trainer manuell."""
- info = trainer.get_info()
- self._trainers[info.trainer_id] = trainer
- pdebug(f"Trainer registriert: {info.name} ({info.trainer_id})")
- def get(self, trainer_id: str) -> ITrainer | None:
- """Liefert einen Trainer nach ID."""
- return self._trainers.get(trainer_id)
- def discover_core(self) -> int:
- """
- Sucht Core-Trainer in trixy_core/trainer/core/.
- Returns:
- Anzahl gefundener Trainer
- """
- core_dir = Path(__file__).parent / "core"
- if not core_dir.exists():
- return 0
- count = 0
- # Flache .py Dateien
- for py_file in core_dir.glob("*.py"):
- if py_file.name.startswith("_"):
- continue
- try:
- module_name = f"trixy_core.trainer.core.{py_file.stem}"
- module = importlib.import_module(module_name)
- count += self._scan_module(module, TrainerType.CORE)
- except Exception as e:
- pdebug(f"Core-Trainer Fehler: {py_file.stem}: {e}")
- # Subdirectories mit trainer.py oder __init__.py
- for sub_dir in core_dir.iterdir():
- if not sub_dir.is_dir() or sub_dir.name.startswith("_"):
- continue
- # trainer.py im Subdirectory suchen
- trainer_file = sub_dir / "trainer.py"
- if trainer_file.is_file():
- try:
- module_name = f"trixy_core.trainer.core.{sub_dir.name}.trainer"
- module = importlib.import_module(module_name)
- found = self._scan_module(module, TrainerType.CORE)
- count += found
- if found:
- pdebug(f"Core-Trainer entdeckt: {sub_dir.name}/trainer.py")
- except Exception as e:
- pdebug(f"Core-Trainer Fehler: {sub_dir.name}: {e}")
- return count
- def discover_plugins(self, plugins_dir: str = "plugins") -> int:
- """
- Sucht Plugin-Trainer in plugins/*/trainer.py.
- Returns:
- Anzahl gefundener Trainer
- """
- base = Path(plugins_dir)
- if not base.exists():
- return 0
- count = 0
- for trainer_file in base.glob("*/trainer.py"):
- try:
- spec = importlib.util.spec_from_file_location(
- f"plugin_trainer_{trainer_file.parent.name}",
- trainer_file,
- )
- if spec and spec.loader:
- module = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(module)
- count += self._scan_module(module, TrainerType.PLUGIN)
- except Exception as e:
- perror(f"Fehler beim Laden von Plugin-Trainer {trainer_file}: {e}")
- return count
- def _scan_module(self, module: object, trainer_type: TrainerType) -> int:
- """Scannt ein Modul nach ITrainer-Klassen und instanziiert sie."""
- count = 0
- for _, cls in inspect.getmembers(module, inspect.isclass):
- if (
- issubclass(cls, ITrainer)
- and cls is not ITrainer
- and not inspect.isabstract(cls)
- ):
- try:
- instance = cls()
- info = instance.get_info()
- info.trainer_type = trainer_type
- self._trainers[info.trainer_id] = instance
- count += 1
- pdebug(f"Trainer entdeckt: {info.name} ({trainer_type.value})")
- except Exception as e:
- perror(f"Fehler beim Instanziieren von {cls.__name__}: {e}")
- return count
- def list_info(self) -> list[TrainerInfo]:
- """Liefert Info-Objekte aller registrierten Trainer."""
- result = []
- for trainer in self._trainers.values():
- result.append(trainer.get_info())
- return result
|