Implemented Phase 2.4 (Dependency Injection Pattern): - Added new dependencies module with DI container and runtime context - RuntimeContainer for injectable factories - RuntimeContext for resolved runtime objects - create_service_manager() factory - build_runtime_context() composition root - Refactored main.py to use dependency container wiring - Main orchestration now resolves runtime via DI factories - Reduced direct constructor coupling in entrypoint - Added unit tests for DI behavior with mocked dependencies - Verifies factory injection for service manager creation - Verifies runtime composition uses injected callables - Updated optimization plan checkboxes for Phase 2.4 Validation: - py_compile passed for new/changed files - tests/unit/test_dependencies.py passed - regression test test_event_queue::test_enqueue passed Notes: - Keeps existing runtime behavior unchanged - Establishes clear composition root for future testability improvements
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""Dependency injection helpers for IoT Bridge runtime wiring."""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Callable
|
|
|
|
from core.bootstrap import BootstrapConfig, bootstrap, get_mqtt_config
|
|
from core.service_manager import ServiceManager
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RuntimeContainer:
|
|
"""Container for runtime dependencies and factory callables."""
|
|
|
|
bootstrap_factory: Callable[[], BootstrapConfig] = bootstrap
|
|
mqtt_config_factory: Callable[[object], object] = get_mqtt_config
|
|
service_manager_factory: Callable[..., ServiceManager] = ServiceManager
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RuntimeContext:
|
|
"""Resolved runtime objects used by main orchestration."""
|
|
|
|
boot_config: BootstrapConfig
|
|
service_manager: ServiceManager
|
|
mqtt_config: object
|
|
|
|
|
|
def create_service_manager(
|
|
boot_config: BootstrapConfig,
|
|
service_manager_factory: Callable[..., ServiceManager] = ServiceManager,
|
|
) -> ServiceManager:
|
|
"""Create service manager via injectable factory."""
|
|
return service_manager_factory(
|
|
config=boot_config.config,
|
|
logger=boot_config.logger,
|
|
bridge_port=boot_config.bridge_port,
|
|
bridge_token=boot_config.bridge_token,
|
|
)
|
|
|
|
|
|
def build_runtime_context(container: RuntimeContainer | None = None) -> RuntimeContext:
|
|
"""Resolve runtime context from dependency container."""
|
|
runtime_container = container or RuntimeContainer()
|
|
|
|
boot_config = runtime_container.bootstrap_factory()
|
|
service_manager = create_service_manager(
|
|
boot_config=boot_config,
|
|
service_manager_factory=runtime_container.service_manager_factory,
|
|
)
|
|
mqtt_config = runtime_container.mqtt_config_factory(boot_config.config)
|
|
|
|
return RuntimeContext(
|
|
boot_config=boot_config,
|
|
service_manager=service_manager,
|
|
mqtt_config=mqtt_config,
|
|
)
|