36 lines
1.1 KiB
Python
36 lines
1.1 KiB
Python
"""Auto-discovery for channel modules — no hardcoded registry."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import pkgutil
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from nanobot.channels.base import BaseChannel
|
|
|
|
_INTERNAL = frozenset({"base", "manager", "registry"})
|
|
|
|
|
|
def discover_channel_names() -> list[str]:
|
|
"""Return all channel module names by scanning the package (zero imports)."""
|
|
import nanobot.channels as pkg
|
|
|
|
return [
|
|
name
|
|
for _, name, ispkg in pkgutil.iter_modules(pkg.__path__)
|
|
if name not in _INTERNAL and not ispkg
|
|
]
|
|
|
|
|
|
def load_channel_class(module_name: str) -> type[BaseChannel]:
|
|
"""Import *module_name* and return the first BaseChannel subclass found."""
|
|
from nanobot.channels.base import BaseChannel as _Base
|
|
|
|
mod = importlib.import_module(f"nanobot.channels.{module_name}")
|
|
for attr in dir(mod):
|
|
obj = getattr(mod, attr)
|
|
if isinstance(obj, type) and issubclass(obj, _Base) and obj is not _Base:
|
|
return obj
|
|
raise ImportError(f"No BaseChannel subclass in nanobot.channels.{module_name}")
|