aiogram-testing 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiogram_testing-1.1.0.dist-info/METADATA +86 -0
- aiogram_testing-1.1.0.dist-info/RECORD +14 -0
- aiogram_testing-1.1.0.dist-info/WHEEL +4 -0
- aiogram_tests/__init__.py +4 -0
- aiogram_tests/exceptions.py +2 -0
- aiogram_tests/handler/__init__.py +6 -0
- aiogram_tests/handler/base.py +79 -0
- aiogram_tests/handler/handler.py +86 -0
- aiogram_tests/mocked_bot.py +104 -0
- aiogram_tests/requester.py +94 -0
- aiogram_tests/types/__init__.py +3 -0
- aiogram_tests/types/dataset/__init__.py +673 -0
- aiogram_tests/types/dataset/base.py +68 -0
- aiogram_tests/utils.py +5 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aiogram-testing
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: A library for testing your bots on aiogram
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: k0te1ch
|
|
7
|
+
Author-email: khvostov40@gmail.com
|
|
8
|
+
Requires-Python: >=3.12,<3.15
|
|
9
|
+
Classifier: Framework :: AsyncIO
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Software Development :: Testing
|
|
17
|
+
Requires-Dist: aiogram (>=3.28,<4.0)
|
|
18
|
+
Project-URL: Homepage, https://github.com/k0te1ch/aiogram_tests
|
|
19
|
+
Project-URL: Repository, https://github.com/k0te1ch/aiogram_tests
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# Aiogram Tests
|
|
23
|
+
|
|
24
|
+
***aiogram_tests*** is a testing library for bots written on [aiogram]("https://github.com/aiogram/aiogram")</a>
|
|
25
|
+
|
|
26
|
+
## 📦 Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install aiogram-testing
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The import name stays `aiogram_tests`:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from aiogram_tests import MockedRequester
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 📚 Simple examples
|
|
39
|
+
|
|
40
|
+
### Simple handler test
|
|
41
|
+
|
|
42
|
+
#### Simple bot
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from aiogram import Bot, Dispatcher, types
|
|
46
|
+
from aiogram.fsm.context import FSMContext
|
|
47
|
+
|
|
48
|
+
# Please, keep your bot tokens on environments, this code only example
|
|
49
|
+
bot = Bot('123456789:AABBCCDDEEFFaabbccddeeff-1234567890')
|
|
50
|
+
dp = Dispatcher()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dp.message()
|
|
54
|
+
async def echo(message: types.Message, state: FSMContext) -> None:
|
|
55
|
+
await message.answer(message.text)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
dp.run_polling(bot)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Test cases
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import pytest
|
|
68
|
+
|
|
69
|
+
from bot import echo
|
|
70
|
+
|
|
71
|
+
from aiogram_tests import MockedRequester
|
|
72
|
+
from aiogram_tests.handler import MessageHandler
|
|
73
|
+
from aiogram_tests.types.dataset import MESSAGE
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.mark.asyncio
|
|
77
|
+
async def test_echo():
|
|
78
|
+
request = MockedRequester(MessageHandler(echo))
|
|
79
|
+
calls = await request.query(message=MESSAGE.as_object(text="Hello, Bot!"))
|
|
80
|
+
answer_message = calls.send_message.fetchone()
|
|
81
|
+
assert answer_message.text == "Hello, Bot!"
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### [▶️ More]("https://github.com/aiogram-tests/aiogram_tests/tree/master/examples") examples
|
|
86
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
aiogram_tests/__init__.py,sha256=JOazEvtgjekpejpdLS43BgW-0u_vNzLxV_e2V8CFEGY,92
|
|
2
|
+
aiogram_tests/exceptions.py,sha256=cgyhFFntzudw_3Lw6QwpC9nKtMr_mMSQPUGbBDKRybQ,50
|
|
3
|
+
aiogram_tests/handler/__init__.py,sha256=ftP0YTO-L8NMVNKv2mXlHas-TDlwv7jB6chmZ3QXZck,265
|
|
4
|
+
aiogram_tests/handler/base.py,sha256=0JXRTsmmh26AUQMZd_qWtCOQiMYaIuHbJD_tUY8fPG4,2667
|
|
5
|
+
aiogram_tests/handler/handler.py,sha256=pHTjSOYsOa34AKcok9ocyt1Dpe3X8EAR8MILcWWZ0nA,2773
|
|
6
|
+
aiogram_tests/mocked_bot.py,sha256=2xdajeMDz3arc8C1eh6ghDgvUBpC-IMh9hfId3Fcni0,3413
|
|
7
|
+
aiogram_tests/requester.py,sha256=IUM_OyNe82219bQJpyJxMrWC3qW2tbAViaCMMBY2Co4,2745
|
|
8
|
+
aiogram_tests/types/__init__.py,sha256=1mKDyeY_uRovMCC49M3Ow3WXGAxkrbyqsw9G-WEWrDY,46
|
|
9
|
+
aiogram_tests/types/dataset/__init__.py,sha256=RSPtOgPhsUU1T9buRb6VO8rd_Ayt7PU8TD7_5NcySIw,14718
|
|
10
|
+
aiogram_tests/types/dataset/base.py,sha256=7oJKipuldXkpsOG20bDfttBHtFqFiWPCSArA9Tkqdq0,1987
|
|
11
|
+
aiogram_tests/utils.py,sha256=PnKkxzEQ6vXcXXPnpTbyjlv4RoJzoTTLyj4MathU09M,112
|
|
12
|
+
aiogram_testing-1.1.0.dist-info/METADATA,sha256=Y8gaA0QGL4RyHqfDczcbLyIPyykAECC708QsbIbqVuA,2167
|
|
13
|
+
aiogram_testing-1.1.0.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
|
|
14
|
+
aiogram_testing-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from .base import RequestHandler
|
|
2
|
+
from .handler import CallbackQueryHandler
|
|
3
|
+
from .handler import MessageHandler
|
|
4
|
+
from .handler import TelegramEventObserverHandler
|
|
5
|
+
|
|
6
|
+
__all__ = ["MessageHandler", "CallbackQueryHandler", "TelegramEventObserverHandler", "RequestHandler"]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
|
|
3
|
+
from aiogram import BaseMiddleware
|
|
4
|
+
from aiogram import Dispatcher
|
|
5
|
+
from aiogram.dispatcher.event.telegram import TelegramEventObserver
|
|
6
|
+
from aiogram.fsm.storage.memory import MemoryStorage
|
|
7
|
+
from aiogram.methods import TelegramMethod
|
|
8
|
+
from aiogram.methods.base import Response
|
|
9
|
+
from aiogram.methods.base import TelegramType
|
|
10
|
+
|
|
11
|
+
from aiogram_tests.mocked_bot import DEFAULT_AUTO_MOCK_SUCCESS
|
|
12
|
+
from aiogram_tests.mocked_bot import MockedBot
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RequestHandler:
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
dp_middlewares: Iterable[BaseMiddleware] = None,
|
|
19
|
+
exclude_observer_methods: Iterable[str] = None,
|
|
20
|
+
auto_mock_success: bool = DEFAULT_AUTO_MOCK_SUCCESS,
|
|
21
|
+
dp: Dispatcher | None = None,
|
|
22
|
+
**kwargs,
|
|
23
|
+
):
|
|
24
|
+
self.bot = MockedBot(auto_mock_success=auto_mock_success)
|
|
25
|
+
if dp is None:
|
|
26
|
+
dp = Dispatcher(storage=MemoryStorage())
|
|
27
|
+
self.dp = dp
|
|
28
|
+
|
|
29
|
+
if dp_middlewares is None:
|
|
30
|
+
dp_middlewares = ()
|
|
31
|
+
|
|
32
|
+
if exclude_observer_methods is None:
|
|
33
|
+
exclude_observer_methods = []
|
|
34
|
+
|
|
35
|
+
dispatcher_methods = self._get_dispatcher_event_observers()
|
|
36
|
+
available_methods = tuple(set(dispatcher_methods) - set(exclude_observer_methods))
|
|
37
|
+
self._register_middlewares(available_methods, tuple(dp_middlewares))
|
|
38
|
+
|
|
39
|
+
def _get_dispatcher_event_observers(self) -> list[str]:
|
|
40
|
+
"""
|
|
41
|
+
Returns a names for bot event observers, like message, callback_query etc.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
result = []
|
|
45
|
+
for name in dir(self.dp):
|
|
46
|
+
if isinstance(getattr(self.dp, name), TelegramEventObserver):
|
|
47
|
+
result.append(name)
|
|
48
|
+
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
def _register_middlewares(self, event_observer: Iterable, middlewares: Iterable) -> None:
|
|
52
|
+
for eo_name in event_observer:
|
|
53
|
+
for m in middlewares:
|
|
54
|
+
eo_obj = getattr(self.dp, eo_name)
|
|
55
|
+
eo_obj.middleware.register(m)
|
|
56
|
+
|
|
57
|
+
async def __call__(self, *args, **kwargs):
|
|
58
|
+
raise NotImplementedError
|
|
59
|
+
|
|
60
|
+
def add_result_for(
|
|
61
|
+
self,
|
|
62
|
+
method: type[TelegramMethod[TelegramType]],
|
|
63
|
+
ok: bool,
|
|
64
|
+
result: TelegramType = None,
|
|
65
|
+
description: str | None = None,
|
|
66
|
+
error_code: int = 200,
|
|
67
|
+
migrate_to_chat_id: int | None = None,
|
|
68
|
+
retry_after: int | None = None,
|
|
69
|
+
) -> Response[TelegramType]:
|
|
70
|
+
response = self.bot.add_result_for(
|
|
71
|
+
method=method,
|
|
72
|
+
ok=ok,
|
|
73
|
+
result=result,
|
|
74
|
+
description=description,
|
|
75
|
+
error_code=error_code,
|
|
76
|
+
migrate_to_chat_id=migrate_to_chat_id,
|
|
77
|
+
retry_after=retry_after,
|
|
78
|
+
)
|
|
79
|
+
return response
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
|
|
4
|
+
from aiogram import types
|
|
5
|
+
from aiogram.filters import Filter
|
|
6
|
+
from aiogram.filters import StateFilter
|
|
7
|
+
from aiogram.fsm.context import FSMContext
|
|
8
|
+
from aiogram.fsm.state import State
|
|
9
|
+
|
|
10
|
+
from .base import RequestHandler
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TelegramEventObserverHandler(RequestHandler):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
callback: Callable,
|
|
17
|
+
*filters: Filter,
|
|
18
|
+
state: State | str | None = None,
|
|
19
|
+
state_data: dict = None,
|
|
20
|
+
state_context: FSMContext | None = None,
|
|
21
|
+
dp_middlewares: Iterable = None,
|
|
22
|
+
exclude_observer_methods: Iterable = None,
|
|
23
|
+
**kwargs,
|
|
24
|
+
):
|
|
25
|
+
super().__init__(dp_middlewares, exclude_observer_methods, **kwargs)
|
|
26
|
+
|
|
27
|
+
self._callback = callback
|
|
28
|
+
self._filters: list = list(filters)
|
|
29
|
+
self._state: State | str | None = state
|
|
30
|
+
self._state_data: dict = state_data
|
|
31
|
+
self._state_context: FSMContext = state_context
|
|
32
|
+
|
|
33
|
+
if self._state_context:
|
|
34
|
+
self._state_context = state_context
|
|
35
|
+
|
|
36
|
+
if self._state_data is None:
|
|
37
|
+
self._state_data = {}
|
|
38
|
+
|
|
39
|
+
if self._filters is None:
|
|
40
|
+
self._filters = []
|
|
41
|
+
|
|
42
|
+
if not isinstance(self._state_data, dict):
|
|
43
|
+
raise ValueError("state_data is not a dict")
|
|
44
|
+
|
|
45
|
+
async def __call__(self, *args, **kwargs):
|
|
46
|
+
if self._state:
|
|
47
|
+
self._filters.append(StateFilter(self._state))
|
|
48
|
+
|
|
49
|
+
self.register_handler()
|
|
50
|
+
|
|
51
|
+
if self._state_context or self._state:
|
|
52
|
+
state = self.dp.fsm.get_context(self.bot, user_id=12345678, chat_id=12345678)
|
|
53
|
+
await state.set_state(self._state)
|
|
54
|
+
await state.update_data(**self._state_data)
|
|
55
|
+
|
|
56
|
+
await self.feed_update(*args, **kwargs)
|
|
57
|
+
|
|
58
|
+
def register_handler(self) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Register TelegramEventObserver in dispatcher
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
raise NotImplementedError
|
|
64
|
+
|
|
65
|
+
async def feed_update(self, *args, **kwargs) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Feed dispatcher updates
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
raise NotImplementedError
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class MessageHandler(TelegramEventObserverHandler):
|
|
74
|
+
def register_handler(self) -> None:
|
|
75
|
+
self.dp.message.register(self._callback, *self._filters)
|
|
76
|
+
|
|
77
|
+
async def feed_update(self, message: types.Message, *args, **kwargs) -> None:
|
|
78
|
+
await self.dp.feed_update(self.bot, types.Update(update_id=12345678, message=message))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class CallbackQueryHandler(TelegramEventObserverHandler):
|
|
82
|
+
def register_handler(self) -> None:
|
|
83
|
+
self.dp.callback_query.register(self._callback, *self._filters)
|
|
84
|
+
|
|
85
|
+
async def feed_update(self, callback_query: types.CallbackQuery, *args, **kwargs) -> None:
|
|
86
|
+
await self.dp.feed_update(self.bot, types.Update(update_id=12345678, callback_query=callback_query))
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from collections import deque
|
|
2
|
+
from collections.abc import AsyncGenerator
|
|
3
|
+
|
|
4
|
+
from aiogram import Bot
|
|
5
|
+
from aiogram.client.session.base import BaseSession
|
|
6
|
+
from aiogram.methods import TelegramMethod
|
|
7
|
+
from aiogram.methods.base import Request
|
|
8
|
+
from aiogram.methods.base import Response
|
|
9
|
+
from aiogram.methods.base import TelegramType
|
|
10
|
+
from aiogram.types import ResponseParameters
|
|
11
|
+
from aiogram.types import User
|
|
12
|
+
from aiogram.types.base import UNSET_TYPE
|
|
13
|
+
|
|
14
|
+
DEFAULT_AUTO_MOCK_SUCCESS = True
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MockedSession(BaseSession):
|
|
18
|
+
def __init__(self):
|
|
19
|
+
super().__init__()
|
|
20
|
+
self.responses: deque[Response[TelegramType]] = deque()
|
|
21
|
+
self.requests: deque[Request] = deque()
|
|
22
|
+
self.closed = True
|
|
23
|
+
|
|
24
|
+
def add_result(self, response: Response[TelegramType]) -> Response[TelegramType]:
|
|
25
|
+
self.responses.appendleft(response)
|
|
26
|
+
return response
|
|
27
|
+
|
|
28
|
+
def get_request(self) -> Request | None:
|
|
29
|
+
if self.requests:
|
|
30
|
+
return self.requests[-1]
|
|
31
|
+
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
async def close(self):
|
|
35
|
+
self.closed = True
|
|
36
|
+
|
|
37
|
+
async def make_request(
|
|
38
|
+
self,
|
|
39
|
+
bot: Bot,
|
|
40
|
+
method: TelegramMethod[TelegramType],
|
|
41
|
+
timeout: int | None = UNSET_TYPE,
|
|
42
|
+
) -> TelegramType:
|
|
43
|
+
self.closed = False
|
|
44
|
+
request = Request(method=method.__api_method__, data=method.__dict__, files=None)
|
|
45
|
+
self.requests.append(request)
|
|
46
|
+
response: Response[TelegramType] = self.responses.pop()
|
|
47
|
+
self.check_response(
|
|
48
|
+
method=method,
|
|
49
|
+
status_code=response.error_code,
|
|
50
|
+
content=response.model_dump_json(),
|
|
51
|
+
bot=bot,
|
|
52
|
+
)
|
|
53
|
+
return response.result # type: ignore
|
|
54
|
+
|
|
55
|
+
async def stream_content(
|
|
56
|
+
self, url: str, timeout: int, chunk_size: int
|
|
57
|
+
) -> AsyncGenerator[bytes, None]: # pragma: no cover
|
|
58
|
+
yield b""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class MockedBot(Bot):
|
|
62
|
+
def __init__(self, auto_mock_success: bool = DEFAULT_AUTO_MOCK_SUCCESS, **kwargs):
|
|
63
|
+
super().__init__(kwargs.pop("token", "42:TEST"), session=MockedSession(), **kwargs)
|
|
64
|
+
self.session = MockedSession()
|
|
65
|
+
self._me = User(
|
|
66
|
+
id=self.id,
|
|
67
|
+
is_bot=True,
|
|
68
|
+
first_name="FirstName",
|
|
69
|
+
last_name="LastName",
|
|
70
|
+
username="username",
|
|
71
|
+
language_code="ru",
|
|
72
|
+
)
|
|
73
|
+
self.auto_mock_success = auto_mock_success
|
|
74
|
+
|
|
75
|
+
def add_result_for(
|
|
76
|
+
self,
|
|
77
|
+
method: type[TelegramMethod[TelegramType]],
|
|
78
|
+
ok: bool,
|
|
79
|
+
result: TelegramType = None,
|
|
80
|
+
description: str | None = None,
|
|
81
|
+
error_code: int = 200,
|
|
82
|
+
migrate_to_chat_id: int | None = None,
|
|
83
|
+
retry_after: int | None = None,
|
|
84
|
+
) -> Response[TelegramType]:
|
|
85
|
+
response = Response[method.__returning__]( # type: ignore
|
|
86
|
+
ok=ok,
|
|
87
|
+
result=result,
|
|
88
|
+
description=description,
|
|
89
|
+
error_code=error_code,
|
|
90
|
+
parameters=ResponseParameters(
|
|
91
|
+
migrate_to_chat_id=migrate_to_chat_id,
|
|
92
|
+
retry_after=retry_after,
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
self.session.add_result(response)
|
|
96
|
+
return response
|
|
97
|
+
|
|
98
|
+
async def __call__(self, method: TelegramMethod, request_timeout: int | None = None):
|
|
99
|
+
if self.auto_mock_success:
|
|
100
|
+
self.add_result_for(method.__class__, ok=True)
|
|
101
|
+
return await super().__call__(method, request_timeout)
|
|
102
|
+
|
|
103
|
+
def get_request(self) -> Request:
|
|
104
|
+
return self.session.get_request()
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from aiogram.methods import TelegramMethod
|
|
2
|
+
from aiogram.methods.base import Response
|
|
3
|
+
from aiogram.methods.base import TelegramType
|
|
4
|
+
|
|
5
|
+
from .exceptions import MethodIsNotCalledError
|
|
6
|
+
from .handler.base import RequestHandler
|
|
7
|
+
from .utils import camel_case2snake_case
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CallsList(list):
|
|
11
|
+
def fetchone(self):
|
|
12
|
+
if len(self) > 0:
|
|
13
|
+
return self[-1]
|
|
14
|
+
else:
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
def fetchall(self):
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Calls:
|
|
22
|
+
def _get_attributes(self):
|
|
23
|
+
res = []
|
|
24
|
+
for item in dir(self):
|
|
25
|
+
if item.startswith("_") or item.endswith("_"):
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
if not callable(getattr(self, item)):
|
|
29
|
+
res.append(item)
|
|
30
|
+
|
|
31
|
+
return tuple(res)
|
|
32
|
+
|
|
33
|
+
def __getattr__(self, item):
|
|
34
|
+
if item in dir(self):
|
|
35
|
+
return getattr(self, item)
|
|
36
|
+
else:
|
|
37
|
+
raise MethodIsNotCalledError(
|
|
38
|
+
f"method '{item}' is not called by bot, so you cant to get this attribute. "
|
|
39
|
+
f"Called methods: {self._get_attributes()}"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class MockedRequester:
|
|
44
|
+
def __init__(self, request_handler: RequestHandler):
|
|
45
|
+
self._handler: RequestHandler = request_handler
|
|
46
|
+
|
|
47
|
+
async def query(self, *args, **kwargs) -> Calls:
|
|
48
|
+
try:
|
|
49
|
+
await self._handler(*args, **kwargs)
|
|
50
|
+
except TypeError as e:
|
|
51
|
+
raise AttributeError(f"incorrect argument name. {e}")
|
|
52
|
+
|
|
53
|
+
requests = self._handler.bot.session.requests
|
|
54
|
+
result = {}
|
|
55
|
+
for r in requests:
|
|
56
|
+
method_name = camel_case2snake_case(r.method)
|
|
57
|
+
|
|
58
|
+
if method_name not in result:
|
|
59
|
+
result[method_name] = CallsList()
|
|
60
|
+
|
|
61
|
+
result[method_name].append(self._dict_to_obj(r.data))
|
|
62
|
+
|
|
63
|
+
return self._generate_result_obj(result)
|
|
64
|
+
|
|
65
|
+
def add_result_for(
|
|
66
|
+
self,
|
|
67
|
+
method: type[TelegramMethod[TelegramType]],
|
|
68
|
+
ok: bool,
|
|
69
|
+
result: TelegramType = None,
|
|
70
|
+
description: str | None = None,
|
|
71
|
+
error_code: int = 200,
|
|
72
|
+
migrate_to_chat_id: int | None = None,
|
|
73
|
+
retry_after: int | None = None,
|
|
74
|
+
) -> Response[TelegramType]:
|
|
75
|
+
response = self._handler.add_result_for(
|
|
76
|
+
method=method,
|
|
77
|
+
ok=ok,
|
|
78
|
+
result=result,
|
|
79
|
+
description=description,
|
|
80
|
+
error_code=error_code,
|
|
81
|
+
migrate_to_chat_id=migrate_to_chat_id,
|
|
82
|
+
retry_after=retry_after,
|
|
83
|
+
)
|
|
84
|
+
return response
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def _dict_to_obj(data: dict):
|
|
88
|
+
GeneratedResponse = type("GeneratedResponse", (), data)
|
|
89
|
+
return GeneratedResponse()
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _generate_result_obj(data: dict):
|
|
93
|
+
GeneratedCalls = type("GeneratedCalls", (Calls,), data)
|
|
94
|
+
return GeneratedCalls()
|
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
from aiogram import types
|
|
2
|
+
|
|
3
|
+
from .base import DatasetItem
|
|
4
|
+
|
|
5
|
+
USER = DatasetItem(
|
|
6
|
+
{
|
|
7
|
+
"id": 12345678,
|
|
8
|
+
"is_bot": False,
|
|
9
|
+
"first_name": "FirstName",
|
|
10
|
+
"last_name": "LastName",
|
|
11
|
+
"username": "username",
|
|
12
|
+
"language_code": "ru",
|
|
13
|
+
},
|
|
14
|
+
model=types.User,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
CHAT = DatasetItem(
|
|
18
|
+
{
|
|
19
|
+
"id": 12345678,
|
|
20
|
+
"first_name": "FirstName",
|
|
21
|
+
"last_name": "LastName",
|
|
22
|
+
"username": "username",
|
|
23
|
+
"type": "private",
|
|
24
|
+
},
|
|
25
|
+
model=types.Chat,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
CHAT_PHOTO = DatasetItem(
|
|
29
|
+
{
|
|
30
|
+
"small_file_id": "small_file_id",
|
|
31
|
+
"small_file_unique_id": "small_file_unique_id",
|
|
32
|
+
"big_file_id": "big_file_id",
|
|
33
|
+
"big_file_unique_id": "big_file_unique_id",
|
|
34
|
+
},
|
|
35
|
+
model=types.ChatPhoto,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
PHOTO = DatasetItem(
|
|
39
|
+
{
|
|
40
|
+
"file_id": "AgADBAADFak0G88YZAf8OAug7bHyS9x2ZxkABHVfpJywcloRAAGAAQABAg",
|
|
41
|
+
"file_unique_id": "file_unique_id",
|
|
42
|
+
"file_size": 1101,
|
|
43
|
+
"width": 90,
|
|
44
|
+
"height": 51,
|
|
45
|
+
},
|
|
46
|
+
model=types.PhotoSize,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
AUDIO = DatasetItem(
|
|
50
|
+
{
|
|
51
|
+
"duration": 236,
|
|
52
|
+
"mime_type": "audio/mpeg3",
|
|
53
|
+
"title": "The Best Song",
|
|
54
|
+
"performer": "The Best Singer",
|
|
55
|
+
"file_id": "CQADAgADbQEAAsnrIUpNoRRNsH7_hAI",
|
|
56
|
+
"file_size": 9507774,
|
|
57
|
+
"file_unique_id": "file_unique_id",
|
|
58
|
+
},
|
|
59
|
+
model=types.Audio,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
BOT_COMMAND = DatasetItem(
|
|
63
|
+
{
|
|
64
|
+
"command": "start",
|
|
65
|
+
"description": "Start bot",
|
|
66
|
+
},
|
|
67
|
+
model=types.BotCommand,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
CHAT_MEMBER = DatasetItem(
|
|
71
|
+
{
|
|
72
|
+
"user": USER,
|
|
73
|
+
"status": "administrator",
|
|
74
|
+
"can_be_edited": False,
|
|
75
|
+
"can_manage_chat": True,
|
|
76
|
+
"can_change_info": True,
|
|
77
|
+
"can_delete_messages": True,
|
|
78
|
+
"can_invite_users": True,
|
|
79
|
+
"can_restrict_members": True,
|
|
80
|
+
"can_pin_messages": True,
|
|
81
|
+
"can_promote_members": False,
|
|
82
|
+
"can_manage_voice_chats": True, # Deprecated
|
|
83
|
+
"can_manage_video_chats": True,
|
|
84
|
+
"is_anonymous": False,
|
|
85
|
+
},
|
|
86
|
+
model=types.ChatMember,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
CHAT_MEMBER_OWNER = DatasetItem(
|
|
90
|
+
{
|
|
91
|
+
"user": USER,
|
|
92
|
+
"status": "creator",
|
|
93
|
+
"is_anonymous": False,
|
|
94
|
+
},
|
|
95
|
+
model=types.ChatMemberOwner,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
CONTACT = DatasetItem(
|
|
99
|
+
{
|
|
100
|
+
"phone_number": "88005553535",
|
|
101
|
+
"first_name": "John",
|
|
102
|
+
"last_name": "Smith",
|
|
103
|
+
},
|
|
104
|
+
model=types.Contact,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
DICE = DatasetItem({"value": 6, "emoji": "🎲"}, model=types.Dice)
|
|
108
|
+
|
|
109
|
+
DOCUMENT = DatasetItem(
|
|
110
|
+
{
|
|
111
|
+
"file_name": "test.docx",
|
|
112
|
+
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
113
|
+
"file_id": "BQADAgADpgADy_JxS66XQTBRHFleAg",
|
|
114
|
+
"file_unique_id": "file_unique_id",
|
|
115
|
+
"file_size": 21331,
|
|
116
|
+
},
|
|
117
|
+
model=types.Document,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
ANIMATION = DatasetItem(
|
|
121
|
+
{"file_id": "file_id", "file_unique_id": "file_unique_id", "width": 50, "height": 50, "duration": 50},
|
|
122
|
+
model=types.Animation,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
ENTITY_BOLD = DatasetItem(
|
|
126
|
+
{
|
|
127
|
+
"offset": 5,
|
|
128
|
+
"length": 2,
|
|
129
|
+
"type": "bold",
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
ENTITY_ITALIC = DatasetItem(
|
|
134
|
+
{
|
|
135
|
+
"offset": 8,
|
|
136
|
+
"length": 1,
|
|
137
|
+
"type": "italic",
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
ENTITY_LINK = DatasetItem(
|
|
142
|
+
{
|
|
143
|
+
"offset": 10,
|
|
144
|
+
"length": 6,
|
|
145
|
+
"type": "text_link",
|
|
146
|
+
"url": "https://google.com/",
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
ENTITY_CODE = DatasetItem(
|
|
151
|
+
{
|
|
152
|
+
"offset": 17,
|
|
153
|
+
"length": 7,
|
|
154
|
+
"type": "code",
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
ENTITY_PRE = DatasetItem(
|
|
159
|
+
{
|
|
160
|
+
"offset": 30,
|
|
161
|
+
"length": 4,
|
|
162
|
+
"type": "pre",
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
ENTITY_MENTION = DatasetItem(
|
|
167
|
+
{
|
|
168
|
+
"offset": 47,
|
|
169
|
+
"length": 9,
|
|
170
|
+
"type": "mention",
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
GAME = DatasetItem(
|
|
175
|
+
{
|
|
176
|
+
"title": "Karate Kido",
|
|
177
|
+
"description": "No trees were harmed in the making of this game :)",
|
|
178
|
+
"photo": [PHOTO, PHOTO, PHOTO],
|
|
179
|
+
"animation": ANIMATION,
|
|
180
|
+
},
|
|
181
|
+
model=types.Game,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
INVOICE = DatasetItem(
|
|
185
|
+
{
|
|
186
|
+
"title": "Working Time Machine",
|
|
187
|
+
"description": "Want to visit your great-great-great-grandparents? "
|
|
188
|
+
"Make a fortune at the races? "
|
|
189
|
+
"Shake hands with Hammurabi and take a stroll in the Hanging Gardens? "
|
|
190
|
+
"Order our Working Time Machine today!",
|
|
191
|
+
"start_parameter": "time-machine-example",
|
|
192
|
+
"currency": "USD",
|
|
193
|
+
"total_amount": 6250,
|
|
194
|
+
},
|
|
195
|
+
model=types.Invoice,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
LOCATION = DatasetItem(
|
|
199
|
+
{
|
|
200
|
+
"latitude": 50.693416,
|
|
201
|
+
"longitude": 30.624605,
|
|
202
|
+
},
|
|
203
|
+
model=types.Location,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
VENUE = DatasetItem(
|
|
207
|
+
{
|
|
208
|
+
"location": LOCATION,
|
|
209
|
+
"title": "Venue Name",
|
|
210
|
+
"address": "Venue Address",
|
|
211
|
+
"foursquare_id": "4e6f2cec483bad563d150f98",
|
|
212
|
+
},
|
|
213
|
+
model=types.Venue,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
SHIPPING_ADDRESS = DatasetItem(
|
|
217
|
+
{
|
|
218
|
+
"country_code": "US",
|
|
219
|
+
"state": "State",
|
|
220
|
+
"city": "DefaultCity",
|
|
221
|
+
"street_line1": "Central",
|
|
222
|
+
"street_line2": "Middle",
|
|
223
|
+
"post_code": "424242",
|
|
224
|
+
},
|
|
225
|
+
model=types.ShippingAddress,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
STICKER = DatasetItem(
|
|
229
|
+
{
|
|
230
|
+
"width": 512,
|
|
231
|
+
"height": 512,
|
|
232
|
+
"emoji": "🛠",
|
|
233
|
+
"set_name": "StickerSet",
|
|
234
|
+
"thumb": PHOTO,
|
|
235
|
+
"file_id": "AAbbCCddEEffGGhh1234567890",
|
|
236
|
+
"file_size": 12345,
|
|
237
|
+
"file_unique_id": "file_unique_id",
|
|
238
|
+
"type": "type",
|
|
239
|
+
"is_animated": False,
|
|
240
|
+
"is_video": False,
|
|
241
|
+
},
|
|
242
|
+
model=types.Sticker,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
SUCCESSFUL_PAYMENT = DatasetItem(
|
|
246
|
+
{
|
|
247
|
+
"currency": "USD",
|
|
248
|
+
"total_amount": 6250,
|
|
249
|
+
"invoice_payload": "HAPPY FRIDAYS COUPON",
|
|
250
|
+
"telegram_payment_charge_id": "_",
|
|
251
|
+
"provider_payment_charge_id": "12345678901234_test",
|
|
252
|
+
},
|
|
253
|
+
model=types.SuccessfulPayment,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
VIDEO = DatasetItem(
|
|
257
|
+
{
|
|
258
|
+
"duration": 52,
|
|
259
|
+
"width": 853,
|
|
260
|
+
"height": 480,
|
|
261
|
+
"mime_type": "video/quicktime",
|
|
262
|
+
"thumb": PHOTO,
|
|
263
|
+
"file_id": "BAADAgpAADdawy_JxS72kRvV3cortAg",
|
|
264
|
+
"file_unique_id": "file_unique_id",
|
|
265
|
+
"file_size": 10099782,
|
|
266
|
+
},
|
|
267
|
+
model=types.Video,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
VIDEO_NOTE = DatasetItem(
|
|
271
|
+
{
|
|
272
|
+
"duration": 4,
|
|
273
|
+
"length": 240,
|
|
274
|
+
"thumb": PHOTO,
|
|
275
|
+
"file_id": "AbCdEfGhIjKlMnOpQrStUvWxYz",
|
|
276
|
+
"file_unique_id": "file_unique_id",
|
|
277
|
+
"file_size": 186562,
|
|
278
|
+
},
|
|
279
|
+
model=types.VideoNote,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
VOICE = DatasetItem(
|
|
283
|
+
{
|
|
284
|
+
"duration": 1,
|
|
285
|
+
"mime_type": "audio/ogg",
|
|
286
|
+
"file_id": "AwADawAgADADy_JxS2gopIVIIxlhAg",
|
|
287
|
+
"file_unique_id": "file_unique_id",
|
|
288
|
+
"file_size": 4321,
|
|
289
|
+
},
|
|
290
|
+
model=types.Voice,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
MESSAGE = DatasetItem(
|
|
294
|
+
{
|
|
295
|
+
"message_id": 11223,
|
|
296
|
+
"from": USER,
|
|
297
|
+
"chat": CHAT,
|
|
298
|
+
"date": 1508709711,
|
|
299
|
+
"text": "Hi, world!",
|
|
300
|
+
},
|
|
301
|
+
model=types.Message,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
CALLBACK_QUERY = DatasetItem(
|
|
305
|
+
{"id": "12345678", "chat_instance": "AABBCC", "from_user": USER, "message": MESSAGE, "data": "data"},
|
|
306
|
+
model=types.CallbackQuery,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
CHANNEL = DatasetItem(
|
|
310
|
+
{
|
|
311
|
+
"type": "channel",
|
|
312
|
+
"username": "best_channel_ever",
|
|
313
|
+
"id": -1001065170817,
|
|
314
|
+
},
|
|
315
|
+
model=types.Chat,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
CHANNEL_POST = DatasetItem(
|
|
319
|
+
{"message_id": 12345, "sender_chat": CHANNEL, "chat": CHANNEL, "date": 1508825372, "text": "Hi, channel!"},
|
|
320
|
+
model=types.Message,
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
EDITED_CHANNEL_POST = DatasetItem(
|
|
324
|
+
{
|
|
325
|
+
"message_id": 12345,
|
|
326
|
+
"sender_chat": CHANNEL,
|
|
327
|
+
"chat": CHANNEL,
|
|
328
|
+
"date": 1508825372,
|
|
329
|
+
"edit_date": 1508825379,
|
|
330
|
+
"text": "Hi, channel! (edited)",
|
|
331
|
+
},
|
|
332
|
+
model=types.Message,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
EDITED_MESSAGE = DatasetItem(
|
|
336
|
+
{
|
|
337
|
+
"message_id": 12345,
|
|
338
|
+
"from": USER,
|
|
339
|
+
"chat": CHAT,
|
|
340
|
+
"date": 1508825372,
|
|
341
|
+
"edit_date": 1508825379,
|
|
342
|
+
"text": "hi there (edited)",
|
|
343
|
+
},
|
|
344
|
+
model=types.Message,
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
FORWARDED_MESSAGE = DatasetItem(
|
|
348
|
+
{
|
|
349
|
+
"message_id": 12345,
|
|
350
|
+
"from": USER,
|
|
351
|
+
"chat": CHAT,
|
|
352
|
+
"date": 1522828529,
|
|
353
|
+
"forward_from_chat": CHAT,
|
|
354
|
+
"forward_from_message_id": 123,
|
|
355
|
+
"forward_date": 1522749037,
|
|
356
|
+
"text": "Forwarded text with entities from public channel ",
|
|
357
|
+
"entities": [ENTITY_BOLD, ENTITY_CODE, ENTITY_ITALIC, ENTITY_LINK, ENTITY_LINK, ENTITY_MENTION, ENTITY_PRE],
|
|
358
|
+
},
|
|
359
|
+
model=types.Message,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
MESSAGE_WITH_AUDIO = DatasetItem(
|
|
363
|
+
{
|
|
364
|
+
"message_id": 12345,
|
|
365
|
+
"from": USER,
|
|
366
|
+
"chat": CHAT,
|
|
367
|
+
"date": 1508739776,
|
|
368
|
+
"audio": AUDIO,
|
|
369
|
+
"caption": "This is my favourite song",
|
|
370
|
+
},
|
|
371
|
+
model=types.Message,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
MESSAGE_WITH_CONTACT = DatasetItem(
|
|
375
|
+
{
|
|
376
|
+
"message_id": 56006,
|
|
377
|
+
"from": USER,
|
|
378
|
+
"chat": CHAT,
|
|
379
|
+
"date": 1522850298,
|
|
380
|
+
"contact": CONTACT,
|
|
381
|
+
},
|
|
382
|
+
model=types.Message,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
MESSAGE_WITH_DICE = DatasetItem(
|
|
386
|
+
{"message_id": 12345, "from": USER, "chat": CHAT, "date": 1508768012, "dice": DICE}, model=types.Message
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
MESSAGE_WITH_DOCUMENT = DatasetItem(
|
|
390
|
+
{
|
|
391
|
+
"message_id": 12345,
|
|
392
|
+
"from": USER,
|
|
393
|
+
"chat": CHAT,
|
|
394
|
+
"date": 1508768012,
|
|
395
|
+
"document": DOCUMENT,
|
|
396
|
+
"caption": "Read my document",
|
|
397
|
+
},
|
|
398
|
+
model=types.Message,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
MESSAGE_WITH_GAME = DatasetItem(
|
|
402
|
+
{
|
|
403
|
+
"message_id": 12345,
|
|
404
|
+
"from": USER,
|
|
405
|
+
"chat": CHAT,
|
|
406
|
+
"date": 1508824810,
|
|
407
|
+
"game": GAME,
|
|
408
|
+
},
|
|
409
|
+
model=types.Message,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
MESSAGE_WITH_INVOICE = DatasetItem(
|
|
413
|
+
{
|
|
414
|
+
"message_id": 9772,
|
|
415
|
+
"from": USER,
|
|
416
|
+
"chat": CHAT,
|
|
417
|
+
"date": 1508761719,
|
|
418
|
+
"invoice": INVOICE,
|
|
419
|
+
},
|
|
420
|
+
model=types.Message,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
MESSAGE_WITH_LOCATION = DatasetItem(
|
|
424
|
+
{
|
|
425
|
+
"message_id": 12345,
|
|
426
|
+
"from": USER,
|
|
427
|
+
"chat": CHAT,
|
|
428
|
+
"date": 1508755473,
|
|
429
|
+
"location": LOCATION,
|
|
430
|
+
},
|
|
431
|
+
model=types.Message,
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
MESSAGE_WITH_MIGRATE_TO_CHAT_ID = DatasetItem(
|
|
435
|
+
{
|
|
436
|
+
"message_id": 12345,
|
|
437
|
+
"from": USER,
|
|
438
|
+
"chat": CHAT,
|
|
439
|
+
"date": 1526943253,
|
|
440
|
+
"migrate_to_chat_id": -1234567890987,
|
|
441
|
+
},
|
|
442
|
+
model=types.Message,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
MESSAGE_WITH_MIGRATE_FROM_CHAT_ID = DatasetItem(
|
|
446
|
+
{
|
|
447
|
+
"message_id": 12345,
|
|
448
|
+
"from": USER,
|
|
449
|
+
"chat": CHAT,
|
|
450
|
+
"date": 1526943253,
|
|
451
|
+
"migrate_from_chat_id": -123456789,
|
|
452
|
+
},
|
|
453
|
+
model=types.Message,
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
MESSAGE_WITH_PHOTO = DatasetItem(
|
|
457
|
+
{
|
|
458
|
+
"message_id": 12345,
|
|
459
|
+
"from": USER,
|
|
460
|
+
"chat": CHAT,
|
|
461
|
+
"date": 1508825154,
|
|
462
|
+
"photo": [PHOTO, PHOTO, PHOTO, PHOTO],
|
|
463
|
+
"caption": "photo description",
|
|
464
|
+
},
|
|
465
|
+
model=types.Message,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
MESSAGE_WITH_MEDIA_GROUP = DatasetItem(
|
|
469
|
+
{
|
|
470
|
+
"message_id": 55966,
|
|
471
|
+
"from": USER,
|
|
472
|
+
"chat": CHAT,
|
|
473
|
+
"date": 1522843665,
|
|
474
|
+
"media_group_id": "12182749320567362",
|
|
475
|
+
"photo": [PHOTO, PHOTO, PHOTO, PHOTO],
|
|
476
|
+
},
|
|
477
|
+
model=types.Message,
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
MESSAGE_WITH_STICKER = DatasetItem(
|
|
481
|
+
{
|
|
482
|
+
"message_id": 12345,
|
|
483
|
+
"from": USER,
|
|
484
|
+
"chat": CHAT,
|
|
485
|
+
"date": 1508771450,
|
|
486
|
+
"sticker": STICKER,
|
|
487
|
+
},
|
|
488
|
+
model=types.Message,
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
MESSAGE_WITH_SUCCESSFUL_PAYMENT = DatasetItem(
|
|
492
|
+
{
|
|
493
|
+
"message_id": 9768,
|
|
494
|
+
"from": USER,
|
|
495
|
+
"chat": CHAT,
|
|
496
|
+
"date": 1508761169,
|
|
497
|
+
"successful_payment": SUCCESSFUL_PAYMENT,
|
|
498
|
+
},
|
|
499
|
+
model=types.Message,
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
MESSAGE_WITH_VENUE = DatasetItem(
|
|
503
|
+
{
|
|
504
|
+
"message_id": 56004,
|
|
505
|
+
"from": USER,
|
|
506
|
+
"chat": CHAT,
|
|
507
|
+
"date": 1522849819,
|
|
508
|
+
"location": LOCATION,
|
|
509
|
+
"venue": VENUE,
|
|
510
|
+
},
|
|
511
|
+
model=types.Message,
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
MESSAGE_WITH_VIDEO = DatasetItem(
|
|
515
|
+
{
|
|
516
|
+
"message_id": 12345,
|
|
517
|
+
"from": USER,
|
|
518
|
+
"chat": CHAT,
|
|
519
|
+
"date": 1508756494,
|
|
520
|
+
"video": VIDEO,
|
|
521
|
+
"caption": "description",
|
|
522
|
+
},
|
|
523
|
+
model=types.Message,
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
MESSAGE_WITH_VIDEO_NOTE = DatasetItem(
|
|
527
|
+
{
|
|
528
|
+
"message_id": 55934,
|
|
529
|
+
"from": USER,
|
|
530
|
+
"chat": CHAT,
|
|
531
|
+
"date": 1522835890,
|
|
532
|
+
"video_note": VIDEO_NOTE,
|
|
533
|
+
},
|
|
534
|
+
model=types.Message,
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
MESSAGE_WITH_VOICE = DatasetItem(
|
|
538
|
+
{
|
|
539
|
+
"message_id": 12345,
|
|
540
|
+
"from": USER,
|
|
541
|
+
"chat": CHAT,
|
|
542
|
+
"date": 1508768403,
|
|
543
|
+
"voice": VOICE,
|
|
544
|
+
},
|
|
545
|
+
model=types.Message,
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
MESSAGE_FROM_CHANNEL = DatasetItem(
|
|
549
|
+
{
|
|
550
|
+
"message_id": 123432,
|
|
551
|
+
"from": None,
|
|
552
|
+
"chat": CHANNEL,
|
|
553
|
+
"date": 1508768405,
|
|
554
|
+
"text": "Hi, world!",
|
|
555
|
+
},
|
|
556
|
+
model=types.Message,
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
PRE_CHECKOUT_QUERY = DatasetItem(
|
|
560
|
+
{
|
|
561
|
+
"id": "262181558630368727",
|
|
562
|
+
"from": USER,
|
|
563
|
+
"currency": "USD",
|
|
564
|
+
"total_amount": 6250,
|
|
565
|
+
"invoice_payload": "HAPPY FRIDAYS COUPON",
|
|
566
|
+
},
|
|
567
|
+
model=types.PreCheckoutQuery,
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
REPLY_MESSAGE = DatasetItem(
|
|
571
|
+
{
|
|
572
|
+
"message_id": 12345,
|
|
573
|
+
"from": USER,
|
|
574
|
+
"chat": CHAT,
|
|
575
|
+
"date": 1508751866,
|
|
576
|
+
"reply_to_message": MESSAGE,
|
|
577
|
+
"text": "Reply to quoted message",
|
|
578
|
+
},
|
|
579
|
+
model=types.Message,
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
SHIPPING_QUERY = DatasetItem(
|
|
583
|
+
{
|
|
584
|
+
"id": "262181558684397422",
|
|
585
|
+
"from": USER,
|
|
586
|
+
"invoice_payload": "HAPPY FRIDAYS COUPON",
|
|
587
|
+
"shipping_address": SHIPPING_ADDRESS,
|
|
588
|
+
},
|
|
589
|
+
model=types.ShippingQuery,
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
USER_PROFILE_PHOTOS = DatasetItem(
|
|
593
|
+
{
|
|
594
|
+
"total_count": 1,
|
|
595
|
+
"photos": [
|
|
596
|
+
[PHOTO, PHOTO, PHOTO],
|
|
597
|
+
],
|
|
598
|
+
},
|
|
599
|
+
model=types.UserProfilePhotos,
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
FILE = DatasetItem(
|
|
603
|
+
{"file_id": "XXXYYYZZZ", "file_size": 5254, "file_path": "voice/file_8", "file_unique_id": "file_unique_id"},
|
|
604
|
+
model=types.File,
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
UPDATE = DatasetItem(
|
|
608
|
+
{
|
|
609
|
+
"update_id": 123456789,
|
|
610
|
+
"message": MESSAGE,
|
|
611
|
+
},
|
|
612
|
+
model=types.Update,
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
WEBHOOK_INFO = DatasetItem(
|
|
616
|
+
{
|
|
617
|
+
"url": "",
|
|
618
|
+
"has_custom_certificate": False,
|
|
619
|
+
"pending_update_count": 0,
|
|
620
|
+
},
|
|
621
|
+
model=types.WebhookInfo,
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
REPLY_KEYBOARD_MARKUP = DatasetItem(
|
|
625
|
+
{
|
|
626
|
+
"keyboard": [[{"text": "something here"}]],
|
|
627
|
+
"resize_keyboard": True,
|
|
628
|
+
},
|
|
629
|
+
model=types.ReplyKeyboardMarkup,
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
CHAT_PERMISSIONS = DatasetItem(
|
|
633
|
+
{
|
|
634
|
+
"can_send_messages": True,
|
|
635
|
+
"can_send_media_messages": True,
|
|
636
|
+
"can_send_polls": True,
|
|
637
|
+
"can_send_other_messages": True,
|
|
638
|
+
"can_add_web_page_previews": True,
|
|
639
|
+
"can_change_info": True,
|
|
640
|
+
"can_invite_users": True,
|
|
641
|
+
"can_pin_messages": True,
|
|
642
|
+
},
|
|
643
|
+
model=types.ChatPermissions,
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
CHAT_LOCATION = DatasetItem(
|
|
647
|
+
{
|
|
648
|
+
"location": LOCATION,
|
|
649
|
+
"address": "address",
|
|
650
|
+
},
|
|
651
|
+
model=types.ChatLocation,
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
FULL_CHAT = DatasetItem(
|
|
655
|
+
{
|
|
656
|
+
**CHAT,
|
|
657
|
+
"photo": CHAT_PHOTO,
|
|
658
|
+
"bio": "bio",
|
|
659
|
+
"has_private_forwards": False,
|
|
660
|
+
"description": "description",
|
|
661
|
+
"invite_link": "invite_link",
|
|
662
|
+
"pinned_message": MESSAGE,
|
|
663
|
+
"permissions": CHAT_PERMISSIONS,
|
|
664
|
+
"slow_mode_delay": 10,
|
|
665
|
+
"message_auto_delete_time": 60,
|
|
666
|
+
"has_protected_content": True,
|
|
667
|
+
"sticker_set_name": "sticker_set_name",
|
|
668
|
+
"can_set_sticker_set": True,
|
|
669
|
+
"linked_chat_id": -1234567890,
|
|
670
|
+
"location": CHAT_LOCATION,
|
|
671
|
+
},
|
|
672
|
+
model=types.Chat,
|
|
673
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DatasetItem(Mapping):
|
|
6
|
+
def __init__(self, data: dict, *, model=None, name=None):
|
|
7
|
+
self._data = data
|
|
8
|
+
self._name = name
|
|
9
|
+
self._model = model
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def data(self) -> dict:
|
|
13
|
+
return self._data
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def name(self) -> str:
|
|
17
|
+
return self._name
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def model(self) -> Any:
|
|
21
|
+
return self._model
|
|
22
|
+
|
|
23
|
+
def as_object(self, **replace_args) -> Any | None:
|
|
24
|
+
"""
|
|
25
|
+
Return an object from dict
|
|
26
|
+
|
|
27
|
+
:return: Any | None
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
data = self._data.copy()
|
|
31
|
+
data.update(**replace_args)
|
|
32
|
+
if self._model and isinstance(self._data, dict):
|
|
33
|
+
return self._recursive_as_object(data, self._model)
|
|
34
|
+
else:
|
|
35
|
+
return data
|
|
36
|
+
except (AttributeError, TypeError):
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
def _recursive_as_object(self, data: dict, model: Any):
|
|
40
|
+
"""
|
|
41
|
+
This method is converting dict data to object, if one of the params is the DatasetItem method will be
|
|
42
|
+
recursive convert it;
|
|
43
|
+
|
|
44
|
+
:param data: the dict that should be as object
|
|
45
|
+
:param model: the object that will be returned
|
|
46
|
+
:return:
|
|
47
|
+
"""
|
|
48
|
+
result_data = data.copy()
|
|
49
|
+
for key, value in data.items():
|
|
50
|
+
if isinstance(value, DatasetItem):
|
|
51
|
+
result_data[key] = self._recursive_as_object(value.data, value.model)
|
|
52
|
+
elif isinstance(value, list):
|
|
53
|
+
for index, item in enumerate(value):
|
|
54
|
+
if not isinstance(item, (DatasetItem, list)):
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
result_data[key][index] = self._recursive_as_object(item.data, item.model)
|
|
58
|
+
|
|
59
|
+
return model(**result_data)
|
|
60
|
+
|
|
61
|
+
def __iter__(self):
|
|
62
|
+
return iter(self._data.keys())
|
|
63
|
+
|
|
64
|
+
def __getitem__(self, item):
|
|
65
|
+
return self._data[item]
|
|
66
|
+
|
|
67
|
+
def __len__(self):
|
|
68
|
+
return len(self._data)
|