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.

Files changed (165) hide show
  1. telegrinder/__init__.py +144 -144
  2. telegrinder/api/__init__.py +8 -8
  3. telegrinder/api/api.py +93 -93
  4. telegrinder/api/error.py +16 -16
  5. telegrinder/api/response.py +20 -20
  6. telegrinder/api/token.py +36 -36
  7. telegrinder/bot/__init__.py +66 -66
  8. telegrinder/bot/bot.py +76 -76
  9. telegrinder/bot/cute_types/__init__.py +17 -17
  10. telegrinder/bot/cute_types/base.py +258 -258
  11. telegrinder/bot/cute_types/callback_query.py +385 -385
  12. telegrinder/bot/cute_types/chat_join_request.py +61 -61
  13. telegrinder/bot/cute_types/chat_member_updated.py +160 -160
  14. telegrinder/bot/cute_types/inline_query.py +43 -43
  15. telegrinder/bot/cute_types/message.py +2637 -2637
  16. telegrinder/bot/cute_types/update.py +104 -109
  17. telegrinder/bot/cute_types/utils.py +95 -95
  18. telegrinder/bot/dispatch/__init__.py +55 -55
  19. telegrinder/bot/dispatch/abc.py +77 -77
  20. telegrinder/bot/dispatch/context.py +98 -98
  21. telegrinder/bot/dispatch/dispatch.py +202 -202
  22. telegrinder/bot/dispatch/handler/__init__.py +13 -13
  23. telegrinder/bot/dispatch/handler/abc.py +24 -24
  24. telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
  25. telegrinder/bot/dispatch/handler/base.py +57 -57
  26. telegrinder/bot/dispatch/handler/document_reply.py +44 -44
  27. telegrinder/bot/dispatch/handler/func.py +135 -135
  28. telegrinder/bot/dispatch/handler/media_group_reply.py +43 -43
  29. telegrinder/bot/dispatch/handler/message_reply.py +36 -36
  30. telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
  31. telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
  32. telegrinder/bot/dispatch/handler/video_reply.py +44 -44
  33. telegrinder/bot/dispatch/middleware/__init__.py +3 -3
  34. telegrinder/bot/dispatch/middleware/abc.py +22 -16
  35. telegrinder/bot/dispatch/process.py +157 -132
  36. telegrinder/bot/dispatch/return_manager/__init__.py +13 -13
  37. telegrinder/bot/dispatch/return_manager/abc.py +108 -108
  38. telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
  39. telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
  40. telegrinder/bot/dispatch/return_manager/message.py +36 -36
  41. telegrinder/bot/dispatch/view/__init__.py +13 -13
  42. telegrinder/bot/dispatch/view/abc.py +41 -41
  43. telegrinder/bot/dispatch/view/base.py +200 -200
  44. telegrinder/bot/dispatch/view/box.py +129 -129
  45. telegrinder/bot/dispatch/view/callback_query.py +17 -17
  46. telegrinder/bot/dispatch/view/chat_join_request.py +16 -16
  47. telegrinder/bot/dispatch/view/chat_member.py +39 -39
  48. telegrinder/bot/dispatch/view/inline_query.py +17 -17
  49. telegrinder/bot/dispatch/view/message.py +44 -44
  50. telegrinder/bot/dispatch/view/raw.py +114 -114
  51. telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
  52. telegrinder/bot/dispatch/waiter_machine/actions.py +13 -13
  53. telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
  54. telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
  55. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
  56. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
  57. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
  58. telegrinder/bot/dispatch/waiter_machine/machine.py +172 -167
  59. telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
  60. telegrinder/bot/dispatch/waiter_machine/short_state.py +68 -68
  61. telegrinder/bot/polling/__init__.py +4 -4
  62. telegrinder/bot/polling/abc.py +25 -25
  63. telegrinder/bot/polling/polling.py +131 -131
  64. telegrinder/bot/rules/__init__.py +62 -62
  65. telegrinder/bot/rules/abc.py +213 -213
  66. telegrinder/bot/rules/adapter/__init__.py +12 -9
  67. telegrinder/bot/rules/adapter/abc.py +31 -29
  68. telegrinder/bot/rules/adapter/errors.py +5 -5
  69. telegrinder/bot/rules/adapter/event.py +65 -67
  70. telegrinder/bot/rules/adapter/node.py +48 -48
  71. telegrinder/bot/rules/adapter/raw_event.py +27 -0
  72. telegrinder/bot/rules/adapter/raw_update.py +30 -30
  73. telegrinder/bot/rules/callback_data.py +170 -170
  74. telegrinder/bot/rules/chat_join.py +46 -46
  75. telegrinder/bot/rules/command.py +126 -126
  76. telegrinder/bot/rules/enum_text.py +36 -36
  77. telegrinder/bot/rules/func.py +26 -26
  78. telegrinder/bot/rules/fuzzy.py +24 -24
  79. telegrinder/bot/rules/inline.py +60 -60
  80. telegrinder/bot/rules/integer.py +20 -20
  81. telegrinder/bot/rules/is_from.py +127 -127
  82. telegrinder/bot/rules/markup.py +43 -43
  83. telegrinder/bot/rules/mention.py +14 -14
  84. telegrinder/bot/rules/message.py +17 -17
  85. telegrinder/bot/rules/message_entities.py +35 -35
  86. telegrinder/bot/rules/node.py +27 -27
  87. telegrinder/bot/rules/regex.py +37 -37
  88. telegrinder/bot/rules/rule_enum.py +72 -72
  89. telegrinder/bot/rules/start.py +42 -42
  90. telegrinder/bot/rules/state.py +37 -37
  91. telegrinder/bot/rules/text.py +33 -33
  92. telegrinder/bot/rules/update.py +15 -15
  93. telegrinder/bot/scenario/__init__.py +5 -5
  94. telegrinder/bot/scenario/abc.py +19 -19
  95. telegrinder/bot/scenario/checkbox.py +176 -167
  96. telegrinder/bot/scenario/choice.py +51 -46
  97. telegrinder/client/__init__.py +4 -4
  98. telegrinder/client/abc.py +75 -75
  99. telegrinder/client/aiohttp.py +130 -130
  100. telegrinder/model.py +320 -295
  101. telegrinder/modules.py +237 -237
  102. telegrinder/msgspec_json.py +14 -14
  103. telegrinder/msgspec_utils.py +410 -410
  104. telegrinder/node/__init__.py +0 -0
  105. telegrinder/node/attachment.py +87 -87
  106. telegrinder/node/base.py +166 -166
  107. telegrinder/node/callback_query.py +53 -53
  108. telegrinder/node/command.py +33 -33
  109. telegrinder/node/composer.py +198 -198
  110. telegrinder/node/container.py +27 -27
  111. telegrinder/node/event.py +65 -65
  112. telegrinder/node/me.py +16 -16
  113. telegrinder/node/message.py +14 -14
  114. telegrinder/node/polymorphic.py +48 -48
  115. telegrinder/node/rule.py +76 -76
  116. telegrinder/node/scope.py +38 -38
  117. telegrinder/node/source.py +71 -71
  118. telegrinder/node/text.py +41 -41
  119. telegrinder/node/tools/__init__.py +3 -3
  120. telegrinder/node/tools/generator.py +40 -40
  121. telegrinder/node/update.py +15 -15
  122. telegrinder/rules.py +0 -0
  123. telegrinder/tools/__init__.py +74 -74
  124. telegrinder/tools/buttons.py +79 -79
  125. telegrinder/tools/error_handler/__init__.py +7 -7
  126. telegrinder/tools/error_handler/abc.py +33 -33
  127. telegrinder/tools/error_handler/error.py +9 -9
  128. telegrinder/tools/error_handler/error_handler.py +193 -193
  129. telegrinder/tools/formatting/__init__.py +46 -46
  130. telegrinder/tools/formatting/html.py +283 -283
  131. telegrinder/tools/formatting/links.py +33 -33
  132. telegrinder/tools/formatting/spec_html_formats.py +111 -111
  133. telegrinder/tools/functional.py +12 -12
  134. telegrinder/tools/global_context/__init__.py +7 -7
  135. telegrinder/tools/global_context/abc.py +63 -63
  136. telegrinder/tools/global_context/global_context.py +412 -412
  137. telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
  138. telegrinder/tools/i18n/__init__.py +7 -7
  139. telegrinder/tools/i18n/abc.py +30 -30
  140. telegrinder/tools/i18n/middleware/__init__.py +3 -3
  141. telegrinder/tools/i18n/middleware/abc.py +25 -25
  142. telegrinder/tools/i18n/simple.py +43 -43
  143. telegrinder/tools/kb_set/__init__.py +4 -4
  144. telegrinder/tools/kb_set/base.py +15 -15
  145. telegrinder/tools/kb_set/yaml.py +63 -63
  146. telegrinder/tools/keyboard.py +132 -132
  147. telegrinder/tools/limited_dict.py +37 -37
  148. telegrinder/tools/loop_wrapper/__init__.py +4 -4
  149. telegrinder/tools/loop_wrapper/abc.py +15 -15
  150. telegrinder/tools/loop_wrapper/loop_wrapper.py +224 -224
  151. telegrinder/tools/magic.py +157 -157
  152. telegrinder/tools/parse_mode.py +6 -6
  153. telegrinder/tools/state_storage/__init__.py +4 -4
  154. telegrinder/tools/state_storage/abc.py +35 -35
  155. telegrinder/tools/state_storage/memory.py +25 -25
  156. telegrinder/types/__init__.py +260 -260
  157. telegrinder/types/enums.py +701 -701
  158. telegrinder/types/methods.py +4633 -4633
  159. telegrinder/types/objects.py +6950 -8561
  160. telegrinder/verification_utils.py +32 -32
  161. {telegrinder-0.3.3.post1.dist-info → telegrinder-0.3.4.post1.dist-info}/LICENSE +22 -22
  162. {telegrinder-0.3.3.post1.dist-info → telegrinder-0.3.4.post1.dist-info}/METADATA +1 -1
  163. telegrinder-0.3.4.post1.dist-info/RECORD +165 -0
  164. telegrinder-0.3.3.post1.dist-info/RECORD +0 -164
  165. {telegrinder-0.3.3.post1.dist-info → telegrinder-0.3.4.post1.dist-info}/WHEEL +0 -0
@@ -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 PhotoReplyHandler(BaseReplyHandler):
12
- def __init__(
13
- self,
14
- photo: 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.photo = photo
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_photo if not self.as_reply else event.reply_photo
36
- await method(
37
- photo=self.photo,
38
- parse_mode=self.parse_mode,
39
- caption=self.caption,
40
- **self.default_params,
41
- )
42
-
43
-
44
- __all__ = ("PhotoReplyHandler",)
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 PhotoReplyHandler(BaseReplyHandler):
12
+ def __init__(
13
+ self,
14
+ photo: 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.photo = photo
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_photo if not self.as_reply else event.reply_photo
36
+ await method(
37
+ photo=self.photo,
38
+ parse_mode=self.parse_mode,
39
+ caption=self.caption,
40
+ **self.default_params,
41
+ )
42
+
43
+
44
+ __all__ = ("PhotoReplyHandler",)
@@ -1,37 +1,37 @@
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 StickerReplyHandler(BaseReplyHandler):
12
- def __init__(
13
- self,
14
- sticker: InputFile | str,
15
- *rules: ABCRule,
16
- emoji: 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.sticker = sticker
23
- self.emoji = emoji
24
- super().__init__(
25
- *rules,
26
- is_blocking=is_blocking,
27
- as_reply=as_reply,
28
- preset_context=preset_context,
29
- **default_params,
30
- )
31
-
32
- async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
33
- method = event.answer_sticker if not self.as_reply else event.reply_sticker
34
- await method(sticker=self.sticker, emoji=self.emoji, **self.default_params)
35
-
36
-
37
- __all__ = ("StickerReplyHandler",)
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 StickerReplyHandler(BaseReplyHandler):
12
+ def __init__(
13
+ self,
14
+ sticker: InputFile | str,
15
+ *rules: ABCRule,
16
+ emoji: 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.sticker = sticker
23
+ self.emoji = emoji
24
+ super().__init__(
25
+ *rules,
26
+ is_blocking=is_blocking,
27
+ as_reply=as_reply,
28
+ preset_context=preset_context,
29
+ **default_params,
30
+ )
31
+
32
+ async def run(self, _: API, event: MessageCute, __: Context) -> typing.Any:
33
+ method = event.answer_sticker if not self.as_reply else event.reply_sticker
34
+ await method(sticker=self.sticker, emoji=self.emoji, **self.default_params)
35
+
36
+
37
+ __all__ = ("StickerReplyHandler",)
@@ -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 VideoReplyHandler(BaseReplyHandler):
12
- def __init__(
13
- self,
14
- video: 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.video = video
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_video if not self.as_reply else event.reply_video
36
- await method(
37
- video=self.video,
38
- parse_mode=self.parse_mode,
39
- caption=self.caption,
40
- **self.default_params,
41
- )
42
-
43
-
44
- __all__ = ("VideoReplyHandler",)
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 VideoReplyHandler(BaseReplyHandler):
12
+ def __init__(
13
+ self,
14
+ video: 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.video = video
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_video if not self.as_reply else event.reply_video
36
+ await method(
37
+ video=self.video,
38
+ parse_mode=self.parse_mode,
39
+ caption=self.caption,
40
+ **self.default_params,
41
+ )
42
+
43
+
44
+ __all__ = ("VideoReplyHandler",)
@@ -1,3 +1,3 @@
1
- from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
2
-
3
- __all__ = ("ABCMiddleware",)
1
+ from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
2
+
3
+ __all__ = ("ABCMiddleware",)
@@ -1,16 +1,22 @@
1
- import typing
2
- from abc import ABC
3
-
4
- from telegrinder.bot.dispatch.context import Context
5
- from telegrinder.model import Model
6
-
7
- Event = typing.TypeVar("Event", bound=Model)
8
-
9
-
10
- class ABCMiddleware(ABC, typing.Generic[Event]):
11
- async def pre(self, event: Event, ctx: Context) -> bool: ...
12
-
13
- async def post(self, event: Event, responses: list[typing.Any], ctx: Context) -> None: ...
14
-
15
-
16
- __all__ = ("ABCMiddleware",)
1
+ import typing
2
+ from abc import ABC
3
+
4
+ from telegrinder.bot.dispatch.context import Context
5
+ from telegrinder.model import Model
6
+ from telegrinder.types.objects import Update
7
+
8
+ if typing.TYPE_CHECKING:
9
+ from telegrinder.bot.rules.adapter.abc import ABCAdapter
10
+
11
+ Event = typing.TypeVar("Event", bound=Model)
12
+
13
+
14
+ class ABCMiddleware(ABC, typing.Generic[Event]):
15
+ adapter: "ABCAdapter[Update, Event] | None" = None
16
+
17
+ async def pre(self, event: Event, ctx: Context) -> bool: ...
18
+
19
+ async def post(self, event: Event, responses: list[typing.Any], ctx: Context) -> None: ...
20
+
21
+
22
+ __all__ = ("ABCMiddleware",)
@@ -1,132 +1,157 @@
1
- import typing
2
-
3
- from fntypes.result import Error, Ok
4
-
5
- from telegrinder.api.api import API
6
- from telegrinder.bot.cute_types.update import UpdateCute
7
- from telegrinder.bot.dispatch.context import Context
8
- from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
9
- from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
10
- from telegrinder.model import Model
11
- from telegrinder.modules import logger
12
- from telegrinder.node.composer import CONTEXT_STORE_NODES_KEY, NodeScope, compose_nodes
13
- from telegrinder.tools.i18n.abc import I18nEnum
14
- from telegrinder.types.objects import Update
15
-
16
- if typing.TYPE_CHECKING:
17
- from telegrinder.bot.dispatch.handler.abc import ABCHandler
18
- from telegrinder.bot.rules.abc import ABCRule
19
-
20
- Event = typing.TypeVar("Event", bound=Model)
21
-
22
-
23
- async def process_inner(
24
- api: API,
25
- event: Event,
26
- raw_event: Update,
27
- middlewares: list[ABCMiddleware[Event]],
28
- handlers: list["ABCHandler[Event]"],
29
- return_manager: ABCReturnManager[Event] | None = None,
30
- ) -> bool:
31
- logger.debug("Processing {!r}...", event.__class__.__name__)
32
- ctx = Context(raw_update=raw_event)
33
- ctx[CONTEXT_STORE_NODES_KEY] = {} # For per-event shared nodes
34
-
35
- logger.debug("Run pre middlewares...")
36
- for middleware in middlewares:
37
- middleware_result = await middleware.pre(event, ctx)
38
- logger.debug("Middleware {!r} returned: {!r}", middleware.__class__.__qualname__, middleware_result)
39
- if middleware_result is False:
40
- return False
41
-
42
- found = False
43
- responses = []
44
- ctx_copy = ctx.copy()
45
-
46
- for handler in handlers:
47
- if await handler.check(api, raw_event, ctx):
48
- logger.debug("Handler {!r} matched, run...", handler)
49
- found = True
50
- response = await handler.run(api, event, ctx)
51
- logger.debug("Handler {!r} returned: {!r}", handler, response)
52
- responses.append(response)
53
- if return_manager is not None:
54
- await return_manager.run(response, event, ctx)
55
- if handler.is_blocking:
56
- break
57
-
58
- ctx = ctx_copy
59
-
60
- logger.debug("Run post middlewares...")
61
- for middleware in middlewares:
62
- logger.debug("Run post middleware {!r}", middleware.__class__.__qualname__)
63
- await middleware.post(event, responses, ctx)
64
-
65
- for session in ctx.get(CONTEXT_STORE_NODES_KEY, {}).values():
66
- await session.close(scopes=(NodeScope.PER_EVENT,))
67
-
68
- logger.debug(
69
- "{} handlers, returns {!r}",
70
- "No found" if not found else "Found",
71
- found,
72
- )
73
- return found
74
-
75
-
76
- async def check_rule(
77
- api: API,
78
- rule: "ABCRule",
79
- update: Update,
80
- ctx: Context,
81
- ) -> bool:
82
- """Checks requirements, adapts update.
83
- Returns check result."""
84
-
85
- # Running adapter
86
- match await rule.adapter.adapt(api, update, ctx):
87
- case Ok(value):
88
- adapted_value = value
89
- case Error(err):
90
- logger.debug("Adapter failed with error message: {!r}", str(err))
91
- return False
92
-
93
- # Preparing update
94
- if isinstance(adapted_val := ctx.get(rule.adapter.ADAPTED_VALUE_KEY or ""), UpdateCute):
95
- update = adapted_val
96
- elif isinstance(adapted_value, UpdateCute):
97
- update = adapted_value
98
- else:
99
- update = UpdateCute.from_update(update, bound_api=api)
100
-
101
- # Running subrules to fetch requirements
102
- ctx_copy = ctx.copy()
103
- for requirement in rule.requires:
104
- if not await check_rule(api, requirement, update, ctx_copy):
105
- return False
106
-
107
- # Translating translatable rules
108
- if I18nEnum.I18N in ctx:
109
- rule = await rule.translate(ctx[I18nEnum.I18N])
110
-
111
- ctx |= ctx_copy
112
-
113
- # Composing required nodes
114
- nodes = rule.required_nodes
115
- node_col = None
116
- if nodes:
117
- result = await compose_nodes(nodes, ctx, data={Update: update, API: api})
118
- if not result:
119
- return False
120
- node_col = result.value
121
-
122
- # Running check
123
- result = await rule.bounding_check(adapted_value, ctx, node_col=node_col)
124
-
125
- # Closing node sessions if there are any
126
- if node_col is not None:
127
- await node_col.close_all()
128
-
129
- return result
130
-
131
-
132
- __all__ = ("check_rule", "process_inner")
1
+ import inspect
2
+ import typing
3
+
4
+ from fntypes.option import Nothing, Option, Some
5
+ from fntypes.result import Error, Ok
6
+
7
+ from telegrinder.api.api import API
8
+ from telegrinder.bot.cute_types.update import UpdateCute
9
+ from telegrinder.bot.dispatch.context import Context
10
+ from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
11
+ from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
12
+ from telegrinder.model import Model
13
+ from telegrinder.modules import logger
14
+ from telegrinder.node.composer import CONTEXT_STORE_NODES_KEY, NodeScope, compose_nodes
15
+ from telegrinder.tools.i18n.abc import I18nEnum
16
+ from telegrinder.types.objects import Update
17
+
18
+ if typing.TYPE_CHECKING:
19
+ from telegrinder.bot.dispatch.handler.abc import ABCHandler
20
+ from telegrinder.bot.rules.abc import ABCRule
21
+ from telegrinder.bot.rules.adapter.abc import ABCAdapter
22
+
23
+ T = typing.TypeVar("T")
24
+ Event = typing.TypeVar("Event", bound=Model)
25
+
26
+
27
+ async def run_adapter(
28
+ adapter: "ABCAdapter[Update, T]",
29
+ api: API,
30
+ update: Update,
31
+ context: Context,
32
+ ) -> Option[T]:
33
+ adapt_result = adapter.adapt(api, update, context)
34
+ match await adapt_result if inspect.isawaitable(adapt_result) else adapt_result:
35
+ case Ok(value):
36
+ return Some(value)
37
+ case Error(err):
38
+ logger.debug("Adapter failed with error message: {!r}", str(err))
39
+ return Nothing()
40
+
41
+
42
+ async def process_inner(
43
+ api: API,
44
+ event: Event,
45
+ raw_event: Update,
46
+ middlewares: list[ABCMiddleware[Event]],
47
+ handlers: list["ABCHandler[Event]"],
48
+ return_manager: ABCReturnManager[Event] | None = None,
49
+ ) -> bool:
50
+ logger.debug("Processing {!r}...", event.__class__.__name__)
51
+ ctx = Context(raw_update=raw_event)
52
+ ctx[CONTEXT_STORE_NODES_KEY] = {} # For per-event shared nodes
53
+
54
+ logger.debug("Run pre middlewares...")
55
+ for middleware in middlewares:
56
+ if middleware.adapter is not None:
57
+ match await run_adapter(middleware.adapter, api, raw_event, ctx):
58
+ case Some(val):
59
+ event = val
60
+ case Nothing():
61
+ return False
62
+
63
+ middleware_result = await middleware.pre(event, ctx)
64
+ logger.debug("Middleware {!r} returned: {!r}", middleware.__class__.__qualname__, middleware_result)
65
+ if middleware_result is False:
66
+ return False
67
+
68
+ found = False
69
+ responses = []
70
+ ctx_copy = ctx.copy()
71
+
72
+ for handler in handlers:
73
+ if await handler.check(api, raw_event, ctx):
74
+ logger.debug("Handler {!r} matched, run...", handler)
75
+ found = True
76
+ response = await handler.run(api, event, ctx)
77
+ logger.debug("Handler {!r} returned: {!r}", handler, response)
78
+ responses.append(response)
79
+ if return_manager is not None:
80
+ await return_manager.run(response, event, ctx)
81
+ if handler.is_blocking:
82
+ break
83
+
84
+ ctx = ctx_copy
85
+
86
+ logger.debug("Run post middlewares...")
87
+ for middleware in middlewares:
88
+ logger.debug("Run post middleware {!r}", middleware.__class__.__qualname__)
89
+ await middleware.post(event, responses, ctx)
90
+
91
+ for session in ctx.get(CONTEXT_STORE_NODES_KEY, {}).values():
92
+ await session.close(scopes=(NodeScope.PER_EVENT,))
93
+
94
+ logger.debug(
95
+ "{} handlers, returns {!r}",
96
+ "No found" if not found else "Found",
97
+ found,
98
+ )
99
+ return found
100
+
101
+
102
+ async def check_rule(
103
+ api: API,
104
+ rule: "ABCRule",
105
+ update: Update,
106
+ ctx: Context,
107
+ ) -> bool:
108
+ """Checks requirements, adapts update.
109
+ Returns check result."""
110
+
111
+ # Running adapter
112
+ match await run_adapter(rule.adapter, api, update, ctx):
113
+ case Some(val):
114
+ adapted_value = val
115
+ case Nothing():
116
+ return False
117
+
118
+ # Preparing update
119
+ if isinstance(adapted_val := ctx.get(rule.adapter.ADAPTED_VALUE_KEY or ""), UpdateCute):
120
+ update = adapted_val
121
+ elif isinstance(adapted_value, UpdateCute):
122
+ update = adapted_value
123
+ else:
124
+ update = UpdateCute.from_update(update, bound_api=api)
125
+
126
+ # Running subrules to fetch requirements
127
+ ctx_copy = ctx.copy()
128
+ for requirement in rule.requires:
129
+ if not await check_rule(api, requirement, update, ctx_copy):
130
+ return False
131
+
132
+ # Translating translatable rules
133
+ if I18nEnum.I18N in ctx:
134
+ rule = await rule.translate(ctx[I18nEnum.I18N])
135
+
136
+ ctx |= ctx_copy
137
+
138
+ # Composing required nodes
139
+ nodes = rule.required_nodes
140
+ node_col = None
141
+ if nodes:
142
+ result = await compose_nodes(nodes, ctx, data={Update: update, API: api})
143
+ if not result:
144
+ return False
145
+ node_col = result.value
146
+
147
+ # Running check
148
+ result = await rule.bounding_check(adapted_value, ctx, node_col=node_col)
149
+
150
+ # Closing node sessions if there are any
151
+ if node_col is not None:
152
+ await node_col.close_all()
153
+
154
+ return result
155
+
156
+
157
+ __all__ = ("check_rule", "process_inner")
@@ -1,19 +1,19 @@
1
- from telegrinder.bot.dispatch.return_manager.abc import (
2
- ABCReturnManager,
3
- BaseReturnManager,
4
- Manager,
5
- register_manager,
6
- )
7
- from telegrinder.bot.dispatch.return_manager.callback_query import CallbackQueryReturnManager
8
- from telegrinder.bot.dispatch.return_manager.inline_query import InlineQueryReturnManager
9
- from telegrinder.bot.dispatch.return_manager.message import MessageReturnManager
10
-
11
- __all__ = (
1
+ from telegrinder.bot.dispatch.return_manager.abc import (
2
+ ABCReturnManager,
3
+ BaseReturnManager,
4
+ Manager,
5
+ register_manager,
6
+ )
7
+ from telegrinder.bot.dispatch.return_manager.callback_query import CallbackQueryReturnManager
8
+ from telegrinder.bot.dispatch.return_manager.inline_query import InlineQueryReturnManager
9
+ from telegrinder.bot.dispatch.return_manager.message import MessageReturnManager
10
+
11
+ __all__ = (
12
12
  "ABCReturnManager",
13
13
  "BaseReturnManager",
14
14
  "CallbackQueryReturnManager",
15
15
  "InlineQueryReturnManager",
16
16
  "Manager",
17
17
  "MessageReturnManager",
18
- "register_manager",
19
- )
18
+ "register_manager",
19
+ )