telegrinder 0.2.1__py3-none-any.whl → 0.2.2__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 +22 -11
- telegrinder/bot/__init__.py +16 -4
- telegrinder/bot/cute_types/chat_member_updated.py +1 -1
- telegrinder/bot/cute_types/message.py +18 -11
- telegrinder/bot/dispatch/__init__.py +18 -2
- telegrinder/bot/dispatch/abc.py +1 -1
- telegrinder/bot/dispatch/context.py +2 -2
- telegrinder/bot/dispatch/dispatch.py +1 -1
- telegrinder/bot/dispatch/handler/__init__.py +17 -1
- telegrinder/bot/dispatch/handler/audio_reply.py +44 -0
- telegrinder/bot/dispatch/handler/base.py +57 -0
- telegrinder/bot/dispatch/handler/document_reply.py +44 -0
- telegrinder/bot/dispatch/handler/func.py +3 -3
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -0
- telegrinder/bot/dispatch/handler/message_reply.py +12 -35
- telegrinder/bot/dispatch/handler/photo_reply.py +44 -0
- telegrinder/bot/dispatch/handler/sticker_reply.py +37 -0
- telegrinder/bot/dispatch/handler/video_reply.py +44 -0
- telegrinder/bot/dispatch/process.py +2 -2
- telegrinder/bot/dispatch/return_manager/abc.py +11 -8
- telegrinder/bot/dispatch/return_manager/callback_query.py +2 -2
- telegrinder/bot/dispatch/return_manager/inline_query.py +2 -2
- telegrinder/bot/dispatch/return_manager/message.py +3 -3
- telegrinder/bot/dispatch/view/__init__.py +2 -1
- telegrinder/bot/dispatch/view/abc.py +2 -181
- telegrinder/bot/dispatch/view/base.py +200 -0
- telegrinder/bot/dispatch/view/callback_query.py +3 -3
- telegrinder/bot/dispatch/view/chat_join_request.py +2 -2
- telegrinder/bot/dispatch/view/chat_member.py +2 -3
- telegrinder/bot/dispatch/view/inline_query.py +2 -2
- telegrinder/bot/dispatch/view/message.py +5 -4
- telegrinder/bot/dispatch/view/raw.py +4 -3
- telegrinder/bot/dispatch/waiter_machine/machine.py +6 -7
- telegrinder/bot/dispatch/waiter_machine/middleware.py +0 -6
- telegrinder/bot/dispatch/waiter_machine/short_state.py +1 -1
- telegrinder/bot/polling/polling.py +5 -2
- telegrinder/bot/rules/__init__.py +3 -3
- telegrinder/bot/rules/abc.py +6 -5
- telegrinder/bot/rules/adapter/__init__.py +1 -1
- telegrinder/bot/rules/integer.py +1 -1
- telegrinder/bot/rules/is_from.py +19 -0
- telegrinder/bot/rules/state.py +9 -6
- telegrinder/bot/scenario/checkbox.py +3 -3
- telegrinder/bot/scenario/choice.py +2 -2
- telegrinder/client/aiohttp.py +5 -7
- telegrinder/model.py +1 -8
- telegrinder/modules.py +16 -25
- telegrinder/msgspec_utils.py +5 -5
- telegrinder/node/base.py +2 -2
- telegrinder/node/composer.py +5 -9
- telegrinder/node/container.py +6 -1
- telegrinder/node/polymorphic.py +7 -7
- telegrinder/node/rule.py +6 -4
- telegrinder/node/scope.py +3 -3
- telegrinder/node/source.py +4 -2
- telegrinder/node/tools/generator.py +7 -6
- telegrinder/rules.py +2 -2
- telegrinder/tools/__init__.py +10 -10
- telegrinder/tools/keyboard.py +6 -1
- telegrinder/tools/loop_wrapper/loop_wrapper.py +4 -5
- telegrinder/tools/magic.py +17 -19
- telegrinder/tools/state_storage/__init__.py +3 -3
- telegrinder/tools/state_storage/abc.py +12 -10
- telegrinder/tools/state_storage/memory.py +6 -3
- telegrinder/types/__init__.py +1 -0
- telegrinder/types/methods.py +10 -2
- telegrinder/types/objects.py +47 -5
- {telegrinder-0.2.1.dist-info → telegrinder-0.2.2.dist-info}/METADATA +3 -4
- {telegrinder-0.2.1.dist-info → telegrinder-0.2.2.dist-info}/RECORD +71 -63
- {telegrinder-0.2.1.dist-info → telegrinder-0.2.2.dist-info}/LICENSE +0 -0
- {telegrinder-0.2.1.dist-info → telegrinder-0.2.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from functools import cached_property
|
|
4
|
+
|
|
5
|
+
from fntypes.option import Nothing, Some
|
|
6
|
+
|
|
7
|
+
from telegrinder.api.api import API
|
|
8
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
9
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
10
|
+
from telegrinder.bot.dispatch.handler.func import FuncHandler
|
|
11
|
+
from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
|
|
12
|
+
from telegrinder.bot.dispatch.process import process_inner
|
|
13
|
+
from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
|
|
14
|
+
from telegrinder.bot.dispatch.view.abc import ABCStateView, ABCView
|
|
15
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
16
|
+
from telegrinder.model import Model
|
|
17
|
+
from telegrinder.msgspec_utils import Option
|
|
18
|
+
from telegrinder.tools.error_handler.error_handler import ABCErrorHandler, ErrorHandler
|
|
19
|
+
from telegrinder.types.objects import Update
|
|
20
|
+
|
|
21
|
+
Event = typing.TypeVar("Event", bound=BaseCute)
|
|
22
|
+
ErrorHandlerT = typing.TypeVar("ErrorHandlerT", bound=ABCErrorHandler)
|
|
23
|
+
MiddlewareT = typing.TypeVar("MiddlewareT", bound=ABCMiddleware)
|
|
24
|
+
|
|
25
|
+
FuncType: typing.TypeAlias = typing.Callable[
|
|
26
|
+
typing.Concatenate[Event, ...],
|
|
27
|
+
typing.Coroutine[typing.Any, typing.Any, typing.Any],
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_event_model_class(view: "BaseView[Event]") -> Option[type[Event]]:
|
|
32
|
+
for base in view.__class__.__bases__ + (view.__class__,):
|
|
33
|
+
if "__orig_bases__" not in base.__dict__:
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
for orig_base in base.__dict__["__orig_bases__"]:
|
|
37
|
+
origin_base = typing.get_origin(orig_base) or orig_base
|
|
38
|
+
if not isinstance(origin_base, type) and not issubclass(origin_base, object):
|
|
39
|
+
continue
|
|
40
|
+
|
|
41
|
+
for generic_type in typing.get_args(orig_base):
|
|
42
|
+
orig_generic_type = typing.get_origin(generic_type) or generic_type
|
|
43
|
+
if isinstance(orig_generic_type, type) and issubclass(orig_generic_type, BaseCute):
|
|
44
|
+
return Some(generic_type)
|
|
45
|
+
|
|
46
|
+
return Nothing()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class BaseView(ABCView, typing.Generic[Event]):
|
|
50
|
+
auto_rules: list[ABCRule]
|
|
51
|
+
handlers: list[ABCHandler[Event]]
|
|
52
|
+
middlewares: list[ABCMiddleware[Event]]
|
|
53
|
+
return_manager: ABCReturnManager[Event] | None = None
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def get_raw_event(update: Update) -> Option[Model]:
|
|
57
|
+
return getattr(update, update.update_type.value)
|
|
58
|
+
|
|
59
|
+
@cached_property
|
|
60
|
+
def event_model_class(self) -> Option[type[Event]]:
|
|
61
|
+
return get_event_model_class(self)
|
|
62
|
+
|
|
63
|
+
@typing.overload
|
|
64
|
+
@classmethod
|
|
65
|
+
def to_handler(
|
|
66
|
+
cls,
|
|
67
|
+
*rules: ABCRule,
|
|
68
|
+
) -> typing.Callable[
|
|
69
|
+
[FuncType[Event]],
|
|
70
|
+
FuncHandler[Event, FuncType[Event], ErrorHandler[Event]],
|
|
71
|
+
]: ...
|
|
72
|
+
|
|
73
|
+
@typing.overload
|
|
74
|
+
@classmethod
|
|
75
|
+
def to_handler(
|
|
76
|
+
cls,
|
|
77
|
+
*rules: ABCRule,
|
|
78
|
+
error_handler: ErrorHandlerT,
|
|
79
|
+
is_blocking: bool = True,
|
|
80
|
+
) -> typing.Callable[[FuncType[Event]], FuncHandler[Event, FuncType[Event], ErrorHandlerT]]: ...
|
|
81
|
+
|
|
82
|
+
@typing.overload
|
|
83
|
+
@classmethod
|
|
84
|
+
def to_handler(
|
|
85
|
+
cls,
|
|
86
|
+
*rules: ABCRule,
|
|
87
|
+
error_handler: typing.Literal[None] = None,
|
|
88
|
+
is_blocking: bool = True,
|
|
89
|
+
) -> typing.Callable[
|
|
90
|
+
[FuncType[Event]],
|
|
91
|
+
FuncHandler[Event, FuncType[Event], ErrorHandler[Event]],
|
|
92
|
+
]: ...
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def to_handler( # type: ignore
|
|
96
|
+
cls,
|
|
97
|
+
*rules: ABCRule,
|
|
98
|
+
error_handler: ABCErrorHandler | None = None,
|
|
99
|
+
is_blocking: bool = True,
|
|
100
|
+
):
|
|
101
|
+
def wrapper(func: FuncType[Event]):
|
|
102
|
+
return FuncHandler(
|
|
103
|
+
func,
|
|
104
|
+
list(rules),
|
|
105
|
+
is_blocking=is_blocking,
|
|
106
|
+
dataclass=None,
|
|
107
|
+
error_handler=error_handler or ErrorHandler(),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return wrapper
|
|
111
|
+
|
|
112
|
+
@typing.overload
|
|
113
|
+
def __call__(
|
|
114
|
+
self,
|
|
115
|
+
*rules: ABCRule,
|
|
116
|
+
) -> typing.Callable[
|
|
117
|
+
[FuncType[Event]],
|
|
118
|
+
FuncHandler[Event, FuncType[Event], ErrorHandler[Event]],
|
|
119
|
+
]: ...
|
|
120
|
+
|
|
121
|
+
@typing.overload
|
|
122
|
+
def __call__( # type: ignore
|
|
123
|
+
self,
|
|
124
|
+
*rules: ABCRule,
|
|
125
|
+
error_handler: ErrorHandlerT,
|
|
126
|
+
is_blocking: bool = True,
|
|
127
|
+
) -> typing.Callable[[FuncType[Event]], FuncHandler[Event, FuncType[Event], ErrorHandlerT]]: ...
|
|
128
|
+
|
|
129
|
+
@typing.overload
|
|
130
|
+
def __call__(
|
|
131
|
+
self,
|
|
132
|
+
*rules: ABCRule,
|
|
133
|
+
error_handler: typing.Literal[None] = None,
|
|
134
|
+
is_blocking: bool = True,
|
|
135
|
+
) -> typing.Callable[
|
|
136
|
+
[FuncType[Event]],
|
|
137
|
+
FuncHandler[Event, FuncType[Event], ErrorHandler[Event]],
|
|
138
|
+
]: ...
|
|
139
|
+
|
|
140
|
+
def __call__( # type: ignore
|
|
141
|
+
self,
|
|
142
|
+
*rules: ABCRule,
|
|
143
|
+
error_handler: ABCErrorHandler | None = None,
|
|
144
|
+
is_blocking: bool = True,
|
|
145
|
+
):
|
|
146
|
+
def wrapper(func: FuncType[Event]):
|
|
147
|
+
func_handler = FuncHandler(
|
|
148
|
+
func,
|
|
149
|
+
[*self.auto_rules, *rules],
|
|
150
|
+
is_blocking=is_blocking,
|
|
151
|
+
dataclass=None,
|
|
152
|
+
error_handler=error_handler or ErrorHandler(),
|
|
153
|
+
)
|
|
154
|
+
self.handlers.append(func_handler)
|
|
155
|
+
return func_handler
|
|
156
|
+
|
|
157
|
+
return wrapper
|
|
158
|
+
|
|
159
|
+
def register_middleware(self, *args: typing.Any, **kwargs: typing.Any):
|
|
160
|
+
def wrapper(cls: type[MiddlewareT]) -> type[MiddlewareT]:
|
|
161
|
+
self.middlewares.append(cls(*args, **kwargs))
|
|
162
|
+
return cls
|
|
163
|
+
|
|
164
|
+
return wrapper
|
|
165
|
+
|
|
166
|
+
async def check(self, event: Update) -> bool:
|
|
167
|
+
match self.get_raw_event(event):
|
|
168
|
+
case Some(e) if issubclass(
|
|
169
|
+
self.event_model_class.expect(
|
|
170
|
+
"{!r} has no event model class in generic.".format(self.__class__.__qualname__),
|
|
171
|
+
),
|
|
172
|
+
e.__class__,
|
|
173
|
+
) and (self.handlers or self.middlewares):
|
|
174
|
+
return True
|
|
175
|
+
case _:
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
async def process(self, event: Update, api: API) -> bool:
|
|
179
|
+
return await process_inner(
|
|
180
|
+
api,
|
|
181
|
+
self.event_model_class.unwrap().from_update(
|
|
182
|
+
update=self.get_raw_event(event).unwrap(),
|
|
183
|
+
bound_api=api,
|
|
184
|
+
),
|
|
185
|
+
event,
|
|
186
|
+
self.middlewares,
|
|
187
|
+
self.handlers,
|
|
188
|
+
self.return_manager,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def load(self, external: typing.Self) -> None:
|
|
192
|
+
self.auto_rules.extend(external.auto_rules)
|
|
193
|
+
self.handlers.extend(external.handlers)
|
|
194
|
+
self.middlewares.extend(external.middlewares)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class BaseStateView(ABCStateView[Event], BaseView[Event], ABC, typing.Generic[Event]):
|
|
198
|
+
@abstractmethod
|
|
199
|
+
def get_state_key(self, event: Event) -> int | None:
|
|
200
|
+
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
2
|
-
from telegrinder.bot.dispatch.return_manager import CallbackQueryReturnManager
|
|
3
|
-
from telegrinder.bot.dispatch.view.
|
|
1
|
+
from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
|
|
2
|
+
from telegrinder.bot.dispatch.return_manager.callback_query import CallbackQueryReturnManager
|
|
3
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class CallbackQueryView(BaseStateView[CallbackQueryCute]):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from telegrinder.bot.cute_types import ChatJoinRequestCute
|
|
2
|
-
from telegrinder.bot.dispatch.view.
|
|
1
|
+
from telegrinder.bot.cute_types.chat_join_request import ChatJoinRequestCute
|
|
2
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class ChatJoinRequestView(BaseStateView[ChatJoinRequestCute]):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
-
from telegrinder.bot.cute_types import ChatMemberUpdatedCute
|
|
4
|
-
from telegrinder.bot.dispatch.view.
|
|
3
|
+
from telegrinder.bot.cute_types.chat_member_updated import ChatMemberUpdatedCute
|
|
4
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
5
5
|
from telegrinder.types.enums import UpdateType
|
|
6
6
|
from telegrinder.types.objects import Update
|
|
7
7
|
|
|
@@ -28,7 +28,6 @@ class ChatMemberView(BaseStateView[ChatMemberUpdatedCute]):
|
|
|
28
28
|
def get_state_key(self, event: ChatMemberUpdatedCute) -> int | None:
|
|
29
29
|
return event.chat_id
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
async def check(self, event: Update) -> bool:
|
|
33
32
|
return not (
|
|
34
33
|
self.update_type is not None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from telegrinder.bot.cute_types import InlineQueryCute
|
|
1
|
+
from telegrinder.bot.cute_types.inline_query import InlineQueryCute
|
|
2
2
|
from telegrinder.bot.dispatch.return_manager import InlineQueryReturnManager
|
|
3
|
-
from telegrinder.bot.dispatch.view.
|
|
3
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class InlineQueryView(BaseStateView[InlineQueryCute]):
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
-
from telegrinder.bot.cute_types import MessageCute
|
|
4
|
-
from telegrinder.bot.dispatch.return_manager import MessageReturnManager
|
|
5
|
-
from telegrinder.bot.dispatch.view.
|
|
6
|
-
from telegrinder.types import
|
|
3
|
+
from telegrinder.bot.cute_types.message import MessageCute
|
|
4
|
+
from telegrinder.bot.dispatch.return_manager.message import MessageReturnManager
|
|
5
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
6
|
+
from telegrinder.types.enums import UpdateType
|
|
7
|
+
from telegrinder.types.objects import Update
|
|
7
8
|
|
|
8
9
|
MessageUpdateType: typing.TypeAlias = typing.Literal[
|
|
9
10
|
UpdateType.MESSAGE,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
-
from telegrinder.api import API
|
|
4
|
-
from telegrinder.bot.cute_types import UpdateCute
|
|
3
|
+
from telegrinder.api.api import API
|
|
4
|
+
from telegrinder.bot.cute_types.update import UpdateCute
|
|
5
5
|
from telegrinder.bot.dispatch.handler.func import FuncHandler
|
|
6
6
|
from telegrinder.bot.dispatch.process import process_inner
|
|
7
|
-
from telegrinder.bot.dispatch.view.abc import ABCEventRawView
|
|
7
|
+
from telegrinder.bot.dispatch.view.abc import ABCEventRawView
|
|
8
|
+
from telegrinder.bot.dispatch.view.base import BaseView, ErrorHandlerT
|
|
8
9
|
from telegrinder.bot.rules.abc import ABCRule
|
|
9
10
|
from telegrinder.tools.error_handler.error_handler import ABCErrorHandler, ErrorHandler
|
|
10
11
|
from telegrinder.types.enums import UpdateType
|
|
@@ -2,9 +2,10 @@ import asyncio
|
|
|
2
2
|
import datetime
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
|
-
from telegrinder.api import API
|
|
5
|
+
from telegrinder.api.api import API
|
|
6
6
|
from telegrinder.bot.dispatch.context import Context
|
|
7
|
-
from telegrinder.bot.dispatch.view.abc import ABCStateView
|
|
7
|
+
from telegrinder.bot.dispatch.view.abc import ABCStateView
|
|
8
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
8
9
|
from telegrinder.bot.dispatch.waiter_machine.middleware import WaiterMiddleware
|
|
9
10
|
from telegrinder.bot.dispatch.waiter_machine.short_state import (
|
|
10
11
|
Behaviour,
|
|
@@ -68,15 +69,13 @@ class WaiterMachine:
|
|
|
68
69
|
)
|
|
69
70
|
|
|
70
71
|
async def drop_all(self) -> None:
|
|
71
|
-
"""Drops all waiters in storage"""
|
|
72
|
+
"""Drops all waiters in storage."""
|
|
73
|
+
|
|
72
74
|
for view_name in self.storage:
|
|
73
75
|
for ident, short_state in self.storage[view_name].items():
|
|
74
76
|
if short_state.context:
|
|
75
77
|
await self.drop(
|
|
76
|
-
view_name,
|
|
77
|
-
ident,
|
|
78
|
-
short_state.context.event,
|
|
79
|
-
short_state.context.context.raw_update
|
|
78
|
+
view_name, ident, short_state.context.event, short_state.context.context.raw_update
|
|
80
79
|
)
|
|
81
80
|
else:
|
|
82
81
|
short_state.cancel()
|
|
@@ -25,12 +25,6 @@ class WaiterMiddleware(ABCMiddleware[EventType]):
|
|
|
25
25
|
self.view = view
|
|
26
26
|
|
|
27
27
|
async def pre(self, event: EventType, ctx: Context) -> bool:
|
|
28
|
-
if not self.view or not hasattr(self.view, "get_state_key"):
|
|
29
|
-
raise RuntimeError(
|
|
30
|
-
"WaiterMiddleware cannot be used inside a view which doesn't "
|
|
31
|
-
"provide get_state_key (ABCStateView interface)."
|
|
32
|
-
)
|
|
33
|
-
|
|
34
28
|
view_name = self.view.__class__.__name__
|
|
35
29
|
if view_name not in self.machine.storage:
|
|
36
30
|
return True
|
|
@@ -3,7 +3,7 @@ import dataclasses
|
|
|
3
3
|
import datetime
|
|
4
4
|
import typing
|
|
5
5
|
|
|
6
|
-
from telegrinder.api import API
|
|
6
|
+
from telegrinder.api.api import API
|
|
7
7
|
from telegrinder.bot.cute_types import BaseCute
|
|
8
8
|
from telegrinder.bot.dispatch.context import Context
|
|
9
9
|
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
@@ -5,7 +5,7 @@ import aiohttp
|
|
|
5
5
|
import msgspec
|
|
6
6
|
from fntypes.result import Error, Ok
|
|
7
7
|
|
|
8
|
-
from telegrinder.api import API
|
|
8
|
+
from telegrinder.api.api import API
|
|
9
9
|
from telegrinder.api.error import InvalidTokenError
|
|
10
10
|
from telegrinder.bot.polling.abc import ABCPolling
|
|
11
11
|
from telegrinder.modules import logger
|
|
@@ -72,7 +72,10 @@ class Polling(ABCPolling):
|
|
|
72
72
|
async def get_updates(self) -> msgspec.Raw | None:
|
|
73
73
|
raw_updates = await self.api.request_raw(
|
|
74
74
|
"getUpdates",
|
|
75
|
-
{
|
|
75
|
+
{
|
|
76
|
+
"offset": self.offset,
|
|
77
|
+
"allowed_updates": self.allowed_updates,
|
|
78
|
+
},
|
|
76
79
|
)
|
|
77
80
|
match raw_updates:
|
|
78
81
|
case Ok(value):
|
|
@@ -83,7 +83,6 @@ __all__ = (
|
|
|
83
83
|
"InlineQueryMarkup",
|
|
84
84
|
"InlineQueryRule",
|
|
85
85
|
"InlineQueryText",
|
|
86
|
-
"IsInteger",
|
|
87
86
|
"IntegerInRange",
|
|
88
87
|
"InviteLinkByCreator",
|
|
89
88
|
"InviteLinkName",
|
|
@@ -96,6 +95,7 @@ __all__ = (
|
|
|
96
95
|
"IsForward",
|
|
97
96
|
"IsForwardType",
|
|
98
97
|
"IsGroup",
|
|
98
|
+
"IsInteger",
|
|
99
99
|
"IsLanguageCode",
|
|
100
100
|
"IsPremium",
|
|
101
101
|
"IsPrivate",
|
|
@@ -107,13 +107,13 @@ __all__ = (
|
|
|
107
107
|
"Markup",
|
|
108
108
|
"MessageEntities",
|
|
109
109
|
"MessageRule",
|
|
110
|
+
"NodeRule",
|
|
110
111
|
"NotRule",
|
|
111
112
|
"OrRule",
|
|
112
113
|
"Regex",
|
|
113
114
|
"RuleEnum",
|
|
114
115
|
"StartCommand",
|
|
115
|
-
"Text",
|
|
116
|
-
"NodeRule",
|
|
117
116
|
"State",
|
|
118
117
|
"StateMeta",
|
|
118
|
+
"Text",
|
|
119
119
|
)
|
telegrinder/bot/rules/abc.py
CHANGED
|
@@ -118,12 +118,13 @@ class ABCRule(ABC, typing.Generic[AdaptTo]):
|
|
|
118
118
|
ctx: Context,
|
|
119
119
|
node_col: "NodeCollection | None" = None,
|
|
120
120
|
) -> bool:
|
|
121
|
+
bound_check_rule = self.check
|
|
121
122
|
kw = {}
|
|
122
123
|
node_col_values = node_col.values if node_col is not None else {}
|
|
123
|
-
temp_ctx = get_default_args(
|
|
124
|
+
temp_ctx = get_default_args(bound_check_rule) | ctx
|
|
124
125
|
|
|
125
|
-
for i, (k, v) in enumerate(get_annotations(
|
|
126
|
-
if (isinstance(adapted_value, Event) and
|
|
126
|
+
for i, (k, v) in enumerate(get_annotations(bound_check_rule).items()):
|
|
127
|
+
if (isinstance(adapted_value, Event) and i == 0) or ( # First arg is Event
|
|
127
128
|
isinstance(v, type) and isinstance(adapted_value, v)
|
|
128
129
|
):
|
|
129
130
|
kw[k] = adapted_value if not isinstance(adapted_value, Event) else adapted_value.obj
|
|
@@ -140,14 +141,14 @@ class ABCRule(ABC, typing.Generic[AdaptTo]):
|
|
|
140
141
|
"because it cannot be resolved."
|
|
141
142
|
)
|
|
142
143
|
|
|
143
|
-
return await
|
|
144
|
+
return await bound_check_rule(**kw)
|
|
144
145
|
|
|
145
146
|
async def translate(self, translator: ABCTranslator) -> typing.Self:
|
|
146
147
|
return self
|
|
147
148
|
|
|
148
149
|
|
|
149
150
|
class AndRule(ABCRule):
|
|
150
|
-
def __init__(self, *rules: ABCRule
|
|
151
|
+
def __init__(self, *rules: ABCRule) -> None:
|
|
151
152
|
self.rules = rules
|
|
152
153
|
|
|
153
154
|
async def check(self, event: Update, ctx: Context) -> bool:
|
telegrinder/bot/rules/integer.py
CHANGED
telegrinder/bot/rules/is_from.py
CHANGED
|
@@ -107,21 +107,40 @@ class IsSticker(MessageRule):
|
|
|
107
107
|
return bool(message.sticker)
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
class IsVideoNote(MessageRule):
|
|
111
|
+
async def check(self, message: Message) -> bool:
|
|
112
|
+
return bool(message.video_note)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class IsDocument(MessageRule):
|
|
116
|
+
async def check(self, message: Message) -> bool:
|
|
117
|
+
return bool(message.document)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class IsPhoto(MessageRule):
|
|
121
|
+
async def check(self, message: Message) -> bool:
|
|
122
|
+
return bool(message.photo)
|
|
123
|
+
|
|
124
|
+
|
|
110
125
|
__all__ = (
|
|
111
126
|
"IsBot",
|
|
112
127
|
"IsChat",
|
|
113
128
|
"IsChatId",
|
|
114
129
|
"IsDice",
|
|
115
130
|
"IsDiceEmoji",
|
|
131
|
+
"IsDocument",
|
|
116
132
|
"IsForum",
|
|
117
133
|
"IsForward",
|
|
118
134
|
"IsForwardType",
|
|
119
135
|
"IsGroup",
|
|
120
136
|
"IsLanguageCode",
|
|
137
|
+
"IsPhoto",
|
|
121
138
|
"IsPremium",
|
|
122
139
|
"IsPrivate",
|
|
123
140
|
"IsReply",
|
|
141
|
+
"IsSticker",
|
|
124
142
|
"IsSuperGroup",
|
|
125
143
|
"IsUser",
|
|
126
144
|
"IsUserId",
|
|
145
|
+
"IsVideoNote",
|
|
127
146
|
)
|
telegrinder/bot/rules/state.py
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import dataclasses
|
|
1
2
|
import enum
|
|
2
3
|
import typing
|
|
3
4
|
|
|
4
5
|
from telegrinder.bot.dispatch.context import Context
|
|
5
6
|
from telegrinder.bot.rules.abc import ABCRule
|
|
6
|
-
from telegrinder.node import Source
|
|
7
|
+
from telegrinder.node.source import Source
|
|
7
8
|
|
|
8
9
|
if typing.TYPE_CHECKING:
|
|
9
|
-
from telegrinder.tools.state_storage import ABCStateStorage
|
|
10
|
+
from telegrinder.tools.state_storage.abc import ABCStateStorage
|
|
11
|
+
|
|
12
|
+
Payload = typing.TypeVar("Payload")
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
class StateMeta(enum.Enum):
|
|
@@ -14,10 +17,10 @@ class StateMeta(enum.Enum):
|
|
|
14
17
|
ANY = enum.auto()
|
|
15
18
|
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
@dataclasses.dataclass(frozen=True, slots=True, repr=False)
|
|
21
|
+
class State(ABCRule, typing.Generic[Payload]):
|
|
22
|
+
storage: "ABCStateStorage[Payload]"
|
|
23
|
+
key: str | StateMeta | enum.Enum
|
|
21
24
|
|
|
22
25
|
async def check(self, source: Source, ctx: Context) -> bool:
|
|
23
26
|
state = await self.storage.get(source.from_user.id)
|
|
@@ -2,16 +2,16 @@ import dataclasses
|
|
|
2
2
|
import secrets
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
|
-
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
5
|
+
from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
|
|
6
6
|
from telegrinder.bot.dispatch.waiter_machine import WaiterMachine
|
|
7
7
|
from telegrinder.bot.scenario.abc import ABCScenario
|
|
8
|
-
from telegrinder.tools import InlineButton, InlineKeyboard
|
|
8
|
+
from telegrinder.tools.keyboard import InlineButton, InlineKeyboard
|
|
9
9
|
from telegrinder.tools.parse_mode import ParseMode
|
|
10
10
|
from telegrinder.types.objects import InlineKeyboardMarkup
|
|
11
11
|
|
|
12
12
|
if typing.TYPE_CHECKING:
|
|
13
13
|
from telegrinder.api import API
|
|
14
|
-
from telegrinder.bot.dispatch.view.
|
|
14
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
@dataclasses.dataclass(slots=True)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
-
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
3
|
+
from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
|
|
4
4
|
from telegrinder.bot.scenario.checkbox import Checkbox
|
|
5
5
|
|
|
6
6
|
if typing.TYPE_CHECKING:
|
|
7
7
|
from telegrinder.api import API
|
|
8
|
-
from telegrinder.bot.dispatch.view.
|
|
8
|
+
from telegrinder.bot.dispatch.view.base import BaseStateView
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Choice(Checkbox):
|
telegrinder/client/aiohttp.py
CHANGED
|
@@ -5,8 +5,8 @@ import aiohttp
|
|
|
5
5
|
import certifi
|
|
6
6
|
from aiohttp import ClientSession, TCPConnector
|
|
7
7
|
|
|
8
|
+
import telegrinder.msgspec_json as json
|
|
8
9
|
from telegrinder.client.abc import ABCClient
|
|
9
|
-
from telegrinder.modules import JSONModule, json
|
|
10
10
|
|
|
11
11
|
if typing.TYPE_CHECKING:
|
|
12
12
|
from aiohttp import ClientResponse
|
|
@@ -16,12 +16,10 @@ class AiohttpClient(ABCClient):
|
|
|
16
16
|
def __init__(
|
|
17
17
|
self,
|
|
18
18
|
session: ClientSession | None = None,
|
|
19
|
-
json_processing_module: JSONModule | None = None,
|
|
20
19
|
timeout: aiohttp.ClientTimeout | None = None,
|
|
21
20
|
**session_params: typing.Any,
|
|
22
21
|
) -> None:
|
|
23
22
|
self.session = session
|
|
24
|
-
self.json_processing_module = json_processing_module or json
|
|
25
23
|
self.session_params = session_params
|
|
26
24
|
self.timeout = timeout or aiohttp.ClientTimeout(total=0)
|
|
27
25
|
|
|
@@ -43,7 +41,7 @@ class AiohttpClient(ABCClient):
|
|
|
43
41
|
if not self.session:
|
|
44
42
|
self.session = ClientSession(
|
|
45
43
|
connector=TCPConnector(ssl=ssl.create_default_context(cafile=certifi.where())),
|
|
46
|
-
json_serialize=
|
|
44
|
+
json_serialize=json.dumps,
|
|
47
45
|
**self.session_params,
|
|
48
46
|
)
|
|
49
47
|
async with self.session.request(
|
|
@@ -65,8 +63,8 @@ class AiohttpClient(ABCClient):
|
|
|
65
63
|
) -> dict[str, typing.Any]:
|
|
66
64
|
response = await self.request_raw(url, method, data, **kwargs)
|
|
67
65
|
return await response.json(
|
|
68
|
-
encoding="
|
|
69
|
-
loads=
|
|
66
|
+
encoding="UTF-8",
|
|
67
|
+
loads=json.loads,
|
|
70
68
|
content_type=None,
|
|
71
69
|
)
|
|
72
70
|
|
|
@@ -78,7 +76,7 @@ class AiohttpClient(ABCClient):
|
|
|
78
76
|
**kwargs: typing.Any,
|
|
79
77
|
) -> str:
|
|
80
78
|
response = await self.request_raw(url, method, data, **kwargs) # type: ignore
|
|
81
|
-
return await response.text(encoding="
|
|
79
|
+
return await response.text(encoding="UTF-8")
|
|
82
80
|
|
|
83
81
|
async def request_bytes(
|
|
84
82
|
self,
|
telegrinder/model.py
CHANGED
|
@@ -16,17 +16,10 @@ if typing.TYPE_CHECKING:
|
|
|
16
16
|
|
|
17
17
|
T = typing.TypeVar("T")
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
def rename_field(name: str) -> str:
|
|
21
|
-
if name.endswith("_") and name.removesuffix("_") in keyword.kwlist:
|
|
22
|
-
return name.removesuffix("_")
|
|
23
|
-
return name if not keyword.iskeyword(name) else name + "_"
|
|
24
|
-
|
|
25
|
-
|
|
26
19
|
MODEL_CONFIG: typing.Final[dict[str, typing.Any]] = {
|
|
27
20
|
"omit_defaults": True,
|
|
28
21
|
"dict": True,
|
|
29
|
-
"rename":
|
|
22
|
+
"rename": {kw + "_": kw for kw in keyword.kwlist},
|
|
30
23
|
}
|
|
31
24
|
|
|
32
25
|
|