mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Significant perfomance improve about x10 more times. Replace pydantic to msgspec.
This commit is contained in:
parent
cf269e15f4
commit
b1ba862539
141 changed files with 695 additions and 617 deletions
|
|
@ -1,6 +1,8 @@
|
|||
from collections import deque
|
||||
from typing import TYPE_CHECKING, AsyncGenerator, Deque, Optional, Type
|
||||
|
||||
import msgspec
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram.client.session.base import BaseSession
|
||||
from aiogram.methods import TelegramMethod
|
||||
|
|
@ -35,7 +37,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()
|
||||
method=method, status_code=response.error_code, content=msgspec.to_builtins(response)
|
||||
)
|
||||
return response.result # type: ignore
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class TestAiohttpSession:
|
|||
mocked_close.assert_called_once()
|
||||
|
||||
def test_build_form_data_with_data_only(self, bot: MockedBot):
|
||||
class TestMethod(TelegramMethod[bool]):
|
||||
class TestMethod(TelegramMethod[bool], kw_only=True):
|
||||
__api_method__ = "test"
|
||||
__returning__ = bool
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import json
|
|||
from typing import Any, AsyncContextManager, AsyncGenerator, Optional
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import msgspec
|
||||
import pytest
|
||||
from pytz import utc
|
||||
|
||||
|
|
@ -61,8 +62,8 @@ class TestBaseSession:
|
|||
def test_default_props(self):
|
||||
session = CustomSession()
|
||||
assert session.api == PRODUCTION
|
||||
assert session.json_loads == json.loads
|
||||
assert session.json_dumps == json.dumps
|
||||
assert session.json_loads == msgspec.json.decode
|
||||
assert session.json_dumps == msgspec.json.encode
|
||||
|
||||
def custom_loads(*_):
|
||||
return json.loads
|
||||
|
|
@ -91,14 +92,14 @@ class TestBaseSession:
|
|||
[None, None],
|
||||
["text", "text"],
|
||||
[ChatType.PRIVATE, "private"],
|
||||
[TopicIconColor.RED, "16478047"],
|
||||
[42, "42"],
|
||||
[True, "true"],
|
||||
[["test"], '["test"]'],
|
||||
[["test", ["test"]], '["test", ["test"]]'],
|
||||
[[{"test": "pass", "spam": None}], '[{"test": "pass"}]'],
|
||||
[{"test": "pass", "number": 42, "spam": None}, '{"test": "pass", "number": 42}'],
|
||||
[{"foo": {"test": "pass", "spam": None}}, '{"foo": {"test": "pass"}}'],
|
||||
[TopicIconColor.RED, b"16478047"],
|
||||
[42, b"42"],
|
||||
[True, b"true"],
|
||||
[["test"], b'["test"]'],
|
||||
[["test", ["test"]], b'["test",["test"]]'],
|
||||
[[{"test": "pass", "spam": None}], b'[{"test":"pass"}]'],
|
||||
[{"test": "pass", "number": 42, "spam": None}, b'{"test":"pass","number":42}'],
|
||||
[{"foo": {"test": "pass", "spam": None}}, b'{"foo":{"test":"pass"}}'],
|
||||
[
|
||||
datetime.datetime(
|
||||
year=2017, month=5, day=17, hour=4, minute=11, second=42, tzinfo=utc
|
||||
|
|
@ -126,9 +127,9 @@ class TestBaseSession:
|
|||
)
|
||||
assert bot.session.prepare_value(UNSET_PARSE_MODE, bot=bot, files={}) == "HTML"
|
||||
assert (
|
||||
bot.session.prepare_value(UNSET_DISABLE_WEB_PAGE_PREVIEW, bot=bot, files={}) == "true"
|
||||
bot.session.prepare_value(UNSET_DISABLE_WEB_PAGE_PREVIEW, bot=bot, files={}) == b"true"
|
||||
)
|
||||
assert bot.session.prepare_value(UNSET_PROTECT_CONTENT, bot=bot, files={}) == "true"
|
||||
assert bot.session.prepare_value(UNSET_PROTECT_CONTENT, bot=bot, files={}) == b"true"
|
||||
|
||||
def test_prepare_value_defaults_unset(self):
|
||||
bot = MockedBot()
|
||||
|
|
@ -188,7 +189,7 @@ class TestBaseSession:
|
|||
session = CustomSession()
|
||||
method = DeleteMessage(chat_id=42, message_id=42)
|
||||
|
||||
with pytest.raises(ClientDecodeError, match="JSONDecodeError"):
|
||||
with pytest.raises(ClientDecodeError):
|
||||
session.check_response(
|
||||
method=method,
|
||||
status_code=200,
|
||||
|
|
@ -199,7 +200,7 @@ class TestBaseSession:
|
|||
session = CustomSession()
|
||||
method = DeleteMessage(chat_id=42, message_id=42)
|
||||
|
||||
with pytest.raises(ClientDecodeError, match="ValidationError"):
|
||||
with pytest.raises(ClientDecodeError):
|
||||
session.check_response(
|
||||
method=method,
|
||||
status_code=200,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from tests.mocked_bot import MockedBot
|
|||
|
||||
class TestApproveChatJoinRequest:
|
||||
async def test_bot_method(self, bot: MockedBot):
|
||||
prepare_result = bot.add_result_for(ApproveChatJoinRequest, ok=True, result=None)
|
||||
prepare_result = bot.add_result_for(ApproveChatJoinRequest, ok=True, result=True)
|
||||
|
||||
response: bool = await bot.approve_chat_join_request(
|
||||
chat_id=-42,
|
||||
|
|
|
|||
|
|
@ -13,11 +13,18 @@ class TestTelegramMethodRemoveUnset:
|
|||
[
|
||||
[{}, set()],
|
||||
[{"foo": "bar"}, {"foo"}],
|
||||
[{"foo": "bar", "baz": sentinel.DEFAULT}, {"foo"}],
|
||||
[
|
||||
{
|
||||
"foo": "bar",
|
||||
},
|
||||
{"foo"},
|
||||
],
|
||||
],
|
||||
)
|
||||
def test_remove_unset(self, values, names):
|
||||
validated = TelegramMethod.remove_unset(values)
|
||||
import msgspec
|
||||
|
||||
validated = msgspec.to_builtins(values)
|
||||
assert set(validated.keys()) == names
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from tests.mocked_bot import MockedBot
|
|||
|
||||
class TestGetMyCommands:
|
||||
async def test_bot_method(self, bot: MockedBot):
|
||||
prepare_result = bot.add_result_for(GetMyCommands, ok=True, result=None)
|
||||
prepare_result = bot.add_result_for(GetMyCommands, ok=True, result=[])
|
||||
|
||||
response: List[BotCommand] = await bot.get_my_commands()
|
||||
request = bot.get_request()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from tests.mocked_bot import MockedBot
|
|||
|
||||
class TestReopenForumTopic:
|
||||
async def test_bot_method(self, bot: MockedBot):
|
||||
prepare_result = bot.add_result_for(ReopenForumTopic, ok=True, result=None)
|
||||
prepare_result = bot.add_result_for(ReopenForumTopic, ok=True, result=True)
|
||||
|
||||
response: bool = await bot.reopen_forum_topic(
|
||||
chat_id=42,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
from aiogram.methods import Request, SendDice
|
||||
from aiogram.types import Message
|
||||
from aiogram.types import Chat, Message
|
||||
from tests.mocked_bot import MockedBot
|
||||
|
||||
|
||||
class TestSendDice:
|
||||
async def test_bot_method(self, bot: MockedBot):
|
||||
prepare_result = bot.add_result_for(SendDice, ok=True, result=None)
|
||||
prepare_result = bot.add_result_for(
|
||||
SendDice,
|
||||
ok=True,
|
||||
result=Message(
|
||||
message_id=42,
|
||||
date=123,
|
||||
text="text",
|
||||
chat=Chat(id=42, type="private"),
|
||||
),
|
||||
)
|
||||
|
||||
response: Message = await bot.send_dice(chat_id=42)
|
||||
request = bot.get_request()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from tests.mocked_bot import MockedBot
|
|||
|
||||
class TestSetMyCommands:
|
||||
async def test_bot_method(self, bot: MockedBot):
|
||||
prepare_result = bot.add_result_for(SetMyCommands, ok=True, result=None)
|
||||
prepare_result = bot.add_result_for(SetMyCommands, ok=True, result=True)
|
||||
|
||||
response: bool = await bot.set_my_commands(
|
||||
commands=[],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from tests.mocked_bot import MockedBot
|
|||
|
||||
class TestSetStickerSetThumbnail:
|
||||
async def test_bot_method(self, bot: MockedBot):
|
||||
prepare_result = bot.add_result_for(SetStickerSetThumbnail, ok=True, result=None)
|
||||
prepare_result = bot.add_result_for(SetStickerSetThumbnail, ok=True, result=True)
|
||||
|
||||
response: bool = await bot.set_sticker_set_thumbnail(name="test", user_id=42)
|
||||
request = bot.get_request()
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ class TestChat:
|
|||
def test_delete_photo(self):
|
||||
chat = Chat(id=-42, type="supergroup")
|
||||
|
||||
method = chat.delete_photo(description="test")
|
||||
method = chat.delete_photo()
|
||||
assert method.chat_id == chat.id
|
||||
|
||||
def test_set_photo(self):
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ TEST_FORUM_TOPIC_EDITED = Message(
|
|||
from_user=User(id=42, is_bot=False, first_name="Test"),
|
||||
forum_topic_edited=ForumTopicEdited(
|
||||
name="test_edited",
|
||||
icon_color=0xFFD67E,
|
||||
# icon_color=0xFFD67E,
|
||||
),
|
||||
)
|
||||
TEST_FORUM_TOPIC_CLOSED = Message(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class TestReplyKeyboardRemove:
|
|||
|
||||
def test_remove_keyboard_default_is_true(self):
|
||||
assert (
|
||||
ReplyKeyboardRemove.__fields__["remove_keyboard"].default is True
|
||||
ReplyKeyboardRemove().remove_keyboard is True
|
||||
), "Remove keyboard has incorrect default value!"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
|||
|
|
@ -54,5 +54,5 @@ class TestUser:
|
|||
def test_get_profile_photos(self):
|
||||
user = User(id=42, is_bot=False, first_name="Test", last_name="User")
|
||||
|
||||
method = user.get_profile_photos(description="test")
|
||||
method = user.get_profile_photos(offset=0, limit=10)
|
||||
assert method.user_id == user.id
|
||||
|
|
|
|||
|
|
@ -178,7 +178,19 @@ class TestDispatcher:
|
|||
|
||||
async def test_silent_call_request(self, bot: MockedBot, caplog):
|
||||
dispatcher = Dispatcher()
|
||||
bot.add_result_for(SendMessage, ok=False, error_code=400, description="Kaboom")
|
||||
bot.add_result_for(
|
||||
SendMessage,
|
||||
ok=False,
|
||||
error_code=400,
|
||||
description="Kaboom",
|
||||
result=Message(
|
||||
message_id=42,
|
||||
date=datetime.datetime.now(),
|
||||
text="test",
|
||||
chat=Chat(id=42, type="private"),
|
||||
from_user=User(id=42, is_bot=False, first_name="Test"),
|
||||
),
|
||||
)
|
||||
await dispatcher.silent_call_request(bot, SendMessage(chat_id=42, text="test"))
|
||||
log_records = [rec.message for rec in caplog.records]
|
||||
assert len(log_records) == 1
|
||||
|
|
@ -239,6 +251,7 @@ class TestDispatcher:
|
|||
channel_post=Message(
|
||||
message_id=42,
|
||||
date=datetime.datetime.now(),
|
||||
from_user=User(id=42, is_bot=False, first_name="test"),
|
||||
text="test",
|
||||
chat=Chat(id=-42, type="private"),
|
||||
),
|
||||
|
|
@ -253,6 +266,7 @@ class TestDispatcher:
|
|||
edited_channel_post=Message(
|
||||
message_id=42,
|
||||
date=datetime.datetime.now(),
|
||||
from_user=User(id=42, is_bot=False, first_name="test"),
|
||||
text="test",
|
||||
chat=Chat(id=-42, type="private"),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ class TestFilterObject:
|
|||
def test_post_init(self):
|
||||
case = F.test
|
||||
filter_obj = FilterObject(callback=case)
|
||||
print(filter_obj.callback)
|
||||
assert filter_obj.callback == case.resolve
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from datetime import datetime
|
||||
|
||||
import msgspec
|
||||
import pytest
|
||||
|
||||
from aiogram.filters.chat_member_updated import (
|
||||
|
|
@ -340,11 +341,17 @@ class TestChatMemberUpdatedStatusFilter:
|
|||
"can_send_other_messages": True,
|
||||
"can_add_web_page_previews": True,
|
||||
}
|
||||
old = msgspec.to_builtins(old)
|
||||
old["update"] = update
|
||||
old = msgspec.from_builtins(old, ChatMember)
|
||||
new = msgspec.to_builtins(new)
|
||||
new["update"] = update
|
||||
new = msgspec.from_builtins(new, ChatMember)
|
||||
event = ChatMemberUpdated(
|
||||
chat=Chat(id=42, type="test"),
|
||||
from_user=user,
|
||||
old_chat_member=old.copy(update=update),
|
||||
new_chat_member=new.copy(update=update),
|
||||
old_chat_member=old,
|
||||
new_chat_member=new,
|
||||
date=datetime.now(),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import pytest
|
|||
|
||||
from aiogram.utils.link import (
|
||||
BRANCH,
|
||||
create_channel_bot_link,
|
||||
create_telegram_link,
|
||||
create_tg_link,
|
||||
docs_url,
|
||||
create_channel_bot_link,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from dataclasses import dataclass
|
|||
from typing import Any, Dict
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import msgspec.json
|
||||
import pytest
|
||||
from aiohttp import MultipartReader, web
|
||||
from aiohttp.test_utils import TestClient
|
||||
|
|
@ -123,12 +124,9 @@ class TestSimpleRequestHandler:
|
|||
|
||||
resp = await self.make_reqest(client=client)
|
||||
assert resp.status == 200
|
||||
assert resp.content_type == "multipart/form-data"
|
||||
result = {}
|
||||
reader = MultipartReader.from_response(resp)
|
||||
while part := await reader.next():
|
||||
value = await part.read()
|
||||
result[part.name] = value.decode()
|
||||
assert resp.content_type == "application/json"
|
||||
result = msgspec.json.decode(await resp.read())
|
||||
print("RESULT:", result)
|
||||
assert result["method"] == "sendMessage"
|
||||
assert result["text"] == "PASS"
|
||||
|
||||
|
|
@ -150,12 +148,8 @@ class TestSimpleRequestHandler:
|
|||
|
||||
resp = await self.make_reqest(client=client, text="spam")
|
||||
assert resp.status == 200
|
||||
assert resp.content_type == "multipart/form-data"
|
||||
result = {}
|
||||
reader = MultipartReader.from_response(resp)
|
||||
while part := await reader.next():
|
||||
value = await part.read()
|
||||
result[part.name] = value.decode()
|
||||
assert resp.content_type == "application/json"
|
||||
result = msgspec.json.decode(await resp.read())
|
||||
assert not result
|
||||
|
||||
async def test_reply_into_webhook_background(self, bot: MockedBot, aiohttp_client):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue