telegrinder 0.3.4.post1__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 (169) hide show
  1. telegrinder/__init__.py +30 -31
  2. telegrinder/api/__init__.py +2 -1
  3. telegrinder/api/api.py +28 -20
  4. telegrinder/api/error.py +8 -4
  5. telegrinder/api/response.py +2 -2
  6. telegrinder/api/token.py +2 -2
  7. telegrinder/bot/__init__.py +6 -0
  8. telegrinder/bot/bot.py +38 -31
  9. telegrinder/bot/cute_types/__init__.py +2 -0
  10. telegrinder/bot/cute_types/base.py +54 -128
  11. telegrinder/bot/cute_types/callback_query.py +76 -61
  12. telegrinder/bot/cute_types/chat_join_request.py +4 -3
  13. telegrinder/bot/cute_types/chat_member_updated.py +28 -31
  14. telegrinder/bot/cute_types/inline_query.py +5 -4
  15. telegrinder/bot/cute_types/message.py +555 -602
  16. telegrinder/bot/cute_types/pre_checkout_query.py +42 -0
  17. telegrinder/bot/cute_types/update.py +20 -12
  18. telegrinder/bot/cute_types/utils.py +3 -36
  19. telegrinder/bot/dispatch/__init__.py +4 -0
  20. telegrinder/bot/dispatch/abc.py +8 -9
  21. telegrinder/bot/dispatch/context.py +5 -7
  22. telegrinder/bot/dispatch/dispatch.py +85 -33
  23. telegrinder/bot/dispatch/handler/abc.py +5 -6
  24. telegrinder/bot/dispatch/handler/audio_reply.py +2 -2
  25. telegrinder/bot/dispatch/handler/base.py +3 -3
  26. telegrinder/bot/dispatch/handler/document_reply.py +2 -2
  27. telegrinder/bot/dispatch/handler/func.py +36 -42
  28. telegrinder/bot/dispatch/handler/media_group_reply.py +5 -4
  29. telegrinder/bot/dispatch/handler/message_reply.py +2 -2
  30. telegrinder/bot/dispatch/handler/photo_reply.py +2 -2
  31. telegrinder/bot/dispatch/handler/sticker_reply.py +2 -2
  32. telegrinder/bot/dispatch/handler/video_reply.py +2 -2
  33. telegrinder/bot/dispatch/middleware/abc.py +83 -8
  34. telegrinder/bot/dispatch/middleware/global_middleware.py +70 -0
  35. telegrinder/bot/dispatch/process.py +44 -50
  36. telegrinder/bot/dispatch/return_manager/__init__.py +2 -0
  37. telegrinder/bot/dispatch/return_manager/abc.py +6 -10
  38. telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +20 -0
  39. telegrinder/bot/dispatch/view/__init__.py +2 -0
  40. telegrinder/bot/dispatch/view/abc.py +10 -6
  41. telegrinder/bot/dispatch/view/base.py +81 -50
  42. telegrinder/bot/dispatch/view/box.py +20 -9
  43. telegrinder/bot/dispatch/view/callback_query.py +3 -4
  44. telegrinder/bot/dispatch/view/chat_join_request.py +2 -7
  45. telegrinder/bot/dispatch/view/chat_member.py +3 -5
  46. telegrinder/bot/dispatch/view/inline_query.py +3 -4
  47. telegrinder/bot/dispatch/view/message.py +3 -4
  48. telegrinder/bot/dispatch/view/pre_checkout_query.py +16 -0
  49. telegrinder/bot/dispatch/view/raw.py +42 -40
  50. telegrinder/bot/dispatch/waiter_machine/actions.py +5 -4
  51. telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +0 -0
  52. telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +0 -0
  53. telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +9 -7
  54. telegrinder/bot/dispatch/waiter_machine/hasher/message.py +0 -0
  55. telegrinder/bot/dispatch/waiter_machine/hasher/state.py +3 -2
  56. telegrinder/bot/dispatch/waiter_machine/machine.py +113 -34
  57. telegrinder/bot/dispatch/waiter_machine/middleware.py +15 -10
  58. telegrinder/bot/dispatch/waiter_machine/short_state.py +7 -18
  59. telegrinder/bot/polling/polling.py +62 -54
  60. telegrinder/bot/rules/__init__.py +24 -1
  61. telegrinder/bot/rules/abc.py +17 -10
  62. telegrinder/bot/rules/callback_data.py +20 -61
  63. telegrinder/bot/rules/chat_join.py +6 -4
  64. telegrinder/bot/rules/command.py +4 -4
  65. telegrinder/bot/rules/enum_text.py +1 -4
  66. telegrinder/bot/rules/func.py +5 -3
  67. telegrinder/bot/rules/fuzzy.py +1 -1
  68. telegrinder/bot/rules/id.py +24 -0
  69. telegrinder/bot/rules/inline.py +6 -4
  70. telegrinder/bot/rules/integer.py +2 -1
  71. telegrinder/bot/rules/logic.py +18 -0
  72. telegrinder/bot/rules/markup.py +5 -6
  73. telegrinder/bot/rules/message.py +2 -4
  74. telegrinder/bot/rules/message_entities.py +1 -3
  75. telegrinder/bot/rules/node.py +15 -9
  76. telegrinder/bot/rules/payload.py +81 -0
  77. telegrinder/bot/rules/payment_invoice.py +29 -0
  78. telegrinder/bot/rules/regex.py +5 -6
  79. telegrinder/bot/rules/state.py +1 -3
  80. telegrinder/bot/rules/text.py +10 -5
  81. telegrinder/bot/rules/update.py +0 -0
  82. telegrinder/bot/scenario/abc.py +2 -4
  83. telegrinder/bot/scenario/checkbox.py +12 -14
  84. telegrinder/bot/scenario/choice.py +6 -9
  85. telegrinder/client/__init__.py +9 -1
  86. telegrinder/client/abc.py +35 -10
  87. telegrinder/client/aiohttp.py +28 -24
  88. telegrinder/client/form_data.py +31 -0
  89. telegrinder/client/sonic.py +212 -0
  90. telegrinder/model.py +38 -145
  91. telegrinder/modules.py +3 -1
  92. telegrinder/msgspec_utils.py +136 -68
  93. telegrinder/node/__init__.py +74 -13
  94. telegrinder/node/attachment.py +92 -16
  95. telegrinder/node/base.py +196 -68
  96. telegrinder/node/callback_query.py +17 -16
  97. telegrinder/node/command.py +3 -2
  98. telegrinder/node/composer.py +40 -75
  99. telegrinder/node/container.py +13 -7
  100. telegrinder/node/either.py +82 -0
  101. telegrinder/node/event.py +20 -31
  102. telegrinder/node/file.py +51 -0
  103. telegrinder/node/me.py +4 -5
  104. telegrinder/node/payload.py +78 -0
  105. telegrinder/node/polymorphic.py +27 -8
  106. telegrinder/node/rule.py +2 -6
  107. telegrinder/node/scope.py +4 -6
  108. telegrinder/node/source.py +37 -21
  109. telegrinder/node/text.py +20 -8
  110. telegrinder/node/tools/generator.py +7 -11
  111. telegrinder/py.typed +0 -0
  112. telegrinder/rules.py +0 -61
  113. telegrinder/tools/__init__.py +97 -38
  114. telegrinder/tools/adapter/__init__.py +19 -0
  115. telegrinder/tools/adapter/abc.py +49 -0
  116. telegrinder/tools/adapter/dataclass.py +56 -0
  117. telegrinder/{bot/rules → tools}/adapter/event.py +8 -10
  118. telegrinder/{bot/rules → tools}/adapter/node.py +8 -10
  119. telegrinder/{bot/rules → tools}/adapter/raw_event.py +2 -2
  120. telegrinder/{bot/rules → tools}/adapter/raw_update.py +2 -2
  121. telegrinder/tools/buttons.py +52 -26
  122. telegrinder/tools/callback_data_serilization/__init__.py +5 -0
  123. telegrinder/tools/callback_data_serilization/abc.py +51 -0
  124. telegrinder/tools/callback_data_serilization/json_ser.py +60 -0
  125. telegrinder/tools/callback_data_serilization/msgpack_ser.py +172 -0
  126. telegrinder/tools/error_handler/abc.py +4 -7
  127. telegrinder/tools/error_handler/error.py +0 -0
  128. telegrinder/tools/error_handler/error_handler.py +34 -48
  129. telegrinder/tools/formatting/__init__.py +57 -37
  130. telegrinder/tools/formatting/deep_links.py +541 -0
  131. telegrinder/tools/formatting/{html.py → html_formatter.py} +51 -79
  132. telegrinder/tools/formatting/spec_html_formats.py +14 -60
  133. telegrinder/tools/functional.py +1 -5
  134. telegrinder/tools/global_context/global_context.py +26 -51
  135. telegrinder/tools/global_context/telegrinder_ctx.py +3 -3
  136. telegrinder/tools/i18n/abc.py +0 -0
  137. telegrinder/tools/i18n/middleware/abc.py +3 -6
  138. telegrinder/tools/input_file_directory.py +30 -0
  139. telegrinder/tools/keyboard.py +9 -9
  140. telegrinder/tools/lifespan.py +105 -0
  141. telegrinder/tools/limited_dict.py +5 -10
  142. telegrinder/tools/loop_wrapper/abc.py +7 -2
  143. telegrinder/tools/loop_wrapper/loop_wrapper.py +40 -95
  144. telegrinder/tools/magic.py +184 -34
  145. telegrinder/tools/state_storage/__init__.py +0 -0
  146. telegrinder/tools/state_storage/abc.py +5 -9
  147. telegrinder/tools/state_storage/memory.py +1 -1
  148. telegrinder/tools/strings.py +13 -0
  149. telegrinder/types/__init__.py +8 -0
  150. telegrinder/types/enums.py +31 -21
  151. telegrinder/types/input_file.py +51 -0
  152. telegrinder/types/methods.py +531 -109
  153. telegrinder/types/objects.py +934 -826
  154. telegrinder/verification_utils.py +0 -2
  155. {telegrinder-0.3.4.post1.dist-info → telegrinder-0.4.0.dist-info}/LICENSE +2 -2
  156. telegrinder-0.4.0.dist-info/METADATA +144 -0
  157. telegrinder-0.4.0.dist-info/RECORD +182 -0
  158. {telegrinder-0.3.4.post1.dist-info → telegrinder-0.4.0.dist-info}/WHEEL +1 -1
  159. telegrinder/bot/rules/adapter/__init__.py +0 -17
  160. telegrinder/bot/rules/adapter/abc.py +0 -31
  161. telegrinder/node/message.py +0 -14
  162. telegrinder/node/update.py +0 -15
  163. telegrinder/tools/formatting/links.py +0 -38
  164. telegrinder/tools/kb_set/__init__.py +0 -4
  165. telegrinder/tools/kb_set/base.py +0 -15
  166. telegrinder/tools/kb_set/yaml.py +0 -63
  167. telegrinder-0.3.4.post1.dist-info/METADATA +0 -110
  168. telegrinder-0.3.4.post1.dist-info/RECORD +0 -165
  169. /telegrinder/{bot/rules → tools}/adapter/errors.py +0 -0
@@ -0,0 +1,541 @@
1
+ import types
2
+ import typing
3
+ from collections import OrderedDict
4
+ from datetime import timedelta
5
+ from functools import wraps
6
+ from urllib.parse import urlencode
7
+
8
+ from telegrinder.tools.magic import get_annotations
9
+
10
+ type DeepLinkFunction[**P] = typing.Callable[P, str]
11
+ type NoValue = types.EllipsisType
12
+ type Permission = typing.Literal[
13
+ "change_info",
14
+ "post_messages",
15
+ "edit_messages",
16
+ "delete_messages",
17
+ "invite_users",
18
+ "restrict_members",
19
+ "promote_members",
20
+ "pin_messages",
21
+ "manage_topics",
22
+ "manage_video_chats",
23
+ "anonymous",
24
+ "manage_chat",
25
+ "post_stories",
26
+ "edit_stories",
27
+ "delete_stories",
28
+ ]
29
+ type Peer = typing.Literal[
30
+ "users",
31
+ "bots",
32
+ "groups",
33
+ "channels",
34
+ ]
35
+ Parameter = typing.Annotated
36
+
37
+ NO_VALUE: typing.Final[NoValue] = typing.cast(NoValue, ...)
38
+
39
+
40
+ def deep_link[**P](
41
+ link: str,
42
+ /,
43
+ *,
44
+ no_value_params: set[str] | None = None,
45
+ order_params: set[str] | None = None,
46
+ ) -> typing.Callable[[DeepLinkFunction[P]], DeepLinkFunction[P]]:
47
+ if not link.startswith("tg://"):
48
+ raise RuntimeError("Invalid deep link format. The link must start with 'tg://'.")
49
+
50
+ def inner(func: DeepLinkFunction[P]) -> DeepLinkFunction[P]:
51
+ @wraps(func)
52
+ def wrapper(*_: P.args, **kwargs: P.kwargs) -> str:
53
+ return parse_deep_link(
54
+ link=link,
55
+ params=get_query_params(func, kwargs, order_params),
56
+ no_value_params=no_value_params,
57
+ )
58
+
59
+ return wrapper
60
+
61
+ return inner
62
+
63
+
64
+ def get_query_params(
65
+ func: DeepLinkFunction[...],
66
+ kwargs: dict[str, typing.Any],
67
+ order_params: set[str] | None = None,
68
+ ) -> dict[str, typing.Any]:
69
+ annotations = get_annotations(func)
70
+ params = OrderedDict()
71
+ param_names = (
72
+ [*order_params, *(p for p in annotations if p not in order_params)] if order_params else annotations
73
+ )
74
+
75
+ for param_name in param_names:
76
+ annotation = annotations[param_name]
77
+ if param_name in kwargs:
78
+ value = kwargs[param_name]
79
+ if typing.get_origin(annotation) is Parameter:
80
+ param_name, validator = get_parameter_metadata(annotation)
81
+ value = validator(value) if validator is not None else value
82
+
83
+ params[param_name] = value
84
+
85
+ return params
86
+
87
+
88
+ def parse_query_params(
89
+ params: dict[str, typing.Any],
90
+ no_value_params: set[str] | None = None,
91
+ /,
92
+ ) -> tuple[set[str], dict[str, typing.Any]]:
93
+ no_value_params = no_value_params or set()
94
+ params_: dict[str, typing.Any] = {}
95
+
96
+ for key, value in params.items():
97
+ if value in (False, None):
98
+ continue
99
+
100
+ if value in (True, NO_VALUE):
101
+ no_value_params.add(key)
102
+ continue
103
+ if isinstance(value, timedelta):
104
+ value = int(value.total_seconds())
105
+
106
+ params_[key] = value
107
+
108
+ return (no_value_params, params_)
109
+
110
+
111
+ def get_parameter_metadata(
112
+ parameter: typing.Any,
113
+ ) -> tuple[str, typing.Callable[[typing.Any], typing.Any] | None]:
114
+ meta: tuple[typing.Any, ...] = getattr(parameter, "__metadata__")
115
+ return meta if len(meta) == 2 else (meta[0], None)
116
+
117
+
118
+ def parse_deep_link(
119
+ *,
120
+ link: str,
121
+ params: dict[str, typing.Any],
122
+ no_value_params: set[str] | None = None,
123
+ ) -> str:
124
+ no_value_params, params = parse_query_params(params, no_value_params)
125
+ query = urlencode(params, encoding="UTF-8") + ("&" if no_value_params else "") + "&".join(no_value_params)
126
+ return f"{link}?{query}"
127
+
128
+
129
+ def validate_permissions(perms: list[Permission] | None, /) -> str | None:
130
+ return None if not perms else "+".join(perms)
131
+
132
+
133
+ def validate_peer(peer: list[Peer] | None, /) -> str | None:
134
+ return None if not peer else "+".join(peer)
135
+
136
+
137
+ @deep_link("tg://resolve")
138
+ def tg_public_username_link(
139
+ *,
140
+ username: Parameter[str, "domain"],
141
+ draft_text: Parameter[str | None, "text"] = None,
142
+ open_profile: Parameter[bool, "profile"] = False,
143
+ ) -> str:
144
+ """Used to link to public `users`, `groups` and `channels`.
145
+
146
+ :param username: Username.
147
+ :param draft_text: Optional. UTF-8 text to pre-enter into the text input bar, if the user can write in the chat.
148
+ :param open_profile: Optional. If set, clicking on this link should open the destination peer's profile page, not the chat view.
149
+ """
150
+ ...
151
+
152
+
153
+ @deep_link("tg://user")
154
+ def tg_mention_link(*, user_id: Parameter[int, "id"]) -> str:
155
+ """ID links are merely an abstraction offered by the `Bot API` to simplify construction of
156
+ `inputMessageEntityMentionName` and `inputKeyboardButtonUserProfile` constructors, and should be
157
+ ignored by normal clients.
158
+
159
+ :param user_id: User ID.
160
+ """
161
+ ...
162
+
163
+
164
+ @deep_link("tg://openmessage")
165
+ def tg_open_message_link(
166
+ *,
167
+ chat_id: int | None = None,
168
+ user_id: int | None = None,
169
+ message_id: int | None = None,
170
+ ) -> str: ...
171
+
172
+
173
+ @deep_link("tg://emoji")
174
+ def tg_emoji_link(*, emoji_id: Parameter[int, "id"]) -> str:
175
+ """Emoji links are merely an abstraction offered by the `Bot API` to simplify construction of
176
+ `messageEntityCustomEmoji` constructors, and should be ignored by normal clients.
177
+
178
+ :param emoji_id: Custom emoji ID.
179
+ """
180
+ ...
181
+
182
+
183
+ @deep_link("tg://addemoji")
184
+ def tg_emoji_stickerset_link(*, short_name: Parameter[str, "set"]) -> str:
185
+ """Used to import custom emoji stickersets.
186
+
187
+ :param short_name: Stickerset short name, used when installing stickers.
188
+ """
189
+ ...
190
+
191
+
192
+ @deep_link("tg://resolve")
193
+ def tg_story_link(
194
+ *,
195
+ username: Parameter[str, "domain"],
196
+ story_id: Parameter[int, "story"],
197
+ ) -> str:
198
+ """Used to link to a Telegram Story.
199
+
200
+ :param username: Username of the user or channel that posted the story.
201
+ :param story_id: ID of the Telegram Story.
202
+ """
203
+ ...
204
+
205
+
206
+ @deep_link("tg://join")
207
+ def tg_chat_invite_link(*, invite_hash: Parameter[str, "invite"]) -> str:
208
+ """Used to invite users to private `groups` and `channels`.
209
+
210
+ :param invite_hash: Invite hash.
211
+ """
212
+ ...
213
+
214
+
215
+ @deep_link("tg://addlist")
216
+ def tg_chat_folder_link(*, slug: str) -> str:
217
+ """Used to add chat folders.
218
+
219
+ :param slug: Folder slug.
220
+ """
221
+ ...
222
+
223
+
224
+ @deep_link("tg://resolve")
225
+ def tg_public_message_link(
226
+ *,
227
+ dialog: Parameter[str, "domain"],
228
+ message_id: Parameter[int, "post"],
229
+ single: bool = False,
230
+ thread_id: Parameter[int | None, "thread"] = None,
231
+ comment: str | None = None,
232
+ timestamp: Parameter[timedelta | None, "t"] = None,
233
+ ) -> str:
234
+ """Used to link to specific messages in public or private `groups` and `channels`.
235
+
236
+ :param dialog: Dialog username.
237
+ :param message_id: Message ID.
238
+ :param single: Optional. For albums/grouped media, if set indicates that this is a link to a specific media in the album; otherwise, it is a link to the entire album.
239
+ :param thread_id: Optional. For message threads, contains the thread ID.
240
+ :param comment: Optional. For channel comments, username will contain the channel username, id will contain the message ID of the channel message that started the comment section and this field will contain the message ID of the comment in the discussion group.
241
+ :param timestamp: Optional. Timestamp at which to start playing the media file present in the body or in the webpage preview of the message.
242
+ """
243
+ ...
244
+
245
+
246
+ @deep_link("tg://privatepost")
247
+ def tg_private_message_link(
248
+ *,
249
+ channel: str,
250
+ message_id: Parameter[int, "post"],
251
+ single: bool = False,
252
+ thread_id: Parameter[int | None, "thread"] = None,
253
+ comment: str | None = None,
254
+ timestamp: Parameter[timedelta | None, "t"] = None,
255
+ ) -> str:
256
+ """Used to link to specific messages in public or private `groups` and `channels`.
257
+
258
+ :param channel: Channel or supergroup ID.
259
+ :param post: Message ID.
260
+ :param single: Optional. For albums/grouped media, if set indicates that this is a link to a specific media in the album; otherwise, it is a link to the entire album.
261
+ :param thread: Optional. For message threads, contains the thread ID.
262
+ :param comment: Optional. For channel comments, username will contain the channel username, id will contain the message ID of the channel message that started the comment section and this field will contain the message ID of the comment in the discussion group.
263
+ :param t: Optional. Timestamp at which to start playing the media file present in the body or in the webpage preview of the message.
264
+ """
265
+ ...
266
+
267
+
268
+ @deep_link("tg://msg_url")
269
+ def tg_share_link(*, url: str, text: str | None = None) -> str:
270
+ """Used to share a prepared message and URL into a chosen chat's text field.
271
+
272
+ These links should be handled as follows:
273
+ * Open a dialog selection prompt
274
+ * After selection: validate, trim and enter the URL at the beginning of the text field
275
+ * Append a newline to the text field
276
+ * Append and select the `text`, if present
277
+
278
+ :param url: URL to share (`urlencoded`).
279
+ :param text: Optional. Text to prepend to the URL.
280
+ """
281
+ ...
282
+
283
+
284
+ @deep_link("tg://boost")
285
+ def tg_public_channel_boost_link(*, channel_username: Parameter[str, "domain"]) -> str:
286
+ """Used by users to boost public channels, granting them the ability to post stories and further perks.
287
+
288
+ :param channel_username: Channel username.
289
+ """
290
+ ...
291
+
292
+
293
+ @deep_link("tg://boost")
294
+ def tg_private_channel_boost_link(*, channel_id: Parameter[int, "channel"]) -> str:
295
+ """Used by users to boost private channels, granting them the ability to post stories and further perks.
296
+
297
+ :param channel_id: Channel ID.
298
+ """
299
+ ...
300
+
301
+
302
+ @deep_link("tg://invoice")
303
+ def tg_invoice_link(*, slug: str) -> str:
304
+ """Used to initiate payment of an invoice, generated using `payments.exportedInvoice`.
305
+
306
+ :param slug: The invoice slug to be used during payment.
307
+ """
308
+ ...
309
+
310
+
311
+ @deep_link("tg://setlanguage")
312
+ def tg_language_pack_link(
313
+ *,
314
+ lang_pack: Parameter[str | None, "lang"] = None,
315
+ ) -> str:
316
+ """Used to import custom language packs using `langpack.getLangPack`.
317
+
318
+ :param lang_pack: Optional. Name of language pack.
319
+ """
320
+ ...
321
+
322
+
323
+ @deep_link("tg://premium_multigift")
324
+ def tg_premium_multigift_link(*, ref: str) -> str:
325
+ """Used to bring the user to the screen used for gifting `Telegram Premium` subscriptions to friends,
326
+ see here for more info on gifting `Telegram Premium` to multiple users.
327
+
328
+ This link is used to invite users to gift `Premium` subscription to other users, see here for the different
329
+ link type containing the actual giftcodes that can be used to import a gifted `Telegram Premium` subscription.
330
+
331
+ :param ref: Used by official apps for analytics using `help.saveAppLog`.
332
+ """
333
+ ...
334
+
335
+
336
+ @deep_link("tg://premium_offer")
337
+ def tg_premium_offer_link(*, ref: str | None = None) -> str:
338
+ """Used by official apps to show the `Telegram Premium` subscription page.
339
+
340
+ :param ref: Optional. Used by official apps for analytics using `help.saveAppLog`.
341
+ """
342
+ ...
343
+
344
+
345
+ @deep_link("tg://resolve")
346
+ def tg_bot_start_link(
347
+ *,
348
+ bot_username: Parameter[str, "domain"],
349
+ parameter: Parameter[str | None, "start"] = None,
350
+ ) -> str:
351
+ """Used to link to bots.
352
+
353
+ :param bot_username: Bot username.
354
+ :param parameter: Optional. Start parameter, up to 64 `base64url` characters: if provided and the `bot_username` is indeed a bot, \
355
+ the text input bar should be replaced with a `Start` button (even if the user has already started the bot) that should invoke \
356
+ `messages.startBot` with the appropriate `parameter` once clicked. Note that if the `bot_username` is equal to the `premium_bot_username` \
357
+ configuration value, clicking on this link should immediately invoke `messages.startBot` with the appropriate `parameter`.
358
+ """
359
+ ...
360
+
361
+
362
+ @deep_link("tg://resolve")
363
+ def tg_bot_startgroup_link(
364
+ *,
365
+ bot_username: Parameter[str, "domain"],
366
+ parameter: Parameter[str | NoValue, "startgroup"] = NO_VALUE,
367
+ permissions: Parameter[list[Permission] | None, "admin", validate_permissions] = None,
368
+ ) -> str:
369
+ """Used to add bots to groups.
370
+ First of all, check that the `<bot_username>` indeed links to a bot.
371
+
372
+ Then, for group links:
373
+
374
+ If the `admin` parameter is not provided:
375
+ - Bring up a dialog selection of groups where the user can add members
376
+ - Add the bot to the group
377
+ - If a `parameter` is provided, invoke `messages.startBot` with the appropriate `parameter`
378
+
379
+ If the admin parameter is provided:
380
+ - Bring up a dialog selection of groups where the user can add/edit admins
381
+ - If the bot is already an admin of the group, combine existing admin rights with the admin rights in admin
382
+ - Add the bot as admin/modify admin permissions to the new rights
383
+ - If a parameter is provided, invoke `messages.startBot` with the appropriate `parameter`
384
+
385
+ :param bot_username: Bot username.
386
+ :param parameter: Optional. Start parameter, only for group links, up to 64 `base64url` characters: if provided and the `bot_username` is indeed a bot, \
387
+ `messages.startBot` with the appropriate parameter should be invoked after adding the bot to the group.
388
+ :param permissions: Optional. A combination of the following identifiers separated by `+`, each corresponding to the appropriate flag in the `chatAdminRights` constructor.
389
+ """
390
+ ...
391
+
392
+
393
+ @deep_link("tg://resolve", no_value_params={"startchannel"})
394
+ def tg_bot_startchannel_link(
395
+ *,
396
+ bot_username: Parameter[str, "domain"],
397
+ permissions: Parameter[list[Permission], "admin", validate_permissions],
398
+ ) -> str:
399
+ """Used to add bots to channels.
400
+ First of all, check that the `<bot_username>` indeed links to a bot.
401
+
402
+ For channel links:
403
+ - Bring up a dialog selection of channels where the user can add/edit admins
404
+ - If the bot is already an admin of the channel, combine existing admin rights with the admin rights in admin
405
+ - Add the bot as admin/modify admin permissions to the new rights
406
+
407
+ :param bot_username: Bot username.
408
+ :param permissions: A combination of the following identifiers separated by `+`, each corresponding to the \
409
+ appropriate flag in the `chatAdminRights` constructor.
410
+ """
411
+ ...
412
+
413
+
414
+ @deep_link("tg://resolve")
415
+ def tg_main_mini_app_link(
416
+ *,
417
+ bot_username: Parameter[str, "domain"],
418
+ parameter: Parameter[str | NoValue, "startapp"] = NO_VALUE,
419
+ mode: typing.Literal["compact"] | None = None,
420
+ ) -> str:
421
+ """Used to open `Main Mini Apps`.
422
+
423
+ If the specified bot does not have a configured `Main` Mini App (i.e. the user.bot_has_main_app flag will not be set),
424
+ fall back to the behavior of username links.
425
+
426
+ The main mini app should be opened using `messages.requestMainWebView`.
427
+
428
+ :param bot_username: Bot username.
429
+ :param parameter: Optional. If provided, should be passed to `messages.requestMainWebView.start_param`.
430
+ :param mode: Optional. If equal to `compact`, the `messages.requestMainWebView.compact` flag must be set.
431
+ """
432
+ ...
433
+
434
+
435
+ @deep_link("tg://resolve")
436
+ def tg_direct_mini_app_link(
437
+ *,
438
+ bot_username: Parameter[str, "domain"],
439
+ short_name: Parameter[str, "appname"],
440
+ parameter: Parameter[str | NoValue, "startapp"] = NO_VALUE,
441
+ mode: typing.Literal["compact"] | None = None,
442
+ ) -> str:
443
+ """Used to share `Direct` link Mini apps.
444
+
445
+ These links are different from bot attachment menu deep links, because they don't require the user to install
446
+ an attachment menu, and a single bot can offer multiple named mini apps, distinguished by their `short_name`.
447
+
448
+ These links should be handled as specified in the direct link Mini Apps documentation.
449
+
450
+ :param bot_username: Username of the bot that owns the game.
451
+ :param short_name: Mini app short name, to pass to `inputBotAppShortName.short_name` when invoking `messages.getBotApp`.
452
+ :param parameter: Optional. To pass to `messages.requestAppWebView.start_param`.
453
+ :param mode: Optional. If equal to `compact`, the `messages.requestAppWebView.compact` flag must be set.
454
+ """
455
+ ...
456
+
457
+
458
+ @deep_link("tg://resolve")
459
+ def tg_bot_attach_open_current_chat(
460
+ *,
461
+ bot_username: Parameter[str, "domain"],
462
+ parameter: Parameter[str | NoValue, "startattach"] = NO_VALUE,
463
+ ) -> str:
464
+ """After installing the attachment/side menu entry globally, opens the associated mini app using
465
+ `messages.requestWebView` in the currently open chat, by passing it to the peer parameter of `messages.requestWebView`.
466
+
467
+ If the current chat is not supported by the `attachMenuBot.peer_types` field:
468
+
469
+ - If the user has just installed the attachment menu in the previous step, notify the user that the attachment menu was installed successfully.
470
+ - Otherwise, notify the user that the attachment menu webapp can't be opened in the specified chat.
471
+
472
+ :param bot_username: Username of the bot that owns the attachment/side menu entry.
473
+ :param parameter: Optional. If provided, should be passed to `messages.requestWebView.start_param`.
474
+ """
475
+ ...
476
+
477
+
478
+ @deep_link("tg://resolve")
479
+ def tg_bot_attach_open_specific_chat(
480
+ *,
481
+ username: Parameter[str, "domain"],
482
+ phone_number: Parameter[str, "phone"],
483
+ bot_username: Parameter[str, "attach"],
484
+ parameter: Parameter[str | NoValue, "startattach"] = NO_VALUE,
485
+ ) -> str:
486
+ """After installing the `attachment/side` menu entry globally, opens the associated mini app using
487
+ `messages.requestWebView` in a specific chat (passed to the peer parameter of `messages.requestWebView`).
488
+
489
+ If the specified chat is not supported by the attachMenuBot.peer_types field:
490
+
491
+ - If the user has just installed the attachment menu in the previous step, notify the user that the attachment menu was installed successfully.
492
+ - Otherwise, notify the user that the attachment menu webapp can't be opened in the specified chat.
493
+ """
494
+ ...
495
+
496
+
497
+ @deep_link("tg://resolve")
498
+ def tg_bot_attach_open_any_chat(
499
+ *,
500
+ bot_username: Parameter[str, "domain"],
501
+ parameter: Parameter[str | NoValue, "startattach"] = NO_VALUE,
502
+ peer: Parameter[list[Peer] | None, "choose", validate_peer] = None,
503
+ ) -> str:
504
+ """After installing the `attachment/side` menu entry globally, opens a dialog selection form that will open the attachment menu
505
+ mini app using `messages.requestWebView` in a specific chat (pass it to the peer parameter of `messages.requestWebView`).
506
+
507
+ :param bot_username: Username of the bot that owns the `attachment/side` menu.
508
+ :param parameter: Optional. If provided, should be passed to `messages.requestWebView.start_param`.
509
+ :param peer: Optional. A combination of `users`, `bots`, `groups`, `channels` separated by `+`: indicates the dialog types to show in \
510
+ the dialog selection popup: must be intersected with the dialog types contained in the `attachMenuBot.peer_types` field before use.
511
+ """
512
+ ...
513
+
514
+
515
+ __all__ = (
516
+ "tg_bot_attach_open_any_chat",
517
+ "tg_bot_attach_open_current_chat",
518
+ "tg_bot_attach_open_specific_chat",
519
+ "tg_bot_start_link",
520
+ "tg_bot_startchannel_link",
521
+ "tg_bot_startgroup_link",
522
+ "tg_chat_folder_link",
523
+ "tg_chat_invite_link",
524
+ "tg_direct_mini_app_link",
525
+ "tg_emoji_link",
526
+ "tg_emoji_stickerset_link",
527
+ "tg_invoice_link",
528
+ "tg_language_pack_link",
529
+ "tg_main_mini_app_link",
530
+ "tg_mention_link",
531
+ "tg_open_message_link",
532
+ "tg_premium_multigift_link",
533
+ "tg_premium_offer_link",
534
+ "tg_private_channel_boost_link",
535
+ "tg_private_message_link",
536
+ "tg_public_channel_boost_link",
537
+ "tg_public_message_link",
538
+ "tg_public_username_link",
539
+ "tg_share_link",
540
+ "tg_story_link",
541
+ )