· 6 years ago · Jan 24, 2020, 08:30 AM
1# -*- coding: utf-8 -*-
2from __future__ import print_function
3
4import threading
5import time
6import re
7import sys
8import six
9
10import os
11import pickle
12
13import logging
14
15logger = logging.getLogger('TeleBot')
16formatter = logging.Formatter(
17 '%(asctime)s (%(filename)s:%(lineno)d %(threadName)s) %(levelname)s - %(name)s: "%(message)s"'
18)
19
20console_output_handler = logging.StreamHandler(sys.stderr)
21console_output_handler.setFormatter(formatter)
22logger.addHandler(console_output_handler)
23
24logger.setLevel(logging.ERROR)
25
26from telebot import apihelper, types, util
27
28"""
29Module : telebot
30"""
31
32
33class Handler:
34 """
35 Class for (next step|reply) handlers
36 """
37 def __init__(self, callback, *args, **kwargs):
38 self.callback = callback
39 self.args = args
40 self.kwargs = kwargs
41
42 def __getitem__(self, item):
43 return getattr(self, item)
44
45
46class Saver:
47 """
48 Class for saving (next step|reply) handlers
49 """
50 def __init__(self, handlers, filename, delay):
51 self.handlers = handlers
52 self.filename = filename
53 self.delay = delay
54 self.timer = threading.Timer(delay, self.save_handlers)
55
56 def start_save_timer(self):
57 if not self.timer.is_alive():
58 if self.delay <= 0:
59 self.save_handlers()
60 else:
61 self.timer = threading.Timer(self.delay, self.save_handlers)
62 self.timer.start()
63
64 def save_handlers(self):
65 self.dump_handlers(self.handlers, self.filename)
66
67 def load_handlers(self, filename, del_file_after_loading=True):
68 tmp = self.return_load_handlers(filename, del_file_after_loading=del_file_after_loading)
69 if tmp is not None:
70 self.handlers.update(tmp)
71
72 @staticmethod
73 def dump_handlers(handlers, filename, file_mode="wb"):
74 dirs = filename.rsplit('/', maxsplit=1)[0]
75 os.makedirs(dirs, exist_ok=True)
76
77 with open(filename + ".tmp", file_mode) as file:
78 pickle.dump(handlers, file)
79
80 if os.path.isfile(filename):
81 os.remove(filename)
82
83 os.rename(filename + ".tmp", filename)
84
85 @staticmethod
86 def return_load_handlers(filename, del_file_after_loading=True):
87 if os.path.isfile(filename) and os.path.getsize(filename) > 0:
88 with open(filename, "rb") as file:
89 handlers = pickle.load(file)
90
91 if del_file_after_loading:
92 os.remove(filename)
93
94 return handlers
95
96
97class TeleBot:
98 """ This is TeleBot Class
99 Methods:
100 getMe
101 sendMessage
102 forwardMessage
103 deleteMessage
104 sendPhoto
105 sendAudio
106 sendDocument
107 sendSticker
108 sendVideo
109 sendVideoNote
110 sendLocation
111 sendChatAction
112 getUserProfilePhotos
113 getUpdates
114 getFile
115 kickChatMember
116 unbanChatMember
117 restrictChatMember
118 promoteChatMember
119 exportChatInviteLink
120 setChatPhoto
121 deleteChatPhoto
122 setChatTitle
123 setChatDescription
124 pinChatMessage
125 unpinChatMessage
126 leaveChat
127 getChat
128 getChatAdministrators
129 getChatMembersCount
130 getChatMember
131 answerCallbackQuery
132 answerInlineQuery
133 """
134
135 def __init__(self, token, threaded=True, skip_pending=False, num_threads=2):
136 """
137 :param token: bot API token
138 :return: Telebot object.
139 """
140
141 self.token = token
142 self.update_listener = []
143 self.skip_pending = skip_pending
144
145 self.__stop_polling = threading.Event()
146 self.last_update_id = 0
147 self.exc_info = None
148
149 # key: message_id, value: handler list
150 self.reply_handlers = {}
151
152 # key: chat_id, value: handler list
153 self.next_step_handlers = {}
154
155 self.next_step_saver = None
156 self.reply_saver = None
157
158 self.message_handlers = []
159 self.edited_message_handlers = []
160 self.channel_post_handlers = []
161 self.edited_channel_post_handlers = []
162 self.inline_handlers = []
163 self.chosen_inline_handlers = []
164 self.callback_query_handlers = []
165 self.shipping_query_handlers = []
166 self.pre_checkout_query_handlers = []
167
168 self.threaded = threaded
169 if self.threaded:
170 self.worker_pool = util.ThreadPool(num_threads=num_threads)
171
172 def enable_save_next_step_handlers(self, delay=120, filename="./.handler-saves/step.save"):
173 """
174 Enable saving next step handlers (by default saving disable)
175
176 :param delay: Delay between changes in handlers and saving
177 :param filename: Filename of save file
178 """
179 self.next_step_saver = Saver(self.next_step_handlers, filename, delay)
180
181 def enable_save_reply_handlers(self, delay=120, filename="./.handler-saves/reply.save"):
182 """
183 Enable saving reply handlers (by default saving disable)
184
185 :param delay: Delay between changes in handlers and saving
186 :param filename: Filename of save file
187 """
188 self.reply_saver = Saver(self.reply_handlers, filename, delay)
189
190 def disable_save_next_step_handlers(self):
191 """
192 Disable saving next step handlers (by default saving disable)
193 """
194 self.next_step_saver = None
195
196 def disable_save_reply_handlers(self):
197 """
198 Disable saving next step handlers (by default saving disable)
199 """
200 self.reply_saver = None
201
202 def load_next_step_handlers(self, filename="./.handler-saves/step.save", del_file_after_loading=True):
203 """
204 Load next step handlers from save file
205
206 :param filename: Filename of the file where handlers was saved
207 :param del_file_after_loading: Is passed True, after loading save file will be deleted
208 """
209 self.next_step_saver.load_handlers(filename, del_file_after_loading)
210
211 def load_reply_handlers(self, filename="./.handler-saves/reply.save", del_file_after_loading=True):
212 """
213 Load reply handlers from save file
214
215 :param filename: Filename of the file where handlers was saved
216 :param del_file_after_loading: Is passed True, after loading save file will be deleted
217 """
218 self.reply_saver.load_handlers(filename)
219
220 def set_webhook(self, url=None, certificate=None, max_connections=None, allowed_updates=None):
221 return apihelper.set_webhook(self.token, url, certificate, max_connections, allowed_updates)
222
223 def delete_webhook(self):
224 """
225 Use this method to remove webhook integration if you decide to switch back to getUpdates.
226 :return: bool
227 """
228 return apihelper.delete_webhook(self.token)
229
230 def get_webhook_info(self):
231 result = apihelper.get_webhook_info(self.token)
232 return types.WebhookInfo.de_json(result)
233
234 def remove_webhook(self):
235 return self.set_webhook() # No params resets webhook
236
237 def get_updates(self, offset=None, limit=None, timeout=20, allowed_updates=None):
238 """
239 Use this method to receive incoming updates using long polling (wiki). An Array of Update objects is returned.
240 :param allowed_updates: Array of string. List the types of updates you want your bot to receive.
241 :param offset: Integer. Identifier of the first update to be returned.
242 :param limit: Integer. Limits the number of updates to be retrieved.
243 :param timeout: Integer. Timeout in seconds for long polling.
244 :return: array of Updates
245 """
246 json_updates = apihelper.get_updates(self.token, offset, limit, timeout, allowed_updates)
247 ret = []
248 for ju in json_updates:
249 ret.append(types.Update.de_json(ju))
250 return ret
251
252 def __skip_updates(self):
253 """
254 Get and discard all pending updates before first poll of the bot
255 :return: total updates skipped
256 """
257 total = 0
258 updates = self.get_updates(offset=self.last_update_id, timeout=1)
259 while updates:
260 total += len(updates)
261 for update in updates:
262 if update.update_id > self.last_update_id:
263 self.last_update_id = update.update_id
264 updates = self.get_updates(offset=self.last_update_id + 1, timeout=1)
265 return total
266
267 def __retrieve_updates(self, timeout=20):
268 """
269 Retrieves any updates from the Telegram API.
270 Registered listeners and applicable message handlers will be notified when a new message arrives.
271 :raises ApiException when a call has failed.
272 """
273 if self.skip_pending:
274 logger.debug('Skipped {0} pending messages'.format(self.__skip_updates()))
275 self.skip_pending = False
276 updates = self.get_updates(offset=(self.last_update_id + 1), timeout=timeout)
277 self.process_new_updates(updates)
278
279 def process_new_updates(self, updates):
280 new_messages = []
281 edited_new_messages = []
282 new_channel_posts = []
283 new_edited_channel_posts = []
284 new_inline_querys = []
285 new_chosen_inline_results = []
286 new_callback_querys = []
287 new_shipping_querys = []
288 new_pre_checkout_querys = []
289
290 for update in updates:
291 if update.update_id > self.last_update_id:
292 self.last_update_id = update.update_id
293 if update.message:
294 new_messages.append(update.message)
295 if update.edited_message:
296 edited_new_messages.append(update.edited_message)
297 if update.channel_post:
298 new_channel_posts.append(update.channel_post)
299 if update.edited_channel_post:
300 new_edited_channel_posts.append(update.edited_channel_post)
301 if update.inline_query:
302 new_inline_querys.append(update.inline_query)
303 if update.chosen_inline_result:
304 new_chosen_inline_results.append(update.chosen_inline_result)
305 if update.callback_query:
306 new_callback_querys.append(update.callback_query)
307 if update.shipping_query:
308 new_shipping_querys.append(update.shipping_query)
309 if update.pre_checkout_query:
310 new_pre_checkout_querys.append(update.pre_checkout_query)
311
312 logger.debug('Received {0} new updates'.format(len(updates)))
313 if len(new_messages) > 0:
314 self.process_new_messages(new_messages)
315 if len(edited_new_messages) > 0:
316 self.process_new_edited_messages(edited_new_messages)
317 if len(new_channel_posts) > 0:
318 self.process_new_channel_posts(new_channel_posts)
319 if len(new_edited_channel_posts) > 0:
320 self.process_new_edited_channel_posts(new_edited_channel_posts)
321 if len(new_inline_querys) > 0:
322 self.process_new_inline_query(new_inline_querys)
323 if len(new_chosen_inline_results) > 0:
324 self.process_new_chosen_inline_query(new_chosen_inline_results)
325 if len(new_callback_querys) > 0:
326 self.process_new_callback_query(new_callback_querys)
327 if len(new_pre_checkout_querys) > 0:
328 self.process_new_pre_checkout_query(new_pre_checkout_querys)
329 if len(new_shipping_querys) > 0:
330 self.process_new_shipping_query(new_shipping_querys)
331
332 def process_new_messages(self, new_messages):
333 self._notify_next_handlers(new_messages)
334 self._notify_reply_handlers(new_messages)
335 self.__notify_update(new_messages)
336 self._notify_command_handlers(self.message_handlers, new_messages)
337
338 def process_new_edited_messages(self, edited_message):
339 self._notify_command_handlers(self.edited_message_handlers, edited_message)
340
341 def process_new_channel_posts(self, channel_post):
342 self._notify_command_handlers(self.channel_post_handlers, channel_post)
343
344 def process_new_edited_channel_posts(self, edited_channel_post):
345 self._notify_command_handlers(self.edited_channel_post_handlers, edited_channel_post)
346
347 def process_new_inline_query(self, new_inline_querys):
348 self._notify_command_handlers(self.inline_handlers, new_inline_querys)
349
350 def process_new_chosen_inline_query(self, new_chosen_inline_querys):
351 self._notify_command_handlers(self.chosen_inline_handlers, new_chosen_inline_querys)
352
353 def process_new_callback_query(self, new_callback_querys):
354 self._notify_command_handlers(self.callback_query_handlers, new_callback_querys)
355
356 def process_new_shipping_query(self, new_shipping_querys):
357 self._notify_command_handlers(self.shipping_query_handlers, new_shipping_querys)
358
359 def process_new_pre_checkout_query(self, pre_checkout_querys):
360 self._notify_command_handlers(self.pre_checkout_query_handlers, pre_checkout_querys)
361
362 def __notify_update(self, new_messages):
363 for listener in self.update_listener:
364 self._exec_task(listener, new_messages)
365
366 def infinity_polling(self, *args, **kwargs):
367 while not self.__stop_polling.is_set():
368 try:
369 self.polling(*args, **kwargs)
370 except Exception as e:
371 time.sleep(5)
372 pass
373 logger.info("Break infinity polling")
374
375 def polling(self, none_stop=False, interval=0, timeout=20):
376 """
377 This function creates a new Thread that calls an internal __retrieve_updates function.
378 This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly.
379
380 Warning: Do not call this function more than once!
381
382 Always get updates.
383 :param interval:
384 :param none_stop: Do not stop polling when an ApiException occurs.
385 :param timeout: Timeout in seconds for long polling.
386 :return:
387 """
388 if self.threaded:
389 self.__threaded_polling(none_stop, interval, timeout)
390 else:
391 self.__non_threaded_polling(none_stop, interval, timeout)
392
393 def __threaded_polling(self, none_stop=False, interval=0, timeout=3):
394 logger.info('Started polling.')
395 self.__stop_polling.clear()
396 error_interval = .25
397
398 polling_thread = util.WorkerThread(name="PollingThread")
399 or_event = util.OrEvent(
400 polling_thread.done_event,
401 polling_thread.exception_event,
402 self.worker_pool.exception_event
403 )
404
405 while not self.__stop_polling.wait(interval):
406 or_event.clear()
407 try:
408 polling_thread.put(self.__retrieve_updates, timeout)
409
410 or_event.wait() # wait for polling thread finish, polling thread error or thread pool error
411
412 polling_thread.raise_exceptions()
413 self.worker_pool.raise_exceptions()
414
415 error_interval = .25
416 except apihelper.ApiException as e:
417 logger.error(e)
418 if not none_stop:
419 self.__stop_polling.set()
420 logger.info("Exception occurred. Stopping.")
421 else:
422 polling_thread.clear_exceptions()
423 self.worker_pool.clear_exceptions()
424 logger.info("Waiting for {0} seconds until retry".format(error_interval))
425 time.sleep(error_interval)
426 error_interval *= 2
427 except KeyboardInterrupt:
428 logger.info("KeyboardInterrupt received.")
429 self.__stop_polling.set()
430 break
431
432 polling_thread.stop()
433 logger.info('Stopped polling.')
434
435 def __non_threaded_polling(self, none_stop=False, interval=0, timeout=3):
436 logger.info('Started polling.')
437 self.__stop_polling.clear()
438 error_interval = .25
439
440 while not self.__stop_polling.wait(interval):
441 try:
442 self.__retrieve_updates(timeout)
443 error_interval = .25
444 except apihelper.ApiException as e:
445 logger.error(e)
446 if not none_stop:
447 self.__stop_polling.set()
448 logger.info("Exception occurred. Stopping.")
449 else:
450 logger.info("Waiting for {0} seconds until retry".format(error_interval))
451 time.sleep(error_interval)
452 error_interval *= 2
453 except KeyboardInterrupt:
454 logger.info("KeyboardInterrupt received.")
455 self.__stop_polling.set()
456 break
457
458 logger.info('Stopped polling.')
459
460 def _exec_task(self, task, *args, **kwargs):
461 if self.threaded:
462 self.worker_pool.put(task, *args, **kwargs)
463 else:
464 task(*args, **kwargs)
465
466 def stop_polling(self):
467 self.__stop_polling.set()
468
469 def stop_bot(self):
470 self.stop_polling()
471 if self.worker_pool:
472 self.worker_pool.close()
473
474 def set_update_listener(self, listener):
475 self.update_listener.append(listener)
476
477 def get_me(self):
478 result = apihelper.get_me(self.token)
479 return types.User.de_json(result)
480
481 def get_file(self, file_id):
482 return types.File.de_json(apihelper.get_file(self.token, file_id))
483
484 def get_file_url(self, file_id):
485 return apihelper.get_file_url(self.token, file_id)
486
487 def download_file(self, file_path):
488 return apihelper.download_file(self.token, file_path)
489
490 def get_user_profile_photos(self, user_id, offset=None, limit=None):
491 """
492 Retrieves the user profile photos of the person with 'user_id'
493 See https://core.telegram.org/bots/api#getuserprofilephotos
494 :param user_id:
495 :param offset:
496 :param limit:
497 :return: API reply.
498 """
499 result = apihelper.get_user_profile_photos(self.token, user_id, offset, limit)
500 return types.UserProfilePhotos.de_json(result)
501
502 def get_chat(self, chat_id):
503 """
504 Use this method to get up to date information about the chat (current name of the user for one-on-one
505 conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
506 :param chat_id:
507 :return:
508 """
509 result = apihelper.get_chat(self.token, chat_id)
510 return types.Chat.de_json(result)
511
512 def leave_chat(self, chat_id):
513 """
514 Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
515 :param chat_id:
516 :return:
517 """
518 result = apihelper.leave_chat(self.token, chat_id)
519 return result
520
521 def get_chat_administrators(self, chat_id):
522 """
523 Use this method to get a list of administrators in a chat. On success, returns an Array of ChatMember objects
524 that contains information about all chat administrators except other bots.
525 :param chat_id:
526 :return:
527 """
528 result = apihelper.get_chat_administrators(self.token, chat_id)
529 ret = []
530 for r in result:
531 ret.append(types.ChatMember.de_json(r))
532 return ret
533
534 def get_chat_members_count(self, chat_id):
535 """
536 Use this method to get the number of members in a chat. Returns Int on success.
537 :param chat_id:
538 :return:
539 """
540 result = apihelper.get_chat_members_count(self.token, chat_id)
541 return result
542
543 def set_chat_sticker_set(self, chat_id, sticker_set_name):
544 """
545 Use this method to set a new group sticker set for a supergroup. The bot must be an administrator
546 in the chat for this to work and must have the appropriate admin rights.
547 Use the field can_set_sticker_set optionally returned in getChat requests to check
548 if the bot can use this method. Returns True on success.
549 :param chat_id: Unique identifier for the target chat or username of the target supergroup
550 (in the format @supergroupusername)
551 :param sticker_set_name: Name of the sticker set to be set as the group sticker set
552 :return:
553 """
554 result = apihelper.set_chat_sticker_set(self.token, chat_id, sticker_set_name)
555 return result
556
557 def delete_chat_sticker_set(self, chat_id):
558 """
559 Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat
560 for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set
561 optionally returned in getChat requests to check if the bot can use this method. Returns True on success.
562 :param chat_id: Unique identifier for the target chat or username of the target supergroup
563 (in the format @supergroupusername)
564 :return:
565 """
566 result = apihelper.delete_chat_sticker_set(self.token, chat_id)
567 return result
568
569 def get_chat_member(self, chat_id, user_id):
570 """
571 Use this method to get information about a member of a chat. Returns a ChatMember object on success.
572 :param chat_id:
573 :param user_id:
574 :return:
575 """
576 result = apihelper.get_chat_member(self.token, chat_id, user_id)
577 return types.ChatMember.de_json(result)
578
579 def send_message(self, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
580 parse_mode=None, disable_notification=None):
581 """
582 Use this method to send text messages.
583
584 Warning: Do not send more than about 5000 characters each message, otherwise you'll risk an HTTP 414 error.
585 If you must send more than 5000 characters, use the split_string function in apihelper.py.
586
587 :param chat_id:
588 :param text:
589 :param disable_web_page_preview:
590 :param reply_to_message_id:
591 :param reply_markup:
592 :param parse_mode:
593 :param disable_notification: Boolean, Optional. Sends the message silently.
594 :return: API reply.
595 """
596 return types.Message.de_json(
597 apihelper.send_message(self.token, chat_id, text, disable_web_page_preview, reply_to_message_id,
598 reply_markup, parse_mode, disable_notification))
599
600 def forward_message(self, chat_id, from_chat_id, message_id, disable_notification=None):
601 """
602 Use this method to forward messages of any kind.
603 :param disable_notification:
604 :param chat_id: which chat to forward
605 :param from_chat_id: which chat message from
606 :param message_id: message id
607 :return: API reply.
608 """
609 return types.Message.de_json(
610 apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification))
611
612 def delete_message(self, chat_id, message_id):
613 """
614 Use this method to delete message. Returns True on success.
615 :param chat_id: in which chat to delete
616 :param message_id: which message to delete
617 :return: API reply.
618 """
619 return apihelper.delete_message(self.token, chat_id, message_id)
620
621 def send_photo(self, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None,
622 parse_mode=None, disable_notification=None):
623 """
624 Use this method to send photos.
625 :param disable_notification:
626 :param chat_id:
627 :param photo:
628 :param caption:
629 :param parse_mode
630 :param reply_to_message_id:
631 :param reply_markup:
632 :return: API reply.
633 """
634 return types.Message.de_json(
635 apihelper.send_photo(self.token, chat_id, photo, caption, reply_to_message_id, reply_markup,
636 parse_mode, disable_notification))
637
638 def send_audio(self, chat_id, audio, caption=None, duration=None, performer=None, title=None,
639 reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None,
640 timeout=None):
641 """
642 Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .mp3 format.
643 :param chat_id:Unique identifier for the message recipient
644 :param audio:Audio file to send.
645 :param duration:Duration of the audio in seconds
646 :param performer:Performer
647 :param title:Track name
648 :param parse_mode
649 :param reply_to_message_id:If the message is a reply, ID of the original message
650 :param reply_markup:
651 :return: Message
652 """
653 return types.Message.de_json(
654 apihelper.send_audio(self.token, chat_id, audio, caption, duration, performer, title, reply_to_message_id,
655 reply_markup, parse_mode, disable_notification, timeout))
656
657 def send_voice(self, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
658 parse_mode=None, disable_notification=None, timeout=None):
659 """
660 Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message.
661 :param chat_id:Unique identifier for the message recipient.
662 :param voice:
663 :param duration:Duration of sent audio in seconds
664 :param reply_to_message_id:
665 :param reply_markup:
666 :param parse_mode
667 :return: Message
668 """
669 return types.Message.de_json(
670 apihelper.send_voice(self.token, chat_id, voice, caption, duration, reply_to_message_id, reply_markup,
671 parse_mode, disable_notification, timeout))
672
673 def send_document(self, chat_id, data, reply_to_message_id=None, caption=None, reply_markup=None,
674 parse_mode=None, disable_notification=None, timeout=None):
675 """
676 Use this method to send general files.
677 :param chat_id:
678 :param data:
679 :param reply_to_message_id:
680 :param reply_markup:
681 :param parse_mode:
682 :param disable_notification:
683 :return: API reply.
684 """
685 return types.Message.de_json(
686 apihelper.send_data(self.token, chat_id, data, 'document', reply_to_message_id, reply_markup,
687 parse_mode, disable_notification, timeout, caption=caption))
688
689 def send_sticker(self, chat_id, data, reply_to_message_id=None, reply_markup=None, disable_notification=None,
690 timeout=None):
691 """
692 Use this method to send .webp stickers.
693 :param chat_id:
694 :param data:
695 :param reply_to_message_id:
696 :param reply_markup:
697 :return: API reply.
698 """
699 return types.Message.de_json(
700 apihelper.send_data(self.token, chat_id, data, 'sticker', reply_to_message_id, reply_markup,
701 disable_notification, timeout))
702
703 def send_video(self, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
704 parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None):
705 """
706 Use this method to send video files, Telegram clients support mp4 videos.
707 :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
708 :param data: InputFile or String : Video to send. You can either pass a file_id as String to resend a video that is already on the Telegram server
709 :param duration: Integer : Duration of sent video in seconds
710 :param caption: String : Video caption (may also be used when resending videos by file_id).
711 :param parse_mode:
712 :param supports_streaming:
713 :param reply_to_message_id:
714 :param reply_markup:
715 :return:
716 """
717 return types.Message.de_json(
718 apihelper.send_video(self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup,
719 parse_mode, supports_streaming, disable_notification, timeout))
720
721 def send_video_note(self, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
722 disable_notification=None, timeout=None):
723 """
724 Use this method to send video files, Telegram clients support mp4 videos.
725 :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
726 :param data: InputFile or String : Video note to send. You can either pass a file_id as String to resend a video that is already on the Telegram server
727 :param duration: Integer : Duration of sent video in seconds
728 :param length: Integer : Video width and height, Can't be None and should be in range of (0, 640)
729 :param reply_to_message_id:
730 :param reply_markup:
731 :return:
732 """
733 return types.Message.de_json(
734 apihelper.send_video_note(self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
735 disable_notification, timeout))
736
737 def send_media_group(self, chat_id, media, disable_notification=None, reply_to_message_id=None):
738 """
739 send a group of photos or videos as an album. On success, an array of the sent Messages is returned.
740 :param chat_id:
741 :param media:
742 :param disable_notification:
743 :param reply_to_message_id:
744 :return:
745 """
746 result = apihelper.send_media_group(self.token, chat_id, media, disable_notification, reply_to_message_id)
747 ret = []
748 for msg in result:
749 ret.append(types.Message.de_json(msg))
750 return ret
751
752 def send_location(self, chat_id, latitude, longitude, live_period=None, reply_to_message_id=None, reply_markup=None,
753 disable_notification=None):
754 """
755 Use this method to send point on the map.
756 :param chat_id:
757 :param latitude:
758 :param longitude:
759 :param live_period
760 :param reply_to_message_id:
761 :param reply_markup:
762 :return: API reply.
763 """
764 return types.Message.de_json(
765 apihelper.send_location(self.token, chat_id, latitude, longitude, live_period, reply_to_message_id,
766 reply_markup,
767 disable_notification))
768
769 def edit_message_live_location(self, latitude, longitude, chat_id=None, message_id=None,
770 inline_message_id=None, reply_markup=None):
771 """
772 Use this method to edit live location
773 :param latitude:
774 :param longitude:
775 :param chat_id:
776 :param message_id:
777 :param inline_message_id:
778 :param reply_markup:
779 :return:
780 """
781 return types.Message.de_json(
782 apihelper.edit_message_live_location(self.token, latitude, longitude, chat_id, message_id,
783 inline_message_id, reply_markup))
784
785 def stop_message_live_location(self, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
786 """
787 Use this method to stop updating a live location message sent by the bot
788 or via the bot (for inline bots) before live_period expires
789 :param chat_id:
790 :param message_id:
791 :param inline_message_id:
792 :param reply_markup:
793 :return:
794 """
795 return types.Message.de_json(
796 apihelper.stop_message_live_location(self.token, chat_id, message_id, inline_message_id, reply_markup))
797
798 def send_venue(self, chat_id, latitude, longitude, title, address, foursquare_id=None, disable_notification=None,
799 reply_to_message_id=None, reply_markup=None):
800 """
801 Use this method to send information about a venue.
802 :param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel
803 :param latitude: Float : Latitude of the venue
804 :param longitude: Float : Longitude of the venue
805 :param title: String : Name of the venue
806 :param address: String : Address of the venue
807 :param foursquare_id: String : Foursquare identifier of the venue
808 :param disable_notification:
809 :param reply_to_message_id:
810 :param reply_markup:
811 :return:
812 """
813 return types.Message.de_json(
814 apihelper.send_venue(self.token, chat_id, latitude, longitude, title, address, foursquare_id,
815 disable_notification, reply_to_message_id, reply_markup)
816 )
817
818 def send_contact(self, chat_id, phone_number, first_name, last_name=None, disable_notification=None,
819 reply_to_message_id=None, reply_markup=None):
820 return types.Message.de_json(
821 apihelper.send_contact(self.token, chat_id, phone_number, first_name, last_name, disable_notification,
822 reply_to_message_id, reply_markup)
823 )
824
825 def send_chat_action(self, chat_id, action):
826 """
827 Use this method when you need to tell the user that something is happening on the bot's side.
828 The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear
829 its typing status).
830 :param chat_id:
831 :param action: One of the following strings: 'typing', 'upload_photo', 'record_video', 'upload_video',
832 'record_audio', 'upload_audio', 'upload_document', 'find_location', 'record_video_note', 'upload_video_note'.
833 :return: API reply. :type: boolean
834 """
835 return apihelper.send_chat_action(self.token, chat_id, action)
836
837 def kick_chat_member(self, chat_id, user_id, until_date=None):
838 """
839 Use this method to kick a user from a group or a supergroup.
840 :param chat_id: Int or string : Unique identifier for the target group or username of the target supergroup
841 :param user_id: Int : Unique identifier of the target user
842 :param until_date: Date when the user will be unbanned, unix time. If user is banned for more than 366 days or
843 less than 30 seconds from the current time they are considered to be banned forever
844 :return: types.Message
845 """
846 return apihelper.kick_chat_member(self.token, chat_id, user_id, until_date)
847
848 def unban_chat_member(self, chat_id, user_id):
849 return apihelper.unban_chat_member(self.token, chat_id, user_id)
850
851 def restrict_chat_member(self, chat_id, user_id, until_date=None, can_send_messages=None,
852 can_send_media_messages=None, can_send_other_messages=None,
853 can_add_web_page_previews=None):
854 """
855 Use this method to restrict a user in a supergroup.
856 The bot must be an administrator in the supergroup for this to work and must have
857 the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user.
858 Returns True on success.
859 :param chat_id: Int or String : Unique identifier for the target group or username of the target supergroup
860 or channel (in the format @channelusername)
861 :param user_id: Int : Unique identifier of the target user
862 :param until_date: Date when restrictions will be lifted for the user, unix time.
863 If user is restricted for more than 366 days or less than 30 seconds from the current time,
864 they are considered to be restricted forever
865 :param can_send_messages: Pass True, if the user can send text messages, contacts, locations and venues
866 :param can_send_media_messages Pass True, if the user can send audios, documents, photos, videos, video notes
867 and voice notes, implies can_send_messages
868 :param can_send_other_messages: Pass True, if the user can send animations, games, stickers and
869 use inline bots, implies can_send_media_messages
870 :param can_add_web_page_previews: Pass True, if the user may add web page previews to their messages,
871 implies can_send_media_messages
872 :return: types.Message
873 """
874 return apihelper.restrict_chat_member(self.token, chat_id, user_id, until_date, can_send_messages,
875 can_send_media_messages, can_send_other_messages,
876 can_add_web_page_previews)
877
878 def promote_chat_member(self, chat_id, user_id, can_change_info=None, can_post_messages=None,
879 can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
880 can_restrict_members=None, can_pin_messages=None, can_promote_members=None):
881 """
882 Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator
883 in the chat for this to work and must have the appropriate admin rights.
884 Pass False for all boolean parameters to demote a user. Returns True on success.
885 :param chat_id: Unique identifier for the target chat or username of the target channel (
886 in the format @channelusername)
887 :param user_id: Int : Unique identifier of the target user
888 :param can_change_info: Bool: Pass True, if the administrator can change chat title, photo and other settings
889 :param can_post_messages: Bool : Pass True, if the administrator can create channel posts, channels only
890 :param can_edit_messages: Bool : Pass True, if the administrator can edit messages of other users, channels only
891 :param can_delete_messages: Bool : Pass True, if the administrator can delete messages of other users
892 :param can_invite_users: Bool : Pass True, if the administrator can invite new users to the chat
893 :param can_restrict_members: Bool: Pass True, if the administrator can restrict, ban or unban chat members
894 :param can_pin_messages: Bool: Pass True, if the administrator can pin messages, supergroups only
895 :param can_promote_members: Bool: Pass True, if the administrator can add new administrators with a subset
896 of his own privileges or demote administrators that he has promoted, directly or indirectly
897 (promoted by administrators that were appointed by him)
898 :return:
899 """
900 return apihelper.promote_chat_member(self.token, chat_id, user_id, can_change_info, can_post_messages,
901 can_edit_messages, can_delete_messages, can_invite_users,
902 can_restrict_members, can_pin_messages, can_promote_members)
903
904 def export_chat_invite_link(self, chat_id):
905 """
906 Use this method to export an invite link to a supergroup or a channel. The bot must be an administrator
907 in the chat for this to work and must have the appropriate admin rights.
908 Returns exported invite link as String on success.
909 :param chat_id: Id: Unique identifier for the target chat or username of the target channel
910 (in the format @channelusername)
911 :return:
912 """
913 return apihelper.export_chat_invite_link(self.token, chat_id)
914
915 def set_chat_photo(self, chat_id, photo):
916 """
917 Use this method to set a new profile photo for the chat. Photos can't be changed for private chats.
918 The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
919 Returns True on success.
920 Note: In regular groups (non-supergroups), this method will only work if the ‘All Members Are Admins’
921 setting is off in the target group.
922 :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel
923 (in the format @channelusername)
924 :param photo: InputFile: New chat photo, uploaded using multipart/form-data
925 :return:
926 """
927 return apihelper.set_chat_photo(self.token, chat_id, photo)
928
929 def delete_chat_photo(self, chat_id):
930 """
931 Use this method to delete a chat photo. Photos can't be changed for private chats.
932 The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
933 Returns True on success.
934 Note: In regular groups (non-supergroups), this method will only work if the ‘All Members Are Admins’
935 setting is off in the target group.
936 :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel
937 (in the format @channelusername)
938 :return:
939 """
940 return apihelper.delete_chat_photo(self.token, chat_id)
941
942 def set_chat_title(self, chat_id, title):
943 """
944 Use this method to change the title of a chat. Titles can't be changed for private chats.
945 The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
946 Returns True on success.
947 Note: In regular groups (non-supergroups), this method will only work if the ‘All Members Are Admins’
948 setting is off in the target group.
949 :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel
950 (in the format @channelusername)
951 :param title: New chat title, 1-255 characters
952 :return:
953 """
954 return apihelper.set_chat_title(self.token, chat_id, title)
955
956 def set_chat_description(self, chat_id, description):
957 """
958 Use this method to change the description of a supergroup or a channel.
959 The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
960 Returns True on success.
961 :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel
962 (in the format @channelusername)
963 :param description: Str: New chat description, 0-255 characters
964 :return:
965 """
966 return apihelper.set_chat_description(self.token, chat_id, description)
967
968 def pin_chat_message(self, chat_id, message_id, disable_notification=False):
969 """
970 Use this method to pin a message in a supergroup.
971 The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
972 Returns True on success.
973 :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel
974 (in the format @channelusername)
975 :param message_id: Int: Identifier of a message to pin
976 :param disable_notification: Bool: Pass True, if it is not necessary to send a notification
977 to all group members about the new pinned message
978 :return:
979 """
980 return apihelper.pin_chat_message(self.token, chat_id, message_id, disable_notification)
981
982 def unpin_chat_message(self, chat_id):
983 """
984 Use this method to unpin a message in a supergroup chat.
985 The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
986 Returns True on success.
987 :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel
988 (in the format @channelusername)
989 :return:
990 """
991 return apihelper.unpin_chat_message(self.token, chat_id)
992
993 def edit_message_text(self, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None,
994 disable_web_page_preview=None, reply_markup=None):
995 result = apihelper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
996 disable_web_page_preview, reply_markup)
997 if type(result) == bool: # if edit inline message return is bool not Message.
998 return result
999 return types.Message.de_json(result)
1000
1001 def edit_message_media(self, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
1002 result = apihelper.edit_message_media(self.token, media, chat_id, message_id, inline_message_id, reply_markup)
1003 if type(result) == bool: # if edit inline message return is bool not Message.
1004 return result
1005 return types.Message.de_json(result)
1006
1007 def edit_message_reply_markup(self, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
1008 result = apihelper.edit_message_reply_markup(self.token, chat_id, message_id, inline_message_id, reply_markup)
1009 if type(result) == bool:
1010 return result
1011 return types.Message.de_json(result)
1012
1013 def send_game(self, chat_id, game_short_name, disable_notification=None, reply_to_message_id=None,
1014 reply_markup=None):
1015 result = apihelper.send_game(self.token, chat_id, game_short_name, disable_notification, reply_to_message_id,
1016 reply_markup)
1017 return types.Message.de_json(result)
1018
1019 def set_game_score(self, user_id, score, force=None, chat_id=None, message_id=None, inline_message_id=None,
1020 edit_message=None):
1021 result = apihelper.set_game_score(self.token, user_id, score, force, chat_id, message_id, inline_message_id,
1022 edit_message)
1023 if type(result) == bool:
1024 return result
1025 return types.Message.de_json(result)
1026
1027 def get_game_high_scores(self, user_id, chat_id=None, message_id=None, inline_message_id=None):
1028 result = apihelper.get_game_high_scores(self.token, user_id, chat_id, message_id, inline_message_id)
1029 ret = []
1030 for r in result:
1031 ret.append(types.GameHighScore.de_json(r))
1032 return ret
1033
1034 def send_invoice(self, chat_id, title, description, invoice_payload, provider_token, currency, prices,
1035 start_parameter, photo_url=None, photo_size=None, photo_width=None, photo_height=None,
1036 need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None,
1037 is_flexible=None, disable_notification=None, reply_to_message_id=None, reply_markup=None,
1038 provider_data=None):
1039 result = apihelper.send_invoice(self.token, chat_id, title, description, invoice_payload, provider_token,
1040 currency, prices, start_parameter, photo_url, photo_size, photo_width,
1041 photo_height,
1042 need_name, need_phone_number, need_email, need_shipping_address, is_flexible,
1043 disable_notification, reply_to_message_id, reply_markup, provider_data)
1044 return types.Message.de_json(result)
1045
1046 def answer_shipping_query(self, shipping_query_id, ok, shipping_options=None, error_message=None):
1047 return apihelper.answer_shipping_query(self.token, shipping_query_id, ok, shipping_options, error_message)
1048
1049 def answer_pre_checkout_query(self, pre_checkout_query_id, ok, error_message=None):
1050 return apihelper.answer_pre_checkout_query(self.token, pre_checkout_query_id, ok, error_message)
1051
1052 def edit_message_caption(self, caption, chat_id=None, message_id=None, inline_message_id=None,
1053 parse_mode=None, reply_markup=None):
1054 result = apihelper.edit_message_caption(self.token, caption, chat_id, message_id, inline_message_id,
1055 parse_mode, reply_markup)
1056 if type(result) == bool:
1057 return result
1058 return types.Message.de_json(result)
1059
1060 def reply_to(self, message, text, **kwargs):
1061 """
1062 Convenience function for `send_message(message.chat.id, text, reply_to_message_id=message.message_id, **kwargs)`
1063 """
1064 return self.send_message(message.chat.id, text, reply_to_message_id=message.message_id, **kwargs)
1065
1066 def answer_inline_query(self, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
1067 switch_pm_text=None, switch_pm_parameter=None):
1068 """
1069 Use this method to send answers to an inline query. On success, True is returned.
1070 No more than 50 results per query are allowed.
1071 :param inline_query_id: Unique identifier for the answered query
1072 :param results: Array of results for the inline query
1073 :param cache_time: The maximum amount of time in seconds that the result of the inline query may be cached on the server.
1074 :param is_personal: Pass True, if results may be cached on the server side only for the user that sent the query.
1075 :param next_offset: Pass the offset that a client should send in the next query with the same text to receive more results.
1076 :param switch_pm_parameter: If passed, clients will display a button with specified text that switches the user
1077 to a private chat with the bot and sends the bot a start message with the parameter switch_pm_parameter
1078 :param switch_pm_text: Parameter for the start message sent to the bot when user presses the switch button
1079 :return: True means success.
1080 """
1081 return apihelper.answer_inline_query(self.token, inline_query_id, results, cache_time, is_personal, next_offset,
1082 switch_pm_text, switch_pm_parameter)
1083
1084 def answer_callback_query(self, callback_query_id, text=None, show_alert=None, url=None, cache_time=None):
1085 """
1086 Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to
1087 the user as a notification at the top of the chat screen or as an alert.
1088 :param callback_query_id:
1089 :param text:
1090 :param show_alert:
1091 :return:
1092 """
1093 return apihelper.answer_callback_query(self.token, callback_query_id, text, show_alert, url, cache_time)
1094
1095 # def send_sticker(self, chat_id, sticker, disable_notification=None, reply_to_message_id=None, reply_markup=None):
1096 # """
1097 # Use this method to send .webp stickers. On success, the sent Message is returned.
1098 # :param chat_id:
1099 # :param sticker:
1100 # :param disable_notification:
1101 # :param reply_to_message_id:
1102 # :param reply_markup:
1103 # :return:
1104 # """
1105 # result = apihelper.send_sticker(self.token, chat_id, sticker, disable_notification, reply_markup, reply_markup)
1106 # return types.Message.de_json(result)
1107
1108 def get_sticker_set(self, name):
1109 """
1110 Use this method to get a sticker set. On success, a StickerSet object is returned.
1111 :param name:
1112 :return:
1113 """
1114 result = apihelper.get_sticker_set(self.token, name)
1115 return types.StickerSet.de_json(result)
1116
1117 def upload_sticker_file(self, user_id, png_sticker):
1118 """
1119 Use this method to upload a .png file with a sticker for later use in createNewStickerSet and addStickerToSet
1120 methods (can be used multiple times). Returns the uploaded File on success.
1121 :param user_id:
1122 :param png_sticker:
1123 :return:
1124 """
1125 result = apihelper.upload_sticker_file(self.token, user_id, png_sticker)
1126 return types.File.de_json(result)
1127
1128 def create_new_sticker_set(self, user_id, name, title, png_sticker, emojis, contains_masks=None,
1129 mask_position=None):
1130 """
1131 Use this method to create new sticker set owned by a user. The bot will be able to edit the created sticker set.
1132 Returns True on success.
1133 :param user_id:
1134 :param name:
1135 :param title:
1136 :param png_sticker:
1137 :param emojis:
1138 :param contains_masks:
1139 :param mask_position:
1140 :return:
1141 """
1142 return apihelper.create_new_sticker_set(self.token, user_id, name, title, png_sticker, emojis, contains_masks,
1143 mask_position)
1144
1145 def add_sticker_to_set(self, user_id, name, png_sticker, emojis, mask_position=None):
1146 """
1147 Use this method to add a new sticker to a set created by the bot. Returns True on success.
1148 :param user_id:
1149 :param name:
1150 :param png_sticker:
1151 :param emojis:
1152 :param mask_position:
1153 :return:
1154 """
1155 return apihelper.add_sticker_to_set(self.token, user_id, name, png_sticker, emojis, mask_position)
1156
1157 def set_sticker_position_in_set(self, sticker, position):
1158 """
1159 Use this method to move a sticker in a set created by the bot to a specific position . Returns True on success.
1160 :param sticker:
1161 :param position:
1162 :return:
1163 """
1164 return apihelper.set_sticker_position_in_set(self.token, sticker, position)
1165
1166 def delete_sticker_from_set(self, sticker):
1167 """
1168 Use this method to delete a sticker from a set created by the bot. Returns True on success.
1169 :param sticker:
1170 :return:
1171 """
1172 return apihelper.delete_sticker_from_set(self.token, sticker)
1173
1174 def register_for_reply(self, message, callback, *args, **kwargs):
1175 """
1176 Registers a callback function to be notified when a reply to `message` arrives.
1177
1178 Warning: In case `callback` as lambda function, saving reply handlers will not work.
1179
1180 :param message: The message for which we are awaiting a reply.
1181 :param callback: The callback function to be called when a reply arrives. Must accept one `message`
1182 parameter, which will contain the replied message.
1183 """
1184 message_id = message.message_id
1185 self.register_for_reply_by_message_id(message_id, callback, *args, **kwargs)
1186
1187 def register_for_reply_by_message_id(self, message_id, callback, *args, **kwargs):
1188 """
1189 Registers a callback function to be notified when a reply to `message` arrives.
1190
1191 Warning: In case `callback` as lambda function, saving reply handlers will not work.
1192
1193 :param message_id: The id of the message for which we are awaiting a reply.
1194 :param callback: The callback function to be called when a reply arrives. Must accept one `message`
1195 parameter, which will contain the replied message.
1196 """
1197 if message_id in self.reply_handlers.keys():
1198 self.reply_handlers[message_id].append(Handler(callback, *args, **kwargs))
1199 else:
1200 self.reply_handlers[message_id] = [Handler(callback, *args, **kwargs)]
1201 if self.reply_saver is not None:
1202 self.reply_saver.start_save_timer()
1203
1204 def _notify_reply_handlers(self, new_messages):
1205 for message in new_messages:
1206 if hasattr(message, "reply_to_message") and message.reply_to_message is not None:
1207 reply_msg_id = message.reply_to_message.message_id
1208 if reply_msg_id in self.reply_handlers.keys():
1209 handlers = self.reply_handlers[reply_msg_id]
1210 for handler in handlers:
1211 self._exec_task(handler["callback"], message, *handler["args"], **handler["kwargs"])
1212 self.reply_handlers.pop(reply_msg_id)
1213 if self.reply_saver is not None:
1214 self.reply_saver.start_save_timer()
1215
1216 def register_next_step_handler(self, message, callback, *args, **kwargs):
1217 """
1218 Registers a callback function to be notified when new message arrives after `message`.
1219
1220 Warning: In case `callback` as lambda function, saving next step handlers will not work.
1221
1222 :param message: The message for which we want to handle new message in the same chat.
1223 :param callback: The callback function which next new message arrives.
1224 :param args: Args to pass in callback func
1225 :param kwargs: Args to pass in callback func
1226 """
1227 chat_id = message.chat.id
1228 self.register_next_step_handler_by_chat_id(chat_id, callback, *args, **kwargs)
1229
1230 def register_next_step_handler_by_chat_id(self, chat_id, callback, *args, **kwargs):
1231 """
1232 Registers a callback function to be notified when new message arrives after `message`.
1233
1234 Warning: In case `callback` as lambda function, saving next step handlers will not work.
1235
1236 :param chat_id: The chat for which we want to handle new message.
1237 :param callback: The callback function which next new message arrives.
1238 :param args: Args to pass in callback func
1239 :param kwargs: Args to pass in callback func
1240 """
1241 if chat_id in self.next_step_handlers.keys():
1242 self.next_step_handlers[chat_id].append(Handler(callback, *args, **kwargs))
1243 else:
1244 self.next_step_handlers[chat_id] = [Handler(callback, *args, **kwargs)]
1245
1246 if self.next_step_saver is not None:
1247 self.next_step_saver.start_save_timer()
1248
1249 def clear_step_handler(self, message):
1250 """
1251 Clears all callback functions registered by register_next_step_handler().
1252
1253 :param message: The message for which we want to handle new message after that in same chat.
1254 """
1255 chat_id = message.chat.id
1256 self.clear_step_handler_by_chat_id(chat_id)
1257
1258 def clear_step_handler_by_chat_id(self, chat_id):
1259 """
1260 Clears all callback functions registered by register_next_step_handler().
1261
1262 :param chat_id: The chat for which we want to clear next step handlers
1263 """
1264 self.next_step_handlers[chat_id] = []
1265
1266 if self.next_step_saver is not None:
1267 self.next_step_saver.start_save_timer()
1268
1269 def clear_reply_handlers(self, message):
1270 """
1271 Clears all callback functions registered by register_for_reply() and register_for_reply_by_message_id().
1272
1273 :param message: The message for which we want to clear reply handlers
1274 """
1275 message_id = message.message_id
1276 self.clear_reply_handlers_by_message_id(message_id)
1277
1278 def clear_reply_handlers_by_message_id(self, message_id):
1279 """
1280 Clears all callback functions registered by register_for_reply() and register_for_reply_by_message_id().
1281
1282 :param message_id: The message id for which we want to clear reply handlers
1283 """
1284 self.reply_handlers[message_id] = []
1285
1286 if self.reply_saver is not None:
1287 self.reply_saver.start_save_timer()
1288
1289 def _notify_next_handlers(self, new_messages):
1290 i = 0
1291 while i < len(new_messages):
1292 message = new_messages[i]
1293 chat_id = message.chat.id
1294 was_poped = False
1295 if chat_id in self.next_step_handlers.keys():
1296 handlers = self.next_step_handlers.pop(chat_id, None)
1297 if (handlers):
1298 for handler in handlers:
1299 self._exec_task(handler["callback"], message, *handler["args"], **handler["kwargs"])
1300 new_messages.pop(i) # removing message that detects with next_step_handler
1301 was_poped = True
1302 if self.next_step_saver is not None:
1303 self.next_step_saver.start_save_timer()
1304 if (not was_poped):
1305 i += 1
1306
1307
1308 @staticmethod
1309 def _build_handler_dict(handler, **filters):
1310 return {
1311 'function': handler,
1312 'filters': filters
1313 }
1314
1315 def message_handler(self, commands=None, regexp=None, func=None, content_types=['text'], **kwargs):
1316 """
1317 Message handler decorator.
1318 This decorator can be used to decorate functions that must handle certain types of messages.
1319 All message handlers are tested in the order they were added.
1320
1321 Example:
1322
1323 bot = TeleBot('TOKEN')
1324
1325 # Handles all messages which text matches regexp.
1326 @bot.message_handler(regexp='someregexp')
1327 def command_help(message):
1328 bot.send_message(message.chat.id, 'Did someone call for help?')
1329
1330 # Handle all sent documents of type 'text/plain'.
1331 @bot.message_handler(func=lambda message: message.document.mime_type == 'text/plain', content_types=['document'])
1332 def command_handle_document(message):
1333 bot.send_message(message.chat.id, 'Document received, sir!')
1334
1335 # Handle all other commands.
1336 @bot.message_handler(func=lambda message: True, content_types=['audio', 'video', 'document', 'text', 'location', 'contact', 'sticker'])
1337 def default_command(message):
1338 bot.send_message(message.chat.id, "This is the default command handler.")
1339
1340 :param regexp: Optional regular expression.
1341 :param func: Optional lambda function. The lambda receives the message to test as the first parameter. It must return True if the command should handle the message.
1342 :param content_types: This commands' supported content types. Must be a list. Defaults to ['text'].
1343 """
1344
1345 def decorator(handler):
1346 handler_dict = self._build_handler_dict(handler,
1347 commands=commands,
1348 regexp=regexp,
1349 func=func,
1350 content_types=content_types,
1351 **kwargs)
1352
1353 self.add_message_handler(handler_dict)
1354
1355 return handler
1356
1357 return decorator
1358
1359 def add_message_handler(self, handler_dict):
1360 self.message_handlers.append(handler_dict)
1361
1362 def edited_message_handler(self, commands=None, regexp=None, func=None, content_types=['text'], **kwargs):
1363 def decorator(handler):
1364 handler_dict = self._build_handler_dict(handler,
1365 commands=commands,
1366 regexp=regexp,
1367 func=func,
1368 content_types=content_types,
1369 **kwargs)
1370 self.add_edited_message_handler(handler_dict)
1371 return handler
1372
1373 return decorator
1374
1375 def add_edited_message_handler(self, handler_dict):
1376 self.edited_message_handlers.append(handler_dict)
1377
1378 def channel_post_handler(self, commands=None, regexp=None, func=None, content_types=['text'], **kwargs):
1379 def decorator(handler):
1380 handler_dict = self._build_handler_dict(handler,
1381 commands=commands,
1382 regexp=regexp,
1383 func=func,
1384 content_types=content_types,
1385 **kwargs)
1386 self.add_channel_post_handler(handler_dict)
1387 return handler
1388
1389 return decorator
1390
1391 def add_channel_post_handler(self, handler_dict):
1392 self.channel_post_handlers.append(handler_dict)
1393
1394 def edited_channel_post_handler(self, commands=None, regexp=None, func=None, content_types=['text'], **kwargs):
1395 def decorator(handler):
1396 handler_dict = self._build_handler_dict(handler,
1397 commands=commands,
1398 regexp=regexp,
1399 func=func,
1400 content_types=content_types,
1401 **kwargs)
1402 self.add_edited_channel_post_handler(handler_dict)
1403 return handler
1404
1405 return decorator
1406
1407 def add_edited_channel_post_handler(self, handler_dict):
1408 self.edited_channel_post_handlers.append(handler_dict)
1409
1410 def inline_handler(self, func, **kwargs):
1411 def decorator(handler):
1412 handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
1413 self.add_inline_handler(handler_dict)
1414 return handler
1415
1416 return decorator
1417
1418 def add_inline_handler(self, handler_dict):
1419 self.inline_handlers.append(handler_dict)
1420
1421 def chosen_inline_handler(self, func, **kwargs):
1422 def decorator(handler):
1423 handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
1424 self.add_chosen_inline_handler(handler_dict)
1425 return handler
1426
1427 return decorator
1428
1429 def add_chosen_inline_handler(self, handler_dict):
1430 self.chosen_inline_handlers.append(handler_dict)
1431
1432 def callback_query_handler(self, func, **kwargs):
1433 def decorator(handler):
1434 handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
1435 self.add_callback_query_handler(handler_dict)
1436 return handler
1437
1438 return decorator
1439
1440 def add_callback_query_handler(self, handler_dict):
1441 self.callback_query_handlers.append(handler_dict)
1442
1443 def shipping_query_handler(self, func, **kwargs):
1444 def decorator(handler):
1445 handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
1446 self.add_shipping_query_handler(handler_dict)
1447 return handler
1448
1449 return decorator
1450
1451 def add_shipping_query_handler(self, handler_dict):
1452 self.shipping_query_handlers.append(handler_dict)
1453
1454 def pre_checkout_query_handler(self, func, **kwargs):
1455 def decorator(handler):
1456 handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
1457 self.add_pre_checkout_query_handler(handler_dict)
1458 return handler
1459
1460 return decorator
1461
1462 def add_pre_checkout_query_handler(self, handler_dict):
1463 self.pre_checkout_query_handlers.append(handler_dict)
1464
1465 def _test_message_handler(self, message_handler, message):
1466 for filter, filter_value in six.iteritems(message_handler['filters']):
1467 if filter_value is None:
1468 continue
1469
1470 if not self._test_filter(filter, filter_value, message):
1471 return False
1472
1473 return True
1474
1475 @staticmethod
1476 def _test_filter(filter, filter_value, message):
1477 test_cases = {
1478 'content_types': lambda msg: msg.content_type in filter_value,
1479 'regexp': lambda msg: msg.content_type == 'text' and re.search(filter_value, msg.text, re.IGNORECASE),
1480 'commands': lambda msg: msg.content_type == 'text' and util.extract_command(msg.text) in filter_value,
1481 'func': lambda msg: filter_value(msg)
1482 }
1483
1484 return test_cases.get(filter, lambda msg: False)(message)
1485
1486 def _notify_command_handlers(self, handlers, new_messages):
1487 for message in new_messages:
1488 for message_handler in handlers:
1489 if self._test_message_handler(message_handler, message):
1490 self._exec_task(message_handler['function'], message)
1491 break
1492
1493
1494class AsyncTeleBot(TeleBot):
1495 def __init__(self, *args, **kwargs):
1496 TeleBot.__init__(self, *args, **kwargs)
1497
1498 @util.async_dec()
1499 def enable_save_next_step_handlers(self, delay=120, filename="./.handler-saves/step.save", del_file_after_loading=True):
1500 return TeleBot.enable_save_next_step_handlers(self, delay, filename, del_file_after_loading)
1501
1502 @util.async_dec()
1503 def enable_save_reply_handlers(self, delay=120, filename="./.handler-saves/reply.save", del_file_after_loading=True):
1504 return TeleBot.enable_save_reply_handlers(self, delay, filename, del_file_after_loading)
1505
1506 @util.async_dec()
1507 def disable_save_next_step_handlers(self):
1508 return TeleBot.disable_save_next_step_handlers(self)
1509
1510 @util.async_dec()
1511 def disable_save_reply_handlers(self):
1512 return TeleBot.enable_save_reply_handlers(self)
1513
1514 @util.async_dec()
1515 def load_next_step_handlers(self, filename="./.handler-saves/step.save"):
1516 return TeleBot.load_next_step_handlers(self, filename)
1517
1518 @util.async_dec()
1519 def load_reply_handlers(self, filename="./.handler-saves/reply.save"):
1520 return TeleBot.load_reply_handlers(self, filename)
1521
1522 @util.async_dec()
1523
1524 @util.async_dec()
1525 def get_me(self):
1526 return TeleBot.get_me(self)
1527
1528 @util.async_dec()
1529 def get_file(self, *args):
1530 return TeleBot.get_file(self, *args)
1531
1532 @util.async_dec()
1533 def download_file(self, *args):
1534 return TeleBot.download_file(self, *args)
1535
1536 @util.async_dec()
1537 def get_user_profile_photos(self, *args, **kwargs):
1538 return TeleBot.get_user_profile_photos(self, *args, **kwargs)
1539
1540 @util.async_dec()
1541 def get_chat(self, *args):
1542 return TeleBot.get_chat(self, *args)
1543
1544 @util.async_dec()
1545 def leave_chat(self, *args):
1546 return TeleBot.leave_chat(self, *args)
1547
1548 @util.async_dec()
1549 def get_chat_administrators(self, *args):
1550 return TeleBot.get_chat_administrators(self, *args)
1551
1552 @util.async_dec()
1553 def get_chat_members_count(self, *args):
1554 return TeleBot.get_chat_members_count(self, *args)
1555
1556 @util.async_dec()
1557 def set_chat_sticker_set(self, *args):
1558 return TeleBot.set_chat_sticker_set(self, *args)
1559
1560 @util.async_dec()
1561 def delete_chat_sticker_set(self, *args):
1562 return TeleBot.delete_chat_sticker_set(self, *args)
1563
1564 @util.async_dec()
1565 def get_chat_member(self, *args):
1566 return TeleBot.get_chat_member(self, *args)
1567
1568 @util.async_dec()
1569 def send_message(self, *args, **kwargs):
1570 return TeleBot.send_message(self, *args, **kwargs)
1571
1572 @util.async_dec()
1573 def forward_message(self, *args, **kwargs):
1574 return TeleBot.forward_message(self, *args, **kwargs)
1575
1576 @util.async_dec()
1577 def delete_message(self, *args):
1578 return TeleBot.delete_message(self, *args)
1579
1580 @util.async_dec()
1581 def send_photo(self, *args, **kwargs):
1582 return TeleBot.send_photo(self, *args, **kwargs)
1583
1584 @util.async_dec()
1585 def send_audio(self, *args, **kwargs):
1586 return TeleBot.send_audio(self, *args, **kwargs)
1587
1588 @util.async_dec()
1589 def send_voice(self, *args, **kwargs):
1590 return TeleBot.send_voice(self, *args, **kwargs)
1591
1592 @util.async_dec()
1593 def send_document(self, *args, **kwargs):
1594 return TeleBot.send_document(self, *args, **kwargs)
1595
1596 @util.async_dec()
1597 def send_sticker(self, *args, **kwargs):
1598 return TeleBot.send_sticker(self, *args, **kwargs)
1599
1600 @util.async_dec()
1601 def send_video(self, *args, **kwargs):
1602 return TeleBot.send_video(self, *args, **kwargs)
1603
1604 @util.async_dec()
1605 def send_video_note(self, *args, **kwargs):
1606 return TeleBot.send_video_note(self, *args, **kwargs)
1607
1608 @util.async_dec()
1609 def send_media_group(self, *args, **kwargs):
1610 return TeleBot.send_media_group(self, *args, **kwargs)
1611
1612 @util.async_dec()
1613 def send_location(self, *args, **kwargs):
1614 return TeleBot.send_location(self, *args, **kwargs)
1615
1616 @util.async_dec()
1617 def edit_message_live_location(self, *args, **kwargs):
1618 return TeleBot.edit_message_live_location(self, *args, **kwargs)
1619
1620 @util.async_dec()
1621 def stop_message_live_location(self, *args, **kwargs):
1622 return TeleBot.stop_message_live_location(self, *args, **kwargs)
1623
1624 @util.async_dec()
1625 def send_venue(self, *args, **kwargs):
1626 return TeleBot.send_venue(self, *args, **kwargs)
1627
1628 @util.async_dec()
1629 def send_contact(self, *args, **kwargs):
1630 return TeleBot.send_contact(self, *args, **kwargs)
1631
1632 @util.async_dec()
1633 def send_chat_action(self, *args, **kwargs):
1634 return TeleBot.send_chat_action(self, *args, **kwargs)
1635
1636 @util.async_dec()
1637 def kick_chat_member(self, *args, **kwargs):
1638 return TeleBot.kick_chat_member(self, *args, **kwargs)
1639
1640 @util.async_dec()
1641 def unban_chat_member(self, *args):
1642 return TeleBot.unban_chat_member(self, *args)
1643
1644 @util.async_dec()
1645 def restrict_chat_member(self, *args, **kwargs):
1646 return TeleBot.restrict_chat_member(self, *args, **kwargs)
1647
1648 @util.async_dec()
1649 def promote_chat_member(self, *args, **kwargs):
1650 return TeleBot.promote_chat_member(self, *args, **kwargs)
1651
1652 @util.async_dec()
1653 def export_chat_invite_link(self, *args):
1654 return TeleBot.export_chat_invite_link(self, *args)
1655
1656 @util.async_dec()
1657 def set_chat_photo(self, *args):
1658 return TeleBot.set_chat_photo(self, *args)
1659
1660 @util.async_dec()
1661 def delete_chat_photo(self, *args):
1662 return TeleBot.delete_chat_photo(self, *args)
1663
1664 @util.async_dec()
1665 def set_chat_title(self, *args):
1666 return TeleBot.set_chat_title(self, *args)
1667
1668 @util.async_dec()
1669 def set_chat_description(self, *args):
1670 return TeleBot.set_chat_description(self, *args)
1671
1672 @util.async_dec()
1673 def pin_chat_message(self, *args, **kwargs):
1674 return TeleBot.pin_chat_message(self, *args, **kwargs)
1675
1676 @util.async_dec()
1677 def unpin_chat_message(self, *args):
1678 return TeleBot.unpin_chat_message(self, *args)
1679
1680 @util.async_dec()
1681 def edit_message_text(self, *args, **kwargs):
1682 return TeleBot.edit_message_text(self, *args, **kwargs)
1683
1684 @util.async_dec()
1685 def edit_message_media(self, *args, **kwargs):
1686 return TeleBot.edit_message_media(self, *args, **kwargs)
1687
1688 @util.async_dec()
1689 def edit_message_reply_markup(self, *args, **kwargs):
1690 return TeleBot.edit_message_reply_markup(self, *args, **kwargs)
1691
1692 @util.async_dec()
1693 def send_game(self, *args, **kwargs):
1694 return TeleBot.send_game(self, *args, **kwargs)
1695
1696 @util.async_dec()
1697 def set_game_score(self, *args, **kwargs):
1698 return TeleBot.set_game_score(self, *args, **kwargs)
1699
1700 @util.async_dec()
1701 def get_game_high_scores(self, *args, **kwargs):
1702 return TeleBot.get_game_high_scores(self, *args, **kwargs)
1703
1704 @util.async_dec()
1705 def send_invoice(self, *args, **kwargs):
1706 return TeleBot.send_invoice(self, *args, **kwargs)
1707
1708 @util.async_dec()
1709 def answer_shipping_query(self, *args, **kwargs):
1710 return TeleBot.answer_shipping_query(self, *args, **kwargs)
1711
1712 @util.async_dec()
1713 def answer_pre_checkout_query(self, *args, **kwargs):
1714 return TeleBot.answer_pre_checkout_query(self, *args, **kwargs)
1715
1716 @util.async_dec()
1717 def edit_message_caption(self, *args, **kwargs):
1718 return TeleBot.edit_message_caption(self, *args, **kwargs)
1719
1720 @util.async_dec()
1721 def answer_inline_query(self, *args, **kwargs):
1722 return TeleBot.answer_inline_query(self, *args, **kwargs)
1723
1724 @util.async_dec()
1725 def answer_callback_query(self, *args, **kwargs):
1726 return TeleBot.answer_callback_query(self, *args, **kwargs)
1727
1728 @util.async_dec()
1729 def send_sticker(self, *args, **kwargs):
1730 return TeleBot.send_sticker(self, *args, **kwargs)
1731
1732 @util.async_dec()
1733 def get_sticker_set(self, *args, **kwargs):
1734 return TeleBot.get_sticker_set(self, *args, **kwargs)
1735
1736 @util.async_dec()
1737 def upload_sticker_file(self, *args, **kwargs):
1738 return TeleBot.upload_sticker_file(self, *args, **kwargs)
1739
1740 @util.async_dec()
1741 def create_new_sticker_set(self, *args, **kwargs):
1742 return TeleBot.create_new_sticker_set(self, *args, **kwargs)
1743
1744 @util.async_dec()
1745 def add_sticker_to_set(self, *args, **kwargs):
1746 return TeleBot.add_sticker_to_set(self, *args, **kwargs)
1747
1748 @util.async_dec()
1749 def set_sticker_position_in_set(self, *args, **kwargs):
1750 return TeleBot.set_sticker_position_in_set(self, *args, **kwargs)
1751
1752 @util.async_dec()
1753 def delete_sticker_from_set(self, *args, **kwargs):
1754 return TeleBot.delete_sticker_from_set(self, *args, **kwargs)