telegrinder 0.3.4__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 -104
  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 -22
  35. telegrinder/bot/dispatch/process.py +157 -157
  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 -172
  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 +206 -206
  66. telegrinder/bot/rules/adapter/__init__.py +17 -17
  67. telegrinder/bot/rules/adapter/abc.py +31 -31
  68. telegrinder/bot/rules/adapter/errors.py +5 -5
  69. telegrinder/bot/rules/adapter/event.py +65 -65
  70. telegrinder/bot/rules/adapter/node.py +48 -48
  71. telegrinder/bot/rules/adapter/raw_event.py +27 -27
  72. telegrinder/bot/rules/adapter/raw_update.py +30 -30
  73. telegrinder/bot/rules/callback_data.py +163 -163
  74. telegrinder/bot/rules/chat_join.py +43 -43
  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 +56 -56
  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 -176
  96. telegrinder/bot/scenario/choice.py +51 -51
  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 +313 -313
  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 +20 -20
  105. telegrinder/node/attachment.py +87 -87
  106. telegrinder/node/base.py +157 -157
  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 +5 -5
  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 +128 -128
  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 -6950
  160. telegrinder/verification_utils.py +32 -32
  161. {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/LICENSE +22 -22
  162. {telegrinder-0.3.4.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.4.dist-info/RECORD +0 -165
  165. {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/WHEEL +0 -0
@@ -1,176 +1,176 @@
1
- import dataclasses
2
- import enum
3
- import secrets
4
- import typing
5
-
6
- from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
7
- from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
8
- from telegrinder.bot.dispatch.waiter_machine.machine import WaiterMachine
9
- from telegrinder.bot.scenario.abc import ABCScenario
10
- from telegrinder.tools.keyboard import InlineButton, InlineKeyboard
11
- from telegrinder.tools.parse_mode import ParseMode
12
- from telegrinder.types.objects import InlineKeyboardMarkup
13
-
14
- if typing.TYPE_CHECKING:
15
- from telegrinder.api.api import API
16
- from telegrinder.bot.dispatch.view.base import BaseStateView
17
-
18
- Key = typing.TypeVar("Key", bound=typing.Hashable)
19
-
20
-
21
- class ChoiceCode(enum.StrEnum):
22
- READY = "ready"
23
- CANCEL = "cancel"
24
-
25
-
26
- @dataclasses.dataclass(slots=True)
27
- class Choice(typing.Generic[Key]):
28
- key: Key
29
- is_picked: bool
30
- default_text: str
31
- picked_text: str
32
- code: str
33
-
34
-
35
- class _Checkbox(ABCScenario[CallbackQueryCute]):
36
- INVALID_CODE = "Invalid code"
37
- CALLBACK_ANSWER = "Done"
38
- PARSE_MODE = ParseMode.HTML
39
-
40
- def __init__(
41
- self,
42
- waiter_machine: WaiterMachine,
43
- chat_id: int,
44
- message: str,
45
- *,
46
- ready_text: str = "Ready",
47
- cancel_text: str | None = None,
48
- max_in_row: int = 3,
49
- ) -> None:
50
- self.chat_id = chat_id
51
- self.message = message
52
- self.choices: list[Choice[typing.Hashable]] = []
53
- self.ready = ready_text
54
- self.max_in_row = max_in_row
55
- self.random_code = secrets.token_hex(8)
56
- self.waiter_machine = waiter_machine
57
- self.cancel_text = cancel_text
58
-
59
- def __repr__(self) -> str:
60
- return (
61
- "<{}@{!r}: (choices={!r}, max_in_row={}) with waiter_machine={!r}, ready_text={!r} "
62
- "for chat_id={} with message={!r}>"
63
- ).format(
64
- self.__class__.__name__,
65
- self.random_code,
66
- self.choices,
67
- self.max_in_row,
68
- self.waiter_machine,
69
- self.ready,
70
- self.chat_id,
71
- self.message,
72
- )
73
-
74
- def get_markup(self) -> InlineKeyboardMarkup:
75
- kb = InlineKeyboard()
76
- choices = self.choices.copy()
77
- while choices:
78
- while len(kb.keyboard[-1]) < self.max_in_row and choices:
79
- choice = choices.pop(0)
80
- kb.add(
81
- InlineButton(
82
- text=(choice.default_text if not choice.is_picked else choice.picked_text),
83
- callback_data=self.random_code + "/" + choice.code,
84
- )
85
- )
86
- kb.row()
87
-
88
- kb.add(InlineButton(self.ready, callback_data=self.random_code + "/" + ChoiceCode.READY))
89
- if self.cancel_text is not None:
90
- kb.row()
91
- kb.add(InlineButton(self.cancel_text, callback_data=self.random_code + "/" + ChoiceCode.CANCEL))
92
-
93
- return kb.get_markup()
94
-
95
- def add_option(
96
- self,
97
- key: Key,
98
- default_text: str,
99
- picked_text: str,
100
- *,
101
- is_picked: bool = False,
102
- ) -> "Checkbox[Key]":
103
- self.choices.append(
104
- Choice(key, is_picked, default_text, picked_text, secrets.token_hex(8)),
105
- )
106
- return self # type: ignore
107
-
108
- async def handle(self, cb: CallbackQueryCute) -> bool:
109
- code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
110
-
111
- match code:
112
- case ChoiceCode.READY:
113
- return False
114
- case ChoiceCode.CANCEL:
115
- self.choices = []
116
- return False
117
-
118
- for i, choice in enumerate(self.choices):
119
- if choice.code == code:
120
- # Toggle choice
121
- self.choices[i].is_picked = not self.choices[i].is_picked
122
- await cb.edit_text(
123
- text=self.message,
124
- parse_mode=self.PARSE_MODE,
125
- reply_markup=self.get_markup(),
126
- )
127
- break
128
-
129
- return True
130
-
131
- async def wait(
132
- self,
133
- hasher: Hasher[CallbackQueryCute, int],
134
- api: "API",
135
- view: "BaseStateView[CallbackQueryCute]",
136
- ) -> tuple[dict[typing.Hashable, bool], int]:
137
- assert len(self.choices) > 0
138
- message = (
139
- await api.send_message(
140
- chat_id=self.chat_id,
141
- text=self.message,
142
- parse_mode=self.PARSE_MODE,
143
- reply_markup=self.get_markup(),
144
- )
145
- ).unwrap()
146
-
147
- while True:
148
- q, _ = await self.waiter_machine.wait(hasher, message.message_id)
149
- should_continue = await self.handle(q)
150
- await q.answer(self.CALLBACK_ANSWER)
151
- if not should_continue:
152
- break
153
-
154
- return (
155
- {choice.key: choice.is_picked for choice in self.choices},
156
- message.message_id,
157
- )
158
-
159
-
160
- if typing.TYPE_CHECKING:
161
-
162
- class Checkbox(_Checkbox, typing.Generic[Key]):
163
- choices: list[Choice[Key]]
164
-
165
- async def wait(
166
- self,
167
- hasher: Hasher[CallbackQueryCute, int],
168
- api: "API",
169
- view: "BaseStateView[CallbackQueryCute]",
170
- ) -> tuple[dict[Key, bool], int]: ...
171
-
172
- else:
173
- Checkbox = _Checkbox
174
-
175
-
176
- __all__ = ("Checkbox", "Choice")
1
+ import dataclasses
2
+ import enum
3
+ import secrets
4
+ import typing
5
+
6
+ from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
7
+ from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
8
+ from telegrinder.bot.dispatch.waiter_machine.machine import WaiterMachine
9
+ from telegrinder.bot.scenario.abc import ABCScenario
10
+ from telegrinder.tools.keyboard import InlineButton, InlineKeyboard
11
+ from telegrinder.tools.parse_mode import ParseMode
12
+ from telegrinder.types.objects import InlineKeyboardMarkup
13
+
14
+ if typing.TYPE_CHECKING:
15
+ from telegrinder.api.api import API
16
+ from telegrinder.bot.dispatch.view.base import BaseStateView
17
+
18
+ Key = typing.TypeVar("Key", bound=typing.Hashable)
19
+
20
+
21
+ class ChoiceCode(enum.StrEnum):
22
+ READY = "ready"
23
+ CANCEL = "cancel"
24
+
25
+
26
+ @dataclasses.dataclass(slots=True)
27
+ class Choice(typing.Generic[Key]):
28
+ key: Key
29
+ is_picked: bool
30
+ default_text: str
31
+ picked_text: str
32
+ code: str
33
+
34
+
35
+ class _Checkbox(ABCScenario[CallbackQueryCute]):
36
+ INVALID_CODE = "Invalid code"
37
+ CALLBACK_ANSWER = "Done"
38
+ PARSE_MODE = ParseMode.HTML
39
+
40
+ def __init__(
41
+ self,
42
+ waiter_machine: WaiterMachine,
43
+ chat_id: int,
44
+ message: str,
45
+ *,
46
+ ready_text: str = "Ready",
47
+ cancel_text: str | None = None,
48
+ max_in_row: int = 3,
49
+ ) -> None:
50
+ self.chat_id = chat_id
51
+ self.message = message
52
+ self.choices: list[Choice[typing.Hashable]] = []
53
+ self.ready = ready_text
54
+ self.max_in_row = max_in_row
55
+ self.random_code = secrets.token_hex(8)
56
+ self.waiter_machine = waiter_machine
57
+ self.cancel_text = cancel_text
58
+
59
+ def __repr__(self) -> str:
60
+ return (
61
+ "<{}@{!r}: (choices={!r}, max_in_row={}) with waiter_machine={!r}, ready_text={!r} "
62
+ "for chat_id={} with message={!r}>"
63
+ ).format(
64
+ self.__class__.__name__,
65
+ self.random_code,
66
+ self.choices,
67
+ self.max_in_row,
68
+ self.waiter_machine,
69
+ self.ready,
70
+ self.chat_id,
71
+ self.message,
72
+ )
73
+
74
+ def get_markup(self) -> InlineKeyboardMarkup:
75
+ kb = InlineKeyboard()
76
+ choices = self.choices.copy()
77
+ while choices:
78
+ while len(kb.keyboard[-1]) < self.max_in_row and choices:
79
+ choice = choices.pop(0)
80
+ kb.add(
81
+ InlineButton(
82
+ text=(choice.default_text if not choice.is_picked else choice.picked_text),
83
+ callback_data=self.random_code + "/" + choice.code,
84
+ )
85
+ )
86
+ kb.row()
87
+
88
+ kb.add(InlineButton(self.ready, callback_data=self.random_code + "/" + ChoiceCode.READY))
89
+ if self.cancel_text is not None:
90
+ kb.row()
91
+ kb.add(InlineButton(self.cancel_text, callback_data=self.random_code + "/" + ChoiceCode.CANCEL))
92
+
93
+ return kb.get_markup()
94
+
95
+ def add_option(
96
+ self,
97
+ key: Key,
98
+ default_text: str,
99
+ picked_text: str,
100
+ *,
101
+ is_picked: bool = False,
102
+ ) -> "Checkbox[Key]":
103
+ self.choices.append(
104
+ Choice(key, is_picked, default_text, picked_text, secrets.token_hex(8)),
105
+ )
106
+ return self # type: ignore
107
+
108
+ async def handle(self, cb: CallbackQueryCute) -> bool:
109
+ code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
110
+
111
+ match code:
112
+ case ChoiceCode.READY:
113
+ return False
114
+ case ChoiceCode.CANCEL:
115
+ self.choices = []
116
+ return False
117
+
118
+ for i, choice in enumerate(self.choices):
119
+ if choice.code == code:
120
+ # Toggle choice
121
+ self.choices[i].is_picked = not self.choices[i].is_picked
122
+ await cb.edit_text(
123
+ text=self.message,
124
+ parse_mode=self.PARSE_MODE,
125
+ reply_markup=self.get_markup(),
126
+ )
127
+ break
128
+
129
+ return True
130
+
131
+ async def wait(
132
+ self,
133
+ hasher: Hasher[CallbackQueryCute, int],
134
+ api: "API",
135
+ view: "BaseStateView[CallbackQueryCute]",
136
+ ) -> tuple[dict[typing.Hashable, bool], int]:
137
+ assert len(self.choices) > 0
138
+ message = (
139
+ await api.send_message(
140
+ chat_id=self.chat_id,
141
+ text=self.message,
142
+ parse_mode=self.PARSE_MODE,
143
+ reply_markup=self.get_markup(),
144
+ )
145
+ ).unwrap()
146
+
147
+ while True:
148
+ q, _ = await self.waiter_machine.wait(hasher, message.message_id)
149
+ should_continue = await self.handle(q)
150
+ await q.answer(self.CALLBACK_ANSWER)
151
+ if not should_continue:
152
+ break
153
+
154
+ return (
155
+ {choice.key: choice.is_picked for choice in self.choices},
156
+ message.message_id,
157
+ )
158
+
159
+
160
+ if typing.TYPE_CHECKING:
161
+
162
+ class Checkbox(_Checkbox, typing.Generic[Key]):
163
+ choices: list[Choice[Key]]
164
+
165
+ async def wait(
166
+ self,
167
+ hasher: Hasher[CallbackQueryCute, int],
168
+ api: "API",
169
+ view: "BaseStateView[CallbackQueryCute]",
170
+ ) -> tuple[dict[Key, bool], int]: ...
171
+
172
+ else:
173
+ Checkbox = _Checkbox
174
+
175
+
176
+ __all__ = ("Checkbox", "Choice")
@@ -1,51 +1,51 @@
1
- import typing
2
-
3
- from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
4
- from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
5
- from telegrinder.bot.scenario.checkbox import Checkbox, ChoiceCode
6
-
7
- if typing.TYPE_CHECKING:
8
- from telegrinder.api.api import API
9
- from telegrinder.bot.dispatch.view.base import BaseStateView
10
- from telegrinder.bot.scenario.checkbox import Key
11
-
12
- class Choice(Checkbox[Key], typing.Generic[Key]):
13
- async def wait(
14
- self,
15
- hasher: Hasher[CallbackQueryCute, int],
16
- api: API,
17
- view: BaseStateView[CallbackQueryCute],
18
- ) -> tuple[Key, int]: ...
19
-
20
- else:
21
-
22
- class Choice(Checkbox):
23
- async def handle(self, cb):
24
- code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
25
- if code == ChoiceCode.READY:
26
- return False
27
-
28
- for choice in self.choices:
29
- choice.is_picked = False
30
-
31
- for i, choice in enumerate(self.choices):
32
- if choice.code == code:
33
- self.choices[i].is_picked = True
34
- await cb.ctx_api.edit_message_text(
35
- text=self.message,
36
- chat_id=cb.message.unwrap().v.chat.id,
37
- message_id=cb.message.unwrap().v.message_id,
38
- parse_mode=self.PARSE_MODE,
39
- reply_markup=self.get_markup(),
40
- )
41
-
42
- return True
43
-
44
- async def wait(self, hasher, api, view):
45
- if len(tuple(choice for choice in self.choices if choice.is_picked)) != 1:
46
- raise ValueError("Exactly one choice must be picked")
47
- choices, m_id = await super().wait(hasher, api, view)
48
- return tuple(choices.keys())[tuple(choices.values()).index(True)], m_id
49
-
50
-
51
- __all__ = ("Choice",)
1
+ import typing
2
+
3
+ from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
4
+ from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
5
+ from telegrinder.bot.scenario.checkbox import Checkbox, ChoiceCode
6
+
7
+ if typing.TYPE_CHECKING:
8
+ from telegrinder.api.api import API
9
+ from telegrinder.bot.dispatch.view.base import BaseStateView
10
+ from telegrinder.bot.scenario.checkbox import Key
11
+
12
+ class Choice(Checkbox[Key], typing.Generic[Key]):
13
+ async def wait(
14
+ self,
15
+ hasher: Hasher[CallbackQueryCute, int],
16
+ api: API,
17
+ view: BaseStateView[CallbackQueryCute],
18
+ ) -> tuple[Key, int]: ...
19
+
20
+ else:
21
+
22
+ class Choice(Checkbox):
23
+ async def handle(self, cb):
24
+ code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
25
+ if code == ChoiceCode.READY:
26
+ return False
27
+
28
+ for choice in self.choices:
29
+ choice.is_picked = False
30
+
31
+ for i, choice in enumerate(self.choices):
32
+ if choice.code == code:
33
+ self.choices[i].is_picked = True
34
+ await cb.ctx_api.edit_message_text(
35
+ text=self.message,
36
+ chat_id=cb.message.unwrap().v.chat.id,
37
+ message_id=cb.message.unwrap().v.message_id,
38
+ parse_mode=self.PARSE_MODE,
39
+ reply_markup=self.get_markup(),
40
+ )
41
+
42
+ return True
43
+
44
+ async def wait(self, hasher, api, view):
45
+ if len(tuple(choice for choice in self.choices if choice.is_picked)) != 1:
46
+ raise ValueError("Exactly one choice must be picked")
47
+ choices, m_id = await super().wait(hasher, api, view)
48
+ return tuple(choices.keys())[tuple(choices.values()).index(True)], m_id
49
+
50
+
51
+ __all__ = ("Choice",)
@@ -1,4 +1,4 @@
1
- from .abc import ABCClient
2
- from .aiohttp import AiohttpClient
3
-
4
- __all__ = ("ABCClient", "AiohttpClient")
1
+ from .abc import ABCClient
2
+ from .aiohttp import AiohttpClient
3
+
4
+ __all__ = ("ABCClient", "AiohttpClient")
telegrinder/client/abc.py CHANGED
@@ -1,75 +1,75 @@
1
- import typing
2
- from abc import ABC, abstractmethod
3
-
4
-
5
- class ABCClient(ABC):
6
- @abstractmethod
7
- def __init__(self, *args: typing.Any, **kwargs: typing.Any):
8
- pass
9
-
10
- @abstractmethod
11
- async def request_text(
12
- self,
13
- url: str,
14
- method: str = "GET",
15
- data: dict[str, typing.Any] | None = None,
16
- **kwargs: typing.Any,
17
- ) -> str:
18
- pass
19
-
20
- @abstractmethod
21
- async def request_json(
22
- self,
23
- url: str,
24
- method: str = "GET",
25
- data: dict[str, typing.Any] | None = None,
26
- **kwargs: typing.Any,
27
- ) -> dict[str, typing.Any]:
28
- pass
29
-
30
- @abstractmethod
31
- async def request_content(
32
- self,
33
- url: str,
34
- method: str = "GET",
35
- data: dict[str, typing.Any] | None = None,
36
- **kwargs: typing.Any,
37
- ) -> bytes:
38
- pass
39
-
40
- @abstractmethod
41
- async def request_bytes(
42
- self,
43
- url: str,
44
- method: str = "GET",
45
- data: dict[str, typing.Any] | None = None,
46
- **kwargs: typing.Any,
47
- ) -> bytes:
48
- pass
49
-
50
- @abstractmethod
51
- async def close(self) -> None:
52
- pass
53
-
54
- @classmethod
55
- @abstractmethod
56
- def get_form(
57
- cls,
58
- data: dict[str, typing.Any],
59
- files: dict[str, tuple[str, bytes]] | None = None,
60
- ) -> typing.Any:
61
- pass
62
-
63
- async def __aenter__(self) -> typing.Self:
64
- return self
65
-
66
- async def __aexit__(
67
- self,
68
- exc_type: type[BaseException],
69
- exc_val: typing.Any,
70
- exc_tb: typing.Any,
71
- ) -> None:
72
- await self.close()
73
-
74
-
75
- __all__ = ("ABCClient",)
1
+ import typing
2
+ from abc import ABC, abstractmethod
3
+
4
+
5
+ class ABCClient(ABC):
6
+ @abstractmethod
7
+ def __init__(self, *args: typing.Any, **kwargs: typing.Any):
8
+ pass
9
+
10
+ @abstractmethod
11
+ async def request_text(
12
+ self,
13
+ url: str,
14
+ method: str = "GET",
15
+ data: dict[str, typing.Any] | None = None,
16
+ **kwargs: typing.Any,
17
+ ) -> str:
18
+ pass
19
+
20
+ @abstractmethod
21
+ async def request_json(
22
+ self,
23
+ url: str,
24
+ method: str = "GET",
25
+ data: dict[str, typing.Any] | None = None,
26
+ **kwargs: typing.Any,
27
+ ) -> dict[str, typing.Any]:
28
+ pass
29
+
30
+ @abstractmethod
31
+ async def request_content(
32
+ self,
33
+ url: str,
34
+ method: str = "GET",
35
+ data: dict[str, typing.Any] | None = None,
36
+ **kwargs: typing.Any,
37
+ ) -> bytes:
38
+ pass
39
+
40
+ @abstractmethod
41
+ async def request_bytes(
42
+ self,
43
+ url: str,
44
+ method: str = "GET",
45
+ data: dict[str, typing.Any] | None = None,
46
+ **kwargs: typing.Any,
47
+ ) -> bytes:
48
+ pass
49
+
50
+ @abstractmethod
51
+ async def close(self) -> None:
52
+ pass
53
+
54
+ @classmethod
55
+ @abstractmethod
56
+ def get_form(
57
+ cls,
58
+ data: dict[str, typing.Any],
59
+ files: dict[str, tuple[str, bytes]] | None = None,
60
+ ) -> typing.Any:
61
+ pass
62
+
63
+ async def __aenter__(self) -> typing.Self:
64
+ return self
65
+
66
+ async def __aexit__(
67
+ self,
68
+ exc_type: type[BaseException],
69
+ exc_val: typing.Any,
70
+ exc_tb: typing.Any,
71
+ ) -> None:
72
+ await self.close()
73
+
74
+
75
+ __all__ = ("ABCClient",)