From 83dc2f58d8a6e9ba4310947699543ca87dd0fa1c Mon Sep 17 00:00:00 2001 From: tikey Date: Fri, 4 Aug 2023 21:57:37 +0300 Subject: [PATCH 1/3] Bump Aiogram 3.0.0b9 version --- aiogram_tests/handler/__init__.py | 7 ++- aiogram_tests/handler/base.py | 42 ++++++--------- aiogram_tests/handler/handler.py | 48 +++++++++-------- aiogram_tests/mocked_bot.py | 72 ++++++++++++++----------- aiogram_tests/requester.py | 17 +++--- aiogram_tests/types/dataset/__init__.py | 53 +++++++++++++++--- aiogram_tests/types/dataset/base.py | 6 ++- dev_requirements.txt | 2 +- examples/example_tests.py | 44 +++++++++------ examples/test_bot.py | 8 ++- requirements.txt | 2 +- tests/bot.py | 8 ++- tests/middleware.py | 5 +- tests/test_bot.py | 43 +++++++++++---- tests/test_dataset_item.py | 32 +++++++++-- tests/test_handler.py | 7 ++- 16 files changed, 261 insertions(+), 135 deletions(-) diff --git a/aiogram_tests/handler/__init__.py b/aiogram_tests/handler/__init__.py index 5c0734f..8604e3b 100644 --- a/aiogram_tests/handler/__init__.py +++ b/aiogram_tests/handler/__init__.py @@ -3,4 +3,9 @@ from .handler import MessageHandler from .handler import TelegramEventObserverHandler -__all__ = ["MessageHandler", "CallbackQueryHandler", "TelegramEventObserverHandler", "RequestHandler"] +__all__ = [ + "MessageHandler", + "CallbackQueryHandler", + "TelegramEventObserverHandler", + "RequestHandler", +] diff --git a/aiogram_tests/handler/base.py b/aiogram_tests/handler/base.py index a8d4c02..9baaf48 100644 --- a/aiogram_tests/handler/base.py +++ b/aiogram_tests/handler/base.py @@ -1,34 +1,26 @@ -from typing import Iterable +from typing import Iterable, Any from typing import List -from typing import Optional -from typing import Type from aiogram import BaseMiddleware -from aiogram import Bot from aiogram import Dispatcher from aiogram.dispatcher.event.telegram import TelegramEventObserver from aiogram.fsm.storage.memory import MemoryStorage from aiogram.methods import TelegramMethod from aiogram.methods.base import Response from aiogram.methods.base import TelegramType -from aiogram.types import Chat -from aiogram.types import User from aiogram_tests.mocked_bot import MockedBot -from aiogram_tests.types.dataset import CHAT -from aiogram_tests.types.dataset import USER class RequestHandler: def __init__( self, - dp_middlewares: Iterable[BaseMiddleware] = None, - exclude_observer_methods: Iterable[str] = None, - auto_mock_success: bool = False, - dp: Optional[Dispatcher] = None, - **kwargs, + dp_middlewares: Iterable[BaseMiddleware] | None = None, + exclude_observer_methods: Iterable[str] | None = None, + dp: Dispatcher | None = None, + **kwargs: Any, ): - self.bot = MockedBot(auto_mock_success=auto_mock_success) + self.bot = MockedBot() if dp is None: dp = Dispatcher(storage=MemoryStorage()) self.dp = dp @@ -40,13 +32,11 @@ def __init__( exclude_observer_methods = [] dispatcher_methods = self._get_dispatcher_event_observers() - available_methods = tuple(set(dispatcher_methods) - set(exclude_observer_methods)) + available_methods = tuple( + set(dispatcher_methods) - set(exclude_observer_methods) + ) self._register_middlewares(available_methods, tuple(dp_middlewares)) - Bot.set_current(self.bot) - User.set_current(USER.as_object()) - Chat.set_current(CHAT.as_object()) - def _get_dispatcher_event_observers(self) -> List[str]: """ Returns a names for bot event observers, like message, callback_query etc. @@ -59,7 +49,9 @@ def _get_dispatcher_event_observers(self) -> List[str]: return result - def _register_middlewares(self, event_observer: Iterable, middlewares: Iterable) -> None: + def _register_middlewares( + self, event_observer: Iterable, middlewares: Iterable + ) -> None: for eo_name in event_observer: for m in middlewares: eo_obj = getattr(self.dp, eo_name) @@ -70,13 +62,13 @@ async def __call__(self, *args, **kwargs): def add_result_for( self, - method: Type[TelegramMethod[TelegramType]], + method: TelegramMethod[TelegramType], ok: bool, - result: TelegramType = None, - description: Optional[str] = None, + result: TelegramType | None = None, + description: str | None = None, error_code: int = 200, - migrate_to_chat_id: Optional[int] = None, - retry_after: Optional[int] = None, + migrate_to_chat_id: int | None = None, + retry_after: int | None = None, ) -> Response[TelegramType]: response = self.bot.add_result_for( method=method, diff --git a/aiogram_tests/handler/handler.py b/aiogram_tests/handler/handler.py index b6de716..6fac527 100644 --- a/aiogram_tests/handler/handler.py +++ b/aiogram_tests/handler/handler.py @@ -1,8 +1,6 @@ -from typing import Callable -from typing import Dict +from typing import Callable, Any from typing import Iterable from typing import List -from typing import Union from aiogram import types from aiogram.filters import Filter @@ -17,18 +15,18 @@ def __init__( self, callback: Callable, *filters: Filter, - state: Union[State, str, None] = None, - state_data: Dict = None, - dp_middlewares: Iterable = None, - exclude_observer_methods: Iterable = None, + state: State | str | None = None, + state_data: dict[str, Any] | None = None, + dp_middlewares: Iterable | None = None, + exclude_observer_methods: Iterable | None = None, **kwargs, ): super().__init__(dp_middlewares, exclude_observer_methods, **kwargs) self._callback = callback self._filters: List = list(filters) - self._state: Union[State, str, None] = state - self._state_data: Dict = state_data + self._state: State | str | None = state + self._state_data: dict[str, Any] | None = state_data if self._state_data is None: self._state_data = {} @@ -46,7 +44,9 @@ async def __call__(self, *args, **kwargs): self.register_handler() if self._state: - state = self.dp.fsm.get_context(self.bot, user_id=12345678, chat_id=12345678) + state = self.dp.fsm.get_context( + self.bot, user_id=12345678, chat_id=12345678 + ) await state.set_state(self._state) await state.update_data(**self._state_data) @@ -72,10 +72,10 @@ def __init__( self, callback: Callable, *filters: Filter, - state: Union[State, str, None] = None, - state_data: Dict = None, - dp_middlewares: Iterable = None, - exclude_observer_methods: Iterable = None, + state: State | str | None = None, + state_data: dict[str, Any] | None = None, + dp_middlewares: Iterable | None = None, + exclude_observer_methods: Iterable | None = None, **kwargs, ): super().__init__( @@ -92,7 +92,9 @@ def register_handler(self) -> None: self.dp.message.register(self._callback, *self._filters) async def feed_update(self, message: types.Message, *args, **kwargs) -> None: - await self.dp.feed_update(self.bot, types.Update(update_id=12345678, message=message)) + await self.dp.feed_update( + self.bot, types.Update(update_id=12345678, message=message) + ) class CallbackQueryHandler(TelegramEventObserverHandler): @@ -100,10 +102,10 @@ def __init__( self, callback: Callable, *filters: Filter, - state: Union[State, str, None] = None, - state_data: Dict = None, - dp_middlewares: Iterable = None, - exclude_observer_methods: Iterable = None, + state: State | str | None = None, + state_data: dict[str, Any] | None = None, + dp_middlewares: Iterable | None = None, + exclude_observer_methods: Iterable | None = None, **kwargs, ): super().__init__( @@ -119,5 +121,9 @@ def __init__( def register_handler(self) -> None: self.dp.callback_query.register(self._callback, *self._filters) - async def feed_update(self, callback_query: types.CallbackQuery, *args, **kwargs) -> None: - await self.dp.feed_update(self.bot, types.Update(update_id=12345678, callback_query=callback_query)) + async def feed_update( + self, callback_query: types.CallbackQuery, *args, **kwargs + ) -> None: + await self.dp.feed_update( + self.bot, types.Update(update_id=12345678, callback_query=callback_query) + ) diff --git a/aiogram_tests/mocked_bot.py b/aiogram_tests/mocked_bot.py index e76924b..c241f78 100644 --- a/aiogram_tests/mocked_bot.py +++ b/aiogram_tests/mocked_bot.py @@ -1,60 +1,70 @@ from collections import deque -from typing import AsyncGenerator +from typing import AsyncGenerator, Dict, Any, TYPE_CHECKING, cast from typing import Deque from typing import Optional -from typing import Type -from typing import Union from aiogram import Bot from aiogram.client.session.base import BaseSession from aiogram.methods import TelegramMethod -from aiogram.methods.base import Request from aiogram.methods.base import Response from aiogram.methods.base import TelegramType -from aiogram.types import ResponseParameters -from aiogram.types import UNSET +from aiogram.types import ResponseParameters, UNSET_PARSE_MODE from aiogram.types import User class MockedSession(BaseSession): def __init__(self): - super().__init__() + super(MockedSession, self).__init__() self.responses: Deque[Response[TelegramType]] = deque() - self.requests: Deque[Request] = deque() + self.requests: Deque[TelegramMethod[TelegramType]] = deque() self.closed = True def add_result(self, response: Response[TelegramType]) -> Response[TelegramType]: self.responses.appendleft(response) return response - def get_request(self) -> Union[Request, None]: - if self.requests: - return self.requests[-1] - - return None + def get_request(self) -> TelegramMethod[TelegramType]: + return self.requests.pop() async def close(self): self.closed = True async def make_request( - self, bot: Bot, method: TelegramMethod[TelegramType], timeout: Optional[int] = UNSET + self, + bot: Bot, + method: TelegramMethod[TelegramType], + timeout: Optional[int] = UNSET_PARSE_MODE, ) -> TelegramType: self.closed = False - self.requests.append(method.build_request(bot)) + self.requests.append(method) response: Response[TelegramType] = self.responses.pop() - self.check_response(method=method, status_code=response.error_code, content=response.json()) + self.check_response( + bot=bot, + method=method, + status_code=cast(int, response.error_code), + content=response.model_dump_json(), + ) return response.result # type: ignore async def stream_content( - self, url: str, timeout: int, chunk_size: int + self, + url: str, + headers: Optional[Dict[str, Any]] = None, + timeout: int = 30, + chunk_size: int = 65536, + raise_for_status: bool = True, ) -> AsyncGenerator[bytes, None]: # pragma: no cover yield b"" class MockedBot(Bot): - def __init__(self, auto_mock_success=False, **kwargs): - super().__init__(kwargs.pop("token", "42:TEST"), session=MockedSession(), **kwargs) - self.session = MockedSession() + if TYPE_CHECKING: + session: MockedSession + + def __init__(self, **kwargs): + super(MockedBot, self).__init__( + kwargs.pop("token", "42:TEST"), session=MockedSession(), **kwargs + ) self._me = User( id=self.id, is_bot=True, @@ -63,17 +73,16 @@ def __init__(self, auto_mock_success=False, **kwargs): username="username", language_code="ru", ) - self.auto_mock_success = auto_mock_success def add_result_for( self, - method: Type[TelegramMethod[TelegramType]], + method: TelegramMethod[TelegramType], ok: bool, - result: TelegramType = None, - description: Optional[str] = None, + result: TelegramType | None = None, + description: str | None = None, error_code: int = 200, - migrate_to_chat_id: Optional[int] = None, - retry_after: Optional[int] = None, + migrate_to_chat_id: int | None = None, + retry_after: int | None = None, ) -> Response[TelegramType]: response = Response[method.__returning__]( # type: ignore ok=ok, @@ -88,10 +97,13 @@ def add_result_for( self.session.add_result(response) return response - async def __call__(self, method: Type[TelegramMethod[TelegramType]], request_timeout: Optional[int] = None): - if self.auto_mock_success: - self.add_result_for(method, ok=True) + async def __call__( + self, + method: TelegramMethod[TelegramType], + request_timeout: Optional[int] = None, + ): + self.add_result_for(method, ok=True) return await super().__call__(method, request_timeout) - def get_request(self) -> Request: + def get_request(self) -> TelegramMethod[TelegramType]: return self.session.get_request() diff --git a/aiogram_tests/requester.py b/aiogram_tests/requester.py index 41f22e4..628b1ee 100644 --- a/aiogram_tests/requester.py +++ b/aiogram_tests/requester.py @@ -1,6 +1,3 @@ -from typing import Optional -from typing import Type - from aiogram.methods import TelegramMethod from aiogram.methods.base import Response from aiogram.methods.base import TelegramType @@ -56,24 +53,24 @@ async def query(self, *args, **kwargs) -> Calls: requests = self._handler.bot.session.requests result = {} for r in requests: - method_name = camel_case2snake_case(r.method) + method_name = camel_case2snake_case(r.__api_method__) if method_name not in result: result[method_name] = CallsList() - result[method_name].append(self._dict_to_obj(r.data)) + result[method_name].append(self._dict_to_obj(r.dict())) return self._generate_result_obj(result) def add_result_for( self, - method: Type[TelegramMethod[TelegramType]], + method: TelegramMethod[TelegramType], ok: bool, - result: TelegramType = None, - description: Optional[str] = None, + result: TelegramType | None = None, + description: str | None = None, error_code: int = 200, - migrate_to_chat_id: Optional[int] = None, - retry_after: Optional[int] = None, + migrate_to_chat_id: int | None = None, + retry_after: int | None = None, ) -> Response[TelegramType]: response = self._handler.add_result_for( method=method, diff --git a/aiogram_tests/types/dataset/__init__.py b/aiogram_tests/types/dataset/__init__.py index 3fed553..3e4b2a3 100644 --- a/aiogram_tests/types/dataset/__init__.py +++ b/aiogram_tests/types/dataset/__init__.py @@ -118,7 +118,13 @@ ) ANIMATION = DatasetItem( - {"file_id": "file_id", "file_unique_id": "file_unique_id", "width": 50, "height": 50, "duration": 50}, + { + "file_id": "file_id", + "file_unique_id": "file_unique_id", + "width": 50, + "height": 50, + "duration": 50, + }, model=types.Animation, ) @@ -291,7 +297,14 @@ ) CALLBACK_QUERY = DatasetItem( - {"id": 12345678, "chat_instance": "AABBCC", "from": USER, "chat": CHAT, "data": "data"}, model=types.CallbackQuery + { + "id": "12345678", + "chat_instance": "AABBCC", + "from": USER, + "chat": CHAT, + "data": "data", + }, + model=types.CallbackQuery, ) CHANNEL = DatasetItem( @@ -304,7 +317,13 @@ ) CHANNEL_POST = DatasetItem( - {"message_id": 12345, "sender_chat": CHANNEL, "chat": CHANNEL, "date": 1508825372, "text": "Hi, channel!"}, + { + "message_id": 12345, + "sender_chat": CHANNEL, + "chat": CHANNEL, + "date": 1508825372, + "text": "Hi, channel!", + }, model=types.Message, ) @@ -342,13 +361,27 @@ "forward_from_message_id": 123, "forward_date": 1522749037, "text": "Forwarded text with entities from public channel ", - "entities": [ENTITY_BOLD, ENTITY_CODE, ENTITY_ITALIC, ENTITY_LINK, ENTITY_LINK, ENTITY_MENTION, ENTITY_PRE], + "entities": [ + ENTITY_BOLD, + ENTITY_CODE, + ENTITY_ITALIC, + ENTITY_LINK, + ENTITY_LINK, + ENTITY_MENTION, + ENTITY_PRE, + ], }, model=types.Message, ) MESSAGE = DatasetItem( - {"message_id": 11223, "from": USER, "chat": CHAT, "date": 1508709711, "text": "Hi, world!"}, + { + "message_id": 11223, + "from": USER, + "chat": CHAT, + "date": 1508709711, + "text": "Hi, world!", + }, model=types.Message, ) @@ -376,7 +409,8 @@ ) MESSAGE_WITH_DICE = DatasetItem( - {"message_id": 12345, "from": USER, "chat": CHAT, "date": 1508768012, "dice": DICE}, model=types.Message + {"message_id": 12345, "from": USER, "chat": CHAT, "date": 1508768012, "dice": DICE}, + model=types.Message, ) MESSAGE_WITH_DOCUMENT = DatasetItem( @@ -593,7 +627,12 @@ ) FILE = DatasetItem( - {"file_id": "XXXYYYZZZ", "file_size": 5254, "file_path": "voice/file_8", "file_unique_id": "file_unique_id"}, + { + "file_id": "XXXYYYZZZ", + "file_size": 5254, + "file_path": "voice/file_8", + "file_unique_id": "file_unique_id", + }, model=types.File, ) diff --git a/aiogram_tests/types/dataset/base.py b/aiogram_tests/types/dataset/base.py index 05b5100..ed2bb1f 100644 --- a/aiogram_tests/types/dataset/base.py +++ b/aiogram_tests/types/dataset/base.py @@ -37,7 +37,7 @@ def as_object(self, **replace_args) -> Union[Any, None]: except (AttributeError, TypeError): return None - def _recursive_as_object(self, data: dict, model: Any): + def _recursive_as_object(self, data: dict[str, "DatasetItem"], model: Any): """ This method is converting dict data to object, if one of the params is the DatasetItem method will be recursive convert it; @@ -55,7 +55,9 @@ def _recursive_as_object(self, data: dict, model: Any): if not isinstance(item, (DatasetItem, list)): continue - result_data[key][index] = self._recursive_as_object(item.data, item.model) + result_data[key][index] = self._recursive_as_object( + item.data, item.model + ) return model(**result_data) diff --git a/dev_requirements.txt b/dev_requirements.txt index 56b3501..dbe76f1 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,4 +1,4 @@ -aiogram==3.0.0b7 +aiogram==3.0.0b9 pytest pytest-asyncio black diff --git a/examples/example_tests.py b/examples/example_tests.py index 3928ec0..1c57d81 100644 --- a/examples/example_tests.py +++ b/examples/example_tests.py @@ -1,19 +1,19 @@ import pytest from aiogram.filters import Command -from test_bot import callback_query_handler -from test_bot import callback_query_handler_with_state -from test_bot import command_handler -from test_bot import message_handler -from test_bot import message_handler_with_state -from test_bot import message_handler_with_state_data -from test_bot import States -from test_bot import TestCallbackData from aiogram_tests import MockedBot from aiogram_tests.handler import CallbackQueryHandler from aiogram_tests.handler import MessageHandler from aiogram_tests.types.dataset import CALLBACK_QUERY from aiogram_tests.types.dataset import MESSAGE +from test_bot import States +from test_bot import TestCallbackData +from test_bot import callback_query_handler +from test_bot import callback_query_handler_with_state +from test_bot import command_handler +from test_bot import message_handler +from test_bot import message_handler_with_state +from test_bot import message_handler_with_state_data @pytest.mark.asyncio @@ -34,7 +34,9 @@ async def test_command_handler(): @pytest.mark.asyncio async def test_message_handler_with_state(): - requester = MockedBot(MessageHandler(message_handler_with_state, state=States.state)) + requester = MockedBot( + MessageHandler(message_handler_with_state, state=States.state) + ) calls = await requester.query(MESSAGE.as_object(text="Hello, bot!")) answer_message = calls.send_message.fetchone().text assert answer_message == "Hello, from state!" @@ -42,10 +44,13 @@ async def test_message_handler_with_state(): @pytest.mark.asyncio async def test_callback_query_handler(): - requester = MockedBot(CallbackQueryHandler(callback_query_handler, TestCallbackData.filter())) + requester = MockedBot( + CallbackQueryHandler(callback_query_handler, TestCallbackData.filter()) + ) callback_query = CALLBACK_QUERY.as_object( - data=TestCallbackData(id=1, name="John").pack(), message=MESSAGE.as_object(text="Hello world!") + data=TestCallbackData(id=1, name="John").pack(), + message=MESSAGE.as_object(text="Hello world!"), ) calls = await requester.query(callback_query) @@ -53,7 +58,8 @@ async def test_callback_query_handler(): assert answer_text == "Hello, John" callback_query = CALLBACK_QUERY.as_object( - data=TestCallbackData(id=1, name="Mike").pack(), message=MESSAGE.as_object(text="Hello world!") + data=TestCallbackData(id=1, name="Mike").pack(), + message=MESSAGE.as_object(text="Hello world!"), ) calls = await requester.query(callback_query) @@ -63,9 +69,15 @@ async def test_callback_query_handler(): @pytest.mark.asyncio async def test_callback_query_handler_with_state(): - requester = MockedBot(CallbackQueryHandler(callback_query_handler_with_state, TestCallbackData.filter())) + requester = MockedBot( + CallbackQueryHandler( + callback_query_handler_with_state, TestCallbackData.filter() + ) + ) - callback_query = CALLBACK_QUERY.as_object(data=TestCallbackData(id=1, name="John").pack()) + callback_query = CALLBACK_QUERY.as_object( + data=TestCallbackData(id=1, name="John").pack() + ) calls = await requester.query(callback_query) answer_text = calls.answer_callback_query.fetchone().text @@ -76,7 +88,9 @@ async def test_callback_query_handler_with_state(): async def test_handler_with_state_data(): requester = MockedBot( MessageHandler( - message_handler_with_state_data, state=States.state_1, state_data={"info": "this is message handler"} + message_handler_with_state_data, + state=States.state_1, + state_data={"info": "this is message handler"}, ) ) diff --git a/examples/test_bot.py b/examples/test_bot.py index 27e6cf3..c83cd04 100644 --- a/examples/test_bot.py +++ b/examples/test_bot.py @@ -37,14 +37,18 @@ async def message_handler_with_state(message: types.Message, state: FSMContext) @dp.message(States.state_1) -async def message_handler_with_state_data(message: types.Message, state: FSMContext) -> None: +async def message_handler_with_state_data( + message: types.Message, state: FSMContext +) -> None: data = await state.get_data() await message.answer(f'Info from state data: {data["info"]}') @dp.callback_query(TestCallbackData.filter()) async def callback_query_handler( - callback_query: types.CallbackQuery, callback_data: TestCallbackData, state: FSMContext + callback_query: types.CallbackQuery, + callback_data: TestCallbackData, + state: FSMContext, ) -> None: name = callback_data.name await callback_query.message.answer(f"Hello, {name}") diff --git a/requirements.txt b/requirements.txt index 3460c0b..15e18b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -aiogram==3.0.0b7 +aiogram==3.0.0b9 pytest pytest-asyncio diff --git a/tests/bot.py b/tests/bot.py index 3a6127b..31513a5 100644 --- a/tests/bot.py +++ b/tests/bot.py @@ -34,14 +34,18 @@ async def message_handler_with_state(message: types.Message, state: FSMContext) @dp.message(States.state_1) -async def message_handler_with_state_data(message: types.Message, state: FSMContext) -> None: +async def message_handler_with_state_data( + message: types.Message, state: FSMContext +) -> None: data = await state.get_data() await message.answer(f'Info from state data: {data["info"]}') @dp.callback_query(TestCallbackData.filter()) async def callback_query_handler( - callback_query: types.CallbackQuery, callback_data: TestCallbackData, state: FSMContext + callback_query: types.CallbackQuery, + callback_data: TestCallbackData, + state: FSMContext, ) -> None: name = callback_data.name await callback_query.message.answer(f"Hello, {name}") diff --git a/tests/middleware.py b/tests/middleware.py index 20b7f14..960cbaf 100644 --- a/tests/middleware.py +++ b/tests/middleware.py @@ -9,6 +9,9 @@ class TestMiddleware(BaseMiddleware): async def __call__( - self, handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], event: Message, data: Dict[str, Any] + self, + handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], + event: Message, + data: Dict[str, Any], ): return await handler(event, data) diff --git a/tests/test_bot.py b/tests/test_bot.py index be1f2f1..661ded0 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -22,7 +22,9 @@ @pytest.mark.asyncio async def test_message_handler(): - requester = MockedBot(request_handler=MessageHandler(message_handler, auto_mock_success=True)) + requester = MockedBot( + request_handler=MessageHandler(message_handler, auto_mock_success=True) + ) calls = await requester.query(MESSAGE.as_object(text="Hello!")) answer_message = calls.send_message.fetchone().text assert answer_message == "Hello!" @@ -30,7 +32,9 @@ async def test_message_handler(): @pytest.mark.asyncio async def test_command_handler(): - requester = MockedBot(request_handler=MessageHandler(command_handler, Command(commands=["start"]))) + requester = MockedBot( + request_handler=MessageHandler(command_handler, Command(commands=["start"])) + ) requester.add_result_for(SendMessage, ok=True) calls = await requester.query(MESSAGE.as_object(text="/start")) answer_message = calls.send_message.fetchone().text @@ -39,7 +43,9 @@ async def test_command_handler(): @pytest.mark.asyncio async def test_message_handler_with_state(): - requester = MockedBot(request_handler=MessageHandler(message_handler_with_state, state=States.state)) + requester = MockedBot( + request_handler=MessageHandler(message_handler_with_state, state=States.state) + ) requester.add_result_for(SendMessage, ok=True) calls = await requester.query(MESSAGE.as_object(text="Hello, bot!")) answer_message = calls.send_message.fetchone().text @@ -48,12 +54,17 @@ async def test_message_handler_with_state(): @pytest.mark.asyncio async def test_callback_query_handler(): - requester = MockedBot(request_handler=CallbackQueryHandler(callback_query_handler, TestCallbackData.filter())) + requester = MockedBot( + request_handler=CallbackQueryHandler( + callback_query_handler, TestCallbackData.filter() + ) + ) requester.add_result_for(AnswerCallbackQuery, ok=True) requester.add_result_for(SendMessage, ok=True) callback_query = CALLBACK_QUERY.as_object( - data=TestCallbackData(id=1, name="John").pack(), message=MESSAGE.as_object(text="Hello world!") + data=TestCallbackData(id=1, name="John").pack(), + message=MESSAGE.as_object(text="Hello world!"), ) calls = await requester.query(callback_query) @@ -63,7 +74,8 @@ async def test_callback_query_handler(): requester.add_result_for(AnswerCallbackQuery, ok=True) requester.add_result_for(SendMessage, ok=True) callback_query = CALLBACK_QUERY.as_object( - data=TestCallbackData(id=1, name="Mike").pack(), message=MESSAGE.as_object(text="Hello world!") + data=TestCallbackData(id=1, name="Mike").pack(), + message=MESSAGE.as_object(text="Hello world!"), ) calls = await requester.query(callback_query) @@ -74,13 +86,17 @@ async def test_callback_query_handler(): @pytest.mark.asyncio async def test_callback_query_handler_with_state(): requester = MockedBot( - request_handler=CallbackQueryHandler(callback_query_handler_with_state, TestCallbackData.filter()) + request_handler=CallbackQueryHandler( + callback_query_handler_with_state, TestCallbackData.filter() + ) ) requester.add_result_for(AnswerCallbackQuery, ok=True) requester.add_result_for(SendMessage, ok=True) - callback_query = CALLBACK_QUERY.as_object(data=TestCallbackData(id=1, name="John").pack()) + callback_query = CALLBACK_QUERY.as_object( + data=TestCallbackData(id=1, name="John").pack() + ) calls = await requester.query(callback_query) answer_text = calls.answer_callback_query.fetchone().text @@ -91,7 +107,9 @@ async def test_callback_query_handler_with_state(): async def test_handler_with_state_data(): requester = MockedBot( request_handler=MessageHandler( - message_handler_with_state_data, state=States.state_1, state_data={"info": "this is message handler"} + message_handler_with_state_data, + state=States.state_1, + state_data={"info": "this is message handler"}, ) ) @@ -105,7 +123,12 @@ async def test_handler_with_state_data(): async def test_handler_with_fail(): requester = MockedBot(request_handler=MessageHandler(foo_command_handler, dp=dp)) - requester.add_result_for(SendMessage, ok=False, description="Have no rights to send a message", error_code=401) + requester.add_result_for( + SendMessage, + ok=False, + description="Have no rights to send a message", + error_code=401, + ) requester.add_result_for(SendMessage, ok=True) calls = await requester.query(MESSAGE.as_object(text="/foo fail")) answer_message = calls.send_message.pop() diff --git a/tests/test_dataset_item.py b/tests/test_dataset_item.py index fb8bae8..a2a4c1f 100644 --- a/tests/test_dataset_item.py +++ b/tests/test_dataset_item.py @@ -8,7 +8,11 @@ def test_as_object(): dataset_item = DatasetItem({"firstArg": 1, "secondArg": 2}) assert dataset_item.as_object() == {"firstArg": 1, "secondArg": 2} assert dataset_item.as_object(firstArg=3) == {"firstArg": 3, "secondArg": 2} - assert dataset_item.as_object(thirdArg=3) == {"firstArg": 1, "secondArg": 2, "thirdArg": 3} + assert dataset_item.as_object(thirdArg=3) == { + "firstArg": 1, + "secondArg": 2, + "thirdArg": 3, + } def test_as_object_converting(): @@ -23,10 +27,18 @@ def test_as_object_converting(): model=types.User, ) assert dataset_item.as_object() == types.User( - id=12345678, is_bot=False, first_name="FirstName", last_name="LastName", username="username" + id=12345678, + is_bot=False, + first_name="FirstName", + last_name="LastName", + username="username", ) assert dataset_item.as_object(first_name="EditedFirstName") == types.User( - id=12345678, is_bot=False, first_name="EditedFirstName", last_name="LastName", username="username" + id=12345678, + is_bot=False, + first_name="EditedFirstName", + last_name="LastName", + username="username", ) assert dataset_item.as_object(language_code="ru") == types.User( id=12345678, @@ -64,9 +76,19 @@ def test_as_object_converting_with_nesting(): assert dataset_item.as_object() == types.Message( message_id=11223, from_user=types.User( - id=12345678, is_bot=False, first_name="FirstName", last_name="LastName", username="username" + id=12345678, + is_bot=False, + first_name="FirstName", + last_name="LastName", + username="username", + ), + chat=types.Chat( + id=12345678, + first_name="FirstName", + last_name="LastName", + username="username", + type="private", ), - chat=types.Chat(id=12345678, first_name="FirstName", last_name="LastName", username="username", type="private"), date=1508709711, text="Hi, world!", ) diff --git a/tests/test_handler.py b/tests/test_handler.py index cd9fb53..110d9c7 100644 --- a/tests/test_handler.py +++ b/tests/test_handler.py @@ -1,10 +1,10 @@ import pytest from aiogram.filters import StateFilter -from .middleware import TestMiddleware from aiogram_tests.handler import MessageHandler from aiogram_tests.handler import RequestHandler from aiogram_tests.handler import TelegramEventObserverHandler +from .middleware import TestMiddleware def test_request_handler_initialization(): @@ -20,7 +20,10 @@ def test_request_handler_dp_middlewares(): middlewares_count = len(r_h.dp.message.middleware) assert middlewares_count == 2 - r_h = RequestHandler(dp_middlewares=(TestMiddleware(), TestMiddleware()), exclude_observer_methods=["message"]) + r_h = RequestHandler( + dp_middlewares=(TestMiddleware(), TestMiddleware()), + exclude_observer_methods=["message"], + ) middlewares_count = len(r_h.dp.message.middleware) assert middlewares_count == 0 From 70efb6d9513a76a94b40737aab1551822d81ea34 Mon Sep 17 00:00:00 2001 From: tikey Date: Sat, 19 Aug 2023 20:43:55 +0300 Subject: [PATCH 2/3] Add my chat member handler --- aiogram_tests/handler/handler.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/aiogram_tests/handler/handler.py b/aiogram_tests/handler/handler.py index 6fac527..360150f 100644 --- a/aiogram_tests/handler/handler.py +++ b/aiogram_tests/handler/handler.py @@ -127,3 +127,35 @@ async def feed_update( await self.dp.feed_update( self.bot, types.Update(update_id=12345678, callback_query=callback_query) ) + + +class MyChatMemberHandler(TelegramEventObserverHandler): + def __init__( + self, + callback: Callable, + *filters: Filter, + state: State | str | None = None, + state_data: dict[str, Any] | None = None, + dp_middlewares: Iterable | None = None, + exclude_observer_methods: Iterable | None = None, + **kwargs, + ): + super().__init__( + callback, + *filters, + state=state, + state_data=state_data, + dp_middlewares=dp_middlewares, + exclude_observer_methods=exclude_observer_methods, + **kwargs, + ) + + def register_handler(self) -> None: + self.dp.my_chat_member.register(self._callback, *self._filters) + + async def feed_update( + self, my_chat_member: types.ChatMemberUpdated, *args, **kwargs + ) -> None: + await self.dp.feed_update( + self.bot, types.Update(update_id=12345678, my_chat_member=my_chat_member) + ) From 3574eb83b3fa3c98496a5141b9fa491054c09b04 Mon Sep 17 00:00:00 2001 From: TiKey Date: Mon, 1 Jan 2024 10:22:27 +0300 Subject: [PATCH 3/3] remove depends --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 93098f4..4f12de7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,3 @@ -[build-system] -requires = ["aiogram ~= 3.0.0b7", "setuptools"] - [project] name = "aiogram_tests" version = "1.0.2"