pyrobale 0.3.5__py3-none-any.whl → 0.3.7__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.
- pyrobale/StateMachine/__init__.py +45 -0
- pyrobale/__init__.py +120 -0
- pyrobale/client/__init__.py +563 -20
- pyrobale/objects/__init__.py +3 -0
- pyrobale/objects/callbackquery.py +19 -24
- pyrobale/objects/chatmember.py +5 -4
- pyrobale/objects/enums.py +16 -0
- pyrobale/objects/message.py +27 -8
- pyrobale/objects/user.py +11 -9
- pyrobale/objects/utils.py +0 -1
- pyrobale-0.3.7.dist-info/METADATA +153 -0
- {pyrobale-0.3.5.dist-info → pyrobale-0.3.7.dist-info}/RECORD +14 -13
- pyrobale-0.3.5.dist-info/METADATA +0 -176
- {pyrobale-0.3.5.dist-info → pyrobale-0.3.7.dist-info}/WHEEL +0 -0
- {pyrobale-0.3.5.dist-info → pyrobale-0.3.7.dist-info}/licenses/LICENSE +0 -0
pyrobale/client/__init__.py
CHANGED
@@ -38,16 +38,17 @@ from ..objects.webappdata import WebAppData
|
|
38
38
|
from ..objects.webappinfo import WebAppInfo
|
39
39
|
from ..objects.utils import *
|
40
40
|
import asyncio
|
41
|
-
import aiohttp
|
42
|
-
import bale
|
43
41
|
from enum import Enum
|
44
42
|
from ..objects.enums import UpdatesTypes, ChatAction, ChatType
|
43
|
+
from ..StateMachine import StateMachine
|
45
44
|
|
46
45
|
|
47
46
|
class Client:
|
48
47
|
"""A client for interacting with the Bale messenger API.
|
49
48
|
|
50
|
-
|
49
|
+
Args:
|
50
|
+
token (str): The bot token.
|
51
|
+
base_url (str, optional): The base URL for the API. Defaults to "https://tapi.bale.ai/bot".
|
51
52
|
"""
|
52
53
|
|
53
54
|
def __init__(self, token: str, base_url: str = "https://tapi.bale.ai/bot"):
|
@@ -56,8 +57,10 @@ class Client:
|
|
56
57
|
self.requests_base = base_url + token
|
57
58
|
|
58
59
|
self.handlers = []
|
60
|
+
self._waiters = []
|
59
61
|
self.running = False
|
60
62
|
self.last_update_id = 0
|
63
|
+
self.state_machine = StateMachine()
|
61
64
|
|
62
65
|
async def get_updates(
|
63
66
|
self,
|
@@ -65,6 +68,15 @@ class Client:
|
|
65
68
|
limit: Optional[int] = None,
|
66
69
|
timeout: Optional[int] = None,
|
67
70
|
) -> List[Dict]:
|
71
|
+
"""Get updates from the Bale API.
|
72
|
+
|
73
|
+
Args:
|
74
|
+
offset (int, optional): The offset of the updates to get. Defaults to None.
|
75
|
+
limit (int, optional): The maximum number of updates to get. Defaults to None.
|
76
|
+
timeout (int, optional): The timeout for the request. Defaults to None.
|
77
|
+
Returns:
|
78
|
+
List[Dict]: The updates.
|
79
|
+
"""
|
68
80
|
data = await make_get(
|
69
81
|
self.requests_base
|
70
82
|
+ f"/getUpdates?offset={offset}&limit={limit}&timeout={timeout}"
|
@@ -72,22 +84,49 @@ class Client:
|
|
72
84
|
return data["result"]
|
73
85
|
|
74
86
|
async def set_webhook(self, url: str) -> bool:
|
87
|
+
"""Set the webhook for the bot.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
url (str): The URL to set the webhook to.
|
91
|
+
Returns:
|
92
|
+
bool: True if the webhook was set successfully, False otherwise.
|
93
|
+
"""
|
75
94
|
data = await make_post(self.requests_base + "/setWebhook", data={"url": url})
|
76
95
|
return data["result"]
|
77
96
|
|
78
97
|
async def get_webhook_info(self) -> Dict:
|
98
|
+
"""Get the webhook information for the bot.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
Dict: The webhook information.
|
102
|
+
"""
|
79
103
|
data = await make_get(self.requests_base + "/getWebhookInfo")
|
80
104
|
return data["result"]
|
81
105
|
|
82
106
|
async def get_me(self) -> User:
|
107
|
+
"""Get information about the bot.
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
User: The information about the bot.
|
111
|
+
"""
|
83
112
|
data = await make_get(self.requests_base + "/getMe")
|
84
113
|
return User(**data["result"])
|
85
114
|
|
86
115
|
async def logout(self) -> bool:
|
116
|
+
"""Log out the bot.
|
117
|
+
|
118
|
+
Returns:
|
119
|
+
bool: True if the bot was logged out successfully, False otherwise.
|
120
|
+
"""
|
87
121
|
data = await make_get(self.requests_base + "/logOut")
|
88
122
|
return data["result"]
|
89
123
|
|
90
124
|
async def close(self) -> bool:
|
125
|
+
"""Close the bot.
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
bool: True if the bot was closed successfully, False otherwise.
|
129
|
+
"""
|
91
130
|
data = await make_get(self.requests_base + "/close")
|
92
131
|
return data["result"]
|
93
132
|
|
@@ -98,6 +137,16 @@ class Client:
|
|
98
137
|
reply_to_message_id: Optional[int] = None,
|
99
138
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
100
139
|
) -> Message:
|
140
|
+
"""Send a message to a chat.
|
141
|
+
|
142
|
+
Args:
|
143
|
+
chat_id (int): The ID of the chat to send the message to.
|
144
|
+
text (str): The text of the message.
|
145
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
146
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
147
|
+
Returns:
|
148
|
+
Message: The message that was sent.
|
149
|
+
"""
|
101
150
|
data = await make_post(
|
102
151
|
self.requests_base + "/sendMessage",
|
103
152
|
data={
|
@@ -112,6 +161,15 @@ class Client:
|
|
112
161
|
async def forward_message(
|
113
162
|
self, chat_id: int, from_chat_id: int, message_id: int
|
114
163
|
) -> Message:
|
164
|
+
"""Forward a message to a chat.
|
165
|
+
|
166
|
+
Args:
|
167
|
+
chat_id (int): The ID of the chat to forward the message to.
|
168
|
+
from_chat_id (int): The ID of the chat to forward the message from.
|
169
|
+
message_id (int): The ID of the message to forward.
|
170
|
+
Returns:
|
171
|
+
Message: The message that was forwarded.
|
172
|
+
"""
|
115
173
|
data = await make_post(
|
116
174
|
self.requests_base + "/forwardMessage",
|
117
175
|
data={
|
@@ -125,6 +183,15 @@ class Client:
|
|
125
183
|
async def copy_message(
|
126
184
|
self, chat_id: int, from_chat_id: int, message_id: int
|
127
185
|
) -> Message:
|
186
|
+
"""Copy a message to a chat.
|
187
|
+
|
188
|
+
Args:
|
189
|
+
chat_id (int): The ID of the chat to copy the message to.
|
190
|
+
from_chat_id (int): The ID of the chat to copy the message from.
|
191
|
+
message_id (int): The ID of the message to copy.
|
192
|
+
Returns:
|
193
|
+
Message: The message that was copied.
|
194
|
+
"""
|
128
195
|
data = await make_post(
|
129
196
|
self.requests_base + "/copyMessage",
|
130
197
|
data={
|
@@ -143,6 +210,17 @@ class Client:
|
|
143
210
|
reply_to_message_id: Optional[int] = None,
|
144
211
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
145
212
|
) -> Message:
|
213
|
+
"""Send a photo to a chat.
|
214
|
+
|
215
|
+
Args:
|
216
|
+
chat_id (Union[int, str]): The ID of the chat to send the photo to.
|
217
|
+
photo (Union[InputFile, str]): The photo to send.
|
218
|
+
caption (str, optional): The caption of the photo. Defaults to None.
|
219
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
220
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
221
|
+
Returns:
|
222
|
+
Message: The message that was sent.
|
223
|
+
"""
|
146
224
|
data = await make_post(
|
147
225
|
self.requests_base + "/sendPhoto",
|
148
226
|
data={
|
@@ -163,6 +241,17 @@ class Client:
|
|
163
241
|
reply_to_message_id: Optional[int] = None,
|
164
242
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
165
243
|
) -> Message:
|
244
|
+
"""Send an audio to a chat.
|
245
|
+
|
246
|
+
Args:
|
247
|
+
chat_id (int): The ID of the chat to send the audio to.
|
248
|
+
audio (Union[InputFile, str]): The audio to send.
|
249
|
+
caption (str, optional): The caption of the audio. Defaults to None.
|
250
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
251
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
252
|
+
Returns:
|
253
|
+
Message: The message that was sent.
|
254
|
+
"""
|
166
255
|
data = await make_post(
|
167
256
|
self.requests_base + "/sendAudio",
|
168
257
|
data={
|
@@ -183,6 +272,17 @@ class Client:
|
|
183
272
|
reply_to_message_id: Optional[int] = None,
|
184
273
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
185
274
|
) -> Message:
|
275
|
+
"""Send a document to a chat.
|
276
|
+
|
277
|
+
Args:
|
278
|
+
chat_id (int): The ID of the chat to send the document to.
|
279
|
+
document (Union[InputFile, str]): The document to send.
|
280
|
+
caption (str, optional): The caption of the document. Defaults to None.
|
281
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
282
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
283
|
+
Returns:
|
284
|
+
Message: The message that was sent.
|
285
|
+
"""
|
186
286
|
data = await make_post(
|
187
287
|
self.requests_base + "/sendDocument",
|
188
288
|
data={
|
@@ -203,6 +303,17 @@ class Client:
|
|
203
303
|
reply_to_message_id: Optional[int] = None,
|
204
304
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
205
305
|
) -> Message:
|
306
|
+
"""Send a video to a chat.
|
307
|
+
|
308
|
+
Args:
|
309
|
+
chat_id (int): The ID of the chat to send the video to.
|
310
|
+
video (Union[InputFile, str]): The video to send.
|
311
|
+
caption (str, optional): The caption of the video. Defaults to None.
|
312
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
313
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
314
|
+
Returns:
|
315
|
+
Message: The message that was sent.
|
316
|
+
"""
|
206
317
|
data = await make_post(
|
207
318
|
self.requests_base + "/sendVideo",
|
208
319
|
data={
|
@@ -223,6 +334,17 @@ class Client:
|
|
223
334
|
reply_to_message_id: Optional[int] = None,
|
224
335
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
225
336
|
) -> Message:
|
337
|
+
"""Send an animation to a chat.
|
338
|
+
|
339
|
+
Args:
|
340
|
+
chat_id (int): The ID of the chat to send the animation to.
|
341
|
+
animation (Union[InputFile, str]): The animation to send.
|
342
|
+
caption (str, optional): The caption of the animation. Defaults to None.
|
343
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
344
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
345
|
+
Returns:
|
346
|
+
Message: The message that was sent.
|
347
|
+
"""
|
226
348
|
data = await make_post(
|
227
349
|
self.requests_base + "/sendAnimation",
|
228
350
|
data={
|
@@ -243,6 +365,17 @@ class Client:
|
|
243
365
|
reply_to_message_id: Optional[int] = None,
|
244
366
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
245
367
|
) -> Message:
|
368
|
+
"""Send a voice message to a chat.
|
369
|
+
|
370
|
+
Args:
|
371
|
+
chat_id (int): The ID of the chat to send the voice message to.
|
372
|
+
voice (Union[InputFile, str]): The voice message to send.
|
373
|
+
caption (str, optional): The caption of the voice message. Defaults to None.
|
374
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
375
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
376
|
+
Returns:
|
377
|
+
Message: The message that was sent.
|
378
|
+
"""
|
246
379
|
data = await make_post(
|
247
380
|
self.requests_base + "/sendVoice",
|
248
381
|
data={
|
@@ -262,6 +395,16 @@ class Client:
|
|
262
395
|
reply_to_message_id: Optional[int] = None,
|
263
396
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
264
397
|
) -> List[Message]:
|
398
|
+
"""Send a media group to a chat.
|
399
|
+
|
400
|
+
Args:
|
401
|
+
chat_id (int): The ID of the chat to send the media group to.
|
402
|
+
media (List[Union[InputMediaPhoto, InputMediaVideo, InputMediaAudio]]): The media group to send.
|
403
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
404
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
405
|
+
Returns:
|
406
|
+
List[Message]: The messages that were sent.
|
407
|
+
"""
|
265
408
|
data = await make_post(
|
266
409
|
self.requests_base + "/sendMediaGroup",
|
267
410
|
data={
|
@@ -281,6 +424,17 @@ class Client:
|
|
281
424
|
reply_to_message_id: Optional[int] = None,
|
282
425
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
283
426
|
) -> Message:
|
427
|
+
"""Send a location to a chat.
|
428
|
+
|
429
|
+
Args:
|
430
|
+
chat_id (int): The ID of the chat to send the location to.
|
431
|
+
latitude (float): The latitude of the location.
|
432
|
+
longitude (float): The longitude of the location.
|
433
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
434
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
435
|
+
Returns:
|
436
|
+
Message: The message that was sent.
|
437
|
+
"""
|
284
438
|
data = await make_post(
|
285
439
|
self.requests_base + "/sendLocation",
|
286
440
|
data={
|
@@ -302,6 +456,18 @@ class Client:
|
|
302
456
|
reply_to_message_id: Optional[int] = None,
|
303
457
|
reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None,
|
304
458
|
) -> Message:
|
459
|
+
"""Send a contact to a chat.
|
460
|
+
|
461
|
+
Args:
|
462
|
+
chat_id (int): The ID of the chat to send the contact to.
|
463
|
+
phone_number (str): The phone number of the contact.
|
464
|
+
first_name (str): The first name of the contact.
|
465
|
+
last_name (str, optional): The last name of the contact. Defaults to None.
|
466
|
+
reply_to_message_id (int, optional): The ID of the message to reply to. Defaults to None.
|
467
|
+
reply_markup (Union[InlineKeyboardMarkup, ReplyKeyboardMarkup], optional): The reply markup to use. Defaults to None.
|
468
|
+
Returns:
|
469
|
+
Message: The message that was sent.
|
470
|
+
"""
|
305
471
|
data = await make_post(
|
306
472
|
self.requests_base + "/sendContact",
|
307
473
|
data={
|
@@ -315,7 +481,55 @@ class Client:
|
|
315
481
|
)
|
316
482
|
return Message(**pythonize(data["result"]))
|
317
483
|
|
484
|
+
async def send_invoice(
|
485
|
+
self,
|
486
|
+
chat_id: Union[str, int],
|
487
|
+
title: str,
|
488
|
+
description: str,
|
489
|
+
payload: str,
|
490
|
+
provider_token: str,
|
491
|
+
prices: list[LabeledPrice],
|
492
|
+
photo_url: Optional[str] = None,
|
493
|
+
reply_to_message_id: Optional[int] = None,
|
494
|
+
) -> Message:
|
495
|
+
"""Sends a message including a invoice for user to pay.
|
496
|
+
|
497
|
+
Args:
|
498
|
+
chat_id (string OR integer): unique chat id to send the invoice
|
499
|
+
title (string): the title of invoice
|
500
|
+
description (string): desciption of invoice, you can explain the invoice here
|
501
|
+
payload (string): payload of invoice, user will not see this, it'll be returned after successful payment
|
502
|
+
provider_token (string): Wallet token or card number of receiver
|
503
|
+
prices (list of LabledPrice): a list of prices that user must pay
|
504
|
+
photo_url (Optional: string): url of a photo that will be sent with invoice
|
505
|
+
reply_to_message_id (Optional: int): message id to reply that
|
506
|
+
|
507
|
+
Returns:
|
508
|
+
Message: returns the sent message with invoice
|
509
|
+
"""
|
510
|
+
data = await make_post(
|
511
|
+
self.requests_base + "/sendInvoice",
|
512
|
+
data={
|
513
|
+
"chat_id": chat_id,
|
514
|
+
"title": title,
|
515
|
+
"description": description,
|
516
|
+
"payload": payload,
|
517
|
+
"provider_token": provider_token,
|
518
|
+
"prices": prices,
|
519
|
+
"photo_url": photo_url,
|
520
|
+
"reply_to_message_id": reply_to_message_id,
|
521
|
+
},
|
522
|
+
)
|
523
|
+
return Message(**pythonize(data["result"]))
|
524
|
+
|
318
525
|
async def get_file(self, file_id: str) -> File:
|
526
|
+
"""Get a file from the Bale servers.
|
527
|
+
|
528
|
+
Args:
|
529
|
+
file_id (str): The ID of the file to get.
|
530
|
+
Returns:
|
531
|
+
File: The file that was retrieved.
|
532
|
+
"""
|
319
533
|
data = await make_post(
|
320
534
|
self.requests_base + "/getFile", data={"file_id": file_id}
|
321
535
|
)
|
@@ -327,6 +541,15 @@ class Client:
|
|
327
541
|
text: Optional[str] = None,
|
328
542
|
show_alert: Optional[bool] = None,
|
329
543
|
):
|
544
|
+
"""Answer a callback query.
|
545
|
+
|
546
|
+
Args:
|
547
|
+
callback_query_id (str): The ID of the callback query to answer.
|
548
|
+
text (str, optional): The text to show to the user. Defaults to None.
|
549
|
+
show_alert (bool, optional): Whether to show an alert to the user. Defaults to None.
|
550
|
+
Returns:
|
551
|
+
bool: Whether the callback query was answered successfully.
|
552
|
+
"""
|
330
553
|
data = await make_post(
|
331
554
|
self.requests_base + "/answerCallbackQuery",
|
332
555
|
data={
|
@@ -338,6 +561,15 @@ class Client:
|
|
338
561
|
return data.get("ok", False)
|
339
562
|
|
340
563
|
async def ban_chat_member(self, chat_id: int, user_id: int) -> bool:
|
564
|
+
"""Ban a user from a chat.
|
565
|
+
|
566
|
+
Args:
|
567
|
+
chat_id (int): The ID of the chat to ban the user from.
|
568
|
+
user_id (int): The ID of the user to ban.
|
569
|
+
Returns:
|
570
|
+
bool: Whether the user was banned successfully
|
571
|
+
"""
|
572
|
+
|
341
573
|
data = await make_post(
|
342
574
|
self.requests_base + "/banChatMember",
|
343
575
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -345,6 +577,14 @@ class Client:
|
|
345
577
|
return data.get("ok", False)
|
346
578
|
|
347
579
|
async def unban_chat_member(self, chat_id: int, user_id: int) -> bool:
|
580
|
+
"""Unban a user from a chat.
|
581
|
+
|
582
|
+
Args:
|
583
|
+
chat_id (int): The ID of the chat to unban the user from.
|
584
|
+
user_id (int): The ID of the user to unban.
|
585
|
+
Returns:
|
586
|
+
bool: Whether the user was unbanned successfully.
|
587
|
+
"""
|
348
588
|
data = await make_post(
|
349
589
|
self.requests_base + "/unbanChatMember",
|
350
590
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -352,6 +592,14 @@ class Client:
|
|
352
592
|
return data.get("ok", False)
|
353
593
|
|
354
594
|
async def get_chat_member(self, chat_id: int, user_id: int) -> ChatMember:
|
595
|
+
"""Get a chat member.
|
596
|
+
|
597
|
+
Args:
|
598
|
+
chat_id (int): The ID of the chat to get the member from.
|
599
|
+
user_id (int): The ID of the user to get.
|
600
|
+
Returns:
|
601
|
+
ChatMember: The chat member that was retrieved.
|
602
|
+
"""
|
355
603
|
data = await make_post(
|
356
604
|
self.requests_base + "/getChatMember",
|
357
605
|
data={"chat_id": chat_id, "user_id": user_id},
|
@@ -373,6 +621,22 @@ class Client:
|
|
373
621
|
can_pin_messages: Optional[bool] = None,
|
374
622
|
can_promote_members: Optional[bool] = None,
|
375
623
|
):
|
624
|
+
"""Promote a user in a chat.
|
625
|
+
|
626
|
+
Args:
|
627
|
+
chat_id (int): The ID of the chat to promote the user in.
|
628
|
+
user_id (int): The ID of the user to promote.
|
629
|
+
can_change_info (bool, optional): Whether the user can change the chat info. Defaults to None.
|
630
|
+
can_post_messages (bool, optional): Whether the user can post messages. Defaults to None.
|
631
|
+
can_edit_messages (bool, optional): Whether the user can edit messages. Defaults to None.
|
632
|
+
can_delete_messages (bool, optional): Whether the user can delete messages. Defaults to None.
|
633
|
+
can_invite_users (bool, optional): Whether the user can invite users. Defaults to None.
|
634
|
+
can_restrict_members (bool, optional): Whether the user can restrict members. Defaults to None.
|
635
|
+
can_pin_messages (bool, optional): Whether the user can pin messages. Defaults to None.
|
636
|
+
can_promote_members (bool, optional): Whether the user can promote members. Defaults to None.
|
637
|
+
Returns:
|
638
|
+
bool: Whether the user was promoted successfully.
|
639
|
+
"""
|
376
640
|
data = await make_post(
|
377
641
|
self.requests_base + "/promoteChatMember",
|
378
642
|
data={
|
@@ -391,6 +655,15 @@ class Client:
|
|
391
655
|
return data.get("ok", False)
|
392
656
|
|
393
657
|
async def set_chat_photo(self, chat_id: int, photo: InputFile) -> bool:
|
658
|
+
"""Set a new profile photo for the chat.
|
659
|
+
|
660
|
+
Args:
|
661
|
+
chat_id (int): Unique identifier for the target chat
|
662
|
+
photo (InputFile): New chat photo
|
663
|
+
|
664
|
+
Returns:
|
665
|
+
bool: True on success
|
666
|
+
"""
|
394
667
|
data = await make_post(
|
395
668
|
self.requests_base + "/setChatPhoto",
|
396
669
|
data={"chat_id": chat_id, "photo": photo},
|
@@ -398,24 +671,57 @@ class Client:
|
|
398
671
|
return data.get("ok", False)
|
399
672
|
|
400
673
|
async def leave_chat(self, chat_id: int) -> bool:
|
674
|
+
"""Leave a group, supergroup or channel.
|
675
|
+
|
676
|
+
Args:
|
677
|
+
chat_id (int): Unique identifier for the target chat
|
678
|
+
|
679
|
+
Returns:
|
680
|
+
bool: True on success
|
681
|
+
"""
|
401
682
|
data = await make_post(
|
402
683
|
self.requests_base + "/leaveChat", data={"chat_id": chat_id}
|
403
684
|
)
|
404
685
|
return data.get("ok", False)
|
405
686
|
|
406
687
|
async def get_chat(self, chat_id: int) -> Chat:
|
688
|
+
"""Get up to date information about the chat.
|
689
|
+
|
690
|
+
Args:
|
691
|
+
chat_id (int): Unique identifier for the target chat
|
692
|
+
|
693
|
+
Returns:
|
694
|
+
Chat: Chat object with information about the chat
|
695
|
+
"""
|
407
696
|
data = await make_post(
|
408
697
|
self.requests_base + "/getChat", data={"chat_id": chat_id}
|
409
698
|
)
|
410
699
|
return Chat(**pythonize(data["result"]))
|
411
700
|
|
412
701
|
async def get_chat_members_count(self, chat_id: int) -> int:
|
702
|
+
"""Get the number of members in a chat.
|
703
|
+
|
704
|
+
Args:
|
705
|
+
chat_id (int): Unique identifier for the target chat
|
706
|
+
|
707
|
+
Returns:
|
708
|
+
int: Number of members in the chat
|
709
|
+
"""
|
413
710
|
data = await make_post(
|
414
711
|
self.requests_base + "/getChatMembersCount", data={"chat_id": chat_id}
|
415
712
|
)
|
416
713
|
return data.get("result", 0)
|
417
714
|
|
418
715
|
async def pin_chat_message(self, chat_id: int, message_id: int) -> bool:
|
716
|
+
"""Pin a message in a chat.
|
717
|
+
|
718
|
+
Args:
|
719
|
+
chat_id (int): Unique identifier for the target chat
|
720
|
+
message_id (int): Identifier of a message to pin
|
721
|
+
|
722
|
+
Returns:
|
723
|
+
bool: True on success
|
724
|
+
"""
|
419
725
|
data = await make_post(
|
420
726
|
self.requests_base + "/pinChatMessage",
|
421
727
|
data={"chat_id": chat_id, "message_id": message_id},
|
@@ -423,18 +729,43 @@ class Client:
|
|
423
729
|
return data.get("ok", False)
|
424
730
|
|
425
731
|
async def unpin_chat_message(self, chat_id: int) -> bool:
|
732
|
+
"""Unpin a message in a chat.
|
733
|
+
|
734
|
+
Args:
|
735
|
+
chat_id (int): Unique identifier for the target chat
|
736
|
+
|
737
|
+
Returns:
|
738
|
+
bool: True on success
|
739
|
+
"""
|
426
740
|
data = await make_post(
|
427
741
|
self.requests_base + "/unpinChatMessage", data={"chat_id": chat_id}
|
428
742
|
)
|
429
743
|
return data.get("ok", False)
|
430
744
|
|
431
745
|
async def unpin_all_chat_messages(self, chat_id: int) -> bool:
|
746
|
+
"""Unpin all messages in a chat.
|
747
|
+
|
748
|
+
Args:
|
749
|
+
chat_id (int): Unique identifier for the target chat
|
750
|
+
|
751
|
+
Returns:
|
752
|
+
bool: True on success
|
753
|
+
"""
|
432
754
|
data = await make_post(
|
433
755
|
self.requests_base + "/unpinAllChatMessages", data={"chat_id": chat_id}
|
434
756
|
)
|
435
757
|
return data.get("ok", False)
|
436
758
|
|
437
759
|
async def set_chat_title(self, chat_id: int, title: str) -> bool:
|
760
|
+
"""Change the title of a chat.
|
761
|
+
|
762
|
+
Args:
|
763
|
+
chat_id (int): Unique identifier for the target chat
|
764
|
+
title (str): New chat title, 1-255 characters
|
765
|
+
|
766
|
+
Returns:
|
767
|
+
bool: True on success
|
768
|
+
"""
|
438
769
|
data = await make_post(
|
439
770
|
self.requests_base + "/setChatTitle",
|
440
771
|
data={"chat_id": chat_id, "title": title},
|
@@ -442,6 +773,15 @@ class Client:
|
|
442
773
|
return data.get("ok", False)
|
443
774
|
|
444
775
|
async def set_chat_description(self, chat_id: int, description: str) -> bool:
|
776
|
+
"""Change the description of a chat.
|
777
|
+
|
778
|
+
Args:
|
779
|
+
chat_id (int): Unique identifier for the target chat
|
780
|
+
description (str): New chat description, 0-255 characters
|
781
|
+
|
782
|
+
Returns:
|
783
|
+
bool: True on success
|
784
|
+
"""
|
445
785
|
data = await make_post(
|
446
786
|
self.requests_base + "/setChatDescription",
|
447
787
|
data={"chat_id": chat_id, "description": description},
|
@@ -449,18 +789,73 @@ class Client:
|
|
449
789
|
return data.get("ok", False)
|
450
790
|
|
451
791
|
async def delete_chat_photo(self, chat_id: int) -> bool:
|
792
|
+
"""Delete a chat photo.
|
793
|
+
|
794
|
+
Args:
|
795
|
+
chat_id (int): Unique identifier for the target chat
|
796
|
+
|
797
|
+
Returns:
|
798
|
+
bool: True on success
|
799
|
+
"""
|
452
800
|
data = await make_post(
|
453
801
|
self.requests_base + "/deleteChatPhoto", data={"chat_id": chat_id}
|
454
802
|
)
|
455
803
|
return data.get("ok", False)
|
456
804
|
|
805
|
+
async def edit_message(
|
806
|
+
self,
|
807
|
+
chat_id: Union[int, str],
|
808
|
+
message_id: int,
|
809
|
+
text: str,
|
810
|
+
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
811
|
+
) -> Message:
|
812
|
+
"""Edits a message in a specified chat
|
813
|
+
|
814
|
+
Args:
|
815
|
+
chat_id (int OR str): Unique identifier for the target chat
|
816
|
+
message_id (int): Unique indentifier for the message you want to edit
|
817
|
+
text (str): New text of message
|
818
|
+
reply_markup (InlineKeyboardMarkup): Inline markup you can add or change in message
|
819
|
+
|
820
|
+
Returns:
|
821
|
+
Message: The object of edited message
|
822
|
+
"""
|
823
|
+
|
824
|
+
data = await make_post(
|
825
|
+
self.requests_base + "/editMessageText",
|
826
|
+
data={
|
827
|
+
"chat_id": chat_id,
|
828
|
+
"message_id": message_id,
|
829
|
+
"text": text,
|
830
|
+
"reply_markup": reply_markup.to_dict() if reply_markup else None,
|
831
|
+
},
|
832
|
+
)
|
833
|
+
return Message(**pythonize(data["result"]))
|
834
|
+
|
457
835
|
async def create_chat_invite_link(self, chat_id: int) -> str:
|
836
|
+
"""Create an additional invite link for a chat.
|
837
|
+
|
838
|
+
Args:
|
839
|
+
chat_id (int): Unique identifier for the target chat
|
840
|
+
|
841
|
+
Returns:
|
842
|
+
str: The new invite link
|
843
|
+
"""
|
458
844
|
data = await make_post(
|
459
845
|
self.requests_base + "/createChatInviteLink", data={"chat_id": chat_id}
|
460
846
|
)
|
461
847
|
return data.get("result", "")
|
462
848
|
|
463
849
|
async def revoke_chat_invite_link(self, chat_id: int, invite_link: str) -> str:
|
850
|
+
"""Revoke an invite link created by the bot.
|
851
|
+
|
852
|
+
Args:
|
853
|
+
chat_id (int): Unique identifier for the target chat
|
854
|
+
invite_link (str): The invite link to revoke
|
855
|
+
|
856
|
+
Returns:
|
857
|
+
str: The revoked invite link
|
858
|
+
"""
|
464
859
|
data = await make_post(
|
465
860
|
self.requests_base + "/revokeChatInviteLink",
|
466
861
|
data={"chat_id": chat_id, "invite_link": invite_link},
|
@@ -468,24 +863,67 @@ class Client:
|
|
468
863
|
return data.get("result", "")
|
469
864
|
|
470
865
|
async def export_chat_invite_link(self, chat_id: int) -> str:
|
866
|
+
"""Generate a new primary invite link for a chat.
|
867
|
+
|
868
|
+
Args:
|
869
|
+
chat_id (int): Unique identifier for the target chat
|
870
|
+
|
871
|
+
Returns:
|
872
|
+
str: The new invite link
|
873
|
+
"""
|
471
874
|
data = await make_post(
|
472
875
|
self.requests_base + "/exportChatInviteLink", data={"chat_id": chat_id}
|
473
876
|
)
|
474
877
|
return data.get("result", "")
|
475
878
|
|
476
879
|
async def send_chat_action(self, chat_id: int, action: ChatAction) -> bool:
|
880
|
+
"""Tell the user that something is happening on the bot's side.
|
881
|
+
|
882
|
+
Args:
|
883
|
+
chat_id (int): Unique identifier for the target chat
|
884
|
+
action (ChatAction): Type of action to broadcast
|
885
|
+
|
886
|
+
Returns:
|
887
|
+
bool: True on success
|
888
|
+
"""
|
477
889
|
data = await make_post(
|
478
890
|
self.requests_base + "/sendChatAction",
|
479
891
|
data={"chat_id": str(chat_id), "action": action.value},
|
480
892
|
)
|
481
893
|
return data.get("ok", False)
|
482
894
|
|
895
|
+
async def wait_for(self, update_type: UpdatesTypes, check=None):
|
896
|
+
"""Wait until a specified update
|
897
|
+
|
898
|
+
Args:
|
899
|
+
update_type (UpdatesTypes): The type of update you're waiting for it.
|
900
|
+
check: a condition that will be checked before passing.
|
901
|
+
"""
|
902
|
+
future = asyncio.get_running_loop().create_future()
|
903
|
+
self._waiters.append((update_type, check, future))
|
904
|
+
return await future
|
905
|
+
|
483
906
|
async def process_update(self, update: Dict[str, Any]) -> None:
|
484
|
-
"""Process a single update and call registered handlers.
|
907
|
+
"""Process a single update and call registered handlers.
|
908
|
+
|
909
|
+
Args:
|
910
|
+
update (Dict[str, Any]): The update to process
|
911
|
+
"""
|
485
912
|
update_id = update.get("update_id")
|
486
913
|
if update_id:
|
487
914
|
self.last_update_id = update_id + 1
|
488
915
|
|
916
|
+
for waiter in list(self._waiters):
|
917
|
+
w_type, check, future = waiter
|
918
|
+
if w_type.value in update:
|
919
|
+
event = update[w_type.value]
|
920
|
+
event = self._convert_event(w_type, event)
|
921
|
+
if check is None or check(event):
|
922
|
+
if not future.done():
|
923
|
+
future.set_result(event)
|
924
|
+
self._waiters.remove(waiter)
|
925
|
+
return update
|
926
|
+
|
489
927
|
for handler in self.handlers:
|
490
928
|
update_type = handler["type"].value
|
491
929
|
if update_type in update:
|
@@ -498,22 +936,101 @@ class Client:
|
|
498
936
|
else:
|
499
937
|
handler["callback"](event)
|
500
938
|
|
939
|
+
def base_handler_decorator(self, update_type: UpdatesTypes):
|
940
|
+
def decorator(callback: Callable[[Any], Union[None, Awaitable[None]]]):
|
941
|
+
self.add_handler(update_type, callback)
|
942
|
+
return callback
|
943
|
+
|
944
|
+
return decorator
|
945
|
+
|
946
|
+
def on_message(self):
|
947
|
+
return self.base_handler_decorator(UpdatesTypes.MESSAGE)
|
948
|
+
|
949
|
+
def on_edited_message(self):
|
950
|
+
return self.base_handler_decorator(UpdatesTypes.MESSAGE_EDITED)
|
951
|
+
|
952
|
+
def on_callback_query(self):
|
953
|
+
return self.base_handler_decorator(UpdatesTypes.CALLBACK_QUERY)
|
954
|
+
|
955
|
+
def on_new_members(self):
|
956
|
+
return self.base_handler_decorator(UpdatesTypes.MEMBER_JOINED)
|
957
|
+
|
958
|
+
def on_memebers_left(self):
|
959
|
+
return self.base_handler_decorator(UpdatesTypes.MEMBER_LEFT)
|
960
|
+
|
961
|
+
def on_pre_checkout_query(self):
|
962
|
+
return self.base_handler_decorator(UpdatesTypes.PRE_CHECKOUT_QUERY)
|
963
|
+
|
964
|
+
def on_photo(self):
|
965
|
+
return self.base_handler_decorator(UpdatesTypes.PHOTO)
|
966
|
+
|
967
|
+
def on_successful_payment(self):
|
968
|
+
return self.base_handler_decorator(UpdatesTypes.SUCCESSFUL_PAYMENT)
|
969
|
+
|
501
970
|
def _convert_event(self, handler_type: UpdatesTypes, event: Dict[str, Any]) -> Any:
|
502
|
-
"""Convert raw event data to appropriate object type.
|
503
|
-
|
504
|
-
|
971
|
+
"""Convert raw event data to appropriate object type.
|
972
|
+
|
973
|
+
Args:
|
974
|
+
handler_type (UpdatesTypes): Type of the update
|
975
|
+
event (Dict[str, Any]): Raw event data
|
976
|
+
|
977
|
+
Returns:
|
978
|
+
Any: Converted event object
|
979
|
+
"""
|
980
|
+
if handler_type in (
|
981
|
+
UpdatesTypes.MESSAGE,
|
982
|
+
UpdatesTypes.MESSAGE_EDITED,
|
983
|
+
UpdatesTypes.MEMBER_JOINED,
|
984
|
+
UpdatesTypes.MEMBER_LEFT,
|
985
|
+
UpdatesTypes.SUCCESSFUL_PAYMENT,
|
986
|
+
):
|
987
|
+
if (
|
988
|
+
event.get("new_chat_member", False)
|
989
|
+
and handler_type == UpdatesTypes.MEMBER_JOINED
|
990
|
+
):
|
991
|
+
return (
|
992
|
+
ChatMember(
|
993
|
+
kwargs={"client": self},
|
994
|
+
**pythonize(event.get("new_chat_member", {})),
|
995
|
+
),
|
996
|
+
Chat(kwargs={"client": self}, **pythonize(event.get("chat", {}))),
|
997
|
+
Message(
|
998
|
+
kwargs={"client": self}, **pythonize(event.get("message", {}))
|
999
|
+
),
|
1000
|
+
)
|
1001
|
+
elif (
|
1002
|
+
event.get("left_chat_member", False)
|
1003
|
+
and handler_type == UpdatesTypes.MEMBER_LEFT
|
1004
|
+
):
|
1005
|
+
return (
|
1006
|
+
ChatMember(
|
1007
|
+
kwargs={"client": self},
|
1008
|
+
**pythonize(event.get("left_chat_member", {})),
|
1009
|
+
),
|
1010
|
+
Chat(kwargs={"client": self}, **pythonize(event.get("chat", {}))),
|
1011
|
+
Message(
|
1012
|
+
kwargs={"client": self}, **pythonize(event.get("message", {}))
|
1013
|
+
),
|
1014
|
+
)
|
1015
|
+
|
1016
|
+
elif (
|
1017
|
+
event.get("successful_payment", False)
|
1018
|
+
and handler_type == UpdatesTypes.SUCCESSFUL_PAYMENT
|
1019
|
+
):
|
1020
|
+
return Message(
|
1021
|
+
**pythonize(event.get("successful_payment", {})),
|
1022
|
+
kwargs={"client": self},
|
1023
|
+
)
|
1024
|
+
|
1025
|
+
else:
|
1026
|
+
return Message(kwargs={"client": self}, **pythonize(event))
|
1027
|
+
|
505
1028
|
elif handler_type == UpdatesTypes.CALLBACK_QUERY:
|
506
1029
|
return CallbackQuery(kwargs={"client": self}, **pythonize(event))
|
1030
|
+
|
507
1031
|
elif handler_type == UpdatesTypes.PRE_CHECKOUT_QUERY:
|
508
1032
|
return PreCheckoutQuery(kwargs={"client": self}, **pythonize(event))
|
509
|
-
|
510
|
-
return ChatMember(
|
511
|
-
kwargs={"client": self}, **pythonize(event.get("new_chat_member", {}))
|
512
|
-
)
|
513
|
-
elif handler_type == UpdatesTypes.MEMBER_LEFT:
|
514
|
-
return ChatMember(
|
515
|
-
kwargs={"client": self}, **pythonize(event.get("left_chat_member", {}))
|
516
|
-
)
|
1033
|
+
|
517
1034
|
return event
|
518
1035
|
|
519
1036
|
def add_handler(
|
@@ -521,13 +1038,22 @@ class Client:
|
|
521
1038
|
update_type: UpdatesTypes,
|
522
1039
|
callback: Callable[[Any], Union[None, Awaitable[None]]],
|
523
1040
|
) -> None:
|
524
|
-
"""Register a handler for specific update type.
|
1041
|
+
"""Register a handler for specific update type.
|
1042
|
+
|
1043
|
+
Args:
|
1044
|
+
update_type (UpdatesTypes): Type of update to handle
|
1045
|
+
callback (Callable): Function to call when update is received
|
1046
|
+
"""
|
525
1047
|
self.handlers.append({"type": update_type, "callback": callback})
|
526
1048
|
|
527
1049
|
def remove_handler(
|
528
1050
|
self, callback: Callable[[Any], Union[None, Awaitable[None]]]
|
529
1051
|
) -> None:
|
530
|
-
"""Remove a handler from the list of handlers.
|
1052
|
+
"""Remove a handler from the list of handlers.
|
1053
|
+
|
1054
|
+
Args:
|
1055
|
+
callback (Callable): Handler function to remove
|
1056
|
+
"""
|
531
1057
|
self.handlers = [
|
532
1058
|
handler for handler in self.handlers if handler["callback"] != callback
|
533
1059
|
]
|
@@ -537,7 +1063,15 @@ class Client:
|
|
537
1063
|
self.handlers = []
|
538
1064
|
|
539
1065
|
async def start_polling(self, timeout: int = 30, limit: int = 100) -> None:
|
540
|
-
"""Start polling updates from the server.
|
1066
|
+
"""Start polling updates from the server.
|
1067
|
+
|
1068
|
+
Args:
|
1069
|
+
timeout (int, optional): Timeout in seconds for long polling. Defaults to 30.
|
1070
|
+
limit (int, optional): Maximum number of updates to retrieve. Defaults to 100.
|
1071
|
+
|
1072
|
+
Raises:
|
1073
|
+
RuntimeError: If client is already running
|
1074
|
+
"""
|
541
1075
|
if self.running:
|
542
1076
|
raise RuntimeError("Client is already running")
|
543
1077
|
|
@@ -560,7 +1094,12 @@ class Client:
|
|
560
1094
|
self.running = False
|
561
1095
|
|
562
1096
|
def run(self, timeout: int = 30, limit: int = 100) -> None:
|
563
|
-
"""Run the client.
|
1097
|
+
"""Run the client.
|
1098
|
+
|
1099
|
+
Args:
|
1100
|
+
timeout (int, optional): Timeout in seconds for long polling. Defaults to 30.
|
1101
|
+
limit (int, optional): Maximum number of updates to retrieve. Defaults to 100.
|
1102
|
+
"""
|
564
1103
|
loop = asyncio.get_event_loop()
|
565
1104
|
loop.run_until_complete(self.start_polling(timeout, limit))
|
566
1105
|
|
@@ -570,5 +1109,9 @@ class Client:
|
|
570
1109
|
loop.run_until_complete(self.stop_polling())
|
571
1110
|
|
572
1111
|
async def handle_webhook_update(self, update_data: Dict[str, Any]) -> None:
|
573
|
-
"""Process an update received via webhook.
|
1112
|
+
"""Process an update received via webhook.
|
1113
|
+
|
1114
|
+
Args:
|
1115
|
+
update_data (Dict[str, Any]): Update data received from webhook
|
1116
|
+
"""
|
574
1117
|
await self.process_update(update_data)
|