telegrinder 0.3.4__py3-none-any.whl → 0.4.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.

Files changed (192) hide show
  1. telegrinder/__init__.py +148 -149
  2. telegrinder/api/__init__.py +9 -8
  3. telegrinder/api/api.py +101 -93
  4. telegrinder/api/error.py +20 -16
  5. telegrinder/api/response.py +20 -20
  6. telegrinder/api/token.py +36 -36
  7. telegrinder/bot/__init__.py +72 -66
  8. telegrinder/bot/bot.py +83 -76
  9. telegrinder/bot/cute_types/__init__.py +19 -17
  10. telegrinder/bot/cute_types/base.py +184 -258
  11. telegrinder/bot/cute_types/callback_query.py +400 -385
  12. telegrinder/bot/cute_types/chat_join_request.py +62 -61
  13. telegrinder/bot/cute_types/chat_member_updated.py +157 -160
  14. telegrinder/bot/cute_types/inline_query.py +44 -43
  15. telegrinder/bot/cute_types/message.py +2590 -2637
  16. telegrinder/bot/cute_types/pre_checkout_query.py +42 -0
  17. telegrinder/bot/cute_types/update.py +112 -104
  18. telegrinder/bot/cute_types/utils.py +62 -95
  19. telegrinder/bot/dispatch/__init__.py +59 -55
  20. telegrinder/bot/dispatch/abc.py +76 -77
  21. telegrinder/bot/dispatch/context.py +96 -98
  22. telegrinder/bot/dispatch/dispatch.py +254 -202
  23. telegrinder/bot/dispatch/handler/__init__.py +13 -13
  24. telegrinder/bot/dispatch/handler/abc.py +23 -24
  25. telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
  26. telegrinder/bot/dispatch/handler/base.py +57 -57
  27. telegrinder/bot/dispatch/handler/document_reply.py +44 -44
  28. telegrinder/bot/dispatch/handler/func.py +129 -135
  29. telegrinder/bot/dispatch/handler/media_group_reply.py +44 -43
  30. telegrinder/bot/dispatch/handler/message_reply.py +36 -36
  31. telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
  32. telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
  33. telegrinder/bot/dispatch/handler/video_reply.py +44 -44
  34. telegrinder/bot/dispatch/middleware/__init__.py +3 -3
  35. telegrinder/bot/dispatch/middleware/abc.py +97 -22
  36. telegrinder/bot/dispatch/middleware/global_middleware.py +70 -0
  37. telegrinder/bot/dispatch/process.py +151 -157
  38. telegrinder/bot/dispatch/return_manager/__init__.py +15 -13
  39. telegrinder/bot/dispatch/return_manager/abc.py +104 -108
  40. telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
  41. telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
  42. telegrinder/bot/dispatch/return_manager/message.py +36 -36
  43. telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +20 -0
  44. telegrinder/bot/dispatch/view/__init__.py +15 -13
  45. telegrinder/bot/dispatch/view/abc.py +45 -41
  46. telegrinder/bot/dispatch/view/base.py +231 -200
  47. telegrinder/bot/dispatch/view/box.py +140 -129
  48. telegrinder/bot/dispatch/view/callback_query.py +16 -17
  49. telegrinder/bot/dispatch/view/chat_join_request.py +11 -16
  50. telegrinder/bot/dispatch/view/chat_member.py +37 -39
  51. telegrinder/bot/dispatch/view/inline_query.py +16 -17
  52. telegrinder/bot/dispatch/view/message.py +43 -44
  53. telegrinder/bot/dispatch/view/pre_checkout_query.py +16 -0
  54. telegrinder/bot/dispatch/view/raw.py +116 -114
  55. telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
  56. telegrinder/bot/dispatch/waiter_machine/actions.py +14 -13
  57. telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
  58. telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
  59. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +59 -57
  60. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
  61. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +20 -19
  62. telegrinder/bot/dispatch/waiter_machine/machine.py +251 -172
  63. telegrinder/bot/dispatch/waiter_machine/middleware.py +94 -89
  64. telegrinder/bot/dispatch/waiter_machine/short_state.py +57 -68
  65. telegrinder/bot/polling/__init__.py +4 -4
  66. telegrinder/bot/polling/abc.py +25 -25
  67. telegrinder/bot/polling/polling.py +139 -131
  68. telegrinder/bot/rules/__init__.py +85 -62
  69. telegrinder/bot/rules/abc.py +213 -206
  70. telegrinder/bot/rules/callback_data.py +122 -163
  71. telegrinder/bot/rules/chat_join.py +45 -43
  72. telegrinder/bot/rules/command.py +126 -126
  73. telegrinder/bot/rules/enum_text.py +33 -36
  74. telegrinder/bot/rules/func.py +28 -26
  75. telegrinder/bot/rules/fuzzy.py +24 -24
  76. telegrinder/bot/rules/id.py +24 -0
  77. telegrinder/bot/rules/inline.py +58 -56
  78. telegrinder/bot/rules/integer.py +21 -20
  79. telegrinder/bot/rules/is_from.py +127 -127
  80. telegrinder/bot/rules/logic.py +18 -0
  81. telegrinder/bot/rules/markup.py +42 -43
  82. telegrinder/bot/rules/mention.py +14 -14
  83. telegrinder/bot/rules/message.py +15 -17
  84. telegrinder/bot/rules/message_entities.py +33 -35
  85. telegrinder/bot/rules/node.py +33 -27
  86. telegrinder/bot/rules/payload.py +81 -0
  87. telegrinder/bot/rules/payment_invoice.py +29 -0
  88. telegrinder/bot/rules/regex.py +36 -37
  89. telegrinder/bot/rules/rule_enum.py +72 -72
  90. telegrinder/bot/rules/start.py +42 -42
  91. telegrinder/bot/rules/state.py +35 -37
  92. telegrinder/bot/rules/text.py +38 -33
  93. telegrinder/bot/rules/update.py +15 -15
  94. telegrinder/bot/scenario/__init__.py +5 -5
  95. telegrinder/bot/scenario/abc.py +17 -19
  96. telegrinder/bot/scenario/checkbox.py +174 -176
  97. telegrinder/bot/scenario/choice.py +48 -51
  98. telegrinder/client/__init__.py +12 -4
  99. telegrinder/client/abc.py +100 -75
  100. telegrinder/client/aiohttp.py +134 -130
  101. telegrinder/client/form_data.py +31 -0
  102. telegrinder/client/sonic.py +212 -0
  103. telegrinder/model.py +208 -315
  104. telegrinder/modules.py +239 -237
  105. telegrinder/msgspec_json.py +14 -14
  106. telegrinder/msgspec_utils.py +478 -410
  107. telegrinder/node/__init__.py +86 -25
  108. telegrinder/node/attachment.py +163 -87
  109. telegrinder/node/base.py +288 -160
  110. telegrinder/node/callback_query.py +54 -53
  111. telegrinder/node/command.py +34 -33
  112. telegrinder/node/composer.py +163 -198
  113. telegrinder/node/container.py +33 -27
  114. telegrinder/node/either.py +82 -0
  115. telegrinder/node/event.py +54 -65
  116. telegrinder/node/file.py +51 -0
  117. telegrinder/node/me.py +15 -16
  118. telegrinder/node/payload.py +78 -0
  119. telegrinder/node/polymorphic.py +67 -48
  120. telegrinder/node/rule.py +72 -76
  121. telegrinder/node/scope.py +36 -38
  122. telegrinder/node/source.py +87 -71
  123. telegrinder/node/text.py +53 -41
  124. telegrinder/node/tools/__init__.py +3 -3
  125. telegrinder/node/tools/generator.py +36 -40
  126. telegrinder/py.typed +0 -0
  127. telegrinder/rules.py +1 -62
  128. telegrinder/tools/__init__.py +152 -93
  129. telegrinder/tools/adapter/__init__.py +19 -0
  130. telegrinder/tools/adapter/abc.py +49 -0
  131. telegrinder/tools/adapter/dataclass.py +56 -0
  132. telegrinder/{bot/rules → tools}/adapter/errors.py +5 -5
  133. telegrinder/{bot/rules → tools}/adapter/event.py +63 -65
  134. telegrinder/{bot/rules → tools}/adapter/node.py +46 -48
  135. telegrinder/{bot/rules → tools}/adapter/raw_event.py +27 -27
  136. telegrinder/{bot/rules → tools}/adapter/raw_update.py +30 -30
  137. telegrinder/tools/buttons.py +106 -80
  138. telegrinder/tools/callback_data_serilization/__init__.py +5 -0
  139. telegrinder/tools/callback_data_serilization/abc.py +51 -0
  140. telegrinder/tools/callback_data_serilization/json_ser.py +60 -0
  141. telegrinder/tools/callback_data_serilization/msgpack_ser.py +172 -0
  142. telegrinder/tools/error_handler/__init__.py +7 -7
  143. telegrinder/tools/error_handler/abc.py +30 -33
  144. telegrinder/tools/error_handler/error.py +9 -9
  145. telegrinder/tools/error_handler/error_handler.py +179 -193
  146. telegrinder/tools/formatting/__init__.py +83 -63
  147. telegrinder/tools/formatting/deep_links.py +541 -0
  148. telegrinder/tools/formatting/{html.py → html_formatter.py} +266 -294
  149. telegrinder/tools/formatting/spec_html_formats.py +71 -117
  150. telegrinder/tools/functional.py +8 -12
  151. telegrinder/tools/global_context/__init__.py +7 -7
  152. telegrinder/tools/global_context/abc.py +63 -63
  153. telegrinder/tools/global_context/global_context.py +387 -412
  154. telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
  155. telegrinder/tools/i18n/__init__.py +7 -7
  156. telegrinder/tools/i18n/abc.py +30 -30
  157. telegrinder/tools/i18n/middleware/__init__.py +3 -3
  158. telegrinder/tools/i18n/middleware/abc.py +22 -25
  159. telegrinder/tools/i18n/simple.py +43 -43
  160. telegrinder/tools/input_file_directory.py +30 -0
  161. telegrinder/tools/keyboard.py +128 -128
  162. telegrinder/tools/lifespan.py +105 -0
  163. telegrinder/tools/limited_dict.py +32 -37
  164. telegrinder/tools/loop_wrapper/__init__.py +4 -4
  165. telegrinder/tools/loop_wrapper/abc.py +20 -15
  166. telegrinder/tools/loop_wrapper/loop_wrapper.py +169 -224
  167. telegrinder/tools/magic.py +307 -157
  168. telegrinder/tools/parse_mode.py +6 -6
  169. telegrinder/tools/state_storage/__init__.py +4 -4
  170. telegrinder/tools/state_storage/abc.py +31 -35
  171. telegrinder/tools/state_storage/memory.py +25 -25
  172. telegrinder/tools/strings.py +13 -0
  173. telegrinder/types/__init__.py +268 -260
  174. telegrinder/types/enums.py +711 -701
  175. telegrinder/types/input_file.py +51 -0
  176. telegrinder/types/methods.py +5055 -4633
  177. telegrinder/types/objects.py +7058 -6950
  178. telegrinder/verification_utils.py +30 -32
  179. {telegrinder-0.3.4.dist-info → telegrinder-0.4.0.dist-info}/LICENSE +22 -22
  180. telegrinder-0.4.0.dist-info/METADATA +144 -0
  181. telegrinder-0.4.0.dist-info/RECORD +182 -0
  182. {telegrinder-0.3.4.dist-info → telegrinder-0.4.0.dist-info}/WHEEL +1 -1
  183. telegrinder/bot/rules/adapter/__init__.py +0 -17
  184. telegrinder/bot/rules/adapter/abc.py +0 -31
  185. telegrinder/node/message.py +0 -14
  186. telegrinder/node/update.py +0 -15
  187. telegrinder/tools/formatting/links.py +0 -38
  188. telegrinder/tools/kb_set/__init__.py +0 -4
  189. telegrinder/tools/kb_set/base.py +0 -15
  190. telegrinder/tools/kb_set/yaml.py +0 -63
  191. telegrinder-0.3.4.dist-info/METADATA +0 -110
  192. telegrinder-0.3.4.dist-info/RECORD +0 -165
@@ -1,43 +1,42 @@
1
- import typing
2
-
3
- import vbml
4
-
5
- from telegrinder.bot.dispatch.context import Context
6
- from telegrinder.node.text import Text
7
- from telegrinder.tools.global_context.telegrinder_ctx import TelegrinderContext
8
-
9
- from .abc import ABCRule
10
-
11
- PatternLike: typing.TypeAlias = str | vbml.Pattern
12
- global_ctx: typing.Final[TelegrinderContext] = TelegrinderContext()
13
-
14
-
15
- def check_string(patterns: list[vbml.Pattern], s: str, ctx: Context) -> bool:
16
- for pattern in patterns:
17
- match global_ctx.vbml_patcher.check(pattern, s):
18
- case None | False:
19
- continue
20
- case {**response}:
21
- ctx |= response
22
- return True
23
- return False
24
-
25
-
26
- class Markup(ABCRule):
27
- """Markup Language. See the [vbml documentation](https://github.com/tesseradecade/vbml/blob/master/docs/index.md)."""
28
-
29
- def __init__(self, patterns: PatternLike | list[PatternLike], /) -> None:
30
- if not isinstance(patterns, list):
31
- patterns = [patterns]
32
- self.patterns = [
33
- vbml.Pattern(pattern, flags=global_ctx.vbml_pattern_flags)
34
- if isinstance(pattern, str)
35
- else pattern
36
- for pattern in patterns
37
- ]
38
-
39
- def check(self, text: Text, ctx: Context) -> bool:
40
- return check_string(self.patterns, text, ctx)
41
-
42
-
43
- __all__ = ("Markup", "check_string")
1
+ import typing
2
+
3
+ import vbml
4
+
5
+ from telegrinder.bot.dispatch.context import Context
6
+ from telegrinder.node.either import Either
7
+ from telegrinder.node.text import Caption, Text
8
+ from telegrinder.tools.global_context.telegrinder_ctx import TelegrinderContext
9
+
10
+ from .abc import ABCRule
11
+
12
+ type PatternLike = str | vbml.Pattern
13
+ global_ctx: typing.Final[TelegrinderContext] = TelegrinderContext()
14
+
15
+
16
+ def check_string(patterns: list[vbml.Pattern], s: str, ctx: Context) -> bool:
17
+ for pattern in patterns:
18
+ match global_ctx.vbml_patcher.check(pattern, s):
19
+ case None | False:
20
+ continue
21
+ case {**response}:
22
+ ctx |= response
23
+ return True
24
+ return False
25
+
26
+
27
+ class Markup(ABCRule):
28
+ """Markup Language. See the [vbml documentation](https://github.com/tesseradecade/vbml/blob/master/docs/index.md)."""
29
+
30
+ def __init__(self, patterns: PatternLike | list[PatternLike], /) -> None:
31
+ if not isinstance(patterns, list):
32
+ patterns = [patterns]
33
+ self.patterns = [
34
+ vbml.Pattern(pattern, flags=global_ctx.vbml_pattern_flags) if isinstance(pattern, str) else pattern
35
+ for pattern in patterns
36
+ ]
37
+
38
+ def check(self, text: Either[Text, Caption], ctx: Context) -> bool:
39
+ return check_string(self.patterns, text, ctx)
40
+
41
+
42
+ __all__ = ("Markup", "check_string")
@@ -1,14 +1,14 @@
1
- from telegrinder.types.enums import MessageEntityType
2
-
3
- from .message import Message, MessageRule
4
- from .text import HasText
5
-
6
-
7
- class HasMention(MessageRule, requires=[HasText()]):
8
- def check(self, message: Message) -> bool:
9
- if not message.entities.unwrap_or_none():
10
- return False
11
- return any(entity.type == MessageEntityType.MENTION for entity in message.entities.unwrap())
12
-
13
-
14
- __all__ = ("HasMention",)
1
+ from telegrinder.types.enums import MessageEntityType
2
+
3
+ from .message import Message, MessageRule
4
+ from .text import HasText
5
+
6
+
7
+ class HasMention(MessageRule, requires=[HasText()]):
8
+ def check(self, message: Message) -> bool:
9
+ if not message.entities.unwrap_or_none():
10
+ return False
11
+ return any(entity.type == MessageEntityType.MENTION for entity in message.entities.unwrap())
12
+
13
+
14
+ __all__ = ("HasMention",)
@@ -1,17 +1,15 @@
1
- import abc
2
- import typing
3
-
4
- from telegrinder.types.objects import Message as MessageEvent
5
-
6
- from .abc import ABCRule, CheckResult, Message
7
- from .adapter import EventAdapter
8
-
9
-
10
- class MessageRule(ABCRule[Message], abc.ABC):
11
- adapter: EventAdapter[Message] = EventAdapter(MessageEvent, Message)
12
-
13
- @abc.abstractmethod
14
- def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
15
-
16
-
17
- __all__ = ("MessageRule",)
1
+ import abc
2
+ import typing
3
+
4
+ from telegrinder.tools.adapter.event import EventAdapter
5
+ from telegrinder.types.objects import Message as MessageEvent
6
+
7
+ from .abc import ABCRule, CheckResult, Message
8
+
9
+
10
+ class MessageRule(ABCRule[Message], abc.ABC, adapter=EventAdapter(MessageEvent, Message)):
11
+ @abc.abstractmethod
12
+ def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
13
+
14
+
15
+ __all__ = ("MessageRule",)
@@ -1,35 +1,33 @@
1
- import typing
2
-
3
- from telegrinder.bot.dispatch.context import Context
4
- from telegrinder.types.enums import MessageEntityType
5
- from telegrinder.types.objects import MessageEntity
6
-
7
- from .message import Message, MessageRule
8
-
9
- Entity: typing.TypeAlias = str | MessageEntityType
10
-
11
-
12
- class HasEntities(MessageRule):
13
- def check(self, message: Message) -> bool:
14
- return bool(message.entities)
15
-
16
-
17
- class MessageEntities(MessageRule, requires=[HasEntities()]):
18
- def __init__(self, entities: Entity | list[Entity], /) -> None:
19
- self.entities = [entities] if not isinstance(entities, list) else entities
20
-
21
- def check(self, message: Message, ctx: Context) -> bool:
22
- message_entities: list[MessageEntity] = []
23
- for entity in message.entities.unwrap():
24
- for entity_type in self.entities:
25
- if entity_type == entity.type:
26
- message_entities.append(entity)
27
-
28
- if not message_entities:
29
- return False
30
-
31
- ctx.message_entities = message_entities
32
- return True
33
-
34
-
35
- __all__ = ("HasEntities", "MessageEntities")
1
+ from telegrinder.bot.dispatch.context import Context
2
+ from telegrinder.types.enums import MessageEntityType
3
+ from telegrinder.types.objects import MessageEntity
4
+
5
+ from .message import Message, MessageRule
6
+
7
+ type Entity = str | MessageEntityType
8
+
9
+
10
+ class HasEntities(MessageRule):
11
+ def check(self, message: Message) -> bool:
12
+ return bool(message.entities)
13
+
14
+
15
+ class MessageEntities(MessageRule, requires=[HasEntities()]):
16
+ def __init__(self, entities: Entity | list[Entity], /) -> None:
17
+ self.entities = [entities] if not isinstance(entities, list) else entities
18
+
19
+ def check(self, message: Message, ctx: Context) -> bool:
20
+ message_entities: list[MessageEntity] = []
21
+ for entity in message.entities.unwrap():
22
+ for entity_type in self.entities:
23
+ if entity_type == entity.type:
24
+ message_entities.append(entity)
25
+
26
+ if not message_entities:
27
+ return False
28
+
29
+ ctx.message_entities = message_entities
30
+ return True
31
+
32
+
33
+ __all__ = ("HasEntities", "MessageEntities")
@@ -1,27 +1,33 @@
1
- import typing
2
-
3
- from telegrinder.bot.dispatch.context import Context
4
- from telegrinder.node.base import Node
5
-
6
- from .abc import ABCRule
7
- from .adapter.node import NodeAdapter
8
-
9
-
10
- class NodeRule(ABCRule[tuple[Node, ...]]):
11
- def __init__(self, *nodes: type[Node] | tuple[str, type[Node]]) -> None:
12
- bindings = [binding if isinstance(binding, tuple) else (None, binding) for binding in nodes]
13
- self.nodes = [binding[1] for binding in bindings]
14
- self.node_keys = [binding[0] for binding in bindings]
15
-
16
- @property
17
- def adapter(self) -> NodeAdapter:
18
- return NodeAdapter(*self.nodes) # type: ignore
19
-
20
- def check(self, resolved_nodes: tuple[Node, ...], ctx: Context) -> typing.Literal[True]:
21
- for i, node in enumerate(resolved_nodes):
22
- if key := self.node_keys[i]:
23
- ctx[key] = node
24
- return True
25
-
26
-
27
- __all__ = ("NodeRule",)
1
+ import typing
2
+
3
+ from telegrinder.bot.dispatch.context import Context
4
+ from telegrinder.node.base import IsNode, NodeType, is_node
5
+ from telegrinder.tools.adapter.node import NodeAdapter
6
+
7
+ from .abc import ABCRule
8
+
9
+
10
+ class NodeRule(ABCRule):
11
+ def __init__(self, *nodes: IsNode | tuple[str, IsNode]) -> None:
12
+ self.nodes: list[IsNode] = []
13
+ self.node_keys: list[str | None] = []
14
+
15
+ for binding in nodes:
16
+ node_key, node_t = binding if isinstance(binding, tuple) else (None, binding)
17
+ if not is_node(node_t):
18
+ continue
19
+ self.nodes.append(node_t)
20
+ self.node_keys.append(node_key)
21
+
22
+ @property
23
+ def adapter(self) -> NodeAdapter:
24
+ return NodeAdapter(*self.nodes)
25
+
26
+ def check(self, resolved_nodes: tuple[NodeType, ...], ctx: Context) -> typing.Literal[True]:
27
+ for i, node in enumerate(resolved_nodes):
28
+ if key := self.node_keys[i]:
29
+ ctx[key] = node
30
+ return True
31
+
32
+
33
+ __all__ = ("NodeRule",)
@@ -0,0 +1,81 @@
1
+ import typing
2
+ from contextlib import suppress
3
+ from functools import cached_property
4
+
5
+ import msgspec
6
+
7
+ from telegrinder.bot.dispatch.context import Context
8
+ from telegrinder.bot.rules.abc import ABCRule
9
+ from telegrinder.bot.rules.markup import Markup, PatternLike, check_string
10
+ from telegrinder.msgspec_json import loads
11
+ from telegrinder.node.base import Node
12
+ from telegrinder.node.payload import Payload, PayloadData
13
+ from telegrinder.tools.callback_data_serilization.abc import ABCDataSerializer, ModelType
14
+ from telegrinder.tools.callback_data_serilization.json_ser import JSONSerializer
15
+
16
+
17
+ class PayloadRule[Data](ABCRule):
18
+ def __init__(
19
+ self,
20
+ data_type: type[Data],
21
+ serializer: type[ABCDataSerializer[Data]],
22
+ *,
23
+ alias: str | None = None,
24
+ ) -> None:
25
+ self.data_type = data_type
26
+ self.serializer = serializer
27
+ self.alias = alias or "data"
28
+
29
+ @cached_property
30
+ def required_nodes(self) -> dict[str, type[Node]]:
31
+ return {"payload": PayloadData[self.data_type, self.serializer]} # type: ignore
32
+
33
+ def check(self, payload: PayloadData[Data], context: Context) -> typing.Literal[True]:
34
+ context.set(self.alias, payload)
35
+ return True
36
+
37
+
38
+ class PayloadModelRule[Model: ModelType](PayloadRule[Model]):
39
+ def __init__(
40
+ self,
41
+ model_t: type[Model],
42
+ *,
43
+ serializer: type[ABCDataSerializer[Model]] | None = None,
44
+ alias: str | None = None,
45
+ ) -> None:
46
+ super().__init__(model_t, serializer or JSONSerializer, alias=alias or "model")
47
+
48
+
49
+ class PayloadEqRule(ABCRule):
50
+ def __init__(self, payloads: str | list[str], /) -> None:
51
+ self.payloads = [payloads] if isinstance(payloads, str) else payloads
52
+
53
+ def check(self, payload: Payload) -> bool:
54
+ return any(p == payload for p in self.payloads)
55
+
56
+
57
+ class PayloadMarkupRule(ABCRule):
58
+ def __init__(self, pattern: PatternLike | list[PatternLike], /) -> None:
59
+ self.patterns = Markup(pattern).patterns
60
+
61
+ def check(self, payload: Payload, context: Context) -> bool:
62
+ return check_string(self.patterns, payload, context)
63
+
64
+
65
+ class PayloadJsonEqRule(ABCRule):
66
+ def __init__(self, payload: dict[str, typing.Any], /) -> None:
67
+ self.payload = payload
68
+
69
+ def check(self, payload: Payload) -> bool:
70
+ with suppress(msgspec.DecodeError, msgspec.ValidationError):
71
+ return self.payload == loads(payload)
72
+ return False
73
+
74
+
75
+ __all__ = (
76
+ "PayloadEqRule",
77
+ "PayloadJsonEqRule",
78
+ "PayloadMarkupRule",
79
+ "PayloadModelRule",
80
+ "PayloadRule",
81
+ )
@@ -0,0 +1,29 @@
1
+ import abc
2
+ import typing
3
+
4
+ from telegrinder.bot.cute_types.pre_checkout_query import PreCheckoutQueryCute
5
+ from telegrinder.bot.rules.abc import ABCRule, CheckResult
6
+ from telegrinder.tools.adapter.event import EventAdapter
7
+ from telegrinder.types.enums import Currency, UpdateType
8
+
9
+ PreCheckoutQuery: typing.TypeAlias = PreCheckoutQueryCute
10
+
11
+
12
+ class PaymentInvoiceRule(
13
+ ABCRule[PreCheckoutQuery],
14
+ abc.ABC,
15
+ adapter=EventAdapter(UpdateType.PRE_CHECKOUT_QUERY, PreCheckoutQuery),
16
+ ):
17
+ @abc.abstractmethod
18
+ def check(self, *args: typing.Any, **kwargs: typing.Any) -> CheckResult: ...
19
+
20
+
21
+ class PaymentInvoiceCurrency(PaymentInvoiceRule):
22
+ def __init__(self, currency: str | Currency, /) -> None:
23
+ self.currency = currency
24
+
25
+ def check(self, query: PreCheckoutQuery) -> bool:
26
+ return self.currency == query.currency
27
+
28
+
29
+ __all__ = ("PaymentInvoiceCurrency", "PaymentInvoiceRule")
@@ -1,37 +1,36 @@
1
- import re
2
- import typing
3
-
4
- from telegrinder.bot.dispatch.context import Context
5
- from telegrinder.node.text import Text
6
-
7
- from .abc import ABCRule
8
-
9
- PatternLike: typing.TypeAlias = str | typing.Pattern[str]
10
-
11
-
12
- class Regex(ABCRule):
13
- def __init__(self, regexp: PatternLike | list[PatternLike]) -> None:
14
- self.regexp: list[re.Pattern[str]] = []
15
- match regexp:
16
- case re.Pattern() as pattern:
17
- self.regexp.append(pattern)
18
- case str(regex):
19
- self.regexp.append(re.compile(regex))
20
- case _:
21
- self.regexp.extend(
22
- re.compile(regexp) if isinstance(regexp, str) else regexp for regexp in regexp
23
- )
24
-
25
- def check(self, text: Text, ctx: Context) -> bool:
26
- for regexp in self.regexp:
27
- response = re.match(regexp, text)
28
- if response is not None:
29
- if matches := response.groupdict():
30
- ctx |= matches
31
- else:
32
- ctx |= {"matches": response.groups() or (response.group(),)}
33
- return True
34
- return False
35
-
36
-
37
- __all__ = ("Regex",)
1
+ import re
2
+ import typing
3
+
4
+ from telegrinder.bot.dispatch.context import Context
5
+ from telegrinder.node.either import Either
6
+ from telegrinder.node.text import Caption, Text
7
+
8
+ from .abc import ABCRule
9
+
10
+ type PatternLike = str | typing.Pattern[str]
11
+
12
+
13
+ class Regex(ABCRule):
14
+ def __init__(self, regexp: PatternLike | list[PatternLike]) -> None:
15
+ self.regexp: list[re.Pattern[str]] = []
16
+ match regexp:
17
+ case re.Pattern() as pattern:
18
+ self.regexp.append(pattern)
19
+ case str(regex):
20
+ self.regexp.append(re.compile(regex))
21
+ case _:
22
+ self.regexp.extend(re.compile(regexp) if isinstance(regexp, str) else regexp for regexp in regexp)
23
+
24
+ def check(self, text: Either[Text, Caption], ctx: Context) -> bool:
25
+ for regexp in self.regexp:
26
+ response = re.match(regexp, text)
27
+ if response is not None:
28
+ if matches := response.groupdict():
29
+ ctx |= matches
30
+ else:
31
+ ctx |= {"matches": response.groups() or (response.group(),)}
32
+ return True
33
+ return False
34
+
35
+
36
+ __all__ = ("Regex",)
@@ -1,72 +1,72 @@
1
- import dataclasses
2
- import typing
3
-
4
- from telegrinder.bot.dispatch.context import Context
5
-
6
- from .abc import ABCRule, Update, check_rule
7
- from .func import FuncRule
8
-
9
-
10
- @dataclasses.dataclass(slots=True)
11
- class RuleEnumState:
12
- name: str
13
- rule: ABCRule
14
- cls: type["RuleEnum"]
15
-
16
- def __eq__(self, other: typing.Self) -> bool:
17
- return self.cls == other.cls and self.name == other.name
18
-
19
-
20
- class RuleEnum(ABCRule):
21
- __enum__: list[RuleEnumState]
22
-
23
- def __init_subclass__(cls, *args: typing.Any, **kwargs: typing.Any) -> None:
24
- new_attributes = set(cls.__dict__) - set(RuleEnum.__dict__) - {"__enum__", "__init__"}
25
- enum_lst: list[RuleEnumState] = []
26
-
27
- self = cls.__new__(cls)
28
- self.__init__()
29
-
30
- for attribute_name in new_attributes:
31
- rules = getattr(cls, attribute_name)
32
- attribute = RuleEnumState(attribute_name, rules, cls)
33
-
34
- setattr(
35
- self,
36
- attribute.name,
37
- self & FuncRule(lambda _, ctx: self.must_be_state(ctx, attribute)), # type: ignore
38
- )
39
- enum_lst.append(attribute)
40
-
41
- setattr(cls, "__enum__", enum_lst)
42
-
43
- @classmethod
44
- def save_state(cls, ctx: Context, enum: RuleEnumState) -> None:
45
- ctx.update({cls.__class__.__name__ + "_state": enum})
46
-
47
- @classmethod
48
- def check_state(cls, ctx: Context) -> RuleEnumState | None:
49
- return ctx.get(cls.__class__.__name__ + "_state")
50
-
51
- @classmethod
52
- def must_be_state(cls, ctx: Context, state: RuleEnumState) -> bool:
53
- real_state = cls.check_state(ctx)
54
- if not real_state:
55
- return False
56
- return real_state == state
57
-
58
- async def check(self, event: Update, ctx: Context) -> bool:
59
- if self.check_state(ctx):
60
- return True
61
-
62
- for enum in self.__enum__:
63
- ctx_copy = ctx.copy()
64
- if await check_rule(event.ctx_api, enum.rule, event, ctx_copy):
65
- ctx.update(ctx_copy)
66
- self.save_state(ctx, enum)
67
- return True
68
-
69
- return False
70
-
71
-
72
- __all__ = ("RuleEnum", "RuleEnumState")
1
+ import dataclasses
2
+ import typing
3
+
4
+ from telegrinder.bot.dispatch.context import Context
5
+
6
+ from .abc import ABCRule, Update, check_rule
7
+ from .func import FuncRule
8
+
9
+
10
+ @dataclasses.dataclass(slots=True)
11
+ class RuleEnumState:
12
+ name: str
13
+ rule: ABCRule
14
+ cls: type["RuleEnum"]
15
+
16
+ def __eq__(self, other: typing.Self) -> bool:
17
+ return self.cls == other.cls and self.name == other.name
18
+
19
+
20
+ class RuleEnum(ABCRule):
21
+ __enum__: list[RuleEnumState]
22
+
23
+ def __init_subclass__(cls, *args: typing.Any, **kwargs: typing.Any) -> None:
24
+ new_attributes = set(cls.__dict__) - set(RuleEnum.__dict__) - {"__enum__", "__init__"}
25
+ enum_lst: list[RuleEnumState] = []
26
+
27
+ self = cls.__new__(cls)
28
+ self.__init__()
29
+
30
+ for attribute_name in new_attributes:
31
+ rules = getattr(cls, attribute_name)
32
+ attribute = RuleEnumState(attribute_name, rules, cls)
33
+
34
+ setattr(
35
+ self,
36
+ attribute.name,
37
+ self & FuncRule(lambda _, ctx: self.must_be_state(ctx, attribute)), # type: ignore
38
+ )
39
+ enum_lst.append(attribute)
40
+
41
+ setattr(cls, "__enum__", enum_lst)
42
+
43
+ @classmethod
44
+ def save_state(cls, ctx: Context, enum: RuleEnumState) -> None:
45
+ ctx.update({cls.__class__.__name__ + "_state": enum})
46
+
47
+ @classmethod
48
+ def check_state(cls, ctx: Context) -> RuleEnumState | None:
49
+ return ctx.get(cls.__class__.__name__ + "_state")
50
+
51
+ @classmethod
52
+ def must_be_state(cls, ctx: Context, state: RuleEnumState) -> bool:
53
+ real_state = cls.check_state(ctx)
54
+ if not real_state:
55
+ return False
56
+ return real_state == state
57
+
58
+ async def check(self, event: Update, ctx: Context) -> bool:
59
+ if self.check_state(ctx):
60
+ return True
61
+
62
+ for enum in self.__enum__:
63
+ ctx_copy = ctx.copy()
64
+ if await check_rule(event.ctx_api, enum.rule, event, ctx_copy):
65
+ ctx.update(ctx_copy)
66
+ self.save_state(ctx, enum)
67
+ return True
68
+
69
+ return False
70
+
71
+
72
+ __all__ = ("RuleEnum", "RuleEnumState")