mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 05:40:26 +02:00
feat: add TTSBackendRegistry for backend registration and creation
- TTSBackendRegistry class with register(), list_backends(), get_metadata(), create_backend() - Global registry singleton with register_backend() and create_backend() convenience functions - Unit tests for registry operations
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
"""
|
||||||
|
TTS Backend Registry
|
||||||
|
|
||||||
|
Provides a global registry for TTS backend factories.
|
||||||
|
Backends register themselves with metadata and a factory callable.
|
||||||
|
The registry is universal and does not know about backend constructors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Callable, Any
|
||||||
|
|
||||||
|
from abogen.tts_backend import TTSBackend, TTSBackendMetadata
|
||||||
|
|
||||||
|
|
||||||
|
class TTSBackendRegistry:
|
||||||
|
"""Registry of TTS backend factories.
|
||||||
|
|
||||||
|
Stores metadata and factory callables for registered backends.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._backends: dict[str, TTSBackendMetadata] = {}
|
||||||
|
self._factories: dict[str, Callable[..., TTSBackend]] = {}
|
||||||
|
|
||||||
|
def register(
|
||||||
|
self,
|
||||||
|
metadata: TTSBackendMetadata,
|
||||||
|
factory: Callable[..., TTSBackend],
|
||||||
|
) -> None:
|
||||||
|
"""Register a backend with its metadata and factory callable."""
|
||||||
|
self._backends[metadata.id] = metadata
|
||||||
|
self._factories[metadata.id] = factory
|
||||||
|
|
||||||
|
def list_backends(self) -> list[TTSBackendMetadata]:
|
||||||
|
"""Return metadata for all registered backends."""
|
||||||
|
return list(self._backends.values())
|
||||||
|
|
||||||
|
def get_metadata(self, backend_id: str) -> TTSBackendMetadata:
|
||||||
|
"""Get metadata for a specific backend.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: If backend with given id is not registered.
|
||||||
|
"""
|
||||||
|
if backend_id not in self._backends:
|
||||||
|
raise KeyError(f"Unknown backend: {backend_id}")
|
||||||
|
return self._backends[backend_id]
|
||||||
|
|
||||||
|
def create_backend(self, backend_id: str, **kwargs: Any) -> TTSBackend:
|
||||||
|
"""Create a backend instance by id.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: If backend with given id is not registered.
|
||||||
|
"""
|
||||||
|
if backend_id not in self._factories:
|
||||||
|
raise KeyError(f"Unknown backend: {backend_id}")
|
||||||
|
return self._factories[backend_id](**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
_registry = TTSBackendRegistry()
|
||||||
|
|
||||||
|
|
||||||
|
def register_backend(
|
||||||
|
metadata: TTSBackendMetadata,
|
||||||
|
factory: Callable[..., TTSBackend],
|
||||||
|
) -> None:
|
||||||
|
"""Register a TTS backend in the global registry."""
|
||||||
|
_registry.register(metadata, factory)
|
||||||
|
|
||||||
|
|
||||||
|
def create_backend(backend_id: str, **kwargs: Any) -> TTSBackend:
|
||||||
|
"""Create a TTS backend instance by provider id."""
|
||||||
|
return _registry.create_backend(backend_id, **kwargs)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from abogen.tts_backend import TTSBackendMetadata
|
from abogen.tts_backend import TTSBackendMetadata
|
||||||
|
from abogen.tts_backend_registry import TTSBackendRegistry
|
||||||
|
|
||||||
|
|
||||||
class TestTTSBackendMetadata:
|
class TestTTSBackendMetadata:
|
||||||
@@ -27,3 +28,72 @@ class TestTTSBackendMetadata:
|
|||||||
)
|
)
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
meta.id = "changed"
|
meta.id = "changed"
|
||||||
|
|
||||||
|
|
||||||
|
class TestTTSBackendRegistry:
|
||||||
|
def test_register_and_list(self):
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
meta = TTSBackendMetadata(id="a", name="A", description="Backend A")
|
||||||
|
registry.register(metadata=meta, factory=lambda: None)
|
||||||
|
|
||||||
|
backends = registry.list_backends()
|
||||||
|
assert len(backends) == 1
|
||||||
|
assert backends[0].id == "a"
|
||||||
|
|
||||||
|
def test_list_multiple(self):
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
meta_a = TTSBackendMetadata(id="a", name="A", description="A")
|
||||||
|
meta_b = TTSBackendMetadata(id="b", name="B", description="B")
|
||||||
|
registry.register(metadata=meta_a, factory=lambda: None)
|
||||||
|
registry.register(metadata=meta_b, factory=lambda: None)
|
||||||
|
|
||||||
|
backends = registry.list_backends()
|
||||||
|
ids = [b.id for b in backends]
|
||||||
|
assert "a" in ids
|
||||||
|
assert "b" in ids
|
||||||
|
|
||||||
|
def test_get_metadata(self):
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
meta = TTSBackendMetadata(id="x", name="X", description="X backend")
|
||||||
|
registry.register(metadata=meta, factory=lambda: None)
|
||||||
|
|
||||||
|
result = registry.get_metadata("x")
|
||||||
|
assert result.id == "x"
|
||||||
|
assert result.name == "X"
|
||||||
|
|
||||||
|
def test_get_metadata_unknown_raises(self):
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
with pytest.raises(KeyError, match="Unknown backend: nope"):
|
||||||
|
registry.get_metadata("nope")
|
||||||
|
|
||||||
|
def test_create_backend(self):
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
meta = TTSBackendMetadata(id="test", name="Test", description="Test backend")
|
||||||
|
|
||||||
|
def factory(**kwargs):
|
||||||
|
return {"created": True, "kwargs": kwargs}
|
||||||
|
|
||||||
|
registry.register(metadata=meta, factory=factory)
|
||||||
|
result = registry.create_backend("test", foo="bar")
|
||||||
|
|
||||||
|
assert result == {"created": True, "kwargs": {"foo": "bar"}}
|
||||||
|
|
||||||
|
def test_create_backend_unknown_raises(self):
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
with pytest.raises(KeyError, match="Unknown backend: missing"):
|
||||||
|
registry.create_backend("missing")
|
||||||
|
|
||||||
|
def test_register_overwrites(self):
|
||||||
|
registry = TTSBackendRegistry()
|
||||||
|
meta1 = TTSBackendMetadata(id="x", name="V1", description="First")
|
||||||
|
meta2 = TTSBackendMetadata(id="x", name="V2", description="Second")
|
||||||
|
registry.register(metadata=meta1, factory=lambda: "v1")
|
||||||
|
registry.register(metadata=meta2, factory=lambda: "v2")
|
||||||
|
|
||||||
|
result = registry.get_metadata("x")
|
||||||
|
assert result.name == "V2"
|
||||||
|
assert registry.create_backend("x") == "v2"
|
||||||
|
|||||||
Reference in New Issue
Block a user