diff --git a/.github/workflows/setup_python.yml b/.github/workflows/setup_python.yml
index 5518ff2f3..670251511 100644
--- a/.github/workflows/setup_python.yml
+++ b/.github/workflows/setup_python.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.8', 'pypy-3.9', 'pypy-3.10']
+ python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.9', 'pypy-3.10']
name: ${{ matrix.python-version }} and tests
steps:
- uses: actions/checkout@v2
diff --git a/README.md b/README.md
index 20b062e70..98f8c389a 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
A simple, but extensible Python implementation for the Telegram Bot API.
Both synchronous and asynchronous.
-## Supported Bot API version: 7.2!
+##
Supported Bot API version: 7.7!
@@ -262,7 +262,7 @@ Handle shipping queries
`@bot.shipping_query_handler() # <- passes a ShippingQuery type object to your function`
#### Pre Checkout Query Handler
-Handle pre checkoupt queries
+Handle pre checkout queries
`@bot.pre_checkout_query_handler() # <- passes a PreCheckoutQuery type object to your function`
#### Poll Handler
@@ -303,7 +303,7 @@ def query_text(inline_query):
#### Chosen Inline handler
-Use chosen_inline_handler to get chosen_inline_result in telebot. Don't forgot add the /setinlinefeedback
+Use chosen_inline_handler to get chosen_inline_result in telebot. Don't forget to add the /setinlinefeedback
command for @Botfather.
More information : [collecting-feedback](https://core.telegram.org/bots/inline#collecting-feedback)
@@ -890,5 +890,6 @@ Here are some examples of template:
* [Best Instagram Downloader Bot](https://t.me/Best_Instagram_Downloader_Bot) ([source](https://github.com/arashnm80/best-instagram-downloader)) by [Arashnm80](https://github.com/arashnm80). Free and open source telegram bot to download posts and reels from Instagram.
* [4K YouTube Downloader](https://github.com/hansanaD/TelegramYTDLBot/) - Youtube Downloader with upto 4K resolution support.
* [DrinkGenius-Bot](https://t.me/cocktail_recommendation_bot) ([source](https://github.com/Povladarchik/DrinkGenius-Bot)) by [Povladarchik](https://github.com/Povladarchik). Your personal assistant in the world of cocktails.
+* [Pytgpt-Bot](https://t.me/pytgpt_bot) ([source](https://github.com/Simatwa/pytgpt-bot)) by [Smartwa](https://github.com/Simatwa). AI powered bot for chatting, text-to-image and text-to-speech conversions.
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**
diff --git a/docs/source/conf.py b/docs/source/conf.py
index aa49bceb2..cfa926801 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -22,7 +22,7 @@
copyright = f'2022-{datetime.now().year}, {author}'
# The full version, including alpha/beta/rc tags
-release = '4.17.0'
+release = '4.21.0'
# -- General configuration ---------------------------------------------------
diff --git a/examples/asynchronous_telebot/echo_bot.py b/examples/asynchronous_telebot/echo_bot.py
index cd2353755..aed26675e 100644
--- a/examples/asynchronous_telebot/echo_bot.py
+++ b/examples/asynchronous_telebot/echo_bot.py
@@ -2,19 +2,18 @@
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
+import asyncio
from telebot.async_telebot import AsyncTeleBot
-bot = AsyncTeleBot('TOKEN')
+bot = AsyncTeleBot('TOKEN')
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
async def send_welcome(message):
- await bot.reply_to(message, """\
-Hi there, I am EchoBot.
-I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
-""")
+ text = 'Hi, I am EchoBot.\nJust write me something and I will repeat it!'
+ await bot.reply_to(message, text)
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
@@ -23,5 +22,4 @@ async def echo_message(message):
await bot.reply_to(message, message.text)
-import asyncio
asyncio.run(bot.polling())
diff --git a/examples/serverless/flask_google_cloud_bot/.gcloudignore b/examples/serverless/flask_google_cloud_bot/.gcloudignore
new file mode 100644
index 000000000..ae412d6a0
--- /dev/null
+++ b/examples/serverless/flask_google_cloud_bot/.gcloudignore
@@ -0,0 +1 @@
+env/
\ No newline at end of file
diff --git a/examples/serverless/flask_google_cloud_bot/app.yaml b/examples/serverless/flask_google_cloud_bot/app.yaml
new file mode 100644
index 000000000..59ad3ad6f
--- /dev/null
+++ b/examples/serverless/flask_google_cloud_bot/app.yaml
@@ -0,0 +1,4 @@
+runtime: python38
+
+env_variables:
+ BUCKET_NAME: "your-google-application"
\ No newline at end of file
diff --git a/examples/serverless/flask_google_cloud_bot/main.py b/examples/serverless/flask_google_cloud_bot/main.py
new file mode 100644
index 000000000..67f479ff6
--- /dev/null
+++ b/examples/serverless/flask_google_cloud_bot/main.py
@@ -0,0 +1,65 @@
+'''
+Simple bot for Google cloud deployment.
+
+Docs:
+https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service
+
+1. Receive your bot's token from https://t.me/BotFather
+
+2. Create a Google Cloud project. https://cloud.google.com/resource-manager/docs/creating-managing-projects
+
+3. Install the Google Cloud CLI. https://cloud.google.com/sdk/docs/install
+
+4. Move to telegram_google_cloud_bot folder
+
+cd telegram_google_cloud_bot/
+
+5. Initialize the gcloud CLI:
+
+gcloud init
+
+6. To set the default project for your Cloud Run service:
+
+gcloud config set project PROJECT_ID
+
+7. Deploy:
+
+gcloud run deploy
+'''
+
+import os
+
+from flask import Flask, request
+
+import telebot
+
+TOKEN = 'token_from_botfather'
+
+bot = telebot.TeleBot(TOKEN)
+
+app = Flask(__name__)
+
+
+@bot.message_handler(commands=['start'])
+def start(message):
+ bot.reply_to(message, 'Hello, ' + message.from_user.first_name)
+
+
+@bot.message_handler(func=lambda message: True, content_types=['text'])
+def echo_message(message):
+ bot.reply_to(message, message.text)
+
+
+@app.route('/' + TOKEN, methods=['POST'])
+def getMessage():
+ json_string = request.get_data().decode('utf-8')
+ update = telebot.types.Update.de_json(json_string)
+ bot.process_new_updates([update])
+ return '!', 200
+
+
+@app.route('/')
+def webhook():
+ bot.remove_webhook()
+ bot.set_webhook(url='https://mydomain.com/' + TOKEN)
+ return '!', 200
\ No newline at end of file
diff --git a/examples/serverless/flask_google_cloud_bot/requirements.txt b/examples/serverless/flask_google_cloud_bot/requirements.txt
new file mode 100644
index 000000000..ed0491b0a
--- /dev/null
+++ b/examples/serverless/flask_google_cloud_bot/requirements.txt
@@ -0,0 +1,4 @@
+pyTelegramBotAPI==4.11.0
+Flask==3.0.0
+gunicorn==22.0.0
+Werkzeug==3.0.3
diff --git a/pyproject.toml b/pyproject.toml
index fde7a8685..0095c3f21 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "pyTelegramBotAPI"
-version = "4.17.0"
+version = "4.21.0"
description = "Python Telegram bot api."
authors = [{name = "eternnoir", email = "eternnoir@gmail.com"}]
license = {text = "GPL2"}
diff --git a/requirements.txt b/requirements.txt
index 32cb38aa1..09014549b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
pytest
-requests==2.31.0
+requests==2.32.0
wheel==0.38.1
aiohttp==3.9.4
diff --git a/telebot/__init__.py b/telebot/__init__.py
index 3da8952be..630edb29e 100644
--- a/telebot/__init__.py
+++ b/telebot/__init__.py
@@ -189,6 +189,7 @@ def __init__(
# logs-related
if colorful_logs:
try:
+ # noinspection PyPackageRequirements
import coloredlogs
coloredlogs.install(logger=logger, level=logger.level)
except ImportError:
@@ -1012,6 +1013,7 @@ def __notify_update(self, new_messages):
def _setup_change_detector(self, path_to_watch: str):
try:
+ # noinspection PyPackageRequirements
from watchdog.observers import Observer
from telebot.ext.reloader import EventHandler
except ImportError:
@@ -1491,7 +1493,7 @@ def get_user_profile_photos(self, user_id: int, offset: Optional[int]=None,
)
- def get_chat(self, chat_id: Union[int, str]) -> types.Chat:
+ def get_chat(self, chat_id: Union[int, str]) -> types.ChatFullInfo:
"""
Use this method to get up to date information about the chat (current name of the user for one-on-one
conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
@@ -1502,9 +1504,9 @@ def get_chat(self, chat_id: Union[int, str]) -> types.Chat:
:type chat_id: :obj:`int` or :obj:`str`
:return: Chat information
- :rtype: :class:`telebot.types.Chat`
+ :rtype: :class:`telebot.types.ChatFullInfo`
"""
- return types.Chat.de_json(
+ return types.ChatFullInfo.de_json(
apihelper.get_chat(self.token, chat_id)
)
@@ -1647,7 +1649,8 @@ def send_message(
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
link_preview_options : Optional[types.LinkPreviewOptions]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send text messages.
@@ -1703,6 +1706,9 @@ def send_message(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -1750,7 +1756,8 @@ def send_message(
self.token, chat_id, text,
reply_markup=reply_markup, parse_mode=parse_mode, disable_notification=disable_notification,
timeout=timeout, entities=entities, protect_content=protect_content, message_thread_id=message_thread_id,
- reply_parameters=reply_parameters, link_preview_options=link_preview_options, business_connection_id=business_connection_id))
+ reply_parameters=reply_parameters, link_preview_options=link_preview_options, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id))
def forward_message(
@@ -1811,9 +1818,13 @@ def copy_message(
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
message_thread_id: Optional[int]=None,
- reply_parameters: Optional[types.ReplyParameters]=None) -> types.MessageID:
+ reply_parameters: Optional[types.ReplyParameters]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.MessageID:
"""
Use this method to copy messages of any kind.
+ Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied.
+ A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method
+ forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success.
Telegram documentation: https://core.telegram.org/bots/api#copymessage
@@ -1822,6 +1833,7 @@ def copy_message(
:param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername)
:type from_chat_id: :obj:`int` or :obj:`str`
+
:param message_id: Message identifier in the chat specified in from_chat_id
:type message_id: :obj:`int`
@@ -1859,10 +1871,14 @@ def copy_message(
:param reply_parameters: Additional parameters for replies to messages
:type reply_parameters: :class:`telebot.types.ReplyParameters`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
:return: On success, the MessageId of the sent message is returned.
:rtype: :class:`telebot.types.MessageID`
"""
+
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
protect_content = self.protect_content if (protect_content is None) else protect_content
@@ -1889,7 +1905,8 @@ def copy_message(
apihelper.copy_message(self.token, chat_id, from_chat_id, message_id, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities, disable_notification=disable_notification,
reply_markup=reply_markup, timeout=timeout, protect_content=protect_content,
- message_thread_id=message_thread_id, reply_parameters=reply_parameters))
+ message_thread_id=message_thread_id, reply_parameters=reply_parameters,
+ show_caption_above_media=show_caption_above_media))
def delete_message(self, chat_id: Union[int, str], message_id: int,
@@ -1936,13 +1953,13 @@ def delete_messages(self, chat_id: Union[int, str], message_ids: List[int]):
:type message_ids: :obj:`list` of :obj:`int`
:return: Returns True on success.
-
"""
return apihelper.delete_messages(self.token, chat_id, message_ids)
- def forward_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, int], message_ids: List[int], disable_notification: Optional[bool]=None,
- message_thread_id: Optional[int]=None, protect_content: Optional[bool]=None) -> List[types.MessageID]:
+ def forward_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, int], message_ids: List[int],
+ disable_notification: Optional[bool]=None, message_thread_id: Optional[int]=None,
+ protect_content: Optional[bool]=None) -> List[types.MessageID]:
"""
Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped.
Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages.
@@ -1985,47 +2002,47 @@ def forward_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, in
def copy_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, int], message_ids: List[int],
disable_notification: Optional[bool] = None, message_thread_id: Optional[int] = None,
protect_content: Optional[bool] = None, remove_caption: Optional[bool] = None) -> List[types.MessageID]:
- """
- Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped.
- Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied.
- A quiz poll can be copied only if the value of the field correct_option_id is known to the bot.
- The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message.
- Album grouping is kept for copied messages. On success, an array of MessageId of the sent messages is returned.
+ """
+ Use this method to copy messages of any kind.
+ If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages,
+ and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous
+ to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array
+ of MessageId of the sent messages is returned.
- Telegram documentation: https://core.telegram.org/bots/api#copymessages
+ Telegram documentation: https://core.telegram.org/bots/api#copymessages
- :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
- :type chat_id: :obj:`int` or :obj:`str`
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
+ :type chat_id: :obj:`int` or :obj:`str`
- :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername)
- :type from_chat_id: :obj:`int` or :obj:`str`
+ :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername)
+ :type from_chat_id: :obj:`int` or :obj:`str`
- :param message_ids: Message identifiers in the chat specified in from_chat_id
- :type message_ids: :obj:`list` of :obj:`int`
+ :param message_ids: Message identifiers in the chat specified in from_chat_id
+ :type message_ids: :obj:`list` of :obj:`int`
- :param disable_notification: Sends the message silently. Users will receive a notification with no sound
- :type disable_notification: :obj:`bool`
+ :param disable_notification: Sends the message silently. Users will receive a notification with no sound
+ :type disable_notification: :obj:`bool`
- :param message_thread_id: Identifier of a message thread, in which the messages will be sent
- :type message_thread_id: :obj:`int`
+ :param message_thread_id: Identifier of a message thread, in which the messages will be sent
+ :type message_thread_id: :obj:`int`
- :param protect_content: Protects the contents of the forwarded message from forwarding and saving
- :type protect_content: :obj:`bool`
+ :param protect_content: Protects the contents of the forwarded message from forwarding and saving
+ :type protect_content: :obj:`bool`
- :param remove_caption: Pass True to copy the messages without their captions
- :type remove_caption: :obj:`bool`
+ :param remove_caption: Pass True to copy the messages without their captions
+ :type remove_caption: :obj:`bool`
- :return: On success, an array of MessageId of the sent messages is returned.
- :rtype: :obj:`list` of :class:`telebot.types.MessageID`
- """
- disable_notification = self.disable_notification if disable_notification is None else disable_notification
- protect_content = self.protect_content if protect_content is None else protect_content
+ :return: On success, an array of MessageId of the sent messages is returned.
+ :rtype: :obj:`list` of :class:`telebot.types.MessageID`
+ """
+ disable_notification = self.disable_notification if disable_notification is None else disable_notification
+ protect_content = self.protect_content if protect_content is None else protect_content
- result = apihelper.copy_messages(
- self.token, chat_id, from_chat_id, message_ids, disable_notification=disable_notification,
- message_thread_id=message_thread_id, protect_content=protect_content, remove_caption=remove_caption)
- return [types.MessageID.de_json(message_id) for message_id in result]
+ result = apihelper.copy_messages(
+ self.token, chat_id, from_chat_id, message_ids, disable_notification=disable_notification,
+ message_thread_id=message_thread_id, protect_content=protect_content, remove_caption=remove_caption)
+ return [types.MessageID.de_json(message_id) for message_id in result]
def send_dice(
@@ -2038,7 +2055,8 @@ def send_dice(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send an animated emoji that will display a random value. On success, the sent Message is returned.
@@ -2080,6 +2098,9 @@ def send_dice(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -2108,7 +2129,8 @@ def send_dice(
apihelper.send_dice(
self.token, chat_id, emoji=emoji, disable_notification=disable_notification,
reply_markup=reply_markup, timeout=timeout, protect_content=protect_content,
- message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id))
+ message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id))
@@ -2125,7 +2147,9 @@ def send_photo(
message_thread_id: Optional[int]=None,
has_spoiler: Optional[bool]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.Message:
"""
Use this method to send photos. On success, the sent Message is returned.
@@ -2179,6 +2203,12 @@ def send_photo(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
@@ -2210,8 +2240,9 @@ def send_photo(
self.token, chat_id, photo, caption=caption, reply_markup=reply_markup,
parse_mode=parse_mode, disable_notification=disable_notification, timeout=timeout,
caption_entities=caption_entities, protect_content=protect_content,
- message_thread_id=message_thread_id, has_spoiler=has_spoiler, reply_parameters=reply_parameters, business_connection_id=business_connection_id))
-
+ message_thread_id=message_thread_id, has_spoiler=has_spoiler, reply_parameters=reply_parameters,
+ business_connection_id=business_connection_id, message_effect_id=message_effect_id,
+ show_caption_above_media=show_caption_above_media))
def send_audio(
@@ -2230,7 +2261,8 @@ def send_audio(
message_thread_id: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send audio files, if you want Telegram clients to display them in the music player.
Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size,
@@ -2303,6 +2335,9 @@ def send_audio(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -2337,8 +2372,8 @@ def send_audio(
self.token, chat_id, audio, caption=caption, duration=duration, performer=performer, title=title,
reply_markup=reply_markup, parse_mode=parse_mode, disable_notification=disable_notification,
timeout=timeout, thumbnail=thumbnail, caption_entities=caption_entities, protect_content=protect_content,
- message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
- )
+ message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id))
def send_voice(
@@ -2354,11 +2389,10 @@ def send_voice(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
- Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message.
- For this to work, your audio must be in an .OGG file encoded with OPUS (other formats may be sent as Audio or Document).
- On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .OGG file encoded with OPUS, or in .MP3 format, or in .M4A format (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
Telegram documentation: https://core.telegram.org/bots/api#sendvoice
@@ -2410,6 +2444,9 @@ def send_voice(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@@ -2439,7 +2476,8 @@ def send_voice(
self.token, chat_id, voice, caption=caption, duration=duration, reply_markup=reply_markup,
parse_mode=parse_mode, disable_notification=disable_notification, timeout=timeout,
caption_entities=caption_entities, protect_content=protect_content,
- message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id)
)
@@ -2460,7 +2498,8 @@ def send_document(
protect_content: Optional[bool]=None, message_thread_id: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send general files.
@@ -2526,6 +2565,9 @@ def send_document(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -2559,13 +2601,18 @@ def send_document(
logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.')
thumbnail = thumb
+ if isinstance(document, types.InputFile) and visible_file_name:
+ # inputfile name ignored, warn
+ logger.warning('Cannot use both InputFile and visible_file_name. InputFile name will be ignored.')
+
return types.Message.de_json(
apihelper.send_data(
self.token, chat_id, document, 'document',
reply_markup=reply_markup, parse_mode=parse_mode, disable_notification=disable_notification,
timeout=timeout, caption=caption, thumbnail=thumbnail, caption_entities=caption_entities,
disable_content_type_detection=disable_content_type_detection, visible_file_name=visible_file_name,
- protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters,
+ business_connection_id=business_connection_id, message_effect_id=message_effect_id)
)
@@ -2582,7 +2629,8 @@ def send_sticker(
message_thread_id: Optional[int]=None,
emoji: Optional[str]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers.
On success, the sent Message is returned.
@@ -2631,6 +2679,9 @@ def send_sticker(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -2664,7 +2715,8 @@ def send_sticker(
self.token, chat_id, sticker, 'sticker',
reply_markup=reply_markup, disable_notification=disable_notification, timeout=timeout,
protect_content=protect_content, message_thread_id=message_thread_id, emoji=emoji,
- reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id)
)
@@ -2689,7 +2741,9 @@ def send_video(
has_spoiler: Optional[bool]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.Message:
"""
Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document).
@@ -2763,6 +2817,12 @@ def send_video(
:param business_connection_id: Identifier of a business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Identifier of a message effect
+ :type message_effect_id: :obj:`str`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -2803,7 +2863,8 @@ def send_video(
supports_streaming=supports_streaming, disable_notification=disable_notification, timeout=timeout,
thumbnail=thumbnail, height=height, width=width, caption_entities=caption_entities,
protect_content=protect_content, message_thread_id=message_thread_id, has_spoiler=has_spoiler,
- reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id,
+ show_caption_above_media=show_caption_above_media)
)
@@ -2826,7 +2887,9 @@ def send_animation(
has_spoiler: Optional[bool]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.Message:
"""
Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
@@ -2899,6 +2962,12 @@ def send_animation(
:param business_connection_id: Identifier of a business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -2934,7 +3003,8 @@ def send_animation(
parse_mode=parse_mode, disable_notification=disable_notification, timeout=timeout,
thumbnail=thumbnail, caption_entities=caption_entities, protect_content=protect_content,
width=width, height=height, message_thread_id=message_thread_id, reply_parameters=reply_parameters,
- has_spoiler=has_spoiler, business_connection_id=business_connection_id)
+ has_spoiler=has_spoiler, business_connection_id=business_connection_id, message_effect_id=message_effect_id,
+ show_caption_above_media=show_caption_above_media)
)
@@ -2952,7 +3022,8 @@ def send_video_note(
message_thread_id: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
As of v.4.0, Telegram clients support rounded square MPEG4 videos of up to 1 minute long.
Use this method to send video messages. On success, the sent Message is returned.
@@ -3010,6 +3081,9 @@ def send_video_note(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3042,7 +3116,63 @@ def send_video_note(
apihelper.send_video_note(
self.token, chat_id, data, duration=duration, length=length, reply_markup=reply_markup,
disable_notification=disable_notification, timeout=timeout, thumbnail=thumbnail,
- protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters,
+ business_connection_id=business_connection_id, message_effect_id=message_effect_id)
+ )
+
+ def send_paid_media(
+ self, chat_id: Union[int, str], star_count: int, media: List[types.InputPaidMedia],
+ caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None,
+ show_caption_above_media: Optional[bool]=None, disable_notification: Optional[bool]=None,
+ protect_content: Optional[bool]=None, reply_parameters: Optional[types.ReplyParameters]=None,
+ reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message:
+ """
+ Use this method to send paid media to channel chats. On success, the sent Message is returned.
+
+ Telegram documentation: https://core.telegram.org/bots/api#sendpaidmedia
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
+ :type chat_id: :obj:`int` or :obj:`str`
+
+ :param star_count: The number of Telegram Stars that must be paid to buy access to the media
+ :type star_count: :obj:`int`
+
+ :param media: A JSON-serialized array describing the media to be sent; up to 10 items
+ :type media: :obj:`list` of :class:`telebot.types.InputPaidMedia`
+
+ :param caption: Media caption, 0-1024 characters after entities parsing
+ :type caption: :obj:`str`
+
+ :param parse_mode: Mode for parsing entities in the media caption
+ :type parse_mode: :obj:`str`
+
+ :param caption_entities: List of special entities that appear in the caption, which can be specified instead of parse_mode
+ :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media
+ :type show_caption_above_media: :obj:`bool`
+
+ :param disable_notification: Sends the message silently. Users will receive a notification with no sound.
+ :type disable_notification: :obj:`bool`
+
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :type protect_content: :obj:`bool`
+
+ :param reply_parameters: Description of the message to reply to
+ :type reply_parameters: :class:`telebot.types.ReplyParameters`
+
+ :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user
+ :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply`
+
+ :return: On success, the sent Message is returned.
+ :rtype: :class:`telebot.types.Message`
+ """
+ return types.Message.de_json(
+ apihelper.send_paid_media(
+ self.token, chat_id, star_count, media, caption=caption, parse_mode=parse_mode,
+ caption_entities=caption_entities, show_caption_above_media=show_caption_above_media,
+ disable_notification=disable_notification, protect_content=protect_content,
+ reply_parameters=reply_parameters, reply_markup=reply_markup)
)
@@ -3058,7 +3188,8 @@ def send_media_group(
allow_sending_without_reply: Optional[bool]=None, # deprecated, for backward compatibility
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> List[types.Message]:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> List[types.Message]:
"""
Use this method to send a group of photos, videos, documents or audios as an album. Documents and audio files
can be only grouped in an album with messages of the same type. On success, an array of Messages that were sent is returned.
@@ -3095,6 +3226,9 @@ def send_media_group(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, an array of Messages that were sent is returned.
:rtype: List[types.Message]
"""
@@ -3128,7 +3262,7 @@ def send_media_group(
result = apihelper.send_media_group(
self.token, chat_id, media, disable_notification=disable_notification, timeout=timeout,
protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters,
- business_connection_id=business_connection_id)
+ business_connection_id=business_connection_id, message_effect_id=message_effect_id)
return [types.Message.de_json(msg) for msg in result]
@@ -3147,7 +3281,8 @@ def send_location(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send point on the map. On success, the sent Message is returned.
@@ -3162,7 +3297,7 @@ def send_location(
:param longitude: Longitude of the location
:type longitude: :obj:`float`
- :param live_period: Period in seconds for which the location will be updated (see Live Locations, should be between 60 and 86400.
+ :param live_period: Period in seconds during which the location will be updated (see Live Locations, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely.
:type live_period: :obj:`int`
:param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard
@@ -3203,6 +3338,9 @@ def send_location(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :parameter message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3232,7 +3370,8 @@ def send_location(
self.token, chat_id, latitude, longitude, live_period=live_period, reply_markup=reply_markup,
disable_notification=disable_notification, timeout=timeout, horizontal_accuracy=horizontal_accuracy,
heading=heading, proximity_alert_radius=proximity_alert_radius, protect_content=protect_content,
- message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id)
)
@@ -3245,7 +3384,10 @@ def edit_message_live_location(
timeout: Optional[int]=None,
horizontal_accuracy: Optional[float]=None,
heading: Optional[int]=None,
- proximity_alert_radius: Optional[int]=None) -> types.Message or bool:
+ proximity_alert_radius: Optional[int]=None,
+ live_period: Optional[int]=None,
+ business_connection_id: Optional[str]=None
+ ) -> types.Message or bool:
"""
Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly
disabled by a call to stopMessageLiveLocation. On success, if the edited message is not an inline message, the edited Message
@@ -3284,6 +3426,12 @@ def edit_message_live_location(
:param proximity_alert_radius: The maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
:type proximity_alert_radius: :obj:`int`
+ :param live_period: New period in seconds during which the location can be updated, starting from the message send date. If 0x7FFFFFFF is specified, then the location can be updated forever. Otherwise, the new value must not exceed the current live_period by more than a day, and the live location expiration date must remain within the next 90 days. If not specified, then live_period remains unchanged
+ :type live_period: :obj:`int`
+
+ :param business_connection_id: Identifier of a business connection
+ :type business_connection_id: :obj:`str`
+
:return: On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned.
:rtype: :class:`telebot.types.Message` or bool
"""
@@ -3291,7 +3439,7 @@ def edit_message_live_location(
apihelper.edit_message_live_location(
self.token, latitude, longitude, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
reply_markup=reply_markup, timeout=timeout, horizontal_accuracy=horizontal_accuracy, heading=heading,
- proximity_alert_radius=proximity_alert_radius)
+ proximity_alert_radius=proximity_alert_radius, live_period=live_period, business_connection_id=business_connection_id)
)
@@ -3300,7 +3448,8 @@ def stop_message_live_location(
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
reply_markup: Optional[types.InlineKeyboardMarkup]=None,
- timeout: Optional[int]=None) -> types.Message or bool:
+ timeout: Optional[int]=None,
+ business_connection_id: Optional[str]=None) -> types.Message or bool:
"""
Use this method to stop updating a live location message before live_period expires.
On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
@@ -3323,13 +3472,16 @@ def stop_message_live_location(
:param timeout: Timeout in seconds for the request.
:type timeout: :obj:`int`
+ :param business_connection_id: Identifier of a business connection
+ :type business_connection_id: :obj:`str`
+
:return: On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
:rtype: :class:`telebot.types.Message` or bool
"""
return types.Message.de_json(
apihelper.stop_message_live_location(
self.token, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
- reply_markup=reply_markup, timeout=timeout)
+ reply_markup=reply_markup, timeout=timeout, business_connection_id=business_connection_id)
)
@@ -3349,7 +3501,8 @@ def send_venue(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send information about a venue. On success, the sent Message is returned.
@@ -3412,6 +3565,9 @@ def send_venue(
:param business_connection_id: Identifier of a business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3441,7 +3597,8 @@ def send_venue(
self.token, chat_id, latitude, longitude, title, address, foursquare_id=foursquare_id,
foursquare_type=foursquare_type, disable_notification=disable_notification, reply_markup=reply_markup,
timeout=timeout, google_place_id=google_place_id, google_place_type=google_place_type,
- protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id)
)
@@ -3456,7 +3613,8 @@ def send_contact(
allow_sending_without_reply: Optional[bool]=None, # deprecated, for backward compatibility
protect_content: Optional[bool]=None, message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send phone contacts. On success, the sent Message is returned.
@@ -3506,6 +3664,9 @@ def send_contact(
:param business_connection_id: Identifier of a business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3534,7 +3695,8 @@ def send_contact(
apihelper.send_contact(
self.token, chat_id, phone_number, first_name, last_name=last_name, vcard=vcard,
disable_notification=disable_notification, reply_markup=reply_markup, timeout=timeout,
- protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters,
+ business_connection_id=business_connection_id, message_effect_id=message_effect_id)
)
@@ -4553,7 +4715,9 @@ def edit_message_text(
entities: Optional[List[types.MessageEntity]]=None,
disable_web_page_preview: Optional[bool]=None, # deprecated, for backward compatibility
reply_markup: Optional[types.InlineKeyboardMarkup]=None,
- link_preview_options : Optional[types.LinkPreviewOptions]=None) -> Union[types.Message, bool]:
+ link_preview_options : Optional[types.LinkPreviewOptions]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit text and game messages.
@@ -4586,6 +4750,12 @@ def edit_message_text(
:param link_preview_options: A JSON-serialized object for options used to automatically generate previews for links.
:type link_preview_options: :obj:`LinkPreviewOptions`
+ :param business_connection_id: Unique identifier of the business connection
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
@@ -4612,9 +4782,10 @@ def edit_message_text(
result = apihelper.edit_message_text(
self.token, text, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
- parse_mode=parse_mode, entities=entities, reply_markup=reply_markup, link_preview_options=link_preview_options)
+ parse_mode=parse_mode, entities=entities, reply_markup=reply_markup, link_preview_options=link_preview_options,
+ business_connection_id=business_connection_id, timeout=timeout)
- if type(result) == bool: # if edit inline message return is bool not Message.
+ if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)
@@ -4623,7 +4794,9 @@ def edit_message_media(
self, media: Any, chat_id: Optional[Union[int, str]]=None,
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit animation, audio, document, photo, or video messages.
If a message is a part of a message album, then it can be edited only to a photo or a video.
@@ -4646,14 +4819,20 @@ def edit_message_media(
:param reply_markup: A JSON-serialized object for an inline keyboard.
:type reply_markup: :obj:`telebot.types.InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply`
+ :param business_connection_id: Unique identifier of the business connection
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
result = apihelper.edit_message_media(
self.token, media, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
- reply_markup=reply_markup)
+ reply_markup=reply_markup, business_connection_id=business_connection_id, timeout=timeout)
- if type(result) == bool: # if edit inline message return is bool not Message.
+ if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)
@@ -4662,7 +4841,9 @@ def edit_message_reply_markup(
self, chat_id: Optional[Union[int, str]]=None,
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit only the reply markup of messages.
@@ -4680,14 +4861,20 @@ def edit_message_reply_markup(
:param reply_markup: A JSON-serialized object for an inline keyboard.
:type reply_markup: :obj:`InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply`
+ :param business_connection_id: Unique identifier of the business connection
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
result = apihelper.edit_message_reply_markup(
self.token, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
- reply_markup=reply_markup)
+ reply_markup=reply_markup, business_connection_id=business_connection_id, timeout=timeout)
- if type(result) == bool:
+ if isinstance(result, bool):
return result
return types.Message.de_json(result)
@@ -4702,7 +4889,8 @@ def send_game(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Used to send the game.
@@ -4741,6 +4929,9 @@ def send_game(
:param business_connection_id: Unique identifier of the business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
@@ -4772,7 +4963,8 @@ def send_game(
apihelper.send_game(
self.token, chat_id, game_short_name, disable_notification=disable_notification,
reply_markup=reply_markup, timeout=timeout, protect_content=protect_content,
- message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ message_effect_id=message_effect_id)
)
@@ -4816,7 +5008,7 @@ def set_game_score(
self.token, user_id, score, force=force, disable_edit_message=disable_edit_message,
chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id)
- if type(result) == bool:
+ if isinstance(result, bool):
return result
return types.Message.de_json(result)
@@ -4857,7 +5049,7 @@ def get_game_high_scores(
def send_invoice(
self, chat_id: Union[int, str], title: str, description: str,
- invoice_payload: str, provider_token: str, currency: str,
+ invoice_payload: str, provider_token: Union[str, None], currency: str,
prices: List[types.LabeledPrice], start_parameter: Optional[str]=None,
photo_url: Optional[str]=None, photo_size: Optional[int]=None,
photo_width: Optional[int]=None, photo_height: Optional[int]=None,
@@ -4876,7 +5068,8 @@ def send_invoice(
suggested_tip_amounts: Optional[List[int]]=None,
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
- reply_parameters: Optional[types.ReplyParameters]=None) -> types.Message:
+ reply_parameters: Optional[types.ReplyParameters]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Sends invoice.
@@ -4895,7 +5088,8 @@ def send_invoice(
use for your internal processes.
:type invoice_payload: :obj:`str`
- :param provider_token: Payments provider token, obtained via @Botfather
+ :param provider_token: Payments provider token, obtained via @Botfather; Pass None to omit the parameter
+ to use "XTR" currency
:type provider_token: :obj:`str`
:param currency: Three-letter ISO 4217 currency code,
@@ -4981,6 +5175,9 @@ def send_invoice(
:param reply_parameters: Required if the message is a reply. Additional interface options.
:type reply_parameters: :obj:`types.ReplyParameters`
+ :param message_effect_id: The identifier of a message effect, which will be applied to the sent message
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
@@ -5019,11 +5216,12 @@ def send_invoice(
disable_notification=disable_notification, reply_markup=reply_markup,
provider_data=provider_data, timeout=timeout, protect_content=protect_content,
message_thread_id=message_thread_id, reply_parameters=reply_parameters,
- max_tip_amount=max_tip_amount, suggested_tip_amounts=suggested_tip_amounts)
+ max_tip_amount=max_tip_amount, suggested_tip_amounts=suggested_tip_amounts,
+ message_effect_id=message_effect_id)
)
def create_invoice_link(self,
- title: str, description: str, payload:str, provider_token: str,
+ title: str, description: str, payload:str, provider_token: Union[str, None],
currency: str, prices: List[types.LabeledPrice],
max_tip_amount: Optional[int] = None,
suggested_tip_amounts: Optional[List[int]]=None,
@@ -5057,7 +5255,8 @@ def create_invoice_link(self,
use for your internal processes.
:type payload: :obj:`str`
- :param provider_token: Payments provider token, obtained via @Botfather
+ :param provider_token: Payments provider token, obtained via @Botfather; Pass None to omit the parameter
+ to use "XTR" currency
:type provider_token: :obj:`str`
:param currency: Three-letter ISO 4217 currency code,
@@ -5129,7 +5328,7 @@ def create_invoice_link(self,
# noinspection PyShadowingBuiltins
def send_poll(
- self, chat_id: Union[int, str], question: str, options: List[str],
+ self, chat_id: Union[int, str], question: str, options: List[types.InputPollOption],
is_anonymous: Optional[bool]=None, type: Optional[str]=None,
allows_multiple_answers: Optional[bool]=None,
correct_option_id: Optional[int]=None,
@@ -5147,7 +5346,10 @@ def send_poll(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ question_parse_mode: Optional[str] = None,
+ question_entities: Optional[List[types.MessageEntity]] = None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send a native poll.
On success, the sent Message is returned.
@@ -5160,8 +5362,8 @@ def send_poll(
:param question: Poll question, 1-300 characters
:type question: :obj:`str`
- :param options: A JSON-serialized list of answer options, 2-10 strings 1-100 characters each
- :type options: :obj:`list` of :obj:`str`
+ :param options: A JSON-serialized list of 2-10 answer options
+ :type options: :obj:`list` of :obj:`InputPollOption`
:param is_anonymous: True, if the poll needs to be anonymous, defaults to True
:type is_anonymous: :obj:`bool`
@@ -5172,12 +5374,10 @@ def send_poll(
:param allows_multiple_answers: True, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to False
:type allows_multiple_answers: :obj:`bool`
- :param correct_option_id: 0-based identifier of the correct answer option. Available only for polls in quiz mode,
- defaults to None
+ :param correct_option_id: 0-based identifier of the correct answer option. Available only for polls in quiz mode, defaults to None
:type correct_option_id: :obj:`int`
- :param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll,
- 0-200 characters with at most 2 line feeds after entities parsing
+ :param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:type explanation: :obj:`str`
:param explanation_parse_mode: Mode for parsing entities in the explanation. See formatting options for more details.
@@ -5201,15 +5401,13 @@ def send_poll(
:param allow_sending_without_reply: deprecated. Pass True, if the message should be sent even if the specified replied-to message is not found
:type allow_sending_without_reply: :obj:`bool`
- :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard,
- instructions to remove reply keyboard or to force a reply from the user.
+ :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user.
:type reply_markup: :obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`
:param timeout: Timeout in seconds for waiting for a response from the user.
:type timeout: :obj:`int`
- :param explanation_entities: A JSON-serialized list of special entities that appear in the explanation,
- which can be specified instead of parse_mode
+ :param explanation_entities: A JSON-serialized list of special entities that appear in the explanation, which can be specified instead of parse_mode
:type explanation_entities: :obj:`list` of :obj:`MessageEntity`
:param protect_content: Protects the contents of the sent message from forwarding and saving
@@ -5224,6 +5422,15 @@ def send_poll(
:param business_connection_id: Identifier of the business connection to use for the poll
:type business_connection_id: :obj:`str`
+ :param question_parse_mode: Mode for parsing entities in the question. See formatting options for more details. Currently, only custom emoji entities are allowed
+ :type question_parse_mode: :obj:`str`
+
+ :param question_entities: A JSON-serialized list of special entities that appear in the poll question. It can be specified instead of question_parse_mode
+ :type question_entities: :obj:`list` of :obj:`MessageEntity`
+
+ :param message_effect_id: Unique identifier of the message effect to apply to the sent message
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
@@ -5255,6 +5462,18 @@ def send_poll(
raise RuntimeError("The send_poll signature was changed, please see send_poll function details.")
explanation_parse_mode = self.parse_mode if (explanation_parse_mode is None) else explanation_parse_mode
+ question_parse_mode = self.parse_mode if (question_parse_mode is None) else question_parse_mode
+
+ if options and (not isinstance(options[0], types.InputPollOption)):
+ # show a deprecation warning
+ logger.warning("The parameter 'options' changed, should be List[types.InputPollOption], other types are deprecated.")
+ # convert options to appropriate type
+ if isinstance(options[0], str):
+ options = [types.InputPollOption(option) for option in options]
+ elif isinstance(options[0], types.PollOption):
+ options = [types.InputPollOption(option.text, text_entities=option.text_entities) for option in options]
+ else:
+ raise RuntimeError("Type of 'options' items is unknown. Options should be List[types.InputPollOption], other types are deprecated.")
return types.Message.de_json(
apihelper.send_poll(
@@ -5265,13 +5484,16 @@ def send_poll(
close_date=close_date, is_closed=is_closed, disable_notification=disable_notification,
reply_markup=reply_markup, timeout=timeout, explanation_entities=explanation_entities,
protect_content=protect_content, message_thread_id=message_thread_id,
- reply_parameters=reply_parameters, business_connection_id=business_connection_id)
+ reply_parameters=reply_parameters, business_connection_id=business_connection_id,
+ question_parse_mode=question_parse_mode, question_entities=question_entities,
+ message_effect_id=message_effect_id)
)
def stop_poll(
self, chat_id: Union[int, str], message_id: int,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> types.Poll:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ business_connection_id: Optional[str]=None) -> types.Poll:
"""
Use this method to stop a poll which was sent by the bot. On success, the stopped Poll is returned.
@@ -5286,11 +5508,14 @@ def stop_poll(
:param reply_markup: A JSON-serialized object for a new message markup.
:type reply_markup: :obj:`InlineKeyboardMarkup`
+ :param business_connection_id: Identifier of the business connection to use for the poll
+ :type business_connection_id: :obj:`str`
+
:return: On success, the stopped Poll is returned.
:rtype: :obj:`types.Poll`
"""
return types.Poll.de_json(
- apihelper.stop_poll(self.token, chat_id, message_id, reply_markup=reply_markup)
+ apihelper.stop_poll(self.token, chat_id, message_id, reply_markup=reply_markup, business_connection_id=business_connection_id)
)
@@ -5354,13 +5579,53 @@ def answer_pre_checkout_query(
self.token, pre_checkout_query_id, ok, error_message=error_message)
+ def get_star_transactions(self, offset: Optional[int]=None, limit: Optional[int]=None) -> types.StarTransactions:
+ """
+ Returns the bot's Telegram Star transactions in chronological order. On success, returns a StarTransactions object.
+
+ Telegram documentation: https://core.telegram.org/bots/api#getstartransactions
+
+ :param offset: Number of transactions to skip in the response
+ :type offset: :obj:`int`
+
+ :param limit: The maximum number of transactions to be retrieved. Values between 1-100 are accepted. Defaults to 100.
+ :type limit: :obj:`int`
+
+ :return: On success, returns a StarTransactions object.
+ :rtype: :obj:`types.StarTransactions`
+ """
+ return types.StarTransactions.de_json(
+ apihelper.get_star_transactions(self.token, offset=offset, limit=limit)
+ )
+
+
+ def refund_star_payment(self, user_id: int, telegram_payment_charge_id: str) -> bool:
+ """
+ Refunds a successful payment in Telegram Stars. Returns True on success.
+
+ Telegram documentation: https://core.telegram.org/bots/api#refundstarpayment
+
+ :param user_id: Identifier of the user whose payment will be refunded
+ :type user_id: :obj:`int`
+
+ :param telegram_payment_charge_id: Telegram payment identifier
+ :type telegram_payment_charge_id: :obj:`str`
+
+ :return: On success, True is returned.
+ :rtype: :obj:`bool`
+ """
+ return apihelper.refund_star_payment(self.token, user_id, telegram_payment_charge_id)
+
def edit_message_caption(
self, caption: str, chat_id: Optional[Union[int, str]]=None,
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ show_caption_above_media: Optional[bool]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit captions of messages.
@@ -5387,6 +5652,15 @@ def edit_message_caption(
:param reply_markup: A JSON-serialized object for an inline keyboard.
:type reply_markup: :obj:`InlineKeyboardMarkup`
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
+
+ :param business_connection_id: Identifier of the business connection to use for the message
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` | :obj:`bool`
"""
@@ -5394,9 +5668,11 @@ def edit_message_caption(
result = apihelper.edit_message_caption(
self.token, caption, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
- parse_mode=parse_mode, caption_entities=caption_entities, reply_markup=reply_markup)
+ parse_mode=parse_mode, caption_entities=caption_entities, reply_markup=reply_markup,
+ show_caption_above_media=show_caption_above_media, business_connection_id=business_connection_id,
+ timeout=timeout)
- if type(result) == bool:
+ if isinstance(result, bool):
return result
return types.Message.de_json(result)
@@ -5564,7 +5840,7 @@ def get_user_chat_boosts(self, chat_id: Union[int, str], user_id: int) -> types.
apihelper.get_user_chat_boosts(self.token, chat_id, user_id)
)
-
+ # noinspection PyShadowingBuiltins
def set_sticker_set_thumbnail(self, name: str, user_id: int, thumbnail: Union[Any, str]=None, format: Optional[str]=None) -> bool:
"""
Use this method to set the thumbnail of a sticker set.
@@ -8122,6 +8398,7 @@ def register_business_message_handler(self,
regexp: Optional[str]=None,
func: Optional[Callable]=None,
content_types: Optional[List[str]]=None,
+ pass_bot: Optional[bool]=False,
**kwargs):
"""
Registers business connection handler.
@@ -8141,11 +8418,15 @@ def register_business_message_handler(self,
:param content_types: Supported message content types. Must be a list. Defaults to ['text'].
:type content_types: :obj:`list` of :obj:`str`
+ :param pass_bot: True, if bot instance should be passed to handler
+ :type pass_bot: :obj:`bool`
+
:param kwargs: Optional keyword arguments(custom filters)
:return: None
"""
- handler_dict = self._build_handler_dict(callback, content_types=content_types, commands=commands, regexp=regexp, func=func, **kwargs)
+ handler_dict = self._build_handler_dict(callback, content_types=content_types, commands=commands, regexp=regexp, func=func,
+ pass_bot=pass_bot, **kwargs)
self.add_business_message_handler(handler_dict)
diff --git a/telebot/apihelper.py b/telebot/apihelper.py
index 3f537065c..0bcb80a96 100644
--- a/telebot/apihelper.py
+++ b/telebot/apihelper.py
@@ -3,6 +3,7 @@
from datetime import datetime
try:
+ # noinspection PyPackageRequirements
import ujson as json
except ImportError:
import json
@@ -93,7 +94,7 @@ def _make_request(token, method_name, method='get', params=None, files=None):
# process types.InputFile
for key, value in files_copy.items():
if isinstance(value, types.InputFile):
- files[key] = value.file
+ files[key] = (value.file_name, value.file)
elif isinstance(value, tuple) and (len(value) == 2) and isinstance(value[1], types.InputFile):
files[key] = (value[0], value[1].file)
@@ -244,7 +245,7 @@ def send_message(
parse_mode=None, disable_notification=None, timeout=None,
entities=None, protect_content=None,
message_thread_id=None, reply_parameters=None, link_preview_options=None,
- business_connection_id=None):
+ business_connection_id=None, message_effect_id=None):
method_url = r'sendMessage'
payload = {'chat_id': str(chat_id), 'text': text}
if link_preview_options is not None:
@@ -267,6 +268,8 @@ def send_message(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload, method='post')
@@ -371,6 +374,7 @@ def get_chat_member_count(token, chat_id):
return _make_request(token, method_url, params=payload)
+# noinspection PyShadowingBuiltins
def set_sticker_set_thumbnail(token, name, user_id, thumbnail, format):
method_url = r'setStickerSetThumbnail'
payload = {'name': name, 'user_id': user_id, 'format': format}
@@ -424,7 +428,7 @@ def forward_message(
def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_markup=None, timeout=None, protect_content=None, message_thread_id=None,
- reply_parameters=None):
+ reply_parameters=None, show_caption_above_media=None):
method_url = r'copyMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if caption is not None:
@@ -432,17 +436,21 @@ def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_m
if parse_mode:
payload['parse_mode'] = parse_mode
if caption_entities is not None:
- payload['caption_entities'] = _convert_entites(caption_entities)
+ payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if disable_notification is not None:
payload['disable_notification'] = disable_notification
if reply_parameters is not None:
payload['reply_parameters'] = reply_parameters.to_json()
+ if reply_markup is not None:
+ payload['reply_markup'] = _convert_markup(reply_markup)
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return _make_request(token, method_url, params=payload)
@@ -450,7 +458,7 @@ def send_dice(
token, chat_id,
emoji=None, disable_notification=None,
reply_markup=None, timeout=None, protect_content=None, message_thread_id=None, reply_parameters=None,
- business_connection_id=None):
+ business_connection_id=None, message_effect_id=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@@ -469,6 +477,8 @@ def send_dice(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload)
@@ -477,7 +487,8 @@ def send_photo(
caption=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, protect_content=None,
- message_thread_id=None, has_spoiler=None, reply_parameters=None, business_connection_id=None):
+ message_thread_id=None, has_spoiler=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None, show_caption_above_media=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@@ -509,13 +520,46 @@ def send_photo(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return _make_request(token, method_url, params=payload, files=files, method='post')
+
+def send_paid_media(
+ token, chat_id, star_count, media,
+ caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None,
+ disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None):
+ method_url = r'sendPaidMedia'
+ media_json, files = convert_input_media_array(media)
+ payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json}
+ if caption:
+ payload['caption'] = caption
+ if parse_mode:
+ payload['parse_mode'] = parse_mode
+ if caption_entities:
+ payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
+ if disable_notification is not None:
+ payload['disable_notification'] = disable_notification
+ if protect_content is not None:
+ payload['protect_content'] = protect_content
+ if reply_parameters is not None:
+ payload['reply_parameters'] = reply_parameters.to_json()
+ if reply_markup:
+ payload['reply_markup'] = _convert_markup(reply_markup)
+ return _make_request(
+ token, method_url, params=payload,
+ method='post' if files else 'get',
+ files=files if files else None)
def send_media_group(
token, chat_id, media,
disable_notification=None,
- timeout=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ timeout=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendMediaGroup'
media_json, files = convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@@ -531,6 +575,8 @@ def send_media_group(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(
token, method_url, params=payload,
method='post' if files else 'get',
@@ -543,7 +589,8 @@ def send_location(
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, protect_content=None,
- message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ message_thread_id=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@@ -568,13 +615,14 @@ def send_location(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload)
def edit_message_live_location(
- token, latitude, longitude, chat_id=None, message_id=None,
- inline_message_id=None, reply_markup=None, timeout=None,
- horizontal_accuracy=None, heading=None, proximity_alert_radius=None):
+ token, latitude, longitude, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None,
+ timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, live_period=None, business_connection_id=None):
method_url = r'editMessageLiveLocation'
payload = {'latitude': latitude, 'longitude': longitude}
if chat_id:
@@ -587,18 +635,22 @@ def edit_message_live_location(
payload['heading'] = heading
if proximity_alert_radius:
payload['proximity_alert_radius'] = proximity_alert_radius
+ if live_period:
+ payload['live_period'] = live_period
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if timeout:
payload['timeout'] = timeout
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
return _make_request(token, method_url, params=payload)
def stop_message_live_location(
token, chat_id=None, message_id=None,
- inline_message_id=None, reply_markup=None, timeout=None):
+ inline_message_id=None, reply_markup=None, timeout=None, business_connection_id=None):
method_url = r'stopMessageLiveLocation'
payload = {}
if chat_id:
@@ -611,6 +663,8 @@ def stop_message_live_location(
payload['reply_markup'] = _convert_markup(reply_markup)
if timeout:
payload['timeout'] = timeout
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
return _make_request(token, method_url, params=payload)
@@ -618,7 +672,8 @@ def send_venue(
token, chat_id, latitude, longitude, title, address,
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_markup=None, timeout=None, google_place_id=None,
- google_place_type=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ google_place_type=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@@ -643,13 +698,16 @@ def send_venue(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload)
def send_contact(
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
disable_notification=None, reply_markup=None, timeout=None,
- protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@@ -670,6 +728,8 @@ def send_contact(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload)
@@ -689,7 +749,8 @@ def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=Non
def send_video(token, chat_id, data, duration=None, caption=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumbnail=None, width=None, height=None, caption_entities=None, protect_content=None,
- message_thread_id=None, has_spoiler=None, reply_parameters=None, business_connection_id=None):
+ message_thread_id=None, has_spoiler=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None, show_caption_above_media=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@@ -735,6 +796,10 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_markup=N
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return _make_request(token, method_url, params=payload, files=files, method='post')
@@ -743,7 +808,7 @@ def send_animation(
token, chat_id, data, duration=None, caption=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
protect_content=None, width=None, height=None, message_thread_id=None, reply_parameters=None,
- has_spoiler=None, business_connection_id=None):
+ has_spoiler=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@@ -787,12 +852,17 @@ def send_animation(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
- protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@@ -822,12 +892,14 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_markup=
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_video_note(token, chat_id, data, duration=None, length=None, reply_markup=None,
disable_notification=None, timeout=None, thumbnail=None, protect_content=None,
- message_thread_id=None, reply_parameters=None,business_connection_id=None):
+ message_thread_id=None, reply_parameters=None,business_connection_id=None, message_effect_id=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@@ -863,12 +935,15 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_mark
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
- caption_entities=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ caption_entities=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@@ -910,13 +985,16 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_data(token, chat_id, data, data_type, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
disable_content_type_detection=None, visible_file_name=None,
- protect_content = None, message_thread_id=None, emoji=None, reply_parameters=None, business_connection_id=None):
+ protect_content = None, message_thread_id=None, emoji=None, reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@@ -959,6 +1037,8 @@ def send_data(token, chat_id, data, data_type, reply_markup=None, parse_mode=Non
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload, files=files, method='post')
@@ -1330,8 +1410,9 @@ def unpin_all_chat_messages(token, chat_id):
# Updating messages
-def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None,
- entities = None, reply_markup=None, link_preview_options=None):
+def edit_message_text(
+ token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, entities = None,
+ reply_markup=None, link_preview_options=None, business_connection_id=None, timeout=None):
method_url = r'editMessageText'
payload = {'text': text}
if chat_id:
@@ -1348,11 +1429,16 @@ def edit_message_text(token, text, chat_id=None, message_id=None, inline_message
payload['reply_markup'] = _convert_markup(reply_markup)
if link_preview_options is not None:
payload['link_preview_options'] = link_preview_options.to_json()
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return _make_request(token, method_url, params=payload, method='post')
-def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None,
- parse_mode=None, caption_entities=None,reply_markup=None):
+def edit_message_caption(
+ token, caption, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, caption_entities=None,
+ reply_markup=None, show_caption_above_media=None, business_connection_id=None, timeout=None):
method_url = r'editMessageCaption'
payload = {'caption': caption}
if chat_id:
@@ -1367,10 +1453,18 @@ def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_m
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return _make_request(token, method_url, params=payload, method='post')
-def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
+def edit_message_media(
+ token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None,
+ business_connection_id=None, timeout=None):
method_url = r'editMessageMedia'
media_json, file = convert_input_media(media)
payload = {'media': media_json}
@@ -1382,10 +1476,16 @@ def edit_message_media(token, media, chat_id=None, message_id=None, inline_messa
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return _make_request(token, method_url, params=payload, files=file, method='post' if file else 'get')
-def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
+def edit_message_reply_markup(
+ token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, business_connection_id=None,
+ timeout=None):
method_url = r'editMessageReplyMarkup'
payload = {}
if chat_id:
@@ -1396,6 +1496,10 @@ def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_messa
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return _make_request(token, method_url, params=payload, method='post')
@@ -1412,7 +1516,7 @@ def delete_message(token, chat_id, message_id, timeout=None):
def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_markup=None, timeout=None,
- protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None):
+ protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@@ -1429,6 +1533,8 @@ def send_game(
payload['reply_parameters'] = reply_parameters.to_json()
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload)
@@ -1494,7 +1600,7 @@ def send_invoice(
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_markup=None, provider_data=None,
timeout=None, max_tip_amount=None, suggested_tip_amounts=None,
- protect_content=None, message_thread_id=None, reply_parameters=None):
+ protect_content=None, message_thread_id=None, reply_parameters=None, message_effect_id=None):
"""
Use this method to send invoices. On success, the sent Message is returned.
:param token: Bot's token (you don't need to fill this)
@@ -1522,15 +1628,16 @@ def send_invoice(
:param provider_data: A JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider.
:param timeout:
:param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency
- :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency.
- At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
+ :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency. At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
:param protect_content: Protects the contents of the sent message from forwarding and saving
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param reply_parameters: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button.
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
:return:
"""
method_url = r'sendInvoice'
payload = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': invoice_payload,
- 'provider_token': provider_token, 'currency': currency,
+ 'currency': currency,
'prices': _convert_list_json_serializable(prices)}
if start_parameter:
payload['start_parameter'] = start_parameter
@@ -1574,6 +1681,10 @@ def send_invoice(
payload['message_thread_id'] = message_thread_id
if reply_parameters is not None:
payload['reply_parameters'] = reply_parameters.to_json()
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if provider_token is not None:
+ payload['provider_token'] = provider_token
return _make_request(token, method_url, params=payload)
@@ -1611,11 +1722,26 @@ def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_message=No
payload['error_message'] = error_message
return _make_request(token, method_url, params=payload)
+def get_star_transactions(token, offset=None, limit=None):
+ method_url = 'getStarTransactions'
+ payload = {}
+ if offset:
+ payload['offset'] = offset
+ if limit:
+ payload['limit'] = limit
+ return _make_request(token, method_url, params=payload)
+
+
+def refund_star_payment(token, user_id, telegram_payment_charge_id):
+ method_url = 'refundStarPayment'
+ payload = {'user_id': user_id, 'telegram_payment_charge_id': telegram_payment_charge_id}
+ return _make_request(token, method_url, params=payload)
+
def unpin_all_general_forum_topic_messages(token, chat_id):
method_url = 'unpinAllGeneralForumTopicMessages'
payload = {'chat_id': chat_id}
- return _make_request(token, method_url, params=payload, method='post')
+ return _make_request(token, method_url, params=payload)
# InlineQuery
@@ -1778,7 +1904,7 @@ def create_invoice_link(token, title, description, payload, provider_token,
need_email=None, need_shipping_address=None, send_phone_number_to_provider=None,
send_email_to_provider=None, is_flexible=None):
method_url = r'createInvoiceLink'
- payload = {'title': title, 'description': description, 'payload': payload, 'provider_token': provider_token,
+ payload = {'title': title, 'description': description, 'payload': payload,
'currency': currency, 'prices': _convert_list_json_serializable(prices)}
if max_tip_amount:
payload['max_tip_amount'] = max_tip_amount
@@ -1808,38 +1934,40 @@ def create_invoice_link(token, title, description, payload, provider_token,
payload['send_email_to_provider'] = send_email_to_provider
if is_flexible is not None:
payload['is_flexible'] = is_flexible
+ if provider_token is not None:
+ payload['provider_token'] = provider_token
return _make_request(token, method_url, params=payload, method='post')
# noinspection PyShadowingBuiltins
def send_poll(
- token, chat_id,
- question, options,
+ token, chat_id, question, options,
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None, explanation = None,
explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None, disable_notification=False,
- reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None, reply_parameters=None,
- business_connection_id=None):
+ reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None,
+ reply_parameters=None, business_connection_id=None, question_parse_mode=None, question_entities=None, message_effect_id=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
'question': question,
- 'options': json.dumps(_convert_poll_options(options))}
+ 'options': json.dumps([option.to_dict() for option in options])
+ }
if is_anonymous is not None:
payload['is_anonymous'] = is_anonymous
- if type is not None:
+ if type:
payload['type'] = type
if allows_multiple_answers is not None:
payload['allows_multiple_answers'] = allows_multiple_answers
if correct_option_id is not None:
payload['correct_option_id'] = correct_option_id
- if explanation is not None:
+ if explanation:
payload['explanation'] = explanation
- if explanation_parse_mode is not None:
+ if explanation_parse_mode:
payload['explanation_parse_mode'] = explanation_parse_mode
- if open_period is not None:
+ if open_period:
payload['open_period'] = open_period
- if close_date is not None:
+ if close_date:
if isinstance(close_date, datetime):
payload['close_date'] = close_date.timestamp()
else:
@@ -1848,21 +1976,26 @@ def send_poll(
payload['is_closed'] = is_closed
if disable_notification:
payload['disable_notification'] = disable_notification
- if reply_markup is not None:
+ if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if timeout:
payload['timeout'] = timeout
if explanation_entities:
- payload['explanation_entities'] = json.dumps(
- types.MessageEntity.to_list_of_dicts(explanation_entities))
+ payload['explanation_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
- if reply_parameters is not None:
+ if reply_parameters:
payload['reply_parameters'] = reply_parameters.to_json()
- if business_connection_id is not None:
+ if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if question_parse_mode:
+ payload['question_parse_mode'] = question_parse_mode
+ if question_entities:
+ payload['question_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(question_entities))
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return _make_request(token, method_url, params=payload)
def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_id=None):
@@ -1907,11 +2040,13 @@ def get_forum_topic_icon_stickers(token):
method_url = r'getForumTopicIconStickers'
return _make_request(token, method_url)
-def stop_poll(token, chat_id, message_id, reply_markup=None):
+def stop_poll(token, chat_id, message_id, reply_markup=None, business_connection_id=None):
method_url = r'stopPoll'
payload = {'chat_id': str(chat_id), 'message_id': message_id}
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
return _make_request(token, method_url, params=payload)
def edit_general_forum_topic(token, chat_id, name):
@@ -1964,7 +2099,7 @@ def forward_messages(token, chat_id, from_chat_id, message_ids, disable_notifica
return _make_request(token, method_url, params=payload)
def copy_messages(token, chat_id, from_chat_id, message_ids, disable_notification=None,
- message_thread_id=None, protect_content=None, remove_caption=None):
+ message_thread_id=None, protect_content=None, remove_caption=None, show_caption_above_media=None):
method_url = 'copyMessages'
payload = {
'chat_id': chat_id,
@@ -1979,6 +2114,8 @@ def copy_messages(token, chat_id, from_chat_id, message_ids, disable_notificatio
payload['protect_content'] = protect_content
if remove_caption is not None:
payload['remove_caption'] = remove_caption
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return _make_request(token, method_url, params=payload)
@@ -1998,31 +2135,6 @@ def _convert_markup(markup):
return markup
-def _convert_entites(entites):
- if entites is None:
- return None
- elif len(entites) == 0:
- return []
- elif isinstance(entites[0], types.JsonSerializable):
- return [entity.to_json() for entity in entites]
- else:
- return entites
-
-
-def _convert_poll_options(poll_options):
- if poll_options is None:
- return None
- elif len(poll_options) == 0:
- return []
- elif isinstance(poll_options[0], str):
- # Compatibility mode with previous bug when only list of string was accepted as poll_options
- return poll_options
- elif isinstance(poll_options[0], types.PollOption):
- return [option.text for option in poll_options]
- else:
- return poll_options
-
-
def convert_input_media(media):
if isinstance(media, types.InputMedia):
return media.convert_input_media()
@@ -2033,7 +2145,7 @@ def convert_input_media_array(array):
media = []
files = {}
for input_media in array:
- if isinstance(input_media, types.InputMedia):
+ if isinstance(input_media, types.InputMedia) or isinstance(input_media, types.InputPaidMedia):
media_dict = input_media.to_dict()
if media_dict['media'].startswith('attach://'):
key = media_dict['media'].replace('attach://', '')
diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py
index fa4a0a7eb..d8dd91e05 100644
--- a/telebot/async_telebot.py
+++ b/telebot/async_telebot.py
@@ -246,7 +246,7 @@ def _setup_change_detector(self, path_to_watch: str) -> None:
self.event_observer.schedule(self.event_handler, path, recursive=True)
self.event_observer.start()
- async def polling(self, non_stop: bool=False, skip_pending=False, interval: int=0, timeout: int=20,
+ async def polling(self, non_stop: bool=True, skip_pending=False, interval: int=0, timeout: int=20,
request_timeout: Optional[int]=None, allowed_updates: Optional[List[str]]=None,
none_stop: Optional[bool]=None, restart_on_change: Optional[bool]=False, path_to_watch: Optional[str]=None):
"""
@@ -257,11 +257,6 @@ async def polling(self, non_stop: bool=False, skip_pending=False, interval: int=
Always gets updates.
- .. note::
-
- Set non_stop=True if you want your bot to continue receiving updates
- if there is an error.
-
.. note::
Install watchdog and psutil before using restart_on_change option.
@@ -393,6 +388,15 @@ def __hide_token(self, message: str) -> str:
return message.replace(code, "*" * len(code))
else:
return message
+
+ async def _handle_error_interval(self, error_interval: float):
+ logger.debug('Waiting for %s seconds before retrying', error_interval)
+ await asyncio.sleep(error_interval)
+ if error_interval * 2 < 60: # same logic as sync
+ error_interval *= 2
+ else:
+ error_interval = 60
+ return error_interval
async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout: int=20,
request_timeout: int=None, allowed_updates: Optional[List[str]]=None):
@@ -426,16 +430,18 @@ async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout:
self._polling = True
+ error_interval = 0.25
+
try:
while self._polling:
try:
-
updates = await self.get_updates(offset=self.offset, allowed_updates=allowed_updates, timeout=timeout, request_timeout=request_timeout)
if updates:
self.offset = updates[-1].update_id + 1
# noinspection PyAsyncCall
asyncio.create_task(self.process_new_updates(updates)) # Seperate task for processing updates
if interval: await asyncio.sleep(interval)
+ error_interval = 0.25 # drop error_interval if no errors
except KeyboardInterrupt:
return
@@ -446,9 +452,11 @@ async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout:
if not handled:
logger.error('Unhandled exception (full traceback for debug level): %s', self.__hide_token(str(e)))
logger.debug(self.__hide_token(traceback.format_exc()))
+
+ if non_stop:
+ error_interval = await self._handle_error_interval(error_interval)
if non_stop or handled:
- await asyncio.sleep(2)
continue
else:
return
@@ -458,6 +466,9 @@ async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout:
logger.error('Unhandled exception (full traceback for debug level): %s', self.__hide_token(str(e)))
logger.debug(self.__hide_token(traceback.format_exc()))
+ if non_stop:
+ error_interval = await self._handle_error_interval(error_interval)
+
if non_stop or handled:
continue
else:
@@ -468,6 +479,9 @@ async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout:
logger.error('Unhandled exception (full traceback for debug level): %s', str(e))
logger.debug(traceback.format_exc())
+ if non_stop:
+ error_interval = await self._handle_error_interval(error_interval)
+
if non_stop or handled:
continue
else:
@@ -523,7 +537,6 @@ async def _run_middlewares_and_handlers(self, message, handlers, middlewares, up
if isinstance(middleware_result, CancelUpdate):
return
elif isinstance(middleware_result, SkipHandler):
- await middleware.post_process(message, data, handler_error)
skip_handlers = True
if handlers and not(skip_handlers):
@@ -2356,6 +2369,7 @@ def register_business_message_handler(self,
regexp: Optional[str]=None,
func: Optional[Callable]=None,
content_types: Optional[List[str]]=None,
+ pass_bot: Optional[bool]=False,
**kwargs):
"""
Registers business connection handler.
@@ -2363,17 +2377,27 @@ def register_business_message_handler(self,
:param callback: function to be called
:type callback: :obj:`function`
+ :param commands: list of commands
+ :type commands: :obj:`list` of :obj:`str`
+
+ :param regexp: Regular expression
+ :type regexp: :obj:`str`
+
:param func: Function executed as a filter
:type func: :obj:`function`
- :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
+ :param content_types: Supported message content types. Must be a list. Defaults to ['text'].
+ :type content_types: :obj:`list` of :obj:`str`
+
+ :param pass_bot: True, if bot instance should be passed to handler
:type pass_bot: :obj:`bool`
:param kwargs: Optional keyword arguments(custom filters)
:return: None
"""
- handler_dict = self._build_handler_dict(callback, content_types=content_types, commands=commands, regexp=regexp, func=func, **kwargs)
+ handler_dict = self._build_handler_dict(callback, content_types=content_types, commands=commands, regexp=regexp, func=func,
+ pass_bot=pass_bot,**kwargs)
self.add_business_message_handler(handler_dict)
@@ -2889,7 +2913,7 @@ async def get_user_profile_photos(self, user_id: int, offset: Optional[int]=None
result = await asyncio_helper.get_user_profile_photos(self.token, user_id, offset, limit)
return types.UserProfilePhotos.de_json(result)
- async def get_chat(self, chat_id: Union[int, str]) -> types.Chat:
+ async def get_chat(self, chat_id: Union[int, str]) -> types.ChatFullInfo:
"""
Use this method to get up to date information about the chat (current name of the user for one-on-one
conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
@@ -2900,10 +2924,10 @@ async def get_chat(self, chat_id: Union[int, str]) -> types.Chat:
:type chat_id: :obj:`int` or :obj:`str`
:return: Chat information
- :rtype: :class:`telebot.types.Chat`
+ :rtype: :class:`telebot.types.ChatFullInfo`
"""
result = await asyncio_helper.get_chat(self.token, chat_id)
- return types.Chat.de_json(result)
+ return types.ChatFullInfo.de_json(result)
async def leave_chat(self, chat_id: Union[int, str]) -> bool:
"""
@@ -3061,7 +3085,8 @@ async def send_message(
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
link_preview_options: Optional[types.LinkPreviewOptions]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send text messages.
@@ -3117,6 +3142,9 @@ async def send_message(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3171,7 +3199,8 @@ async def send_message(
await asyncio_helper.send_message(
self.token, chat_id, text,
reply_markup, parse_mode, disable_notification, timeout,
- entities, protect_content, message_thread_id, reply_parameters, link_preview_options, business_connection_id))
+ entities, protect_content, message_thread_id, reply_parameters, link_preview_options, business_connection_id,
+ message_effect_id=message_effect_id))
async def forward_message(
self, chat_id: Union[int, str], from_chat_id: Union[int, str],
@@ -3229,9 +3258,14 @@ async def copy_message(
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
message_thread_id: Optional[int]=None,
- reply_parameters: Optional[types.ReplyParameters]=None) -> types.MessageID:
+ reply_parameters: Optional[types.ReplyParameters]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.MessageID:
"""
Use this method to copy messages of any kind.
+ If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages,
+ and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous
+ to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array
+ of MessageId of the sent messages is returned.
Telegram documentation: https://core.telegram.org/bots/api#copymessage
@@ -3277,6 +3311,9 @@ async def copy_message(
:param reply_parameters: Reply parameters.
:type reply_parameters: :class:`telebot.types.ReplyParameters`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
:return: On success, the MessageId of the sent message is returned.
:rtype: :class:`telebot.types.MessageID`
@@ -3308,7 +3345,7 @@ async def copy_message(
return types.MessageID.de_json(
await asyncio_helper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities,
disable_notification, reply_markup,
- timeout, protect_content, message_thread_id, reply_parameters))
+ timeout, protect_content, message_thread_id, reply_parameters, show_caption_above_media=show_caption_above_media))
async def delete_message(self, chat_id: Union[int, str], message_id: int,
timeout: Optional[int]=None) -> bool:
@@ -3396,44 +3433,43 @@ async def forward_messages(self, chat_id: Union[str, int], from_chat_id: Union[s
async def copy_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, int], message_ids: List[int],
disable_notification: Optional[bool] = None, message_thread_id: Optional[int] = None,
protect_content: Optional[bool] = None, remove_caption: Optional[bool] = None) -> List[types.MessageID]:
- """
- Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped.
- Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied
- only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessages, but
- the copied messages don't have a link to the original message. Album grouping is kept for copied messages.
- On success, an array of MessageId of the sent messages is returned.
+ """
+ Use this method to copy messages of any kind.
+ Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied.
+ A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method
+ forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success.
- Telegram documentation: https://core.telegram.org/bots/api#copymessages
+ Telegram documentation: https://core.telegram.org/bots/api#copymessages
- :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
- :type chat_id: :obj:`int` or :obj:`str`
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
+ :type chat_id: :obj:`int` or :obj:`str`
- :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername)
- :type from_chat_id: :obj:`int` or :obj:`str`
+ :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername)
+ :type from_chat_id: :obj:`int` or :obj:`str`
- :param message_ids: Message identifiers in the chat specified in from_chat_id
- :type message_ids: :obj:`list` of :obj:`int`
+ :param message_ids: Message identifiers in the chat specified in from_chat_id
+ :type message_ids: :obj:`list` of :obj:`int`
- :param disable_notification: Sends the message silently. Users will receive a notification with no sound
- :type disable_notification: :obj:`bool`
+ :param disable_notification: Sends the message silently. Users will receive a notification with no sound
+ :type disable_notification: :obj:`bool`
- :param message_thread_id: Identifier of a message thread, in which the messages will be sent
- :type message_thread_id: :obj:`int`
+ :param message_thread_id: Identifier of a message thread, in which the messages will be sent
+ :type message_thread_id: :obj:`int`
- :param protect_content: Protects the contents of the forwarded message from forwarding and saving
- :type protect_content: :obj:`bool`
+ :param protect_content: Protects the contents of the forwarded message from forwarding and saving
+ :type protect_content: :obj:`bool`
- :param remove_caption: Pass True to copy the messages without their captions
- :type remove_caption: :obj:`bool`
+ :param remove_caption: Pass True to copy the messages without their captions
+ :type remove_caption: :obj:`bool`
- :return: On success, an array of MessageId of the sent messages is returned.
- :rtype: :obj:`list` of :class:`telebot.types.MessageID`
- """
- disable_notification = self.disable_notification if disable_notification is None else disable_notification
- protect_content = self.protect_content if protect_content is None else protect_content
- result = await asyncio_helper.copy_messages(self.token, chat_id, from_chat_id, message_ids, disable_notification,
- protect_content, message_thread_id, remove_caption)
- return [types.MessageID.de_json(message_id) for message_id in result]
+ :return: On success, an array of MessageId of the sent messages is returned.
+ :rtype: :obj:`list` of :class:`telebot.types.MessageID`
+ """
+ disable_notification = self.disable_notification if disable_notification is None else disable_notification
+ protect_content = self.protect_content if protect_content is None else protect_content
+ result = await asyncio_helper.copy_messages(self.token, chat_id, from_chat_id, message_ids, disable_notification, message_thread_id,
+ protect_content, remove_caption)
+ return [types.MessageID.de_json(message_id) for message_id in result]
async def send_dice(
self, chat_id: Union[int, str],
@@ -3445,7 +3481,8 @@ async def send_dice(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send an animated emoji that will display a random value. On success, the sent Message is returned.
@@ -3487,6 +3524,9 @@ async def send_dice(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3517,7 +3557,7 @@ async def send_dice(
return types.Message.de_json(
await asyncio_helper.send_dice(
self.token, chat_id, emoji, disable_notification,
- reply_markup, timeout, protect_content, message_thread_id, reply_parameters, business_connection_id))
+ reply_markup, timeout, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
async def send_photo(
@@ -3533,7 +3573,9 @@ async def send_photo(
message_thread_id: Optional[int]=None,
has_spoiler: Optional[bool]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.Message:
"""
Use this method to send photos. On success, the sent Message is returned.
@@ -3587,6 +3629,12 @@ async def send_photo(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
@@ -3620,7 +3668,8 @@ async def send_photo(
await asyncio_helper.send_photo(
self.token, chat_id, photo, caption, reply_markup,
parse_mode, disable_notification, timeout, caption_entities,
- protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id))
+ protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id, message_effect_id=message_effect_id,
+ show_caption_above_media=show_caption_above_media))
async def send_audio(
self, chat_id: Union[int, str], audio: Union[Any, str],
@@ -3638,7 +3687,8 @@ async def send_audio(
message_thread_id: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send audio files, if you want Telegram clients to display them in the music player.
Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size,
@@ -3711,6 +3761,9 @@ async def send_audio(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3747,7 +3800,7 @@ async def send_audio(
await asyncio_helper.send_audio(
self.token, chat_id, audio, caption, duration, performer, title,
reply_markup, parse_mode, disable_notification, timeout, thumbnail,
- caption_entities, protect_content, message_thread_id, reply_parameters, business_connection_id))
+ caption_entities, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
async def send_voice(
self, chat_id: Union[int, str], voice: Union[Any, str],
@@ -3762,11 +3815,10 @@ async def send_voice(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
- Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message.
- For this to work, your audio must be in an .OGG file encoded with OPUS (other formats may be sent as Audio or Document).
- On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .OGG file encoded with OPUS, or in .MP3 format, or in .M4A format (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
Telegram documentation: https://core.telegram.org/bots/api#sendvoice
@@ -3818,6 +3870,9 @@ async def send_voice(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@@ -3849,7 +3904,7 @@ async def send_voice(
await asyncio_helper.send_voice(
self.token, chat_id, voice, caption, duration, reply_markup,
parse_mode, disable_notification, timeout, caption_entities,
- protect_content, message_thread_id, reply_parameters, business_connection_id))
+ protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
async def send_document(
self, chat_id: Union[int, str], document: Union[Any, str],
@@ -3869,7 +3924,8 @@ async def send_document(
message_thread_id: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send general files.
@@ -3935,6 +3991,9 @@ async def send_document(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -3972,6 +4031,10 @@ async def send_document(
if reply_parameters and (reply_parameters.allow_sending_without_reply is None):
reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply
+ if isinstance(document, types.InputFile) and visible_file_name:
+ # inputfile name ignored, warn
+ logger.warning('Cannot use both InputFile and visible_file_name. InputFile name will be ignored.')
+
return types.Message.de_json(
await asyncio_helper.send_data(
self.token, chat_id, document, 'document',
@@ -3979,7 +4042,7 @@ async def send_document(
disable_notification = disable_notification, timeout = timeout, caption = caption, thumbnail= thumbnail,
caption_entities = caption_entities,
disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content,
- message_thread_id = message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id))
+ message_thread_id = message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id))
async def send_sticker(
self, chat_id: Union[int, str], sticker: Union[Any, str],
@@ -3993,7 +4056,8 @@ async def send_sticker(
message_thread_id: Optional[int]=None,
emoji: Optional[str]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers.
On success, the sent Message is returned.
@@ -4042,6 +4106,9 @@ async def send_sticker(
:param business_connection_id: Unique identifier for the target business connection
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier for the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4080,7 +4147,7 @@ async def send_sticker(
reply_markup=reply_markup,
disable_notification=disable_notification, timeout=timeout,
protect_content=protect_content,
- message_thread_id=message_thread_id, emoji=emoji, reply_parameters=reply_parameters, business_connection_id=business_connection_id))
+ message_thread_id=message_thread_id, emoji=emoji, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id))
async def send_video(
self, chat_id: Union[int, str], video: Union[Any, str],
@@ -4103,7 +4170,9 @@ async def send_video(
has_spoiler: Optional[bool]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.Message:
"""
Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document).
@@ -4177,6 +4246,12 @@ async def send_video(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4218,7 +4293,8 @@ async def send_video(
await asyncio_helper.send_video(
self.token, chat_id, video, duration, caption, reply_markup,
parse_mode, supports_streaming, disable_notification, timeout, thumbnail, width, height,
- caption_entities, protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id))
+ caption_entities, protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id, message_effect_id=message_effect_id,
+ show_caption_above_media=show_caption_above_media))
async def send_animation(
self, chat_id: Union[int, str], animation: Union[Any, str],
@@ -4239,7 +4315,9 @@ async def send_animation(
has_spoiler: Optional[bool]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None,
+ show_caption_above_media: Optional[bool]=None) -> types.Message:
"""
Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
@@ -4312,6 +4390,12 @@ async def send_animation(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4348,7 +4432,8 @@ async def send_animation(
await asyncio_helper.send_animation(
self.token, chat_id, animation, duration, caption,
reply_markup, parse_mode, disable_notification, timeout, thumbnail,
- caption_entities, width, height, protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id))
+ caption_entities, width, height, protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id,
+ message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media))
async def send_video_note(
self, chat_id: Union[int, str], data: Union[Any, str],
@@ -4364,7 +4449,8 @@ async def send_video_note(
message_thread_id: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
As of v.4.0, Telegram clients support rounded square MPEG4 videos of up to 1 minute long.
Use this method to send video messages. On success, the sent Message is returned.
@@ -4422,6 +4508,9 @@ async def send_video_note(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4456,7 +4545,62 @@ async def send_video_note(
return types.Message.de_json(
await asyncio_helper.send_video_note(
self.token, chat_id, data, duration, length, reply_markup,
- disable_notification, timeout, thumbnail, protect_content, message_thread_id, reply_parameters, business_connection_id))
+ disable_notification, timeout, thumbnail, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
+
+ async def send_paid_media(
+ self, chat_id: Union[int, str], star_count: int, media: List[types.InputPaidMedia],
+ caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None,
+ show_caption_above_media: Optional[bool]=None, disable_notification: Optional[bool]=None,
+ protect_content: Optional[bool]=None, reply_parameters: Optional[types.ReplyParameters]=None,
+ reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message:
+ """
+ Use this method to send paid media to channel chats. On success, the sent Message is returned.
+
+ Telegram documentation: https://core.telegram.org/bots/api#sendpaidmedia
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
+ :type chat_id: :obj:`int` or :obj:`str`
+
+ :param star_count: The number of Telegram Stars that must be paid to buy access to the media
+ :type star_count: :obj:`int`
+
+ :param media: A JSON-serialized array describing the media to be sent; up to 10 items
+ :type media: :obj:`list` of :class:`telebot.types.InputPaidMedia`
+
+ :param caption: Media caption, 0-1024 characters after entities parsing
+ :type caption: :obj:`str`
+
+ :param parse_mode: Mode for parsing entities in the media caption
+ :type parse_mode: :obj:`str`
+
+ :param caption_entities: List of special entities that appear in the caption, which can be specified instead of parse_mode
+ :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
+
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media
+ :type show_caption_above_media: :obj:`bool`
+
+ :param disable_notification: Sends the message silently. Users will receive a notification with no sound.
+ :type disable_notification: :obj:`bool`
+
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :type protect_content: :obj:`bool`
+
+ :param reply_parameters: Description of the message to reply to
+ :type reply_parameters: :class:`telebot.types.ReplyParameters`
+
+ :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user
+ :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply`
+
+ :return: On success, the sent Message is returned.
+ :rtype: :class:`telebot.types.Message`
+ """
+ return types.Message.de_json(
+ await asyncio_helper.send_paid_media(
+ self.token, chat_id, star_count, media, caption=caption, parse_mode=parse_mode,
+ caption_entities=caption_entities, show_caption_above_media=show_caption_above_media,
+ disable_notification=disable_notification, protect_content=protect_content,
+ reply_parameters=reply_parameters, reply_markup=reply_markup)
+ )
async def send_media_group(
self, chat_id: Union[int, str],
@@ -4470,7 +4614,8 @@ async def send_media_group(
allow_sending_without_reply: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> List[types.Message]:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> List[types.Message]:
"""
Use this method to send a group of photos, videos, documents or audios as an album. Documents and audio files
can be only grouped in an album with messages of the same type. On success, an array of Messages that were sent is returned.
@@ -4507,6 +4652,9 @@ async def send_media_group(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, an array of Messages that were sent is returned.
:rtype: List[types.Message]
"""
@@ -4540,7 +4688,7 @@ async def send_media_group(
reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply
result = await asyncio_helper.send_media_group(
- self.token, chat_id, media, disable_notification, timeout, protect_content, message_thread_id, reply_parameters, business_connection_id)
+ self.token, chat_id, media, disable_notification, timeout, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id)
return [types.Message.de_json(msg) for msg in result]
async def send_location(
@@ -4558,7 +4706,8 @@ async def send_location(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send point on the map. On success, the sent Message is returned.
@@ -4573,7 +4722,7 @@ async def send_location(
:param longitude: Longitude of the location
:type longitude: :obj:`float`
- :param live_period: Period in seconds for which the location will be updated (see Live Locations, should be between 60 and 86400.
+ :param live_period: Period in seconds during which the location will be updated (see Live Locations, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely.
:type live_period: :obj:`int`
:param reply_to_message_id: Deprecated - Use reply_parameters instead. If the message is a reply, ID of the original message
@@ -4614,6 +4763,9 @@ async def send_location(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4646,7 +4798,7 @@ async def send_location(
self.token, chat_id, latitude, longitude, live_period,
reply_markup, disable_notification, timeout,
horizontal_accuracy, heading, proximity_alert_radius,
- protect_content, message_thread_id, reply_parameters, business_connection_id))
+ protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
async def edit_message_live_location(
self, latitude: float, longitude: float,
@@ -4657,7 +4809,10 @@ async def edit_message_live_location(
timeout: Optional[int]=None,
horizontal_accuracy: Optional[float]=None,
heading: Optional[int]=None,
- proximity_alert_radius: Optional[int]=None) -> types.Message:
+ proximity_alert_radius: Optional[int]=None,
+ live_period: Optional[int]=None,
+ business_connection_id: Optional[str]=None
+ ) -> types.Message:
"""
Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly
disabled by a call to stopMessageLiveLocation. On success, if the edited message is not an inline message, the edited Message
@@ -4696,6 +4851,12 @@ async def edit_message_live_location(
:param proximity_alert_radius: The maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
:type proximity_alert_radius: :obj:`int`
+ :param live_period: New period in seconds during which the location can be updated, starting from the message send date. If 0x7FFFFFFF is specified, then the location can be updated forever. Otherwise, the new value must not exceed the current live_period by more than a day, and the live location expiration date must remain within the next 90 days. If not specified, then live_period remains unchanged
+ :type live_period: :obj:`int`
+
+ :param business_connection_id: Identifier of a business connection, in which the message will be edited
+ :type business_connection_id: :obj:`str`
+
:return: On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned.
:rtype: :class:`telebot.types.Message` or bool
"""
@@ -4703,14 +4864,16 @@ async def edit_message_live_location(
await asyncio_helper.edit_message_live_location(
self.token, latitude, longitude, chat_id, message_id,
inline_message_id, reply_markup, timeout,
- horizontal_accuracy, heading, proximity_alert_radius))
+ horizontal_accuracy, heading, proximity_alert_radius, live_period=live_period, business_connection_id=business_connection_id)
+ )
async def stop_message_live_location(
self, chat_id: Optional[Union[int, str]]=None,
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
reply_markup: Optional[types.InlineKeyboardMarkup]=None,
- timeout: Optional[int]=None) -> types.Message:
+ timeout: Optional[int]=None,
+ business_connection_id: Optional[str]=None) -> types.Message:
"""
Use this method to stop updating a live location message before live_period expires.
On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
@@ -4733,12 +4896,15 @@ async def stop_message_live_location(
:param timeout: Timeout in seconds for the request.
:type timeout: :obj:`int`
+ :param business_connection_id: Identifier of a business connection, in which the message will be edited
+ :type business_connection_id: :obj:`str`
+
:return: On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned.
:rtype: :class:`telebot.types.Message` or bool
"""
return types.Message.de_json(
await asyncio_helper.stop_message_live_location(
- self.token, chat_id, message_id, inline_message_id, reply_markup, timeout))
+ self.token, chat_id, message_id, inline_message_id, reply_markup, timeout, business_connection_id))
async def send_venue(
self, chat_id: Union[int, str],
@@ -4756,7 +4922,8 @@ async def send_venue(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send information about a venue. On success, the sent Message is returned.
@@ -4820,6 +4987,9 @@ async def send_venue(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4851,7 +5021,7 @@ async def send_venue(
await asyncio_helper.send_venue(
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
disable_notification, reply_markup, timeout,
- google_place_id, google_place_type, protect_content, message_thread_id, reply_parameters, business_connection_id))
+ google_place_id, google_place_type, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
async def send_contact(
@@ -4866,7 +5036,8 @@ async def send_contact(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send phone contacts. On success, the sent Message is returned.
@@ -4917,6 +5088,9 @@ async def send_contact(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Unique identifier of the message effect
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
@@ -4948,7 +5122,7 @@ async def send_contact(
await asyncio_helper.send_contact(
self.token, chat_id, phone_number, first_name, last_name, vcard,
disable_notification, reply_markup, timeout,
- protect_content, message_thread_id, reply_parameters, business_connection_id))
+ protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id))
async def send_chat_action(
@@ -5921,7 +6095,9 @@ async def edit_message_text(
entities: Optional[List[types.MessageEntity]]=None,
disable_web_page_preview: Optional[bool]=None,
reply_markup: Optional[types.InlineKeyboardMarkup]=None,
- link_preview_options: Optional[types.LinkPreviewOptions]=None) -> Union[types.Message, bool]:
+ link_preview_options: Optional[types.LinkPreviewOptions]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit text and game messages.
@@ -5954,6 +6130,12 @@ async def edit_message_text(
:param link_preview_options: A JSON-serialized object for options used to automatically generate Telegram link previews for messages.
:type link_preview_options: :obj:`LinkPreviewOptions`
+ :param business_connection_id: Unique identifier of the business connection
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
@@ -5978,9 +6160,10 @@ async def edit_message_text(
# create a LinkPreviewOptions object
link_preview_options = types.LinkPreviewOptions(is_disabled=self.disable_web_page_preview)
- result = await asyncio_helper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
- entities, reply_markup, link_preview_options)
- if type(result) == bool: # if edit inline message return is bool not Message.
+ result = await asyncio_helper.edit_message_text(
+ self.token, text, chat_id, message_id, inline_message_id, parse_mode, entities, reply_markup,
+ link_preview_options, business_connection_id, timeout)
+ if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)
@@ -5988,7 +6171,9 @@ async def edit_message_media(
self, media: Any, chat_id: Optional[Union[int, str]]=None,
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit animation, audio, document, photo, or video messages.
If a message is a part of a message album, then it can be edited only to a photo or a video.
@@ -6011,11 +6196,18 @@ async def edit_message_media(
:param reply_markup: A JSON-serialized object for an inline keyboard.
:type reply_markup: :obj:`telebot.types.InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply`
+ :param business_connection_id: Unique identifier of the business connection
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
- result = await asyncio_helper.edit_message_media(self.token, media, chat_id, message_id, inline_message_id, reply_markup)
- if type(result) == bool: # if edit inline message return is bool not Message.
+ result = await asyncio_helper.edit_message_media(
+ self.token, media, chat_id, message_id, inline_message_id, reply_markup, business_connection_id, timeout)
+ if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)
@@ -6023,7 +6215,9 @@ async def edit_message_reply_markup(
self, chat_id: Optional[Union[int, str]]=None,
message_id: Optional[int]=None,
inline_message_id: Optional[str]=None,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit only the reply markup of messages.
@@ -6041,11 +6235,18 @@ async def edit_message_reply_markup(
:param reply_markup: A JSON-serialized object for an inline keyboard.
:type reply_markup: :obj:`InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply`
+ :param business_connection_id: Unique identifier of the business connection
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
- result = await asyncio_helper.edit_message_reply_markup(self.token, chat_id, message_id, inline_message_id, reply_markup)
- if type(result) == bool:
+ result = await asyncio_helper.edit_message_reply_markup(
+ self.token, chat_id, message_id, inline_message_id, reply_markup, business_connection_id, timeout)
+ if isinstance(result, bool):
return result
return types.Message.de_json(result)
@@ -6059,7 +6260,8 @@ async def send_game(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Used to send the game.
@@ -6098,6 +6300,9 @@ async def send_game(
:param business_connection_id: Identifier of the business connection.
:type business_connection_id: :obj:`str`
+ :param message_effect_id: Identifier of the message effect.
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
@@ -6128,7 +6333,7 @@ async def send_game(
result = await asyncio_helper.send_game(
self.token, chat_id, game_short_name, disable_notification,
reply_markup, timeout,
- protect_content, message_thread_id, reply_parameters, business_connection_id)
+ protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id)
return types.Message.de_json(result)
async def set_game_score(
@@ -6169,7 +6374,7 @@ async def set_game_score(
"""
result = await asyncio_helper.set_game_score(self.token, user_id, score, force, disable_edit_message, chat_id,
message_id, inline_message_id)
- if type(result) == bool:
+ if isinstance(result, bool):
return result
return types.Message.de_json(result)
@@ -6207,7 +6412,7 @@ async def get_game_high_scores(
async def send_invoice(
self, chat_id: Union[int, str], title: str, description: str,
- invoice_payload: str, provider_token: str, currency: str,
+ invoice_payload: str, provider_token: Union[str, None], currency: str,
prices: List[types.LabeledPrice], start_parameter: Optional[str]=None,
photo_url: Optional[str]=None, photo_size: Optional[int]=None,
photo_width: Optional[int]=None, photo_height: Optional[int]=None,
@@ -6226,7 +6431,8 @@ async def send_invoice(
suggested_tip_amounts: Optional[List[int]]=None,
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
- reply_parameters: Optional[types.ReplyParameters]=None) -> types.Message:
+ reply_parameters: Optional[types.ReplyParameters]=None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Sends invoice.
@@ -6245,7 +6451,8 @@ async def send_invoice(
use for your internal processes.
:type invoice_payload: :obj:`str`
- :param provider_token: Payments provider token, obtained via @Botfather
+ :param provider_token: Payments provider token, obtained via @Botfather; Pass None to omit the parameter
+ to use "XTR" currency
:type provider_token: :obj:`str`
:param currency: Three-letter ISO 4217 currency code,
@@ -6331,6 +6538,9 @@ async def send_invoice(
:param reply_parameters: Reply parameters.
:type reply_parameters: :class:`telebot.types.ReplyParameters`
+ :param message_effect_id: The identifier of a message effect to be applied to the message
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
@@ -6364,12 +6574,13 @@ async def send_invoice(
photo_height, need_name, need_phone_number, need_email, need_shipping_address,
send_phone_number_to_provider, send_email_to_provider, is_flexible, disable_notification,
reply_markup, provider_data, timeout,
- max_tip_amount, suggested_tip_amounts, protect_content, message_thread_id, reply_parameters)
+ max_tip_amount, suggested_tip_amounts, protect_content, message_thread_id, reply_parameters,
+ message_effect_id=message_effect_id)
return types.Message.de_json(result)
async def create_invoice_link(self,
- title: str, description: str, payload:str, provider_token: str,
+ title: str, description: str, payload:str, provider_token: Union[str, None],
currency: str, prices: List[types.LabeledPrice],
max_tip_amount: Optional[int] = None,
suggested_tip_amounts: Optional[List[int]]=None,
@@ -6403,7 +6614,8 @@ async def create_invoice_link(self,
use for your internal processes.
:type payload: :obj:`str`
- :param provider_token: Payments provider token, obtained via @Botfather
+ :param provider_token: Payments provider token, obtained via @Botfather; Pass None to omit the parameter
+ to use "XTR" currency
:type provider_token: :obj:`str`
:param currency: Three-letter ISO 4217 currency code,
@@ -6473,7 +6685,7 @@ async def create_invoice_link(self,
# noinspection PyShadowingBuiltins
async def send_poll(
- self, chat_id: Union[int, str], question: str, options: List[str],
+ self, chat_id: Union[int, str], question: str, options: List[types.InputPollOption],
is_anonymous: Optional[bool]=None, type: Optional[str]=None,
allows_multiple_answers: Optional[bool]=None,
correct_option_id: Optional[int]=None,
@@ -6491,7 +6703,10 @@ async def send_poll(
protect_content: Optional[bool]=None,
message_thread_id: Optional[int]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
- business_connection_id: Optional[str]=None) -> types.Message:
+ business_connection_id: Optional[str]=None,
+ question_parse_mode: Optional[str] = None,
+ question_entities: Optional[List[types.MessageEntity]] = None,
+ message_effect_id: Optional[str]=None) -> types.Message:
"""
Use this method to send a native poll.
On success, the sent Message is returned.
@@ -6504,8 +6719,8 @@ async def send_poll(
:param question: Poll question, 1-300 characters
:type question: :obj:`str`
- :param options: A JSON-serialized list of answer options, 2-10 strings 1-100 characters each
- :type options: :obj:`list` of :obj:`str`
+ :param options: A JSON-serialized list of 2-10 answer options
+ :type options: :obj:`list` of :obj:`InputPollOption`
:param is_anonymous: True, if the poll needs to be anonymous, defaults to True
:type is_anonymous: :obj:`bool`
@@ -6568,6 +6783,15 @@ async def send_poll(
:param business_connection_id: Identifier of the business connection to send the message through
:type business_connection_id: :obj:`str`
+ :param question_parse_mode: Mode for parsing entities in the question. See formatting options for more details. Currently, only custom emoji entities are allowed
+ :type question_parse_mode: :obj:`str`
+
+ :param question_entities: A JSON-serialized list of special entities that appear in the poll question. It can be specified instead of question_parse_mode
+ :type question_entities: :obj:`list` of :obj:`MessageEntity`
+
+ :param message_effect_id: Identifier of the message effect to apply to the sent message
+ :type message_effect_id: :obj:`str`
+
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
@@ -6575,6 +6799,7 @@ async def send_poll(
protect_content = self.protect_content if (protect_content is None) else protect_content
explanation_parse_mode = self.parse_mode if (explanation_parse_mode is None) else explanation_parse_mode
+ question_parse_mode = self.parse_mode if (question_parse_mode is None) else question_parse_mode
if allow_sending_without_reply is not None:
logger.warning("The parameter 'allow_sending_without_reply' is deprecated. Use 'reply_parameters' instead.")
@@ -6599,6 +6824,17 @@ async def send_poll(
if isinstance(question, types.Poll):
raise RuntimeError("The send_poll signature was changed, please see send_poll function details.")
+ if options and (not isinstance(options[0], types.InputPollOption)):
+ # show a deprecation warning
+ logger.warning("The parameter 'options' changed, should be List[types.InputPollOption], other types are deprecated.")
+ # convert options to appropriate type
+ if isinstance(options[0], str):
+ options = [types.InputPollOption(option) for option in options]
+ elif isinstance(options[0], types.PollOption):
+ options = [types.InputPollOption(option.text, text_entities=option.text_entities) for option in options]
+ else:
+ raise RuntimeError("Type of 'options' items is unknown. Options should be List[types.InputPollOption], other types are deprecated.")
+
return types.Message.de_json(
await asyncio_helper.send_poll(
self.token, chat_id,
@@ -6606,11 +6842,14 @@ async def send_poll(
is_anonymous, type, allows_multiple_answers, correct_option_id,
explanation, explanation_parse_mode, open_period, close_date, is_closed,
disable_notification,
- reply_markup, timeout, explanation_entities, protect_content, message_thread_id, reply_parameters, business_connection_id))
+ reply_markup, timeout, explanation_entities, protect_content, message_thread_id, reply_parameters,
+ business_connection_id, question_parse_mode=question_parse_mode, question_entities=question_entities,
+ message_effect_id=message_effect_id))
async def stop_poll(
self, chat_id: Union[int, str], message_id: int,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> types.Poll:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ business_connection_id: Optional[str]=None) -> types.Poll:
"""
Use this method to stop a poll which was sent by the bot. On success, the stopped Poll is returned.
@@ -6625,10 +6864,13 @@ async def stop_poll(
:param reply_markup: A JSON-serialized object for a new message markup.
:type reply_markup: :obj:`InlineKeyboardMarkup`
+ :param business_connection_id: Identifier of the business connection to send the message through
+ :type business_connection_id: :obj:`str`
+
:return: On success, the stopped Poll is returned.
:rtype: :obj:`types.Poll`
"""
- return types.Poll.de_json(await asyncio_helper.stop_poll(self.token, chat_id, message_id, reply_markup))
+ return types.Poll.de_json(await asyncio_helper.stop_poll(self.token, chat_id, message_id, reply_markup, business_connection_id))
async def answer_shipping_query(
self, shipping_query_id: str, ok: bool,
@@ -6685,6 +6927,42 @@ async def answer_pre_checkout_query(
:rtype: :obj:`bool`
"""
return await asyncio_helper.answer_pre_checkout_query(self.token, pre_checkout_query_id, ok, error_message)
+
+
+ async def get_star_transactions(self, offset: Optional[int]=None, limit: Optional[int]=None) -> types.StarTransactions:
+ """
+ Returns the bot's Telegram Star transactions in chronological order.
+
+ Telegram documentation: https://core.telegram.org/bots/api#getstartransactions
+
+ :param offset: Number of transactions to skip in the response
+ :type offset: :obj:`int`
+
+ :param limit: The maximum number of transactions to be retrieved. Values between 1-100 are accepted. Defaults to 100.
+ :type limit: :obj:`int`
+
+ :return: On success, returns a StarTransactions object.
+ :rtype: :obj:`types.StarTransactions`
+ """
+
+ return types.StarTransactions.de_json(await asyncio_helper.get_star_transactions(self.token, offset, limit))
+
+ async def refund_star_payment(self, user_id: int, telegram_payment_charge_id: str) -> bool:
+ """
+ Refunds a successful payment in Telegram Stars. Returns True on success.
+
+ Telegram documentation: https://core.telegram.org/bots/api#refundstarpayment
+
+ :param user_id: Identifier of the user whose payment will be refunded
+ :type user_id: :obj:`int`
+
+ :param telegram_payment_charge_id: Telegram payment identifier
+ :type telegram_payment_charge_id: :obj:`str`
+
+ :return: On success, True is returned.
+ :rtype: :obj:`bool`
+ """
+ return await asyncio_helper.refund_star_payment(self.token, user_id, telegram_payment_charge_id)
async def edit_message_caption(
self, caption: str, chat_id: Optional[Union[int, str]]=None,
@@ -6692,7 +6970,10 @@ async def edit_message_caption(
inline_message_id: Optional[str]=None,
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
- reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]:
+ reply_markup: Optional[types.InlineKeyboardMarkup]=None,
+ show_caption_above_media: Optional[bool]=None,
+ business_connection_id: Optional[str]=None,
+ timeout: Optional[int]=None) -> Union[types.Message, bool]:
"""
Use this method to edit captions of messages.
@@ -6719,14 +7000,25 @@ async def edit_message_caption(
:param reply_markup: A JSON-serialized object for an inline keyboard.
:type reply_markup: :obj:`InlineKeyboardMarkup`
+ :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :type show_caption_above_media: :obj:`bool`
+
+ :param business_connection_id: Identifier of the business connection to send the message through
+ :type business_connection_id: :obj:`str`
+
+ :param timeout: Timeout in seconds for the request.
+ :type timeout: :obj:`int`
+
:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` | :obj:`bool`
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
- result = await asyncio_helper.edit_message_caption(self.token, caption, chat_id, message_id, inline_message_id,
- parse_mode, caption_entities, reply_markup)
- if type(result) == bool:
+ result = await asyncio_helper.edit_message_caption(
+ self.token, caption, chat_id, message_id, inline_message_id, parse_mode, caption_entities, reply_markup,
+ show_caption_above_media=show_caption_above_media, business_connection_id=business_connection_id,
+ timeout=timeout)
+ if isinstance(result, bool):
return result
return types.Message.de_json(result)
diff --git a/telebot/asyncio_filters.py b/telebot/asyncio_filters.py
index 72695e90b..da794b77b 100644
--- a/telebot/asyncio_filters.py
+++ b/telebot/asyncio_filters.py
@@ -27,7 +27,7 @@ def check(self, message):
key: str = None
- async def check(self, message):
+ async def check(self, message) -> bool:
"""
Perform a check.
"""
diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py
index 3aadccc65..b70508a2a 100644
--- a/telebot/asyncio_helper.py
+++ b/telebot/asyncio_helper.py
@@ -130,6 +130,8 @@ def _prepare_data(params=None, files=None):
if isinstance(f, tuple):
if len(f) == 2:
file_name, file = f
+ if isinstance(file, types.InputFile):
+ file = file.file
else:
raise ValueError('Tuple must have exactly 2 elements: filename, fileobj')
elif isinstance(f, types.InputFile):
@@ -281,7 +283,7 @@ async def send_message(
reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, protect_content=None,
- message_thread_id=None, reply_parameters=None, link_preview_options=None, business_connection_id=None):
+ message_thread_id=None, reply_parameters=None, link_preview_options=None, business_connection_id=None, message_effect_id=None):
method_name = 'sendMessage'
params = {'chat_id': str(chat_id), 'text': text}
if link_preview_options is not None:
@@ -304,6 +306,8 @@ async def send_message(
params['message_thread_id'] = message_thread_id
if business_connection_id:
params['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ params['message_effect_id'] = message_effect_id
return await _process_request(token, method_name, params=params)
@@ -414,7 +418,7 @@ async def forward_message(
async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None,
- reply_markup=None, timeout=None, protect_content=None, message_thread_id=None, reply_parameters=None):
+ reply_markup=None, timeout=None, protect_content=None, message_thread_id=None, reply_parameters=None, show_caption_above_media=None):
method_url = r'copyMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if caption is not None:
@@ -422,7 +426,7 @@ async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, p
if parse_mode:
payload['parse_mode'] = parse_mode
if caption_entities is not None:
- payload['caption_entities'] = await _convert_entites(caption_entities)
+ payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if disable_notification is not None:
payload['disable_notification'] = disable_notification
if reply_parameters is not None:
@@ -435,6 +439,8 @@ async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, p
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return await _process_request(token, method_url, params=payload)
@@ -442,7 +448,7 @@ async def send_dice(
token, chat_id,
emoji=None, disable_notification=None,
reply_markup=None, timeout=None, protect_content=None,
- message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@@ -461,6 +467,8 @@ async def send_dice(
payload['reply_parameters'] = json.dumps(reply_parameters.to_dict())
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload)
@@ -470,7 +478,7 @@ async def send_photo(
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, protect_content=None,
message_thread_id=None, has_spoiler=None,reply_parameters=None,
- business_connection_id=None):
+ business_connection_id=None, message_effect_id=None, show_caption_above_media=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@@ -502,13 +510,44 @@ async def send_photo(
payload['has_spoiler'] = has_spoiler
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return await _process_request(token, method_url, params=payload, files=files, method='post')
+async def send_paid_media(
+ token, chat_id, star_count, media,
+ caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None,
+ disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None):
+ method_url = r'sendPaidMedia'
+ media_json, files = convert_input_media_array(media)
+ payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json}
+ if caption:
+ payload['caption'] = caption
+ if parse_mode:
+ payload['parse_mode'] = parse_mode
+ if caption_entities:
+ payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
+ if disable_notification is not None:
+ payload['disable_notification'] = disable_notification
+ if protect_content is not None:
+ payload['protect_content'] = protect_content
+ if reply_parameters is not None:
+ payload['reply_parameters'] = reply_parameters.to_json()
+ if reply_markup:
+ payload['reply_markup'] = _convert_markup(reply_markup)
+ return await _process_request(
+ token, method_url, params=payload,
+ method='post' if files else 'get',
+ files=files if files else None)
async def send_media_group(
token, chat_id, media,
disable_notification=None,
- timeout=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ timeout=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = r'sendMediaGroup'
media_json, files = await convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@@ -524,6 +563,8 @@ async def send_media_group(
payload['reply_parameters'] = json.dumps(reply_parameters.to_dict())
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(
token, method_url, params=payload,
method='post' if files else 'get',
@@ -535,7 +576,8 @@ async def send_location(
live_period=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
- proximity_alert_radius=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ proximity_alert_radius=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@@ -560,13 +602,14 @@ async def send_location(
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload)
async def edit_message_live_location(
- token, latitude, longitude, chat_id=None, message_id=None,
- inline_message_id=None, reply_markup=None, timeout=None,
- horizontal_accuracy=None, heading=None, proximity_alert_radius=None):
+ token, latitude, longitude, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None,
+ timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, live_period=None, business_connection_id=None):
method_url = r'editMessageLiveLocation'
payload = {'latitude': latitude, 'longitude': longitude}
if chat_id:
@@ -579,18 +622,22 @@ async def edit_message_live_location(
payload['heading'] = heading
if proximity_alert_radius:
payload['proximity_alert_radius'] = proximity_alert_radius
+ if live_period:
+ payload['live_period'] = live_period
if inline_message_id:
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = await _convert_markup(reply_markup)
if timeout:
payload['timeout'] = timeout
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
return await _process_request(token, method_url, params=payload)
async def stop_message_live_location(
token, chat_id=None, message_id=None,
- inline_message_id=None, reply_markup=None, timeout=None):
+ inline_message_id=None, reply_markup=None, timeout=None, business_connection_id=None):
method_url = r'stopMessageLiveLocation'
payload = {}
if chat_id:
@@ -603,6 +650,8 @@ async def stop_message_live_location(
payload['reply_markup'] = await _convert_markup(reply_markup)
if timeout:
payload['timeout'] = timeout
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
return await _process_request(token, method_url, params=payload)
@@ -611,7 +660,8 @@ async def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_markup=None, timeout=None,
google_place_id=None,
- google_place_type=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ google_place_type=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@@ -636,13 +686,15 @@ async def send_venue(
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload)
async def send_contact(
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
disable_notification=None, reply_markup=None, timeout=None,
- protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@@ -663,6 +715,8 @@ async def send_contact(
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload)
@@ -681,7 +735,8 @@ async def send_chat_action(token, chat_id, action, timeout=None, message_thread_
async def send_video(token, chat_id, data, duration=None, caption=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumbnail=None, width=None, height=None, caption_entities=None,
- protect_content=None, message_thread_id=None, has_spoiler=None,reply_parameters=None, business_connection_id=None):
+ protect_content=None, message_thread_id=None, has_spoiler=None,reply_parameters=None, business_connection_id=None,
+ message_effect_id=None, show_caption_above_media=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@@ -727,6 +782,10 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_m
payload['has_spoiler'] = has_spoiler
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return await _process_request(token, method_url, params=payload, files=files, method='post')
@@ -734,7 +793,7 @@ async def send_animation(
token, chat_id, data, duration=None, caption=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
width=None, height=None, protect_content=None, message_thread_id=None,
- has_spoiler=None,reply_parameters=None, business_connection_id=None):
+ has_spoiler=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@@ -778,12 +837,16 @@ async def send_animation(
payload['has_spoiler'] = has_spoiler
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
- protect_content=None, message_thread_id=None,reply_parameters=None,business_connection_id=None):
+ protect_content=None, message_thread_id=None,reply_parameters=None,business_connection_id=None, message_effect_id=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@@ -813,12 +876,14 @@ async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_video_note(token, chat_id, data, duration=None, length=None, reply_markup=None,
disable_notification=None, timeout=None, thumbnail=None, protect_content=None,
- message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@@ -854,12 +919,15 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, rep
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
- caption_entities=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ caption_entities=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None,
+ message_effect_id=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@@ -901,13 +969,15 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_data(token, chat_id, data, data_type, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
disable_content_type_detection=None, visible_file_name=None, protect_content=None,
- message_thread_id=None, emoji=None,reply_parameters=None, business_connection_id=None):
+ message_thread_id=None, emoji=None,reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = await get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@@ -950,6 +1020,8 @@ async def send_data(token, chat_id, data, data_type, reply_markup=None, parse_m
payload['emoji'] = emoji
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
@@ -1317,8 +1389,9 @@ async def unpin_all_chat_messages(token, chat_id):
# Updating messages
-async def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None,
- entities = None, reply_markup=None, link_preview_options=None):
+async def edit_message_text(
+ token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, entities = None,
+ reply_markup=None, link_preview_options=None, business_connection_id=None, timeout=None):
method_url = r'editMessageText'
payload = {'text': text}
if chat_id:
@@ -1335,11 +1408,16 @@ async def edit_message_text(token, text, chat_id=None, message_id=None, inline_m
payload['reply_markup'] = await _convert_markup(reply_markup)
if link_preview_options is not None:
payload['link_preview_options'] = link_preview_options.to_json()
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return await _process_request(token, method_url, params=payload, method='post')
-async def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None,
- parse_mode=None, caption_entities=None,reply_markup=None):
+async def edit_message_caption(
+ token, caption, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, caption_entities=None,
+ reply_markup=None, show_caption_above_media=None, business_connection_id=None, timeout=None):
method_url = r'editMessageCaption'
payload = {'caption': caption}
if chat_id:
@@ -1354,10 +1432,18 @@ async def edit_message_caption(token, caption, chat_id=None, message_id=None, in
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if reply_markup:
payload['reply_markup'] = await _convert_markup(reply_markup)
+ if show_caption_above_media is not None:
+ payload['show_caption_above_media'] = show_caption_above_media
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return await _process_request(token, method_url, params=payload, method='post')
-async def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
+async def edit_message_media(
+ token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None,
+ business_connection_id=None, timeout=None):
method_url = r'editMessageMedia'
media_json, file = await convert_input_media(media)
payload = {'media': media_json}
@@ -1369,10 +1455,16 @@ async def edit_message_media(token, media, chat_id=None, message_id=None, inline
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = await _convert_markup(reply_markup)
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return await _process_request(token, method_url, params=payload, files=file, method='post' if file else 'get')
-async def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None):
+async def edit_message_reply_markup(
+ token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, business_connection_id=None,
+ timeout=None):
method_url = r'editMessageReplyMarkup'
payload = {}
if chat_id:
@@ -1383,6 +1475,10 @@ async def edit_message_reply_markup(token, chat_id=None, message_id=None, inline
payload['inline_message_id'] = inline_message_id
if reply_markup:
payload['reply_markup'] = await _convert_markup(reply_markup)
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
+ if timeout:
+ payload['timeout'] = timeout
return await _process_request(token, method_url, params=payload, method='post')
@@ -1399,7 +1495,7 @@ async def delete_message(token, chat_id, message_id, timeout=None):
async def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_markup=None, timeout=None,
- protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None):
+ protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@@ -1416,6 +1512,8 @@ async def send_game(
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload)
@@ -1481,7 +1579,7 @@ async def send_invoice(
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_markup=None, provider_data=None,
timeout=None, max_tip_amount=None, suggested_tip_amounts=None,
- protect_content=None, message_thread_id=None, reply_parameters=None):
+ protect_content=None, message_thread_id=None, reply_parameters=None, message_effect_id=None):
"""
Use this method to send invoices. On success, the sent Message is returned.
:param token: Bot's token (you don't need to fill this)
@@ -1514,12 +1612,13 @@ async def send_invoice(
:param protect_content: Protects the contents of the sent message from forwarding and saving
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:param reply_parameters: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button.
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
:return:
"""
method_url = r'sendInvoice'
payload = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': invoice_payload,
- 'provider_token': provider_token, 'currency': currency,
- 'prices': await _convert_list_json_serializable(prices)}
+ 'currency': currency,
+ 'prices': await _convert_list_json_serializable(prices)}
if start_parameter:
payload['start_parameter'] = start_parameter
if photo_url:
@@ -1562,6 +1661,10 @@ async def send_invoice(
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
+ if provider_token is not None:
+ payload['provider_token'] = provider_token
return await _process_request(token, method_url, params=payload)
@@ -1599,11 +1702,25 @@ async def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_mess
payload['error_message'] = error_message
return await _process_request(token, method_url, params=payload)
+async def get_star_transactions(token, offset=None, limit=None):
+ method_url = 'getStarTransactions'
+ payload = {}
+ if offset:
+ payload['offset'] = offset
+ if limit:
+ payload['limit'] = limit
+ return await _process_request(token, method_url, params=payload)
+
+async def refund_star_payment(token, user_id, telegram_payment_charge_id):
+ method_url = 'refundStarPayment'
+ payload = {'user_id': user_id, 'telegram_payment_charge_id': telegram_payment_charge_id}
+ return await _process_request(token, method_url, params=payload)
+
async def unpin_all_general_forum_topic_messages(token, chat_id):
method_url = 'unpinAllGeneralForumTopicMessages'
payload = {'chat_id': chat_id}
- return await _process_request(token, method_url, params=payload, method='post')
+ return await _process_request(token, method_url, params=payload)
# InlineQuery
@@ -1761,7 +1878,7 @@ async def create_invoice_link(token, title, description, payload, provider_token
need_email=None, need_shipping_address=None, send_phone_number_to_provider=None,
send_email_to_provider=None, is_flexible=None):
method_url = r'createInvoiceLink'
- payload = {'title': title, 'description': description, 'payload': payload, 'provider_token': provider_token,
+ payload = {'title': title, 'description': description, 'payload': payload,
'currency': currency, 'prices': await _convert_list_json_serializable(prices)}
if max_tip_amount:
payload['max_tip_amount'] = max_tip_amount
@@ -1791,23 +1908,26 @@ async def create_invoice_link(token, title, description, payload, provider_token
payload['send_email_to_provider'] = send_email_to_provider
if is_flexible is not None:
payload['is_flexible'] = is_flexible
+ if provider_token is not None:
+ payload['provider_token'] = provider_token
return await _process_request(token, method_url, params=payload, method='post')
# noinspection PyShadowingBuiltins
async def send_poll(
- token, chat_id,
- question, options,
+ token, chat_id, question, options,
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
disable_notification=False,
- reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None,reply_parameters=None,business_connection_id=None):
+ reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None,
+ reply_parameters=None,business_connection_id=None, question_parse_mode=None, question_entities=None, message_effect_id=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
'question': question,
- 'options': json.dumps(await _convert_poll_options(options))}
+ 'options': json.dumps([option.to_dict() for option in options])
+ }
if is_anonymous is not None:
payload['is_anonymous'] = is_anonymous
@@ -1830,7 +1950,6 @@ async def send_poll(
payload['close_date'] = close_date
if is_closed is not None:
payload['is_closed'] = is_closed
-
if disable_notification:
payload['disable_notification'] = disable_notification
if reply_parameters is not None:
@@ -1848,6 +1967,12 @@ async def send_poll(
payload['message_thread_id'] = message_thread_id
if business_connection_id:
payload['business_connection_id'] = business_connection_id
+ if question_parse_mode:
+ payload['question_parse_mode'] = question_parse_mode
+ if question_entities:
+ payload['question_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(question_entities))
+ if message_effect_id:
+ payload['message_effect_id'] = message_effect_id
return await _process_request(token, method_url, params=payload)
@@ -1975,32 +2100,6 @@ async def _convert_list_json_serializable(results):
return '[' + ret + ']'
-
-async def _convert_entites(entites):
- if entites is None:
- return None
- elif len(entites) == 0:
- return []
- elif isinstance(entites[0], types.JsonSerializable):
- return [entity.to_json() for entity in entites]
- else:
- return entites
-
-
-async def _convert_poll_options(poll_options):
- if poll_options is None:
- return None
- elif len(poll_options) == 0:
- return []
- elif isinstance(poll_options[0], str):
- # Compatibility mode with previous bug when only list of string was accepted as poll_options
- return poll_options
- elif isinstance(poll_options[0], types.PollOption):
- return [option.text for option in poll_options]
- else:
- return poll_options
-
-
async def convert_input_media(media):
if isinstance(media, types.InputMedia):
return media.convert_input_media()
@@ -2011,7 +2110,7 @@ async def convert_input_media_array(array):
media = []
files = {}
for input_media in array:
- if isinstance(input_media, types.InputMedia):
+ if isinstance(input_media, types.InputMedia) or isinstance(input_media, types.InputPaidMedia):
media_dict = input_media.to_dict()
if media_dict['media'].startswith('attach://'):
key = media_dict['media'].replace('attach://', '')
@@ -2029,11 +2128,13 @@ def wrapper(key, val):
return wrapper
-async def stop_poll(token, chat_id, message_id, reply_markup=None):
+async def stop_poll(token, chat_id, message_id, reply_markup=None, business_connection_id=None):
method_url = r'stopPoll'
payload = {'chat_id': str(chat_id), 'message_id': message_id}
if reply_markup:
payload['reply_markup'] = await _convert_markup(reply_markup)
+ if business_connection_id:
+ payload['business_connection_id'] = business_connection_id
return await _process_request(token, method_url, params=payload)
# exceptions
diff --git a/telebot/custom_filters.py b/telebot/custom_filters.py
index d4d4ffeca..a1c0aba14 100644
--- a/telebot/custom_filters.py
+++ b/telebot/custom_filters.py
@@ -5,8 +5,6 @@
from telebot import types
-
-
class SimpleCustomFilter(ABC):
"""
Simple Custom Filter base class.
@@ -215,7 +213,7 @@ def check(self, message, text):
"""
if isinstance(text, TextFilter):
return text.check(message)
- elif type(text) is list:
+ elif isinstance(text, list):
return message.text in text
else:
return text == message.text
@@ -311,7 +309,7 @@ def check(self, message):
"""
:meta private:
"""
- return message.forward_date is not None
+ return message.forward_origin is not None
class IsReplyFilter(SimpleCustomFilter):
@@ -353,7 +351,7 @@ def check(self, message, text):
"""
:meta private:
"""
- if type(text) is list:
+ if isinstance(text, list):
return message.from_user.language_code in text
else:
return message.from_user.language_code == text
@@ -433,7 +431,7 @@ def check(self, message, text):
group_state = self.bot.current_states.get_state(chat_id, user_id)
if group_state == text:
return True
- elif type(text) is list and group_state in text:
+ elif isinstance(text, list) and group_state in text:
return True
@@ -441,7 +439,7 @@ def check(self, message, text):
user_state = self.bot.current_states.get_state(chat_id, user_id)
if user_state == text:
return True
- elif type(text) is list and user_state in text:
+ elif isinstance(text, list) and user_state in text:
return True
diff --git a/telebot/formatting.py b/telebot/formatting.py
index e536e1bb0..51869a2a0 100644
--- a/telebot/formatting.py
+++ b/telebot/formatting.py
@@ -403,6 +403,8 @@ def apply_html_entities(text: str, entities: Optional[List], custom_subs: Option
"spoiler": "{text}",
"custom_emoji": "{text}",
"blockquote": "{text}
",
+ "expandable_blockquote": "{text}
",
+
}
if custom_subs:
diff --git a/telebot/types.py b/telebot/types.py
index 7c2782788..6913452be 100644
--- a/telebot/types.py
+++ b/telebot/types.py
@@ -9,6 +9,7 @@
from abc import ABC
try:
+ # noinspection PyPackageRequirements
import ujson as json
except ImportError:
import json
@@ -190,7 +191,7 @@ class Update(JsonDeserializable):
:type edited_business_message: :class:`telebot.types.Message`
:param deleted_business_messages: Optional. Service message: the chat connected to the business account was deleted
- :type deleted_business_messages: :class:`telebot.types.Message`
+ :type deleted_business_messages: :class:`telebot.types.BusinessMessagesDeleted`
:return: Instance of the class
:rtype: :class:`telebot.types.Update`
@@ -226,13 +227,15 @@ def de_json(cls, json_string):
return cls(update_id, message, edited_message, channel_post, edited_channel_post, inline_query,
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer,
- my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count, removed_chat_boost, chat_boost,
- business_connection, business_message, edited_business_message, deleted_business_messages)
+ my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count,
+ removed_chat_boost, chat_boost, business_connection, business_message, edited_business_message,
+ deleted_business_messages)
def __init__(self, update_id, message, edited_message, channel_post, edited_channel_post, inline_query,
chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer,
- my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count, removed_chat_boost, chat_boost,
- business_connection, business_message, edited_business_message, deleted_business_messages, **kwargs):
+ my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count,
+ removed_chat_boost, chat_boost, business_connection, business_message, edited_business_message,
+ deleted_business_messages, **kwargs):
self.update_id = update_id
self.message = message
self.edited_message = edited_message
@@ -284,6 +287,9 @@ class ChatMemberUpdated(JsonDeserializable):
link events only.
:type invite_link: :class:`telebot.types.ChatInviteLink`
+ :param via_join_request: Optional. True, if the user joined the chat after sending a direct join request without using an invite link and being approved by an administrator
+ :type via_join_request: :obj:`bool`
+
:param via_chat_folder_invite_link: Optional. True, if the user joined the chat via a chat folder invite link
:type via_chat_folder_invite_link: :obj:`bool`
@@ -301,7 +307,8 @@ def de_json(cls, json_string):
obj['invite_link'] = ChatInviteLink.de_json(obj.get('invite_link'))
return cls(**obj)
- def __init__(self, chat, from_user, date, old_chat_member, new_chat_member, invite_link=None, via_chat_folder_invite_link=None,
+ def __init__(self, chat, from_user, date, old_chat_member, new_chat_member, invite_link=None,
+ via_join_request=None, via_chat_folder_invite_link=None,
**kwargs):
self.chat: Chat = chat
self.from_user: User = from_user
@@ -309,8 +316,9 @@ def __init__(self, chat, from_user, date, old_chat_member, new_chat_member, invi
self.old_chat_member: ChatMember = old_chat_member
self.new_chat_member: ChatMember = new_chat_member
self.invite_link: Optional[ChatInviteLink] = invite_link
+ self.via_join_request: Optional[bool] = via_join_request
self.via_chat_folder_invite_link: Optional[bool] = via_chat_folder_invite_link
-
+
@property
def difference(self) -> Dict[str, List]:
"""
@@ -495,7 +503,8 @@ def de_json(cls, json_string):
obj = cls.check_json(json_string, dict_copy=False)
return cls(**obj)
- def __init__(self, id, is_bot, first_name, last_name=None, username=None, language_code=None,
+ # noinspection PyShadowingBuiltins
+ def __init__(self, id, is_bot, first_name, last_name=None, username=None, language_code=None,
can_join_groups=None, can_read_all_group_messages=None, supports_inline_queries=None,
is_premium=None, added_to_attachment_menu=None, can_connect_to_business=None, **kwargs):
self.id: int = id
@@ -511,7 +520,6 @@ def __init__(self, id, is_bot, first_name, last_name=None, username=None, langua
self.added_to_attachment_menu: bool = added_to_attachment_menu
self.can_connect_to_business: bool = can_connect_to_business
-
@property
def full_name(self):
"""
@@ -538,9 +546,9 @@ def to_dict(self):
'is_premium': self.is_premium,
'added_to_attachment_menu': self.added_to_attachment_menu,
'can_connect_to_business': self.can_connect_to_business}
-
+# noinspection PyShadowingBuiltins
class GroupChat(JsonDeserializable):
"""
:meta private:
@@ -556,7 +564,8 @@ def __init__(self, id, title, **kwargs):
self.title: str = title
-class Chat(JsonDeserializable):
+# noinspection PyShadowingBuiltins
+class ChatFullInfo(JsonDeserializable):
"""
This object represents a chat.
@@ -585,11 +594,13 @@ class Chat(JsonDeserializable):
:param is_forum: Optional. True, if the supergroup chat is a forum (has topics enabled)
:type is_forum: :obj:`bool`
+ :param max_reaction_count: Optional. The maximum number of reactions that can be set on a message in the chat
+ :type max_reaction_count: :obj:`int`
+
:param photo: Optional. Chat photo. Returned only in getChat.
:type photo: :class:`telebot.types.ChatPhoto`
- :param active_usernames: Optional. If non-empty, the list of all active chat usernames; for private chats, supergroups and channels.
- Returned only in getChat.
+ :param active_usernames: Optional. If non-empty, the list of all active chat usernames; for private chats, supergroups and channels. Returned only in getChat.
:type active_usernames: :obj:`list` of :obj:`str`
:param birthdate: Optional. Birthdate of the other party in a private chat. Returned only in getChat.
@@ -607,100 +618,80 @@ class Chat(JsonDeserializable):
:param personal_chat: Optional. For private chats, the personal channel of the user. Returned only in getChat.
:type personal_chat: :class:`telebot.types.Chat`
- :param available_reactions: Optional. List of available chat reactions; for private chats, supergroups and channels.
- Returned only in getChat.
+ :param available_reactions: Optional. List of available chat reactions; for private chats, supergroups and channels. Returned only in getChat.
:type available_reactions: :obj:`list` of :class:`telebot.types.ReactionType`
:param accent_color_id: Optional. Optional. Identifier of the accent color for the chat name and backgrounds of the chat photo,
reply header, and link preview. See accent colors for more details. Returned only in getChat. Always returned in getChat.
:type accent_color_id: :obj:`int`
- :param background_custom_emoji_id: Optional. Custom emoji identifier of emoji chosen by the chat for the reply header
- and link preview background. Returned only in getChat.
+ :param background_custom_emoji_id: Optional. Custom emoji identifier of emoji chosen by the chat for the reply header and link preview background. Returned only in getChat.
:type background_custom_emoji_id: :obj:`str`
- :param profile_accent_color_id: Optional. Identifier of the accent color for the chat's profile background.
- See profile accent colors for more details. Returned only in getChat.
+ :param profile_accent_color_id: Optional. Identifier of the accent color for the chat's profile background. See profile accent colors for more details. Returned only in getChat.
:type profile_accent_color_id: :obj:`int`
- :param profile_background_custom_emoji_id: Optional. Custom emoji identifier of the emoji chosen by the chat for its profile background.
- Returned only in getChat.
+ :param profile_background_custom_emoji_id: Optional. Custom emoji identifier of the emoji chosen by the chat for its profile background. Returned only in getChat.
:type profile_background_custom_emoji_id: :obj:`str`
- :param emoji_status_custom_emoji_id: Optional. Custom emoji identifier of emoji status of the other party in a private chat.
- Returned only in getChat.
+ :param emoji_status_custom_emoji_id: Optional. Custom emoji identifier of emoji status of the other party in a private chat. Returned only in getChat.
:type emoji_status_custom_emoji_id: :obj:`str`
- :param emoji_status_expiration_date: Optional. Expiration date of the emoji status of the other party in a private chat,
- if any. Returned only in getChat.
+ :param emoji_status_expiration_date: Optional. Expiration date of the emoji status of the other party in a private chat, if any. Returned only in getChat.
:type emoji_status_expiration_date: :obj:`int`
:param bio: Optional. Bio of the other party in a private chat. Returned only in getChat.
:type bio: :obj:`str`
- :param has_private_forwards: Optional. :obj:`bool`, if privacy settings of the other party in the private chat
- allows to use tg://user?id= links only in chats with the user. Returned only in getChat.
+ :param has_private_forwards: Optional. :obj:`bool`, if privacy settings of the other party in the private chat allows to use tg://user?id= links only in chats with the user. Returned only in getChat.
:type has_private_forwards: :obj:`bool`
- :param has_restricted_voice_and_video_messages: Optional. True, if the privacy settings of the other party restrict sending voice and video note messages
- in the private chat. Returned only in getChat.
+ :param has_restricted_voice_and_video_messages: Optional. True, if the privacy settings of the other party restrict sending voice and video note messages in the private chat. Returned only in getChat.
:type :obj:`bool`
- :param join_to_send_messages: Optional. :obj:`bool`, if users need to join the supergroup before they can send
- messages. Returned only in getChat.
+ :param join_to_send_messages: Optional. :obj:`bool`, if users need to join the supergroup before they can send messages. Returned only in getChat.
:type join_to_send_messages: :obj:`bool`
- :param join_by_request: Optional. :obj:`bool`, if all users directly joining the supergroup need to be approved
- by supergroup administrators. Returned only in getChat.
+ :param join_by_request: Optional. :obj:`bool`, if all users directly joining the supergroup need to be approved by supergroup administrators. Returned only in getChat.
:type join_by_request: :obj:`bool`
:param description: Optional. Description, for groups, supergroups and channel chats. Returned only in getChat.
:type description: :obj:`str`
- :param invite_link: Optional. Primary invite link, for groups, supergroups and channel chats. Returned only in
- getChat.
+ :param invite_link: Optional. Primary invite link, for groups, supergroups and channel chats. Returned only in getChat.
:type invite_link: :obj:`str`
:param pinned_message: Optional. The most recent pinned message (by sending date). Returned only in getChat.
:type pinned_message: :class:`telebot.types.Message`
- :param permissions: Optional. Default chat member permissions, for groups and supergroups. Returned only in
- getChat.
+ :param permissions: Optional. Default chat member permissions, for groups and supergroups. Returned only in getChat.
:type permissions: :class:`telebot.types.ChatPermissions`
- :param slow_mode_delay: Optional. For supergroups, the minimum allowed delay between consecutive messages sent
- by each unpriviledged user; in seconds. Returned only in getChat.
+ :param slow_mode_delay: Optional. For supergroups, the minimum allowed delay between consecutive messages sent by each unpriviledged user; in seconds. Returned only in getChat.
:type slow_mode_delay: :obj:`int`
- :param unrestrict_boost_count: Optional. For supergroups, the minimum number of boosts that a non-administrator
- user needs to add in order to ignore slow mode and chat permissions. Returned only in getChat.
+ :param unrestrict_boost_count: Optional. For supergroups, the minimum number of boosts that a non-administrator user needs to add in order to ignore slow mode and chat permissions. Returned only in getChat.
:type unrestrict_boost_count: :obj:`int`
- :param message_auto_delete_time: Optional. The time after which all messages sent to the chat will be
- automatically deleted; in seconds. Returned only in getChat.
+ :param message_auto_delete_time: Optional. The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in getChat.
:type message_auto_delete_time: :obj:`int`
- :param has_aggressive_anti_spam_enabled: Optional. :obj:`bool`, if the chat has enabled aggressive anti-spam
- protection. Returned only in getChat.
+ :param has_aggressive_anti_spam_enabled: Optional. :obj:`bool`, if the chat has enabled aggressive anti-spam protection. Returned only in getChat.
:type has_aggressive_anti_spam_enabled: :obj:`bool`
- :param has_hidden_members: Optional. :obj:`bool`, if the chat has enabled hidden members. Returned only in
- getChat.
+ :param has_hidden_members: Optional. :obj:`bool`, if the chat has enabled hidden members. Returned only in getChat.
:type has_hidden_members: :obj:`bool`
- :param has_protected_content: Optional. :obj:`bool`, if messages from the chat can't be forwarded to other
- chats. Returned only in getChat.
+ :param has_protected_content: Optional. :obj:`bool`, if messages from the chat can't be forwarded to other chats. Returned only in getChat.
:type has_protected_content: :obj:`bool`
- :param has_visible_history: Optional. True, if new chat members will have access to old messages;
- available only to chat administrators. Returned only in getChat.
+ :param has_visible_history: Optional. True, if new chat members will have access to old messages; available only to chat administrators. Returned only in getChat.
:type has_visible_history: :obj:`bool`
:param sticker_set_name: Optional. For supergroups, name of group sticker set. Returned only in getChat.
:type sticker_set_name: :obj:`str`
- :param can_set_sticker_set: Optional. :obj:`bool`, if the bot can change the group sticker set. Returned only in
- getChat.
+ :param can_set_sticker_set: Optional. :obj:`bool`, if the bot can change the group sticker set. Returned only in getChat.
:type can_set_sticker_set: :obj:`bool`
:param custom_emoji_sticker_set_name: Optional. For supergroups, the name of the group's custom emoji sticker set.
@@ -713,12 +704,15 @@ class Chat(JsonDeserializable):
signed 64 bit integer or double-precision float type are safe for storing this identifier. Returned only in getChat.
:type linked_chat_id: :obj:`int`
- :param location: Optional. For supergroups, the location to which the supergroup is connected. Returned only in
- getChat.
+ :param location: Optional. For supergroups, the location to which the supergroup is connected. Returned only in getChat.
:type location: :class:`telebot.types.ChatLocation`
+ :param can_send_paid_media: Optional. True, if paid media messages can be sent or forwarded to the channel chat.
+ The field is available only for channel chats.
+ :type can_send_paid_media: :obj:`bool`
+
:return: Instance of the class
- :rtype: :class:`telebot.types.Chat`
+ :rtype: :class:`telebot.types.ChatFullInfo`
"""
@classmethod
def de_json(cls, json_string):
@@ -753,12 +747,13 @@ def __init__(self, id, type, title=None, username=None, first_name=None,
message_auto_delete_time=None, has_protected_content=None, sticker_set_name=None,
can_set_sticker_set=None, linked_chat_id=None, location=None,
join_to_send_messages=None, join_by_request=None, has_restricted_voice_and_video_messages=None,
- is_forum=None, active_usernames=None, emoji_status_custom_emoji_id=None,
+ is_forum=None, max_reaction_count=None, active_usernames=None, emoji_status_custom_emoji_id=None,
has_hidden_members=None, has_aggressive_anti_spam_enabled=None, emoji_status_expiration_date=None,
available_reactions=None, accent_color_id=None, background_custom_emoji_id=None, profile_accent_color_id=None,
profile_background_custom_emoji_id=None, has_visible_history=None,
unrestrict_boost_count=None, custom_emoji_sticker_set_name=None, business_intro=None, business_location=None,
- business_opening_hours=None, personal_chat=None, birthdate=None, **kwargs):
+ business_opening_hours=None, personal_chat=None, birthdate=None,
+ can_send_paid_media=None, **kwargs):
self.id: int = id
self.type: str = type
self.title: str = title
@@ -766,6 +761,7 @@ def __init__(self, id, type, title=None, username=None, first_name=None,
self.first_name: str = first_name
self.last_name: str = last_name
self.is_forum: bool = is_forum
+ self.max_reaction_count: int = max_reaction_count
self.photo: ChatPhoto = photo
self.bio: str = bio
self.join_to_send_messages: bool = join_to_send_messages
@@ -801,8 +797,20 @@ def __init__(self, id, type, title=None, username=None, first_name=None,
self.business_opening_hours: BusinessOpeningHours = business_opening_hours
self.personal_chat: Chat = personal_chat
self.birthdate: Birthdate = birthdate
+ self.can_send_paid_media: bool = can_send_paid_media
+class Chat(ChatFullInfo):
+ """
+ In BotAPI 7.3 Chat was reduced and full info moved to ChatFullInfo:
+ "Split out the class ChatFullInfo from the class Chat and changed the return type of the method getChat to ChatFullInfo."
+
+ https://core.telegram.org/bots/api#chatfullinfo
+
+ Currently Chat is left as full copy of ChatFullInfo for compatibility.
+ """
+ pass
+
class MessageID(JsonDeserializable):
"""
@@ -949,6 +957,9 @@ class Message(JsonDeserializable):
if it is a text message and link preview options were changed
:type link_preview_options: :class:`telebot.types.LinkPreviewOptions`
+ :param effect_id: Optional. Unique identifier of the message effect added to the message
+ :type effect_id: :obj:`str`
+
:param animation: Optional. Message is an animation, information about the animation. For backward
compatibility, when this field is set, the document field will also be set
:type animation: :class:`telebot.types.Animation`
@@ -959,6 +970,9 @@ class Message(JsonDeserializable):
:param document: Optional. Message is a general file, information about the file
:type document: :class:`telebot.types.Document`
+ :param paid_media: Optional. Message contains paid media; information about the paid media
+ :type paid_media: :class:`telebot.types.PaidMediaInfo`
+
:param photo: Optional. Message is a photo, available sizes of the photo
:type photo: :obj:`list` of :class:`telebot.types.PhotoSize`
@@ -984,6 +998,9 @@ class Message(JsonDeserializable):
commands, etc. that appear in the caption
:type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
+ :param show_caption_above_media: Optional. True, if the caption must be shown above the message media
+ :type show_caption_above_media: :obj:`bool`
+
:param has_media_spoiler: Optional. True, if the message media is covered by a spoiler animation
:type has_media_spoiler: :obj:`bool`
@@ -1063,6 +1080,9 @@ class Message(JsonDeserializable):
the payment. More about payments »
:type successful_payment: :class:`telebot.types.SuccessfulPayment`
+ :param refunded_payment: Optional. Message is a service message about a refunded payment, information about the payment. More about payments »
+ :type refunded_payment: :class:`telebot.types.RefundedPayment`
+
:param users_shared: Optional. Service message: a user was shared with the bot
:type users_shared: :class:`telebot.types.UsersShared`
@@ -1087,6 +1107,9 @@ class Message(JsonDeserializable):
:param boost_added: Optional. Service message: user boosted the chat
:type boost_added: :class:`telebot.types.ChatBoostAdded`
+ :param chat_background_set: Optional. Service message: chat background set
+ :type chat_background_set: :class:`telebot.types.ChatBackground`
+
:param forum_topic_created: Optional. Service message: forum topic created
:type forum_topic_created: :class:`telebot.types.ForumTopicCreated`
@@ -1132,8 +1155,7 @@ class Message(JsonDeserializable):
:param web_app_data: Optional. Service message: data sent by a Web App
:type web_app_data: :class:`telebot.types.WebAppData`
- :param reply_markup: Optional. Inline keyboard attached to the message. login_url buttons are represented as
- ordinary url buttons.
+ :param reply_markup: Optional. Inline keyboard attached to the message. login_url buttons are represented as ordinary url buttons.
:type reply_markup: :class:`telebot.types.InlineKeyboardMarkup`
:return: Instance of the class
@@ -1298,6 +1320,9 @@ def de_json(cls, json_string):
content_type = 'message_auto_delete_timer_changed'
if 'reply_markup' in obj:
opts['reply_markup'] = InlineKeyboardMarkup.de_json(obj['reply_markup'])
+ if 'chat_background_set' in obj:
+ opts['chat_background_set'] = ChatBackground.de_json(obj['chat_background_set'])
+ content_type = 'chat_background_set'
if 'forum_topic_created' in obj:
opts['forum_topic_created'] = ForumTopicCreated.de_json(obj['forum_topic_created'])
content_type = 'forum_topic_created'
@@ -1363,8 +1388,14 @@ def de_json(cls, json_string):
opts['business_connection_id'] = obj['business_connection_id']
if 'is_from_offline' in obj:
opts['is_from_offline'] = obj['is_from_offline']
-
-
+ if 'effect_id' in obj:
+ opts['effect_id'] = obj['effect_id']
+ if 'show_caption_above_media' in obj:
+ opts['show_caption_above_media'] = obj['show_caption_above_media']
+ if 'paid_media' in obj:
+ opts['paid_media'] = PaidMediaInfo.de_json(obj['paid_media'])
+ if 'refunded_payment' in obj:
+ opts['refunded_payment'] = RefundedPayment.de_json(obj['refunded_payment'])
return cls(message_id, from_user, date, chat, content_type, opts, json_string)
@@ -1446,6 +1477,7 @@ def __init__(self, message_id, from_user, date, chat, content_type, options, jso
self.reply_markup: Optional[InlineKeyboardMarkup] = None
self.message_thread_id: Optional[int] = None
self.is_topic_message: Optional[bool] = None
+ self.chat_background_set: Optional[ChatBackground] = None
self.forum_topic_created: Optional[ForumTopicCreated] = None
self.forum_topic_closed: Optional[ForumTopicClosed] = None
self.forum_topic_reopened: Optional[ForumTopicReopened] = None
@@ -1471,6 +1503,10 @@ def __init__(self, message_id, from_user, date, chat, content_type, options, jso
self.sender_business_bot: Optional[User] = None
self.business_connection_id: Optional[str] = None
self.is_from_offline: Optional[bool] = None
+ self.effect_id: Optional[str] = None
+ self.show_caption_above_media: Optional[bool] = None
+ self.paid_media : Optional[PaidMediaInfo] = None
+ self.refunded_payment : Optional[RefundedPayment] = None
for key in options:
setattr(self, key, options[key])
@@ -1571,18 +1607,19 @@ def user_shared(self):
return self.users_shared
+# noinspection PyShadowingBuiltins
class MessageEntity(Dictionaryable, JsonSerializable, JsonDeserializable):
"""
This object represents one special entity in a text message. For example, hashtags, usernames, URLs, etc.
Telegram Documentation: https://core.telegram.org/bots/api#messageentity
- :param type: Type of the entity. Currently, can be “mention” (@username), “hashtag” (#hashtag), “cashtag”
- ($USD), “bot_command” (/start@jobs_bot), “url” (https://telegram.org), “email”
- (do-not-reply@telegram.org), “phone_number” (+1-212-555-0123), “bold” (bold text), “italic” (italic text),
- “underline” (underlined text), “strikethrough” (strikethrough text), “spoiler” (spoiler message), “code”
- (monowidth string), “pre” (monowidth block), “text_link” (for clickable text URLs), “text_mention” (for users
- without usernames), “custom_emoji” (for inline custom emoji stickers)
+ :param type: Type of the entity. Currently, can be “mention” (@username), “hashtag” (#hashtag), “cashtag” ($USD),
+ “bot_command” (/start@jobs_bot),“url” (https://telegram.org), “email” (do-not-reply@telegram.org), “phone_number” (+1-212-555-0123),
+ “bold” (bold text), “italic” (italic text), “underline” (underlined text), “strikethrough” (strikethrough text),
+ “spoiler” (spoiler message), “blockquote” (block quotation), “expandable_blockquote” (collapsed-by-default block quotation),
+ “code” (monowidth string), “pre” (monowidth block), “text_link” (for clickable text URLs),
+ “text_mention” (for users without usernames), “custom_emoji” (for inline custom emoji stickers)
:type type: :obj:`str`
:param offset: Offset in UTF-16 code units to the start of the entity
@@ -1612,10 +1649,12 @@ def to_list_of_dicts(entity_list) -> Union[List[Dict], None]:
"""
Converts a list of MessageEntity objects to a list of dictionaries.
"""
- res = []
- for e in entity_list:
- res.append(MessageEntity.to_dict(e))
- return res or None
+ if entity_list is None or len(entity_list) == 0:
+ return None
+ elif isinstance(entity_list[0], MessageEntity):
+ return [MessageEntity.to_dict(e) for e in entity_list]
+ else:
+ return entity_list
@classmethod
def de_json(cls, json_string):
@@ -1642,8 +1681,8 @@ def to_dict(self):
"offset": self.offset,
"length": self.length,
"url": self.url,
- "user": self.user,
- "language": self.language,
+ "user": self.user.to_dict() if self.user else None,
+ "language": self.language,
"custom_emoji_id": self.custom_emoji_id}
@@ -2446,20 +2485,20 @@ def to_json(self):
return json.dumps(json_dict)
+# noinspection PyShadowingBuiltins
class KeyboardButtonPollType(Dictionaryable):
"""
This object represents type of a poll, which is allowed to be created and sent when the corresponding button is pressed.
Telegram Documentation: https://core.telegram.org/bots/api#keyboardbuttonpolltype
- :param type: Optional. If quiz is passed, the user will be allowed to create only polls in the quiz mode. If regular is
- passed, only regular polls will be allowed. Otherwise, the user will be allowed to create a poll of any type.
+ :param type: Optional. If quiz is passed, the user will be allowed to create only polls in the quiz mode. If regular is passed, only regular polls will be allowed. Otherwise, the user will be allowed to create a poll of any type.
:type type: :obj:`str`
:return: Instance of the class
:rtype: :class:`telebot.types.KeyboardButtonPollType`
"""
- def __init__(self, type=''):
+ def __init__(self, type=None):
self.type: str = type
def to_dict(self):
@@ -2976,6 +3015,7 @@ def to_dict(self):
return json_dict
+# noinspection PyShadowingBuiltins
class CallbackQuery(JsonDeserializable):
"""
This object represents an incoming callback query from a callback button in an inline keyboard. If the button that originated the query was attached to a message sent by the bot, the field message will be present. If the button was attached to a message sent via the bot (in inline mode), the field inline_message_id will be present. Exactly one of the fields data or game_short_name will be present.
@@ -3570,6 +3610,7 @@ def to_dict(self):
# BotCommandScopes
+# noinspection PyShadowingBuiltins
class BotCommandScope(ABC, JsonSerializable):
"""
This object represents the scope to which bot commands are applied. Currently, the following 7 scopes are supported:
@@ -3775,6 +3816,7 @@ def __init__(self, chat_id=None, user_id=None):
# InlineQuery
+# noinspection PyShadowingBuiltins
class InlineQuery(JsonDeserializable):
"""
This object represents an incoming inline query. When the user sends an empty query, your bot could return some default or trending results.
@@ -3890,16 +3932,13 @@ class InputLocationMessageContent(Dictionaryable):
:param horizontal_accuracy: Optional. The radius of uncertainty for the location, measured in meters; 0-1500
:type horizontal_accuracy: :obj:`float` number
- :param live_period: Optional. Period in seconds for which the location can be updated, should be between 60 and
- 86400.
+ :param live_period: Optional. Period in seconds during which the location can be updated, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely.
:type live_period: :obj:`int`
- :param heading: Optional. For live locations, a direction in which the user is moving, in degrees. Must be between 1
- and 360 if specified.
+ :param heading: Optional. For live locations, a direction in which the user is moving, in degrees. Must be between 1 and 360 if specified.
:type heading: :obj:`int`
- :param proximity_alert_radius: Optional. For live locations, a maximum distance for proximity alerts about
- approaching another chat member, in meters. Must be between 1 and 100000 if specified.
+ :param proximity_alert_radius: Optional. For live locations, a maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
:type proximity_alert_radius: :obj:`int`
:return: Instance of the class
@@ -4304,7 +4343,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultArticle(InlineQueryResultBase):
"""
Represents a link to an article or web page.
@@ -4389,7 +4428,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultPhoto(InlineQueryResultBase):
"""
Represents a link to a photo. By default, this photo will be sent by the user with optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the photo.
@@ -4437,11 +4476,15 @@ class InlineQueryResultPhoto(InlineQueryResultBase):
:param input_message_content: Optional. Content of the message to be sent instead of the photo
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. If true, a caption is shown over the photo or video
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultPhoto`
"""
def __init__(self, id, photo_url, thumbnail_url, photo_width=None, photo_height=None, title=None,
- description=None, caption=None, caption_entities=None, parse_mode=None, reply_markup=None, input_message_content=None):
+ description=None, caption=None, caption_entities=None, parse_mode=None, reply_markup=None, input_message_content=None,
+ show_caption_above_media=None):
super().__init__('photo', id, title = title, caption = caption,
input_message_content = input_message_content, reply_markup = reply_markup,
parse_mode = parse_mode, caption_entities = caption_entities)
@@ -4450,6 +4493,7 @@ def __init__(self, id, photo_url, thumbnail_url, photo_width=None, photo_height=
self.photo_width = photo_width
self.photo_height = photo_height
self.description = description
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
@property
def thumb_url(self):
@@ -4466,10 +4510,12 @@ def to_dict(self):
json_dict['photo_height'] = self.photo_height
if self.description:
json_dict['description'] = self.description
+ if self.show_caption_above_media is not None:
+ json_dict['show_caption_above_media'] = self.show_caption_above_media
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultGif(InlineQueryResultBase):
"""
Represents a link to an animated GIF file. By default, this animated GIF file will be sent by the user with optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the animation.
@@ -4520,13 +4566,16 @@ class InlineQueryResultGif(InlineQueryResultBase):
:param input_message_content: Optional. Content of the message to be sent instead of the GIF animation
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. If true, a caption is shown over the photo or video
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultGif`
"""
def __init__(self, id, gif_url, thumbnail_url, gif_width=None, gif_height=None,
title=None, caption=None, caption_entities=None,
reply_markup=None, input_message_content=None, gif_duration=None, parse_mode=None,
- thumbnail_mime_type=None):
+ thumbnail_mime_type=None, show_caption_above_media=None):
super().__init__('gif', id, title = title, caption = caption,
input_message_content = input_message_content, reply_markup = reply_markup,
parse_mode = parse_mode, caption_entities = caption_entities)
@@ -4536,6 +4585,7 @@ def __init__(self, id, gif_url, thumbnail_url, gif_width=None, gif_height=None,
self.thumbnail_url = thumbnail_url
self.gif_duration = gif_duration
self.thumbnail_mime_type = thumbnail_mime_type
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
@property
def thumb_url(self):
@@ -4559,10 +4609,12 @@ def to_dict(self):
json_dict['gif_duration'] = self.gif_duration
if self.thumbnail_mime_type:
json_dict['thumbnail_mime_type'] = self.thumbnail_mime_type
+ if self.show_caption_above_media is not None:
+ json_dict['show_caption_above_media'] = self.show_caption_above_media
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultMpeg4Gif(InlineQueryResultBase):
"""
Represents a link to a video animation (H.264/MPEG-4 AVC video without sound). By default, this animated MPEG-4 file will be sent by the user with optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the animation.
@@ -4613,13 +4665,16 @@ class InlineQueryResultMpeg4Gif(InlineQueryResultBase):
:param input_message_content: Optional. Content of the message to be sent instead of the video animation
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. If true, a caption is shown over the photo or video
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultMpeg4Gif`
"""
def __init__(self, id, mpeg4_url, thumbnail_url, mpeg4_width=None, mpeg4_height=None,
title=None, caption=None, caption_entities=None,
parse_mode=None, reply_markup=None, input_message_content=None, mpeg4_duration=None,
- thumbnail_mime_type=None):
+ thumbnail_mime_type=None, show_caption_above_media=None):
super().__init__('mpeg4_gif', id, title = title, caption = caption,
input_message_content = input_message_content, reply_markup = reply_markup,
parse_mode = parse_mode, caption_entities = caption_entities)
@@ -4629,6 +4684,7 @@ def __init__(self, id, mpeg4_url, thumbnail_url, mpeg4_width=None, mpeg4_height=
self.thumbnail_url = thumbnail_url
self.mpeg4_duration = mpeg4_duration
self.thumbnail_mime_type = thumbnail_mime_type
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
@property
def thumb_url(self):
@@ -4652,10 +4708,12 @@ def to_dict(self):
json_dict['mpeg4_duration '] = self.mpeg4_duration
if self.thumbnail_mime_type:
json_dict['thumbnail_mime_type'] = self.thumbnail_mime_type
+ if self.show_caption_above_media is not None:
+ json_dict['show_caption_above_media'] = self.show_caption_above_media
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultVideo(InlineQueryResultBase):
"""
Represents a link to a page containing an embedded video player or a video file. By default, this video file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the video.
@@ -4710,13 +4768,16 @@ class InlineQueryResultVideo(InlineQueryResultBase):
required if InlineQueryResultVideo is used to send an HTML-page as a result (e.g., a YouTube video).
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. If true, a caption is shown over the video
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultVideo`
"""
def __init__(self, id, video_url, mime_type, thumbnail_url,
title, caption=None, caption_entities=None, parse_mode=None,
video_width=None, video_height=None, video_duration=None,
- description=None, reply_markup=None, input_message_content=None):
+ description=None, reply_markup=None, input_message_content=None, show_caption_above_media=None):
super().__init__('video', id, title = title, caption = caption,
input_message_content = input_message_content, reply_markup = reply_markup,
parse_mode = parse_mode, caption_entities = caption_entities)
@@ -4727,6 +4788,7 @@ def __init__(self, id, video_url, mime_type, thumbnail_url,
self.video_height = video_height
self.video_duration = video_duration
self.description = description
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
@property
def thumb_url(self):
@@ -4744,10 +4806,12 @@ def to_dict(self):
json_dict['video_duration'] = self.video_duration
if self.description:
json_dict['description'] = self.description
+ if self.show_caption_above_media is not None:
+ json_dict['show_caption_above_media'] = self.show_caption_above_media
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultAudio(InlineQueryResultBase):
"""
Represents a link to an MP3 audio file. By default, this audio file will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the audio.
@@ -4812,7 +4876,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultVoice(InlineQueryResultBase):
"""
Represents a link to a voice recording in an .OGG container encoded with OPUS. By default, this voice recording will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the the voice message.
@@ -4870,7 +4934,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultDocument(InlineQueryResultBase):
"""
Represents a link to a file. By default, this file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the file. Currently, only .PDF and .ZIP files can be sent using this method.
@@ -4967,7 +5031,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultLocation(InlineQueryResultBase):
"""
Represents a location on a map. By default, the location will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the location.
@@ -4992,16 +5056,13 @@ class InlineQueryResultLocation(InlineQueryResultBase):
:param horizontal_accuracy: Optional. The radius of uncertainty for the location, measured in meters; 0-1500
:type horizontal_accuracy: :obj:`float` number
- :param live_period: Optional. Period in seconds for which the location can be updated, should be between 60 and
- 86400.
+ :param live_period: Optional. Period in seconds during which the location can be updated, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely.
:type live_period: :obj:`int`
- :param heading: Optional. For live locations, a direction in which the user is moving, in degrees. Must be between 1
- and 360 if specified.
+ :param heading: Optional. For live locations, a direction in which the user is moving, in degrees. Must be between 1 and 360 if specified.
:type heading: :obj:`int`
- :param proximity_alert_radius: Optional. For live locations, a maximum distance for proximity alerts about
- approaching another chat member, in meters. Must be between 1 and 100000 if specified.
+ :param proximity_alert_radius: Optional. For live locations, a maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
:type proximity_alert_radius: :obj:`int`
:param reply_markup: Optional. Inline keyboard attached to the message
@@ -5072,7 +5133,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultVenue(InlineQueryResultBase):
"""
Represents a venue. By default, the venue will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the venue.
@@ -5181,7 +5242,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultContact(InlineQueryResultBase):
"""
Represents a contact with a phone number. By default, this contact will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the contact.
@@ -5269,7 +5330,7 @@ def to_dict(self):
return json_dict
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultGame(InlineQueryResultBase):
"""
Represents a Game.
@@ -5316,6 +5377,7 @@ def __init__(self):
self.parse_mode = None
self.caption_entities = None
self.payload_dic = {}
+ self.show_caption_above_media = None
def to_json(self):
json_dict = self.payload_dic
@@ -5335,10 +5397,12 @@ def to_json(self):
json_dict['parse_mode'] = self.parse_mode
if self.caption_entities:
json_dict['caption_entities'] = MessageEntity.to_list_of_dicts(self.caption_entities)
+ if self.show_caption_above_media is not None:
+ json_dict['show_caption_above_media'] = self.show_caption_above_media
return json.dumps(json_dict)
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedPhoto(InlineQueryResultCachedBase):
"""
Represents a link to a photo stored on the Telegram servers. By default, this photo will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the photo.
@@ -5377,12 +5441,15 @@ class InlineQueryResultCachedPhoto(InlineQueryResultCachedBase):
:param input_message_content: Optional. Content of the message to be sent instead of the photo
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. Pass True, if a caption is not required for the media
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultCachedPhoto`
"""
def __init__(self, id, photo_file_id, title=None, description=None,
caption=None, caption_entities = None, parse_mode=None,
- reply_markup=None, input_message_content=None):
+ reply_markup=None, input_message_content=None, show_caption_above_media=None):
InlineQueryResultCachedBase.__init__(self)
self.type = 'photo'
self.id = id
@@ -5395,9 +5462,10 @@ def __init__(self, id, photo_file_id, title=None, description=None,
self.input_message_content = input_message_content
self.parse_mode = parse_mode
self.payload_dic['photo_file_id'] = photo_file_id
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedGif(InlineQueryResultCachedBase):
"""
Represents a link to an animated GIF file stored on the Telegram servers. By default, this animated GIF file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with specified content instead of the animation.
@@ -5432,12 +5500,15 @@ class InlineQueryResultCachedGif(InlineQueryResultCachedBase):
:param input_message_content: Optional. Content of the message to be sent instead of the GIF animation
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. Pass True, if a caption is not required for the media
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultCachedGif`
"""
def __init__(self, id, gif_file_id, title=None, description=None,
caption=None, caption_entities = None, parse_mode=None,
- reply_markup=None, input_message_content=None):
+ reply_markup=None, input_message_content=None, show_caption_above_media=None):
InlineQueryResultCachedBase.__init__(self)
self.type = 'gif'
self.id = id
@@ -5450,9 +5521,10 @@ def __init__(self, id, gif_file_id, title=None, description=None,
self.input_message_content = input_message_content
self.parse_mode = parse_mode
self.payload_dic['gif_file_id'] = gif_file_id
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedMpeg4Gif(InlineQueryResultCachedBase):
"""
Represents a link to a video animation (H.264/MPEG-4 AVC video without sound) stored on the Telegram servers. By default, this animated MPEG-4 file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the animation.
@@ -5487,12 +5559,15 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResultCachedBase):
:param input_message_content: Optional. Content of the message to be sent instead of the video animation
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. Pass True, if caption should be shown above the media
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultCachedMpeg4Gif`
"""
def __init__(self, id, mpeg4_file_id, title=None, description=None,
caption=None, caption_entities = None, parse_mode=None,
- reply_markup=None, input_message_content=None):
+ reply_markup=None, input_message_content=None, show_caption_above_media=None):
InlineQueryResultCachedBase.__init__(self)
self.type = 'mpeg4_gif'
self.id = id
@@ -5505,9 +5580,9 @@ def __init__(self, id, mpeg4_file_id, title=None, description=None,
self.input_message_content = input_message_content
self.parse_mode = parse_mode
self.payload_dic['mpeg4_file_id'] = mpeg4_file_id
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
-
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedSticker(InlineQueryResultCachedBase):
"""
Represents a link to a sticker stored on the Telegram servers. By default, this sticker will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the sticker.
@@ -5542,7 +5617,7 @@ def __init__(self, id, sticker_file_id, reply_markup=None, input_message_content
self.payload_dic['sticker_file_id'] = sticker_file_id
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedDocument(InlineQueryResultCachedBase):
"""
Represents a link to a file stored on the Telegram servers. By default, this file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the file.
@@ -5601,7 +5676,7 @@ def __init__(self, id, document_file_id, title, description=None,
self.payload_dic['document_file_id'] = document_file_id
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedVideo(InlineQueryResultCachedBase):
"""
Represents a link to a video file stored on the Telegram servers. By default, this video file will be sent by the user with an optional caption. Alternatively, you can use input_message_content to send a message with the specified content instead of the video.
@@ -5640,13 +5715,16 @@ class InlineQueryResultCachedVideo(InlineQueryResultCachedBase):
:param input_message_content: Optional. Content of the message to be sent instead of the video
:type input_message_content: :class:`telebot.types.InputMessageContent`
+ :param show_caption_above_media: Optional. Pass True, if a caption is not required for the media
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InlineQueryResultCachedVideo`
"""
def __init__(self, id, video_file_id, title, description=None,
caption=None, caption_entities = None, parse_mode=None,
reply_markup=None,
- input_message_content=None):
+ input_message_content=None, show_caption_above_media=None):
InlineQueryResultCachedBase.__init__(self)
self.type = 'video'
self.id = id
@@ -5659,9 +5737,10 @@ def __init__(self, id, video_file_id, title, description=None,
self.input_message_content = input_message_content
self.parse_mode = parse_mode
self.payload_dic['video_file_id'] = video_file_id
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedVoice(InlineQueryResultCachedBase):
"""
Represents a link to a voice message stored on the Telegram servers. By default, this voice message will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the voice message.
@@ -5715,7 +5794,7 @@ def __init__(self, id, voice_file_id, title, caption=None, caption_entities = No
self.payload_dic['voice_file_id'] = voice_file_id
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class InlineQueryResultCachedAudio(InlineQueryResultCachedBase):
"""
Represents a link to an MP3 audio file stored on the Telegram servers. By default, this audio file will be sent by the user. Alternatively, you can use input_message_content to send a message with the specified content instead of the audio.
@@ -6083,7 +6162,7 @@ def __init__(self, name=None, phone_number=None, email=None, shipping_address=No
self.shipping_address: ShippingAddress = shipping_address
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class ShippingOption(JsonSerializable):
"""
This object represents one shipping option.
@@ -6178,6 +6257,7 @@ def __init__(self, currency, total_amount, invoice_payload, shipping_option_id=N
self.provider_payment_charge_id: str = provider_payment_charge_id
+# noinspection PyShadowingBuiltins
class ShippingQuery(JsonDeserializable):
"""
This object contains information about an incoming shipping query.
@@ -6214,6 +6294,7 @@ def __init__(self, id, from_user, invoice_payload, shipping_address, **kwargs):
self.shipping_address: ShippingAddress = shipping_address
+# noinspection PyShadowingBuiltins
class PreCheckoutQuery(JsonDeserializable):
"""
This object contains information about an incoming pre-checkout query.
@@ -6341,6 +6422,7 @@ def is_video(self):
return False
+# noinspection PyShadowingBuiltins
class Sticker(JsonDeserializable):
"""
This object represents a sticker.
@@ -6485,6 +6567,7 @@ def to_dict(self):
# InputMedia
+# noinspection PyShadowingBuiltins
class InputMedia(Dictionaryable, JsonSerializable):
"""
This object represents the content of a media message to be sent. It should be one of
@@ -6557,10 +6640,13 @@ class InputMediaPhoto(InputMedia):
:param has_spoiler: Optional. True, if the uploaded photo is a spoiler
:type has_spoiler: :obj:`bool`
+ :param show_caption_above_media: Optional. True, if the caption should be shown above the photo
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InputMediaPhoto`
"""
- def __init__(self, media, caption=None, parse_mode=None, caption_entities=None, has_spoiler=None):
+ def __init__(self, media, caption=None, parse_mode=None, caption_entities=None, has_spoiler=None, show_caption_above_media=None):
if service_utils.is_pil_image(media):
media = service_utils.pil_image_to_file(media)
@@ -6568,11 +6654,14 @@ def __init__(self, media, caption=None, parse_mode=None, caption_entities=None,
type="photo", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities)
self.has_spoiler: Optional[bool] = has_spoiler
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
def to_dict(self):
ret = super(InputMediaPhoto, self).to_dict()
if self.has_spoiler is not None:
ret['has_spoiler'] = self.has_spoiler
+ if self.show_caption_above_media is not None:
+ ret['show_caption_above_media'] = self.show_caption_above_media
return ret
@@ -6620,11 +6709,14 @@ class InputMediaVideo(InputMedia):
:param has_spoiler: Optional. True, if the uploaded video is a spoiler
:type has_spoiler: :obj:`bool`
+ :param show_caption_above_media: Optional. True, if the caption should be shown above the video
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InputMediaVideo`
"""
def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption_entities=None,
- width=None, height=None, duration=None, supports_streaming=None, has_spoiler=None):
+ width=None, height=None, duration=None, supports_streaming=None, has_spoiler=None, show_caption_above_media=None):
super(InputMediaVideo, self).__init__(
type="video", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities)
self.thumbnail = thumbnail
@@ -6633,6 +6725,7 @@ def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption
self.duration = duration
self.supports_streaming = supports_streaming
self.has_spoiler: Optional[bool] = has_spoiler
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
@property
def thumb(self):
@@ -6649,10 +6742,12 @@ def to_dict(self):
ret['height'] = self.height
if self.duration:
ret['duration'] = self.duration
- if self.supports_streaming:
+ if self.supports_streaming is not None:
ret['supports_streaming'] = self.supports_streaming
if self.has_spoiler is not None:
ret['has_spoiler'] = self.has_spoiler
+ if self.show_caption_above_media is not None:
+ ret['show_caption_above_media'] = self.show_caption_above_media
return ret
@@ -6697,11 +6792,14 @@ class InputMediaAnimation(InputMedia):
:param has_spoiler: Optional. True, if the uploaded animation is a spoiler
:type has_spoiler: :obj:`bool`
+ :param show_caption_above_media: Optional. True, if the caption should be shown above the animation
+ :type show_caption_above_media: :obj:`bool`
+
:return: Instance of the class
:rtype: :class:`telebot.types.InputMediaAnimation`
"""
def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption_entities=None,
- width=None, height=None, duration=None, has_spoiler=None):
+ width=None, height=None, duration=None, has_spoiler=None, show_caption_above_media=None):
super(InputMediaAnimation, self).__init__(
type="animation", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities)
self.thumbnail = thumbnail
@@ -6709,6 +6807,7 @@ def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption
self.height = height
self.duration = duration
self.has_spoiler: Optional[bool] = has_spoiler
+ self.show_caption_above_media: Optional[bool] = show_caption_above_media
@property
def thumb(self):
@@ -6727,6 +6826,8 @@ def to_dict(self):
ret['duration'] = self.duration
if self.has_spoiler is not None:
ret['has_spoiler'] = self.has_spoiler
+ if self.show_caption_above_media is not None:
+ ret['show_caption_above_media'] = self.show_caption_above_media
return ret
@@ -6867,6 +6968,9 @@ class PollOption(JsonDeserializable):
:param voter_count: Number of users that voted for this option
:type voter_count: :obj:`int`
+ :param text_entities: Optional. Special entities that appear in the option text. Currently, only custom emoji entities are allowed in poll option texts
+ :type text_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
+
:return: Instance of the class
:rtype: :class:`telebot.types.PollOption`
"""
@@ -6874,17 +6978,57 @@ class PollOption(JsonDeserializable):
def de_json(cls, json_string):
if json_string is None: return None
obj = cls.check_json(json_string, dict_copy=False)
+ if 'text_entities' in obj:
+ obj['text_entities'] = Message.parse_entities(obj['text_entities'])
return cls(**obj)
- def __init__(self, text, voter_count = 0, **kwargs):
+ def __init__(self, text, voter_count = 0, text_entities=None, **kwargs):
self.text: str = text
self.voter_count: int = voter_count
+ self.text_entities: List[MessageEntity] = text_entities
# Converted in _convert_poll_options
# def to_json(self):
# # send_poll Option is a simple string: https://core.telegram.org/bots/api#sendpoll
# return json.dumps(self.text)
+class InputPollOption(JsonSerializable):
+ """
+ This object contains information about one answer option in a poll to send.
+
+ Telegram Documentation: https://core.telegram.org/bots/api#inputpolloption
+
+ :param text: Option text, 1-100 characters
+ :type text: :obj:`str`
+
+ :param text_parse_mode: Optional. Mode for parsing entities in the text. See formatting options for more details. Currently, only custom emoji entities are allowed
+ :type text_parse_mode: :obj:`str`
+
+ :param text_entities: Optional. A JSON-serialized list of special entities that appear in the poll option text. It can be specified instead of text_parse_mode
+ :type text_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
+
+ :return: Instance of the class
+ :rtype: :class:`telebot.types.PollOption`
+ """
+ def __init__(self, text, text_parse_mode=None, text_entities=None, **kwargs):
+ self.text: str = text
+ self.text_parse_mode: Optional[str] = text_parse_mode
+ self.text_entities: List[MessageEntity] = text_entities
+
+ def to_json(self):
+ return json.dumps(self.to_dict())
+
+ def to_dict(self):
+ json_dict = {
+ "text": self.text,
+ }
+ if self.text_parse_mode:
+ json_dict["text_parse_mode"] = self.text_parse_mode
+ if self.text_entities:
+ json_dict['text_entities'] = [entity.to_dict() for entity in self.text_entities]
+ return json_dict
+
+
class Poll(JsonDeserializable):
"""
This object contains information about a poll.
@@ -6915,16 +7059,13 @@ class Poll(JsonDeserializable):
:param allows_multiple_answers: True, if the poll allows multiple answers
:type allows_multiple_answers: :obj:`bool`
- :param correct_option_id: Optional. 0-based identifier of the correct answer option. Available only for polls in
- the quiz mode, which are closed, or was sent (not forwarded) by the bot or to the private chat with the bot.
+ :param correct_option_id: Optional. 0-based identifier of the correct answer option. Available only for polls in the quiz mode, which are closed, or was sent (not forwarded) by the bot or to the private chat with the bot.
:type correct_option_id: :obj:`int`
- :param explanation: Optional. Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a
- quiz-style poll, 0-200 characters
+ :param explanation: Optional. Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters
:type explanation: :obj:`str`
- :param explanation_entities: Optional. Special entities like usernames, URLs, bot commands, etc. that appear in
- the explanation
+ :param explanation_entities: Optional. Special entities like usernames, URLs, bot commands, etc. that appear in the explanation
:type explanation_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
:param open_period: Optional. Amount of time in seconds the poll will be active after creation
@@ -6933,6 +7074,9 @@ class Poll(JsonDeserializable):
:param close_date: Optional. Point in time (Unix timestamp) when the poll will be automatically closed
:type close_date: :obj:`int`
+ :param question_entities: Optional. Special entities that appear in the question. Currently, only custom emoji entities are allowed in poll questions
+ :type question_entities: :obj:`list` of :class:`telebot.types.MessageEntity`
+
:return: Instance of the class
:rtype: :class:`telebot.types.Poll`
"""
@@ -6947,6 +7091,8 @@ def de_json(cls, json_string):
obj['options'] = options or None
if 'explanation_entities' in obj:
obj['explanation_entities'] = Message.parse_entities(obj['explanation_entities'])
+ if 'question_entities' in obj:
+ obj['question_entities'] = Message.parse_entities(obj['question_entities'])
return cls(**obj)
# noinspection PyShadowingBuiltins
@@ -6955,7 +7101,8 @@ def __init__(
question, options,
poll_id=None, total_voter_count=None, is_closed=None, is_anonymous=None, type=None,
allows_multiple_answers=None, correct_option_id=None, explanation=None, explanation_entities=None,
- open_period=None, close_date=None, poll_type=None, **kwargs):
+ open_period=None, close_date=None, poll_type=None, question_entities=None,
+ **kwargs):
self.id: str = poll_id
self.question: str = question
self.options: List[PollOption] = options
@@ -6971,6 +7118,7 @@ def __init__(
self.correct_option_id: int = correct_option_id
self.explanation: str = explanation
self.explanation_entities: List[MessageEntity] = explanation_entities
+ self.question_entities: List[MessageEntity] = question_entities
self.open_period: int = open_period
self.close_date: int = close_date
@@ -7342,12 +7490,12 @@ class MenuButton(JsonDeserializable, JsonSerializable, Dictionaryable):
def de_json(cls, json_string):
if json_string is None: return None
obj = cls.check_json(json_string)
- map = {
+ types = {
'commands': MenuButtonCommands,
'web_app': MenuButtonWebApp,
'default': MenuButtonDefault
}
- return map[obj['type']](**obj)
+ return types[obj['type']](**obj)
def to_json(self):
"""
@@ -7360,8 +7508,9 @@ def to_dict(self):
:meta private:
"""
raise NotImplementedError
-
+
+# noinspection PyUnusedLocal
class MenuButtonCommands(MenuButton):
"""
Represents a menu button, which opens the bot's list of commands.
@@ -7385,6 +7534,7 @@ def to_json(self):
return json.dumps(self.to_dict())
+# noinspection PyUnusedLocal
class MenuButtonWebApp(MenuButton):
"""
Represents a menu button, which launches a Web App.
@@ -7398,7 +7548,9 @@ class MenuButtonWebApp(MenuButton):
:type text: :obj:`str`
:param web_app: Description of the Web App that will be launched when the user presses the button. The Web App will be
- able to send an arbitrary message on behalf of the user using the method answerWebAppQuery.
+ able to send an arbitrary message on behalf of the user using the method answerWebAppQuery. Alternatively, a t.me link
+ to a Web App of the bot can be specified in the object instead of the Web App's URL, in which case the Web App will be
+ opened as if the user pressed the link.
:type web_app: :class:`telebot.types.WebAppInfo`
:return: Instance of the class
@@ -7416,7 +7568,8 @@ def to_dict(self):
def to_json(self):
return json.dumps(self.to_dict())
-
+
+# noinspection PyUnusedLocal
class MenuButtonDefault(MenuButton):
"""
Describes that no specific value for the menu button was set.
@@ -7600,8 +7753,11 @@ class InputFile:
InputFile(pathlib.Path('/path/to/file/file.txt'))
)
"""
- def __init__(self, file) -> None:
- self._file, self.file_name = self._resolve_file(file)
+ def __init__(self, file: Union[str, IOBase, Path], file_name: Optional[str] = None):
+ self._file, self._file_name = self._resolve_file(file)
+ if file_name:
+ self._file_name = file_name
+
@staticmethod
def _resolve_file(file):
@@ -7622,6 +7778,13 @@ def file(self):
File object.
"""
return self._file
+
+ @property
+ def file_name(self):
+ """
+ File name.
+ """
+ return self._file_name
class ForumTopicCreated(JsonDeserializable):
@@ -7897,6 +8060,7 @@ def __init__(self, short_description: str, **kwargs) -> None:
self.short_description: str = short_description
+# noinspection PyShadowingBuiltins
class InputSticker(Dictionaryable, JsonSerializable):
"""
This object describes a sticker to be added to a sticker set.
@@ -8131,6 +8295,7 @@ def __init__(self, chat: Chat, id: int, **kwargs) -> None:
# base class
+# noinspection PyShadowingBuiltins
class ReactionType(JsonDeserializable, Dictionaryable, JsonSerializable):
"""
This object represents a reaction type.
@@ -8315,8 +8480,9 @@ def __init__(self, chat: Chat, message_id: int, date: int, reactions: List[React
self.message_id: int = message_id
self.date: int = date
self.reactions: List[ReactionCount] = reactions
-
+
+# noinspection PyShadowingBuiltins
class ReactionCount(JsonDeserializable):
"""
This object represents a reaction added to a message along with the number of times it was added.
@@ -8373,6 +8539,9 @@ class ExternalReplyInfo(JsonDeserializable):
:param document: Optional. Message is a general file, information about the file
:type document: :class:`Document`
+ :param paid_media: Optional. Message is a paid media content
+ :type paid_media: :class:`PaidMedia`
+
:param photo: Optional. Message is a photo, available sizes of the photo
:type photo: :obj:`list` of :class:`PhotoSize`
@@ -8481,7 +8650,7 @@ def __init__(
dice: Optional[Dice]=None, game: Optional[Game]=None, giveaway: Optional[Giveaway]=None,
giveaway_winners: Optional[GiveawayWinners]=None, invoice: Optional[Invoice]=None,
location: Optional[Location]=None, poll: Optional[Poll]=None,
- venue: Optional[Venue]=None, **kwargs) -> None:
+ venue: Optional[Venue]=None, paid_media: Optional[PaidMediaInfo]=None, **kwargs) -> None:
self.origin: MessageOrigin = origin
self.chat: Optional[Chat] = chat
self.message_id: Optional[int] = message_id
@@ -8505,9 +8674,10 @@ def __init__(
self.location: Optional[Location] = location
self.poll: Optional[Poll] = poll
self.venue: Optional[Venue] = venue
+ self.paid_media: Optional[PaidMediaInfo] = paid_media
-# noinspection PyUnresolvedReferences
+# noinspection PyUnresolvedReferences,PyShadowingBuiltins
class MessageOrigin(JsonDeserializable):
"""
This object describes the origin of a message.
@@ -8983,13 +9153,8 @@ class UsersShared(JsonDeserializable):
:param request_id: Identifier of the request
:type request_id: :obj:`int`
- :param user_ids: Array of :obj:`types.SharedUser` of the shared users. These numbers may have more than 32 significant bits
- and some programming languages may have difficulty/silent defects in interpreting them.
- But they have at most 52 significant bits, so 64-bit integers or double-precision float
- types are safe for storing these identifiers. The bot may not have access to the users and
- could be unable to use these identifiers unless the users are already known to the bot by
- some other means.
- :type user_ids: :obj:`list` of :obj:`types.SharedUser`
+ :param users: Information about users shared with the bot
+ :type users: :obj:`list` of :obj:`types.SharedUser`
:return: Instance of the class
:rtype: :class:`UsersShared`
@@ -8998,20 +9163,23 @@ class UsersShared(JsonDeserializable):
def de_json(cls, json_string):
if json_string is None: return None
obj = cls.check_json(json_string)
-
- obj['user_ids'] = [SharedUser.de_json(user) for user in obj['user_ids']]
-
+ obj['users'] = [SharedUser.de_json(user) for user in obj['users']]
return cls(**obj)
- def __init__(self, request_id, user_ids: SharedUser, **kwargs):
+ def __init__(self, request_id, users: List[SharedUser], **kwargs):
self.request_id = request_id
- self.user_ids = user_ids
+ self.users = users
@property
def user_id(self):
logger.warning('The parameter "user_id" is deprecated, use "user_ids" instead')
return None
-
+
+ @property
+ def user_ids(self):
+ logger.warning('The parameter "user_ids" is deprecated, use "users" instead')
+ return self.users
+
class ChatBoostUpdated(JsonDeserializable):
"""
@@ -9320,7 +9488,7 @@ def __getattr__(self, item):
'group_chat_created', 'supergroup_chat_created', 'channel_chat_created', 'message_auto_delete_timer_changed',
'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', 'invoice', 'successful_payment',
'users_shared', 'chat_shared', 'connected_website', 'write_access_allowed', 'passport_data',
- 'proximity_alert_triggered', 'forum_topic_created', 'forum_topic_edited', 'forum_topic_closed',
+ 'proximity_alert_triggered', 'chat_background_set', 'forum_topic_created', 'forum_topic_edited', 'forum_topic_closed',
'forum_topic_reopened', 'general_forum_topic_hidden', 'general_forum_topic_unhidden', 'giveaway_created',
'giveaway', 'giveaway_winners', 'giveaway_completed', 'video_chat_scheduled', 'video_chat_started',
'video_chat_ended', 'video_chat_participants_invited', 'web_app_data', 'reply_markup'
@@ -9353,7 +9521,7 @@ def __init__(self, boost_count, **kwargs):
self.boost_count: int = boost_count
-
+# noinspection PyShadowingBuiltins
class BusinessConnection(JsonDeserializable):
"""
This object describes the connection of the bot with a business account.
@@ -9620,4 +9788,942 @@ def de_json(cls, json_string):
def __init__(self, day, month, year=None, **kwargs):
self.day: int = day
self.month: int = month
- self.year: Optional[int] = year
\ No newline at end of file
+ self.year: Optional[int] = year
+
+
+class BackgroundFill(ABC, JsonDeserializable):
+ """
+ This object describes the way a background is filled based on the selected colors. Currently, it can be one of
+ BackgroundFillSolid
+ BackgroundFillGradient
+ BackgroundFillFreeformGradient
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundfill
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundFillSolid` or :class:`BackgroundFillGradient` or :class:`BackgroundFillFreeformGradient`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if obj["type"] == "solid":
+ return BackgroundFillSolid.de_json(obj)
+ elif obj["type"] == "gradient":
+ return BackgroundFillGradient.de_json(obj)
+ elif obj["type"] == "freeform_gradient":
+ return BackgroundFillFreeformGradient.de_json(obj)
+ return None
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundFillSolid(BackgroundFill):
+ """
+ The background is filled using the selected color.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundfillsolid
+
+ :param type: Type of the background fill, always “solid”
+ :type type: :obj:`str`
+
+ :param color: The color of the background fill in the RGB24 format
+ :type color: :class:`int`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundFillSolid`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+ def __init__(self, type, color, **kwargs):
+ self.type: str = type
+ self.color: int = color
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundFillGradient(BackgroundFill):
+ """
+ The background is a gradient fill.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundfillgradient
+
+ :param type: Type of the background fill, always “gradient”
+ :type type: :obj:`str`
+
+ :param top_color: Top color of the gradient in the RGB24 format
+ :type top_color: :class:`int`
+
+ :param bottom_color: Bottom color of the gradient in the RGB24 format
+ :type bottom_color: :class:`int`
+
+ :param rotation_angle: Clockwise rotation angle of the background fill in degrees; 0-359
+ :type rotation_angle: :class:`int`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundFillGradient`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+ def __init__(self, type, top_color, bottom_color, rotation_angle, **kwargs):
+ self.type: str = type
+ self.top_color: int = top_color
+ self.bottom_color: int = bottom_color
+ self.rotation_angle: int = rotation_angle
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundFillFreeformGradient(BackgroundFill):
+ """
+ The background is a freeform gradient that rotates after every message in the chat.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundfillfreeformgradient
+
+ :param type: Type of the background fill, always “freeform_gradient”
+ :type type: :obj:`str`
+
+ :param colors: A list of the 3 or 4 base colors that are used to generate the freeform gradient in the RGB24 format
+ :type colors: :obj:`list` of :class:`int`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundFillFreeformGradient`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+ def __init__(self, type, colors, **kwargs):
+ self.type: str = type
+ self.colors: List[int] = colors
+
+
+class BackgroundType(ABC, JsonDeserializable):
+ """
+ This object describes the type of a background. Currently, it can be one of
+ BackgroundTypeFill
+ BackgroundTypeWallpaper
+ BackgroundTypePattern
+ BackgroundTypeChatTheme
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundtype
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundTypeFill` or :class:`BackgroundTypeWallpaper` or :class:`BackgroundTypePattern` or :class:`BackgroundTypeChatTheme`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if obj["type"] == "fill":
+ return BackgroundTypeFill.de_json(obj)
+ elif obj["type"] == "wallpaper":
+ return BackgroundTypeWallpaper.de_json(obj)
+ elif obj["type"] == "pattern":
+ return BackgroundTypePattern.de_json(obj)
+ elif obj["type"] == "chat_theme":
+ return BackgroundTypeChatTheme.de_json(obj)
+ return None
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundTypeFill(BackgroundFill):
+ """
+ The background is automatically filled based on the selected colors.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundtypefill
+
+ :param type: Type of the background, always “fill”
+ :type type: :obj:`str`
+
+ :param fill: The background fill
+ :type fill: :class:`BackgroundFill`
+
+ :param dark_theme_dimming: Dimming of the background in dark themes, as a percentage; 0-100
+ :type dark_theme_dimming: :obj:`int`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundTypeFill`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['fill'] = BackgroundFill.de_json(obj['fill'])
+ return cls(**obj)
+
+ def __init__(self, type, fill, dark_theme_dimming, **kwargs):
+ self.type: str = type
+ self.fill: BackgroundFill = fill
+ self.dark_theme_dimming: int = dark_theme_dimming
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundTypeWallpaper(BackgroundFill):
+ """
+ The background is a wallpaper in the JPEG format.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundtypewallpaper
+
+ :param type: Type of the background, always “wallpaper”
+ :type type: :obj:`str`
+
+ :param document: Document with the wallpaper
+ :type document: :class:`Document`
+
+ :param dark_theme_dimming: Dimming of the background in dark themes, as a percentage; 0-100
+ :type dark_theme_dimming: :obj:`int`
+
+ :param is_blurred: Optional. True, if the wallpaper is downscaled to fit in a 450x450 square and then box-blurred with radius 12
+ :type is_blurred: :obj:`bool`
+
+ :param is_moving: Optional. True, if the background moves slightly when the device is tilted
+ :type is_moving: :obj:`bool`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundTypeWallpaper`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['document'] = Document.de_json(obj['document'])
+ return cls(**obj)
+
+ def __init__(self, type, document, dark_theme_dimming, is_blurred=None, is_moving=None, **kwargs):
+ self.type: str = type
+ self.document: Document = document
+ self.dark_theme_dimming: int = dark_theme_dimming
+ self.is_blurred: Optional[bool] = is_blurred
+ self.is_moving: Optional[bool] = is_moving
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundTypePattern(BackgroundFill):
+ """
+ The background is a wallpaper in the JPEG format.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundtypepattern
+
+ :param type: Type of the background, always “pattern”
+ :type type: :obj:`str`
+
+ :param document: Document with the pattern
+ :type document: :class:`Document`
+
+ :param fill: The background fill that is combined with the pattern
+ :type fill: :class:`BackgroundFill`
+
+ :param intensity: Intensity of the pattern when it is shown above the filled background; 0-100
+ :type intensity: :obj:`int`
+
+ :param is_inverted: Optional. True, if the background fill must be applied only to the pattern itself. All other pixels are black in this case. For dark themes only
+ :type is_inverted: :obj:`bool`
+
+ :param is_moving: Optional. True, if the background moves slightly when the device is tilted
+ :type is_moving: :obj:`bool`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundTypePattern`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['document'] = Document.de_json(obj['document'])
+ return cls(**obj)
+
+ def __init__(self, type, document, fill, intensity, is_inverted=None, is_moving=None, **kwargs):
+ self.type: str = type
+ self.document: Document = document
+ self.fill: BackgroundFill = fill
+ self.intensity: int = intensity
+ self.is_inverted: Optional[bool] = is_inverted
+ self.is_moving: Optional[bool] = is_moving
+
+
+# noinspection PyShadowingBuiltins
+class BackgroundTypeChatTheme(BackgroundFill):
+ """
+ The background is taken directly from a built-in chat theme.
+
+ Telegram documentation: https://core.telegram.org/bots/api#backgroundtypechattheme
+
+ :param type: Type of the background, always “chat_theme”
+ :type type: :obj:`str`
+
+ :param theme_name: Intensity of the pattern when it is shown above the filled background; 0-100
+ :type theme_name: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`BackgroundTypeChatTheme`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+ def __init__(self, type, theme_name, **kwargs):
+ self.type: str = type
+ self.theme_name: str = theme_name
+
+
+# noinspection PyShadowingBuiltins
+class ChatBackground(JsonDeserializable):
+ """
+ This object represents a chat background.
+
+ Telegram documentation: https://core.telegram.org/bots/api#chatbackground
+
+ :param type: Type of the background
+ :type type: :class:`BackgroundType`
+
+ :return: Instance of the class
+ :rtype: :class:`ChatBackground`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['type'] = BackgroundType.de_json(obj['type'])
+ return cls(**obj)
+
+ def __init__(self, type, **kwargs):
+ self.type: BackgroundType = type
+
+
+class RevenueWithdrawalState(JsonDeserializable):
+ # noinspection PyUnresolvedReferences
+ """
+ This object describes the state of a revenue withdrawal operation. Currently, it can be one of
+ RevenueWithdrawalStatePending
+ RevenueWithdrawalStateSucceeded
+ RevenueWithdrawalStateFailed
+
+ Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstate
+
+ :param type: Type of the state, always “pending” or “succeeded” or “failed”
+ :type type: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`RevenueWithdrawalStatePending` or :class:`RevenueWithdrawalStateSucceeded` or :class:`RevenueWithdrawalStateFailed`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if obj["type"] == "pending":
+ return RevenueWithdrawalStatePending.de_json(obj)
+ elif obj["type"] == "succeeded":
+ return RevenueWithdrawalStateSucceeded.de_json(obj)
+ elif obj["type"] == "failed":
+ return RevenueWithdrawalStateFailed.de_json(obj)
+ return None
+
+
+class RevenueWithdrawalStatePending(RevenueWithdrawalState):
+ """
+ The withdrawal is in progress.
+
+ Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstatepending
+
+ :param type: Type of the state, always “pending”
+ :type type: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`RevenueWithdrawalStatePending`
+ """
+
+ # noinspection PyPackageRequirements
+ def __init__(self, type, **kwargs):
+ self.type: str = type
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+
+class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState):
+ """
+ The withdrawal succeeded.
+
+ Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstatesucceeded
+
+ :param type: Type of the state, always “succeeded”
+ :type type: :obj:`str`
+
+ :param date: Date the withdrawal was completed in Unix time
+ :type date: :obj:`int`
+
+ :param url: An HTTPS URL that can be used to see transaction details
+ :type url: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`RevenueWithdrawalStateSucceeded`
+ """
+
+ # noinspection PyPackageRequirements
+ def __init__(self, type, date, url, **kwargs):
+ self.type: str = type
+ self.date: int = date
+ self.url: str = url
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+
+
+class RevenueWithdrawalStateFailed(RevenueWithdrawalState):
+ """
+ The withdrawal failed and the transaction was refunded.
+
+ Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstatefailed
+
+ :param type: Type of the state, always “failed”
+ :type type: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`RevenueWithdrawalStateFailed`
+ """
+
+ # noinspection PyPackageRequirements
+ def __init__(self, type, **kwargs):
+ self.type: str = type
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+
+class TransactionPartner(JsonDeserializable):
+ # noinspection PyUnresolvedReferences
+ """
+ This object describes the source of a transaction, or its recipient for outgoing transactions. Currently, it can be one of
+ TransactionPartnerFragment
+ TransactionPartnerUser
+ TransactionPartnerOther
+
+ Telegram documentation: https://core.telegram.org/bots/api#transactionpartner
+
+ :param type: Type of the transaction partner
+ :type type: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`TransactionPartnerFragment` or :class:`TransactionPartnerUser` or :class:`TransactionPartnerOther`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if obj["type"] == "fragment":
+ return TransactionPartnerFragment.de_json(obj)
+ elif obj["type"] == "user":
+ return TransactionPartnerUser.de_json(obj)
+ elif obj["type"] == "telegram_ads":
+ return TransactionPartnerTelegramAds.de_json(obj)
+ elif obj["type"] == "other":
+ return TransactionPartnerOther.de_json(obj)
+
+class TransactionPartnerFragment(TransactionPartner):
+ """
+ Describes a withdrawal transaction with Fragment.
+
+ Telegram documentation: https://core.telegram.org/bots/api#transactionpartnerfragment
+
+ :param type: Type of the transaction partner, always “fragment”
+ :type type: :obj:`str`
+
+ :param withdrawal_state: Optional. State of the transaction if the transaction is outgoing
+ :type withdrawal_state: :class:`RevenueWithdrawalState`
+
+ :return: Instance of the class
+ :rtype: :class:`TransactionPartnerFragment`
+
+ """
+
+ # noinspection PyPackageRequirements
+ def __init__(self, type, withdrawal_state=None, **kwargs):
+ self.type: str = type
+ self.withdrawal_state: Optional[RevenueWithdrawalState] = withdrawal_state
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if 'withdrawal_state' in obj:
+ obj['withdrawal_state'] = RevenueWithdrawalState.de_json(obj['withdrawal_state'])
+ return cls(**obj)
+
+
+
+class TransactionPartnerUser(TransactionPartner):
+ """
+ Describes a transaction with a user.
+
+ Telegram documentation: https://core.telegram.org/bots/api#transactionpartneruser
+
+ :param type: Type of the transaction partner, always “user”
+ :type type: :obj:`str`
+
+ :param user: Information about the user
+ :type user: :class:`User`
+
+ :param invoice_payload: Optional, Bot-specified invoice payload
+ :type invoice_payload: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`TransactionPartnerUser`
+ """
+
+ def __init__(self, type, user, invoice_payload=None, **kwargs):
+ self.type: str = type
+ self.user: User = user
+ self.invoice_payload: Optional[str] = invoice_payload
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['user'] = User.de_json(obj['user'])
+ return cls(**obj)
+
+class TransactionPartnerTelegramAds(TransactionPartner):
+ """
+ Describes a transaction with Telegram Ads.
+
+ Telegram documentation: https://core.telegram.org/bots/api#transactionpartnertelegramads
+
+ :param type: Type of the transaction partner, always “telegram_ads”
+ :type type: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`TransactionPartnerTelegramAds`
+ """
+
+ def __init__(self, type, **kwargs):
+ self.type: str = type
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+
+
+class TransactionPartnerOther(TransactionPartner):
+ """
+ Describes a transaction with an unknown source or recipient.
+
+ Telegram documentation: https://core.telegram.org/bots/api#transactionpartnerother
+
+ :param type: Type of the transaction partner, always “other”
+ :type type: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`TransactionPartnerOther`
+ """
+
+ def __init__(self, type, **kwargs):
+ self.type: str = type
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+
+
+class StarTransaction(JsonDeserializable):
+ """
+ Describes a Telegram Star transaction.
+
+ Telegram documentation: https://core.telegram.org/bots/api#startransaction
+
+ :param id: Unique identifier of the transaction. Coincides with the identifer of the original transaction for refund transactions. Coincides with SuccessfulPayment.telegram_payment_charge_id for successful incoming payments from users.
+ :type id: :obj:`str`
+
+ :param amount: Number of Telegram Stars transferred by the transaction
+ :type amount: :obj:`int`
+
+ :param date: Date the transaction was created in Unix time
+ :type date: :obj:`int`
+
+ :param source: Optional. Source of an incoming transaction (e.g., a user purchasing goods or services, Fragment refunding a failed withdrawal). Only for incoming transactions
+ :type source: :class:`TransactionPartner`
+
+ :param receiver: Optional. Receiver of an outgoing transaction (e.g., a user for a purchase refund, Fragment for a withdrawal). Only for outgoing transactions
+ :type receiver: :class:`TransactionPartner`
+
+ :return: Instance of the class
+ :rtype: :class:`StarTransaction`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if 'source' in obj:
+ obj['source'] = TransactionPartner.de_json(obj['source'])
+ if 'receiver' in obj:
+ obj['receiver'] = TransactionPartner.de_json(obj['receiver'])
+ return cls(**obj)
+
+ def __init__(self, id, amount, date, source=None, receiver=None, **kwargs):
+ self.id: str = id
+ self.amount: int = amount
+ self.date: int = date
+ self.source: Optional[TransactionPartner] = source
+ self.receiver: Optional[TransactionPartner] = receiver
+
+
+class StarTransactions(JsonDeserializable):
+ """
+ Contains a list of Telegram Star transactions.
+
+ Telegram documentation: https://core.telegram.org/bots/api#startransactions
+
+ :param transactions: The list of transactions
+ :type transactions: :obj:`list` of :class:`StarTransaction`
+
+ :return: Instance of the class
+ :rtype: :class:`StarTransactions`
+
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['transactions'] = [StarTransaction.de_json(transaction) for transaction in obj['transactions']]
+ return cls(**obj)
+
+ def __init__(self, transactions, **kwargs):
+ self.transactions: List[StarTransaction] = transactions
+
+
+class PaidMedia(JsonDeserializable):
+ """
+ This object describes paid media. Currently, it can be one of
+
+ PaidMediaPreview
+ PaidMediaPhoto
+ PaidMediaVideo
+
+ Telegram documentation: https://core.telegram.org/bots/api#paidmedia
+
+ :return: Instance of the class
+ :rtype: :class:`PaidMediaPreview` or :class:`PaidMediaPhoto` or :class:`PaidMediaVideo`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ if obj["type"] == "preview":
+ return PaidMediaPreview.de_json(obj)
+ elif obj["type"] == "photo":
+ return PaidMediaPhoto.de_json(obj)
+ elif obj["type"] == "video":
+ return PaidMediaVideo.de_json(obj)
+
+class PaidMediaPreview(PaidMedia):
+ """
+ The paid media isn't available before the payment.
+
+ Telegram documentation: https://core.telegram.org/bots/api#paidmediapreview
+
+ :param type: Type of the paid media, always “preview”
+ :type type: :obj:`str`
+
+ :param width: Optional. Media width as defined by the sender
+ :type width: :obj:`int`
+
+ :param height: Optional. Media height as defined by the sender
+ :type height: :obj:`int`
+
+ :param duration: Optional. Duration of the media in seconds as defined by the sender
+ :type duration: :obj:`int`
+
+ :return: Instance of the class
+ :rtype: :class:`PaidMediaPreview`
+ """
+
+ def __init__(self, type, width=None, height=None, duration=None, **kwargs):
+ self.type: str = type
+ self.width: Optional[int] = width
+ self.height: Optional[int] = height
+ self.duration: Optional[int] = duration
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+
+class PaidMediaPhoto(PaidMedia):
+ """
+ The paid media is a photo.
+
+ Telegram documentation: https://core.telegram.org/bots/api#paidmediaphoto
+
+ :param type: Type of the paid media, always “photo”
+ :type type: :obj:`str`
+
+ :param photo: The photo
+ :type photo: :obj:`list` of :class:`PhotoSize`
+
+ :return: Instance of the class
+ :rtype: :class:`PaidMediaPhoto`
+
+ """
+
+ def __init__(self, type, photo, **kwargs):
+ self.type: str = type
+ self.photo: List[PhotoSize] = photo
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+
+ obj['photo'] = [PhotoSize.de_json(photo) for photo in obj['photo']]
+ return cls(**obj)
+
+
+class PaidMediaVideo(PaidMedia):
+ """
+ The paid media is a video.
+
+ Telegram documentation: https://core.telegram.org/bots/api#paidmediavideo
+
+ :param type: Type of the paid media, always “video”
+ :type type: :obj:`str`
+
+ :param video: The video
+ :type video: :class:`Video`
+
+ :return: Instance of the class
+ :rtype: :class:`PaidMediaVideo`
+ """
+
+ def __init__(self, type, video, **kwargs):
+ self.type: str = type
+ self.video: Video = video
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['video'] = Video.de_json(obj['video'])
+ return cls(**obj)
+
+
+class PaidMediaInfo(JsonDeserializable):
+ """
+ Describes the paid media added to a message.
+
+ Telegram documentation: https://core.telegram.org/bots/api#paidmediainfo
+
+ :param star_count: The number of Telegram Stars that must be paid to buy access to the media
+ :type star_count: :obj:`int`
+
+ :param paid_media: Information about the paid media
+ :type paid_media: :obj:`list` of :class:`PaidMedia`
+
+ :return: Instance of the class
+ :rtype: :class:`PaidMediaInfo`
+ """
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ obj['paid_media'] = [PaidMedia.de_json(media) for media in obj['paid_media']]
+ return cls(**obj)
+
+ def __init__(self, star_count, paid_media, **kwargs):
+ self.star_count: int = star_count
+ self.paid_media: List[PaidMedia] = paid_media
+
+
+class InputPaidMedia(JsonSerializable):
+ """
+ This object describes the paid media to be sent. Currently, it can be one of
+ InputPaidMediaPhoto
+ InputPaidMediaVideo
+
+ Telegram documentation: https://core.telegram.org/bots/api#inputpaidmedia
+
+ :return: Instance of the class
+ :rtype: :class:`InputPaidMediaPhoto` or :class:`InputPaidMediaVideo`
+ """
+
+ def __init__(self, type, media, **kwargs):
+ self.type = type
+ self.media = media
+
+ if service_utils.is_string(self.media):
+ self._media_name = ''
+ self._media_dic = self.media
+ else:
+ self._media_name = service_utils.generate_random_token()
+ self._media_dic = 'attach://{0}'.format(self._media_name)
+
+ def to_json(self):
+ return json.dumps(self.to_dict())
+
+ def to_dict(self):
+ data = {
+ 'type': self.type,
+ 'media': self._media_dic
+ }
+ return data
+
+class InputPaidMediaPhoto(InputPaidMedia):
+ """
+ The paid media to send is a photo.
+
+ Telegram documentation: https://core.telegram.org/bots/api#inputpaidmediaphoto
+
+ :param type: Type of the media, must be photo
+ :type type: :obj:`str`
+
+ :param media: File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for
+ Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data
+ under name. More information on Sending Files »
+ :type media: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`InputPaidMediaPhoto`
+ """
+
+ def __init__(self, media, **kwargs):
+ super().__init__(type='photo', media=media)
+
+class InputPaidMediaVideo(InputPaidMedia):
+ """
+ The paid media to send is a video.
+
+ Telegram documentation: https://core.telegram.org/bots/api#inputpaidmediavideo
+
+ :param type: Type of the media, must be video
+ :type type: :obj:`str`
+
+ :param media: File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for
+ Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data
+ under name. More information on Sending Files »
+ :type media: :obj:`str`
+
+ :param thumbnail: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side.
+ The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320.
+ Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file,
+ so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under .
+ More information on Sending Files »
+ :type thumbnail: :class:`InputFile`
+
+ :param width: Optional. Video width
+ :type width: :obj:`int`
+
+ :param height: Optional. Video height
+ :type height: :obj:`int`
+
+ :param duration: Optional. Video duration in seconds
+ :type duration: :obj:`int`
+
+ :param supports_streaming: Optional. Pass True if the uploaded video is suitable for streaming
+ :type supports_streaming: :obj:`bool`
+
+ :return: Instance of the class
+ :rtype: :class:`InputPaidMediaVideo`
+
+ """
+
+ def __init__(self, media, thumbnail=None, width=None, height=None, duration=None, supports_streaming=None, **kwargs):
+ super().__init__(type='video', media=media)
+ self.thumbnail = thumbnail
+ self.width = width
+ self.height = height
+ self.duration = duration
+ self.supports_streaming = supports_streaming
+
+ def to_dict(self):
+ data = super().to_dict()
+ if self.thumbnail:
+ data['thumbnail'] = self.thumbnail
+ if self.width:
+ data['width'] = self.width
+ if self.height:
+ data['height'] = self.height
+ if self.duration:
+ data['duration'] = self.duration
+ if self.supports_streaming is not None:
+ data['supports_streaming'] = self.supports_streaming
+ return data
+
+class RefundedPayment(JsonDeserializable):
+ """
+ This object contains basic information about a refunded payment.
+
+ Telegram documentation: https://core.telegram.org/bots/api#refundedpayment
+
+ :param currency: Three-letter ISO 4217 currency code, or “XTR” for payments in Telegram Stars. Currently, always “XTR”
+ :type currency: :obj:`str`
+
+ :param total_amount: Total refunded price in the smallest units of the currency (integer, not float/double). For example, for a price of US$ 1.45, total_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).
+ :type total_amount: :obj:`int`
+
+ :param invoice_payload: Bot-specified invoice payload
+ :type invoice_payload: :obj:`str`
+
+ :param telegram_payment_charge_id: Telegram payment identifier
+ :type telegram_payment_charge_id: :obj:`str`
+
+ :param provider_payment_charge_id: Optional. Provider payment identifier
+ :type provider_payment_charge_id: :obj:`str`
+
+ :return: Instance of the class
+ :rtype: :class:`RefundedPayment`
+ """
+
+ def __init__(self, currency, total_amount, invoice_payload, telegram_payment_charge_id, provider_payment_charge_id=None, **kwargs):
+ self.currency: str = currency
+ self.total_amount: int = total_amount
+ self.invoice_payload: str = invoice_payload
+ self.telegram_payment_charge_id: str = telegram_payment_charge_id
+ self.provider_payment_charge_id: Optional[str] = provider_payment_charge_id
+
+ @classmethod
+ def de_json(cls, json_string):
+ if json_string is None: return None
+ obj = cls.check_json(json_string)
+ return cls(**obj)
+
+
\ No newline at end of file
diff --git a/telebot/version.py b/telebot/version.py
index 3eb8b787f..5016764c6 100644
--- a/telebot/version.py
+++ b/telebot/version.py
@@ -1,3 +1,3 @@
# Versions should comply with PEP440.
# This line is parsed in setup.py:
-__version__ = '4.17.0'
+__version__ = '4.21.0'