Compare commits

...

10 Commits

Author SHA1 Message Date
Badiboy 7c9b01b10a
Merge pull request #1722 from Badiboy/master
Handlers and Middlewares processing union
2022-09-24 22:16:33 +03:00
Badiboy b3993bb019 Merge remote-tracking branch 'upstream/master' 2022-09-24 22:14:45 +03:00
Badiboy 36b889feab
Merge pull request #1736 from AntonGlyzin/antonglyzin-shopbotlist
Added a new bot to the list
2022-09-24 16:06:33 +03:00
Anton d943f40643 Added a new bot to the list 2022-09-24 15:33:11 +03:00
_run dafafd2ad2
Merge pull request #1735 from coder2020official/class_params
⚙️ Added some frequent parameters to classes(see full list)
2022-09-23 22:06:09 +04:00
coder2020official e002484a9b ⚙️ Added some frequent parameters to classes(see full list)
Added:
- disable_web_page_preview
- disable_notification
- protect_content
- allow_sending_without_reply
2022-09-23 21:52:40 +04:00
Badiboy 52e09637c2 Fix: do not call handler in one more task 2022-09-17 23:17:07 +03:00
Badiboy e7a96ec2ed Rename also in Async 2022-09-17 14:09:05 +03:00
Badiboy 598de25b6d Rename _check_middlewares to _get_middlewares 2022-09-17 12:55:55 +03:00
Badiboy da639dd1f6 Handlers and Middlewares processing union
Call for handlers now union in a single function for future extension.

Plus minor fixes in storages.
2022-09-17 11:57:12 +03:00
8 changed files with 353 additions and 128 deletions

View File

@ -885,5 +885,6 @@ Here are some examples of template:
* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang is a multi-functional robot, such as OSU game information query, IP test, animation screenshot search and other functions. * [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang is a multi-functional robot, such as OSU game information query, IP test, animation screenshot search and other functions.
* [Feedback-bot](https://github.com/coder2020official/feedbackbot) A feedback bot for user-admin communication. Made on AsyncTeleBot, using [template](https://github.com/coder2020official/asynctelebot_template). * [Feedback-bot](https://github.com/coder2020official/feedbackbot) A feedback bot for user-admin communication. Made on AsyncTeleBot, using [template](https://github.com/coder2020official/asynctelebot_template).
* [TeleServ](https://github.com/ablakely/TeleServ) by [ablakely](https://github.com/ablakely) This is a Telegram to IRC bridge which links as an IRC server and makes Telegram users appear as native IRC users. * [TeleServ](https://github.com/ablakely/TeleServ) by [ablakely](https://github.com/ablakely) This is a Telegram to IRC bridge which links as an IRC server and makes Telegram users appear as native IRC users.
* [Simple Store Bot](https://github.com/AntonGlyzin/myshopbot) by [Anton Glyzin](https://github.com/AntonGlyzin) This is a simple telegram-store with an admin panel. Designed according to a template.
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**

View File

@ -131,6 +131,18 @@ class TeleBot:
:param use_class_middlewares: Use class middlewares, defaults to False :param use_class_middlewares: Use class middlewares, defaults to False
:type use_class_middlewares: :obj:`bool`, optional :type use_class_middlewares: :obj:`bool`, optional
:param disable_web_page_preview: Default value for disable_web_page_preview, defaults to None
:type disable_web_page_preview: :obj:`bool`, optional
:param disable_notification: Default value for disable_notification, defaults to None
:type disable_notification: :obj:`bool`, optional
:param protect_content: Default value for protect_content, defaults to None
:type protect_content: :obj:`bool`, optional
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
:type allow_sending_without_reply: :obj:`bool`, optional
""" """
def __init__( def __init__(
@ -139,18 +151,32 @@ class TeleBot:
next_step_backend: Optional[HandlerBackend]=None, reply_backend: Optional[HandlerBackend]=None, next_step_backend: Optional[HandlerBackend]=None, reply_backend: Optional[HandlerBackend]=None,
exception_handler: Optional[ExceptionHandler]=None, last_update_id: Optional[int]=0, exception_handler: Optional[ExceptionHandler]=None, last_update_id: Optional[int]=0,
suppress_middleware_excepions: Optional[bool]=False, state_storage: Optional[StateStorageBase]=StateMemoryStorage(), suppress_middleware_excepions: Optional[bool]=False, state_storage: Optional[StateStorageBase]=StateMemoryStorage(),
use_class_middlewares: Optional[bool]=False use_class_middlewares: Optional[bool]=False,
disable_web_page_preview: Optional[bool]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
allow_sending_without_reply: Optional[bool]=None
): ):
self.token = token
self.parse_mode = parse_mode
self.update_listener = []
self.skip_pending = skip_pending
self.suppress_middleware_excepions = suppress_middleware_excepions
self.__stop_polling = threading.Event() # update-related
self.token = token
self.skip_pending = skip_pending # backward compatibility
self.last_update_id = last_update_id self.last_update_id = last_update_id
# propertys
self.suppress_middleware_excepions = suppress_middleware_excepions
self.parse_mode = parse_mode
self.disable_web_page_preview = disable_web_page_preview
self.disable_notification = disable_notification
self.protect_content = protect_content
self.allow_sending_without_reply = allow_sending_without_reply
# threading-related
self.__stop_polling = threading.Event()
self.exc_info = None self.exc_info = None
# states & register_next_step_handler
self.current_states = state_storage
self.next_step_backend = next_step_backend self.next_step_backend = next_step_backend
if not self.next_step_backend: if not self.next_step_backend:
self.next_step_backend = MemoryHandlerBackend() self.next_step_backend = MemoryHandlerBackend()
@ -159,8 +185,9 @@ class TeleBot:
if not self.reply_backend: if not self.reply_backend:
self.reply_backend = MemoryHandlerBackend() self.reply_backend = MemoryHandlerBackend()
# handlers
self.exception_handler = exception_handler self.exception_handler = exception_handler
self.update_listener = []
self.message_handlers = [] self.message_handlers = []
self.edited_message_handlers = [] self.edited_message_handlers = []
self.channel_post_handlers = [] self.channel_post_handlers = []
@ -178,8 +205,7 @@ class TeleBot:
self.custom_filters = {} self.custom_filters = {}
self.state_handlers = [] self.state_handlers = []
self.current_states = state_storage # middlewares
self.use_class_middlewares = use_class_middlewares self.use_class_middlewares = use_class_middlewares
if apihelper.ENABLE_MIDDLEWARE and not use_class_middlewares: if apihelper.ENABLE_MIDDLEWARE and not use_class_middlewares:
self.typed_middleware_handlers = { self.typed_middleware_handlers = {
@ -205,6 +231,8 @@ class TeleBot:
'You are using class based middlewares while having ENABLE_MIDDLEWARE set to True. This is not recommended.' 'You are using class based middlewares while having ENABLE_MIDDLEWARE set to True. This is not recommended.'
) )
self.middlewares = [] if use_class_middlewares else None self.middlewares = [] if use_class_middlewares else None
# threads
self.threaded = threaded self.threaded = threaded
if self.threaded: if self.threaded:
self.worker_pool = util.ThreadPool(self, num_threads=num_threads) self.worker_pool = util.ThreadPool(self, num_threads=num_threads)
@ -469,6 +497,7 @@ class TeleBot:
webhook_url = "{}://{}:{}/{}".format(protocol, listen, port, url_path) webhook_url = "{}://{}:{}/{}".format(protocol, listen, port, url_path)
if certificate and certificate_key: if certificate and certificate_key:
# noinspection PyTypeChecker
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx.load_cert_chain(certificate, certificate_key) ssl_ctx.load_cert_chain(certificate, certificate_key)
@ -1087,11 +1116,6 @@ class TeleBot:
def _exec_task(self, task, *args, **kwargs): def _exec_task(self, task, *args, **kwargs):
if kwargs:
if kwargs.pop('task_type', "") == 'handler':
if kwargs.pop('pass_bot', False):
kwargs['bot'] = self
if self.threaded: if self.threaded:
self.worker_pool.put(task, *args, **kwargs) self.worker_pool.put(task, *args, **kwargs)
else: else:
@ -1444,6 +1468,10 @@ class TeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_message( apihelper.send_message(
@ -1482,6 +1510,9 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
return types.Message.de_json( return types.Message.de_json(
apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content)) apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content))
@ -1544,6 +1575,11 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.MessageID.de_json( return types.MessageID.de_json(
apihelper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities, apihelper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities,
disable_notification, reply_to_message_id, allow_sending_without_reply, reply_markup, disable_notification, reply_to_message_id, allow_sending_without_reply, reply_markup,
@ -1621,6 +1657,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_dice( apihelper.send_dice(
self.token, chat_id, emoji, disable_notification, reply_to_message_id, self.token, chat_id, emoji, disable_notification, reply_to_message_id,
@ -1684,6 +1724,9 @@ class TeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_photo( apihelper.send_photo(
@ -1769,6 +1812,9 @@ class TeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_audio( apihelper.send_audio(
@ -1837,6 +1883,9 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_voice( apihelper.send_voice(
@ -1917,6 +1966,10 @@ class TeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if data and not(document): if data and not(document):
# function typo miss compatibility # function typo miss compatibility
document = data document = data
@ -1981,9 +2034,14 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if data and not(sticker): if data and not(sticker):
# function typo miss compatibility # function typo miss compatibility
sticker = data sticker = data
return types.Message.de_json( return types.Message.de_json(
apihelper.send_data( apihelper.send_data(
self.token, chat_id, sticker, 'sticker', self.token, chat_id, sticker, 'sticker',
@ -2071,6 +2129,10 @@ class TeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if data and not(video): if data and not(video):
# function typo miss compatibility # function typo miss compatibility
video = data video = data
@ -2157,6 +2219,9 @@ class TeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_animation( apihelper.send_animation(
@ -2224,6 +2289,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_video_note( apihelper.send_video_note(
self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup, self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
@ -2270,6 +2339,10 @@ class TeleBot:
:return: On success, an array of Messages that were sent is returned. :return: On success, an array of Messages that were sent is returned.
:rtype: List[types.Message] :rtype: List[types.Message]
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
result = apihelper.send_media_group( result = apihelper.send_media_group(
self.token, chat_id, media, disable_notification, reply_to_message_id, timeout, self.token, chat_id, media, disable_notification, reply_to_message_id, timeout,
allow_sending_without_reply, protect_content) allow_sending_without_reply, protect_content)
@ -2338,6 +2411,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_location( apihelper.send_location(
self.token, chat_id, latitude, longitude, live_period, self.token, chat_id, latitude, longitude, live_period,
@ -2509,6 +2586,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_venue( apihelper.send_venue(
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
@ -2571,6 +2652,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
apihelper.send_contact( apihelper.send_contact(
self.token, chat_id, phone_number, first_name, last_name, vcard, self.token, chat_id, phone_number, first_name, last_name, vcard,
@ -3322,6 +3407,8 @@ class TeleBot:
:return: True on success. :return: True on success.
:rtype: :obj:`bool` :rtype: :obj:`bool`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
return apihelper.pin_chat_message(self.token, chat_id, message_id, disable_notification) return apihelper.pin_chat_message(self.token, chat_id, message_id, disable_notification)
def unpin_chat_message(self, chat_id: Union[int, str], message_id: Optional[int]=None) -> bool: def unpin_chat_message(self, chat_id: Union[int, str], message_id: Optional[int]=None) -> bool:
@ -3403,6 +3490,7 @@ class TeleBot:
:rtype: :obj:`types.Message` or :obj:`bool` :rtype: :obj:`types.Message` or :obj:`bool`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
result = apihelper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode, result = apihelper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
entities, disable_web_page_preview, reply_markup) entities, disable_web_page_preview, reply_markup)
@ -3515,6 +3603,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :obj:`types.Message` :rtype: :obj:`types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
result = apihelper.send_game( result = apihelper.send_game(
self.token, chat_id, game_short_name, disable_notification, self.token, chat_id, game_short_name, disable_notification,
reply_to_message_id, reply_markup, timeout, reply_to_message_id, reply_markup, timeout,
@ -3717,6 +3809,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :obj:`types.Message` :rtype: :obj:`types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
result = apihelper.send_invoice( result = apihelper.send_invoice(
self.token, chat_id, title, description, invoice_payload, provider_token, self.token, chat_id, title, description, invoice_payload, provider_token,
currency, prices, start_parameter, photo_url, photo_size, photo_width, currency, prices, start_parameter, photo_url, photo_size, photo_width,
@ -3918,6 +4014,10 @@ class TeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :obj:`types.Message` :rtype: :obj:`types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if isinstance(question, types.Poll): if isinstance(question, types.Poll):
raise RuntimeError("The send_poll signature was changed, please see send_poll function details.") raise RuntimeError("The send_poll signature was changed, please see send_poll function details.")
@ -4790,8 +4890,14 @@ class TeleBot:
if not isinstance(regexp, str): if not isinstance(regexp, str):
logger.error(f"{method_name}: Regexp filter should be string. Not able to use the supplied type.") logger.error(f"{method_name}: Regexp filter should be string. Not able to use the supplied type.")
def message_handler(self, commands: Optional[List[str]]=None, regexp: Optional[str]=None, func: Optional[Callable]=None, def message_handler(
content_types: Optional[List[str]]=None, chat_types: Optional[List[str]]=None, **kwargs): self,
commands: Optional[List[str]]=None,
regexp: Optional[str]=None,
func: Optional[Callable]=None,
content_types: Optional[List[str]]=None,
chat_types: Optional[List[str]]=None,
**kwargs):
""" """
Handles New incoming message of any kind - text, photo, sticker, etc. Handles New incoming message of any kind - text, photo, sticker, etc.
As a parameter to the decorator function, it passes :class:`telebot.types.Message` object. As a parameter to the decorator function, it passes :class:`telebot.types.Message` object.
@ -5875,7 +5981,7 @@ class TeleBot:
return False return False
# middleware check-up method # middleware check-up method
def _check_middleware(self, update_type): def _get_middlewares(self, update_type):
""" """
Check middleware Check middleware
@ -5889,100 +5995,115 @@ class TeleBot:
def _run_middlewares_and_handler(self, message, handlers, middlewares, update_type): def _run_middlewares_and_handler(self, message, handlers, middlewares, update_type):
""" """
This class is made to run handler and middleware in queue. This method is made to run handlers and middlewares in queue.
:param handler: handler that should be executed. :param message: received message (update part) to process with handlers and/or middlewares
:param middleware: middleware that should be executed. :param handlers: all created handlers (not filtered)
:param middlewares: middlewares that should be executed (already filtered)
:param update_type: handler/update type (Update field name)
:return: :return:
""" """
data = {}
params =[]
handler_error = None
skip_handlers = False
if middlewares: if not self.use_class_middlewares:
for middleware in middlewares: if handlers:
if middleware.update_sensitive:
if hasattr(middleware, f'pre_process_{update_type}'):
result = getattr(middleware, f'pre_process_{update_type}')(message, data)
else:
logger.error('Middleware {} does not have pre_process_{} method. pre_process function execution was skipped.'.format(middleware.__class__.__name__, update_type))
result = None
else:
result = middleware.pre_process(message, data)
# We will break this loop if CancelUpdate is returned
# Also, we will not run other middlewares
if isinstance(result, CancelUpdate):
return
elif isinstance(result, SkipHandler):
skip_handlers = True
if handlers and not(skip_handlers):
try:
for handler in handlers: for handler in handlers:
process_handler = self._test_message_handler(handler, message) if self._test_message_handler(handler, message):
if not process_handler: continue if handler.get('pass_bot', False):
for i in inspect.signature(handler['function']).parameters: handler['function'](message, bot = self)
params.append(i)
if len(params) == 1:
handler['function'](message)
elif "data" in params:
if len(params) == 2:
handler['function'](message, data)
elif len(params) == 3:
handler['function'](message, data=data, bot=self)
else: else:
logger.error("It is not allowed to pass data and values inside data to the handler. Check your handler: {}".format(handler['function'])) handler['function'](message)
return break
else: else:
data_copy = data.copy() data = {}
for key in list(data_copy): params =[]
# remove data from data_copy if handler does not accept it handler_error = None
if key not in params: skip_handlers = False
del data_copy[key]
if handler.get('pass_bot'):
data_copy["bot"] = self
if len(data_copy) > len(params) - 1: # remove the message parameter
logger.error("You are passing more parameters than the handler needs. Check your handler: {}".format(handler['function']))
return
handler["function"](message, **data_copy)
break
except Exception as e:
handler_error = e
if self.exception_handler:
self.exception_handler.handle(e)
else:
logging.error(str(e))
logger.debug("Exception traceback:\n%s", traceback.format_exc())
if middlewares: if middlewares:
for middleware in middlewares: for middleware in middlewares:
if middleware.update_sensitive: if middleware.update_sensitive:
if hasattr(middleware, f'post_process_{update_type}'): if hasattr(middleware, f'pre_process_{update_type}'):
getattr(middleware, f'post_process_{update_type}')(message, data, handler_error) result = getattr(middleware, f'pre_process_{update_type}')(message, data)
else:
logger.error('Middleware {} does not have pre_process_{} method. pre_process function execution was skipped.'.format(middleware.__class__.__name__, update_type))
result = None
else: else:
logger.error("Middleware: {} does not have post_process_{} method. Post process function was not executed.".format(middleware.__class__.__name__, update_type)) result = middleware.pre_process(message, data)
else: # We will break this loop if CancelUpdate is returned
middleware.post_process(message, data, handler_error) # Also, we will not run other middlewares
if isinstance(result, CancelUpdate):
return
elif isinstance(result, SkipHandler):
skip_handlers = True
if handlers and not(skip_handlers):
try:
for handler in handlers:
process_handler = self._test_message_handler(handler, message)
if not process_handler: continue
for i in inspect.signature(handler['function']).parameters:
params.append(i)
if len(params) == 1:
handler['function'](message)
elif "data" in params:
if len(params) == 2:
handler['function'](message, data)
elif len(params) == 3:
handler['function'](message, data=data, bot=self)
else:
logger.error("It is not allowed to pass data and values inside data to the handler. Check your handler: {}".format(handler['function']))
return
else:
data_copy = data.copy()
for key in list(data_copy):
# remove data from data_copy if handler does not accept it
if key not in params:
del data_copy[key]
if handler.get('pass_bot'):
data_copy["bot"] = self
if len(data_copy) > len(params) - 1: # remove the message parameter
logger.error("You are passing more parameters than the handler needs. Check your handler: {}".format(handler['function']))
return
handler["function"](message, **data_copy)
break
except Exception as e:
handler_error = e
if self.exception_handler:
self.exception_handler.handle(e)
else:
logger.error(str(e))
logger.debug("Exception traceback:\n%s", traceback.format_exc())
if middlewares:
for middleware in middlewares:
if middleware.update_sensitive:
if hasattr(middleware, f'post_process_{update_type}'):
getattr(middleware, f'post_process_{update_type}')(message, data, handler_error)
else:
logger.error("Middleware: {} does not have post_process_{} method. Post process function was not executed.".format(middleware.__class__.__name__, update_type))
else:
middleware.post_process(message, data, handler_error)
def _notify_command_handlers(self, handlers, new_messages, update_type): def _notify_command_handlers(self, handlers, new_messages, update_type):
""" """
Notifies command handlers. Notifies command handlers.
:param handlers: :param handlers: all created handlers
:param new_messages: :param new_messages: received messages to proceed
:param update_type: handler/update type (Update fields)
:return: :return:
""" """
if not(handlers) and not(self.use_class_middlewares): if not(handlers) and not(self.use_class_middlewares):
return return
if self.use_class_middlewares:
middlewares = self._get_middlewares(update_type)
else:
middlewares = None
for message in new_messages: for message in new_messages:
if not self.use_class_middlewares: self._exec_task(
for message_handler in handlers: self._run_middlewares_and_handler,
if self._test_message_handler(message_handler, message): message,
self._exec_task(message_handler['function'], message, pass_bot=message_handler['pass_bot'], task_type='handler') handlers=handlers,
break middlewares=middlewares,
else: update_type=update_type)
middleware = self._check_middleware(update_type)
self._exec_task(self._run_middlewares_and_handler, message, handlers=handlers, middlewares=middleware, update_type=update_type)
return

View File

@ -3,7 +3,6 @@ from datetime import datetime
import logging import logging
import re import re
import time
import traceback import traceback
from typing import Any, Awaitable, Callable, List, Optional, Union from typing import Any, Awaitable, Callable, List, Optional, Union
@ -99,21 +98,45 @@ class AsyncTeleBot:
:param state_storage: Storage for states, defaults to StateMemoryStorage() :param state_storage: Storage for states, defaults to StateMemoryStorage()
:type state_storage: :class:`telebot.asyncio_storage.StateMemoryStorage`, optional :type state_storage: :class:`telebot.asyncio_storage.StateMemoryStorage`, optional
:param disable_web_page_preview: Default value for disable_web_page_preview, defaults to None
:type disable_web_page_preview: :obj:`bool`, optional
:param disable_notification: Default value for disable_notification, defaults to None
:type disable_notification: :obj:`bool`, optional
:param protect_content: Default value for protect_content, defaults to None
:type protect_content: :obj:`bool`, optional
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
:type allow_sending_without_reply: :obj:`bool`, optional
""" """
def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[int]=None, def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[int]=None,
exception_handler: Optional[ExceptionHandler]=None, state_storage: Optional[StateStorageBase]=StateMemoryStorage()) -> None: exception_handler: Optional[ExceptionHandler]=None,
state_storage: Optional[StateStorageBase]=StateMemoryStorage(),
disable_web_page_preview: Optional[bool]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
allow_sending_without_reply: Optional[bool]=None) -> None:
# update-related
self.token = token self.token = token
self.offset = offset self.offset = offset
self.token = token
# properties
self.parse_mode = parse_mode self.parse_mode = parse_mode
self.disable_web_page_preview = disable_web_page_preview
self.disable_notification = disable_notification
self.protect_content = protect_content
self.allow_sending_without_reply = allow_sending_without_reply
# states
self.current_states = state_storage
# handlers
self.update_listener = [] self.update_listener = []
self.exception_handler = exception_handler self.exception_handler = exception_handler
self.message_handlers = [] self.message_handlers = []
self.edited_message_handlers = [] self.edited_message_handlers = []
self.channel_post_handlers = [] self.channel_post_handlers = []
@ -130,9 +153,6 @@ class AsyncTeleBot:
self.chat_join_request_handlers = [] self.chat_join_request_handlers = []
self.custom_filters = {} self.custom_filters = {}
self.state_handlers = [] self.state_handlers = []
self.current_states = state_storage
self.middlewares = [] self.middlewares = []
async def close_session(self): async def close_session(self):
@ -339,7 +359,8 @@ class AsyncTeleBot:
await self.close_session() await self.close_session()
logger.warning('Polling is stopped.') logger.warning('Polling is stopped.')
def _loop_create_task(self, coro): @staticmethod
def _loop_create_task(coro):
return asyncio.create_task(coro) return asyncio.create_task(coro)
async def _process_updates(self, handlers, messages, update_type): async def _process_updates(self, handlers, messages, update_type):
@ -351,12 +372,22 @@ class AsyncTeleBot:
:return: :return:
""" """
tasks = [] tasks = []
middlewares = await self._get_middlewares(update_type)
for message in messages: for message in messages:
middleware = await self.process_middlewares(update_type) tasks.append(self._run_middlewares_and_handlers(message, handlers, middlewares, update_type))
tasks.append(self._run_middlewares_and_handlers(handlers, message, middleware, update_type))
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
async def _run_middlewares_and_handlers(self, handlers, message, middlewares, update_type): async def _run_middlewares_and_handlers(self, message, handlers, middlewares, update_type):
"""
This method is made to run handlers and middlewares in queue.
:param message: received message (update part) to process with handlers and/or middlewares
:param handlers: all created handlers (not filtered)
:param middlewares: middlewares that should be executed (already filtered)
:param update_type: handler/update type (Update field name)
:return:
"""
handler_error = None handler_error = None
data = {} data = {}
skip_handlers = False skip_handlers = False
@ -426,7 +457,7 @@ class AsyncTeleBot:
else: else:
logger.error('Middleware {} does not have post_process_{} method. post_process function execution was skipped.'.format(middleware.__class__.__name__, update_type)) logger.error('Middleware {} does not have post_process_{} method. post_process function execution was skipped.'.format(middleware.__class__.__name__, update_type))
else: await middleware.post_process(message, data, handler_error) else: await middleware.post_process(message, data, handler_error)
# update handling
async def process_new_updates(self, updates: List[types.Update]): async def process_new_updates(self, updates: List[types.Update]):
""" """
Process new updates. Process new updates.
@ -615,7 +646,7 @@ class AsyncTeleBot:
""" """
await self._process_updates(self.chat_join_request_handlers, chat_join_request, 'chat_join_request') await self._process_updates(self.chat_join_request_handlers, chat_join_request, 'chat_join_request')
async def process_middlewares(self, update_type): async def _get_middlewares(self, update_type):
""" """
:meta private: :meta private:
""" """
@ -2277,6 +2308,10 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_message( await asyncio_helper.send_message(
@ -2315,6 +2350,9 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content)) await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content))
@ -2377,6 +2415,9 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.MessageID.de_json( return types.MessageID.de_json(
await asyncio_helper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities, await asyncio_helper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities,
@ -2455,6 +2496,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_dice( await asyncio_helper.send_dice(
self.token, chat_id, emoji, disable_notification, reply_to_message_id, self.token, chat_id, emoji, disable_notification, reply_to_message_id,
@ -2517,6 +2562,9 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_photo( await asyncio_helper.send_photo(
@ -2601,6 +2649,9 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_audio( await asyncio_helper.send_audio(
@ -2668,6 +2719,9 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_voice( await asyncio_helper.send_voice(
@ -2747,6 +2801,10 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if data and not(document): if data and not(document):
# function typo miss compatibility # function typo miss compatibility
document = data document = data
@ -2807,6 +2865,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if data and not(sticker): if data and not(sticker):
# function typo miss compatibility # function typo miss compatibility
logger.warning("send_sticker: data parameter is deprecated. Use sticker instead.") logger.warning("send_sticker: data parameter is deprecated. Use sticker instead.")
@ -2898,6 +2960,10 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
if data and not(video): if data and not(video):
# function typo miss compatibility # function typo miss compatibility
logger.warning("send_sticker: data parameter is deprecated. Use video instead.") logger.warning("send_sticker: data parameter is deprecated. Use video instead.")
@ -2985,6 +3051,9 @@ class AsyncTeleBot:
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_animation( await asyncio_helper.send_animation(
@ -3051,6 +3120,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_video_note( await asyncio_helper.send_video_note(
self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup, self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
@ -3096,6 +3169,10 @@ class AsyncTeleBot:
:return: On success, an array of Messages that were sent is returned. :return: On success, an array of Messages that were sent is returned.
:rtype: List[types.Message] :rtype: List[types.Message]
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
result = await asyncio_helper.send_media_group( result = await asyncio_helper.send_media_group(
self.token, chat_id, media, disable_notification, reply_to_message_id, timeout, self.token, chat_id, media, disable_notification, reply_to_message_id, timeout,
allow_sending_without_reply, protect_content) allow_sending_without_reply, protect_content)
@ -3163,6 +3240,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_location( await asyncio_helper.send_location(
self.token, chat_id, latitude, longitude, live_period, self.token, chat_id, latitude, longitude, live_period,
@ -3333,6 +3414,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_venue( await asyncio_helper.send_venue(
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
@ -3394,6 +3479,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message` :rtype: :class:`telebot.types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_contact( await asyncio_helper.send_contact(
self.token, chat_id, phone_number, first_name, last_name, vcard, self.token, chat_id, phone_number, first_name, last_name, vcard,
@ -4154,6 +4243,8 @@ class AsyncTeleBot:
:return: True on success. :return: True on success.
:rtype: :obj:`bool` :rtype: :obj:`bool`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
return await asyncio_helper.pin_chat_message(self.token, chat_id, message_id, disable_notification) return await asyncio_helper.pin_chat_message(self.token, chat_id, message_id, disable_notification)
async def unpin_chat_message(self, chat_id: Union[int, str], message_id: Optional[int]=None) -> bool: async def unpin_chat_message(self, chat_id: Union[int, str], message_id: Optional[int]=None) -> bool:
@ -4235,6 +4326,7 @@ class AsyncTeleBot:
:rtype: :obj:`types.Message` or :obj:`bool` :rtype: :obj:`types.Message` or :obj:`bool`
""" """
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
result = await asyncio_helper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode, result = await asyncio_helper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
entities, disable_web_page_preview, reply_markup) entities, disable_web_page_preview, reply_markup)
@ -4347,6 +4439,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :obj:`types.Message` :rtype: :obj:`types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
result = await asyncio_helper.send_game( result = await asyncio_helper.send_game(
self.token, chat_id, game_short_name, disable_notification, self.token, chat_id, game_short_name, disable_notification,
reply_to_message_id, reply_markup, timeout, reply_to_message_id, reply_markup, timeout,
@ -4548,6 +4644,10 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :obj:`types.Message` :rtype: :obj:`types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
result = await asyncio_helper.send_invoice( result = await asyncio_helper.send_invoice(
self.token, chat_id, title, description, invoice_payload, provider_token, self.token, chat_id, title, description, invoice_payload, provider_token,
currency, prices, start_parameter, photo_url, photo_size, photo_width, currency, prices, start_parameter, photo_url, photo_size, photo_width,
@ -4749,12 +4849,14 @@ class AsyncTeleBot:
:return: On success, the sent Message is returned. :return: On success, the sent Message is returned.
:rtype: :obj:`types.Message` :rtype: :obj:`types.Message`
""" """
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
explanation_parse_mode = self.parse_mode if (explanation_parse_mode is None) else explanation_parse_mode
if isinstance(question, types.Poll): if isinstance(question, types.Poll):
raise RuntimeError("The send_poll signature was changed, please see send_poll function details.") raise RuntimeError("The send_poll signature was changed, please see send_poll function details.")
explanation_parse_mode = self.parse_mode if (explanation_parse_mode is None) else explanation_parse_mode
return types.Message.de_json( return types.Message.de_json(
await asyncio_helper.send_poll( await asyncio_helper.send_poll(
self.token, chat_id, self.token, chat_id,

View File

@ -1,6 +1,5 @@
""" """
This file is used by TeleBot.run_webhooks() function. This file is used by TeleBot.run_webhooks() function.
Fastapi is required to run this script. Fastapi is required to run this script.
""" """
@ -15,15 +14,11 @@ try:
except ImportError: except ImportError:
fastapi_installed = False fastapi_installed = False
from telebot.types import Update from telebot.types import Update
from typing import Optional from typing import Optional
class SyncWebhookListener: class SyncWebhookListener:
def __init__(self, bot, def __init__(self, bot,
secret_token: str, host: Optional[str]="127.0.0.1", secret_token: str, host: Optional[str]="127.0.0.1",
@ -33,13 +28,13 @@ class SyncWebhookListener:
debug: Optional[bool]=False debug: Optional[bool]=False
) -> None: ) -> None:
""" """
Aynchronous implementation of webhook listener Synchronous implementation of webhook listener
for asynchronous version of telebot. for synchronous version of telebot.
Not supposed to be used manually by user. Not supposed to be used manually by user.
Use AsyncTeleBot.run_webhooks() instead. Use TeleBot.run_webhooks() instead.
:param bot: AsyncTeleBot instance. :param bot: TeleBot instance.
:type bot: telebot.async_telebot.AsyncTeleBot :type bot: telebot.TeleBot
:param secret_token: Telegram secret token :param secret_token: Telegram secret token
:type secret_token: str :type secret_token: str
@ -77,7 +72,8 @@ class SyncWebhookListener:
self._prepare_endpoint_urls() self._prepare_endpoint_urls()
def _check_dependencies(self): @staticmethod
def _check_dependencies():
if not fastapi_installed: if not fastapi_installed:
raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.') raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.')

View File

@ -41,7 +41,10 @@ class StateStorageBase:
def get_state(self, chat_id, user_id): def get_state(self, chat_id, user_id):
raise NotImplementedError raise NotImplementedError
def get_interactive_data(self, chat_id, user_id):
raise NotImplementedError
def save(self, chat_id, user_id, data): def save(self, chat_id, user_id, data):
raise NotImplementedError raise NotImplementedError

View File

@ -3,6 +3,7 @@ from telebot.storage.base_storage import StateStorageBase, StateContext
class StateMemoryStorage(StateStorageBase): class StateMemoryStorage(StateStorageBase):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__()
self.data = {} self.data = {}
# #
# {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...} # {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...}

View File

@ -5,8 +5,8 @@ import pickle
class StatePickleStorage(StateStorageBase): class StatePickleStorage(StateStorageBase):
# noinspection PyMissingConstructor
def __init__(self, file_path="./.state-save/states.pkl") -> None: def __init__(self, file_path="./.state-save/states.pkl") -> None:
super().__init__()
self.file_path = file_path self.file_path = file_path
self.create_dir() self.create_dir()
self.data = self.read() self.data = self.read()

View File

@ -16,6 +16,7 @@ class StateRedisStorage(StateStorageBase):
TeleBot(storage=StateRedisStorage()) TeleBot(storage=StateRedisStorage())
""" """
def __init__(self, host='localhost', port=6379, db=0, password=None, prefix='telebot_'): def __init__(self, host='localhost', port=6379, db=0, password=None, prefix='telebot_'):
super().__init__()
self.redis = ConnectionPool(host=host, port=port, db=db, password=password) self.redis = ConnectionPool(host=host, port=port, db=db, password=password)
#self.con = Redis(connection_pool=self.redis) -> use this when necessary #self.con = Redis(connection_pool=self.redis) -> use this when necessary
# #