Completed docstrings for all files except types.py

This commit is contained in:
_run 2022-07-24 23:14:09 +05:00
parent 7c12162576
commit b0e06253ff
12 changed files with 3286 additions and 866 deletions

View File

@ -84,10 +84,13 @@ class TeleBot:
Usage: Usage:
.. code-block:: python .. code-block:: python3
:caption: Creating instance of TeleBot
from telebot import TeleBot from telebot import TeleBot
bot = TeleBot('token') # get token from @BotFather bot = TeleBot('token') # get token from @BotFather
# now you can register other handlers/update listeners,
# and use bot methods.
See more examples in examples/ directory: See more examples in examples/ directory:
https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples
@ -243,7 +246,7 @@ class TeleBot:
Enable saving states (by default saving disabled) Enable saving states (by default saving disabled)
.. note:: .. note::
It is recommended to pass a :class:`~telebot.storage.StateMemoryStorage` instance as state_storage It is recommended to pass a :class:`~telebot.storage.StatePickleStorage` instance as state_storage
to TeleBot class. to TeleBot class.
:param filename: Filename of saving file, defaults to "./.state-save/states.pkl" :param filename: Filename of saving file, defaults to "./.state-save/states.pkl"
@ -547,8 +550,6 @@ class TeleBot:
Telegram documentation: https://core.telegram.org/bots/api#getupdates Telegram documentation: https://core.telegram.org/bots/api#getupdates
:param allowed_updates: Array of string. List the types of updates you want your bot to receive.
:type allowed_updates: :obj:`list`, optional
:param offset: Identifier of the first update to be returned. Must be greater by one than the highest among the identifiers of previously received updates. :param offset: Identifier of the first update to be returned. Must be greater by one than the highest among the identifiers of previously received updates.
By default, updates starting with the earliest unconfirmed update are returned. An update is considered confirmed as soon as getUpdates is called with an offset By default, updates starting with the earliest unconfirmed update are returned. An update is considered confirmed as soon as getUpdates is called with an offset
@ -562,6 +563,9 @@ class TeleBot:
:param timeout: Request connection timeout :param timeout: Request connection timeout
:type timeout: :obj:`int`, optional :type timeout: :obj:`int`, optional
:param allowed_updates: Array of string. List the types of updates you want your bot to receive.
:type allowed_updates: :obj:`list`, optional
:param long_polling_timeout: Timeout in seconds for long polling. :param long_polling_timeout: Timeout in seconds for long polling.
:type long_polling_timeout: :obj:`int`, optional :type long_polling_timeout: :obj:`int`, optional
@ -604,6 +608,9 @@ class TeleBot:
Processes new updates. Just pass list of subclasses of Update to this method. Processes new updates. Just pass list of subclasses of Update to this method.
:param updates: List of :class:`telebot.types.Update` objects. :param updates: List of :class:`telebot.types.Update` objects.
:type updates: :obj:`list` of :class:`telebot.types.Update`
:return None:
""" """
upd_count = len(updates) upd_count = len(updates)
logger.debug('Received {0} new updates'.format(upd_count)) logger.debug('Received {0} new updates'.format(upd_count))
@ -885,11 +892,11 @@ class TeleBot:
none_stop: Optional[bool]=None): none_stop: Optional[bool]=None):
""" """
This function creates a new Thread that calls an internal __retrieve_updates function. This function creates a new Thread that calls an internal __retrieve_updates function.
This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly. This allows the bot to retrieve Updates automatically and notify listeners and message handlers accordingly.
Warning: Do not call this function more than once! Warning: Do not call this function more than once!
Always get updates. Always gets updates.
.. deprecated:: 4.1.1 .. deprecated:: 4.1.1
Use :meth:`infinity_polling` instead. Use :meth:`infinity_polling` instead.
@ -921,7 +928,7 @@ class TeleBot:
Please note that this parameter doesn't affect updates created before the call to the get_updates, Please note that this parameter doesn't affect updates created before the call to the get_updates,
so unwanted updates may be received for a short period of time. so unwanted updates may be received for a short period of time.
:type allowed_updates: :obj:`list`] of :obj:`str` :type allowed_updates: :obj:`list` of :obj:`str`
:param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility. :param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility.
:type none_stop: :obj:`bool` :type none_stop: :obj:`bool`
@ -1104,6 +1111,8 @@ class TeleBot:
def stop_polling(self): def stop_polling(self):
""" """
Stops polling. Stops polling.
Does not accept any arguments.
""" """
self.__stop_polling.set() self.__stop_polling.set()
@ -1170,6 +1179,15 @@ class TeleBot:
def download_file(self, file_path: str) -> bytes: def download_file(self, file_path: str) -> bytes:
"""
Downloads file.
:param file_path: Path where the file should be downloaded.
:type file_path: str
:return: bytes
:rtype: :obj:`bytes`
"""
return apihelper.download_file(self.token, file_path) return apihelper.download_file(self.token, file_path)
@ -1209,7 +1227,7 @@ class TeleBot:
limit: Optional[int]=None) -> types.UserProfilePhotos: limit: Optional[int]=None) -> types.UserProfilePhotos:
""" """
Use this method to get a list of profile pictures for a user. Use this method to get a list of profile pictures for a user.
Returns a UserProfilePhotos object. Returns a :class:`telebot.types.UserProfilePhotos` object.
Telegram documentation: https://core.telegram.org/bots/api#getuserprofilephotos Telegram documentation: https://core.telegram.org/bots/api#getuserprofilephotos
@ -1240,7 +1258,7 @@ class TeleBot:
:param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername) :param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername)
:type chat_id: :obj:`int` or :obj:`str` :type chat_id: :obj:`int` or :obj:`str`
:return: :class:`telebot.types.Chat` :return: Chat information
:rtype: :class:`telebot.types.Chat` :rtype: :class:`telebot.types.Chat`
""" """
result = apihelper.get_chat(self.token, chat_id) result = apihelper.get_chat(self.token, chat_id)
@ -1384,8 +1402,8 @@ class TeleBot:
""" """
Use this method to send text messages. Use this method to send text messages.
Warning: Do not send more than about 4000 characters each message, otherwise you'll risk an HTTP 414 error. Warning: Do not send more than about 4096 characters each message, otherwise you'll risk an HTTP 414 error.
If you must send more than 4000 characters, If you must send more than 4096 characters,
use the `split_string` or `smart_split` function in util.py. use the `split_string` or `smart_split` function in util.py.
Telegram documentation: https://core.telegram.org/bots/api#sendmessage Telegram documentation: https://core.telegram.org/bots/api#sendmessage
@ -3552,7 +3570,12 @@ class TeleBot:
message_id: Optional[int]=None, message_id: Optional[int]=None,
inline_message_id: Optional[str]=None) -> List[types.GameHighScore]: inline_message_id: Optional[str]=None) -> List[types.GameHighScore]:
""" """
Gets top points and game play. Use this method to get data for high score tables. Will return the score of the specified user and several of
their neighbors in a game. On success, returns an Array of GameHighScore objects.
This method will currently return scores for the target user, plus two of their closest neighbors on each side.
Will also return the top three users if the user and their neighbors are not among them.
Please note that this behavior is subject to change.
Telegram documentation: https://core.telegram.org/bots/api#getgamehighscores Telegram documentation: https://core.telegram.org/bots/api#getgamehighscores
@ -4430,10 +4453,16 @@ class TeleBot:
self.middlewares.append(middleware) self.middlewares.append(middleware)
def set_state(self, user_id: int, state: Union[int, str, State], chat_id: int=None) -> None: def set_state(self, user_id: int, state: Union[int, str, State], chat_id: Optional[int]=None) -> None:
""" """
Sets a new state of a user. Sets a new state of a user.
.. note::
You should set both user id and chat id in order to set state for a user in a chat.
Otherwise, if you only set user_id, chat_id will equal to user_id, this means that
state will be set for the user in his private chat with a bot.
:param user_id: User's identifier :param user_id: User's identifier
:type user_id: :obj:`int` :type user_id: :obj:`int`
@ -4449,7 +4478,7 @@ class TeleBot:
chat_id = user_id chat_id = user_id
self.current_states.set_state(chat_id, user_id, state) self.current_states.set_state(chat_id, user_id, state)
def reset_data(self, user_id: int, chat_id: int=None): def reset_data(self, user_id: int, chat_id: Optional[int]=None):
""" """
Reset data for a user in chat. Reset data for a user in chat.
@ -4465,7 +4494,7 @@ class TeleBot:
chat_id = user_id chat_id = user_id
self.current_states.reset_data(chat_id, user_id) self.current_states.reset_data(chat_id, user_id)
def delete_state(self, user_id: int, chat_id: int=None) -> None: def delete_state(self, user_id: int, chat_id: Optional[int]=None) -> None:
""" """
Delete the current state of a user. Delete the current state of a user.
@ -4481,12 +4510,24 @@ class TeleBot:
chat_id = user_id chat_id = user_id
self.current_states.delete_state(chat_id, user_id) self.current_states.delete_state(chat_id, user_id)
def retrieve_data(self, user_id: int, chat_id: int=None) -> Optional[Any]: def retrieve_data(self, user_id: int, chat_id: Optional[int]=None) -> Optional[Any]:
"""
Returns context manager with data for a user in chat.
:param user_id: User identifier
:type user_id: int
:param chat_id: Chat's unique identifier, defaults to user_id
:type chat_id: int, optional
:return: Context manager with data for a user in chat
:rtype: Optional[Any]
"""
if chat_id is None: if chat_id is None:
chat_id = user_id chat_id = user_id
return self.current_states.get_interactive_data(chat_id, user_id) return self.current_states.get_interactive_data(chat_id, user_id)
def get_state(self, user_id: int, chat_id: int=None) -> Optional[Union[int, str, State]]: def get_state(self, user_id: int, chat_id: Optional[int]=None) -> Optional[Union[int, str, State]]:
""" """
Gets current state of a user. Gets current state of a user.
Not recommended to use this method. But it is ok for debugging. Not recommended to use this method. But it is ok for debugging.
@ -4504,7 +4545,7 @@ class TeleBot:
chat_id = user_id chat_id = user_id
return self.current_states.get_state(chat_id, user_id) return self.current_states.get_state(chat_id, user_id)
def add_data(self, user_id: int, chat_id:int=None, **kwargs): def add_data(self, user_id: int, chat_id: Optional[int]=None, **kwargs):
""" """
Add data to states. Add data to states.
@ -4635,6 +4676,7 @@ class TeleBot:
Example: Example:
.. code-block:: python3 .. code-block:: python3
:caption: Usage of middleware_handler
bot = TeleBot('TOKEN') bot = TeleBot('TOKEN')
@ -4728,13 +4770,14 @@ class TeleBot:
def message_handler(self, commands: Optional[List[str]]=None, regexp: Optional[str]=None, func: Optional[Callable]=None, def message_handler(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): content_types: Optional[List[str]]=None, chat_types: Optional[List[str]]=None, **kwargs):
""" """
Message handler decorator. Handles New incoming message of any kind - text, photo, sticker, etc.
This decorator can be used to decorate functions that must handle certain types of messages. As a parameter to the decorator function, it passes :class:`telebot.types.Message` object.
All message handlers are tested in the order they were added. All message handlers are tested in the order they were added.
Example: Example:
.. code-block:: python .. code-block:: python3
:caption: Usage of message_handler
bot = TeleBot('TOKEN') bot = TeleBot('TOKEN')
@ -4768,8 +4811,17 @@ class TeleBot:
:param func: Optional lambda function. The lambda receives the message to test as the first parameter. :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. It must return True if the command should handle the message.
:type func: :obj:`lambda`
:param content_types: Supported message content types. Must be a list. Defaults to ['text']. :param content_types: Supported message content types. Must be a list. Defaults to ['text'].
:type content_types: :obj:`list` of :obj:`str`
:param chat_types: list of chat types :param chat_types: list of chat types
:type chat_types: :obj:`list` of :obj:`str`
:param kwargs: Optional keyword arguments(custom filters)
:return: decorated function
""" """
if content_types is None: if content_types is None:
content_types = ["text"] content_types = ["text"]
@ -4871,7 +4923,8 @@ class TeleBot:
def edited_message_handler(self, commands=None, regexp=None, func=None, content_types=None, chat_types=None, **kwargs): def edited_message_handler(self, commands=None, regexp=None, func=None, content_types=None, chat_types=None, **kwargs):
""" """
Edit message handler decorator Handles new version of a message that is known to the bot and was edited.
As a parameter to the decorator function, it passes :class:`telebot.types.Message` object.
:param commands: Optional list of strings (commands to handle). :param commands: Optional list of strings (commands to handle).
:type commands: :obj:`list` of :obj:`str` :type commands: :obj:`list` of :obj:`str`
@ -4889,6 +4942,7 @@ class TeleBot:
:type chat_types: :obj:`list` of :obj:`str` :type chat_types: :obj:`list` of :obj:`str`
:param kwargs: Optional keyword arguments(custom filters) :param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
if content_types is None: if content_types is None:
@ -4960,6 +5014,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
method_name = "register_edited_message_handler" method_name = "register_edited_message_handler"
@ -4988,7 +5044,8 @@ class TeleBot:
def channel_post_handler(self, commands=None, regexp=None, func=None, content_types=None, **kwargs): def channel_post_handler(self, commands=None, regexp=None, func=None, content_types=None, **kwargs):
""" """
Channel post handler decorator. Handles new incoming channel post of any kind - text, photo, sticker, etc.
As a parameter to the decorator function, it passes :class:`telebot.types.Message` object.
:param commands: Optional list of strings (commands to handle). :param commands: Optional list of strings (commands to handle).
:type commands: :obj:`list` of :obj:`str` :type commands: :obj:`list` of :obj:`str`
@ -5003,6 +5060,7 @@ class TeleBot:
:type content_types: :obj:`list` of :obj:`str` :type content_types: :obj:`list` of :obj:`str`
:param kwargs: Optional keyword arguments(custom filters) :param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
if content_types is None: if content_types is None:
@ -5069,6 +5127,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
method_name = "register_channel_post_handler" method_name = "register_channel_post_handler"
@ -5096,7 +5156,8 @@ class TeleBot:
def edited_channel_post_handler(self, commands=None, regexp=None, func=None, content_types=None, **kwargs): def edited_channel_post_handler(self, commands=None, regexp=None, func=None, content_types=None, **kwargs):
""" """
Edit channel post handler decorator Handles new version of a channel post that is known to the bot and was edited.
As a parameter to the decorator function, it passes :class:`telebot.types.Message` object.
:param commands: Optional list of strings (commands to handle). :param commands: Optional list of strings (commands to handle).
:type commands: :obj:`list` of :obj:`str` :type commands: :obj:`list` of :obj:`str`
@ -5178,6 +5239,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: decorated function :return: decorated function
""" """
method_name = "register_edited_channel_post_handler" method_name = "register_edited_channel_post_handler"
@ -5205,7 +5268,8 @@ class TeleBot:
def inline_handler(self, func, **kwargs): def inline_handler(self, func, **kwargs):
""" """
Inline call handler decorator Handles new incoming inline query.
As a parameter to the decorator function, it passes :class:`telebot.types.InlineQuery` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5246,6 +5310,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: decorated function :return: decorated function
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5253,7 +5319,9 @@ class TeleBot:
def chosen_inline_handler(self, func, **kwargs): def chosen_inline_handler(self, func, **kwargs):
""" """
Description: The result of an inline query that was chosen by a user and sent to their chat partner. Handles the result of an inline query that was chosen by a user and sent to their chat partner.
Please see our documentation on the feedback collecting for details on how to enable these updates for your bot.
As a parameter to the decorator function, it passes :class:`telebot.types.ChosenInlineResult` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5294,6 +5362,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5301,7 +5371,8 @@ class TeleBot:
def callback_query_handler(self, func, **kwargs): def callback_query_handler(self, func, **kwargs):
""" """
Callback request handler decorator Handles new incoming callback query.
As a parameter to the decorator function, it passes :class:`telebot.types.CallbackQuery` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5342,6 +5413,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5349,7 +5422,8 @@ class TeleBot:
def shipping_query_handler(self, func, **kwargs): def shipping_query_handler(self, func, **kwargs):
""" """
Shipping request handler Handles new incoming shipping query. Only for invoices with flexible price.
As a parameter to the decorator function, it passes :class:`telebot.types.ShippingQuery` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5390,6 +5464,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5397,7 +5473,8 @@ class TeleBot:
def pre_checkout_query_handler(self, func, **kwargs): def pre_checkout_query_handler(self, func, **kwargs):
""" """
Pre-checkout request handler New incoming pre-checkout query. Contains full information about checkout.
As a parameter to the decorator function, it passes :class:`telebot.types.PreCheckoutQuery` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5437,6 +5514,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: decorated function :return: decorated function
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5444,7 +5523,8 @@ class TeleBot:
def poll_handler(self, func, **kwargs): def poll_handler(self, func, **kwargs):
""" """
Poll request handler Handles new state of a poll. Bots receive only updates about stopped polls and polls, which are sent by the bot
As a parameter to the decorator function, it passes :class:`telebot.types.Poll` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5484,6 +5564,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5491,7 +5573,9 @@ class TeleBot:
def poll_answer_handler(self, func=None, **kwargs): def poll_answer_handler(self, func=None, **kwargs):
""" """
Poll_answer request handler Handles change of user's answer in a non-anonymous poll(when user changes the vote).
Bots receive new votes only in polls that were sent by the bot itself.
As a parameter to the decorator function, it passes :class:`telebot.types.PollAnswer` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5532,6 +5616,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5539,8 +5625,9 @@ class TeleBot:
def my_chat_member_handler(self, func=None, **kwargs): def my_chat_member_handler(self, func=None, **kwargs):
""" """
The bot's chat member status was updated in a chat. For private chats, Handles update in a status of a bot. For private chats,
this update is received only when the bot is blocked or unblocked by the user. this update is received only when the bot is blocked or unblocked by the user.
As a parameter to the decorator function, it passes :class:`telebot.types.ChatMemberUpdated` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5581,6 +5668,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5588,8 +5677,10 @@ class TeleBot:
def chat_member_handler(self, func=None, **kwargs): def chat_member_handler(self, func=None, **kwargs):
""" """
A chat member's status was updated in a chat. The bot must be an administrator Handles update in a status of a user in a chat.
in the chat and must explicitly specify chat_member in the list of allowed_updates to receive these updates. The bot must be an administrator in the chat and must explicitly specify chat_member
in the list of allowed_updates to receive these updates.
As a parameter to the decorator function, it passes :class:`telebot.types.ChatMemberUpdated` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5639,8 +5730,9 @@ class TeleBot:
def chat_join_request_handler(self, func=None, **kwargs): def chat_join_request_handler(self, func=None, **kwargs):
""" """
A request to join the chat has been sent. The bot must have the can_invite_users Handles a request to join the chat has been sent. The bot must have the can_invite_users
administrator right in the chat to receive these updates. administrator right in the chat to receive these updates.
As a parameter to the decorator function, it passes :class:`telebot.types.ChatJoinRequest` object.
:param func: Function executed as a filter :param func: Function executed as a filter
:type func: :obj:`function` :type func: :obj:`function`
@ -5681,6 +5773,8 @@ class TeleBot:
:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool` :type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None :return: None
""" """
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
@ -5707,6 +5801,15 @@ class TeleBot:
""" """
Create custom filter. Create custom filter.
.. code-block:: python3
:caption: Example on checking the text of a message
class TextMatchFilter(AdvancedCustomFilter):
key = 'text'
async def check(self, message, text):
return text == message.text
:param custom_filter: Class with check(message) method. :param custom_filter: Class with check(message) method.
:param custom_filter: Custom filter class with key. :param custom_filter: Custom filter class with key.
""" """

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,19 @@ class SimpleCustomFilter(ABC):
Simple Custom Filter base class. Simple Custom Filter base class.
Create child class with check() method. Create child class with check() method.
Accepts only message, returns bool value, that is compared with given in handler. Accepts only message, returns bool value, that is compared with given in handler.
Child classes should have .key property. Child classes should have .key property.
.. code-block:: python3
:caption: Example on creating a simple custom filter.
class ForwardFilter(SimpleCustomFilter):
# Check whether message was forwarded from channel or group.
key = 'is_forwarded'
def check(self, message):
return message.forward_date is not None
""" """
key: str = None key: str = None
@ -25,13 +36,23 @@ class SimpleCustomFilter(ABC):
class AdvancedCustomFilter(ABC): class AdvancedCustomFilter(ABC):
""" """
Simple Custom Filter base class. Advanced Custom Filter base class.
Create child class with check() method. Create child class with check() method.
Accepts two parameters, returns bool: True - filter passed, False - filter failed. Accepts two parameters, returns bool: True - filter passed, False - filter failed.
message: Message class message: Message class
text: Filter value given in handler text: Filter value given in handler
Child classes should have .key property. Child classes should have .key property.
.. code-block:: python3
:caption: Example on creating an advanced custom filter.
class TextStartsFilter(AdvancedCustomFilter):
# Filter to check whether message starts with some text.
key = 'text_startswith'
def check(self, message, text):
return message.text.startswith(text)
""" """
key: str = None key: str = None
@ -48,6 +69,25 @@ class TextFilter:
Advanced text filter to check (types.Message, types.CallbackQuery, types.InlineQuery, types.Poll) Advanced text filter to check (types.Message, types.CallbackQuery, types.InlineQuery, types.Poll)
example of usage is in examples/asynchronous_telebot/custom_filters/advanced_text_filter.py example of usage is in examples/asynchronous_telebot/custom_filters/advanced_text_filter.py
:param equals: string, True if object's text is equal to passed string
:type equals: :obj:`str`
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
:type contains: list[str] or tuple[str]
:param starts_with: string, True if object's text starts with passed string
:type starts_with: :obj:`str`
:param ends_with: string, True if object's text starts with passed string
:type ends_with: :obj:`str`
:param ignore_case: bool (default False), case insensitive
:type ignore_case: :obj:`bool`
:raises ValueError: if incorrect value for a parameter was supplied
:return: None
""" """
def __init__(self, def __init__(self,
@ -56,13 +96,25 @@ class TextFilter:
starts_with: Optional[Union[str, list, tuple]] = None, starts_with: Optional[Union[str, list, tuple]] = None,
ends_with: Optional[Union[str, list, tuple]] = None, ends_with: Optional[Union[str, list, tuple]] = None,
ignore_case: bool = False): ignore_case: bool = False):
""" """
:param equals: string, True if object's text is equal to passed string :param equals: string, True if object's text is equal to passed string
:type equals: :obj:`str`
:param contains: list[str] or tuple[str], True if any string element of iterable is in text :param contains: list[str] or tuple[str], True if any string element of iterable is in text
:type contains: list[str] or tuple[str]
:param starts_with: string, True if object's text starts with passed string :param starts_with: string, True if object's text starts with passed string
:type starts_with: :obj:`str`
:param ends_with: string, True if object's text starts with passed string :param ends_with: string, True if object's text starts with passed string
:type ends_with: :obj:`str`
:param ignore_case: bool (default False), case insensitive :param ignore_case: bool (default False), case insensitive
:type ignore_case: :obj:`bool`
:raises ValueError: if incorrect value for a parameter was supplied
:return: None
""" """
to_check = sum((pattern is not None for pattern in (equals, contains, starts_with, ends_with))) to_check = sum((pattern is not None for pattern in (equals, contains, starts_with, ends_with)))
@ -87,7 +139,9 @@ class TextFilter:
return iterable return iterable
async def check(self, obj: Union[types.Message, types.CallbackQuery, types.InlineQuery, types.Poll]): async def check(self, obj: Union[types.Message, types.CallbackQuery, types.InlineQuery, types.Poll]):
"""
:meta private:
"""
if isinstance(obj, types.Poll): if isinstance(obj, types.Poll):
text = obj.question text = obj.question
elif isinstance(obj, types.Message): elif isinstance(obj, types.Message):
@ -135,15 +189,20 @@ class TextFilter:
class TextMatchFilter(AdvancedCustomFilter): class TextMatchFilter(AdvancedCustomFilter):
""" """
Filter to check Text message. Filter to check Text message.
key: text
Example: .. code-block:: python3
@bot.message_handler(text=['account']) :caption: Example on using this filter:
@bot.message_handler(text=['account'])
# your function
""" """
key = 'text' key = 'text'
async def check(self, message, text): async def check(self, message, text):
"""
:meta private:
"""
if isinstance(text, TextFilter): if isinstance(text, TextFilter):
return await text.check(message) return await text.check(message)
elif type(text) is list: elif type(text) is list:
@ -157,14 +216,21 @@ class TextContainsFilter(AdvancedCustomFilter):
Filter to check Text message. Filter to check Text message.
key: text key: text
Example:
# Will respond if any message.text contains word 'account' .. code-block:: python3
@bot.message_handler(text_contains=['account']) :caption: Example on using this filter:
# Will respond if any message.text contains word 'account'
@bot.message_handler(text_contains=['account'])
# your function
""" """
key = 'text_contains' key = 'text_contains'
async def check(self, message, text): async def check(self, message, text):
"""
:meta private:
"""
if not isinstance(text, str) and not isinstance(text, list) and not isinstance(text, tuple): if not isinstance(text, str) and not isinstance(text, list) and not isinstance(text, tuple):
raise ValueError("Incorrect text_contains value") raise ValueError("Incorrect text_contains value")
elif isinstance(text, str): elif isinstance(text, str):
@ -179,14 +245,20 @@ class TextStartsFilter(AdvancedCustomFilter):
""" """
Filter to check whether message starts with some text. Filter to check whether message starts with some text.
Example: .. code-block:: python3
# Will work if message.text starts with 'Sir'. :caption: Example on using this filter:
@bot.message_handler(text_startswith='Sir')
# Will work if message.text starts with 'sir'.
@bot.message_handler(text_startswith='sir')
# your function
""" """
key = 'text_startswith' key = 'text_startswith'
async def check(self, message, text): async def check(self, message, text):
"""
:meta private:
"""
return message.text.startswith(text) return message.text.startswith(text)
@ -194,13 +266,19 @@ class ChatFilter(AdvancedCustomFilter):
""" """
Check whether chat_id corresponds to given chat_id. Check whether chat_id corresponds to given chat_id.
Example: .. code-block:: python3
@bot.message_handler(chat_id=[99999]) :caption: Example on using this filter:
@bot.message_handler(chat_id=[99999])
# your function
""" """
key = 'chat_id' key = 'chat_id'
async def check(self, message, text): async def check(self, message, text):
"""
:meta private:
"""
if isinstance(message, types.CallbackQuery): if isinstance(message, types.CallbackQuery):
return message.message.chat.id in text return message.message.chat.id in text
return message.chat.id in text return message.chat.id in text
@ -210,14 +288,19 @@ class ForwardFilter(SimpleCustomFilter):
""" """
Check whether message was forwarded from channel or group. Check whether message was forwarded from channel or group.
Example: .. code-block:: python3
:caption: Example on using this filter:
@bot.message_handler(is_forwarded=True) @bot.message_handler(is_forwarded=True)
# your function
""" """
key = 'is_forwarded' key = 'is_forwarded'
async def check(self, message): async def check(self, message):
"""
:meta private:
"""
return message.forward_date is not None return message.forward_date is not None
@ -225,14 +308,19 @@ class IsReplyFilter(SimpleCustomFilter):
""" """
Check whether message is a reply. Check whether message is a reply.
Example: .. code-block:: python3
:caption: Example on using this filter:
@bot.message_handler(is_reply=True) @bot.message_handler(is_reply=True)
# your function
""" """
key = 'is_reply' key = 'is_reply'
async def check(self, message): async def check(self, message):
"""
:meta private:
"""
if isinstance(message, types.CallbackQuery): if isinstance(message, types.CallbackQuery):
return message.message.reply_to_message is not None return message.message.reply_to_message is not None
return message.reply_to_message is not None return message.reply_to_message is not None
@ -242,14 +330,19 @@ class LanguageFilter(AdvancedCustomFilter):
""" """
Check users language_code. Check users language_code.
Example: .. code-block:: python3
:caption: Example on using this filter:
@bot.message_handler(language_code=['ru']) @bot.message_handler(language_code=['ru'])
# your function
""" """
key = 'language_code' key = 'language_code'
async def check(self, message, text): async def check(self, message, text):
"""
:meta private:
"""
if type(text) is list: if type(text) is list:
return message.from_user.language_code in text return message.from_user.language_code in text
else: else:
@ -260,8 +353,11 @@ class IsAdminFilter(SimpleCustomFilter):
""" """
Check whether the user is administrator / owner of the chat. Check whether the user is administrator / owner of the chat.
Example: .. code-block:: python3
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True) :caption: Example on using this filter:
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
# your function
""" """
key = 'is_chat_admin' key = 'is_chat_admin'
@ -270,6 +366,9 @@ class IsAdminFilter(SimpleCustomFilter):
self._bot = bot self._bot = bot
async def check(self, message): async def check(self, message):
"""
:meta private:
"""
if isinstance(message, types.CallbackQuery): if isinstance(message, types.CallbackQuery):
result = await self._bot.get_chat_member(message.message.chat.id, message.from_user.id) result = await self._bot.get_chat_member(message.message.chat.id, message.from_user.id)
return result.status ('creator', 'administrator') return result.status ('creator', 'administrator')
@ -281,8 +380,11 @@ class StateFilter(AdvancedCustomFilter):
""" """
Filter to check state. Filter to check state.
Example: .. code-block:: python3
@bot.message_handler(state=1) :caption: Example on using this filter:
@bot.message_handler(state=1)
# your function
""" """
def __init__(self, bot): def __init__(self, bot):
@ -291,6 +393,9 @@ class StateFilter(AdvancedCustomFilter):
key = 'state' key = 'state'
async def check(self, message, text): async def check(self, message, text):
"""
:meta private:
"""
if text == '*': return True if text == '*': return True
# needs to work with callbackquery # needs to work with callbackquery
@ -334,10 +439,16 @@ class IsDigitFilter(SimpleCustomFilter):
""" """
Filter to check whether the string is made up of only digits. Filter to check whether the string is made up of only digits.
Example: .. code-block:: python3
@bot.message_handler(is_digit=True) :caption: Example on using this filter:
@bot.message_handler(is_digit=True)
# your function
""" """
key = 'is_digit' key = 'is_digit'
async def check(self, message): async def check(self, message):
"""
:meta private:
"""
return message.text.isdigit() return message.text.isdigit()

View File

@ -1,3 +1,10 @@
"""
File with all middleware classes, states.
"""
class BaseMiddleware: class BaseMiddleware:
""" """
Base class for middleware. Base class for middleware.
@ -9,23 +16,25 @@ class BaseMiddleware:
so on. Same applies to post_process. so on. Same applies to post_process.
.. code-block:: python .. code-block:: python
:caption: Example of class-based middlewares
class MyMiddleware(BaseMiddleware): class MyMiddleware(BaseMiddleware):
def __init__(self): def __init__(self):
self.update_sensitive = True self.update_sensitive = True
self.update_types = ['message', 'edited_message'] self.update_types = ['message', 'edited_message']
def pre_process_message(self, message, data): async def pre_process_message(self, message, data):
# only message update here # only message update here
pass pass
def post_process_message(self, message, data, exception): async def post_process_message(self, message, data, exception):
pass # only message update here for post_process pass # only message update here for post_process
def pre_process_edited_message(self, message, data): async def pre_process_edited_message(self, message, data):
# only edited_message update here # only edited_message update here
pass pass
def post_process_edited_message(self, message, data, exception): async def post_process_edited_message(self, message, data, exception):
pass # only edited_message update here for post_process pass # only edited_message update here for post_process
""" """
@ -42,6 +51,14 @@ class BaseMiddleware:
class State: class State:
"""
Class representing a state.
.. code-block:: python3
class MyStates(StatesGroup):
my_state = State() # returns my_state:State string.
"""
def __init__(self) -> None: def __init__(self) -> None:
self.name = None self.name = None
@ -50,6 +67,14 @@ class State:
class StatesGroup: class StatesGroup:
"""
Class representing common states.
.. code-block:: python3
class MyStates(StatesGroup):
my_state = State() # returns my_state:State string.
"""
def __init_subclass__(cls) -> None: def __init_subclass__(cls) -> None:
for name, value in cls.__dict__.items(): for name, value in cls.__dict__.items():

View File

@ -1,3 +1,7 @@
"""
Callback data factory's file.
"""
""" """
Copyright (c) 2017-2018 Alex Root Junior Copyright (c) 2017-2018 Alex Root Junior
@ -29,17 +33,23 @@ import typing
class CallbackDataFilter: class CallbackDataFilter:
"""
Filter for CallbackData.
"""
def __init__(self, factory, config: typing.Dict[str, str]): def __init__(self, factory, config: typing.Dict[str, str]):
self.config = config self.config = config
self.factory = factory self.factory = factory
def check(self, query): def check(self, query) -> bool:
""" """
Checks if query.data appropriates to specified config Checks if query.data appropriates to specified config
:param query: telebot.types.CallbackQuery :param query: telebot.types.CallbackQuery
:return: bool :type query: telebot.types.CallbackQuery
:return: True if query.data appropriates to specified config
:rtype: bool
""" """
try: try:
@ -135,7 +145,7 @@ class CallbackData:
""" """
Generate filter Generate filter
:param config: specified named parameters will be checked with CallbackQury.data :param config: specified named parameters will be checked with CallbackQuery.data
:return: CallbackDataFilter class :return: CallbackDataFilter class
""" """

View File

@ -14,6 +14,17 @@ class SimpleCustomFilter(ABC):
Accepts only message, returns bool value, that is compared with given in handler. Accepts only message, returns bool value, that is compared with given in handler.
Child classes should have .key property. Child classes should have .key property.
.. code-block:: python3
:caption: Example on creating a simple custom filter.
class ForwardFilter(SimpleCustomFilter):
# Check whether message was forwarded from channel or group.
key = 'is_forwarded'
def check(self, message):
return message.forward_date is not None
""" """
key: str = None key: str = None
@ -27,13 +38,23 @@ class SimpleCustomFilter(ABC):
class AdvancedCustomFilter(ABC): class AdvancedCustomFilter(ABC):
""" """
Simple Custom Filter base class. Advanced Custom Filter base class.
Create child class with check() method. Create child class with check() method.
Accepts two parameters, returns bool: True - filter passed, False - filter failed. Accepts two parameters, returns bool: True - filter passed, False - filter failed.
message: Message class message: Message class
text: Filter value given in handler text: Filter value given in handler
Child classes should have .key property. Child classes should have .key property.
.. code-block:: python3
:caption: Example on creating an advanced custom filter.
class TextStartsFilter(AdvancedCustomFilter):
# Filter to check whether message starts with some text.
key = 'text_startswith'
def check(self, message, text):
return message.text.startswith(text)
""" """
key: str = None key: str = None
@ -50,6 +71,25 @@ class TextFilter:
Advanced text filter to check (types.Message, types.CallbackQuery, types.InlineQuery, types.Poll) Advanced text filter to check (types.Message, types.CallbackQuery, types.InlineQuery, types.Poll)
example of usage is in examples/custom_filters/advanced_text_filter.py example of usage is in examples/custom_filters/advanced_text_filter.py
:param equals: string, True if object's text is equal to passed string
:type equals: :obj:`str`
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
:type contains: list[str] or tuple[str]
:param starts_with: string, True if object's text starts with passed string
:type starts_with: :obj:`str`
:param ends_with: string, True if object's text starts with passed string
:type ends_with: :obj:`str`
:param ignore_case: bool (default False), case insensitive
:type ignore_case: :obj:`bool`
:raises ValueError: if incorrect value for a parameter was supplied
:return: None
""" """
def __init__(self, def __init__(self,
@ -58,15 +98,27 @@ class TextFilter:
starts_with: Optional[Union[str, list, tuple]] = None, starts_with: Optional[Union[str, list, tuple]] = None,
ends_with: Optional[Union[str, list, tuple]] = None, ends_with: Optional[Union[str, list, tuple]] = None,
ignore_case: bool = False): ignore_case: bool = False):
""" """
:param equals: string, True if object's text is equal to passed string :param equals: string, True if object's text is equal to passed string
:param contains: list[str] or tuple[str], True if any string element of iterable is in text :type equals: :obj:`str`
:param starts_with: string, True if object's text starts with passed string
:param ends_with: string, True if object's text starts with passed string
:param ignore_case: bool (default False), case insensitive
"""
:param contains: list[str] or tuple[str], True if any string element of iterable is in text
:type contains: list[str] or tuple[str]
:param starts_with: string, True if object's text starts with passed string
:type starts_with: :obj:`str`
:param ends_with: string, True if object's text starts with passed string
:type ends_with: :obj:`str`
:param ignore_case: bool (default False), case insensitive
:type ignore_case: :obj:`bool`
:raises ValueError: if incorrect value for a parameter was supplied
:return: None
"""
to_check = sum((pattern is not None for pattern in (equals, contains, starts_with, ends_with))) to_check = sum((pattern is not None for pattern in (equals, contains, starts_with, ends_with)))
if to_check == 0: if to_check == 0:
raise ValueError('None of the check modes was specified') raise ValueError('None of the check modes was specified')
@ -89,6 +141,9 @@ class TextFilter:
return iterable return iterable
def check(self, obj: Union[types.Message, types.CallbackQuery, types.InlineQuery, types.Poll]): def check(self, obj: Union[types.Message, types.CallbackQuery, types.InlineQuery, types.Poll]):
"""
:meta private:
"""
if isinstance(obj, types.Poll): if isinstance(obj, types.Poll):
text = obj.question text = obj.question
@ -142,15 +197,20 @@ class TextFilter:
class TextMatchFilter(AdvancedCustomFilter): class TextMatchFilter(AdvancedCustomFilter):
""" """
Filter to check Text message. Filter to check Text message.
key: text
Example: .. code-block:: python3
@bot.message_handler(text=['account']) :caption: Example on using this filter:
@bot.message_handler(text=['account'])
# your function
""" """
key = 'text' key = 'text'
def check(self, message, text): def check(self, message, text):
"""
:meta private:
"""
if isinstance(text, TextFilter): if isinstance(text, TextFilter):
return text.check(message) return text.check(message)
elif type(text) is list: elif type(text) is list:
@ -164,14 +224,21 @@ class TextContainsFilter(AdvancedCustomFilter):
Filter to check Text message. Filter to check Text message.
key: text key: text
Example:
# Will respond if any message.text contains word 'account' .. code-block:: python3
@bot.message_handler(text_contains=['account']) :caption: Example on using this filter:
# Will respond if any message.text contains word 'account'
@bot.message_handler(text_contains=['account'])
# your function
""" """
key = 'text_contains' key = 'text_contains'
def check(self, message, text): def check(self, message, text):
"""
:meta private:
"""
if not isinstance(text, str) and not isinstance(text, list) and not isinstance(text, tuple): if not isinstance(text, str) and not isinstance(text, list) and not isinstance(text, tuple):
raise ValueError("Incorrect text_contains value") raise ValueError("Incorrect text_contains value")
elif isinstance(text, str): elif isinstance(text, str):
@ -186,14 +253,20 @@ class TextStartsFilter(AdvancedCustomFilter):
""" """
Filter to check whether message starts with some text. Filter to check whether message starts with some text.
Example: .. code-block:: python3
# Will work if message.text starts with 'Sir'. :caption: Example on using this filter:
@bot.message_handler(text_startswith='Sir')
# Will work if message.text starts with 'sir'.
@bot.message_handler(text_startswith='sir')
# your function
""" """
key = 'text_startswith' key = 'text_startswith'
def check(self, message, text): def check(self, message, text):
"""
:meta private:
"""
return message.text.startswith(text) return message.text.startswith(text)
@ -201,13 +274,19 @@ class ChatFilter(AdvancedCustomFilter):
""" """
Check whether chat_id corresponds to given chat_id. Check whether chat_id corresponds to given chat_id.
Example: .. code-block:: python3
@bot.message_handler(chat_id=[99999]) :caption: Example on using this filter:
@bot.message_handler(chat_id=[99999])
# your function
""" """
key = 'chat_id' key = 'chat_id'
def check(self, message, text): def check(self, message, text):
"""
:meta private:
"""
if isinstance(message, types.CallbackQuery): if isinstance(message, types.CallbackQuery):
return message.message.chat.id in text return message.message.chat.id in text
return message.chat.id in text return message.chat.id in text
@ -217,14 +296,19 @@ class ForwardFilter(SimpleCustomFilter):
""" """
Check whether message was forwarded from channel or group. Check whether message was forwarded from channel or group.
Example: .. code-block:: python3
:caption: Example on using this filter:
@bot.message_handler(is_forwarded=True) @bot.message_handler(is_forwarded=True)
# your function
""" """
key = 'is_forwarded' key = 'is_forwarded'
def check(self, message): def check(self, message):
"""
:meta private:
"""
return message.forward_date is not None return message.forward_date is not None
@ -232,14 +316,19 @@ class IsReplyFilter(SimpleCustomFilter):
""" """
Check whether message is a reply. Check whether message is a reply.
Example: .. code-block:: python3
:caption: Example on using this filter:
@bot.message_handler(is_reply=True) @bot.message_handler(is_reply=True)
# your function
""" """
key = 'is_reply' key = 'is_reply'
def check(self, message): def check(self, message):
"""
:meta private:
"""
if isinstance(message, types.CallbackQuery): if isinstance(message, types.CallbackQuery):
return message.message.reply_to_message is not None return message.message.reply_to_message is not None
return message.reply_to_message is not None return message.reply_to_message is not None
@ -249,14 +338,19 @@ class LanguageFilter(AdvancedCustomFilter):
""" """
Check users language_code. Check users language_code.
Example: .. code-block:: python3
:caption: Example on using this filter:
@bot.message_handler(language_code=['ru']) @bot.message_handler(language_code=['ru'])
# your function
""" """
key = 'language_code' key = 'language_code'
def check(self, message, text): def check(self, message, text):
"""
:meta private:
"""
if type(text) is list: if type(text) is list:
return message.from_user.language_code in text return message.from_user.language_code in text
else: else:
@ -267,8 +361,11 @@ class IsAdminFilter(SimpleCustomFilter):
""" """
Check whether the user is administrator / owner of the chat. Check whether the user is administrator / owner of the chat.
Example: .. code-block:: python3
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True) :caption: Example on using this filter:
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
# your function
""" """
key = 'is_chat_admin' key = 'is_chat_admin'
@ -277,6 +374,9 @@ class IsAdminFilter(SimpleCustomFilter):
self._bot = bot self._bot = bot
def check(self, message): def check(self, message):
"""
:meta private:
"""
if isinstance(message, types.CallbackQuery): if isinstance(message, types.CallbackQuery):
return self._bot.get_chat_member(message.message.chat.id, message.from_user.id).status in ['creator', 'administrator'] return self._bot.get_chat_member(message.message.chat.id, message.from_user.id).status in ['creator', 'administrator']
return self._bot.get_chat_member(message.chat.id, message.from_user.id).status in ['creator', 'administrator'] return self._bot.get_chat_member(message.chat.id, message.from_user.id).status in ['creator', 'administrator']
@ -286,8 +386,11 @@ class StateFilter(AdvancedCustomFilter):
""" """
Filter to check state. Filter to check state.
Example: .. code-block:: python3
@bot.message_handler(state=1) :caption: Example on using this filter:
@bot.message_handler(state=1)
# your function
""" """
def __init__(self, bot): def __init__(self, bot):
@ -296,6 +399,9 @@ class StateFilter(AdvancedCustomFilter):
key = 'state' key = 'state'
def check(self, message, text): def check(self, message, text):
"""
:meta private:
"""
if text == '*': return True if text == '*': return True
# needs to work with callbackquery # needs to work with callbackquery
@ -341,10 +447,16 @@ class IsDigitFilter(SimpleCustomFilter):
""" """
Filter to check whether the string is made up of only digits. Filter to check whether the string is made up of only digits.
Example: .. code-block:: python3
@bot.message_handler(is_digit=True) :caption: Example on using this filter:
@bot.message_handler(is_digit=True)
# your function
""" """
key = 'is_digit' key = 'is_digit'
def check(self, message): def check(self, message):
"""
:meta private:
"""
return message.text.isdigit() return message.text.isdigit()

View File

@ -34,14 +34,34 @@ class AsyncWebhookListener:
""" """
Aynchronous implementation of webhook listener Aynchronous implementation of webhook listener
for asynchronous version of telebot. for asynchronous version of telebot.
Not supposed to be used manually by user.
Use AsyncTeleBot.run_webhooks() instead.
:param bot: AsyncTeleBot instance.
:type bot: telebot.async_telebot.AsyncTeleBot
:param bot: TeleBot instance
:param secret_token: Telegram secret token :param secret_token: Telegram secret token
:type secret_token: str
:param host: Webhook host :param host: Webhook host
:type host: str
:param port: Webhook port :param port: Webhook port
:type port: int
:param ssl_context: SSL context :param ssl_context: SSL context
:type ssl_context: tuple
:param url_path: Webhook url path :param url_path: Webhook url path
:type url_path: str
:param debug: Debug mode :param debug: Debug mode
:type debug: bool
:raises ImportError: If FastAPI or uvicorn is not installed.
:raises ImportError: If Starlette version is too old.
:return: None
""" """
self._check_dependencies() self._check_dependencies()
@ -73,6 +93,8 @@ class AsyncWebhookListener:
async def process_update(self, request: Request, update: dict): async def process_update(self, request: Request, update: dict):
""" """
Processes updates. Processes updates.
:meta private:
""" """
# header containsX-Telegram-Bot-Api-Secret-Token # header containsX-Telegram-Bot-Api-Secret-Token
if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token: if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token:
@ -88,7 +110,10 @@ class AsyncWebhookListener:
async def run_app(self): async def run_app(self):
""" """
Run app with the given parameters. Run app with the given parameters to init.
Not supposed to be used manually by user.
:return: None
""" """
config = Config(app=self.app, config = Config(app=self.app,

View File

@ -1,8 +1,7 @@
""" """
This file is used by TeleBot.run_webhooks() & This file is used by TeleBot.run_webhooks() function.
AsyncTeleBot.run_webhooks() functions.
Flask/fastapi is required to run this script. Fastapi is required to run this script.
""" """
# modules required for running this script # modules required for running this script
@ -34,16 +33,36 @@ class SyncWebhookListener:
debug: Optional[bool]=False debug: Optional[bool]=False
) -> None: ) -> None:
""" """
Synchronous implementation of webhook listener Aynchronous implementation of webhook listener
for synchronous version of telebot. for asynchronous version of telebot.
Not supposed to be used manually by user.
Use AsyncTeleBot.run_webhooks() instead.
:param bot: AsyncTeleBot instance.
:type bot: telebot.async_telebot.AsyncTeleBot
:param bot: TeleBot instance
:param secret_token: Telegram secret token :param secret_token: Telegram secret token
:type secret_token: str
:param host: Webhook host :param host: Webhook host
:type host: str
:param port: Webhook port :param port: Webhook port
:type port: int
:param ssl_context: SSL context :param ssl_context: SSL context
:type ssl_context: tuple
:param url_path: Webhook url path :param url_path: Webhook url path
:type url_path: str
:param debug: Debug mode :param debug: Debug mode
:type debug: bool
:raises ImportError: If FastAPI or uvicorn is not installed.
:raises ImportError: If Starlette version is too old.
:return: None
""" """
self._check_dependencies() self._check_dependencies()
@ -75,6 +94,8 @@ class SyncWebhookListener:
def process_update(self, request: Request, update: dict): def process_update(self, request: Request, update: dict):
""" """
Processes updates. Processes updates.
:meta private:
""" """
# header containsX-Telegram-Bot-Api-Secret-Token # header containsX-Telegram-Bot-Api-Secret-Token
if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token: if request.headers.get('X-Telegram-Bot-Api-Secret-Token') != self._secret_token:
@ -89,7 +110,10 @@ class SyncWebhookListener:
def run_app(self): def run_app(self):
""" """
Run app with the given parameters. Run app with the given parameters to init.
Not supposed to be used manually by user.
:return: None
""" """
uvicorn.run(app=self.app, uvicorn.run(app=self.app,

View File

@ -5,14 +5,17 @@ Markdown & HTML formatting functions.
""" """
import html import html
import re import re
from typing import Optional
def format_text(*args, separator="\n"): def format_text(*args, separator="\n"):
""" """
Formats a list of strings into a single string. Formats a list of strings into a single string.
.. code:: python .. code:: python3
format_text( # just an example format_text( # just an example
mbold('Hello'), mbold('Hello'),
@ -20,7 +23,13 @@ def format_text(*args, separator="\n"):
) )
:param args: Strings to format. :param args: Strings to format.
:type args: :obj:`str`
:param separator: The separator to use between each string. :param separator: The separator to use between each string.
:type separator: :obj:`str`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return separator.join(args) return separator.join(args)
@ -31,6 +40,10 @@ def escape_html(content: str) -> str:
Escapes HTML characters in a string of HTML. Escapes HTML characters in a string of HTML.
:param content: The string of HTML to escape. :param content: The string of HTML to escape.
:type content: :obj:`str`
:return: The escaped string.
:rtype: :obj:`str`
""" """
return html.escape(content) return html.escape(content)
@ -39,9 +52,13 @@ def escape_markdown(content: str) -> str:
""" """
Escapes Markdown characters in a string of Markdown. Escapes Markdown characters in a string of Markdown.
Credits: simonsmh Credits to: simonsmh
:param content: The string of Markdown to escape. :param content: The string of Markdown to escape.
:type content: :obj:`str`
:return: The escaped string.
:rtype: :obj:`str`
""" """
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!])", r"\\\1", content) parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!])", r"\\\1", content)
@ -49,154 +66,249 @@ def escape_markdown(content: str) -> str:
return reparse return reparse
def mbold(content: str, escape: bool=True) -> str: def mbold(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted bold string. Returns a Markdown-formatted bold string.
:param content: The string to bold. :param content: The string to bold.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '*{}*'.format(escape_markdown(content) if escape else content) return '*{}*'.format(escape_markdown(content) if escape else content)
def hbold(content: str, escape: bool=True) -> str: def hbold(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted bold string. Returns an HTML-formatted bold string.
:param content: The string to bold. :param content: The string to bold.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<b>{}</b>'.format(escape_html(content) if escape else content) return '<b>{}</b>'.format(escape_html(content) if escape else content)
def mitalic(content: str, escape: bool=True) -> str: def mitalic(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted italic string. Returns a Markdown-formatted italic string.
:param content: The string to italicize. :param content: The string to italicize.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '_{}_\r'.format(escape_markdown(content) if escape else content) return '_{}_\r'.format(escape_markdown(content) if escape else content)
def hitalic(content: str, escape: bool=True) -> str: def hitalic(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted italic string. Returns an HTML-formatted italic string.
:param content: The string to italicize. :param content: The string to italicize.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<i>{}</i>'.format(escape_html(content) if escape else content) return '<i>{}</i>'.format(escape_html(content) if escape else content)
def munderline(content: str, escape: bool=True) -> str: def munderline(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted underline string. Returns a Markdown-formatted underline string.
:param content: The string to underline. :param content: The string to underline.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '__{}__'.format(escape_markdown(content) if escape else content) return '__{}__'.format(escape_markdown(content) if escape else content)
def hunderline(content: str, escape: bool=True) -> str: def hunderline(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted underline string. Returns an HTML-formatted underline string.
:param content: The string to underline. :param content: The string to underline.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<u>{}</u>'.format(escape_html(content) if escape else content) return '<u>{}</u>'.format(escape_html(content) if escape else content)
def mstrikethrough(content: str, escape: bool=True) -> str: def mstrikethrough(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted strikethrough string. Returns a Markdown-formatted strikethrough string.
:param content: The string to strikethrough. :param content: The string to strikethrough.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '~{}~'.format(escape_markdown(content) if escape else content) return '~{}~'.format(escape_markdown(content) if escape else content)
def hstrikethrough(content: str, escape: bool=True) -> str: def hstrikethrough(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted strikethrough string. Returns an HTML-formatted strikethrough string.
:param content: The string to strikethrough. :param content: The string to strikethrough.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<s>{}</s>'.format(escape_html(content) if escape else content) return '<s>{}</s>'.format(escape_html(content) if escape else content)
def mspoiler(content: str, escape: bool=True) -> str: def mspoiler(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted spoiler string. Returns a Markdown-formatted spoiler string.
:param content: The string to spoiler. :param content: The string to spoiler.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '||{}||'.format(escape_markdown(content) if escape else content) return '||{}||'.format(escape_markdown(content) if escape else content)
def hspoiler(content: str, escape: bool=True) -> str: def hspoiler(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted spoiler string. Returns an HTML-formatted spoiler string.
:param content: The string to spoiler. :param content: The string to spoiler.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<tg-spoiler>{}</tg-spoiler>'.format(escape_html(content) if escape else content) return '<tg-spoiler>{}</tg-spoiler>'.format(escape_html(content) if escape else content)
def mlink(content: str, url: str, escape: bool=True) -> str: def mlink(content: str, url: str, escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted link string. Returns a Markdown-formatted link string.
:param content: The string to link. :param content: The string to link.
:type content: :obj:`str`
:param url: The URL to link to. :param url: The URL to link to.
:param escape: True if you need to escape special characters. :type url: str
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '[{}]({})'.format(escape_markdown(content), escape_markdown(url) if escape else content) return '[{}]({})'.format(escape_markdown(content), escape_markdown(url) if escape else content)
def hlink(content: str, url: str, escape: bool=True) -> str: def hlink(content: str, url: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted link string. Returns an HTML-formatted link string.
:param content: The string to link. :param content: The string to link.
:type content: :obj:`str`
:param url: The URL to link to. :param url: The URL to link to.
:param escape: True if you need to escape special characters. :type url: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<a href="{}">{}</a>'.format(escape_html(url), escape_html(content) if escape else content) return '<a href="{}">{}</a>'.format(escape_html(url), escape_html(content) if escape else content)
def mcode(content: str, language: str="", escape: bool=True) -> str: def mcode(content: str, language: str="", escape: Optional[bool]=True) -> str:
""" """
Returns a Markdown-formatted code string. Returns a Markdown-formatted code string.
:param content: The string to code. :param content: The string to code.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '```{}\n{}```'.format(language, escape_markdown(content) if escape else content) return '```{}\n{}```'.format(language, escape_markdown(content) if escape else content)
def hcode(content: str, escape: bool=True) -> str: def hcode(content: str, escape: Optional[bool]=True) -> str:
""" """
Returns an HTML-formatted code string. Returns an HTML-formatted code string.
:param content: The string to code. :param content: The string to code.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<code>{}</code>'.format(escape_html(content) if escape else content) return '<code>{}</code>'.format(escape_html(content) if escape else content)
def hpre(content: str, escape: bool=True, language: str="") -> str: def hpre(content: str, escape: Optional[bool]=True, language: str="") -> str:
""" """
Returns an HTML-formatted preformatted string. Returns an HTML-formatted preformatted string.
:param content: The string to preformatted. :param content: The string to preformatted.
:param escape: True if you need to escape special characters. :type content: :obj:`str`
:param escape: True if you need to escape special characters. Defaults to True.
:type escape: :obj:`bool`
:return: The formatted string.
:rtype: :obj:`str`
""" """
return '<pre><code class="{}">{}</code></pre>'.format(language, escape_html(content) if escape else content) return '<pre><code class="{}">{}</code></pre>'.format(language, escape_html(content) if escape else content)
@ -205,7 +317,10 @@ def hide_link(url: str) -> str:
""" """
Hide url of an image. Hide url of an image.
:param url: :param url: The url of the image.
:return: str :type url: :obj:`str`
:return: The hidden url.
:rtype: :obj:`str`
""" """
return f'<a href="{url}">&#8288;</a>' return f'<a href="{url}">&#8288;</a>'

View File

@ -12,7 +12,9 @@ except:
class HandlerBackend(object): class HandlerBackend(object):
""" """
Class for saving (next step|reply) handlers Class for saving (next step|reply) handlers.
:meta private:
""" """
def __init__(self, handlers=None): def __init__(self, handlers=None):
if handlers is None: if handlers is None:
@ -30,6 +32,9 @@ class HandlerBackend(object):
class MemoryHandlerBackend(HandlerBackend): class MemoryHandlerBackend(HandlerBackend):
"""
:meta private:
"""
def register_handler(self, handler_group_id, handler): def register_handler(self, handler_group_id, handler):
if handler_group_id in self.handlers: if handler_group_id in self.handlers:
self.handlers[handler_group_id].append(handler) self.handlers[handler_group_id].append(handler)
@ -47,6 +52,9 @@ class MemoryHandlerBackend(HandlerBackend):
class FileHandlerBackend(HandlerBackend): class FileHandlerBackend(HandlerBackend):
"""
:meta private:
"""
def __init__(self, handlers=None, filename='./.handler-saves/handlers.save', delay=120): def __init__(self, handlers=None, filename='./.handler-saves/handlers.save', delay=120):
super(FileHandlerBackend, self).__init__(handlers) super(FileHandlerBackend, self).__init__(handlers)
self.filename = filename self.filename = filename
@ -119,6 +127,9 @@ class FileHandlerBackend(HandlerBackend):
class RedisHandlerBackend(HandlerBackend): class RedisHandlerBackend(HandlerBackend):
"""
:meta private:
"""
def __init__(self, handlers=None, host='localhost', port=6379, db=0, prefix='telebot', password=None): def __init__(self, handlers=None, host='localhost', port=6379, db=0, prefix='telebot', password=None):
super(RedisHandlerBackend, self).__init__(handlers) super(RedisHandlerBackend, self).__init__(handlers)
if not redis_installed: if not redis_installed:
@ -150,6 +161,14 @@ class RedisHandlerBackend(HandlerBackend):
class State: class State:
"""
Class representing a state.
.. code-block:: python3
class MyStates(StatesGroup):
my_state = State() # returns my_state:State string.
"""
def __init__(self) -> None: def __init__(self) -> None:
self.name = None self.name = None
def __str__(self) -> str: def __str__(self) -> str:
@ -158,6 +177,14 @@ class State:
class StatesGroup: class StatesGroup:
"""
Class representing common states.
.. code-block:: python3
class MyStates(StatesGroup):
my_state = State() # returns my_state:State string.
"""
def __init_subclass__(cls) -> None: def __init_subclass__(cls) -> None:
for name, value in cls.__dict__.items(): for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State): if not name.startswith('__') and not callable(value) and isinstance(value, State):
@ -179,8 +206,13 @@ class BaseMiddleware:
message update, then you will have to create pre_process_message function, and message update, then you will have to create pre_process_message function, and
so on. Same applies to post_process. so on. Same applies to post_process.
.. code-block:: python .. note::
If you want to use middleware, you have to set use_class_middlewares=True in your
TeleBot instance.
.. code-block:: python3
:caption: Example of class-based middlewares.
class MyMiddleware(BaseMiddleware): class MyMiddleware(BaseMiddleware):
def __init__(self): def __init__(self):
self.update_sensitive = True self.update_sensitive = True

View File

@ -20,6 +20,7 @@ class JsonSerializable(object):
""" """
Subclasses of this class are guaranteed to be able to be converted to JSON format. Subclasses of this class are guaranteed to be able to be converted to JSON format.
All subclasses of this class must override to_json. All subclasses of this class must override to_json.
""" """
def to_json(self): def to_json(self):
@ -36,6 +37,7 @@ class Dictionaryable(object):
""" """
Subclasses of this class are guaranteed to be able to be converted to dictionary. Subclasses of this class are guaranteed to be able to be converted to dictionary.
All subclasses of this class must override to_dict. All subclasses of this class must override to_dict.
""" """
def to_dict(self): def to_dict(self):
@ -90,6 +92,65 @@ class JsonDeserializable(object):
class Update(JsonDeserializable): class Update(JsonDeserializable):
"""
This object represents an incoming update.
https://core.telegram.org/bots/api#update
:attribute update_id: The update's unique identifier. Update identifiers start from a certain positive number and increase sequentially.
This ID becomes especially handy if you're using webhooks, since it allows you to ignore repeated updates or to restore the correct
update sequence, should they get out of order. If there are no new updates for at least a week, then identifier of the next update will
be chosen randomly instead of sequentially.
:type update_id: int
:attribute message: New incoming message of any kind text, photo, sticker, etc.
:type message: :class:`telebot.types.Message`
:attribute edited_message: New version of a message that is known to the bot and was edited.
:type edited_message: :class:`telebot.types.Message`
:attribute channel_post: New incoming channel post of any kind text, photo, sticker, etc.
:type channel_post: :class:`telebot.types.Message`
:attribute edited_channel_post: New version of a channel post that is known to the bot and was edited.
:type edited_channel_post: :class:`telebot.types.Message`
:attribute inline_query: New incoming query from a user, which is answered by a bot and can be further processed.
:type inline_query: :class:`telebot.types.InlineQuery`
:attribute chosen_inline_result: New incoming result of an inline query that was chosen by a user and sent to their chat partner.
:type chosen_inline_result: :class:`telebot.types.ChosenInlineResult`
:attribute callback_query: New incoming callback query from a user.
:type callback_query: :class:`telebot.types.CallbackQuery`
:attribute shipping_query: New incoming shipping query. Only for invoices with flexible price
:type shipping_query: :class:`telebot.types.ShippingQuery`
:attribute pre_checkout_query: New incoming pre-checkout query. Contains full information about checkout
:type pre_checkout_query: :class:`telebot.types.PreCheckoutQuery`
:attribute poll: New poll state. Bots receive only updates about stopped polls and polls, which are sent by the bot
:type poll: :class:`telebot.types.Poll`
:attribute poll_answer: A user changed their answer in a non-anonymous poll. Bots receive new votes only in polls that were sent by the bot itself.
:type poll_answer: :class:`telebot.types.PollAnswer`
:attribute my_chat_member: The bot's chat member status was updated in a chat. For private chats,
this update is received only when the bot is blocked or unblocked by the user.
:type my_chat_member: :class:`telebot.types.ChatMember`
:attribute chat_member: A chat member's status was updated in a chat. The bot must be an administrator in the chat and must
explicitly specify chat_member in the list of allowed_updates to receive these updates.
:type chat_member: :class:`telebot.types.ChatMember`
:attribute chat_join_request: A request to join the chat has been sent. The bot must have the can_invite_users
administrator right in the chat to receive these updates.
:type chat_join_request: :class:`telebot.types.ChatJoinRequest`
:return: An Update object.
:rtype: :class:`telebot.types.Update`
"""
@classmethod @classmethod
def de_json(cls, json_string): def de_json(cls, json_string):
if json_string is None: return None if json_string is None: return None

View File

@ -35,11 +35,13 @@ logger = logging.getLogger('TeleBot')
thread_local = threading.local() thread_local = threading.local()
#: Contains all media content types.
content_type_media = [ content_type_media = [
'text', 'audio', 'animation', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact', 'dice', 'poll', 'text', 'audio', 'animation', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact', 'dice', 'poll',
'venue', 'location' 'venue', 'location'
] ]
#: Contains all service content types such as `User joined the group`.
content_type_service = [ content_type_service = [
'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', 'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created',
'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', 'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message',
@ -47,6 +49,7 @@ content_type_service = [
'video_chat_participants_invited', 'message_auto_delete_timer_changed' 'video_chat_participants_invited', 'message_auto_delete_timer_changed'
] ]
#: All update types, should be used for allowed_updates parameter in polling.
update_types = [ update_types = [
"message", "edited_message", "channel_post", "edited_channel_post", "inline_query", "message", "edited_message", "channel_post", "edited_channel_post", "inline_query",
"chosen_inline_result", "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer", "chosen_inline_result", "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer",
@ -55,6 +58,9 @@ update_types = [
class WorkerThread(threading.Thread): class WorkerThread(threading.Thread):
"""
:meta private:
"""
count = 0 count = 0
def __init__(self, exception_callback=None, queue=None, name=None): def __init__(self, exception_callback=None, queue=None, name=None):
@ -118,7 +124,9 @@ class WorkerThread(threading.Thread):
class ThreadPool: class ThreadPool:
"""
:meta private:
"""
def __init__(self, telebot, num_threads=2): def __init__(self, telebot, num_threads=2):
self.telebot = telebot self.telebot = telebot
self.tasks = Queue.Queue() self.tasks = Queue.Queue()
@ -156,6 +164,9 @@ class ThreadPool:
class AsyncTask: class AsyncTask:
"""
:meta private:
"""
def __init__(self, target, *args, **kwargs): def __init__(self, target, *args, **kwargs):
self.target = target self.target = target
self.args = args self.args = args
@ -182,6 +193,9 @@ class AsyncTask:
class CustomRequestResponse(): class CustomRequestResponse():
"""
:meta private:
"""
def __init__(self, json_text, status_code = 200, reason = ""): def __init__(self, json_text, status_code = 200, reason = ""):
self.status_code = status_code self.status_code = status_code
self.text = json_text self.text = json_text
@ -192,6 +206,9 @@ class CustomRequestResponse():
def async_dec(): def async_dec():
"""
:meta private:
"""
def decorator(fn): def decorator(fn):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
return AsyncTask(fn, *args, **kwargs) return AsyncTask(fn, *args, **kwargs)
@ -201,19 +218,49 @@ def async_dec():
return decorator return decorator
def is_string(var): def is_string(var) -> bool:
"""
Returns True if the given object is a string.
"""
return isinstance(var, str) return isinstance(var, str)
def is_dict(var): def is_dict(var) -> bool:
"""
Returns True if the given object is a dictionary.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a dictionary.
:rtype: :obj:`bool`
"""
return isinstance(var, dict) return isinstance(var, dict)
def is_bytes(var): def is_bytes(var) -> bool:
"""
Returns True if the given object is a bytes object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a bytes object.
:rtype: :obj:`bool`
"""
return isinstance(var, bytes) return isinstance(var, bytes)
def is_pil_image(var): def is_pil_image(var) -> bool:
"""
Returns True if the given object is a PIL.Image.Image object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a PIL.Image.Image object.
:rtype: :obj:`bool`
"""
return pil_imported and isinstance(var, Image.Image) return pil_imported and isinstance(var, Image.Image)
@ -233,7 +280,10 @@ def is_command(text: str) -> bool:
Checks if `text` is a command. Telegram chat commands start with the '/' character. Checks if `text` is a command. Telegram chat commands start with the '/' character.
:param text: Text to check. :param text: Text to check.
:type text: :obj:`str`
:return: True if `text` is a command, else False. :return: True if `text` is a command, else False.
:rtype: :obj:`bool`
""" """
if text is None: return False if text is None: return False
return text.startswith('/') return text.startswith('/')
@ -244,30 +294,40 @@ def extract_command(text: str) -> Union[str, None]:
Extracts the command from `text` (minus the '/') if `text` is a command (see is_command). Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
If `text` is not a command, this function returns None. If `text` is not a command, this function returns None.
Examples: .. code-block:: python3
extract_command('/help'): 'help' :caption: Examples:
extract_command('/help@BotName'): 'help'
extract_command('/search black eyed peas'): 'search' extract_command('/help'): 'help'
extract_command('Good day to you'): None extract_command('/help@BotName'): 'help'
extract_command('/search black eyed peas'): 'search'
extract_command('Good day to you'): None
:param text: String to extract the command from :param text: String to extract the command from
:type text: :obj:`str`
:return: the command if `text` is a command (according to is_command), else None. :return: the command if `text` is a command (according to is_command), else None.
:rtype: :obj:`str` or :obj:`None`
""" """
if text is None: return None if text is None: return None
return text.split()[0].split('@')[0][1:] if is_command(text) else None return text.split()[0].split('@')[0][1:] if is_command(text) else None
def extract_arguments(text: str) -> str: def extract_arguments(text: str) -> str or None:
""" """
Returns the argument after the command. Returns the argument after the command.
Examples: .. code-block:: python3
extract_arguments("/get name"): 'name' :caption: Examples:
extract_arguments("/get"): ''
extract_arguments("/get@botName name"): 'name' extract_arguments("/get name"): 'name'
extract_arguments("/get"): ''
extract_arguments("/get@botName name"): 'name'
:param text: String to extract the arguments from a command :param text: String to extract the arguments from a command
:type text: :obj:`str`
:return: the arguments if `text` is a command (according to is_command), else None. :return: the arguments if `text` is a command (according to is_command), else None.
:rtype: :obj:`str` or :obj:`None`
""" """
regexp = re.compile(r"/\w*(@\w*)*\s*([\s\S]*)", re.IGNORECASE) regexp = re.compile(r"/\w*(@\w*)*\s*([\s\S]*)", re.IGNORECASE)
result = regexp.match(text) result = regexp.match(text)
@ -280,8 +340,13 @@ def split_string(text: str, chars_per_string: int) -> List[str]:
This is very useful for splitting one giant message into multiples. This is very useful for splitting one giant message into multiples.
:param text: The text to split :param text: The text to split
:type text: :obj:`str`
:param chars_per_string: The number of characters per line the text is split into. :param chars_per_string: The number of characters per line the text is split into.
:type chars_per_string: :obj:`int`
:return: The splitted text as a list of strings. :return: The splitted text as a list of strings.
:rtype: :obj:`list` of :obj:`str`
""" """
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)] return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
@ -294,8 +359,13 @@ def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str
Splits by '\n', '. ' or ' ' in exactly this priority. Splits by '\n', '. ' or ' ' in exactly this priority.
:param text: The text to split :param text: The text to split
:type text: :obj:`str`
:param chars_per_string: The number of maximum characters per part the text is split to. :param chars_per_string: The number of maximum characters per part the text is split to.
:type chars_per_string: :obj:`int`
:return: The splitted text as a list of strings. :return: The splitted text as a list of strings.
:rtype: :obj:`list` of :obj:`str`
""" """
def _text_before_last(substr: str) -> str: def _text_before_last(substr: str) -> str:
@ -336,12 +406,25 @@ def user_link(user: types.User, include_id: bool=False) -> str:
Returns an HTML user link. This is useful for reports. Returns an HTML user link. This is useful for reports.
Attention: Don't forget to set parse_mode to 'HTML'! Attention: Don't forget to set parse_mode to 'HTML'!
Example:
bot.send_message(your_user_id, user_link(message.from_user) + ' started the bot!', parse_mode='HTML') .. code-block:: python3
:caption: Example:
bot.send_message(your_user_id, user_link(message.from_user) + ' started the bot!', parse_mode='HTML')
.. note::
You can use formatting.* for all other formatting options(bold, italic, links, and etc.)
This method is kept for backward compatibility, and it is recommended to use formatting.* for
more options.
:param user: the user (not the user_id) :param user: the user (not the user_id)
:type user: :obj:`telebot.types.User`
:param include_id: include the user_id :param include_id: include the user_id
:type include_id: :obj:`bool`
:return: HTML user link :return: HTML user link
:rtype: :obj:`str`
""" """
name = escape(user.first_name) name = escape(user.first_name)
return (f"<a href='tg://user?id={user.id}'>{name}</a>" return (f"<a href='tg://user?id={user.id}'>{name}</a>"
@ -355,15 +438,16 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
Example: Example:
.. code-block:: python .. code-block:: python3
:caption: Using quick_markup:
quick_markup({ quick_markup({
'Twitter': {'url': 'https://twitter.com'}, 'Twitter': {'url': 'https://twitter.com'},
'Facebook': {'url': 'https://facebook.com'}, 'Facebook': {'url': 'https://facebook.com'},
'Back': {'callback_data': 'whatever'} 'Back': {'callback_data': 'whatever'}
}, row_width=2): }, row_width=2):
# returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook # returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook
# and a back button below # and a back button below
# kwargs can be: # kwargs can be:
{ {
@ -378,8 +462,13 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
} }
:param values: a dict containing all buttons to create in this format: {text: kwargs} {str:} :param values: a dict containing all buttons to create in this format: {text: kwargs} {str:}
:type values: :obj:`dict`
:param row_width: int row width :param row_width: int row width
:type row_width: :obj:`int`
:return: InlineKeyboardMarkup :return: InlineKeyboardMarkup
:rtype: :obj:`types.InlineKeyboardMarkup`
""" """
markup = types.InlineKeyboardMarkup(row_width=row_width) markup = types.InlineKeyboardMarkup(row_width=row_width)
buttons = [ buttons = [
@ -392,16 +481,25 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I
# CREDITS TO http://stackoverflow.com/questions/12317940#answer-12320352 # CREDITS TO http://stackoverflow.com/questions/12317940#answer-12320352
def or_set(self): def or_set(self):
"""
:meta private:
"""
self._set() self._set()
self.changed() self.changed()
def or_clear(self): def or_clear(self):
"""
:meta private:
"""
self._clear() self._clear()
self.changed() self.changed()
def orify(e, changed_callback): def orify(e, changed_callback):
"""
:meta private:
"""
if not hasattr(e, "_set"): if not hasattr(e, "_set"):
e._set = e.set e._set = e.set
if not hasattr(e, "_clear"): if not hasattr(e, "_clear"):
@ -412,6 +510,9 @@ def orify(e, changed_callback):
def OrEvent(*events): def OrEvent(*events):
"""
:meta private:
"""
or_event = threading.Event() or_event = threading.Event()
def changed(): def changed():
@ -435,6 +536,9 @@ def OrEvent(*events):
def per_thread(key, construct_value, reset=False): def per_thread(key, construct_value, reset=False):
"""
:meta private:
"""
if reset or not hasattr(thread_local, key): if reset or not hasattr(thread_local, key):
value = construct_value() value = construct_value()
setattr(thread_local, key, value) setattr(thread_local, key, value)
@ -449,7 +553,13 @@ def chunks(lst, n):
yield lst[i:i + n] yield lst[i:i + n]
def generate_random_token(): def generate_random_token() -> str:
"""
Generates a random token consisting of letters and digits, 16 characters long.
:return: a random token
:rtype: :obj:`str`
"""
return ''.join(random.sample(string.ascii_letters, 16)) return ''.join(random.sample(string.ascii_letters, 16))
@ -457,10 +567,19 @@ def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecatio
""" """
Use this decorator to mark functions as deprecated. Use this decorator to mark functions as deprecated.
When the function is used, an info (or warning if `warn` is True) is logged. When the function is used, an info (or warning if `warn` is True) is logged.
:meta private:
:param warn: If True a warning is logged else an info :param warn: If True a warning is logged else an info
:type warn: :obj:`bool`
:param alternative: The new function to use instead :param alternative: The new function to use instead
:type alternative: :obj:`Callable`
:param deprecation_text: Custom deprecation text :param deprecation_text: Custom deprecation text
:type deprecation_text: :obj:`str`
:return: The decorated function
""" """
def decorator(function): def decorator(function):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
@ -480,7 +599,17 @@ def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecatio
# Cloud helpers # Cloud helpers
def webhook_google_functions(bot, request): def webhook_google_functions(bot, request):
"""A webhook endpoint for Google Cloud Functions FaaS.""" """
A webhook endpoint for Google Cloud Functions FaaS.
:param bot: The bot instance
:type bot: :obj:`telebot.TeleBot` or :obj:`telebot.async_telebot.AsyncTeleBot`
:param request: The request object
:type request: :obj:`flask.Request`
:return: The response object
"""
if request.is_json: if request.is_json:
try: try:
request_json = request.get_json() request_json = request.get_json()
@ -494,7 +623,7 @@ def webhook_google_functions(bot, request):
return 'Bot ON' return 'Bot ON'
def antiflood(function, *args, **kwargs): def antiflood(function: Callable, *args, **kwargs):
""" """
Use this function inside loops in order to avoid getting TooManyRequests error. Use this function inside loops in order to avoid getting TooManyRequests error.
Example: Example:
@ -505,9 +634,15 @@ def antiflood(function, *args, **kwargs):
for chat_id in chat_id_list: for chat_id in chat_id_list:
msg = antiflood(bot.send_message, chat_id, text) msg = antiflood(bot.send_message, chat_id, text)
:param function: :param function: The function to call
:param args: :type function: :obj:`Callable`
:param kwargs:
:param args: The arguments to pass to the function
:type args: :obj:`tuple`
:param kwargs: The keyword arguments to pass to the function
:type kwargs: :obj:`dict`
:return: None :return: None
""" """
from telebot.apihelper import ApiTelegramException from telebot.apihelper import ApiTelegramException
@ -524,6 +659,17 @@ def antiflood(function, *args, **kwargs):
def parse_web_app_data(token: str, raw_init_data: str): def parse_web_app_data(token: str, raw_init_data: str):
"""
Parses web app data.
:param token: The bot token
:type token: :obj:`str`
:param raw_init_data: The raw init data
:type raw_init_data: :obj:`str`
:return: The parsed init data
"""
is_valid = validate_web_app_data(token, raw_init_data) is_valid = validate_web_app_data(token, raw_init_data)
if not is_valid: if not is_valid:
return False return False
@ -539,7 +685,18 @@ def parse_web_app_data(token: str, raw_init_data: str):
return result return result
def validate_web_app_data(token, raw_init_data): def validate_web_app_data(token: str, raw_init_data: str):
"""
Validates web app data.
:param token: The bot token
:type token: :obj:`str`
:param raw_init_data: The raw init data
:type raw_init_data: :obj:`str`
:return: The parsed init data
"""
try: try:
parsed_data = dict(parse_qsl(raw_init_data)) parsed_data = dict(parse_qsl(raw_init_data))
except ValueError: except ValueError: