telegrinder 0.1.dev171__py3-none-any.whl → 0.2.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.
Potentially problematic release.
This version of telegrinder might be problematic. Click here for more details.
- telegrinder/__init__.py +2 -2
- telegrinder/api/__init__.py +1 -2
- telegrinder/api/api.py +3 -3
- telegrinder/api/token.py +36 -0
- telegrinder/bot/__init__.py +12 -6
- telegrinder/bot/bot.py +12 -5
- telegrinder/bot/cute_types/__init__.py +7 -7
- telegrinder/bot/cute_types/base.py +7 -32
- telegrinder/bot/cute_types/callback_query.py +5 -6
- telegrinder/bot/cute_types/chat_join_request.py +4 -5
- telegrinder/bot/cute_types/chat_member_updated.py +3 -4
- telegrinder/bot/cute_types/inline_query.py +3 -4
- telegrinder/bot/cute_types/message.py +9 -10
- telegrinder/bot/cute_types/update.py +8 -9
- telegrinder/bot/cute_types/utils.py +1 -1
- telegrinder/bot/dispatch/__init__.py +9 -9
- telegrinder/bot/dispatch/abc.py +2 -2
- telegrinder/bot/dispatch/context.py +11 -2
- telegrinder/bot/dispatch/dispatch.py +18 -33
- telegrinder/bot/dispatch/handler/__init__.py +3 -3
- telegrinder/bot/dispatch/handler/abc.py +3 -3
- telegrinder/bot/dispatch/handler/func.py +17 -12
- telegrinder/bot/dispatch/handler/message_reply.py +6 -7
- telegrinder/bot/dispatch/middleware/__init__.py +1 -1
- telegrinder/bot/dispatch/process.py +30 -11
- telegrinder/bot/dispatch/return_manager/__init__.py +4 -4
- telegrinder/bot/dispatch/return_manager/callback_query.py +1 -2
- telegrinder/bot/dispatch/return_manager/inline_query.py +1 -2
- telegrinder/bot/dispatch/return_manager/message.py +1 -2
- telegrinder/bot/dispatch/view/__init__.py +8 -8
- telegrinder/bot/dispatch/view/abc.py +9 -4
- telegrinder/bot/dispatch/view/box.py +2 -2
- telegrinder/bot/dispatch/view/callback_query.py +1 -2
- telegrinder/bot/dispatch/view/chat_join_request.py +1 -2
- telegrinder/bot/dispatch/view/chat_member.py +16 -2
- telegrinder/bot/dispatch/view/inline_query.py +1 -2
- telegrinder/bot/dispatch/view/message.py +1 -2
- telegrinder/bot/dispatch/view/raw.py +8 -10
- telegrinder/bot/dispatch/waiter_machine/__init__.py +3 -3
- telegrinder/bot/dispatch/waiter_machine/machine.py +10 -6
- telegrinder/bot/dispatch/waiter_machine/short_state.py +2 -2
- telegrinder/bot/polling/abc.py +1 -1
- telegrinder/bot/polling/polling.py +3 -3
- telegrinder/bot/rules/__init__.py +20 -20
- telegrinder/bot/rules/abc.py +50 -40
- telegrinder/bot/rules/adapter/__init__.py +5 -5
- telegrinder/bot/rules/adapter/abc.py +6 -3
- telegrinder/bot/rules/adapter/errors.py +2 -1
- telegrinder/bot/rules/adapter/event.py +27 -15
- telegrinder/bot/rules/adapter/node.py +28 -22
- telegrinder/bot/rules/adapter/raw_update.py +13 -5
- telegrinder/bot/rules/callback_data.py +4 -4
- telegrinder/bot/rules/chat_join.py +4 -4
- telegrinder/bot/rules/func.py +1 -1
- telegrinder/bot/rules/inline.py +3 -3
- telegrinder/bot/rules/markup.py +3 -1
- telegrinder/bot/rules/message_entities.py +1 -1
- telegrinder/bot/rules/text.py +1 -2
- telegrinder/bot/rules/update.py +1 -2
- telegrinder/bot/scenario/abc.py +2 -2
- telegrinder/bot/scenario/checkbox.py +1 -2
- telegrinder/bot/scenario/choice.py +1 -2
- telegrinder/model.py +6 -1
- telegrinder/msgspec_utils.py +55 -55
- telegrinder/node/__init__.py +1 -3
- telegrinder/node/base.py +14 -86
- telegrinder/node/composer.py +71 -74
- telegrinder/node/container.py +3 -3
- telegrinder/node/event.py +40 -31
- telegrinder/node/polymorphic.py +12 -6
- telegrinder/node/rule.py +1 -9
- telegrinder/node/scope.py +9 -1
- telegrinder/node/source.py +11 -0
- telegrinder/node/update.py +6 -2
- telegrinder/rules.py +59 -0
- telegrinder/tools/error_handler/abc.py +2 -2
- telegrinder/tools/error_handler/error_handler.py +5 -5
- telegrinder/tools/global_context/global_context.py +1 -1
- telegrinder/tools/keyboard.py +1 -1
- telegrinder/tools/loop_wrapper/loop_wrapper.py +9 -9
- telegrinder/tools/magic.py +64 -19
- telegrinder/types/__init__.py +1 -0
- telegrinder/types/enums.py +1 -0
- telegrinder/types/methods.py +78 -11
- telegrinder/types/objects.py +46 -24
- telegrinder/verification_utils.py +1 -3
- {telegrinder-0.1.dev171.dist-info → telegrinder-0.2.0.dist-info}/METADATA +1 -1
- telegrinder-0.2.0.dist-info/RECORD +145 -0
- telegrinder/api/abc.py +0 -79
- telegrinder-0.1.dev171.dist-info/RECORD +0 -145
- {telegrinder-0.1.dev171.dist-info → telegrinder-0.2.0.dist-info}/LICENSE +0 -0
- {telegrinder-0.1.dev171.dist-info → telegrinder-0.2.0.dist-info}/WHEEL +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from .abc import ABCRule, AndRule, NotRule, OrRule
|
|
2
|
-
from .callback_data import (
|
|
1
|
+
from telegrinder.bot.rules.abc import ABCRule, AndRule, NotRule, OrRule
|
|
2
|
+
from telegrinder.bot.rules.callback_data import (
|
|
3
3
|
CallbackDataEq,
|
|
4
4
|
CallbackDataJsonEq,
|
|
5
5
|
CallbackDataJsonModel,
|
|
@@ -9,25 +9,25 @@ from .callback_data import (
|
|
|
9
9
|
CallbackQueryRule,
|
|
10
10
|
HasData,
|
|
11
11
|
)
|
|
12
|
-
from .chat_join import (
|
|
12
|
+
from telegrinder.bot.rules.chat_join import (
|
|
13
13
|
ChatJoinRequestRule,
|
|
14
14
|
HasInviteLink,
|
|
15
15
|
InviteLinkByCreator,
|
|
16
16
|
InviteLinkName,
|
|
17
17
|
)
|
|
18
|
-
from .command import Argument, Command
|
|
19
|
-
from .enum_text import EnumTextRule
|
|
20
|
-
from .func import FuncRule
|
|
21
|
-
from .fuzzy import FuzzyText
|
|
22
|
-
from .inline import (
|
|
18
|
+
from telegrinder.bot.rules.command import Argument, Command
|
|
19
|
+
from telegrinder.bot.rules.enum_text import EnumTextRule
|
|
20
|
+
from telegrinder.bot.rules.func import FuncRule
|
|
21
|
+
from telegrinder.bot.rules.fuzzy import FuzzyText
|
|
22
|
+
from telegrinder.bot.rules.inline import (
|
|
23
23
|
HasLocation,
|
|
24
24
|
InlineQueryChatType,
|
|
25
25
|
InlineQueryMarkup,
|
|
26
26
|
InlineQueryRule,
|
|
27
27
|
InlineQueryText,
|
|
28
28
|
)
|
|
29
|
-
from .integer import IntegerInRange, IsInteger
|
|
30
|
-
from .is_from import (
|
|
29
|
+
from telegrinder.bot.rules.integer import IntegerInRange, IsInteger
|
|
30
|
+
from telegrinder.bot.rules.is_from import (
|
|
31
31
|
IsBot,
|
|
32
32
|
IsChat,
|
|
33
33
|
IsChatId,
|
|
@@ -45,16 +45,16 @@ from .is_from import (
|
|
|
45
45
|
IsUser,
|
|
46
46
|
IsUserId,
|
|
47
47
|
)
|
|
48
|
-
from .markup import Markup
|
|
49
|
-
from .mention import HasMention
|
|
50
|
-
from .message import MessageRule
|
|
51
|
-
from .message_entities import HasEntities, MessageEntities
|
|
52
|
-
from .node import NodeRule
|
|
53
|
-
from .regex import Regex
|
|
54
|
-
from .rule_enum import RuleEnum
|
|
55
|
-
from .start import StartCommand
|
|
56
|
-
from .text import HasText, Text
|
|
57
|
-
from .update import IsUpdateType
|
|
48
|
+
from telegrinder.bot.rules.markup import Markup
|
|
49
|
+
from telegrinder.bot.rules.mention import HasMention
|
|
50
|
+
from telegrinder.bot.rules.message import MessageRule
|
|
51
|
+
from telegrinder.bot.rules.message_entities import HasEntities, MessageEntities
|
|
52
|
+
from telegrinder.bot.rules.node import NodeRule
|
|
53
|
+
from telegrinder.bot.rules.regex import Regex
|
|
54
|
+
from telegrinder.bot.rules.rule_enum import RuleEnum
|
|
55
|
+
from telegrinder.bot.rules.start import StartCommand
|
|
56
|
+
from telegrinder.bot.rules.text import HasText, Text
|
|
57
|
+
from telegrinder.bot.rules.update import IsUpdateType
|
|
58
58
|
|
|
59
59
|
__all__ = (
|
|
60
60
|
"ABCRule",
|
telegrinder/bot/rules/abc.py
CHANGED
|
@@ -11,7 +11,12 @@ from telegrinder.bot.rules.adapter import ABCAdapter, RawUpdateAdapter
|
|
|
11
11
|
from telegrinder.bot.rules.adapter.node import Event
|
|
12
12
|
from telegrinder.node.base import Node, get_nodes, is_node
|
|
13
13
|
from telegrinder.tools.i18n.base import ABCTranslator
|
|
14
|
-
from telegrinder.tools.magic import
|
|
14
|
+
from telegrinder.tools.magic import (
|
|
15
|
+
cache_translation,
|
|
16
|
+
get_annotations,
|
|
17
|
+
get_cached_translation,
|
|
18
|
+
get_default_args,
|
|
19
|
+
)
|
|
15
20
|
from telegrinder.types.objects import Update as UpdateObject
|
|
16
21
|
|
|
17
22
|
if typing.TYPE_CHECKING:
|
|
@@ -37,51 +42,16 @@ def with_caching_translations(func: typing.Callable[..., typing.Any]):
|
|
|
37
42
|
|
|
38
43
|
|
|
39
44
|
class ABCRule(ABC, typing.Generic[AdaptTo]):
|
|
40
|
-
adapter: ABCAdapter[UpdateObject, AdaptTo]
|
|
45
|
+
adapter: ABCAdapter[UpdateObject, AdaptTo]
|
|
41
46
|
requires: list["ABCRule"] = []
|
|
42
47
|
|
|
48
|
+
if not typing.TYPE_CHECKING:
|
|
49
|
+
adapter = RawUpdateAdapter()
|
|
50
|
+
|
|
43
51
|
@abstractmethod
|
|
44
52
|
async def check(self, event: AdaptTo, *, ctx: Context) -> bool:
|
|
45
53
|
pass
|
|
46
54
|
|
|
47
|
-
@cached_property
|
|
48
|
-
def required_nodes(self) -> dict[str, type[Node]]:
|
|
49
|
-
return get_nodes(self.check)
|
|
50
|
-
|
|
51
|
-
async def bounding_check(
|
|
52
|
-
self,
|
|
53
|
-
adapted_value: AdaptTo,
|
|
54
|
-
ctx: Context,
|
|
55
|
-
node_col: "NodeCollection | None" = None,
|
|
56
|
-
) -> bool:
|
|
57
|
-
kw = {}
|
|
58
|
-
node_col_values = node_col.values() if node_col is not None else {}
|
|
59
|
-
|
|
60
|
-
for i, (k, v) in enumerate(get_annotations(self.check).items()):
|
|
61
|
-
if (isinstance(adapted_value, Event) and not i) or (
|
|
62
|
-
isinstance(v, type) and isinstance(adapted_value, v)
|
|
63
|
-
):
|
|
64
|
-
kw[k] = adapted_value if not isinstance(adapted_value, Event) else adapted_value.obj
|
|
65
|
-
elif is_node(v):
|
|
66
|
-
assert k in node_col_values, "Node is undefined, error while bounding."
|
|
67
|
-
kw[k] = node_col_values[k]
|
|
68
|
-
elif k in ctx:
|
|
69
|
-
kw[k] = ctx[k]
|
|
70
|
-
elif v is Context:
|
|
71
|
-
kw[k] = ctx
|
|
72
|
-
else:
|
|
73
|
-
raise LookupError(
|
|
74
|
-
f"Cannot bound {k!r} of type {v!r} to '{self.__class__.__name__}.check()', because it cannot be resolved."
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
return await self.check(**kw)
|
|
78
|
-
|
|
79
|
-
def optional(self) -> "ABCRule":
|
|
80
|
-
return self | Always()
|
|
81
|
-
|
|
82
|
-
def should_fail(self) -> "ABCRule":
|
|
83
|
-
return self & Never()
|
|
84
|
-
|
|
85
55
|
def __init_subclass__(cls, requires: list["ABCRule"] | None = None) -> None:
|
|
86
56
|
"""Merges requirements from inherited classes and rule-specific requirements."""
|
|
87
57
|
|
|
@@ -132,6 +102,46 @@ class ABCRule(ABC, typing.Generic[AdaptTo]):
|
|
|
132
102
|
self.adapter,
|
|
133
103
|
)
|
|
134
104
|
|
|
105
|
+
@cached_property
|
|
106
|
+
def required_nodes(self) -> dict[str, type[Node]]:
|
|
107
|
+
return get_nodes(self.check)
|
|
108
|
+
|
|
109
|
+
def as_optional(self) -> "ABCRule":
|
|
110
|
+
return self | Always()
|
|
111
|
+
|
|
112
|
+
def should_fail(self) -> "ABCRule":
|
|
113
|
+
return self & Never()
|
|
114
|
+
|
|
115
|
+
async def bounding_check(
|
|
116
|
+
self,
|
|
117
|
+
adapted_value: AdaptTo,
|
|
118
|
+
ctx: Context,
|
|
119
|
+
node_col: "NodeCollection | None" = None,
|
|
120
|
+
) -> bool:
|
|
121
|
+
kw = {}
|
|
122
|
+
node_col_values = node_col.values if node_col is not None else {}
|
|
123
|
+
temp_ctx = get_default_args(self.check) | ctx
|
|
124
|
+
|
|
125
|
+
for i, (k, v) in enumerate(get_annotations(self.check).items()):
|
|
126
|
+
if (isinstance(adapted_value, Event) and not i) or (
|
|
127
|
+
isinstance(v, type) and isinstance(adapted_value, v)
|
|
128
|
+
):
|
|
129
|
+
kw[k] = adapted_value if not isinstance(adapted_value, Event) else adapted_value.obj
|
|
130
|
+
elif is_node(v):
|
|
131
|
+
assert k in node_col_values, "Node is undefined, error while bounding."
|
|
132
|
+
kw[k] = node_col_values[k]
|
|
133
|
+
elif k in temp_ctx:
|
|
134
|
+
kw[k] = temp_ctx[k]
|
|
135
|
+
elif v is Context:
|
|
136
|
+
kw[k] = ctx
|
|
137
|
+
else:
|
|
138
|
+
raise LookupError(
|
|
139
|
+
f"Cannot bound {k!r} of type {v!r} to '{self.__class__.__qualname__}.check()', "
|
|
140
|
+
"because it cannot be resolved."
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return await self.check(**kw)
|
|
144
|
+
|
|
135
145
|
async def translate(self, translator: ABCTranslator) -> typing.Self:
|
|
136
146
|
return self
|
|
137
147
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from .abc import ABCAdapter, Event
|
|
2
|
-
from .errors import AdapterError
|
|
3
|
-
from .event import EventAdapter
|
|
4
|
-
from .node import NodeAdapter
|
|
5
|
-
from .raw_update import RawUpdateAdapter
|
|
1
|
+
from telegrinder.bot.rules.adapter.abc import ABCAdapter, Event
|
|
2
|
+
from telegrinder.bot.rules.adapter.errors import AdapterError
|
|
3
|
+
from telegrinder.bot.rules.adapter.event import EventAdapter
|
|
4
|
+
from telegrinder.bot.rules.adapter.node import NodeAdapter
|
|
5
|
+
from telegrinder.bot.rules.adapter.raw_update import RawUpdateAdapter
|
|
6
6
|
|
|
7
7
|
__all__ = (
|
|
8
8
|
"ABCAdapter",
|
|
@@ -4,7 +4,8 @@ import typing
|
|
|
4
4
|
|
|
5
5
|
from fntypes.result import Result
|
|
6
6
|
|
|
7
|
-
from telegrinder.api
|
|
7
|
+
from telegrinder.api import API
|
|
8
|
+
from telegrinder.bot.dispatch.context import Context
|
|
8
9
|
from telegrinder.bot.rules.adapter.errors import AdapterError
|
|
9
10
|
from telegrinder.model import Model
|
|
10
11
|
|
|
@@ -13,12 +14,14 @@ To = typing.TypeVar("To")
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class ABCAdapter(abc.ABC, typing.Generic[From, To]):
|
|
17
|
+
ADAPTED_VALUE_KEY: str | None = None
|
|
18
|
+
|
|
16
19
|
@abc.abstractmethod
|
|
17
|
-
async def adapt(self, api:
|
|
20
|
+
async def adapt(self, api: API, update: From, context: Context) -> Result[To, AdapterError]:
|
|
18
21
|
pass
|
|
19
22
|
|
|
20
23
|
|
|
21
|
-
@dataclasses.dataclass
|
|
24
|
+
@dataclasses.dataclass(slots=True)
|
|
22
25
|
class Event(typing.Generic[To]):
|
|
23
26
|
obj: To
|
|
24
27
|
|
|
@@ -2,8 +2,9 @@ import typing
|
|
|
2
2
|
|
|
3
3
|
from fntypes.result import Error, Ok, Result
|
|
4
4
|
|
|
5
|
-
from telegrinder.api
|
|
5
|
+
from telegrinder.api import API
|
|
6
6
|
from telegrinder.bot.cute_types.base import BaseCute
|
|
7
|
+
from telegrinder.bot.dispatch.context import Context
|
|
7
8
|
from telegrinder.bot.rules.adapter.abc import ABCAdapter
|
|
8
9
|
from telegrinder.bot.rules.adapter.errors import AdapterError
|
|
9
10
|
from telegrinder.msgspec_utils import Nothing
|
|
@@ -14,6 +15,8 @@ ToCute = typing.TypeVar("ToCute", bound=BaseCute)
|
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class EventAdapter(ABCAdapter[Update, ToCute]):
|
|
18
|
+
ADAPTED_VALUE_KEY: str = "_adapted_cute_event"
|
|
19
|
+
|
|
17
20
|
def __init__(self, event: UpdateType | type[Model], cute_model: type[ToCute]) -> None:
|
|
18
21
|
self.event = event
|
|
19
22
|
self.cute_model = cute_model
|
|
@@ -29,36 +32,45 @@ class EventAdapter(ABCAdapter[Update, ToCute]):
|
|
|
29
32
|
else:
|
|
30
33
|
raw_update_type = self.event.__name__
|
|
31
34
|
|
|
32
|
-
return "<{}: adapt {} -> {}>".format(
|
|
35
|
+
return "<{}: adapt Update -> {} -> {}>".format(
|
|
33
36
|
self.__class__.__name__,
|
|
34
37
|
raw_update_type,
|
|
35
38
|
self.cute_model.__name__,
|
|
36
39
|
)
|
|
37
40
|
|
|
38
|
-
async def adapt(self, api:
|
|
39
|
-
|
|
41
|
+
async def adapt(self, api: API, update: Update, context: Context) -> Result[ToCute, AdapterError]:
|
|
42
|
+
if self.ADAPTED_VALUE_KEY in context:
|
|
43
|
+
return Ok(context[self.ADAPTED_VALUE_KEY])
|
|
44
|
+
|
|
40
45
|
if isinstance(self.event, UpdateType):
|
|
41
46
|
if update.update_type != self.event:
|
|
42
47
|
return Error(
|
|
43
48
|
AdapterError(f"Update is not of event type {self.event!r}."),
|
|
44
49
|
)
|
|
45
50
|
|
|
46
|
-
if (event := getattr(update, self.event.value, Nothing)
|
|
51
|
+
if isinstance(event := getattr(update, self.event.value, Nothing), type(Nothing)):
|
|
47
52
|
return Error(
|
|
48
53
|
AdapterError(f"Update is not an {self.event!r}."),
|
|
49
54
|
)
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
event = event.unwrap()
|
|
57
|
+
|
|
58
|
+
if type(event) is self.cute_model:
|
|
59
|
+
adapted = event
|
|
60
|
+
else:
|
|
61
|
+
adapted = self.cute_model.from_update(event, bound_api=api)
|
|
62
|
+
else:
|
|
63
|
+
event = getattr(update, update.update_type.value).unwrap()
|
|
64
|
+
if not update.update_type or not issubclass(type(event), self.event):
|
|
65
|
+
return Error(AdapterError(f"Update is not an {self.event.__name__!r}."))
|
|
66
|
+
|
|
67
|
+
if type(event) is self.cute_model:
|
|
68
|
+
adapted = event
|
|
69
|
+
else:
|
|
70
|
+
adapted = self.cute_model.from_update(event, bound_api=api)
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return Error(AdapterError(f"Update is not an {self.event.__name__!r}."))
|
|
61
|
-
return Ok(self.cute_model.from_update(event, bound_api=api))
|
|
72
|
+
context[self.ADAPTED_VALUE_KEY] = adapted
|
|
73
|
+
return Ok(adapted) # type: ignore
|
|
62
74
|
|
|
63
75
|
|
|
64
76
|
__all__ = ("EventAdapter",)
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
|
|
1
|
+
import typing_extensions as typing
|
|
3
2
|
from fntypes.result import Error, Ok, Result
|
|
4
3
|
|
|
5
|
-
from telegrinder.api
|
|
6
|
-
from telegrinder.bot.cute_types.update import UpdateCute
|
|
4
|
+
from telegrinder.api import API
|
|
7
5
|
from telegrinder.bot.dispatch.context import Context
|
|
8
6
|
from telegrinder.bot.rules.adapter.abc import ABCAdapter, Event
|
|
9
7
|
from telegrinder.bot.rules.adapter.errors import AdapterError
|
|
10
|
-
from telegrinder.
|
|
11
|
-
from telegrinder.node.composer import NodeSession,
|
|
8
|
+
from telegrinder.msgspec_utils import repr_type
|
|
9
|
+
from telegrinder.node.composer import NodeSession, compose_nodes
|
|
12
10
|
from telegrinder.types.objects import Update
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
if typing.TYPE_CHECKING:
|
|
13
|
+
from telegrinder.node.base import Node
|
|
14
|
+
|
|
15
|
+
Ts = typing.TypeVarTuple("Ts", default=typing.Unpack[tuple[type["Node"], ...]])
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class NodeAdapter(typing.Generic[*Ts], ABCAdapter[Update, Event[tuple[*Ts]]]):
|
|
@@ -19,24 +20,29 @@ class NodeAdapter(typing.Generic[*Ts], ABCAdapter[Update, Event[tuple[*Ts]]]):
|
|
|
19
20
|
self.nodes = nodes
|
|
20
21
|
|
|
21
22
|
def __repr__(self) -> str:
|
|
22
|
-
return "<{}: adapt Update -> {}>".format(
|
|
23
|
+
return "<{}: adapt Update -> ({})>".format(
|
|
23
24
|
self.__class__.__name__,
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
", ".join(repr_type(node) for node in self.nodes),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
async def adapt(
|
|
29
|
+
self,
|
|
30
|
+
api: API,
|
|
31
|
+
update: Update,
|
|
32
|
+
context: Context,
|
|
33
|
+
) -> Result[Event[tuple[*Ts]], AdapterError]:
|
|
34
|
+
result = await compose_nodes(
|
|
35
|
+
nodes={str(i): typing.cast(type["Node"], node) for i, node in enumerate(self.nodes)},
|
|
36
|
+
ctx=context,
|
|
37
|
+
data={Update: update, API: api},
|
|
26
38
|
)
|
|
27
39
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
node_sessions.append(await compose_node(node_t, update_cute, Context(raw_update=update))) # type: ignore
|
|
35
|
-
except ComposeError:
|
|
36
|
-
for session in node_sessions:
|
|
37
|
-
await session.close(with_value=None)
|
|
38
|
-
return Error(AdapterError(f"Couldn't compose nodes, error on {node_t}"))
|
|
39
|
-
return Ok(Event(tuple(node_sessions))) # type: ignore
|
|
40
|
+
match result:
|
|
41
|
+
case Ok(collection):
|
|
42
|
+
sessions: list[NodeSession] = list(collection.sessions.values())
|
|
43
|
+
return Ok(Event(tuple(sessions))) # type: ignore
|
|
44
|
+
case Error(err):
|
|
45
|
+
return Error(AdapterError(f"Couldn't compose nodes, error: {err}."))
|
|
40
46
|
|
|
41
47
|
|
|
42
48
|
__all__ = ("NodeAdapter",)
|
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
from fntypes.result import Ok, Result
|
|
2
2
|
|
|
3
|
-
from telegrinder.api
|
|
3
|
+
from telegrinder.api import API
|
|
4
4
|
from telegrinder.bot.cute_types.update import UpdateCute
|
|
5
|
+
from telegrinder.bot.dispatch.context import Context
|
|
5
6
|
from telegrinder.bot.rules.adapter.abc import ABCAdapter
|
|
6
7
|
from telegrinder.bot.rules.adapter.errors import AdapterError
|
|
7
8
|
from telegrinder.types.objects import Update
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class RawUpdateAdapter(ABCAdapter[Update, UpdateCute]):
|
|
12
|
+
ADAPTED_VALUE_KEY: str = "_adapted_update_cute"
|
|
13
|
+
|
|
11
14
|
def __repr__(self) -> str:
|
|
12
15
|
return f"<{self.__class__.__name__}: adapt Update -> UpdateCute>"
|
|
13
16
|
|
|
14
17
|
async def adapt(
|
|
15
18
|
self,
|
|
16
|
-
api:
|
|
19
|
+
api: API,
|
|
17
20
|
update: Update,
|
|
21
|
+
context: Context,
|
|
18
22
|
) -> Result[UpdateCute, AdapterError]:
|
|
19
|
-
if not
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
if self.ADAPTED_VALUE_KEY not in context:
|
|
24
|
+
context[self.ADAPTED_VALUE_KEY] = (
|
|
25
|
+
UpdateCute.from_update(update, api)
|
|
26
|
+
if not isinstance(update, UpdateCute)
|
|
27
|
+
else update
|
|
28
|
+
)
|
|
29
|
+
return Ok(context[self.ADAPTED_VALUE_KEY])
|
|
22
30
|
|
|
23
31
|
|
|
24
32
|
__all__ = ("RawUpdateAdapter",)
|
|
@@ -26,12 +26,12 @@ class CallbackQueryRule(ABCRule[CallbackQuery], abc.ABC):
|
|
|
26
26
|
adapter: EventAdapter[CallbackQuery] = EventAdapter(UpdateType.CALLBACK_QUERY, CallbackQuery)
|
|
27
27
|
|
|
28
28
|
@abc.abstractmethod
|
|
29
|
-
async def check(self, event: CallbackQuery,
|
|
29
|
+
async def check(self, event: CallbackQuery, context: Context) -> bool:
|
|
30
30
|
pass
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class HasData(CallbackQueryRule):
|
|
34
|
-
async def check(self, event: CallbackQuery
|
|
34
|
+
async def check(self, event: CallbackQuery) -> bool:
|
|
35
35
|
return bool(event.data.unwrap_or_none())
|
|
36
36
|
|
|
37
37
|
|
|
@@ -122,7 +122,7 @@ class CallbackDataEq(CallbackQueryDataRule):
|
|
|
122
122
|
def __init__(self, value: str, /) -> None:
|
|
123
123
|
self.value = value
|
|
124
124
|
|
|
125
|
-
async def check(self, event: CallbackQuery
|
|
125
|
+
async def check(self, event: CallbackQuery) -> bool:
|
|
126
126
|
return event.data.unwrap() == self.value
|
|
127
127
|
|
|
128
128
|
|
|
@@ -130,7 +130,7 @@ class CallbackDataJsonEq(CallbackQueryDataRule):
|
|
|
130
130
|
def __init__(self, d: dict[str, typing.Any], /) -> None:
|
|
131
131
|
self.d = d
|
|
132
132
|
|
|
133
|
-
async def check(self, event: CallbackQuery
|
|
133
|
+
async def check(self, event: CallbackQuery) -> bool:
|
|
134
134
|
return event.decode_callback_data().unwrap_or_none() == self.d
|
|
135
135
|
|
|
136
136
|
|
|
@@ -15,12 +15,12 @@ class ChatJoinRequestRule(ABCRule[ChatJoinRequest], requires=[]):
|
|
|
15
15
|
adapter: EventAdapter[ChatJoinRequest] = EventAdapter(UpdateType.CHAT_JOIN_REQUEST, ChatJoinRequest)
|
|
16
16
|
|
|
17
17
|
@abc.abstractmethod
|
|
18
|
-
async def check(self, event: ChatJoinRequest,
|
|
18
|
+
async def check(self, event: ChatJoinRequest, context: Context) -> bool:
|
|
19
19
|
pass
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class HasInviteLink(ChatJoinRequestRule):
|
|
23
|
-
async def check(self, event: ChatJoinRequest
|
|
23
|
+
async def check(self, event: ChatJoinRequest) -> bool:
|
|
24
24
|
return bool(event.invite_link)
|
|
25
25
|
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ class InviteLinkName(ChatJoinRequestRule, requires=[HasInviteLink()]):
|
|
|
28
28
|
def __init__(self, name: str, /) -> None:
|
|
29
29
|
self.name = name
|
|
30
30
|
|
|
31
|
-
async def check(self, event: ChatJoinRequest
|
|
31
|
+
async def check(self, event: ChatJoinRequest) -> bool:
|
|
32
32
|
return event.invite_link.unwrap().name.unwrap_or_none() == self.name
|
|
33
33
|
|
|
34
34
|
|
|
@@ -36,7 +36,7 @@ class InviteLinkByCreator(ChatJoinRequestRule, requires=[HasInviteLink()]):
|
|
|
36
36
|
def __init__(self, creator_id: int, /) -> None:
|
|
37
37
|
self.creator_id = creator_id
|
|
38
38
|
|
|
39
|
-
async def check(self, event: ChatJoinRequest
|
|
39
|
+
async def check(self, event: ChatJoinRequest) -> bool:
|
|
40
40
|
return event.invite_link.unwrap().creator.id == self.creator_id
|
|
41
41
|
|
|
42
42
|
|
telegrinder/bot/rules/func.py
CHANGED
|
@@ -12,7 +12,7 @@ class FuncRule(ABCRule, typing.Generic[AdaptTo]):
|
|
|
12
12
|
self,
|
|
13
13
|
func: typing.Callable[[AdaptTo, Context], typing.Awaitable[bool] | bool],
|
|
14
14
|
adapter: ABCAdapter[Update, AdaptTo] | None = None,
|
|
15
|
-
):
|
|
15
|
+
) -> None:
|
|
16
16
|
self.func = func
|
|
17
17
|
self.adapter = adapter or RawUpdateAdapter() # type: ignore
|
|
18
18
|
|
telegrinder/bot/rules/inline.py
CHANGED
|
@@ -21,7 +21,7 @@ class InlineQueryRule(ABCRule[InlineQuery], abc.ABC):
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class HasLocation(InlineQueryRule):
|
|
24
|
-
async def check(self, query: InlineQuery
|
|
24
|
+
async def check(self, query: InlineQuery) -> bool:
|
|
25
25
|
return bool(query.location)
|
|
26
26
|
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ class InlineQueryChatType(InlineQueryRule):
|
|
|
29
29
|
def __init__(self, chat_type: ChatType, /) -> None:
|
|
30
30
|
self.chat_type = chat_type
|
|
31
31
|
|
|
32
|
-
async def check(self, query: InlineQuery
|
|
32
|
+
async def check(self, query: InlineQuery) -> bool:
|
|
33
33
|
return query.chat_type.map(lambda x: x == self.chat_type).unwrap_or(False)
|
|
34
34
|
|
|
35
35
|
|
|
@@ -40,7 +40,7 @@ class InlineQueryText(InlineQueryRule):
|
|
|
40
40
|
]
|
|
41
41
|
self.lower_case = lower_case
|
|
42
42
|
|
|
43
|
-
async def check(self, query: InlineQuery
|
|
43
|
+
async def check(self, query: InlineQuery) -> bool:
|
|
44
44
|
return (query.query.lower() if self.lower_case else query.query) in self.texts
|
|
45
45
|
|
|
46
46
|
|
telegrinder/bot/rules/markup.py
CHANGED
|
@@ -9,7 +9,7 @@ from telegrinder.tools.global_context.telegrinder_ctx import TelegrinderContext
|
|
|
9
9
|
from .abc import ABCRule
|
|
10
10
|
|
|
11
11
|
PatternLike: typing.TypeAlias = str | vbml.Pattern
|
|
12
|
-
global_ctx = TelegrinderContext()
|
|
12
|
+
global_ctx: typing.Final[TelegrinderContext] = TelegrinderContext()
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def check_string(patterns: list[vbml.Pattern], s: str, ctx: Context) -> bool:
|
|
@@ -24,6 +24,8 @@ def check_string(patterns: list[vbml.Pattern], s: str, ctx: Context) -> bool:
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class Markup(ABCRule):
|
|
27
|
+
"""Markup Language. See [VBML docs](https://github.com/tesseradecade/vbml/blob/master/docs/index.md)"""
|
|
28
|
+
|
|
27
29
|
def __init__(self, patterns: PatternLike | list[PatternLike], /) -> None:
|
|
28
30
|
if not isinstance(patterns, list):
|
|
29
31
|
patterns = [patterns]
|
telegrinder/bot/rules/text.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from telegrinder import node
|
|
2
|
-
from telegrinder.bot.dispatch.context import Context
|
|
3
2
|
from telegrinder.tools.i18n.base import ABCTranslator
|
|
4
3
|
|
|
5
4
|
from .abc import ABCRule, with_caching_translations
|
|
@@ -18,7 +17,7 @@ class Text(ABCRule):
|
|
|
18
17
|
self.texts = texts if not ignore_case else list(map(str.lower, texts))
|
|
19
18
|
self.ignore_case = ignore_case
|
|
20
19
|
|
|
21
|
-
async def check(self, text: node.text.Text
|
|
20
|
+
async def check(self, text: node.text.Text) -> bool:
|
|
22
21
|
return (text if not self.ignore_case else text.lower()) in self.texts
|
|
23
22
|
|
|
24
23
|
@with_caching_translations
|
telegrinder/bot/rules/update.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from telegrinder.bot.cute_types.update import UpdateCute
|
|
2
|
-
from telegrinder.bot.dispatch.context import Context
|
|
3
2
|
from telegrinder.types.enums import UpdateType
|
|
4
3
|
|
|
5
4
|
from .abc import ABCRule
|
|
@@ -9,7 +8,7 @@ class IsUpdateType(ABCRule):
|
|
|
9
8
|
def __init__(self, update_type: UpdateType, /) -> None:
|
|
10
9
|
self.update_type = update_type
|
|
11
10
|
|
|
12
|
-
async def check(self, event: UpdateCute
|
|
11
|
+
async def check(self, event: UpdateCute) -> bool:
|
|
13
12
|
return event.update_type == self.update_type
|
|
14
13
|
|
|
15
14
|
|
telegrinder/bot/scenario/abc.py
CHANGED
|
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from telegrinder.bot.cute_types.base import BaseCute
|
|
5
5
|
|
|
6
6
|
if typing.TYPE_CHECKING:
|
|
7
|
-
from telegrinder.api import
|
|
7
|
+
from telegrinder.api import API
|
|
8
8
|
from telegrinder.bot.dispatch.view.abc import ABCStateView
|
|
9
9
|
|
|
10
10
|
EventT = typing.TypeVar("EventT", bound=BaseCute)
|
|
@@ -12,7 +12,7 @@ EventT = typing.TypeVar("EventT", bound=BaseCute)
|
|
|
12
12
|
|
|
13
13
|
class ABCScenario(ABC, typing.Generic[EventT]):
|
|
14
14
|
@abstractmethod
|
|
15
|
-
def wait(self, api: "
|
|
15
|
+
def wait(self, api: "API", view: "ABCStateView[EventT]") -> typing.Any:
|
|
16
16
|
pass
|
|
17
17
|
|
|
18
18
|
|
|
@@ -4,12 +4,11 @@ import typing
|
|
|
4
4
|
|
|
5
5
|
from telegrinder.bot.cute_types import CallbackQueryCute
|
|
6
6
|
from telegrinder.bot.dispatch.waiter_machine import WaiterMachine
|
|
7
|
+
from telegrinder.bot.scenario.abc import ABCScenario
|
|
7
8
|
from telegrinder.tools import InlineButton, InlineKeyboard
|
|
8
9
|
from telegrinder.tools.parse_mode import ParseMode
|
|
9
10
|
from telegrinder.types.objects import InlineKeyboardMarkup
|
|
10
11
|
|
|
11
|
-
from .abc import ABCScenario
|
|
12
|
-
|
|
13
12
|
if typing.TYPE_CHECKING:
|
|
14
13
|
from telegrinder.api import API
|
|
15
14
|
from telegrinder.bot.dispatch.view.abc import BaseStateView
|
telegrinder/model.py
CHANGED
|
@@ -58,6 +58,11 @@ def get_params(params: dict[str, typing.Any]) -> dict[str, typing.Any]:
|
|
|
58
58
|
return validated_params
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
def encode_name(name: str) -> str:
|
|
62
|
+
# TODO
|
|
63
|
+
return MODEL_CONFIG.get("rename", {}).get(name, name)
|
|
64
|
+
|
|
65
|
+
|
|
61
66
|
class Model(msgspec.Struct, **MODEL_CONFIG):
|
|
62
67
|
@classmethod
|
|
63
68
|
def from_data(cls, data: dict[str, typing.Any]) -> typing.Self:
|
|
@@ -168,7 +173,7 @@ class DataConverter:
|
|
|
168
173
|
data: Model,
|
|
169
174
|
serialize: bool = True,
|
|
170
175
|
) -> str | dict[str, typing.Any]:
|
|
171
|
-
converted_dct = self(data.
|
|
176
|
+
converted_dct = self(data.to_dict(), serialize=False)
|
|
172
177
|
return encoder.encode(converted_dct) if serialize is True else converted_dct
|
|
173
178
|
|
|
174
179
|
def convert_dct(
|