Внедрение зависимостей
DI - это метод программирования, который делает класс независимым от его зависимостей.
Это достигается путем отделения использования объекта от его создания.
Это поможет вам следовать принципу инверсии зависимостей SOLID и принципу единой ответственности.
Как это работает в aliceio
Для каждого события в aliceio.dispatcher.dispatcher.Dispatcher проходит обработка контекстных данных. Фильтры и мидлвари также могут вносить изменения в контекст.
Для доступа к контекстным данным необходимо указать соответствующий ключевой параметр в хэндлере или фильтре.
Например, чтобы получить aliceio.fsm.context.FSMContext, достаточно сделать так:
| @router.message(...)
async def some_message(message: Message, skill: Skill, state: FSMContext) -> Any:
... # do something
|
Внедрение собственных зависимостей
Aliceio предоставляет несколько способов дополнения и изменения контекстных данных.
Инициализация
Первый и самый простой способ - просто указать именованные аргументы при иницализации aliceio.dispatcher.dispatcher.Dispatcher или aliceio.webhook.aiohttp_server.OneSkillAiohttpRequestHandler.
| def main() -> None:
dp = Dispatcher(..., foo=42)
...
|
| def main() -> None:
dp = Dispatcher(..., foo=42)
handler = OneSkillAiohttpRequestHandler(dispatcher=dp, skill=skill, bar="Bazz")
...
|
Также можно изменять workflow_data в aliceio.dispatcher.dispatcher.Dispatcher как словарь:
| dp = Dispatcher(...)
dp["eggs"] = Spam()
|
Мидлвари
Мидлвари также могут изменять контекст:
| class RandomFloatMiddleware(BaseMiddleware[Message]):
def __init__(self, start: float = 0.01, end: float = 100.0) -> None:
self.start = start
self.end = end
async def __call__(
self,
handler: Callable[[Message, dict[str, Any]], Awaitable[Any]],
event: Message,
data: dict[str, Any],
) -> Any:
# Добаляем значение в контекст
data["float_num"] = round(random.uniform(self.start, self.end), 3)
return await handler(event, data)
|
Фильтры
Фильтры могут дополнять контекстные данные:
| class RandomNumberFilter(BaseFilter):
async def __call__(
self,
message: Message,
event_from_user: User
# Фильтры также могут принимать данные из контекста как обработчики
) -> Union[bool, dict[str, Any]]:
if message.command == "число":
# Возврат словаря обновит контекст
return {"int_num": random.randint(1_000, 10_000)}
return False
|
Или через MagicFilter с помощью метода .as_(...):
| @router.message(F.text.as_("real_text"), ~F.session.new)
async def start_handler(message: Message, real_text: str) -> str:
assert real_text == message.text
return real_text
|
Примеры