telegrinder 0.3.3.post1__py3-none-any.whl → 0.3.4.post1__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 +144 -144
- telegrinder/api/__init__.py +8 -8
- telegrinder/api/api.py +93 -93
- telegrinder/api/error.py +16 -16
- telegrinder/api/response.py +20 -20
- telegrinder/api/token.py +36 -36
- telegrinder/bot/__init__.py +66 -66
- telegrinder/bot/bot.py +76 -76
- telegrinder/bot/cute_types/__init__.py +17 -17
- telegrinder/bot/cute_types/base.py +258 -258
- telegrinder/bot/cute_types/callback_query.py +385 -385
- telegrinder/bot/cute_types/chat_join_request.py +61 -61
- telegrinder/bot/cute_types/chat_member_updated.py +160 -160
- telegrinder/bot/cute_types/inline_query.py +43 -43
- telegrinder/bot/cute_types/message.py +2637 -2637
- telegrinder/bot/cute_types/update.py +104 -109
- telegrinder/bot/cute_types/utils.py +95 -95
- telegrinder/bot/dispatch/__init__.py +55 -55
- telegrinder/bot/dispatch/abc.py +77 -77
- telegrinder/bot/dispatch/context.py +98 -98
- telegrinder/bot/dispatch/dispatch.py +202 -202
- telegrinder/bot/dispatch/handler/__init__.py +13 -13
- telegrinder/bot/dispatch/handler/abc.py +24 -24
- telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
- telegrinder/bot/dispatch/handler/base.py +57 -57
- telegrinder/bot/dispatch/handler/document_reply.py +44 -44
- telegrinder/bot/dispatch/handler/func.py +135 -135
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -43
- telegrinder/bot/dispatch/handler/message_reply.py +36 -36
- telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
- telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
- telegrinder/bot/dispatch/handler/video_reply.py +44 -44
- telegrinder/bot/dispatch/middleware/__init__.py +3 -3
- telegrinder/bot/dispatch/middleware/abc.py +22 -16
- telegrinder/bot/dispatch/process.py +157 -132
- telegrinder/bot/dispatch/return_manager/__init__.py +13 -13
- telegrinder/bot/dispatch/return_manager/abc.py +108 -108
- telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
- telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
- telegrinder/bot/dispatch/return_manager/message.py +36 -36
- telegrinder/bot/dispatch/view/__init__.py +13 -13
- telegrinder/bot/dispatch/view/abc.py +41 -41
- telegrinder/bot/dispatch/view/base.py +200 -200
- telegrinder/bot/dispatch/view/box.py +129 -129
- telegrinder/bot/dispatch/view/callback_query.py +17 -17
- telegrinder/bot/dispatch/view/chat_join_request.py +16 -16
- telegrinder/bot/dispatch/view/chat_member.py +39 -39
- telegrinder/bot/dispatch/view/inline_query.py +17 -17
- telegrinder/bot/dispatch/view/message.py +44 -44
- telegrinder/bot/dispatch/view/raw.py +114 -114
- telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
- telegrinder/bot/dispatch/waiter_machine/actions.py +13 -13
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
- telegrinder/bot/dispatch/waiter_machine/machine.py +172 -167
- telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
- telegrinder/bot/dispatch/waiter_machine/short_state.py +68 -68
- telegrinder/bot/polling/__init__.py +4 -4
- telegrinder/bot/polling/abc.py +25 -25
- telegrinder/bot/polling/polling.py +131 -131
- telegrinder/bot/rules/__init__.py +62 -62
- telegrinder/bot/rules/abc.py +213 -213
- telegrinder/bot/rules/adapter/__init__.py +12 -9
- telegrinder/bot/rules/adapter/abc.py +31 -29
- telegrinder/bot/rules/adapter/errors.py +5 -5
- telegrinder/bot/rules/adapter/event.py +65 -67
- telegrinder/bot/rules/adapter/node.py +48 -48
- telegrinder/bot/rules/adapter/raw_event.py +27 -0
- telegrinder/bot/rules/adapter/raw_update.py +30 -30
- telegrinder/bot/rules/callback_data.py +170 -170
- telegrinder/bot/rules/chat_join.py +46 -46
- telegrinder/bot/rules/command.py +126 -126
- telegrinder/bot/rules/enum_text.py +36 -36
- telegrinder/bot/rules/func.py +26 -26
- telegrinder/bot/rules/fuzzy.py +24 -24
- telegrinder/bot/rules/inline.py +60 -60
- telegrinder/bot/rules/integer.py +20 -20
- telegrinder/bot/rules/is_from.py +127 -127
- telegrinder/bot/rules/markup.py +43 -43
- telegrinder/bot/rules/mention.py +14 -14
- telegrinder/bot/rules/message.py +17 -17
- telegrinder/bot/rules/message_entities.py +35 -35
- telegrinder/bot/rules/node.py +27 -27
- telegrinder/bot/rules/regex.py +37 -37
- telegrinder/bot/rules/rule_enum.py +72 -72
- telegrinder/bot/rules/start.py +42 -42
- telegrinder/bot/rules/state.py +37 -37
- telegrinder/bot/rules/text.py +33 -33
- telegrinder/bot/rules/update.py +15 -15
- telegrinder/bot/scenario/__init__.py +5 -5
- telegrinder/bot/scenario/abc.py +19 -19
- telegrinder/bot/scenario/checkbox.py +176 -167
- telegrinder/bot/scenario/choice.py +51 -46
- telegrinder/client/__init__.py +4 -4
- telegrinder/client/abc.py +75 -75
- telegrinder/client/aiohttp.py +130 -130
- telegrinder/model.py +320 -295
- telegrinder/modules.py +237 -237
- telegrinder/msgspec_json.py +14 -14
- telegrinder/msgspec_utils.py +410 -410
- telegrinder/node/__init__.py +0 -0
- telegrinder/node/attachment.py +87 -87
- telegrinder/node/base.py +166 -166
- telegrinder/node/callback_query.py +53 -53
- telegrinder/node/command.py +33 -33
- telegrinder/node/composer.py +198 -198
- telegrinder/node/container.py +27 -27
- telegrinder/node/event.py +65 -65
- telegrinder/node/me.py +16 -16
- telegrinder/node/message.py +14 -14
- telegrinder/node/polymorphic.py +48 -48
- telegrinder/node/rule.py +76 -76
- telegrinder/node/scope.py +38 -38
- telegrinder/node/source.py +71 -71
- telegrinder/node/text.py +41 -41
- telegrinder/node/tools/__init__.py +3 -3
- telegrinder/node/tools/generator.py +40 -40
- telegrinder/node/update.py +15 -15
- telegrinder/rules.py +0 -0
- telegrinder/tools/__init__.py +74 -74
- telegrinder/tools/buttons.py +79 -79
- telegrinder/tools/error_handler/__init__.py +7 -7
- telegrinder/tools/error_handler/abc.py +33 -33
- telegrinder/tools/error_handler/error.py +9 -9
- telegrinder/tools/error_handler/error_handler.py +193 -193
- telegrinder/tools/formatting/__init__.py +46 -46
- telegrinder/tools/formatting/html.py +283 -283
- telegrinder/tools/formatting/links.py +33 -33
- telegrinder/tools/formatting/spec_html_formats.py +111 -111
- telegrinder/tools/functional.py +12 -12
- telegrinder/tools/global_context/__init__.py +7 -7
- telegrinder/tools/global_context/abc.py +63 -63
- telegrinder/tools/global_context/global_context.py +412 -412
- telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
- telegrinder/tools/i18n/__init__.py +7 -7
- telegrinder/tools/i18n/abc.py +30 -30
- telegrinder/tools/i18n/middleware/__init__.py +3 -3
- telegrinder/tools/i18n/middleware/abc.py +25 -25
- telegrinder/tools/i18n/simple.py +43 -43
- telegrinder/tools/kb_set/__init__.py +4 -4
- telegrinder/tools/kb_set/base.py +15 -15
- telegrinder/tools/kb_set/yaml.py +63 -63
- telegrinder/tools/keyboard.py +132 -132
- telegrinder/tools/limited_dict.py +37 -37
- telegrinder/tools/loop_wrapper/__init__.py +4 -4
- telegrinder/tools/loop_wrapper/abc.py +15 -15
- telegrinder/tools/loop_wrapper/loop_wrapper.py +224 -224
- telegrinder/tools/magic.py +157 -157
- telegrinder/tools/parse_mode.py +6 -6
- telegrinder/tools/state_storage/__init__.py +4 -4
- telegrinder/tools/state_storage/abc.py +35 -35
- telegrinder/tools/state_storage/memory.py +25 -25
- telegrinder/types/__init__.py +260 -260
- telegrinder/types/enums.py +701 -701
- telegrinder/types/methods.py +4633 -4633
- telegrinder/types/objects.py +6950 -8561
- telegrinder/verification_utils.py +32 -32
- {telegrinder-0.3.3.post1.dist-info → telegrinder-0.3.4.post1.dist-info}/LICENSE +22 -22
- {telegrinder-0.3.3.post1.dist-info → telegrinder-0.3.4.post1.dist-info}/METADATA +1 -1
- telegrinder-0.3.4.post1.dist-info/RECORD +165 -0
- telegrinder-0.3.3.post1.dist-info/RECORD +0 -164
- {telegrinder-0.3.3.post1.dist-info → telegrinder-0.3.4.post1.dist-info}/WHEEL +0 -0
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import abc
|
|
2
|
-
import typing
|
|
3
|
-
|
|
4
|
-
from fntypes.result import Result
|
|
5
|
-
|
|
6
|
-
from telegrinder.api.api import API
|
|
7
|
-
from telegrinder.api.error import APIError
|
|
8
|
-
from telegrinder.bot.cute_types.message import MessageCute
|
|
9
|
-
from telegrinder.bot.dispatch.context import Context
|
|
10
|
-
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
11
|
-
from telegrinder.bot.dispatch.process import check_rule
|
|
12
|
-
from telegrinder.bot.rules.abc import ABCRule
|
|
13
|
-
from telegrinder.modules import logger
|
|
14
|
-
from telegrinder.types.objects import Update
|
|
15
|
-
|
|
16
|
-
APIMethod: typing.TypeAlias = typing.Callable[
|
|
17
|
-
typing.Concatenate[MessageCute, ...], typing.Awaitable[Result[typing.Any, APIError]]
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class BaseReplyHandler(ABCHandler[MessageCute], abc.ABC):
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
*rules: ABCRule,
|
|
25
|
-
is_blocking: bool = True,
|
|
26
|
-
as_reply: bool = False,
|
|
27
|
-
preset_context: Context | None = None,
|
|
28
|
-
**default_params: typing.Any,
|
|
29
|
-
) -> None:
|
|
30
|
-
self.rules = list(rules)
|
|
31
|
-
self.as_reply = as_reply
|
|
32
|
-
self.is_blocking = is_blocking
|
|
33
|
-
self.default_params = default_params
|
|
34
|
-
self.preset_context = preset_context or Context()
|
|
35
|
-
|
|
36
|
-
def __repr__(self) -> str:
|
|
37
|
-
return f"<{self.__class__.__qualname__}>"
|
|
38
|
-
|
|
39
|
-
async def check(self, api: API, event: Update, ctx: Context | None = None) -> bool:
|
|
40
|
-
ctx = Context(raw_update=event) if ctx is None else ctx
|
|
41
|
-
temp_ctx = ctx.copy()
|
|
42
|
-
temp_ctx |= self.preset_context
|
|
43
|
-
|
|
44
|
-
for rule in self.rules:
|
|
45
|
-
if not await check_rule(api, rule, event, ctx):
|
|
46
|
-
logger.debug("Rule {!r} failed!", rule)
|
|
47
|
-
return False
|
|
48
|
-
|
|
49
|
-
ctx |= temp_ctx
|
|
50
|
-
return True
|
|
51
|
-
|
|
52
|
-
@abc.abstractmethod
|
|
53
|
-
async def run(self, api: API, event: MessageCute, ctx: Context) -> typing.Any:
|
|
54
|
-
pass
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
__all__ = ("BaseReplyHandler",)
|
|
1
|
+
import abc
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from fntypes.result import Result
|
|
5
|
+
|
|
6
|
+
from telegrinder.api.api import API
|
|
7
|
+
from telegrinder.api.error import APIError
|
|
8
|
+
from telegrinder.bot.cute_types.message import MessageCute
|
|
9
|
+
from telegrinder.bot.dispatch.context import Context
|
|
10
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
11
|
+
from telegrinder.bot.dispatch.process import check_rule
|
|
12
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
13
|
+
from telegrinder.modules import logger
|
|
14
|
+
from telegrinder.types.objects import Update
|
|
15
|
+
|
|
16
|
+
APIMethod: typing.TypeAlias = typing.Callable[
|
|
17
|
+
typing.Concatenate[MessageCute, ...], typing.Awaitable[Result[typing.Any, APIError]]
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BaseReplyHandler(ABCHandler[MessageCute], abc.ABC):
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
*rules: ABCRule,
|
|
25
|
+
is_blocking: bool = True,
|
|
26
|
+
as_reply: bool = False,
|
|
27
|
+
preset_context: Context | None = None,
|
|
28
|
+
**default_params: typing.Any,
|
|
29
|
+
) -> None:
|
|
30
|
+
self.rules = list(rules)
|
|
31
|
+
self.as_reply = as_reply
|
|
32
|
+
self.is_blocking = is_blocking
|
|
33
|
+
self.default_params = default_params
|
|
34
|
+
self.preset_context = preset_context or Context()
|
|
35
|
+
|
|
36
|
+
def __repr__(self) -> str:
|
|
37
|
+
return f"<{self.__class__.__qualname__}>"
|
|
38
|
+
|
|
39
|
+
async def check(self, api: API, event: Update, ctx: Context | None = None) -> bool:
|
|
40
|
+
ctx = Context(raw_update=event) if ctx is None else ctx
|
|
41
|
+
temp_ctx = ctx.copy()
|
|
42
|
+
temp_ctx |= self.preset_context
|
|
43
|
+
|
|
44
|
+
for rule in self.rules:
|
|
45
|
+
if not await check_rule(api, rule, event, ctx):
|
|
46
|
+
logger.debug("Rule {!r} failed!", rule)
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
ctx |= temp_ctx
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
@abc.abstractmethod
|
|
53
|
+
async def run(self, api: API, event: MessageCute, ctx: Context) -> typing.Any:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = ("BaseReplyHandler",)
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
|
|
3
|
-
from telegrinder.api.api import API
|
|
4
|
-
from telegrinder.bot.cute_types.message import MessageCute
|
|
5
|
-
from telegrinder.bot.dispatch.context import Context
|
|
6
|
-
from telegrinder.bot.dispatch.handler.base import BaseReplyHandler
|
|
7
|
-
from telegrinder.bot.rules.abc import ABCRule
|
|
8
|
-
from telegrinder.types.objects import InputFile
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class DocumentReplyHandler(BaseReplyHandler):
|
|
12
|
-
def __init__(
|
|
13
|
-
self,
|
|
14
|
-
document: InputFile | str,
|
|
15
|
-
*rules: ABCRule,
|
|
16
|
-
caption: str | None = None,
|
|
17
|
-
parse_mode: str | None = None,
|
|
18
|
-
is_blocking: bool = True,
|
|
19
|
-
as_reply: bool = False,
|
|
20
|
-
preset_context: Context | None = None,
|
|
21
|
-
**default_params: typing.Any,
|
|
22
|
-
) -> None:
|
|
23
|
-
self.document = document
|
|
24
|
-
self.parse_mode = parse_mode
|
|
25
|
-
self.caption = caption
|
|
26
|
-
super().__init__(
|
|
27
|
-
*rules,
|
|
28
|
-
is_blocking=is_blocking,
|
|
29
|
-
as_reply=as_reply,
|
|
30
|
-
preset_context=preset_context,
|
|
31
|
-
**default_params,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
|
|
35
|
-
method = event.answer_document if not self.as_reply else event.reply_document
|
|
36
|
-
await method(
|
|
37
|
-
document=self.document,
|
|
38
|
-
parse_mode=self.parse_mode,
|
|
39
|
-
caption=self.caption,
|
|
40
|
-
**self.default_params,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
__all__ = ("DocumentReplyHandler",)
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from telegrinder.api.api import API
|
|
4
|
+
from telegrinder.bot.cute_types.message import MessageCute
|
|
5
|
+
from telegrinder.bot.dispatch.context import Context
|
|
6
|
+
from telegrinder.bot.dispatch.handler.base import BaseReplyHandler
|
|
7
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
8
|
+
from telegrinder.types.objects import InputFile
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DocumentReplyHandler(BaseReplyHandler):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
document: InputFile | str,
|
|
15
|
+
*rules: ABCRule,
|
|
16
|
+
caption: str | None = None,
|
|
17
|
+
parse_mode: str | None = None,
|
|
18
|
+
is_blocking: bool = True,
|
|
19
|
+
as_reply: bool = False,
|
|
20
|
+
preset_context: Context | None = None,
|
|
21
|
+
**default_params: typing.Any,
|
|
22
|
+
) -> None:
|
|
23
|
+
self.document = document
|
|
24
|
+
self.parse_mode = parse_mode
|
|
25
|
+
self.caption = caption
|
|
26
|
+
super().__init__(
|
|
27
|
+
*rules,
|
|
28
|
+
is_blocking=is_blocking,
|
|
29
|
+
as_reply=as_reply,
|
|
30
|
+
preset_context=preset_context,
|
|
31
|
+
**default_params,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
|
|
35
|
+
method = event.answer_document if not self.as_reply else event.reply_document
|
|
36
|
+
await method(
|
|
37
|
+
document=self.document,
|
|
38
|
+
parse_mode=self.parse_mode,
|
|
39
|
+
caption=self.caption,
|
|
40
|
+
**self.default_params,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
__all__ = ("DocumentReplyHandler",)
|
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
from functools import cached_property
|
|
3
|
-
|
|
4
|
-
import typing_extensions as typing
|
|
5
|
-
|
|
6
|
-
from telegrinder.api.api import API
|
|
7
|
-
from telegrinder.bot.cute_types import BaseCute, UpdateCute
|
|
8
|
-
from telegrinder.bot.dispatch.context import Context
|
|
9
|
-
from telegrinder.bot.dispatch.process import check_rule
|
|
10
|
-
from telegrinder.model import Model
|
|
11
|
-
from telegrinder.modules import logger
|
|
12
|
-
from telegrinder.node.base import Node, get_nodes
|
|
13
|
-
from telegrinder.node.composer import NodeCollection, compose_nodes
|
|
14
|
-
from telegrinder.node.event import EVENT_NODE_KEY
|
|
15
|
-
from telegrinder.tools.error_handler import ABCErrorHandler, ErrorHandler
|
|
16
|
-
from telegrinder.types.enums import UpdateType
|
|
17
|
-
from telegrinder.types.objects import Update
|
|
18
|
-
|
|
19
|
-
from .abc import ABCHandler
|
|
20
|
-
|
|
21
|
-
if typing.TYPE_CHECKING:
|
|
22
|
-
from telegrinder.bot.rules.abc import ABCRule
|
|
23
|
-
from telegrinder.node.composer import NodeCollection
|
|
24
|
-
|
|
25
|
-
Rest = typing.ParamSpec("Rest")
|
|
26
|
-
Result = typing.TypeVar("Result")
|
|
27
|
-
Function = typing.TypeVar("Function", bound="Func[..., typing.Any]")
|
|
28
|
-
Event = typing.TypeVar("Event", bound=Model)
|
|
29
|
-
ErrorHandlerT = typing.TypeVar("ErrorHandlerT", bound=ABCErrorHandler, default=ErrorHandler)
|
|
30
|
-
|
|
31
|
-
Func: typing.TypeAlias = typing.Callable[Rest, typing.Coroutine[typing.Any, typing.Any, Result]]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@dataclasses.dataclass(repr=False, slots=True)
|
|
35
|
-
class FuncHandler(ABCHandler[Event], typing.Generic[Event, Function, ErrorHandlerT]):
|
|
36
|
-
function: Function
|
|
37
|
-
rules: list["ABCRule"]
|
|
38
|
-
is_blocking: bool = dataclasses.field(default=True, kw_only=True)
|
|
39
|
-
dataclass: type[typing.Any] | None = dataclasses.field(default=dict, kw_only=True)
|
|
40
|
-
error_handler: ErrorHandlerT = dataclasses.field(
|
|
41
|
-
default_factory=lambda: typing.cast(ErrorHandlerT, ErrorHandler()),
|
|
42
|
-
kw_only=True,
|
|
43
|
-
)
|
|
44
|
-
preset_context: Context = dataclasses.field(default_factory=lambda: Context(), kw_only=True)
|
|
45
|
-
update_type: UpdateType | None = dataclasses.field(default=None, kw_only=True)
|
|
46
|
-
|
|
47
|
-
def __post_init__(self) -> None:
|
|
48
|
-
self.dataclass = typing.get_origin(self.dataclass) or self.dataclass
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def __call__(self) -> Function:
|
|
52
|
-
return self.function
|
|
53
|
-
|
|
54
|
-
def __repr__(self) -> str:
|
|
55
|
-
return "<{}: {}={!r} with rules={!r}, dataclass={!r}, error_handler={!r}>".format(
|
|
56
|
-
self.__class__.__name__,
|
|
57
|
-
"blocking function" if self.is_blocking else "function",
|
|
58
|
-
self.function.__qualname__,
|
|
59
|
-
self.rules,
|
|
60
|
-
self.dataclass,
|
|
61
|
-
self.error_handler,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
@cached_property
|
|
65
|
-
def required_nodes(self) -> dict[str, type[Node]]:
|
|
66
|
-
return get_nodes(self.function)
|
|
67
|
-
|
|
68
|
-
async def check(self, api: API, event: Update, ctx: Context | None = None) -> bool:
|
|
69
|
-
if self.update_type is not None and self.update_type != event.update_type:
|
|
70
|
-
return False
|
|
71
|
-
|
|
72
|
-
logger.debug("Checking handler {!r}...", self)
|
|
73
|
-
ctx = Context(raw_update=event) if ctx is None else ctx
|
|
74
|
-
temp_ctx = ctx.copy()
|
|
75
|
-
temp_ctx |= self.preset_context
|
|
76
|
-
update = event
|
|
77
|
-
|
|
78
|
-
for rule in self.rules:
|
|
79
|
-
if not await check_rule(api, rule, update, temp_ctx):
|
|
80
|
-
logger.debug("Rule {!r} failed!", rule)
|
|
81
|
-
return False
|
|
82
|
-
|
|
83
|
-
nodes = self.required_nodes
|
|
84
|
-
node_col = None
|
|
85
|
-
if nodes:
|
|
86
|
-
result = await compose_nodes(nodes, ctx, data={Update: event, API: api})
|
|
87
|
-
if not result:
|
|
88
|
-
logger.debug(f"Cannot compose nodes for handler. Error: {result.error!r}")
|
|
89
|
-
return False
|
|
90
|
-
|
|
91
|
-
node_col = result.value
|
|
92
|
-
temp_ctx |= node_col.values
|
|
93
|
-
|
|
94
|
-
if EVENT_NODE_KEY in ctx:
|
|
95
|
-
for name, node in nodes.items():
|
|
96
|
-
if node is ctx[EVENT_NODE_KEY] and name in temp_ctx:
|
|
97
|
-
ctx[name] = temp_ctx.pop(name)
|
|
98
|
-
|
|
99
|
-
logger.debug("All checks passed for handler.")
|
|
100
|
-
|
|
101
|
-
temp_ctx["node_col"] = node_col
|
|
102
|
-
ctx |= temp_ctx
|
|
103
|
-
return True
|
|
104
|
-
|
|
105
|
-
async def run(
|
|
106
|
-
self,
|
|
107
|
-
api: API,
|
|
108
|
-
event: Event,
|
|
109
|
-
ctx: Context,
|
|
110
|
-
node_col: "NodeCollection | None" = None,
|
|
111
|
-
) -> typing.Any:
|
|
112
|
-
logger.debug(f"Running func handler {self.function.__qualname__!r}")
|
|
113
|
-
|
|
114
|
-
if self.dataclass is not None and EVENT_NODE_KEY not in ctx:
|
|
115
|
-
if self.update_type is not None and isinstance(event, Update):
|
|
116
|
-
update = getattr(event, event.update_type.value).unwrap()
|
|
117
|
-
event = (
|
|
118
|
-
self.dataclass.from_update(update, bound_api=api)
|
|
119
|
-
if issubclass(self.dataclass, BaseCute)
|
|
120
|
-
else self.dataclass(**update.to_dict()) # type: ignore
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
elif issubclass(self.dataclass, UpdateCute) and isinstance(event, Update):
|
|
124
|
-
event = self.dataclass.from_update(event, bound_api=api)
|
|
125
|
-
|
|
126
|
-
else:
|
|
127
|
-
event = self.dataclass(**event.to_dict()) # type: ignore
|
|
128
|
-
|
|
129
|
-
result = (await self.error_handler.run(self.function, event, api, ctx)).unwrap()
|
|
130
|
-
if node_col := ctx.node_col:
|
|
131
|
-
await node_col.close_all()
|
|
132
|
-
return result
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
__all__ = ("FuncHandler",)
|
|
1
|
+
import dataclasses
|
|
2
|
+
from functools import cached_property
|
|
3
|
+
|
|
4
|
+
import typing_extensions as typing
|
|
5
|
+
|
|
6
|
+
from telegrinder.api.api import API
|
|
7
|
+
from telegrinder.bot.cute_types import BaseCute, UpdateCute
|
|
8
|
+
from telegrinder.bot.dispatch.context import Context
|
|
9
|
+
from telegrinder.bot.dispatch.process import check_rule
|
|
10
|
+
from telegrinder.model import Model
|
|
11
|
+
from telegrinder.modules import logger
|
|
12
|
+
from telegrinder.node.base import Node, get_nodes
|
|
13
|
+
from telegrinder.node.composer import NodeCollection, compose_nodes
|
|
14
|
+
from telegrinder.node.event import EVENT_NODE_KEY
|
|
15
|
+
from telegrinder.tools.error_handler import ABCErrorHandler, ErrorHandler
|
|
16
|
+
from telegrinder.types.enums import UpdateType
|
|
17
|
+
from telegrinder.types.objects import Update
|
|
18
|
+
|
|
19
|
+
from .abc import ABCHandler
|
|
20
|
+
|
|
21
|
+
if typing.TYPE_CHECKING:
|
|
22
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
23
|
+
from telegrinder.node.composer import NodeCollection
|
|
24
|
+
|
|
25
|
+
Rest = typing.ParamSpec("Rest")
|
|
26
|
+
Result = typing.TypeVar("Result")
|
|
27
|
+
Function = typing.TypeVar("Function", bound="Func[..., typing.Any]")
|
|
28
|
+
Event = typing.TypeVar("Event", bound=Model)
|
|
29
|
+
ErrorHandlerT = typing.TypeVar("ErrorHandlerT", bound=ABCErrorHandler, default=ErrorHandler)
|
|
30
|
+
|
|
31
|
+
Func: typing.TypeAlias = typing.Callable[Rest, typing.Coroutine[typing.Any, typing.Any, Result]]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclasses.dataclass(repr=False, slots=True)
|
|
35
|
+
class FuncHandler(ABCHandler[Event], typing.Generic[Event, Function, ErrorHandlerT]):
|
|
36
|
+
function: Function
|
|
37
|
+
rules: list["ABCRule"]
|
|
38
|
+
is_blocking: bool = dataclasses.field(default=True, kw_only=True)
|
|
39
|
+
dataclass: type[typing.Any] | None = dataclasses.field(default=dict, kw_only=True)
|
|
40
|
+
error_handler: ErrorHandlerT = dataclasses.field(
|
|
41
|
+
default_factory=lambda: typing.cast(ErrorHandlerT, ErrorHandler()),
|
|
42
|
+
kw_only=True,
|
|
43
|
+
)
|
|
44
|
+
preset_context: Context = dataclasses.field(default_factory=lambda: Context(), kw_only=True)
|
|
45
|
+
update_type: UpdateType | None = dataclasses.field(default=None, kw_only=True)
|
|
46
|
+
|
|
47
|
+
def __post_init__(self) -> None:
|
|
48
|
+
self.dataclass = typing.get_origin(self.dataclass) or self.dataclass
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def __call__(self) -> Function:
|
|
52
|
+
return self.function
|
|
53
|
+
|
|
54
|
+
def __repr__(self) -> str:
|
|
55
|
+
return "<{}: {}={!r} with rules={!r}, dataclass={!r}, error_handler={!r}>".format(
|
|
56
|
+
self.__class__.__name__,
|
|
57
|
+
"blocking function" if self.is_blocking else "function",
|
|
58
|
+
self.function.__qualname__,
|
|
59
|
+
self.rules,
|
|
60
|
+
self.dataclass,
|
|
61
|
+
self.error_handler,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@cached_property
|
|
65
|
+
def required_nodes(self) -> dict[str, type[Node]]:
|
|
66
|
+
return get_nodes(self.function)
|
|
67
|
+
|
|
68
|
+
async def check(self, api: API, event: Update, ctx: Context | None = None) -> bool:
|
|
69
|
+
if self.update_type is not None and self.update_type != event.update_type:
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
logger.debug("Checking handler {!r}...", self)
|
|
73
|
+
ctx = Context(raw_update=event) if ctx is None else ctx
|
|
74
|
+
temp_ctx = ctx.copy()
|
|
75
|
+
temp_ctx |= self.preset_context
|
|
76
|
+
update = event
|
|
77
|
+
|
|
78
|
+
for rule in self.rules:
|
|
79
|
+
if not await check_rule(api, rule, update, temp_ctx):
|
|
80
|
+
logger.debug("Rule {!r} failed!", rule)
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
nodes = self.required_nodes
|
|
84
|
+
node_col = None
|
|
85
|
+
if nodes:
|
|
86
|
+
result = await compose_nodes(nodes, ctx, data={Update: event, API: api})
|
|
87
|
+
if not result:
|
|
88
|
+
logger.debug(f"Cannot compose nodes for handler. Error: {result.error!r}")
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
node_col = result.value
|
|
92
|
+
temp_ctx |= node_col.values
|
|
93
|
+
|
|
94
|
+
if EVENT_NODE_KEY in ctx:
|
|
95
|
+
for name, node in nodes.items():
|
|
96
|
+
if node is ctx[EVENT_NODE_KEY] and name in temp_ctx:
|
|
97
|
+
ctx[name] = temp_ctx.pop(name)
|
|
98
|
+
|
|
99
|
+
logger.debug("All checks passed for handler.")
|
|
100
|
+
|
|
101
|
+
temp_ctx["node_col"] = node_col
|
|
102
|
+
ctx |= temp_ctx
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
async def run(
|
|
106
|
+
self,
|
|
107
|
+
api: API,
|
|
108
|
+
event: Event,
|
|
109
|
+
ctx: Context,
|
|
110
|
+
node_col: "NodeCollection | None" = None,
|
|
111
|
+
) -> typing.Any:
|
|
112
|
+
logger.debug(f"Running func handler {self.function.__qualname__!r}")
|
|
113
|
+
|
|
114
|
+
if self.dataclass is not None and EVENT_NODE_KEY not in ctx:
|
|
115
|
+
if self.update_type is not None and isinstance(event, Update):
|
|
116
|
+
update = getattr(event, event.update_type.value).unwrap()
|
|
117
|
+
event = (
|
|
118
|
+
self.dataclass.from_update(update, bound_api=api)
|
|
119
|
+
if issubclass(self.dataclass, BaseCute)
|
|
120
|
+
else self.dataclass(**update.to_dict()) # type: ignore
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
elif issubclass(self.dataclass, UpdateCute) and isinstance(event, Update):
|
|
124
|
+
event = self.dataclass.from_update(event, bound_api=api)
|
|
125
|
+
|
|
126
|
+
else:
|
|
127
|
+
event = self.dataclass(**event.to_dict()) # type: ignore
|
|
128
|
+
|
|
129
|
+
result = (await self.error_handler.run(self.function, event, api, ctx)).unwrap()
|
|
130
|
+
if node_col := ctx.node_col:
|
|
131
|
+
await node_col.close_all()
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
__all__ = ("FuncHandler",)
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
|
|
3
|
-
from telegrinder.api.api import API
|
|
4
|
-
from telegrinder.bot.cute_types.message import InputMediaType, MessageCute
|
|
5
|
-
from telegrinder.bot.dispatch.context import Context
|
|
6
|
-
from telegrinder.bot.dispatch.handler.base import BaseReplyHandler
|
|
7
|
-
from telegrinder.bot.rules.abc import ABCRule
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class MediaGroupReplyHandler(BaseReplyHandler):
|
|
11
|
-
def __init__(
|
|
12
|
-
self,
|
|
13
|
-
media: InputMediaType | list[InputMediaType],
|
|
14
|
-
*rules: ABCRule,
|
|
15
|
-
caption: str | list[str] | None = None,
|
|
16
|
-
parse_mode: str | list[str] | None = None,
|
|
17
|
-
is_blocking: bool = True,
|
|
18
|
-
as_reply: bool = False,
|
|
19
|
-
preset_context: Context | None = None,
|
|
20
|
-
**default_params: typing.Any,
|
|
21
|
-
) -> None:
|
|
22
|
-
self.media = media
|
|
23
|
-
self.parse_mode = parse_mode
|
|
24
|
-
self.caption = caption
|
|
25
|
-
super().__init__(
|
|
26
|
-
*rules,
|
|
27
|
-
is_blocking=is_blocking,
|
|
28
|
-
as_reply=as_reply,
|
|
29
|
-
preset_context=preset_context,
|
|
30
|
-
**default_params,
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
|
|
34
|
-
method = event.answer_media_group if not self.as_reply else event.reply_media_group
|
|
35
|
-
await method(
|
|
36
|
-
media=self.media,
|
|
37
|
-
parse_mode=self.parse_mode,
|
|
38
|
-
caption=self.caption,
|
|
39
|
-
**self.default_params,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
__all__ = ("MediaGroupReplyHandler",)
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from telegrinder.api.api import API
|
|
4
|
+
from telegrinder.bot.cute_types.message import InputMediaType, MessageCute
|
|
5
|
+
from telegrinder.bot.dispatch.context import Context
|
|
6
|
+
from telegrinder.bot.dispatch.handler.base import BaseReplyHandler
|
|
7
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MediaGroupReplyHandler(BaseReplyHandler):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
media: InputMediaType | list[InputMediaType],
|
|
14
|
+
*rules: ABCRule,
|
|
15
|
+
caption: str | list[str] | None = None,
|
|
16
|
+
parse_mode: str | list[str] | None = None,
|
|
17
|
+
is_blocking: bool = True,
|
|
18
|
+
as_reply: bool = False,
|
|
19
|
+
preset_context: Context | None = None,
|
|
20
|
+
**default_params: typing.Any,
|
|
21
|
+
) -> None:
|
|
22
|
+
self.media = media
|
|
23
|
+
self.parse_mode = parse_mode
|
|
24
|
+
self.caption = caption
|
|
25
|
+
super().__init__(
|
|
26
|
+
*rules,
|
|
27
|
+
is_blocking=is_blocking,
|
|
28
|
+
as_reply=as_reply,
|
|
29
|
+
preset_context=preset_context,
|
|
30
|
+
**default_params,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
|
|
34
|
+
method = event.answer_media_group if not self.as_reply else event.reply_media_group
|
|
35
|
+
await method(
|
|
36
|
+
media=self.media,
|
|
37
|
+
parse_mode=self.parse_mode,
|
|
38
|
+
caption=self.caption,
|
|
39
|
+
**self.default_params,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
__all__ = ("MediaGroupReplyHandler",)
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
|
|
3
|
-
from telegrinder.api.api import API
|
|
4
|
-
from telegrinder.bot.cute_types.message import MessageCute
|
|
5
|
-
from telegrinder.bot.dispatch.context import Context
|
|
6
|
-
from telegrinder.bot.dispatch.handler.base import BaseReplyHandler
|
|
7
|
-
from telegrinder.bot.rules.abc import ABCRule
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class MessageReplyHandler(BaseReplyHandler):
|
|
11
|
-
def __init__(
|
|
12
|
-
self,
|
|
13
|
-
text: str,
|
|
14
|
-
*rules: ABCRule,
|
|
15
|
-
parse_mode: str | None = None,
|
|
16
|
-
is_blocking: bool = True,
|
|
17
|
-
as_reply: bool = False,
|
|
18
|
-
preset_context: Context | None = None,
|
|
19
|
-
**default_params: typing.Any,
|
|
20
|
-
) -> None:
|
|
21
|
-
self.text = text
|
|
22
|
-
self.parse_mode = parse_mode
|
|
23
|
-
super().__init__(
|
|
24
|
-
*rules,
|
|
25
|
-
is_blocking=is_blocking,
|
|
26
|
-
as_reply=as_reply,
|
|
27
|
-
preset_context=preset_context,
|
|
28
|
-
**default_params,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
|
|
32
|
-
method = event.answer if not self.as_reply else event.reply
|
|
33
|
-
await method(text=self.text, parse_mode=self.parse_mode, **self.default_params)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
__all__ = ("MessageReplyHandler",)
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from telegrinder.api.api import API
|
|
4
|
+
from telegrinder.bot.cute_types.message import MessageCute
|
|
5
|
+
from telegrinder.bot.dispatch.context import Context
|
|
6
|
+
from telegrinder.bot.dispatch.handler.base import BaseReplyHandler
|
|
7
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MessageReplyHandler(BaseReplyHandler):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
text: str,
|
|
14
|
+
*rules: ABCRule,
|
|
15
|
+
parse_mode: str | None = None,
|
|
16
|
+
is_blocking: bool = True,
|
|
17
|
+
as_reply: bool = False,
|
|
18
|
+
preset_context: Context | None = None,
|
|
19
|
+
**default_params: typing.Any,
|
|
20
|
+
) -> None:
|
|
21
|
+
self.text = text
|
|
22
|
+
self.parse_mode = parse_mode
|
|
23
|
+
super().__init__(
|
|
24
|
+
*rules,
|
|
25
|
+
is_blocking=is_blocking,
|
|
26
|
+
as_reply=as_reply,
|
|
27
|
+
preset_context=preset_context,
|
|
28
|
+
**default_params,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
|
|
32
|
+
method = event.answer if not self.as_reply else event.reply
|
|
33
|
+
await method(text=self.text, parse_mode=self.parse_mode, **self.default_params)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = ("MessageReplyHandler",)
|