diff --git a/aiogram/api/types/base.py b/aiogram/api/types/base.py index 8c098202..a75b121a 100644 --- a/aiogram/api/types/base.py +++ b/aiogram/api/types/base.py @@ -1,9 +1,15 @@ +from __future__ import annotations + import datetime +import typing from pydantic import BaseModel, Extra from aiogram.utils.mixins import ContextInstanceMixin +if typing.TYPE_CHECKING: + from ..client.bot import Bot # pragma: no cover + class TelegramObject(ContextInstanceMixin["TelegramObject"], BaseModel): class Config: @@ -15,6 +21,19 @@ class TelegramObject(ContextInstanceMixin["TelegramObject"], BaseModel): allow_population_by_field_name = True json_encoders = {datetime.datetime: lambda dt: int(dt.timestamp())} + @property + def bot(self) -> Bot: + from ..client.bot import Bot + + bot = Bot.get_current() + if bot is None: + raise RuntimeError( + "Can't get bot instance from context. " + "You can fix it with setting current instance: " + "'Bot.set_current(bot_instance)'" + ) + return bot + class MutableTelegramObject(TelegramObject): class Config: diff --git a/tests/test_api/test_types/test_telegram_object.py b/tests/test_api/test_types/test_telegram_object.py new file mode 100644 index 00000000..b7f5bc1b --- /dev/null +++ b/tests/test_api/test_types/test_telegram_object.py @@ -0,0 +1,21 @@ +import pytest + +from aiogram import Bot +from aiogram.api.types import TelegramObject + + +class TestTelegramObject: + @pytest.fixture() + def context_cleanup(self): + yield + Bot.reset_current(self.__token) + + @pytest.mark.usefixtures("context_cleanup") + def test_bot_property_positive(self): + self.__token = Bot.set_current(Bot("42:TEST")) + + assert isinstance(TelegramObject().bot, Bot) + + def test_bot_property_negative(self): + with pytest.raises(RuntimeError, match=r"Bot.set_current\(bot_instance\)"): + isinstance(TelegramObject().bot, Bot)