telegrinder 0.3.4.post1__py3-none-any.whl → 0.4.1__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.
Potentially problematic release.
This version of telegrinder might be problematic. Click here for more details.
- telegrinder/__init__.py +30 -31
- telegrinder/api/__init__.py +2 -1
- telegrinder/api/api.py +28 -20
- telegrinder/api/error.py +8 -4
- telegrinder/api/response.py +2 -2
- telegrinder/api/token.py +2 -2
- telegrinder/bot/__init__.py +6 -0
- telegrinder/bot/bot.py +38 -31
- telegrinder/bot/cute_types/__init__.py +2 -0
- telegrinder/bot/cute_types/base.py +55 -129
- telegrinder/bot/cute_types/callback_query.py +76 -61
- telegrinder/bot/cute_types/chat_join_request.py +4 -3
- telegrinder/bot/cute_types/chat_member_updated.py +28 -31
- telegrinder/bot/cute_types/inline_query.py +5 -4
- telegrinder/bot/cute_types/message.py +555 -602
- telegrinder/bot/cute_types/pre_checkout_query.py +42 -0
- telegrinder/bot/cute_types/update.py +20 -12
- telegrinder/bot/cute_types/utils.py +3 -36
- telegrinder/bot/dispatch/__init__.py +4 -0
- telegrinder/bot/dispatch/abc.py +8 -9
- telegrinder/bot/dispatch/context.py +5 -7
- telegrinder/bot/dispatch/dispatch.py +85 -33
- telegrinder/bot/dispatch/handler/abc.py +5 -6
- telegrinder/bot/dispatch/handler/audio_reply.py +2 -2
- telegrinder/bot/dispatch/handler/base.py +3 -3
- telegrinder/bot/dispatch/handler/document_reply.py +2 -2
- telegrinder/bot/dispatch/handler/func.py +36 -42
- telegrinder/bot/dispatch/handler/media_group_reply.py +5 -4
- telegrinder/bot/dispatch/handler/message_reply.py +2 -2
- telegrinder/bot/dispatch/handler/photo_reply.py +2 -2
- telegrinder/bot/dispatch/handler/sticker_reply.py +2 -2
- telegrinder/bot/dispatch/handler/video_reply.py +2 -2
- telegrinder/bot/dispatch/middleware/abc.py +83 -8
- telegrinder/bot/dispatch/middleware/global_middleware.py +70 -0
- telegrinder/bot/dispatch/process.py +44 -50
- telegrinder/bot/dispatch/return_manager/__init__.py +2 -0
- telegrinder/bot/dispatch/return_manager/abc.py +6 -10
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +20 -0
- telegrinder/bot/dispatch/view/__init__.py +2 -0
- telegrinder/bot/dispatch/view/abc.py +10 -6
- telegrinder/bot/dispatch/view/base.py +81 -50
- telegrinder/bot/dispatch/view/box.py +20 -9
- telegrinder/bot/dispatch/view/callback_query.py +3 -4
- telegrinder/bot/dispatch/view/chat_join_request.py +2 -7
- telegrinder/bot/dispatch/view/chat_member.py +3 -5
- telegrinder/bot/dispatch/view/inline_query.py +3 -4
- telegrinder/bot/dispatch/view/message.py +3 -4
- telegrinder/bot/dispatch/view/pre_checkout_query.py +16 -0
- telegrinder/bot/dispatch/view/raw.py +42 -40
- telegrinder/bot/dispatch/waiter_machine/actions.py +5 -4
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +9 -7
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +3 -2
- telegrinder/bot/dispatch/waiter_machine/machine.py +113 -34
- telegrinder/bot/dispatch/waiter_machine/middleware.py +15 -10
- telegrinder/bot/dispatch/waiter_machine/short_state.py +7 -18
- telegrinder/bot/polling/polling.py +62 -54
- telegrinder/bot/rules/__init__.py +24 -1
- telegrinder/bot/rules/abc.py +17 -10
- telegrinder/bot/rules/callback_data.py +20 -61
- telegrinder/bot/rules/chat_join.py +6 -4
- telegrinder/bot/rules/command.py +4 -4
- telegrinder/bot/rules/enum_text.py +1 -4
- telegrinder/bot/rules/func.py +5 -3
- telegrinder/bot/rules/fuzzy.py +1 -1
- telegrinder/bot/rules/id.py +24 -0
- telegrinder/bot/rules/inline.py +6 -4
- telegrinder/bot/rules/integer.py +2 -1
- telegrinder/bot/rules/logic.py +18 -0
- telegrinder/bot/rules/markup.py +5 -6
- telegrinder/bot/rules/message.py +2 -4
- telegrinder/bot/rules/message_entities.py +1 -3
- telegrinder/bot/rules/node.py +15 -9
- telegrinder/bot/rules/payload.py +81 -0
- telegrinder/bot/rules/payment_invoice.py +29 -0
- telegrinder/bot/rules/regex.py +5 -6
- telegrinder/bot/rules/state.py +1 -3
- telegrinder/bot/rules/text.py +10 -5
- telegrinder/bot/rules/update.py +0 -0
- telegrinder/bot/scenario/abc.py +2 -4
- telegrinder/bot/scenario/checkbox.py +12 -14
- telegrinder/bot/scenario/choice.py +6 -9
- telegrinder/client/__init__.py +9 -1
- telegrinder/client/abc.py +35 -10
- telegrinder/client/aiohttp.py +28 -24
- telegrinder/client/form_data.py +31 -0
- telegrinder/client/sonic.py +212 -0
- telegrinder/model.py +38 -145
- telegrinder/modules.py +3 -1
- telegrinder/msgspec_utils.py +136 -68
- telegrinder/node/__init__.py +74 -13
- telegrinder/node/attachment.py +92 -16
- telegrinder/node/base.py +196 -68
- telegrinder/node/callback_query.py +17 -16
- telegrinder/node/command.py +3 -2
- telegrinder/node/composer.py +40 -75
- telegrinder/node/container.py +13 -7
- telegrinder/node/either.py +82 -0
- telegrinder/node/event.py +20 -31
- telegrinder/node/file.py +51 -0
- telegrinder/node/me.py +4 -5
- telegrinder/node/payload.py +78 -0
- telegrinder/node/polymorphic.py +28 -9
- telegrinder/node/rule.py +2 -6
- telegrinder/node/scope.py +4 -6
- telegrinder/node/source.py +37 -21
- telegrinder/node/text.py +20 -8
- telegrinder/node/tools/generator.py +7 -11
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +0 -61
- telegrinder/tools/__init__.py +97 -38
- telegrinder/tools/adapter/__init__.py +19 -0
- telegrinder/tools/adapter/abc.py +49 -0
- telegrinder/tools/adapter/dataclass.py +56 -0
- telegrinder/{bot/rules → tools}/adapter/event.py +8 -10
- telegrinder/{bot/rules → tools}/adapter/node.py +8 -10
- telegrinder/{bot/rules → tools}/adapter/raw_event.py +2 -2
- telegrinder/{bot/rules → tools}/adapter/raw_update.py +2 -2
- telegrinder/tools/buttons.py +52 -26
- telegrinder/tools/callback_data_serilization/__init__.py +5 -0
- telegrinder/tools/callback_data_serilization/abc.py +51 -0
- telegrinder/tools/callback_data_serilization/json_ser.py +60 -0
- telegrinder/tools/callback_data_serilization/msgpack_ser.py +172 -0
- telegrinder/tools/error_handler/abc.py +4 -7
- telegrinder/tools/error_handler/error.py +0 -0
- telegrinder/tools/error_handler/error_handler.py +34 -48
- telegrinder/tools/formatting/__init__.py +57 -37
- telegrinder/tools/formatting/deep_links.py +541 -0
- telegrinder/tools/formatting/{html.py → html_formatter.py} +51 -79
- telegrinder/tools/formatting/spec_html_formats.py +14 -60
- telegrinder/tools/functional.py +1 -5
- telegrinder/tools/global_context/global_context.py +26 -51
- telegrinder/tools/global_context/telegrinder_ctx.py +3 -3
- telegrinder/tools/i18n/abc.py +0 -0
- telegrinder/tools/i18n/middleware/abc.py +3 -6
- telegrinder/tools/input_file_directory.py +30 -0
- telegrinder/tools/keyboard.py +9 -9
- telegrinder/tools/lifespan.py +105 -0
- telegrinder/tools/limited_dict.py +5 -10
- telegrinder/tools/loop_wrapper/abc.py +7 -2
- telegrinder/tools/loop_wrapper/loop_wrapper.py +40 -95
- telegrinder/tools/magic.py +236 -60
- telegrinder/tools/state_storage/__init__.py +0 -0
- telegrinder/tools/state_storage/abc.py +5 -9
- telegrinder/tools/state_storage/memory.py +1 -1
- telegrinder/tools/strings.py +13 -0
- telegrinder/types/__init__.py +8 -0
- telegrinder/types/enums.py +31 -21
- telegrinder/types/input_file.py +51 -0
- telegrinder/types/methods.py +531 -109
- telegrinder/types/objects.py +934 -826
- telegrinder/verification_utils.py +0 -2
- {telegrinder-0.3.4.post1.dist-info → telegrinder-0.4.1.dist-info}/LICENSE +2 -2
- telegrinder-0.4.1.dist-info/METADATA +143 -0
- telegrinder-0.4.1.dist-info/RECORD +182 -0
- {telegrinder-0.3.4.post1.dist-info → telegrinder-0.4.1.dist-info}/WHEEL +1 -1
- telegrinder/bot/rules/adapter/__init__.py +0 -17
- telegrinder/bot/rules/adapter/abc.py +0 -31
- telegrinder/node/message.py +0 -14
- telegrinder/node/update.py +0 -15
- telegrinder/tools/formatting/links.py +0 -38
- telegrinder/tools/kb_set/__init__.py +0 -4
- telegrinder/tools/kb_set/base.py +0 -15
- telegrinder/tools/kb_set/yaml.py +0 -63
- telegrinder-0.3.4.post1.dist-info/METADATA +0 -110
- telegrinder-0.3.4.post1.dist-info/RECORD +0 -165
- /telegrinder/{bot/rules → tools}/adapter/errors.py +0 -0
telegrinder/__init__.py
CHANGED
|
@@ -33,7 +33,7 @@ bot.run_forever()
|
|
|
33
33
|
|
|
34
34
|
import typing
|
|
35
35
|
|
|
36
|
-
from .api import API, APIError, APIResponse, Token
|
|
36
|
+
from .api import API, APIError, APIResponse, APIServerError, Token
|
|
37
37
|
from .bot import (
|
|
38
38
|
CALLBACK_QUERY_FOR_MESSAGE,
|
|
39
39
|
CALLBACK_QUERY_FROM_CHAT,
|
|
@@ -82,6 +82,9 @@ from .bot import (
|
|
|
82
82
|
MessageView,
|
|
83
83
|
PhotoReplyHandler,
|
|
84
84
|
Polling,
|
|
85
|
+
PreCheckoutQueryCute,
|
|
86
|
+
PreCheckoutQueryManager,
|
|
87
|
+
PreCheckoutQueryView,
|
|
85
88
|
RawEventView,
|
|
86
89
|
ShortState,
|
|
87
90
|
StateViewHasher,
|
|
@@ -93,45 +96,37 @@ from .bot import (
|
|
|
93
96
|
WaiterMachine,
|
|
94
97
|
register_manager,
|
|
95
98
|
)
|
|
96
|
-
from .
|
|
97
|
-
from .client import ABCClient, AiohttpClient
|
|
99
|
+
from .client import ABCClient, AiohttpClient, AiosonicClient
|
|
98
100
|
from .model import Model
|
|
99
101
|
from .modules import logger
|
|
100
|
-
from .tools import
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
ABCStateStorage,
|
|
102
|
+
from .tools.error_handler import ABCErrorHandler, ErrorHandler
|
|
103
|
+
from .tools.formatting import HTMLFormatter
|
|
104
|
+
from .tools.global_context import ABCGlobalContext, CtxVar, GlobalContext, ctx_var
|
|
105
|
+
from .tools.i18n import (
|
|
105
106
|
ABCTranslator,
|
|
106
107
|
ABCTranslatorMiddleware,
|
|
108
|
+
I18nEnum,
|
|
109
|
+
SimpleI18n,
|
|
110
|
+
SimpleTranslator,
|
|
111
|
+
)
|
|
112
|
+
from .tools.input_file_directory import InputFileDirectory
|
|
113
|
+
from .tools.keyboard import (
|
|
107
114
|
AnyMarkup,
|
|
108
115
|
Button,
|
|
109
|
-
CtxVar,
|
|
110
|
-
DelayedTask,
|
|
111
|
-
ErrorHandler,
|
|
112
|
-
FormatString,
|
|
113
|
-
GlobalContext,
|
|
114
|
-
HTMLFormatter,
|
|
115
|
-
I18nEnum,
|
|
116
116
|
InlineButton,
|
|
117
117
|
InlineKeyboard,
|
|
118
118
|
Keyboard,
|
|
119
|
-
KeyboardSetBase,
|
|
120
|
-
KeyboardSetYAML,
|
|
121
|
-
Lifespan,
|
|
122
|
-
LoopWrapper,
|
|
123
|
-
MemoryStateStorage,
|
|
124
|
-
ParseMode,
|
|
125
119
|
RowButtons,
|
|
126
|
-
SimpleI18n,
|
|
127
|
-
SimpleTranslator,
|
|
128
|
-
StateData,
|
|
129
|
-
ctx_var,
|
|
130
|
-
magic_bundle,
|
|
131
120
|
)
|
|
121
|
+
from .tools.lifespan import Lifespan
|
|
122
|
+
from .tools.loop_wrapper import ABCLoopWrapper, DelayedTask, LoopWrapper
|
|
123
|
+
from .tools.magic import cache_translation, get_cached_translation, magic_bundle
|
|
124
|
+
from .tools.parse_mode import ParseMode
|
|
125
|
+
from .tools.state_storage import ABCStateStorage, MemoryStateStorage, StateData
|
|
132
126
|
|
|
133
127
|
Update: typing.TypeAlias = UpdateCute
|
|
134
128
|
Message: typing.TypeAlias = MessageCute
|
|
129
|
+
PreCheckoutQuery: typing.TypeAlias = PreCheckoutQueryCute
|
|
135
130
|
ChatJoinRequest: typing.TypeAlias = ChatJoinRequestCute
|
|
136
131
|
ChatMemberUpdated: typing.TypeAlias = ChatMemberUpdatedCute
|
|
137
132
|
CallbackQuery: typing.TypeAlias = CallbackQueryCute
|
|
@@ -160,7 +155,9 @@ __all__ = (
|
|
|
160
155
|
"API",
|
|
161
156
|
"APIError",
|
|
162
157
|
"APIResponse",
|
|
158
|
+
"APIServerError",
|
|
163
159
|
"AiohttpClient",
|
|
160
|
+
"AiosonicClient",
|
|
164
161
|
"AnyMarkup",
|
|
165
162
|
"AudioReplyHandler",
|
|
166
163
|
"BaseCute",
|
|
@@ -192,7 +189,6 @@ __all__ = (
|
|
|
192
189
|
"Dispatch",
|
|
193
190
|
"DocumentReplyHandler",
|
|
194
191
|
"ErrorHandler",
|
|
195
|
-
"FormatString",
|
|
196
192
|
"FuncHandler",
|
|
197
193
|
"GlobalContext",
|
|
198
194
|
"HTMLFormatter",
|
|
@@ -204,9 +200,8 @@ __all__ = (
|
|
|
204
200
|
"InlineQueryCute",
|
|
205
201
|
"InlineQueryReturnManager",
|
|
206
202
|
"InlineQueryRule",
|
|
203
|
+
"InputFileDirectory",
|
|
207
204
|
"Keyboard",
|
|
208
|
-
"KeyboardSetBase",
|
|
209
|
-
"KeyboardSetYAML",
|
|
210
205
|
"Lifespan",
|
|
211
206
|
"LoopWrapper",
|
|
212
207
|
"MESSAGE_FROM_USER",
|
|
@@ -226,6 +221,10 @@ __all__ = (
|
|
|
226
221
|
"ParseMode",
|
|
227
222
|
"PhotoReplyHandler",
|
|
228
223
|
"Polling",
|
|
224
|
+
"PreCheckoutQuery",
|
|
225
|
+
"PreCheckoutQueryCute",
|
|
226
|
+
"PreCheckoutQueryManager",
|
|
227
|
+
"PreCheckoutQueryView",
|
|
229
228
|
"RawEventView",
|
|
230
229
|
"RowButtons",
|
|
231
230
|
"ShortState",
|
|
@@ -233,8 +232,6 @@ __all__ = (
|
|
|
233
232
|
"SimpleTranslator",
|
|
234
233
|
"StateData",
|
|
235
234
|
"StateData",
|
|
236
|
-
"StateMeta",
|
|
237
|
-
"StateMeta",
|
|
238
235
|
"StateViewHasher",
|
|
239
236
|
"StickerReplyHandler",
|
|
240
237
|
"Telegrinder",
|
|
@@ -244,7 +241,9 @@ __all__ = (
|
|
|
244
241
|
"VideoReplyHandler",
|
|
245
242
|
"ViewBox",
|
|
246
243
|
"WaiterMachine",
|
|
244
|
+
"cache_translation",
|
|
247
245
|
"ctx_var",
|
|
246
|
+
"get_cached_translation",
|
|
248
247
|
"logger",
|
|
249
248
|
"magic_bundle",
|
|
250
249
|
"register_manager",
|
telegrinder/api/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from .api import API
|
|
2
|
-
from .error import APIError, InvalidTokenError
|
|
2
|
+
from .error import APIError, APIServerError, InvalidTokenError
|
|
3
3
|
from .response import APIResponse
|
|
4
4
|
from .token import Token
|
|
5
5
|
|
|
@@ -7,6 +7,7 @@ __all__ = (
|
|
|
7
7
|
"API",
|
|
8
8
|
"APIError",
|
|
9
9
|
"APIResponse",
|
|
10
|
+
"APIServerError",
|
|
10
11
|
"InvalidTokenError",
|
|
11
12
|
"Token",
|
|
12
13
|
)
|
telegrinder/api/api.py
CHANGED
|
@@ -1,39 +1,44 @@
|
|
|
1
|
-
import typing
|
|
2
1
|
from functools import cached_property
|
|
3
2
|
|
|
4
3
|
import msgspec
|
|
4
|
+
import typing_extensions as typing
|
|
5
5
|
from fntypes.result import Error, Ok, Result
|
|
6
6
|
|
|
7
7
|
from telegrinder.api.error import APIError
|
|
8
8
|
from telegrinder.api.response import APIResponse
|
|
9
9
|
from telegrinder.api.token import Token
|
|
10
|
-
from telegrinder.client import ABCClient, AiohttpClient
|
|
11
|
-
from telegrinder.model import
|
|
10
|
+
from telegrinder.client import ABCClient, AiohttpClient, MultipartFormProto
|
|
11
|
+
from telegrinder.model import decoder
|
|
12
12
|
from telegrinder.types.methods import APIMethods
|
|
13
13
|
|
|
14
|
+
HTTPClient = typing.TypeVar("HTTPClient", bound=ABCClient, default=AiohttpClient)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
type Json = str | int | float | bool | list[Json] | dict[str, Json] | None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def compose_data[MultipartForm: MultipartFormProto](
|
|
20
|
+
client: ABCClient[MultipartForm],
|
|
17
21
|
data: dict[str, typing.Any],
|
|
18
22
|
files: dict[str, tuple[str, bytes]],
|
|
19
|
-
) ->
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
files=converter.files,
|
|
24
|
-
)
|
|
23
|
+
) -> MultipartForm:
|
|
24
|
+
if not data and not files:
|
|
25
|
+
return client.multipart_form_factory()
|
|
26
|
+
return client.get_form(data=data, files=files)
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
class API(APIMethods):
|
|
29
|
+
class API(APIMethods[HTTPClient], typing.Generic[HTTPClient]):
|
|
28
30
|
"""Bot API with available API methods and http client."""
|
|
29
31
|
|
|
30
32
|
API_URL = "https://api.telegram.org/"
|
|
31
33
|
API_FILE_URL = "https://api.telegram.org/file/"
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
token: Token
|
|
36
|
+
http: HTTPClient
|
|
37
|
+
|
|
38
|
+
def __init__(self, token: Token, *, http: HTTPClient | None = None) -> None:
|
|
34
39
|
self.token = token
|
|
35
|
-
self.http = http or AiohttpClient()
|
|
36
|
-
super().__init__(self)
|
|
40
|
+
self.http = http or AiohttpClient() # type: ignore
|
|
41
|
+
super().__init__(api=self)
|
|
37
42
|
|
|
38
43
|
def __repr__(self) -> str:
|
|
39
44
|
return "<{}: token={!r}, http={!r}>".format(
|
|
@@ -62,19 +67,20 @@ class API(APIMethods):
|
|
|
62
67
|
method: str,
|
|
63
68
|
data: dict[str, typing.Any] | None = None,
|
|
64
69
|
files: dict[str, tuple[str, bytes]] | None = None,
|
|
65
|
-
) -> Result[
|
|
70
|
+
) -> Result[Json, APIError]:
|
|
71
|
+
"""Request a `JSON` response with the `POST` HTTP method and passing data, files as `multipart/form-data`."""
|
|
66
72
|
response = await self.http.request_json(
|
|
67
73
|
url=self.request_url + method,
|
|
74
|
+
method="POST",
|
|
68
75
|
data=compose_data(self.http, data or {}, files or {}),
|
|
69
76
|
)
|
|
70
|
-
if response.get("ok"):
|
|
71
|
-
assert "result" in response
|
|
77
|
+
if response.get("ok", False) is True:
|
|
72
78
|
return Ok(response["result"])
|
|
73
79
|
return Error(
|
|
74
80
|
APIError(
|
|
75
81
|
code=response.get("error_code", 400),
|
|
76
|
-
error=response.get("description"),
|
|
77
|
-
)
|
|
82
|
+
error=response.get("description", "Something went wrong"),
|
|
83
|
+
),
|
|
78
84
|
)
|
|
79
85
|
|
|
80
86
|
async def request_raw(
|
|
@@ -83,8 +89,10 @@ class API(APIMethods):
|
|
|
83
89
|
data: dict[str, typing.Any] | None = None,
|
|
84
90
|
files: dict[str, tuple[str, bytes]] | None = None,
|
|
85
91
|
) -> Result[msgspec.Raw, APIError]:
|
|
92
|
+
"""Request a `raw` response with the `POST` HTTP method and passing data, files as `multipart/form-data`."""
|
|
86
93
|
response_bytes = await self.http.request_bytes(
|
|
87
94
|
url=self.request_url + method,
|
|
95
|
+
method="POST",
|
|
88
96
|
data=compose_data(self.http, data or {}, files or {}),
|
|
89
97
|
)
|
|
90
98
|
return decoder.decode(response_bytes, type=APIResponse).to_result()
|
telegrinder/api/error.py
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
class APIError(
|
|
2
|
-
def __init__(self, code: int, error: str
|
|
1
|
+
class APIError(Exception):
|
|
2
|
+
def __init__(self, code: int, error: str) -> None:
|
|
3
3
|
self.code, self.error = code, error
|
|
4
4
|
|
|
5
5
|
def __str__(self) -> str:
|
|
6
|
-
return f"[{self.code}] {self.error
|
|
6
|
+
return f"[{self.code}] {self.error}"
|
|
7
7
|
|
|
8
8
|
def __repr__(self) -> str:
|
|
9
9
|
return f"<APIError: {self.__str__()}>"
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
class APIServerError(Exception):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
12
16
|
class InvalidTokenError(BaseException):
|
|
13
17
|
pass
|
|
14
18
|
|
|
15
19
|
|
|
16
|
-
__all__ = ("APIError", "InvalidTokenError")
|
|
20
|
+
__all__ = ("APIError", "APIServerError", "InvalidTokenError")
|
telegrinder/api/response.py
CHANGED
|
@@ -8,8 +8,8 @@ from telegrinder.model import Model
|
|
|
8
8
|
class APIResponse(Model):
|
|
9
9
|
ok: bool = False
|
|
10
10
|
result: msgspec.Raw = msgspec.Raw(b"")
|
|
11
|
-
error_code: int =
|
|
12
|
-
description: str = ""
|
|
11
|
+
error_code: int = 400
|
|
12
|
+
description: str = "Something went wrong"
|
|
13
13
|
|
|
14
14
|
def to_result(self) -> Result[msgspec.Raw, APIError]:
|
|
15
15
|
if self.ok:
|
telegrinder/api/token.py
CHANGED
|
@@ -8,9 +8,9 @@ from .error import InvalidTokenError
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Token(str):
|
|
11
|
-
def __new__(cls, token: str) -> typing.Self:
|
|
11
|
+
def __new__(cls, token: str, /) -> typing.Self:
|
|
12
12
|
if token.count(":") != 1 or not token.split(":")[0].isdigit():
|
|
13
|
-
raise InvalidTokenError("Invalid token, it should look like this
|
|
13
|
+
raise InvalidTokenError("Invalid token, it should look like this: 12345:ABCdef")
|
|
14
14
|
return super().__new__(cls, token)
|
|
15
15
|
|
|
16
16
|
def __repr__(self) -> str:
|
telegrinder/bot/__init__.py
CHANGED
|
@@ -6,6 +6,7 @@ from telegrinder.bot.cute_types import (
|
|
|
6
6
|
ChatMemberUpdatedCute,
|
|
7
7
|
InlineQueryCute,
|
|
8
8
|
MessageCute,
|
|
9
|
+
PreCheckoutQueryCute,
|
|
9
10
|
UpdateCute,
|
|
10
11
|
)
|
|
11
12
|
from telegrinder.bot.dispatch import (
|
|
@@ -41,6 +42,8 @@ from telegrinder.bot.dispatch import (
|
|
|
41
42
|
MessageReturnManager,
|
|
42
43
|
MessageView,
|
|
43
44
|
PhotoReplyHandler,
|
|
45
|
+
PreCheckoutQueryManager,
|
|
46
|
+
PreCheckoutQueryView,
|
|
44
47
|
RawEventView,
|
|
45
48
|
ShortState,
|
|
46
49
|
StateViewHasher,
|
|
@@ -110,6 +113,9 @@ __all__ = (
|
|
|
110
113
|
"MessageView",
|
|
111
114
|
"PhotoReplyHandler",
|
|
112
115
|
"Polling",
|
|
116
|
+
"PreCheckoutQueryCute",
|
|
117
|
+
"PreCheckoutQueryManager",
|
|
118
|
+
"PreCheckoutQueryView",
|
|
113
119
|
"RawEventView",
|
|
114
120
|
"ShortState",
|
|
115
121
|
"StateViewHasher",
|
telegrinder/bot/bot.py
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import typing_extensions as typing
|
|
2
2
|
|
|
3
|
-
from telegrinder.api.api import API
|
|
3
|
+
from telegrinder.api.api import API, HTTPClient
|
|
4
|
+
from telegrinder.bot.dispatch import dispatch as dp
|
|
4
5
|
from telegrinder.bot.dispatch.abc import ABCDispatch
|
|
5
|
-
from telegrinder.bot.
|
|
6
|
+
from telegrinder.bot.polling import polling as pg
|
|
6
7
|
from telegrinder.bot.polling.abc import ABCPolling
|
|
7
|
-
from telegrinder.bot.polling.polling import Polling
|
|
8
8
|
from telegrinder.modules import logger
|
|
9
9
|
from telegrinder.tools.loop_wrapper import ABCLoopWrapper
|
|
10
|
-
from telegrinder.tools.loop_wrapper
|
|
10
|
+
from telegrinder.tools.loop_wrapper import loop_wrapper as lw
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
Dispatch = typing.TypeVar("Dispatch", bound=ABCDispatch, default=dp.Dispatch[HTTPClient])
|
|
13
|
+
Polling = typing.TypeVar("Polling", bound=ABCPolling, default=pg.Polling[HTTPClient])
|
|
14
|
+
LoopWrapper = typing.TypeVar("LoopWrapper", bound=ABCLoopWrapper, default=lw.LoopWrapper)
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class Telegrinder(typing.Generic[
|
|
17
|
+
class Telegrinder(typing.Generic[HTTPClient, Dispatch, Polling, LoopWrapper]):
|
|
18
18
|
def __init__(
|
|
19
19
|
self,
|
|
20
|
-
api: API,
|
|
20
|
+
api: API[HTTPClient],
|
|
21
21
|
*,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
loop_wrapper:
|
|
22
|
+
dispatch: Dispatch | None = None,
|
|
23
|
+
polling: Polling | None = None,
|
|
24
|
+
loop_wrapper: LoopWrapper | None = None,
|
|
25
25
|
) -> None:
|
|
26
26
|
self.api = api
|
|
27
|
-
self.dispatch = typing.cast(
|
|
28
|
-
self.polling = typing.cast(
|
|
29
|
-
self.loop_wrapper = typing.cast(
|
|
27
|
+
self.dispatch = typing.cast(Dispatch, dispatch or dp.Dispatch())
|
|
28
|
+
self.polling = typing.cast(Polling, polling or pg.Polling(api))
|
|
29
|
+
self.loop_wrapper = typing.cast(LoopWrapper, loop_wrapper or lw.LoopWrapper())
|
|
30
30
|
|
|
31
31
|
def __repr__(self) -> str:
|
|
32
32
|
return "<{}: api={!r}, dispatch={!r}, polling={!r}, loop_wrapper={!r}>".format(
|
|
@@ -38,7 +38,7 @@ class Telegrinder(typing.Generic[DispatchT, PollingT, LoopWrapperT]):
|
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
@property
|
|
41
|
-
def on(self) ->
|
|
41
|
+
def on(self) -> Dispatch:
|
|
42
42
|
return self.dispatch
|
|
43
43
|
|
|
44
44
|
async def reset_webhook(self) -> None:
|
|
@@ -51,23 +51,30 @@ class Telegrinder(typing.Generic[DispatchT, PollingT, LoopWrapperT]):
|
|
|
51
51
|
*,
|
|
52
52
|
offset: int = 0,
|
|
53
53
|
skip_updates: bool = False,
|
|
54
|
-
) ->
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
) -> typing.NoReturn:
|
|
55
|
+
async def polling() -> typing.NoReturn:
|
|
56
|
+
if skip_updates:
|
|
57
|
+
logger.debug("Dropping pending updates")
|
|
58
|
+
await self.reset_webhook()
|
|
59
|
+
await self.api.delete_webhook(drop_pending_updates=True)
|
|
60
|
+
self.polling.offset = offset
|
|
61
|
+
|
|
62
|
+
async for updates in self.polling.listen():
|
|
63
|
+
for update in updates:
|
|
64
|
+
logger.debug(
|
|
65
|
+
"Received update (update_id={}, update_type={!r})",
|
|
66
|
+
update.update_id,
|
|
67
|
+
update.update_type.name,
|
|
68
|
+
)
|
|
69
|
+
self.loop_wrapper.add_task(self.dispatch.feed(update, self.api))
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
update.update_type.name,
|
|
67
|
-
)
|
|
68
|
-
self.loop_wrapper.add_task(self.dispatch.feed(update, self.api))
|
|
71
|
+
if self.loop_wrapper.is_running:
|
|
72
|
+
await polling()
|
|
73
|
+
else:
|
|
74
|
+
self.loop_wrapper.add_task(polling())
|
|
75
|
+
self.loop_wrapper.run_event_loop()
|
|
69
76
|
|
|
70
|
-
def run_forever(self, *, offset: int = 0, skip_updates: bool = False) ->
|
|
77
|
+
def run_forever(self, *, offset: int = 0, skip_updates: bool = False) -> typing.NoReturn:
|
|
71
78
|
logger.debug("Running blocking polling (id={})", self.api.id)
|
|
72
79
|
self.loop_wrapper.add_task(self.run_polling(offset=offset, skip_updates=skip_updates))
|
|
73
80
|
self.loop_wrapper.run_event_loop()
|
|
@@ -4,6 +4,7 @@ from telegrinder.bot.cute_types.chat_join_request import ChatJoinRequestCute
|
|
|
4
4
|
from telegrinder.bot.cute_types.chat_member_updated import ChatMemberUpdatedCute
|
|
5
5
|
from telegrinder.bot.cute_types.inline_query import InlineQueryCute
|
|
6
6
|
from telegrinder.bot.cute_types.message import MessageCute
|
|
7
|
+
from telegrinder.bot.cute_types.pre_checkout_query import PreCheckoutQueryCute
|
|
7
8
|
from telegrinder.bot.cute_types.update import UpdateCute
|
|
8
9
|
|
|
9
10
|
__all__ = (
|
|
@@ -13,5 +14,6 @@ __all__ = (
|
|
|
13
14
|
"ChatMemberUpdatedCute",
|
|
14
15
|
"InlineQueryCute",
|
|
15
16
|
"MessageCute",
|
|
17
|
+
"PreCheckoutQueryCute",
|
|
16
18
|
"UpdateCute",
|
|
17
19
|
)
|