PoC: Bot instance inside method shortcuts using pydantic Validation Context (#1210)

* PoC: Mount objects to the Bot instance, bind shortcuts to configured instance

* Fixe docstring of the bind method

* Pass Bot instance explicitly to the URLInputFile

* Added tests

* Added changelog

* Refactor aiogram client and update tests

Refactored base.py to improve code readability by separating response_type operation from model_validate(). Also, adjusted the parameters in URLInputFile() within test_input_file.py for better test coverage. Updated input_file.py to streamline read method and avoid unnecessary instantiation of Bot class. Lastly, adjusted typing in methods/base.py to enhance code clarity.

* Update changelog
This commit is contained in:
Alex Root Junior 2023-07-11 23:17:26 +03:00 committed by GitHub
parent c39a803747
commit a7b92bb050
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 228 additions and 111 deletions

View file

@ -35,7 +35,7 @@ class MockedSession(BaseSession):
self.requests.append(method)
response: Response[TelegramType] = self.responses.pop()
self.check_response(
method=method, status_code=response.error_code, content=response.json()
bot=bot, method=method, status_code=response.error_code, content=response.json()
)
return response.result # type: ignore

View file

@ -0,0 +1,36 @@
from aiogram.client.context_controller import BotContextController
from tests.mocked_bot import MockedBot
class MyModel(BotContextController):
id: int
class TestBotContextController:
def test_via_model_validate(self, bot: MockedBot):
my_model = MyModel.model_validate({"id": 1}, context={"bot": bot})
assert my_model.id == 1
assert my_model._bot == bot
def test_via_model_validate_none(self):
my_model = MyModel.model_validate({"id": 1}, context={})
assert my_model.id == 1
assert my_model._bot is None
def test_as(self, bot: MockedBot):
my_model = MyModel(id=1).as_(bot)
assert my_model.id == 1
assert my_model._bot == bot
def test_as_none(self):
my_model = MyModel(id=1).as_(None)
assert my_model.id == 1
assert my_model._bot is None
def test_replacement(self, bot: MockedBot):
my_model = MyModel(id=1).as_(bot)
assert my_model.id == 1
assert my_model._bot == bot
my_model = my_model.as_(None)
assert my_model.id == 1
assert my_model._bot is None

View file

@ -170,9 +170,11 @@ class TestBaseSession:
)
def test_check_response(self, status_code, content, error):
session = CustomSession()
bot = MockedBot()
method = DeleteMessage(chat_id=42, message_id=42)
if error is None:
session.check_response(
bot=bot,
method=method,
status_code=status_code,
content=content,
@ -180,6 +182,7 @@ class TestBaseSession:
else:
with pytest.raises(error) as exc_info:
session.check_response(
bot=bot,
method=method,
status_code=status_code,
content=content,
@ -191,10 +194,12 @@ class TestBaseSession:
def test_check_response_json_decode_error(self):
session = CustomSession()
bot = MockedBot()
method = DeleteMessage(chat_id=42, message_id=42)
with pytest.raises(ClientDecodeError, match="JSONDecodeError"):
session.check_response(
bot=bot,
method=method,
status_code=200,
content="is not a JSON object",
@ -202,10 +207,12 @@ class TestBaseSession:
def test_check_response_validation_error(self):
session = CustomSession()
bot = MockedBot()
method = DeleteMessage(chat_id=42, message_id=42)
with pytest.raises(ClientDecodeError, match="ValidationError"):
session.check_response(
bot=bot,
method=method,
status_code=200,
content='{"ok": "test"}',

View file

@ -22,6 +22,14 @@ class TestTelegramMethodRemoveUnset:
class TestTelegramMethodCall:
async def test_async_emit_unsuccessful(self, bot: MockedBot):
with pytest.raises(
RuntimeError,
match="This method is not mounted to a any bot instance.+",
):
await GetMe()
async def test_async_emit(self, bot: MockedBot):
bot.add_result_for(GetMe, ok=True, result=User(id=42, is_bot=True, first_name="Test"))
assert isinstance(await GetMe(), User)
method = GetMe().as_(bot)
assert isinstance(await method, User)

View file

@ -4,6 +4,7 @@ from aresponses import ResponsesMockServer
from aiogram import Bot
from aiogram.types import BufferedInputFile, FSInputFile, InputFile, URLInputFile
from tests.mocked_bot import MockedBot
class TestInputFile:
@ -72,10 +73,8 @@ class TestInputFile:
aresponses.add(
aresponses.ANY, aresponses.ANY, "get", aresponses.Response(status=200, body=b"\f" * 10)
)
Bot.set_current(Bot("42:TEST"))
file = URLInputFile("https://test.org/", chunk_size=1)
bot = Bot(token="42:TEST")
file = URLInputFile("https://test.org/", bot, chunk_size=1)
size = 0
async for chunk in file: