Queer European MD passionate about IT
Browse Source

Compliance with Telegram Bot API 6.3

Davte 1 year ago
parent
commit
881d249256
4 changed files with 653 additions and 44 deletions
  1. 1 1
      davtelepot/__init__.py
  2. 645 40
      davtelepot/api.py
  3. 3 3
      davtelepot/api_helper.py
  4. 4 0
      davtelepot/bot.py

+ 1 - 1
davtelepot/__init__.py

@@ -11,7 +11,7 @@ __author__ = "Davide Testa"
 __email__ = "davide@davte.it"
 __credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
 __license__ = "GNU General Public License v3.0"
-__version__ = "2.8.7"
+__version__ = "2.8.8"
 __maintainer__ = "Davide Testa"
 __contact__ = "t.me/davte"
 

+ 645 - 40
davtelepot/api.py

@@ -44,7 +44,11 @@ class TelegramError(Exception):
 
 
 class ChatPermissions(dict):
-    """Actions that a non-administrator user is allowed to take in a chat."""
+    """Actions that a non-administrator user is allowed to take in a chat.
+
+    See https://core.telegram.org/bots/api#chatpermissions for details.
+    """
+
     def __init__(self,
                  can_send_messages: bool = True,
                  can_send_media_messages: bool = True,
@@ -74,6 +78,198 @@ class Command(dict):
         self['description'] = description
 
 
+class BotCommandScope(dict):
+    """This object represents the scope to which bot commands are applied.
+
+    See https://core.telegram.org/bots/api#botcommandscope for details.
+
+    Currently, the following 7 scopes are supported:
+        - BotCommandScopeDefault;
+        - BotCommandScopeAllPrivateChats;
+        - BotCommandScopeAllGroupChats;
+        - BotCommandScopeAllChatAdministrators;
+        - BotCommandScopeChat;
+        - BotCommandScopeChatAdministrators;
+        - BotCommandScopeChatMember.
+
+    An algorithm described [here](https://core.telegram.org/bots/api#botcommandscope)
+        is used to determine the list of commands for a particular user
+        viewing the bot menu.
+    """
+
+    # noinspection PyShadowingBuiltins
+    def __init__(self,
+                 type: str = 'default'):
+        if type not in ('default', 'all_private_chats', 'all_group_chats',
+                        'all_chat_administrators', 'chat', 'chat_administrators',
+                        'chat_member'):
+            raise TypeError(f"Unknown bot command scope type: `{type}`.")
+        super().__init__(self)
+        self['type'] = type
+
+
+class WebAppInfo(dict):
+    """Describes a Web App.
+
+    See https://core.telegram.org/bots/api#webappinfo for details."""
+
+    def __init__(self,
+                 url: str = None):
+        super().__init__(self)
+        self['url'] = url
+
+
+class MenuButton(dict):
+    # noinspection PyShadowingBuiltins
+    def __init__(self,
+                 type: str = 'default',
+                 text: str = None,
+                 web_app: 'WebAppInfo' = None):
+        if type not in ('default', 'commands', 'web_app'):
+            raise TypeError(f"Unknown menu button type: `{type}`.")
+        super().__init__(self)
+        self['type'] = type
+        if type == 'web_app':
+            self['text'] = text
+            self['web_app'] = web_app
+
+
+class ChatAdministratorRights(dict):
+    """Represents the rights of an administrator in a chat."""
+
+    def __init__(self,
+                 is_anonymous: bool = False,
+                 can_manage_chat: bool = False,
+                 can_delete_messages: bool = False,
+                 can_manage_video_chats: bool = False,
+                 can_restrict_members: bool = False,
+                 can_promote_members: bool = False,
+                 can_change_info: bool = False,
+                 can_invite_users: bool = False,
+                 can_post_messages: bool = False,
+                 can_edit_messages: bool = False,
+                 can_pin_messages: bool = False,
+                 can_manage_topics: bool = False):
+        """Represents the rights of an administrator in a chat.
+
+        @param is_anonymous: True, if the user's presence in the chat is hidden
+        @param can_manage_chat: True, if the administrator can access the chat
+            event log, chat statistics, message statistics in channels, see
+            channel members, see anonymous administrators in supergroups and
+            ignore slow mode. Implied by any other administrator privilege
+        @param can_delete_messages: True, if the administrator can delete
+            messages of other users
+        @param can_manage_video_chats: True, if the administrator can manage
+            video chats
+        @param can_restrict_members: True, if the administrator can restrict,
+            ban or unban chat members
+        @param can_promote_members: True, if the administrator can add new
+            administrators with a subset of their own privileges or demote
+            administrators that he has promoted, directly or indirectly
+            (promoted by administrators that were appointed by the user)
+        @param can_change_info: True, if the user is allowed to change the
+            chat title, photo and other settings
+        @param can_invite_users: True, if the user is allowed to invite new
+            users to the chat
+        @param can_post_messages: Optional. True, if the administrator can
+            post in the channel; channels only
+        @param can_edit_messages: Optional. True, if the administrator can
+            edit messages of other users and can pin messages; channels only
+        @param can_pin_messages: Optional. True, if the user is allowed to
+            pin messages; groups and supergroups only
+        @param can_manage_topics: Optional. True, if the user is allowed to
+            create, rename, close, and reopen forum topics; supergroups only
+        """
+        super().__init__(self)
+        self['is_anonymous'] = is_anonymous
+        self['can_manage_chat'] = can_manage_chat
+        self['can_delete_messages'] = can_delete_messages
+        self['can_manage_video_chats'] = can_manage_video_chats
+        self['can_restrict_members'] = can_restrict_members
+        self['can_promote_members'] = can_promote_members
+        self['can_change_info'] = can_change_info
+        self['can_invite_users'] = can_invite_users
+        self['can_post_messages'] = can_post_messages
+        self['can_edit_messages'] = can_edit_messages
+        self['can_pin_messages'] = can_pin_messages
+        self['can_manage_topics'] = can_manage_topics
+
+
+class LabeledPrice(dict):
+    """This object represents a portion of the price for goods or services."""
+    def __init__(self, label: str, amount: int):
+        """This object represents a portion of the price for goods or services.
+
+        @param label: Portion label.
+        @param amount: Price of the product in the smallest units of the
+            currency (integer, not float/double).
+            For example, for a price of US$ 1.45 pass amount = 145.
+            See the exp parameter in currencies.json, it shows the number of
+            digits past the decimal point for each currency (2 for the majority
+            of currencies).
+        Reference (currencies.json): https://core.telegram.org/bots/payments/currencies.json
+        """
+        super().__init__(self)
+        self['label'] = label
+        self['amount'] = amount
+
+
+class InlineQueryResult(dict):
+    """This object represents one result of an inline query.
+
+    Telegram clients currently support results of the following 20 types:
+        - InlineQueryResultCachedAudio;
+        - InlineQueryResultCachedDocument;
+        - InlineQueryResultCachedGif;
+        - InlineQueryResultCachedMpeg4Gif;
+        - InlineQueryResultCachedPhoto;
+        - InlineQueryResultCachedSticker;
+        - InlineQueryResultCachedVideo;
+        - InlineQueryResultCachedVoice;
+        - InlineQueryResultArticle;
+        - InlineQueryResultAudio;
+        - InlineQueryResultContact;
+        - InlineQueryResultGame;
+        - InlineQueryResultDocument;
+        - InlineQueryResultGif;
+        - InlineQueryResultLocation;
+        - InlineQueryResultMpeg4Gif;
+        - InlineQueryResultPhoto;
+        - InlineQueryResultVenue;
+        - InlineQueryResultVideo.
+    Note: All URLs passed in inline query results will be available to end
+        users and therefore must be assumed to be public.
+    """
+    # noinspection PyShadowingBuiltins
+    def __init__(self,
+                 type: str = 'default',
+                 **kwargs):
+        if type not in ('InlineQueryResultCachedAudio',
+                        'InlineQueryResultCachedDocument',
+                        'InlineQueryResultCachedGif',
+                        'InlineQueryResultCachedMpeg4Gif',
+                        'InlineQueryResultCachedPhoto',
+                        'InlineQueryResultCachedSticker',
+                        'InlineQueryResultCachedVideo',
+                        'InlineQueryResultCachedVoice',
+                        'InlineQueryResultArticle',
+                        'InlineQueryResultAudio',
+                        'InlineQueryResultContact',
+                        'InlineQueryResultGame',
+                        'InlineQueryResultDocument',
+                        'InlineQueryResultGif',
+                        'InlineQueryResultLocation',
+                        'InlineQueryResultMpeg4Gif',
+                        'InlineQueryResultPhoto',
+                        'InlineQueryResultVenue',
+                        'InlineQueryResultVideo'):
+            raise TypeError(f"Unknown InlineQueryResult type: `{type}`.")
+        super().__init__(self)
+        self['type'] = type
+        for key, value in kwargs.items():
+            self[key] = value
+
+
 # This class needs to mirror Telegram API, so camelCase method are needed
 # noinspection PyPep8Naming
 class TelegramBot:
@@ -94,7 +290,7 @@ class TelegramBot:
             close=False
         )
     }
-    _absolute_cooldown_timedelta = datetime.timedelta(seconds=1/30)
+    _absolute_cooldown_timedelta = datetime.timedelta(seconds=1 / 30)
     _per_chat_cooldown_timedelta = datetime.timedelta(seconds=1)
     _allowed_messages_per_group_per_minute = 20
 
@@ -108,10 +304,8 @@ class TelegramBot:
         self._flood_wait = 0
         # Each `telegram_id` key has a list of `datetime.datetime` as value
         self.last_sending_time = {
-            'absolute': (
-                datetime.datetime.now()
-                - self.absolute_cooldown_timedelta
-            ),
+            'absolute': (datetime.datetime.now()
+                         - self.absolute_cooldown_timedelta),
             0: []
         }
 
@@ -200,10 +394,8 @@ class TelegramBot:
         data = aiohttp.FormData(quote_fields=False)
         for key, value in parameters.items():
             if not (key in exclude or value is None):
-                if (
-                    type(value) in (int, list,)
-                    or (type(value) is dict and 'file' not in value)
-                ):
+                if (type(value) in (int, list,)
+                        or (type(value) is dict and 'file' not in value)):
                     value = json.dumps(value, separators=(',', ':'))
                 data.add_field(key, value)
         return data
@@ -299,12 +491,12 @@ class TelegramBot:
                     ]
                 ) >= self.allowed_messages_per_group_per_minute
             ) or (
-                chat_id in self.last_sending_time
-                and len(self.last_sending_time[chat_id]) > 0
-                and now() < (
-                    self.last_sending_time[chat_id][-1]
-                    + self.per_chat_cooldown_timedelta
-                )
+                    chat_id in self.last_sending_time
+                    and len(self.last_sending_time[chat_id]) > 0
+                    and now() < (
+                            self.last_sending_time[chat_id][-1]
+                            + self.per_chat_cooldown_timedelta
+                    )
             ):
                 await asyncio.sleep(0.5)
             if chat_id not in self.last_sending_time:
@@ -313,10 +505,8 @@ class TelegramBot:
             self.last_sending_time[chat_id] = [
                 sending_datetime
                 for sending_datetime in self.last_sending_time[chat_id]
-                if sending_datetime >= (
-                    now()
-                    - self.longest_cooldown_timedelta
-                )
+                if sending_datetime >= (now()
+                                        - self.longest_cooldown_timedelta)
             ]
         self.last_sending_time['absolute'] = now()
         return
@@ -339,11 +529,9 @@ class TelegramBot:
             await self.prevent_flooding(parameters['chat_id'])
         parameters = self.adapt_parameters(parameters, exclude=exclude)
         try:
-            async with session.post(
-                "https://api.telegram.org/bot"
-                f"{self.token}/{method}",
-                data=parameters
-            ) as response:
+            async with session.post("https://api.telegram.org/bot"
+                                    f"{self.token}/{method}",
+                                    data=parameters) as response:
                 try:
                     response_object = self.check_telegram_api_json(
                         await response.json()  # Telegram returns json objects
@@ -357,7 +545,7 @@ class TelegramBot:
                             ) + 30
                         except Exception as e:
                             logging.error(f"{e}")
-                            flood_wait = 5*60
+                            flood_wait = 5 * 60
                         logging.critical(
                             "Telegram antiflood control triggered!\n"
                             f"Wait {flood_wait} seconds before making another "
@@ -410,10 +598,19 @@ class TelegramBot:
                          ip_address: str = None,
                          max_connections: int = None,
                          allowed_updates: List[str] = None,
-                         drop_pending_updates: bool = None):
+                         drop_pending_updates: bool = None,
+                         secret_token: str = None):
         """Set or remove a webhook. Telegram will post to `url` new updates.
 
         See https://core.telegram.org/bots/api#setwebhook for details.
+
+        Notes:
+            1. You will not be able to receive updates using getUpdates for as
+                long as an outgoing webhook is set up.
+            2. To use a self-signed certificate, you need to upload your public
+                key certificate using certificate parameter.
+                Please upload as InputFile, sending a String will not work.
+            3. Ports currently supported for webhooks: 443, 80, 88, 8443.
         """
         certificate = self.prepare_file_object(certificate)
         result = await self.api_request(
@@ -443,11 +640,14 @@ class TelegramBot:
             'getWebhookInfo',
         )
 
-    async def sendMessage(self, chat_id: Union[int, str], text: str,
+    async def sendMessage(self, chat_id: Union[int, str],
+                          text: str,
+                          message_thread_id: int = None,
                           parse_mode: str = None,
                           entities: List[dict] = None,
                           disable_web_page_preview: bool = None,
                           disable_notification: bool = None,
+                          protect_content: bool = None,
                           reply_to_message_id: int = None,
                           allow_sending_without_reply: bool = None,
                           reply_markup=None):
@@ -463,6 +663,8 @@ class TelegramBot:
     async def forwardMessage(self, chat_id: Union[int, str],
                              from_chat_id: Union[int, str],
                              message_id: int,
+                             message_thread_id: int = None,
+                             protect_content: bool = None,
                              disable_notification: bool = None):
         """Forward a message.
 
@@ -477,6 +679,8 @@ class TelegramBot:
                         caption: str = None,
                         parse_mode: str = None,
                         caption_entities: List[dict] = None,
+                        message_thread_id: int = None,
+                        protect_content: bool = None,
                         disable_notification: bool = None,
                         reply_to_message_id: int = None,
                         allow_sending_without_reply: bool = None,
@@ -501,6 +705,8 @@ class TelegramBot:
                         disable_notification: bool = None,
                         reply_to_message_id: int = None,
                         allow_sending_without_reply: bool = None,
+                        message_thread_id: int = None,
+                        protect_content: bool = None,
                         reply_markup=None):
         """Send an audio file from file_id, HTTP url or file.
 
@@ -520,6 +726,8 @@ class TelegramBot:
                            disable_notification: bool = None,
                            reply_to_message_id: int = None,
                            allow_sending_without_reply: bool = None,
+                           message_thread_id: int = None,
+                           protect_content: bool = None,
                            reply_markup=None):
         """Send a document from file_id, HTTP url or file.
 
@@ -542,6 +750,8 @@ class TelegramBot:
                         disable_notification: bool = None,
                         reply_to_message_id: int = None,
                         allow_sending_without_reply: bool = None,
+                        message_thread_id: int = None,
+                        protect_content: bool = None,
                         reply_markup=None):
         """Send a video from file_id, HTTP url or file.
 
@@ -563,6 +773,8 @@ class TelegramBot:
                             disable_notification: bool = None,
                             reply_to_message_id: int = None,
                             allow_sending_without_reply: bool = None,
+                            message_thread_id: int = None,
+                            protect_content: bool = None,
                             reply_markup=None):
         """Send animation files (GIF or H.264/MPEG-4 AVC video without sound).
 
@@ -581,6 +793,8 @@ class TelegramBot:
                         disable_notification: bool = None,
                         reply_to_message_id: int = None,
                         allow_sending_without_reply: bool = None,
+                        message_thread_id: int = None,
+                        protect_content: bool = None,
                         reply_markup=None):
         """Send an audio file to be displayed as playable voice message.
 
@@ -599,6 +813,8 @@ class TelegramBot:
                             disable_notification: bool = None,
                             reply_to_message_id: int = None,
                             allow_sending_without_reply: bool = None,
+                            message_thread_id: int = None,
+                            protect_content: bool = None,
                             reply_markup=None):
         """Send a rounded square mp4 video message of up to 1 minute long.
 
@@ -612,6 +828,8 @@ class TelegramBot:
     async def sendMediaGroup(self, chat_id: Union[int, str], media: list,
                              disable_notification: bool = None,
                              reply_to_message_id: int = None,
+                             message_thread_id: int = None,
+                             protect_content: bool = None,
                              allow_sending_without_reply: bool = None):
         """Send a group of photos or videos as an album.
 
@@ -633,6 +851,8 @@ class TelegramBot:
                            disable_notification: bool = None,
                            reply_to_message_id: int = None,
                            allow_sending_without_reply: bool = None,
+                           message_thread_id: int = None,
+                           protect_content: bool = None,
                            reply_markup=None):
         """Send a point on the map. May be kept updated for a `live_period`.
 
@@ -709,6 +929,8 @@ class TelegramBot:
                         disable_notification: bool = None,
                         reply_to_message_id: int = None,
                         allow_sending_without_reply: bool = None,
+                        message_thread_id: int = None,
+                        protect_content: bool = None,
                         reply_markup=None):
         """Send information about a venue.
 
@@ -728,6 +950,8 @@ class TelegramBot:
                           disable_notification: bool = None,
                           reply_to_message_id: int = None,
                           allow_sending_without_reply: bool = None,
+                          message_thread_id: int = None,
+                          protect_content: bool = None,
                           reply_markup=None):
         """Send a phone contact.
 
@@ -755,6 +979,8 @@ class TelegramBot:
                        disable_notification: bool = None,
                        allow_sending_without_reply: bool = None,
                        reply_to_message_id: int = None,
+                       message_thread_id: int = None,
+                       protect_content: bool = None,
                        reply_markup=None):
         """Send a native poll in a group, a supergroup or channel.
 
@@ -796,7 +1022,7 @@ class TelegramBot:
 
     async def getUserProfilePhotos(self, user_id,
                                    offset=None,
-                                   limit=None,):
+                                   limit=None):
         """Get a list of profile pictures for a user.
 
         See https://core.telegram.org/bots/api#getuserprofilephotos
@@ -889,7 +1115,10 @@ class TelegramBot:
                                 can_invite_users: bool = None,
                                 can_restrict_members: bool = None,
                                 can_pin_messages: bool = None,
-                                can_promote_members: bool = None):
+                                can_promote_members: bool = None,
+                                can_manage_topics: bool = None,
+                                can_manage_chat: bool = None,
+                                can_manage_video_chats: bool = None):
         """Promote or demote a user in a supergroup or a channel.
 
         The bot must be an administrator in the chat for this to work and must
@@ -1230,6 +1459,8 @@ class TelegramBot:
                           disable_notification: bool = None,
                           reply_to_message_id: int = None,
                           allow_sending_without_reply: bool = None,
+                          message_thread_id: int = None,
+                          protect_content: bool = None,
                           reply_markup=None):
         """Send `.webp` stickers.
 
@@ -1279,17 +1510,27 @@ class TelegramBot:
                                   emojis: str,
                                   png_sticker: Union[str, dict, IO] = None,
                                   tgs_sticker: Union[str, dict, IO] = None,
-                                  contains_masks: bool = None,
-                                  mask_position: dict = None):
+                                  webm_sticker: Union[str, dict, IO] = None,
+                                  sticker_type: str = 'regular',
+                                  mask_position: dict = None,
+                                  **kwargs):
         """Create new sticker set owned by a user.
 
         The bot will be able to edit the created sticker set.
         Returns True on success.
         See https://core.telegram.org/bots/api#createnewstickerset for details.
         """
+        if 'contains_masks' in kwargs:
+            logging.error("Parameter `contains_masks` of method "
+                          "`createNewStickerSet` has been deprecated. "
+                          "Use `sticker_type = 'mask'` instead.")
+            sticker_type = 'mask' if kwargs['contains_masks'] else 'regular'
+        if sticker_type not in ('regular', 'mask'):
+            raise TypeError
         png_sticker = self.prepare_file_object(png_sticker)
         tgs_sticker = self.prepare_file_object(tgs_sticker)
-        if png_sticker is None and tgs_sticker is None:
+        webm_sticker = self.prepare_file_object(webm_sticker)
+        if png_sticker is None and tgs_sticker is None and webm_sticker is None:
             logging.error("Invalid sticker provided!")
             return
         result = await self.api_request(
@@ -1300,12 +1541,15 @@ class TelegramBot:
             png_sticker['file'].close()
         if type(tgs_sticker) is dict:  # Close tgs_sticker file, if it was open
             tgs_sticker['file'].close()
+        if type(webm_sticker) is dict:  # Close webm_sticker file, if it was open
+            webm_sticker['file'].close()
         return result
 
     async def addStickerToSet(self, user_id: int, name: str,
                               emojis: str,
                               png_sticker: Union[str, dict, IO] = None,
                               tgs_sticker: Union[str, dict, IO] = None,
+                              webm_sticker: Union[str, dict, IO] = None,
                               mask_position: dict = None):
         """Add a new sticker to a set created by the bot.
 
@@ -1314,7 +1558,8 @@ class TelegramBot:
         """
         png_sticker = self.prepare_file_object(png_sticker)
         tgs_sticker = self.prepare_file_object(tgs_sticker)
-        if png_sticker is None and tgs_sticker is None:
+        webm_sticker = self.prepare_file_object(webm_sticker)
+        if png_sticker is None and tgs_sticker is None and webm_sticker is None:
             logging.error("Invalid sticker provided!")
             return
         result = await self.api_request(
@@ -1325,6 +1570,8 @@ class TelegramBot:
             png_sticker['file'].close()
         if type(tgs_sticker) is dict:  # Close tgs_sticker file, if it was open
             tgs_sticker['file'].close()
+        if type(webm_sticker) is dict:  # Close webm_sticker file, if it was open
+            webm_sticker['file'].close()
         return result
 
     async def setStickerPositionInSet(self, sticker, position):
@@ -1371,7 +1618,12 @@ class TelegramBot:
 
     async def sendInvoice(self, chat_id: int, title: str, description: str,
                           payload: str, provider_token: str,
-                          start_parameter: str, currency: str, prices: List[dict],
+                          start_parameter: str,
+                          currency: str, prices: List[dict],
+                          message_thread_id: int = None,
+                          protect_content: bool = None,
+                          max_tip_amount: int = None,
+                          suggested_tip_amounts: List[int] = None,
                           provider_data: str = None,
                           photo_url: str = None,
                           photo_size: int = None,
@@ -1456,6 +1708,8 @@ class TelegramBot:
         )
 
     async def sendGame(self, chat_id: Union[int, str], game_short_name,
+                       message_thread_id: int = None,
+                       protect_content: bool = None,
                        disable_notification: bool = None,
                        reply_to_message_id: int = None,
                        reply_markup=None,
@@ -1518,6 +1772,8 @@ class TelegramBot:
                        disable_notification: bool = None,
                        reply_to_message_id: int = None,
                        allow_sending_without_reply: bool = None,
+                       message_thread_id: int = None,
+                       protect_content: bool = None,
                        reply_markup=None):
         """Send a dice.
 
@@ -1568,7 +1824,10 @@ class TelegramBot:
             parameters=locals()
         )
 
-    async def setMyCommands(self, commands: List[Union[Command, dict]]):
+    async def setMyCommands(self,
+                            commands: List[Union[Command, dict]],
+                            scope: 'BotCommandScope' = None,
+                            language_code: str = None):
         """Change the list of the bot's commands.
 
         Use this method to change the list of the bot's commands.
@@ -1580,12 +1839,15 @@ class TelegramBot:
             parameters=locals()
         )
 
-    async def getMyCommands(self):
+    async def getMyCommands(self,
+                            scope: 'BotCommandScope' = None,
+                            language_code: str = None):
         """Get the current list of the bot's commands.
 
-        Use this method to get the current list of the bot's commands.
-        Requires no parameters.
-        Returns Array of BotCommand on success.
+        Use this method to get the current list of the bot's commands for
+            the given scope and user language.
+        Returns an Array of BotCommand objects.
+        If commands aren't set, an empty list is returned.
         See https://core.telegram.org/bots/api#getmycommands for details.
         """
         return await self.api_request(
@@ -1647,6 +1909,8 @@ class TelegramBot:
     async def copyMessage(self, chat_id: Union[int, str],
                           from_chat_id: Union[int, str],
                           message_id: int,
+                          message_thread_id: int = None,
+                          protect_content: bool = None,
                           caption: str = None,
                           parse_mode: str = None,
                           caption_entities: list = None,
@@ -1680,3 +1944,344 @@ class TelegramBot:
             'unpinAllChatMessages',
             parameters=locals()
         )
+
+    async def banChatMember(self, chat_id: Union[int, str],
+                            user_id: int, until_date: int,
+                            revoke_messages: bool):
+        """Use this method to ban a user in a group, a supergroup or a channel.
+
+        In the case of supergroups and channels, the user will not be able to
+            return to the chat on their own using invite links, etc., unless
+            unbanned first.
+        The bot must be an administrator in the chat for this to work and must
+            have the appropriate administrator rights.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#banchatmember for details.
+        """
+        return await self.api_request(
+            'banChatMember',
+            parameters=locals()
+        )
+
+    async def banChatSenderChat(self, chat_id: Union[int, str], sender_chat_id: int):
+        """Use this method to ban a channel chat in a supergroup or a channel.
+
+        Until the chat is unbanned, the owner of the banned chat won't be able
+            to send messages on behalf of any of their channels.
+        The bot must be an administrator in the supergroup or channel for this
+            to work and must have the appropriate administrator rights.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#banchatsenderchat for details.
+        """
+        return await self.api_request(
+            'banChatSenderChat',
+            parameters=locals()
+        )
+
+    async def unbanChatSenderChat(self, chat_id: Union[int, str], sender_chat_id: int):
+        """Use this method to unban a previously banned channel chat in a supergroup or channel.
+
+        The bot must be an administrator for this to work and must have the
+            appropriate administrator rights.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#unbanchatsenderchat for details.
+        """
+        return await self.api_request(
+            'unbanChatSenderChat',
+            parameters=locals()
+        )
+
+    async def createChatInviteLink(self, chat_id: Union[int, str], name: str,
+                                   expire_date: int, member_limit: int,
+                                   creates_join_request: bool):
+        """Use this method to create an additional invite link for a chat.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the appropriate administrator rights.
+        The link can be revoked using the method revokeChatInviteLink.
+        Returns the new invite link as ChatInviteLink object.
+        See https://core.telegram.org/bots/api#createchatinvitelink for details.
+        """
+        return await self.api_request(
+            'createChatInviteLink',
+            parameters=locals()
+        )
+
+    async def editChatInviteLink(self, chat_id: Union[int, str],
+                                 invite_link: str, name: str, expire_date: int,
+                                 member_limit: int, creates_join_request: bool):
+        """Use this method to edit a non-primary invite link created by the bot.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the appropriate administrator rights.
+        Returns the edited invite link as a ChatInviteLink object.
+        See https://core.telegram.org/bots/api#editchatinvitelink for details.
+        """
+        return await self.api_request(
+            'editChatInviteLink',
+            parameters=locals()
+        )
+
+    async def revokeChatInviteLink(self, chat_id: Union[int, str], invite_link: str):
+        """Use this method to revoke an invite link created by the bot.
+
+        If the primary link is revoked, a new link is automatically generated.
+        The bot must be an administrator in the chat for this to work and must
+            have the appropriate administrator rights.
+        Returns the revoked invite link as ChatInviteLink object.
+        See https://core.telegram.org/bots/api#revokechatinvitelink for details.
+        """
+        return await self.api_request(
+            'revokeChatInviteLink',
+            parameters=locals()
+        )
+
+    async def approveChatJoinRequest(self, chat_id: Union[int, str], user_id: int):
+        """Use this method to approve a chat join request.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the can_invite_users administrator right.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#approvechatjoinrequest for details.
+        """
+        return await self.api_request(
+            'approveChatJoinRequest',
+            parameters=locals()
+        )
+
+    async def declineChatJoinRequest(self, chat_id: Union[int, str], user_id: int):
+        """Use this method to decline a chat join request.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the can_invite_users administrator right.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#declinechatjoinrequest for details.
+        """
+        return await self.api_request(
+            'declineChatJoinRequest',
+            parameters=locals()
+        )
+
+    async def getChatMemberCount(self, chat_id: Union[int, str]):
+        """Use this method to get the number of members in a chat. Returns Int on success.
+        See https://core.telegram.org/bots/api#getchatmembercount for details.
+        """
+        return await self.api_request(
+            'getChatMemberCount',
+            parameters=locals()
+        )
+
+    async def getForumTopicIconStickers(self):
+        """Use this method to get custom emoji stickers.
+
+        They can be used as a forum topic icon by any user.
+        Requires no parameters. Returns an Array of Sticker objects.
+        See https://core.telegram.org/bots/api#getforumtopiciconstickers for details.
+        """
+        return await self.api_request(
+            'getForumTopicIconStickers',
+            parameters=locals()
+        )
+
+    async def createForumTopic(self, chat_id: Union[int, str], name: str,
+                               icon_color: int, icon_custom_emoji_id: str):
+        """Use this method to create a topic in a forum supergroup chat.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the can_manage_topics administrator rights.
+        Returns information about the created topic as a ForumTopic object.
+        See https://core.telegram.org/bots/api#createforumtopic for details.
+        """
+        return await self.api_request(
+            'createForumTopic',
+            parameters=locals()
+        )
+
+    async def editForumTopic(self, chat_id: Union[int, str],
+                             message_thread_id: int, name: str,
+                             icon_custom_emoji_id: str):
+        """Use this method to edit name and icon of a topic in a forum supergroup chat.
+
+        The bot must be an administrator in the chat for this to work and must
+            have can_manage_topics administrator rights, unless it is the
+            creator of the topic.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#editforumtopic for details.
+        """
+        return await self.api_request(
+            'editForumTopic',
+            parameters=locals()
+        )
+
+    async def closeForumTopic(self, chat_id: Union[int, str],
+                              message_thread_id: int):
+        """Use this method to close an open topic in a forum supergroup chat.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the can_manage_topics administrator rights, unless it is the
+            creator of the topic.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#closeforumtopic for details.
+        """
+        return await self.api_request(
+            'closeForumTopic',
+            parameters=locals()
+        )
+
+    async def reopenForumTopic(self, chat_id: Union[int, str],
+                               message_thread_id: int):
+        """Use this method to reopen a closed topic in a forum supergroup chat.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the can_manage_topics administrator rights, unless it is the
+            creator of the topic.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#reopenforumtopic for details.
+        """
+        return await self.api_request(
+            'reopenForumTopic',
+            parameters=locals()
+        )
+
+    async def deleteForumTopic(self, chat_id: Union[int, str],
+                               message_thread_id: int):
+        """Use this method to delete a forum topic.
+
+        This method deletes a forum topic along with all its messages in a
+            forum supergroup chat.
+        The bot must be an administrator in the chat for this to work and must
+            have the can_delete_messages administrator rights.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#deleteforumtopic for details.
+        """
+        return await self.api_request(
+            'deleteForumTopic',
+            parameters=locals()
+        )
+
+    async def unpinAllForumTopicMessages(self, chat_id: Union[int, str],
+                                         message_thread_id: int):
+        """Use this method to clear the list of pinned messages in a forum topic.
+
+        The bot must be an administrator in the chat for this to work and must
+            have the can_pin_messages administrator right in the supergroup.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#unpinallforumtopicmessages for details.
+        """
+        return await self.api_request(
+            'unpinAllForumTopicMessages',
+            parameters=locals()
+        )
+
+    async def deleteMyCommands(self, scope: 'BotCommandScope', language_code: str):
+        """Use this method to delete the list of the bot's commands for the given scope and user language.
+
+        After deletion, higher level commands will be shown to affected users.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#deletemycommands for details.
+        """
+        return await self.api_request(
+            'deleteMyCommands',
+            parameters=locals()
+        )
+
+    async def setChatMenuButton(self, chat_id: int, menu_button: 'MenuButton'):
+        """Use this method to change the bot's menu button in a private chat, or the default menu button.
+
+        Returns True on success.
+        See https://core.telegram.org/bots/api#setchatmenubutton for details.
+        """
+        return await self.api_request(
+            'setChatMenuButton',
+            parameters=locals()
+        )
+
+    async def getChatMenuButton(self, chat_id: int):
+        """Use this method to get the current value of the bot's menu button.
+
+        Use this method to get the current value of the bot's menu button in a
+            private chat, or the default menu button.
+        Returns MenuButton on success.
+        See https://core.telegram.org/bots/api#getchatmenubutton for details.
+        """
+        return await self.api_request(
+            'getChatMenuButton',
+            parameters=locals()
+        )
+
+    async def setMyDefaultAdministratorRights(self,
+                                              rights: 'ChatAdministratorRights',
+                                              for_channels: bool):
+        """Use this method to change the default administrator rights.
+
+        Use this method to change the default administrator rights requested by
+            the bot when it's added as an administrator to groups or channels.
+        These rights will be suggested to users, but they are free to modify
+            the list before adding the bot.
+        Returns True on success.
+        See https://core.telegram.org/bots/api#setmydefaultadministratorrights for details.
+        """
+        return await self.api_request(
+            'setMyDefaultAdministratorRights',
+            parameters=locals()
+        )
+
+    async def getMyDefaultAdministratorRights(self, for_channels: bool):
+        """Use this method to get the current default administrator rights of
+            the bot.
+        Returns ChatAdministratorRights on success.
+        See https://core.telegram.org/bots/api#getmydefaultadministratorrights for details.
+        """
+        return await self.api_request(
+            'getMyDefaultAdministratorRights',
+            parameters=locals()
+        )
+
+    async def getCustomEmojiStickers(self, custom_emoji_ids: List[str]):
+        """Use this method to get information about custom emoji stickers by their identifiers.
+
+        Returns an Array of Sticker objects.
+        See https://core.telegram.org/bots/api#getcustomemojistickers for details.
+        """
+        return await self.api_request(
+            'getCustomEmojiStickers',
+            parameters=locals()
+        )
+
+    async def answerWebAppQuery(self, web_app_query_id: str,
+                                result: 'InlineQueryResult'):
+        """Use this method to set the result of an interaction with a Web App.
+
+        Use this method to set the result of an interaction with a Web App and
+            send a corresponding message on behalf of the user to the chat from
+            which the query originated.
+        On success, a SentWebAppMessage object is returned.
+        See https://core.telegram.org/bots/api#answerwebappquery for details.
+        """
+        return await self.api_request(
+            'answerWebAppQuery',
+            parameters=locals()
+        )
+
+    async def createInvoiceLink(self, title: str, description: str,
+                                payload: str, provider_token: str,
+                                currency: str, prices: List['LabeledPrice'],
+                                max_tip_amount: int,
+                                suggested_tip_amounts: List[int],
+                                provider_data: str, photo_url: str,
+                                photo_size: int, photo_width: int,
+                                photo_height: int, need_name: bool,
+                                need_phone_number: bool, need_email: bool,
+                                need_shipping_address: bool,
+                                send_phone_number_to_provider: bool,
+                                send_email_to_provider: bool,
+                                is_flexible: bool):
+        """Use this method to create a link for an invoice.
+
+        Returns the created invoice link as String on success.
+        See https://core.telegram.org/bots/api#createinvoicelink for details.
+        """
+        return await self.api_request(
+            'createInvoiceLink',
+            parameters=locals()
+        )

+ 3 - 3
davtelepot/api_helper.py

@@ -170,7 +170,7 @@ async def print_api_methods(filename=None,
                 if parameter != 'self'
             )
             new_parameters = parameters - implemented_parameters
-            deprecated_parameters = implemented_parameters - parameters
+            deprecated_parameters = implemented_parameters - parameters - {'kwargs'}
             if new_parameters or deprecated_parameters:
                 edited_methods.append(
                     dict(
@@ -193,9 +193,9 @@ async def print_api_methods(filename=None,
                 f"{', '.join(['self'] + method.parameters_with_types)}"
                 f"):\n"
                 f"        \"\"\""
-                f"    {method.description.replace(new_line, new_line + ' ' * 4)}\n"
+                f"{method.description.replace(new_line, new_line + ' ' * 4)}\n"
                 f"        See https://core.telegram.org/bots/api#"
-                f"    {method.name.lower()} for details.\n"
+                f"{method.name.lower()} for details.\n"
                 f"        \"\"\"\n"
                 f"        return await self.api_request(\n"
                 f"            '{method.name}',\n"

+ 4 - 0
davtelepot/bot.py

@@ -1285,6 +1285,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
                            text: str = None,
                            entities: List[dict] = None,
                            parse_mode: str = 'HTML',
+                           message_thread_id: int = None,
+                           protect_content: bool = None,
                            disable_web_page_preview: bool = None,
                            disable_notification: bool = None,
                            reply_to_message_id: int = None,
@@ -1364,6 +1366,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
                 text=text_chunk,
                 parse_mode=parse_mode,
                 entities=entities,
+                message_thread_id=message_thread_id,
+                protect_content=protect_content,
                 disable_web_page_preview=disable_web_page_preview,
                 disable_notification=disable_notification,
                 reply_to_message_id=reply_to_message_id,