telegrinder 0.3.1__py3-none-any.whl → 0.3.2__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 (164) 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 +11 -11
  10. telegrinder/bot/cute_types/base.py +258 -234
  11. telegrinder/bot/cute_types/callback_query.py +382 -382
  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 +53 -53
  15. telegrinder/bot/cute_types/message.py +2631 -2631
  16. telegrinder/bot/cute_types/update.py +75 -75
  17. telegrinder/bot/cute_types/utils.py +92 -92
  18. telegrinder/bot/dispatch/__init__.py +55 -55
  19. telegrinder/bot/dispatch/abc.py +77 -77
  20. telegrinder/bot/dispatch/context.py +92 -92
  21. telegrinder/bot/dispatch/dispatch.py +202 -201
  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 +128 -123
  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 +16 -16
  35. telegrinder/bot/dispatch/process.py +132 -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 -211
  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 -118
  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 +57 -57
  55. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
  56. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +53 -53
  57. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
  58. telegrinder/bot/dispatch/waiter_machine/machine.py +168 -170
  59. telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
  60. telegrinder/bot/dispatch/waiter_machine/short_state.py +65 -65
  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 +238 -238
  66. telegrinder/bot/rules/adapter/__init__.py +9 -9
  67. telegrinder/bot/rules/adapter/abc.py +29 -29
  68. telegrinder/bot/rules/adapter/errors.py +5 -5
  69. telegrinder/bot/rules/adapter/event.py +76 -76
  70. telegrinder/bot/rules/adapter/node.py +48 -48
  71. telegrinder/bot/rules/adapter/raw_update.py +30 -30
  72. telegrinder/bot/rules/callback_data.py +171 -171
  73. telegrinder/bot/rules/chat_join.py +48 -48
  74. telegrinder/bot/rules/command.py +126 -126
  75. telegrinder/bot/rules/enum_text.py +36 -36
  76. telegrinder/bot/rules/func.py +26 -26
  77. telegrinder/bot/rules/fuzzy.py +24 -24
  78. telegrinder/bot/rules/inline.py +60 -60
  79. telegrinder/bot/rules/integer.py +20 -20
  80. telegrinder/bot/rules/is_from.py +146 -146
  81. telegrinder/bot/rules/markup.py +43 -43
  82. telegrinder/bot/rules/mention.py +14 -14
  83. telegrinder/bot/rules/message.py +17 -17
  84. telegrinder/bot/rules/message_entities.py +35 -35
  85. telegrinder/bot/rules/node.py +27 -27
  86. telegrinder/bot/rules/regex.py +37 -37
  87. telegrinder/bot/rules/rule_enum.py +72 -72
  88. telegrinder/bot/rules/start.py +42 -42
  89. telegrinder/bot/rules/state.py +37 -37
  90. telegrinder/bot/rules/text.py +33 -33
  91. telegrinder/bot/rules/update.py +15 -15
  92. telegrinder/bot/scenario/__init__.py +5 -5
  93. telegrinder/bot/scenario/abc.py +19 -19
  94. telegrinder/bot/scenario/checkbox.py +167 -147
  95. telegrinder/bot/scenario/choice.py +46 -44
  96. telegrinder/client/__init__.py +4 -4
  97. telegrinder/client/abc.py +75 -75
  98. telegrinder/client/aiohttp.py +130 -130
  99. telegrinder/model.py +244 -244
  100. telegrinder/modules.py +237 -237
  101. telegrinder/msgspec_json.py +14 -14
  102. telegrinder/msgspec_utils.py +410 -410
  103. telegrinder/node/__init__.py +20 -20
  104. telegrinder/node/attachment.py +92 -92
  105. telegrinder/node/base.py +143 -144
  106. telegrinder/node/callback_query.py +14 -14
  107. telegrinder/node/command.py +33 -33
  108. telegrinder/node/composer.py +196 -184
  109. telegrinder/node/container.py +27 -27
  110. telegrinder/node/event.py +71 -73
  111. telegrinder/node/me.py +16 -16
  112. telegrinder/node/message.py +14 -14
  113. telegrinder/node/polymorphic.py +48 -52
  114. telegrinder/node/rule.py +76 -76
  115. telegrinder/node/scope.py +38 -38
  116. telegrinder/node/source.py +71 -71
  117. telegrinder/node/text.py +21 -21
  118. telegrinder/node/tools/__init__.py +3 -3
  119. telegrinder/node/tools/generator.py +40 -40
  120. telegrinder/node/update.py +15 -15
  121. telegrinder/rules.py +0 -0
  122. telegrinder/tools/__init__.py +74 -74
  123. telegrinder/tools/buttons.py +79 -79
  124. telegrinder/tools/error_handler/__init__.py +7 -7
  125. telegrinder/tools/error_handler/abc.py +33 -33
  126. telegrinder/tools/error_handler/error.py +9 -9
  127. telegrinder/tools/error_handler/error_handler.py +193 -193
  128. telegrinder/tools/formatting/__init__.py +46 -46
  129. telegrinder/tools/formatting/html.py +308 -308
  130. telegrinder/tools/formatting/links.py +33 -33
  131. telegrinder/tools/formatting/spec_html_formats.py +111 -111
  132. telegrinder/tools/functional.py +12 -12
  133. telegrinder/tools/global_context/__init__.py +7 -7
  134. telegrinder/tools/global_context/abc.py +63 -63
  135. telegrinder/tools/global_context/global_context.py +412 -412
  136. telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
  137. telegrinder/tools/i18n/__init__.py +12 -12
  138. telegrinder/tools/i18n/abc.py +32 -32
  139. telegrinder/tools/i18n/middleware/__init__.py +3 -3
  140. telegrinder/tools/i18n/middleware/abc.py +25 -25
  141. telegrinder/tools/i18n/simple.py +43 -43
  142. telegrinder/tools/kb_set/__init__.py +4 -4
  143. telegrinder/tools/kb_set/base.py +15 -15
  144. telegrinder/tools/kb_set/yaml.py +63 -63
  145. telegrinder/tools/keyboard.py +128 -128
  146. telegrinder/tools/limited_dict.py +37 -37
  147. telegrinder/tools/loop_wrapper/__init__.py +4 -4
  148. telegrinder/tools/loop_wrapper/abc.py +15 -15
  149. telegrinder/tools/loop_wrapper/loop_wrapper.py +216 -216
  150. telegrinder/tools/magic.py +168 -168
  151. telegrinder/tools/parse_mode.py +6 -6
  152. telegrinder/tools/state_storage/__init__.py +4 -4
  153. telegrinder/tools/state_storage/abc.py +35 -35
  154. telegrinder/tools/state_storage/memory.py +25 -25
  155. telegrinder/types/__init__.py +6 -6
  156. telegrinder/types/enums.py +672 -672
  157. telegrinder/types/methods.py +4633 -4633
  158. telegrinder/types/objects.py +6317 -6317
  159. telegrinder/verification_utils.py +32 -32
  160. {telegrinder-0.3.1.dist-info → telegrinder-0.3.2.dist-info}/LICENSE +22 -22
  161. {telegrinder-0.3.1.dist-info → telegrinder-0.3.2.dist-info}/METADATA +1 -1
  162. telegrinder-0.3.2.dist-info/RECORD +164 -0
  163. telegrinder-0.3.1.dist-info/RECORD +0 -164
  164. {telegrinder-0.3.1.dist-info → telegrinder-0.3.2.dist-info}/WHEEL +0 -0
@@ -1,147 +1,167 @@
1
- import dataclasses
2
- import secrets
3
- import typing
4
-
5
- from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
6
- from telegrinder.bot.dispatch.waiter_machine import StateViewHasher, WaiterMachine
7
- from telegrinder.bot.scenario.abc import ABCScenario
8
- from telegrinder.tools.keyboard import InlineButton, InlineKeyboard
9
- from telegrinder.tools.parse_mode import ParseMode
10
- from telegrinder.types.objects import InlineKeyboardMarkup
11
-
12
- if typing.TYPE_CHECKING:
13
- from telegrinder.api import API
14
- from telegrinder.bot.dispatch.view.base import BaseStateView
15
-
16
-
17
- @dataclasses.dataclass(slots=True)
18
- class Choice:
19
- name: str
20
- is_picked: bool
21
- default_text: str
22
- picked_text: str
23
- code: str
24
-
25
-
26
- class Checkbox(ABCScenario[CallbackQueryCute]):
27
- INVALID_CODE = "Invalid code"
28
- CALLBACK_ANSWER = "Done"
29
- PARSE_MODE = ParseMode.HTML
30
-
31
- def __init__(
32
- self,
33
- waiter_machine: WaiterMachine,
34
- chat_id: int,
35
- message: str,
36
- *,
37
- ready_text: str = "Ready",
38
- cancel_text: str | None = None,
39
- max_in_row: int = 3,
40
- ) -> None:
41
- self.chat_id = chat_id
42
- self.message = message
43
- self.choices: list[Choice] = []
44
- self.ready = ready_text
45
- self.max_in_row = max_in_row
46
- self.random_code = secrets.token_hex(8)
47
- self.waiter_machine = waiter_machine
48
- self.cancel_text = cancel_text
49
-
50
- def __repr__(self) -> str:
51
- return (
52
- "<{}@{!r}: (choices={!r}, max_in_row={}) with waiter_machine={!r}, ready_text={!r} "
53
- "for chat_id={} with message={!r}>"
54
- ).format(
55
- self.__class__.__name__,
56
- self.random_code,
57
- self.choices,
58
- self.max_in_row,
59
- self.waiter_machine,
60
- self.ready,
61
- self.chat_id,
62
- self.message,
63
- )
64
-
65
- def get_markup(self) -> InlineKeyboardMarkup:
66
- kb = InlineKeyboard()
67
- choices = self.choices.copy()
68
- while choices:
69
- while len(kb.keyboard[-1]) < self.max_in_row and choices:
70
- choice = choices.pop(0)
71
- kb.add(
72
- InlineButton(
73
- text=(choice.default_text if not choice.is_picked else choice.picked_text),
74
- callback_data=self.random_code + "/" + choice.code,
75
- )
76
- )
77
- kb.row()
78
-
79
- kb.add(InlineButton(self.ready, callback_data=self.random_code + "/ready"))
80
- if self.cancel_text is not None:
81
- kb.row()
82
- kb.add(InlineButton(self.cancel_text, callback_data=self.random_code + "/cancel"))
83
- return kb.get_markup()
84
-
85
- def add_option(
86
- self,
87
- name: str,
88
- default_text: str,
89
- picked_text: str,
90
- *,
91
- is_picked: bool = False,
92
- ) -> typing.Self:
93
- self.choices.append(
94
- Choice(name, is_picked, default_text, picked_text, secrets.token_hex(8)),
95
- )
96
- return self
97
-
98
- async def handle(self, cb: CallbackQueryCute) -> bool:
99
- code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
100
- if code == "ready":
101
- return False
102
- elif code == "cancel":
103
- self.choices = []
104
- return False
105
-
106
- for i, choice in enumerate(self.choices):
107
- if choice.code == code:
108
- # Toggle choice
109
- self.choices[i].is_picked = not self.choices[i].is_picked
110
- await cb.edit_text(
111
- text=self.message,
112
- parse_mode=self.PARSE_MODE,
113
- reply_markup=self.get_markup(),
114
- )
115
- break
116
-
117
- return True
118
-
119
- async def wait(
120
- self,
121
- api: "API",
122
- view: "BaseStateView[CallbackQueryCute]",
123
- ) -> tuple[dict[str, bool], int]:
124
- assert len(self.choices) > 0
125
- message = (
126
- await api.send_message(
127
- chat_id=self.chat_id,
128
- text=self.message,
129
- parse_mode=self.PARSE_MODE,
130
- reply_markup=self.get_markup(),
131
- )
132
- ).unwrap()
133
-
134
- while True:
135
- q, _ = await self.waiter_machine.wait(StateViewHasher(view), message.message_id)
136
- should_continue = await self.handle(q)
137
- await q.answer(self.CALLBACK_ANSWER)
138
- if not should_continue:
139
- break
140
-
141
- return (
142
- {choice.name: choice.is_picked for choice in self.choices},
143
- message.message_id,
144
- )
145
-
146
-
147
- __all__ = ("Checkbox", "Choice")
1
+ import dataclasses
2
+ import secrets
3
+ import typing
4
+
5
+ from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
6
+ from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
7
+ from telegrinder.bot.dispatch.waiter_machine.machine import WaiterMachine
8
+ from telegrinder.bot.scenario.abc import ABCScenario
9
+ from telegrinder.tools.keyboard import InlineButton, InlineKeyboard
10
+ from telegrinder.tools.parse_mode import ParseMode
11
+ from telegrinder.types.objects import InlineKeyboardMarkup
12
+
13
+ if typing.TYPE_CHECKING:
14
+ from telegrinder.api.api import API
15
+ from telegrinder.bot.dispatch.view.base import BaseStateView
16
+
17
+ Key = typing.TypeVar("Key", bound=typing.Hashable)
18
+
19
+
20
+ @dataclasses.dataclass(slots=True)
21
+ class Choice(typing.Generic[Key]):
22
+ key: Key
23
+ is_picked: bool
24
+ default_text: str
25
+ picked_text: str
26
+ code: str
27
+
28
+
29
+ class _Checkbox(ABCScenario[CallbackQueryCute]):
30
+ INVALID_CODE = "Invalid code"
31
+ CALLBACK_ANSWER = "Done"
32
+ PARSE_MODE = ParseMode.HTML
33
+
34
+ def __init__(
35
+ self,
36
+ waiter_machine: WaiterMachine,
37
+ chat_id: int,
38
+ message: str,
39
+ *,
40
+ ready_text: str = "Ready",
41
+ cancel_text: str | None = None,
42
+ max_in_row: int = 3,
43
+ ) -> None:
44
+ self.chat_id = chat_id
45
+ self.message = message
46
+ self.choices: list[Choice[typing.Hashable]] = []
47
+ self.ready = ready_text
48
+ self.max_in_row = max_in_row
49
+ self.random_code = secrets.token_hex(8)
50
+ self.waiter_machine = waiter_machine
51
+ self.cancel_text = cancel_text
52
+
53
+ def __repr__(self) -> str:
54
+ return (
55
+ "<{}@{!r}: (choices={!r}, max_in_row={}) with waiter_machine={!r}, ready_text={!r} "
56
+ "for chat_id={} with message={!r}>"
57
+ ).format(
58
+ self.__class__.__name__,
59
+ self.random_code,
60
+ self.choices,
61
+ self.max_in_row,
62
+ self.waiter_machine,
63
+ self.ready,
64
+ self.chat_id,
65
+ self.message,
66
+ )
67
+
68
+ def get_markup(self) -> InlineKeyboardMarkup:
69
+ kb = InlineKeyboard()
70
+ choices = self.choices.copy()
71
+ while choices:
72
+ while len(kb.keyboard[-1]) < self.max_in_row and choices:
73
+ choice = choices.pop(0)
74
+ kb.add(
75
+ InlineButton(
76
+ text=(choice.default_text if not choice.is_picked else choice.picked_text),
77
+ callback_data=self.random_code + "/" + choice.code,
78
+ )
79
+ )
80
+ kb.row()
81
+
82
+ kb.add(InlineButton(self.ready, callback_data=self.random_code + "/ready"))
83
+ if self.cancel_text is not None:
84
+ kb.row()
85
+ kb.add(InlineButton(self.cancel_text, callback_data=self.random_code + "/cancel"))
86
+ return kb.get_markup()
87
+
88
+ def add_option(
89
+ self,
90
+ key: Key,
91
+ default_text: str,
92
+ picked_text: str,
93
+ *,
94
+ is_picked: bool = False,
95
+ ) -> "Checkbox[Key]":
96
+ self.choices.append(
97
+ Choice(key, is_picked, default_text, picked_text, secrets.token_hex(8)),
98
+ )
99
+ return self # type: ignore
100
+
101
+ async def handle(self, cb: CallbackQueryCute) -> bool:
102
+ code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
103
+ if code == "ready":
104
+ return False
105
+ elif code == "cancel":
106
+ self.choices = []
107
+ return False
108
+
109
+ for i, choice in enumerate(self.choices):
110
+ if choice.code == code:
111
+ # Toggle choice
112
+ self.choices[i].is_picked = not self.choices[i].is_picked
113
+ await cb.edit_text(
114
+ text=self.message,
115
+ parse_mode=self.PARSE_MODE,
116
+ reply_markup=self.get_markup(),
117
+ )
118
+ break
119
+
120
+ return True
121
+
122
+ async def wait(
123
+ self,
124
+ hasher: Hasher[CallbackQueryCute, int],
125
+ api: "API",
126
+ view: "BaseStateView[CallbackQueryCute]",
127
+ ) -> tuple[dict[typing.Hashable, bool], int]:
128
+ assert len(self.choices) > 0
129
+ message = (
130
+ await api.send_message(
131
+ chat_id=self.chat_id,
132
+ text=self.message,
133
+ parse_mode=self.PARSE_MODE,
134
+ reply_markup=self.get_markup(),
135
+ )
136
+ ).unwrap()
137
+
138
+ while True:
139
+ q, _ = await self.waiter_machine.wait(hasher, message.message_id)
140
+ should_continue = await self.handle(q)
141
+ await q.answer(self.CALLBACK_ANSWER)
142
+ if not should_continue:
143
+ break
144
+
145
+ return (
146
+ {choice.key: choice.is_picked for choice in self.choices},
147
+ message.message_id,
148
+ )
149
+
150
+
151
+ if typing.TYPE_CHECKING:
152
+
153
+ class Checkbox(_Checkbox, typing.Generic[Key]):
154
+ choices: list[Choice[Key]]
155
+
156
+ async def wait(
157
+ self,
158
+ hasher: Hasher[CallbackQueryCute, int],
159
+ api: "API",
160
+ view: "BaseStateView[CallbackQueryCute]",
161
+ ) -> tuple[dict[Key, bool], int]: ...
162
+
163
+ else:
164
+ Checkbox = _Checkbox
165
+
166
+
167
+ __all__ = ("Checkbox", "Choice")
@@ -1,44 +1,46 @@
1
- import typing
2
-
3
- from telegrinder.bot.cute_types.callback_query import CallbackQueryCute
4
- from telegrinder.bot.scenario.checkbox import Checkbox
5
-
6
- if typing.TYPE_CHECKING:
7
- from telegrinder.api import API
8
- from telegrinder.bot.dispatch.view.base import BaseStateView
9
-
10
-
11
- class Choice(Checkbox):
12
- async def handle(self, cb: CallbackQueryCute) -> bool:
13
- code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
14
- if code == "ready":
15
- return False
16
-
17
- for choice in self.choices:
18
- choice.is_picked = False
19
-
20
- for i, choice in enumerate(self.choices):
21
- if choice.code == code:
22
- self.choices[i].is_picked = True
23
- await cb.ctx_api.edit_message_text(
24
- text=self.message,
25
- chat_id=cb.message.unwrap().v.chat.id,
26
- message_id=cb.message.unwrap().v.message_id,
27
- parse_mode=self.PARSE_MODE,
28
- reply_markup=self.get_markup(),
29
- )
30
-
31
- return True
32
-
33
- async def wait(
34
- self,
35
- api: "API",
36
- view: "BaseStateView[CallbackQueryCute]",
37
- ) -> tuple[str, int]:
38
- if len(tuple(choice for choice in self.choices if choice.is_picked)) != 1:
39
- raise ValueError("Exactly one choice must be picked")
40
- choices, m_id = await super().wait(api, view)
41
- return tuple(choices.keys())[tuple(choices.values()).index(True)], m_id
42
-
43
-
44
- __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
6
+
7
+ if typing.TYPE_CHECKING:
8
+ from telegrinder.api import API
9
+ from telegrinder.bot.dispatch.view.base import BaseStateView
10
+
11
+
12
+ class Choice(Checkbox):
13
+ async def handle(self, cb: CallbackQueryCute) -> bool:
14
+ code = cb.data.unwrap().replace(self.random_code + "/", "", 1)
15
+ if code == "ready":
16
+ return False
17
+
18
+ for choice in self.choices:
19
+ choice.is_picked = False
20
+
21
+ for i, choice in enumerate(self.choices):
22
+ if choice.code == code:
23
+ self.choices[i].is_picked = True
24
+ await cb.ctx_api.edit_message_text(
25
+ text=self.message,
26
+ chat_id=cb.message.unwrap().v.chat.id,
27
+ message_id=cb.message.unwrap().v.message_id,
28
+ parse_mode=self.PARSE_MODE,
29
+ reply_markup=self.get_markup(),
30
+ )
31
+
32
+ return True
33
+
34
+ async def wait(
35
+ self,
36
+ hasher: Hasher[CallbackQueryCute, int],
37
+ api: "API",
38
+ view: "BaseStateView[CallbackQueryCute]",
39
+ ) -> tuple[str, int]:
40
+ if len(tuple(choice for choice in self.choices if choice.is_picked)) != 1:
41
+ raise ValueError("Exactly one choice must be picked")
42
+ choices, m_id = await super().wait(hasher, api, view)
43
+ return tuple(choices.keys())[tuple(choices.values()).index(True)], m_id
44
+
45
+
46
+ __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",)