Coverage for src / dataknobs_bots / api / dependencies.py: 0%
35 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-16 10:13 -0700
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-16 10:13 -0700
1"""Dependency injection helpers for FastAPI.
3This module provides singleton management and FastAPI dependency injection
4for bot-related services.
6Example:
7 ```python
8 from fastapi import FastAPI
9 from dataknobs_bots.api.dependencies import (
10 init_bot_manager,
11 BotManagerDep,
12 )
14 app = FastAPI()
16 @app.on_event("startup")
17 async def startup():
18 # Initialize with a config loader
19 init_bot_manager(config_loader=my_loader)
21 @app.post("/chat/{bot_id}")
22 async def chat(
23 bot_id: str,
24 message: str,
25 manager: BotManagerDep,
26 ):
27 bot = await manager.get_or_create(bot_id)
28 return await bot.chat(message, context)
29 ```
30"""
32from __future__ import annotations
34import logging
35from typing import Annotated, Any
37from dataknobs_bots.bot.manager import BotManager, ConfigLoaderType
40logger = logging.getLogger(__name__)
43class _BotManagerSingleton:
44 """Singleton container for BotManager instance.
46 Using a class-based approach avoids global statement warnings
47 while maintaining singleton semantics.
48 """
50 _instance: BotManager | None = None
52 @classmethod
53 def get(cls) -> BotManager:
54 """Get the singleton instance, creating with defaults if needed."""
55 if cls._instance is None:
56 cls._instance = BotManager()
57 logger.info("Created default BotManager singleton (no config loader)")
58 return cls._instance
60 @classmethod
61 def init(
62 cls,
63 config_loader: ConfigLoaderType | None = None,
64 **kwargs: Any,
65 ) -> BotManager:
66 """Initialize the singleton with configuration."""
67 cls._instance = BotManager(config_loader=config_loader, **kwargs)
68 logger.info("Initialized BotManager singleton")
69 return cls._instance
71 @classmethod
72 def reset(cls) -> None:
73 """Reset the singleton instance."""
74 cls._instance = None
75 logger.info("Reset BotManager singleton")
78def get_bot_manager() -> BotManager:
79 """Get or create BotManager singleton instance.
81 Returns:
82 BotManager instance
84 Note:
85 Call `init_bot_manager()` during app startup to configure
86 the singleton before using this dependency.
87 """
88 return _BotManagerSingleton.get()
91def init_bot_manager(
92 config_loader: ConfigLoaderType | None = None,
93 **kwargs: Any,
94) -> BotManager:
95 """Initialize the BotManager singleton with configuration.
97 Call this during application startup to configure the singleton.
99 Args:
100 config_loader: Optional configuration loader for bots
101 **kwargs: Additional arguments passed to BotManager
103 Returns:
104 Configured BotManager instance
106 Example:
107 ```python
108 @app.on_event("startup")
109 async def startup():
110 init_bot_manager(
111 config_loader=MyConfigLoader("./configs")
112 )
113 ```
114 """
115 return _BotManagerSingleton.init(config_loader=config_loader, **kwargs)
118def reset_bot_manager() -> None:
119 """Reset the BotManager singleton.
121 Useful for testing or when reconfiguring the application.
122 """
123 _BotManagerSingleton.reset()
126# Dependency function for FastAPI
127def _get_bot_manager_dep() -> BotManager:
128 """Dependency function for FastAPI."""
129 return get_bot_manager()
132# Type alias for FastAPI dependency injection
133# Usage: async def endpoint(manager: BotManagerDep):
134try:
135 from fastapi import Depends
137 BotManagerDep = Annotated[BotManager, Depends(_get_bot_manager_dep)]
138except ImportError:
139 # FastAPI not installed - provide a placeholder
140 BotManagerDep = BotManager # type: ignore