Инъекция бота в типы (BotMixin)¶
BotMixin - это mixin, который добавляет в датакласс ссылку на экземпляр бота.
Все типы, наследующие MaxoType, автоматически получают эту функциональность, так как MaxoType уже включает BotMixin.
Зачем это нужно?¶
Иногда удобно, чтобы десериализованный объект сам мог обращаться к боту - например,
для выполнения API-вызовов прямо из метода типа. Благодаря BotMixin вам не нужно
вручную пробрасывать bot через аргументы каждого метода.
from maxo.types import MaxoType
class UserProfile(MaxoType):
user_id: int
name: str
async def notify(self, text: str) -> None:
await self.bot.send_message(chat_id=self.user_id, text=text)
Свойство bot¶
BotMixin добавляет свойство bot, которое возвращает экземпляр Bot.
profile: UserProfile = ...
bot_instance = profile.bot # Bot
Если бот не был внедрён, обращение к свойству вызовет AttributeIsEmptyError:
from maxo.errors import AttributeIsEmptyError
profile = UserProfile(user_id=1, name="Alice")
try:
_ = profile.bot
except AttributeIsEmptyError:
print("Бот не внедрён в объект!")
Метод as_¶
as_(bot) внедряет бота в объект и возвращает его же (self), что позволяет использовать fluent-стиль:
profile = UserProfile(user_id=1, name="Alice").as_(bot)
await profile.notify("Привет!")
Автоматическая инъекция через ретроту¶
Основной сценарий использования BotMixin - автоматическое внедрение бота при десериализации
через Retort. Реторта бота (bot.retort) настроена так,
что при загрузке любого MaxoType бот автоматически присваивается каждому объекту в дереве вложенности.
from maxo.types import MaxoType
class Sub(MaxoType):
value: int
class MyData(MaxoType):
name: str
sub: Sub
# bot.retort автоматически внедряет бот во все MaxoType-объекты
data = {"name": "test", "sub": {"value": 42}}
my = bot.retort.load(data, MyData)
assert my.bot is bot # бот внедрён в корневой объект
assert my.sub.bot is bot # и во вложенный
Обратная операция - dump - также работает корректно и не включает поле _bot в результат:
result = bot.retort.dump(my, MyData)
assert result == {"name": "test", "sub": {"value": 42}}
Использование create_retort вручную¶
Если вы создаёте ретроту самостоятельно через create_retort(),
передайте bot= для включения инъекции:
from maxo.serialization import create_retort
retort = create_retort(bot=bot)
my = retort.load(data, MyData)
assert my.bot is bot
Если bot не передан (или передан как None), инъекция не производится,
и обращение к .bot вызовет AttributeIsEmptyError:
from maxo.errors import AttributeIsEmptyError
retort = create_retort() # bot не передан
my = retort.load(data, MyData)
try:
_ = my.bot
except AttributeIsEmptyError:
print("Бот не внедрён!") # ожидаемое поведение
Создание собственных миксинов¶
Если вы хотите добавить функциональность бота только к отдельным типам, не используя MaxoType,
можно унаследоваться напрямую от BotMixin:
from maxo.types import BaseMaxoType, BotMixin
class LightType(BaseMaxoType, BotMixin):
value: int
Примечание
При использовании BotMixin без MaxoType инъекция через bot.retort работает
только для типов, которые являются подклассами MaxoType. Для LightType потребуется
вызвать as_(bot) вручную.
API¶
- class maxo.types.BotMixin[исходный код]¶
-
- as_(bot)[исходный код]¶
- class maxo.types.BaseMaxoType[исходный код]¶
Базовые классы:
objectBaseMaxoType()
- class maxo.types.MaxoType[исходный код]¶
Базовые классы:
BaseMaxoType,BotMixinMaxoType()