From 91f0f5697d82f35bc7a75ae759301b0c5c94bd8f Mon Sep 17 00:00:00 2001 From: Timur Pavlov Date: Tue, 25 Oct 2022 08:56:28 +0300 Subject: [PATCH 1/5] fix: build params fix --- .github/workflows/build.yml | 23 +++++++++++++++++++++++ Pipfile | 2 -- pyproject.toml | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..591d83b --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,23 @@ +name: Build +on: + push: + branches: + - master + pull_request: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r dev_requirements.txt + - name: Build project + run: | + python3 -m build + diff --git a/Pipfile b/Pipfile index 2293e16..92ea52c 100644 --- a/Pipfile +++ b/Pipfile @@ -8,7 +8,5 @@ aiogram = ">=3.0.0" pytest = "*" pytest-asyncio = "*" -[dev-packages] - [requires] python_version = "3.9" diff --git a/pyproject.toml b/pyproject.toml index 71ad5fb..e26085c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["aiogram ~= 3.0.0b5", "setuptools"] [project] name = "aiogram_tests" -version = "1.0.0" +version = "1.0.1" authors = [ { name = "Timur", email = "pavlov.timur556@yandex.ru" } ] From 53194dab19216f5fb0b9d9c18d424cd366a6062b Mon Sep 17 00:00:00 2001 From: Timur Pavlov Date: Tue, 25 Oct 2022 08:58:10 +0300 Subject: [PATCH 2/5] fix: build params fix --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 591d83b..ef683ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,4 +20,7 @@ jobs: - name: Build project run: | python3 -m build + - name: Publish to Pypi + run: | + twine upload dist/* -u __token__ -p ${{ secrets.PYPI_API_TOKEN }} From 7435dbef99c69195a2b42a1af486d78b5baaf671 Mon Sep 17 00:00:00 2001 From: Timur Pavlov Date: Tue, 25 Oct 2022 18:55:21 +0300 Subject: [PATCH 3/5] delete (github action): deleted build.yml --- .github/workflows/build.yml | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index ef683ce..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Build -on: - push: - branches: - - master - pull_request: - branches: - - master -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r dev_requirements.txt - - name: Build project - run: | - python3 -m build - - name: Publish to Pypi - run: | - twine upload dist/* -u __token__ -p ${{ secrets.PYPI_API_TOKEN }} - From 5ac56757d279c499922c6dce09fdf1ef520dab87 Mon Sep 17 00:00:00 2001 From: Timur Pavlov Date: Tue, 25 Oct 2022 19:36:54 +0300 Subject: [PATCH 4/5] fix: TelegramEventObserverHandler feed update fix added async --- aiogram_tests/handler/__init__.py | 4 ++ aiogram_tests/handler/base.py | 70 ++++++++++++++++++++++++++ aiogram_tests/handler/handler.py | 83 +++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 aiogram_tests/handler/__init__.py create mode 100644 aiogram_tests/handler/base.py create mode 100644 aiogram_tests/handler/handler.py diff --git a/aiogram_tests/handler/__init__.py b/aiogram_tests/handler/__init__.py new file mode 100644 index 0000000..5ba7bf4 --- /dev/null +++ b/aiogram_tests/handler/__init__.py @@ -0,0 +1,4 @@ +from .handler import CallbackQueryHandler +from .handler import MessageHandler + +__all__ = ["MessageHandler", "CallbackQueryHandler"] diff --git a/aiogram_tests/handler/base.py b/aiogram_tests/handler/base.py new file mode 100644 index 0000000..ae9337b --- /dev/null +++ b/aiogram_tests/handler/base.py @@ -0,0 +1,70 @@ +from typing import Iterable +from typing import List + +from aiogram import Bot +from aiogram import Dispatcher +from aiogram.dispatcher.event.telegram import TelegramEventObserver +from aiogram.fsm.storage.memory import MemoryStorage +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 = None, + dp_filters: Iterable = None, + exclude_observer_methods: Iterable = None, + **kwargs, + ): + self.bot = MockedBot() + self.dp = Dispatcher(storage=MemoryStorage()) + + if dp_middlewares is None: + dp_middlewares = () + + if dp_filters is None: + dp_filters = () + + if exclude_observer_methods is None: + exclude_observer_methods = [] + + dispatcher_methods = self._get_dispatcher_event_observers() + available_methods = tuple(set(dispatcher_methods) - set(exclude_observer_methods)) + self._register_middlewares(available_methods, tuple(dp_middlewares)) + self._register_filters(available_methods, tuple(dp_filters)) + + 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. + """ + + result = [] + for name in dir(self.bot): + if isinstance(getattr(self.bot, name), TelegramEventObserver): + result.append(name) + + return result + + def _register_middlewares(self, event_observer: Iterable, middlewares: Iterable) -> None: + for eo_name in event_observer: + for m in middlewares: + eo_obj = getattr(self.bot, eo_name) + eo_obj.middleware.register(m) + + def _register_filters(self, event_observer: Iterable, filters: Iterable) -> None: + for eo_name in event_observer: + for f in filters: + eo_obj = getattr(self.bot, eo_name) + eo_obj.middleware.register(f) + + async def __call__(self, *args, **kwargs): + raise NotImplementedError diff --git a/aiogram_tests/handler/handler.py b/aiogram_tests/handler/handler.py new file mode 100644 index 0000000..b52c481 --- /dev/null +++ b/aiogram_tests/handler/handler.py @@ -0,0 +1,83 @@ +from typing import Callable +from typing import Dict +from typing import Iterable +from typing import List +from typing import Union + +from aiogram import types +from aiogram.filters import Filter +from aiogram.filters import StateFilter +from aiogram.fsm.state import State + +from .base import RequestHandler + + +class TelegramEventObserverHandler(RequestHandler): + 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, + **kwargs, + ): + super().__init__(dp_middlewares, (), exclude_observer_methods) + + self._callback = callback + self._filters: List = list(filters) + self._state: Union[State, str, None] = state + self._state_data: Dict = state_data + + if self._state_data is None: + self._state_data = {} + + if self._filters is None: + self._filters = [] + + if not isinstance(self._state_data, dict): + raise ValueError("state_data is not a dict") + + async def __call__(self, *args, **kwargs): + if self._state: + self._filters.append(StateFilter(self._state)) + + self.register_handler() + + if self._state: + 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) + + await self.feed_update(*args, **kwargs) + + def register_handler(self) -> None: + """ + Register TelegramEventObserver in dispatcher + """ + + raise NotImplementedError + + async def feed_update(self, *args, **kwargs) -> None: + """ + Feed dispatcher updates + """ + + raise NotImplementedError + + +class MessageHandler(TelegramEventObserverHandler): + 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)) + + +class CallbackQueryHandler(TelegramEventObserverHandler): + 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)) From d1087e4ef44f34bd6c4b3370c9368a034c8fe2b7 Mon Sep 17 00:00:00 2001 From: Timur Pavlov Date: Tue, 25 Oct 2022 19:37:30 +0300 Subject: [PATCH 5/5] refactor: code refactoring --- aiogram_tests/handler.py | 143 ------------------------------------- aiogram_tests/requester.py | 7 +- 2 files changed, 4 insertions(+), 146 deletions(-) delete mode 100644 aiogram_tests/handler.py diff --git a/aiogram_tests/handler.py b/aiogram_tests/handler.py deleted file mode 100644 index 225dbc4..0000000 --- a/aiogram_tests/handler.py +++ /dev/null @@ -1,143 +0,0 @@ -from typing import Callable -from typing import Dict -from typing import Generator -from typing import Iterable -from typing import List -from typing import Union - -from aiogram import Bot -from aiogram import Dispatcher -from aiogram import types -from aiogram.dispatcher.event.telegram import TelegramEventObserver -from aiogram.filters import Filter -from aiogram.filters import StateFilter -from aiogram.fsm.state import State -from aiogram.fsm.storage.memory import MemoryStorage - -from .mocked_bot import MockedBot -from .types.dataset import CHAT -from .types.dataset import USER - - -class RequestHandler: - def __init__( - self, - dp_middlewares: Iterable = None, - dp_filters: Iterable = None, - exclude_observer_methods: Iterable = None, - **kwargs, - ): - self.bot = MockedBot() - self.dp = Dispatcher(storage=MemoryStorage()) - - if dp_middlewares is None: - dp_middlewares = () - - if dp_filters is None: - dp_filters = () - - if exclude_observer_methods is None: - exclude_observer_methods = [] - - dispatcher_methods = self._get_dispatcher_event_observers() - available_methods = tuple(set(dispatcher_methods) - set(exclude_observer_methods)) - self._register_middlewares(available_methods, tuple(dp_middlewares)) - self._register_filters(available_methods, tuple(dp_filters)) - - Bot.set_current(self.bot) - types.User.set_current(USER.as_object()) - types.Chat.set_current(CHAT.as_object()) - - def _get_dispatcher_event_observers(self) -> Generator[str]: - """ - Returns a names for bot event observers, like message, callback_query etc. - """ - - result = (name for name in dir(self.bot) if isinstance(getattr(self.bot, name), TelegramEventObserver)) - return result - - def _register_middlewares(self, event_observer: Iterable, middlewares: Iterable) -> None: - for eo_name in event_observer: - for m in middlewares: - eo_obj = getattr(self.bot, eo_name) - eo_obj.middleware.register(m) - - def _register_filters(self, event_observer: Iterable, filters: Iterable) -> None: - for eo_name in event_observer: - for f in filters: - eo_obj = getattr(self.bot, eo_name) - eo_obj.middleware.register(f) - - async def __call__(self, *args, **kwargs): - raise NotImplementedError - - -class TelegramEventObserverHandler(RequestHandler): - 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, - **kwargs, - ): - super().__init__(dp_middlewares, (), exclude_observer_methods) - - self._callback = callback - self._filters: List = list(filters) - self._state: Union[State, str, None] = state - self._state_data: Dict = state_data - - if self._state_data is None: - self._state_data = {} - - if self._filters is None: - self._filters = [] - - if not isinstance(self._state_data, dict): - raise ValueError("state_data is not a dict") - - def __call__(self, *args, **kwargs): - if self._state: - self._filters.append(StateFilter(self._state)) - - self.register_handler() - - if self._state: - 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) - - self.feed_update(*args, **kwargs) - - def register_handler(self) -> None: - """ - Register TelegramEventObserver in dispatcher - """ - - raise NotImplementedError - - def feed_update(self, *args, **kwargs) -> None: - """ - Feed dispatcher updates - """ - - raise NotImplementedError - - -class MessageHandler(TelegramEventObserverHandler): - def register_handler(self) -> None: - self.dp.message.register(self._callback, *self._filters) - - def feed_update(self, message: types.Message, *args, **kwargs) -> None: - self.dp.feed_update(self.bot, types.Update(update_id=12345678, message=message)) - - -class CallbackQueryHandler(TelegramEventObserverHandler): - def register_handler(self) -> None: - self.dp.callback_query.register(self._callback, *self._filters) - - def feed_update(self, callback_query: types.CallbackQuery, *args, **kwargs) -> None: - self.dp.feed_update(self.bot, types.Update(update_id=12345678, callback_query=callback_query)) diff --git a/aiogram_tests/requester.py b/aiogram_tests/requester.py index eeaa8e5..9991b95 100644 --- a/aiogram_tests/requester.py +++ b/aiogram_tests/requester.py @@ -2,7 +2,7 @@ from aiogram.utils.helper import Item from .exceptions import MethodIsNotCalledError -from .handler import RequestHandler +from .handler.base import RequestHandler from .utils import camel_case2snake_case @@ -146,13 +146,14 @@ def __getattr__(self, item): return getattr(self, item) else: raise MethodIsNotCalledError( - "method '{}' is not called.\nTry to use: {}".format(item, ", ".join(self._get_attributes())) + "method '%s' is not called by bot, so you cant to get this attribute. Called methods: %s" + % (item, self._get_attributes()) ) class Requester: def __init__(self, *, request_handler: RequestHandler): - self._handler = request_handler + self._handler: RequestHandler = request_handler async def query(self, *args, **kwargs) -> Calls: await self._handler(*args, **kwargs)