1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Compare commits

..

45 Commits
4.2.1 ... 4.3.0

Author SHA1 Message Date
ae2dbd00fa Merge pull request #1405 from Badiboy/master
Bump version to 4.3.0
2022-01-08 20:03:30 +03:00
6550a5d745 Bump version to 4.3.0 2022-01-08 20:02:54 +03:00
593b27358b Merge pull request #1404 from coder2020official/master
Create webhook_fastapi_echo_bot.py
2022-01-03 23:01:37 +03:00
a51ff0f100 Fix readme typos 2022-01-03 16:30:49 +04:00
a96bc802bc Update README.md 2022-01-03 16:28:24 +04:00
df8f34e726 Create webhook_fastapi_echo_bot.py 2022-01-03 16:16:19 +04:00
00998ac9c8 Merge pull request #1402 from coder2020official/master
Push bot API to 5.6
2022-01-02 23:26:01 +03:00
3f243c64ca Fix data-typo 2022-01-02 22:09:09 +04:00
034241ba31 Fix commit 2022-01-02 14:58:15 +04:00
ed6fb57cb5 Added protect_content parameter to all methods 2022-01-02 14:53:47 +04:00
b71507387f Added spoiler 2022-01-02 14:12:15 +04:00
e7d0ec1f6c Fix asyncio_helper.py 2021-12-31 19:25:29 +04:00
b3b318fd28 Delete asyncio_types.py 2021-12-31 15:14:42 +04:00
d334f5cb8d Added protect_content parameter. Remade some methods. 2021-12-31 15:05:40 +04:00
7f06424980 Update README.md 2021-12-31 13:20:54 +04:00
7490aa0d26 Merge pull request #1400 from Badiboy/master
send_document param type fix
2021-12-25 16:26:50 +03:00
e59e2ee2ee send_document param type fix 2021-12-25 16:23:26 +03:00
f25dcad10c Merge pull request #1399 from coder2020official/master
_make_request edited
2021-12-25 15:32:51 +03:00
24a9491ec0 _make_request function edited 2021-12-25 16:04:29 +04:00
744549defe Merge pull request #1397 from EnriqueMoran/master
Added bot using pyTelegramBotAPI to readme
2021-12-23 23:38:03 +03:00
c86fc4c3fa Added bot to readme 2021-12-23 12:31:01 -08:00
943396767c Merge pull request #1392 from studentenherz/master
Added bot using pyTelegramBotAPI
2021-12-13 10:07:39 +03:00
13fffe58a1 Added bot using pyTelegramBotAPI 2021-12-12 23:23:52 -03:00
7fe60e19ef Merge pull request #1390 from coder2020official/master
Update README.md
2021-12-12 14:11:51 +03:00
ba9bf17f46 Update README.md 2021-12-12 15:54:06 +05:00
373ee4b45b Merge pull request #1389 from coder2020official/master
Polling is now asynchronous, and some readme fixes.
2021-12-12 13:28:57 +03:00
e5f0ba67fc Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-12-12 15:13:10 +05:00
096d58ae71 Update admin_filter_example.py 2021-12-12 15:13:07 +05:00
ed5b47cb96 Update README.md 2021-12-12 15:11:42 +05:00
e92946301f Asyncio.run back 2021-12-12 15:07:30 +05:00
7588c9fb9f infinity_polling 2021-12-10 21:32:57 +03:00
6d10bfefbd Merge pull request #1386 from zeph1997/master
Create a template for QWERTY custom keyboard an example for ReplyKeyboardMarkup
2021-12-10 21:32:19 +03:00
cebfbb83fa Merge branch 'master' of https://github.com/zeph1997/pyTelegramBotAPI 2021-12-11 02:28:41 +08:00
5a06d8021b changed markup.add row from hardcoded index to *row 2021-12-11 02:28:19 +08:00
a75841aa8e Merge branch 'eternnoir:master' into master 2021-12-11 02:11:44 +08:00
e76649bb49 Create reply_keyboard_markup_example.py
Example to show how to use ReplyKeyboardMarkup as well as a template for a QWERTY keyboard
2021-12-11 02:11:15 +08:00
7567c6cd71 Merge pull request #1384 from Badiboy/master
Bump version to 4.2.2
2021-12-08 23:45:27 +03:00
751deeafd7 Bump version to 4.2.2 2021-12-08 23:44:57 +03:00
3ebefa15bf Merge pull request #1383 from coder2020official/master
Bot API 5.5
2021-12-08 13:19:56 +03:00
bb19687854 fix 2021-12-08 15:15:57 +05:00
311eec6888 fix 2021-12-08 14:15:40 +05:00
08fc32b70a Comment fix 2021-12-08 14:13:39 +05:00
555257a3fe Documentation Bug fixed 2021-12-08 14:00:39 +05:00
5a03ab62d0 Update test_types.py 2021-12-07 22:27:19 +05:00
038be81db3 5.5 2021-12-07 22:17:51 +05:00
30 changed files with 869 additions and 291 deletions

View File

@ -1,6 +1,5 @@
language: python
python:
- "3.6"
- "3.7"
- "3.8"
- "3.9"

View File

@ -9,7 +9,7 @@
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
<p align="center">Supports both sync and async ways.</p>
## <p align="center">Supporting Bot API version: <a href="https://core.telegram.org/bots/api#november-5-2021">5.4</a>!
## <p align="center">Supporting Bot API version: <a href="https://core.telegram.org/bots/api#december-30-2021">5.6</a>!
## Contents
@ -58,6 +58,7 @@
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
* [How can I handle reocurring ConnectionResetErrors?](#how-can-i-handle-reocurring-connectionreseterrors)
* [The Telegram Chat Group](#the-telegram-chat-group)
* [Telegram Channel](#telegram-channel)
* [More examples](#more-examples)
* [Bots using this API](#bots-using-this-api)
@ -685,8 +686,10 @@ Result will be:
## API conformance
* ✔ [Bot API 5.6](https://core.telegram.org/bots/api#december-30-2021)
* ✔ [Bot API 5.5](https://core.telegram.org/bots/api#december-7-2021)
* ✔ [Bot API 5.4](https://core.telegram.org/bots/api#november-5-2021)
* [Bot API 5.3](https://core.telegram.org/bots/api#june-25-2021) - ChatMemberXXX classes are full copies of ChatMember
* [Bot API 5.3](https://core.telegram.org/bots/api#june-25-2021) - ChatMember* classes are full copies of ChatMember
* ✔ [Bot API 5.2](https://core.telegram.org/bots/api#april-26-2021)
* ✔ [Bot API 5.1](https://core.telegram.org/bots/api#march-9-2021)
* ✔ [Bot API 5.0](https://core.telegram.org/bots/api-changelog#november-4-2020)
@ -700,18 +703,6 @@ Result will be:
* ✔ [Bot API 4.2](https://core.telegram.org/bots/api-changelog#april-14-2019)
* [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support
* [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support
* ✔ [Bot API 3.6](https://core.telegram.org/bots/api-changelog#february-13-2018)
* ✔ [Bot API 3.5](https://core.telegram.org/bots/api-changelog#november-17-2017)
* ✔ [Bot API 3.4](https://core.telegram.org/bots/api-changelog#october-11-2017)
* ✔ [Bot API 3.3](https://core.telegram.org/bots/api-changelog#august-23-2017)
* ✔ [Bot API 3.2](https://core.telegram.org/bots/api-changelog#july-21-2017)
* ✔ [Bot API 3.1](https://core.telegram.org/bots/api-changelog#june-30-2017)
* ✔ [Bot API 3.0](https://core.telegram.org/bots/api-changelog#may-18-2017)
* ✔ [Bot API 2.3.1](https://core.telegram.org/bots/api-changelog#december-4-2016)
* ✔ [Bot API 2.3](https://core.telegram.org/bots/api-changelog#november-21-2016)
* ✔ [Bot API 2.2](https://core.telegram.org/bots/api-changelog#october-3-2016)
* ✔ [Bot API 2.1](https://core.telegram.org/bots/api-changelog#may-22-2016)
* ✔ [Bot API 2.0](https://core.telegram.org/bots/api-changelog#april-9-2016)
## AsyncTeleBot
@ -727,6 +718,7 @@ Echo Bot example on AsyncTeleBot:
# It echoes any incoming text messages.
from telebot.async_telebot import AsyncTeleBot
import asyncio
bot = AsyncTeleBot('TOKEN')
@ -746,7 +738,7 @@ async def echo_message(message):
await bot.reply_to(message, message.text)
bot.polling()
asyncio.run(bot.polling())
```
As you can see here, keywords are await and async.
@ -791,7 +783,11 @@ Bot instances that were idle for a long time might be rejected by the server whe
Get help. Discuss. Chat.
* Join the [pyTelegramBotAPI Telegram Chat Group](https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A)
## Telegram Channel
Join the [News channel](https://t.me/pyTelegramBotAPI). Here we will post releases and updates.
## More examples
* [Echo Bot](https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/echo_bot.py)
@ -845,5 +841,7 @@ Get help. Discuss. Chat.
* [ETHGasFeeTrackerBot](https://t.me/ETHGasFeeTrackerBot) ([Source](https://github.com/DevAdvik/ETHGasFeeTrackerBot]) by *DevAdvik* - Get Live Ethereum Gas Fees in GWEI
* [Google Sheet Bot](https://github.com/JoachimStanislaus/Tele_Sheet_bot) by [JoachimStanislaus](https://github.com/JoachimStanislaus). This bot can help you to track your expenses by uploading your bot entries to your google sheet.
* [GrandQuiz Bot](https://github.com/Carlosma7/TFM-GrandQuiz) by [Carlosma7](https://github.com/Carlosma7). This bot is a trivia game that allows you to play with people from different ages. This project addresses the use of a system through chatbots to carry out a social and intergenerational game as an alternative to traditional game development.
* [Diccionario de la RAE](https://t.me/dleraebot) ([source](https://github.com/studentenherz/dleraebot)) This bot lets you find difinitions of words in Spanish using [RAE's dictionary](https://dle.rae.es/). It features direct message and inline search.
* [remoteTelegramShell](https://github.com/EnriqueMoran/remoteTelegramShell) by [EnriqueMoran](https://github.com/EnriqueMoran). Control your LinuxOS computer through Telegram.
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**

View File

@ -84,4 +84,5 @@ async def back_callback(call: types.CallbackQuery):
bot.add_custom_filter(ProductsCallbackFilter())
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -8,4 +8,5 @@ async def make_some(message: telebot.types.ChatJoinRequest):
await bot.send_message(message.chat.id, 'I accepted a new user!')
await bot.approve_chat_join_request(message.chat.id, message.from_user.id)
bot.polling(skip_pending=True)
import asyncio
asyncio.run(bot.polling())

View File

@ -30,4 +30,5 @@ async def my_chat_m(message: types.ChatMemberUpdated):
@bot.message_handler(content_types=util.content_type_service)
async def delall(message: types.Message):
await bot.delete_message(message.chat.id,message.message_id)
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -9,4 +9,6 @@ async def answer_for_admin(message):
# Register filter
bot.add_custom_filter(asyncio_filters.IsAdminFilter(bot))
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -40,4 +40,5 @@ async def bye_user(message):
bot.add_custom_filter(MainFilter())
bot.add_custom_filter(IsAdmin())
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -14,4 +14,5 @@ async def not_admin(message):
# Do not forget to register
bot.add_custom_filter(telebot.asyncio_filters.ChatFilter())
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -19,4 +19,5 @@ async def text_filter(message):
bot.add_custom_filter(telebot.asyncio_filters.IsReplyFilter())
bot.add_custom_filter(telebot.asyncio_filters.ForwardFilter())
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -17,4 +17,5 @@ async def text_filter(message):
bot.add_custom_filter(telebot.asyncio_filters.TextMatchFilter())
bot.add_custom_filter(telebot.asyncio_filters.TextStartsFilter())
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -71,4 +71,5 @@ bot.add_custom_filter(asyncio_filters.IsDigitFilter())
# set saving states into file.
bot.enable_saving_states() # you can delete this if you do not need to save states
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -17,4 +17,5 @@ async def new_message(message: telebot.types.Message):
await bot.edit_message_text(chat_id=message.chat.id, message_id=result_message.id, text='<i>Done!</i>', parse_mode='HTML')
bot.polling(skip_pending=True)
import asyncio
asyncio.run(bot.polling())

View File

@ -23,4 +23,5 @@ async def echo_message(message):
await bot.reply_to(message, message.text)
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -24,4 +24,5 @@ async def photo_send(message: telebot.types.Message):
bot.polling(skip_pending=True)
import asyncio
asyncio.run(bot.polling())

View File

@ -36,4 +36,5 @@ bot.setup_middleware(SimpleMiddleware(2))
async def start(message):
await bot.send_message(message.chat.id, 'Hello!')
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -45,4 +45,5 @@ async def start(message, data: dict):
await bot.send_message(message.chat.id, data['response'])
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -15,4 +15,6 @@ bot.register_message_handler(start_executor, commands=['start']) # Start command
# bot.register_edited_message_handler(*args, **kwargs)
# And other functions..
bot.polling(skip_pending=True)
import asyncio
asyncio.run(bot.polling())

View File

@ -24,4 +24,6 @@ async def photos_send(message: telebot.types.Message):
bot.polling(skip_pending=True)
import asyncio
asyncio.run(bot.polling())

View File

@ -10,4 +10,6 @@ async def send_welcome(message):
async def echo_all(message):
await bot.reply_to(message, message.text)
bot.polling(skip_pending=True)# Skip pending skips old updates
import asyncio
asyncio.run(bot.polling(skip_pending=True)) # to skip updates

View File

@ -11,4 +11,6 @@ async def update_listener(messages):
bot.set_update_listener(update_listener)
bot.polling()
import asyncio
asyncio.run(bot.polling())

View File

@ -0,0 +1,63 @@
# This example shows you how to create a custom QWERTY keyboard using reply keyboard markup
import telebot
from telebot.types import ReplyKeyboardMarkup, KeyboardButton
TOKEN = "<your_token>"
bot = telebot.TeleBot(TOKEN)
keys = ["1","2","3","4","5","6","7","8","9","0","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m"]
symbols = ["1","2","3","4","5","6","7","8","9","0","!","@","#","$","%","^","&","*","(",")","\'","\"","/","\\",",",".",";",":"]
def keyboard(key_type="Normal"):
markup = ReplyKeyboardMarkup(row_width=10)
if key_type == "Normal":
row = [KeyboardButton(x) for x in keys[:10]]
markup.add(*row)
row = [KeyboardButton(x) for x in keys[10:20]]
markup.add(*row)
row = [KeyboardButton(x) for x in keys[20:29]]
markup.add(*row)
row = [KeyboardButton(x) for x in keys[29:]]
markup.add(*row)
markup.add(KeyboardButton("Caps Lock"),KeyboardButton("Symbols"),KeyboardButton("🔙Delete"),KeyboardButton("✅Done"))
elif key_type == "Symbols":
row = [KeyboardButton(x) for x in symbols[:10]]
markup.add(*row)
row = [KeyboardButton(x) for x in symbols[10:20]]
markup.add(*row)
row = [KeyboardButton(x) for x in symbols[20:]]
markup.add(*row)
markup.add(KeyboardButton("Caps Lock"),KeyboardButton("Normal"),KeyboardButton("🔙Delete"),KeyboardButton("✅Done"))
else:
row = [KeyboardButton(x.upper()) for x in keys[:10]]
markup.add(*row)
row = [KeyboardButton(x.upper()) for x in keys[10:20]]
markup.add(*row)
row = [KeyboardButton(x.upper()) for x in keys[20:29]]
markup.add(*row)
row = [KeyboardButton(x.upper()) for x in keys[29:]]
markup.add(*row)
markup.add(KeyboardButton("Normal"),KeyboardButton("Symbols"),KeyboardButton("🔙Delete"),KeyboardButton("✅Done"))
return markup
@bot.message_handler(commands=["start"])
def start_message(message):
bot.send_message(message.chat.id,"You can use the keyboard",reply_markup=keyboard())
@bot.message_handler(func=lambda message:True)
def all_messages(message):
if message.text == "✅Done":
markup = telebot.types.ReplyKeyboardRemove()
bot.send_message(message.from_user.id,"Done with Keyboard",reply_markup=markup)
elif message.text == "Symbols":
bot.send_message(message.from_user.id,"Special characters",reply_markup=keyboard("Symbols"))
elif message.text == "Normal":
bot.send_message(message.from_user.id,"Normal Keyboard",reply_markup=keyboard("Normal"))
elif message.text == "Caps Lock":
bot.send_message(message.from_user.id,"Caps Lock",reply_markup=keyboard("Caps"))
elif message.text == "🔙Delete":
bot.delete_message(message.from_user.id,message.message_id)
else:
bot.send_message(message.chat.id,message.text)
bot.infinity_polling()

View File

@ -50,5 +50,12 @@ There are 5 examples in this directory using different libraries:
* **Cons:**
* Twisted is low-level, which may be good or bad depending on use case
* Considerable learning curve - reading docs is a must.
* **FastAPI(0.70.1):** *webhook_fastapi_echo_bot.py*
* **Pros:**
* Can be written for both sync and async
* Good documentation
* **Cons:**
* Requires python 3.6+
*Latest update of this document: 2020-12-17*
*Latest update of this document: 01-03-2022

View File

@ -0,0 +1,79 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This is a simple echo bot using decorators and webhook with fastapi
# It echoes any incoming text messages and does not use the polling method.
import logging
import fastapi
import telebot
API_TOKEN = 'TOKEN'
WEBHOOK_HOST = '<ip/domain>'
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out webhook_pkey.pem 2048
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN)
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN)
app = fastapi.FastAPI()
# Process webhook calls
@app.post(f'/{API_TOKEN}/')
def process_webhook(update: dict):
if update:
update = telebot.types.Update.de_json(update)
bot.process_new_updates([update])
else:
return
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
# Remove webhook, it fails sometimes the set if there is a previous webhook
bot.remove_webhook()
# Set webhook
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
import uvicorn
uvicorn.run(
app,
host=WEBHOOK_LISTEN,
port=WEBHOOK_PORT,
ssl_certfile=WEBHOOK_SSL_CERT,
ssl_keyfile=WEBHOOK_SSL_PRIV
)

View File

@ -936,32 +936,35 @@ class TeleBot:
def send_message(
self, chat_id: Union[int, str], text: str,
disable_web_page_preview: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
disable_web_page_preview: Optional[bool]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None) -> types.Message:
"""
Use this method to send text messages.
Warning: Do not send more than about 4000 characters each message, otherwise you'll risk an HTTP 414 error.
If you must send more than 4000 characters,
use the `split_string` or `smart_split` function in util.py.
:param chat_id:
:param text:
:param disable_web_page_preview:
:param reply_to_message_id:
:param reply_markup:
:param parse_mode:
:param disable_notification: Boolean, Optional. Sends the message silently.
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param text: Text of the message to be sent
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message.
:param entities: List of special entities that appear in message text, which can be specified instead of parse_mode
:param disable_web_page_preview: Disables link previews for links in this message
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
:param protect_content: If True, the message content will be hidden for all users except for the target user
:param reply_to_message_id: If the message is a reply, ID of the original message
:param allow_sending_without_reply: Pass True, if the message should be sent even if the specified replied-to message is not found
: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 timeout:
:param entities:
:param allow_sending_without_reply:
:return: API reply.
:return:
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -969,11 +972,12 @@ class TeleBot:
apihelper.send_message(
self.token, chat_id, text, disable_web_page_preview, reply_to_message_id,
reply_markup, parse_mode, disable_notification, timeout,
entities, allow_sending_without_reply))
entities, allow_sending_without_reply, protect_content=protect_content))
def forward_message(
self, chat_id: Union[int, str], from_chat_id: Union[int, str],
message_id: int, disable_notification: Optional[bool]=None,
message_id: int, disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
timeout: Optional[int]=None) -> types.Message:
"""
Use this method to forward messages of any kind.
@ -981,11 +985,12 @@ class TeleBot:
:param chat_id: which chat to forward
:param from_chat_id: which chat message from
:param message_id: message id
:param protect_content: Protects the contents of the forwarded message from forwarding and saving
:param timeout:
:return: API reply.
"""
return types.Message.de_json(
apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout))
apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content))
def copy_message(
self, chat_id: Union[int, str],
@ -995,6 +1000,7 @@ class TeleBot:
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
@ -1008,6 +1014,7 @@ class TeleBot:
:param parse_mode:
:param caption_entities:
:param disable_notification:
:param protect_content:
:param reply_to_message_id:
:param allow_sending_without_reply:
:param reply_markup:
@ -1017,7 +1024,7 @@ class TeleBot:
return types.MessageID.de_json(
apihelper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities,
disable_notification, reply_to_message_id, allow_sending_without_reply, reply_markup,
timeout))
timeout, protect_content))
def delete_message(self, chat_id: Union[int, str], message_id: int,
timeout: Optional[int]=None) -> bool:
@ -1036,7 +1043,8 @@ class TeleBot:
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send dices.
:param chat_id:
@ -1046,35 +1054,39 @@ class TeleBot:
:param reply_markup:
:param timeout:
:param allow_sending_without_reply:
:param protect_content:
:return: Message
"""
return types.Message.de_json(
apihelper.send_dice(
self.token, chat_id, emoji, disable_notification, reply_to_message_id,
reply_markup, timeout, allow_sending_without_reply)
reply_markup, timeout, allow_sending_without_reply, protect_content)
)
def send_photo(
self, chat_id: Union[int, str], photo: Union[Any, str],
caption: Optional[str]=None, reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
caption: Optional[str]=None, parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,) -> types.Message:
"""
Use this method to send photos.
Use this method to send photos. On success, the sent Message is returned.
:param chat_id:
:param photo:
:param caption:
:param parse_mode:
:param caption_entities:
:param disable_notification:
:param protect_content:
:param reply_to_message_id:
:param allow_sending_without_reply:
:param reply_markup:
:param timeout:
:param caption_entities:
:param allow_sending_without_reply:
:return: API reply.
:return: Message
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1082,8 +1094,9 @@ class TeleBot:
apihelper.send_photo(
self.token, chat_id, photo, caption, reply_to_message_id, reply_markup,
parse_mode, disable_notification, timeout, caption_entities,
allow_sending_without_reply))
allow_sending_without_reply, protect_content))
# TODO: Rewrite this method like in API.
def send_audio(
self, chat_id: Union[int, str], audio: Union[Any, str],
caption: Optional[str]=None, duration: Optional[int]=None,
@ -1095,7 +1108,8 @@ class TeleBot:
timeout: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=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 format.
@ -1113,6 +1127,7 @@ class TeleBot:
:param thumb:
:param caption_entities:
:param allow_sending_without_reply:
:param protect_content:
:return: Message
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1121,8 +1136,9 @@ class TeleBot:
apihelper.send_audio(
self.token, chat_id, audio, caption, duration, performer, title, reply_to_message_id,
reply_markup, parse_mode, disable_notification, timeout, thumb,
caption_entities, allow_sending_without_reply))
caption_entities, allow_sending_without_reply, protect_content))
# TODO: Rewrite this method like in API.
def send_voice(
self, chat_id: Union[int, str], voice: Union[Any, str],
caption: Optional[str]=None, duration: Optional[int]=None,
@ -1132,7 +1148,8 @@ class TeleBot:
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send audio files, if you want Telegram clients to display the file
as a playable voice message.
@ -1147,6 +1164,7 @@ class TeleBot:
:param timeout:
:param caption_entities:
:param allow_sending_without_reply:
:param protect_content:
:return: Message
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1155,10 +1173,11 @@ class TeleBot:
apihelper.send_voice(
self.token, chat_id, voice, caption, duration, reply_to_message_id, reply_markup,
parse_mode, disable_notification, timeout, caption_entities,
allow_sending_without_reply))
allow_sending_without_reply, protect_content))
# TODO: Rewrite this method like in API.
def send_document(
self, chat_id: Union[int, str], data: Union[Any, str],
self, chat_id: Union[int, str], document: Union[Any, str],
reply_to_message_id: Optional[int]=None,
caption: Optional[str]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
@ -1169,11 +1188,13 @@ class TeleBot:
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None,
visible_file_name: Optional[str]=None,
disable_content_type_detection: Optional[bool]=None) -> types.Message:
disable_content_type_detection: Optional[bool]=None,
data: Optional[Union[Any, str]]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send general files.
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param data: (document) File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data
:param document: (document) File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data
:param reply_to_message_id: If the message is a reply, ID of the original message
:param caption: Document caption (may also be used when resending documents by file_id), 0-1024 characters after entities parsing
:param reply_markup:
@ -1185,25 +1206,33 @@ class TeleBot:
:param allow_sending_without_reply:
:param visible_file_name: allows to define file name that will be visible in the Telegram instead of original file name
:param disable_content_type_detection: Disables automatic server-side content type detection for files uploaded using multipart/form-data
:param data: function typo miss compatibility: do not use it
:param protect_content:
:return: API reply.
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
if data and not(document):
# function typo miss compatibility
document = data
return types.Message.de_json(
apihelper.send_data(
self.token, chat_id, data, 'document',
self.token, chat_id, document, 'document',
reply_to_message_id = reply_to_message_id, reply_markup = reply_markup, parse_mode = parse_mode,
disable_notification = disable_notification, timeout = timeout, caption = caption, thumb = thumb,
caption_entities = caption_entities, allow_sending_without_reply = allow_sending_without_reply,
disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name))
disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content))
# TODO: Rewrite this method like in API.
def send_sticker(
self, chat_id: Union[int, str], data: Union[Any, str],
self, chat_id: Union[int, str], sticker: Union[Any, str],
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content:Optional[bool]=None,
data: Union[Any, str]=None) -> types.Message:
"""
Use this method to send .webp stickers.
:param chat_id:
@ -1213,83 +1242,98 @@ class TeleBot:
:param disable_notification: to disable the notification
:param timeout: timeout
:param allow_sending_without_reply:
:param protect_content:
:param data: function typo miss compatibility: do not use it
:return: API reply.
"""
if data and not(sticker):
# function typo miss compatibility
sticker = data
return types.Message.de_json(
apihelper.send_data(
self.token, chat_id, data, 'sticker',
self.token, chat_id, sticker, 'sticker',
reply_to_message_id=reply_to_message_id, reply_markup=reply_markup,
disable_notification=disable_notification, timeout=timeout,
allow_sending_without_reply=allow_sending_without_reply))
allow_sending_without_reply=allow_sending_without_reply, protect_content=protect_content))
def send_video(
self, chat_id: Union[int, str], data: Union[Any, str],
duration: Optional[int]=None,
caption: Optional[str]=None,
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None,
supports_streaming: Optional[bool]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
width: Optional[int]=None,
self, chat_id: Union[int, str], video: Union[Any, str],
duration: Optional[int]=None,
width: Optional[int]=None,
height: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
caption: Optional[str]=None,
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
supports_streaming: Optional[bool]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
data: Optional[Union[Any, str]]=None) -> types.Message:
"""
Use this method to send video files, Telegram clients support mp4 videos.
:param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
:param data: InputFile or String : Video to send. You can either pass a file_id as String to resend
a video that is already on the Telegram server
:param duration: Integer : Duration of sent video in seconds
:param caption: String : Video caption (may also be used when resending videos by file_id).
:param parse_mode:
:param supports_streaming:
:param reply_to_message_id:
:param reply_markup:
:param disable_notification:
:param timeout:
:param thumb: InputFile or String : Thumbnail of the file sent
:param width:
:param height:
Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document).
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param video: Video to send. You can either pass a file_id as String to resend a video that is already on the Telegram servers, or upload a new video file using multipart/form-data.
:param duration: Duration of sent video in seconds
:param width: Video width
:param height: Video height
:param thumb: 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://<file_attach_name>” if the thumbnail was uploaded using multipart/form-data under <file_attach_name>.
:param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing
:param parse_mode: Mode for parsing entities in the video caption
:param caption_entities:
:param supports_streaming: Pass True, if the uploaded video is suitable for streaming
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
:param protect_content:
:param reply_to_message_id: If the message is a reply, ID of the original message
:param allow_sending_without_reply:
:return:
:param reply_markup:
:param timeout:
:param data: function typo miss compatibility: do not use it
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
if data and not(video):
# function typo miss compatibility
video = data
return types.Message.de_json(
apihelper.send_video(
self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup,
self.token, chat_id, video, duration, caption, reply_to_message_id, reply_markup,
parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height,
caption_entities, allow_sending_without_reply))
caption_entities, allow_sending_without_reply, protect_content))
def send_animation(
self, chat_id: Union[int, str], animation: Union[Any, str],
duration: Optional[int]=None,
caption: Optional[str]=None,
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
width: Optional[int]=None,
height: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
caption: Optional[str]=None,
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None, ) -> types.Message:
"""
Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
:param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
:param animation: InputFile or String : Animation to send. You can either pass a file_id as String to resend an
animation that is already on the Telegram server
:param duration: Integer : Duration of sent video in seconds
:param width: Integer : Video width
:param height: Integer : Video height
:param thumb: InputFile or String : Thumbnail of the file sent
:param caption: String : Animation caption (may also be used when resending animation by file_id).
:param parse_mode:
:param reply_to_message_id:
:param reply_markup:
:param disable_notification:
:param timeout:
:param thumb: InputFile or String : Thumbnail of the file sent
:param caption_entities:
:param allow_sending_without_reply:
:return:
@ -1300,8 +1344,9 @@ class TeleBot:
apihelper.send_animation(
self.token, chat_id, animation, duration, caption, reply_to_message_id,
reply_markup, parse_mode, disable_notification, timeout, thumb,
caption_entities, allow_sending_without_reply))
caption_entities, allow_sending_without_reply, protect_content, width, height))
# TODO: Rewrite this method like in API.
def send_video_note(
self, chat_id: Union[int, str], data: Union[Any, str],
duration: Optional[int]=None,
@ -1311,7 +1356,8 @@ class TeleBot:
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. Use this method to send
video messages.
@ -1326,12 +1372,13 @@ class TeleBot:
:param timeout:
:param thumb: InputFile or String : Thumbnail of the file sent
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
return types.Message.de_json(
apihelper.send_video_note(
self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
disable_notification, timeout, thumb, allow_sending_without_reply))
disable_notification, timeout, thumb, allow_sending_without_reply, protect_content))
def send_media_group(
self, chat_id: Union[int, str],
@ -1339,6 +1386,7 @@ class TeleBot:
types.InputMediaAudio, types.InputMediaDocument,
types.InputMediaPhoto, types.InputMediaVideo]],
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> List[types.Message]:
@ -1347,6 +1395,7 @@ class TeleBot:
:param chat_id:
:param media:
:param disable_notification:
:param protect_content:
:param reply_to_message_id:
:param timeout:
:param allow_sending_without_reply:
@ -1354,9 +1403,11 @@ class TeleBot:
"""
result = apihelper.send_media_group(
self.token, chat_id, media, disable_notification, reply_to_message_id, timeout,
allow_sending_without_reply)
allow_sending_without_reply, protect_content)
return [types.Message.de_json(msg) for msg in result]
# TODO: Rewrite this method like in API.
def send_location(
self, chat_id: Union[int, str],
latitude: float, longitude: float,
@ -1368,7 +1419,8 @@ class TeleBot:
horizontal_accuracy: Optional[float]=None,
heading: Optional[int]=None,
proximity_alert_radius: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
@ -1385,6 +1437,7 @@ class TeleBot:
:param heading:
:param proximity_alert_radius:
:param allow_sending_without_reply:
:param protect_content:
:return: API reply.
"""
return types.Message.de_json(
@ -1392,7 +1445,7 @@ class TeleBot:
self.token, chat_id, latitude, longitude, live_period,
reply_to_message_id, reply_markup, disable_notification, timeout,
horizontal_accuracy, heading, proximity_alert_radius,
allow_sending_without_reply))
allow_sending_without_reply, protect_content))
def edit_message_live_location(
self, latitude: float, longitude: float,
@ -1444,6 +1497,7 @@ class TeleBot:
apihelper.stop_message_live_location(
self.token, chat_id, message_id, inline_message_id, reply_markup, timeout))
# TODO: Rewrite this method like in API.
def send_venue(
self, chat_id: Union[int, str],
latitude: float, longitude: float,
@ -1456,7 +1510,8 @@ class TeleBot:
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
google_place_id: Optional[str]=None,
google_place_type: Optional[str]=None) -> types.Message:
google_place_type: Optional[str]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send information about a venue.
:param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel
@ -1474,15 +1529,16 @@ class TeleBot:
:param allow_sending_without_reply:
:param google_place_id:
:param google_place_type:
:param protect_content:
:return:
"""
return types.Message.de_json(
apihelper.send_venue(
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
disable_notification, reply_to_message_id, reply_markup, timeout,
allow_sending_without_reply, google_place_id, google_place_type)
)
allow_sending_without_reply, google_place_id, google_place_type, protect_content))
# TODO: Rewrite this method like in API.
def send_contact(
self, chat_id: Union[int, str], phone_number: str,
first_name: str, last_name: Optional[str]=None,
@ -1491,13 +1547,13 @@ class TeleBot:
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
return types.Message.de_json(
apihelper.send_contact(
self.token, chat_id, phone_number, first_name, last_name, vcard,
disable_notification, reply_to_message_id, reply_markup, timeout,
allow_sending_without_reply)
)
allow_sending_without_reply, protect_content))
def send_chat_action(
self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None) -> bool:
@ -1667,6 +1723,38 @@ class TeleBot:
"""
return apihelper.set_chat_administrator_custom_title(self.token, chat_id, user_id, custom_title)
def ban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel.
The owner of the chat will not be able to send messages and join live
streams on behalf of the chat, unless it is unbanned first.
The bot must be an administrator in the supergroup or channel
for this to work and must have the appropriate administrator rights.
Returns True on success.
:params:
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param sender_chat_id: Unique identifier of the target sender chat
:return: True on success.
"""
return apihelper.ban_chat_sender_chat(self.token, chat_id, sender_chat_id)
def unban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to unban a previously banned channel chat in a supergroup or channel.
The bot must be an administrator for this to work and must have the appropriate
administrator rights.
Returns True on success.
:params:
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param sender_chat_id: Unique identifier of the target sender chat
:return: True on success.
"""
return apihelper.unban_chat_sender_chat(self.token, chat_id, sender_chat_id)
def set_chat_permissions(
self, chat_id: Union[int, str], permissions: types.ChatPermissions) -> bool:
"""
@ -1989,7 +2077,8 @@ class TeleBot:
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Used to send the game
:param chat_id:
@ -1999,12 +2088,13 @@ class TeleBot:
:param reply_markup:
:param timeout:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
result = apihelper.send_game(
self.token, chat_id, game_short_name, disable_notification,
reply_to_message_id, reply_markup, timeout,
allow_sending_without_reply)
allow_sending_without_reply, protect_content)
return types.Message.de_json(result)
def set_game_score(
@ -2046,6 +2136,7 @@ class TeleBot:
result = apihelper.get_game_high_scores(self.token, user_id, chat_id, message_id, inline_message_id)
return [types.GameHighScore.de_json(r) for r in result]
# TODO: rewrite this method like in API
def send_invoice(
self, chat_id: Union[int, str], title: str, description: str,
invoice_payload: str, provider_token: str, currency: str,
@ -2064,7 +2155,8 @@ class TeleBot:
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
max_tip_amount: Optional[int] = None,
suggested_tip_amounts: Optional[List[int]]=None) -> types.Message:
suggested_tip_amounts: Optional[List[int]]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Sends invoice
:param chat_id: Unique identifier for the target private chat
@ -2103,6 +2195,7 @@ class TeleBot:
: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:
:return:
"""
result = apihelper.send_invoice(
@ -2111,10 +2204,11 @@ class TeleBot:
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_to_message_id, reply_markup, provider_data, timeout, allow_sending_without_reply,
max_tip_amount, suggested_tip_amounts)
max_tip_amount, suggested_tip_amounts, protect_content)
return types.Message.de_json(result)
# noinspection PyShadowingBuiltins
# TODO: rewrite this method like in API
def send_poll(
self, chat_id: Union[int, str], question: str, options: List[str],
is_anonymous: Optional[bool]=None, type: Optional[str]=None,
@ -2130,7 +2224,8 @@ class TeleBot:
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
allow_sending_without_reply: Optional[bool]=None,
timeout: Optional[int]=None,
explanation_entities: Optional[List[types.MessageEntity]]=None) -> types.Message:
explanation_entities: Optional[List[types.MessageEntity]]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Send polls
:param chat_id:
@ -2151,6 +2246,7 @@ class TeleBot:
:param reply_markup:
:param timeout:
:param explanation_entities:
:param protect_content:
:return:
"""
@ -2164,7 +2260,7 @@ class TeleBot:
is_anonymous, type, allows_multiple_answers, correct_option_id,
explanation, explanation_parse_mode, open_period, close_date, is_closed,
disable_notification, reply_to_message_id, allow_sending_without_reply,
reply_markup, timeout, explanation_entities))
reply_markup, timeout, explanation_entities, protect_content))
def stop_poll(
self, chat_id: Union[int, str], message_id: int,

View File

@ -232,7 +232,7 @@ def send_message(
token, chat_id, text,
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, allow_sending_without_reply=None):
entities=None, allow_sending_without_reply=None, protect_content=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
@ -266,6 +266,8 @@ def send_message(
payload['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload, method='post')
@ -390,19 +392,21 @@ def get_chat_member(token, chat_id, user_id):
def forward_message(
token, chat_id, from_chat_id, message_id,
disable_notification=None, timeout=None):
disable_notification=None, timeout=None, protect_content=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification is not None:
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None):
reply_markup=None, timeout=None, protect_content=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:
@ -421,13 +425,15 @@ def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_m
payload['allow_sending_without_reply'] = allow_sending_without_reply
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
def send_dice(
token, chat_id,
emoji=None, disable_notification=None, reply_to_message_id=None,
reply_markup=None, timeout=None, allow_sending_without_reply=None):
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@ -442,6 +448,8 @@ def send_dice(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
@ -449,7 +457,7 @@ def send_photo(
token, chat_id, photo,
caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, allow_sending_without_reply=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -475,13 +483,15 @@ def send_photo(
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_media_group(
token, chat_id, media,
disable_notification=None, reply_to_message_id=None,
timeout=None, allow_sending_without_reply=None):
timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendMediaGroup'
media_json, files = convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@ -493,6 +503,8 @@ def send_media_group(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(
token, method_url, params=payload,
method='post' if files else 'get',
@ -504,7 +516,7 @@ def send_location(
live_period=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, allow_sending_without_reply=None):
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@ -525,6 +537,8 @@ def send_location(
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
@ -576,7 +590,7 @@ def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, google_place_id=None,
google_place_type=None):
google_place_type=None, protect_content=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@ -597,13 +611,15 @@ def send_venue(
payload['google_place_id'] = google_place_id
if google_place_type:
payload['google_place_type'] = google_place_type
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@ -620,6 +636,9 @@ def send_contact(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
@ -633,7 +652,7 @@ def send_chat_action(token, chat_id, action, timeout=None):
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None):
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -673,13 +692,15 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_animation(
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None, width=None, height=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@ -713,12 +734,18 @@ def send_animation(
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if width:
payload['width'] = width
if height:
payload['height'] = height
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -744,11 +771,13 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None):
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@ -780,12 +809,14 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m
payload['thumb'] = thumb
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
caption_entities=None, allow_sending_without_reply=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -823,6 +854,8 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload, files=files, method='post')
@ -969,6 +1002,18 @@ def set_chat_administrator_custom_title(token, chat_id, user_id, custom_title):
return _make_request(token, method_url, params=payload, method='post')
def ban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'banChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return _make_request(token, method_url, params=payload, method='post')
def unban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'unbanChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return _make_request(token, method_url, params=payload, method='post')
def set_chat_permissions(token, chat_id, permissions):
method_url = 'setChatPermissions'
payload = {
@ -1224,7 +1269,7 @@ def delete_message(token, chat_id, message_id, timeout=None):
def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@ -1237,6 +1282,9 @@ def send_game(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
@ -1301,7 +1349,8 @@ def send_invoice(
need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None,
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None):
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None,
protect_content=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)
@ -1379,6 +1428,8 @@ def send_invoice(
payload['max_tip_amount'] = max_tip_amount
if suggested_tip_amounts is not None:
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
if protect_content is not None:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)
@ -1527,7 +1578,7 @@ def send_poll(
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_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, explanation_entities=None):
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
@ -1569,6 +1620,8 @@ def send_poll(
if explanation_entities:
payload['explanation_entities'] = json.dumps(
types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
return _make_request(token, method_url, params=payload)

View File

@ -6,7 +6,7 @@ import re
import sys
import time
import traceback
from typing import Any, Callable, List, Optional, Union
from typing import Any, List, Optional, Union
# this imports are used to avoid circular import error
import telebot.util
@ -94,7 +94,81 @@ class CancelUpdate:
pass
class AsyncTeleBot:
""" This is AsyncTeleBot Class
Methods:
getMe
logOut
close
sendMessage
forwardMessage
copyMessage
deleteMessage
sendPhoto
sendAudio
sendDocument
sendSticker
sendVideo
sendVenue
sendAnimation
sendVideoNote
sendLocation
sendChatAction
sendDice
sendContact
sendInvoice
sendMediaGroup
getUserProfilePhotos
getUpdates
getFile
sendPoll
stopPoll
sendGame
setGameScore
getGameHighScores
editMessageText
editMessageCaption
editMessageMedia
editMessageReplyMarkup
editMessageLiveLocation
stopMessageLiveLocation
banChatMember
unbanChatMember
restrictChatMember
promoteChatMember
setChatAdministratorCustomTitle
setChatPermissions
createChatInviteLink
editChatInviteLink
revokeChatInviteLink
exportChatInviteLink
setChatStickerSet
deleteChatStickerSet
createNewStickerSet
addStickerToSet
deleteStickerFromSet
setStickerPositionInSet
uploadStickerFile
setStickerSetThumb
getStickerSet
setChatPhoto
deleteChatPhoto
setChatTitle
setChatDescription
pinChatMessage
unpinChatMessage
leaveChat
getChat
getChatAdministrators
getChatMemberCount
getChatMember
answerCallbackQuery
getMyCommands
setMyCommands
deleteMyCommands
answerInlineQuery
answerShippingQuery
answerPreCheckoutQuery
"""
def __init__(self, token: str, parse_mode: Optional[str]=None, offset=None,
exception_handler=None) -> None: # TODO: ADD TYPEHINTS
@ -133,11 +207,11 @@ class AsyncTeleBot:
async def get_updates(self, offset: Optional[int]=None, limit: Optional[int]=None,
timeout: Optional[int]=None, allowed_updates: Optional[List]=None, request_timeout: Optional[int]=None) -> types.Update:
timeout: Optional[int]=None, allowed_updates: Optional[List]=None, request_timeout: Optional[int]=None) -> List[types.Update]:
json_updates = await asyncio_helper.get_updates(self.token, offset, limit, timeout, allowed_updates, request_timeout)
return [types.Update.de_json(ju) for ju in json_updates]
def polling(self, non_stop: bool=False, skip_pending=False, interval: int=0, timeout: int=20,
async def polling(self, non_stop: bool=False, skip_pending=False, interval: int=0, timeout: int=20,
request_timeout: int=20, allowed_updates: Optional[List[str]]=None,
none_stop: Optional[bool]=None):
"""
@ -166,16 +240,16 @@ class AsyncTeleBot:
non_stop = none_stop
if skip_pending:
asyncio.run(self.skip_updates())
asyncio.run(self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates))
await self.skip_updates()
await self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates)
def infinity_polling(self, timeout: int=20, skip_pending: bool=False, request_timeout: int=20, logger_level=logging.ERROR,
async def infinity_polling(self, timeout: int=20, skip_pending: bool=False, request_timeout: int=20, logger_level=logging.ERROR,
allowed_updates: Optional[List[str]]=None, *args, **kwargs):
"""
Wrap polling with infinite loop and exception handling to avoid bot stops polling.
:param timeout: Request connection timeout
:param long_polling_timeout: Timeout in seconds for long polling (see API docs)
:param request_timeout: Timeout in seconds for long polling (see API docs)
:param skip_pending: skip old updates
:param logger_level: Custom logging level for infinity_polling logging.
Use logger levels from logging as a value. None/NOTSET = no error logging
@ -189,12 +263,12 @@ class AsyncTeleBot:
so unwanted updates may be received for a short period of time.
"""
if skip_pending:
asyncio.run(self.skip_updates())
await self.skip_updates()
self._polling = True
while self._polling:
try:
asyncio.run( self._process_polling(non_stop=True, timeout=timeout, request_timeout=request_timeout,
allowed_updates=allowed_updates, *args, **kwargs) )
await self._process_polling(non_stop=True, timeout=timeout, request_timeout=request_timeout,
allowed_updates=allowed_updates, *args, **kwargs)
except Exception as e:
if logger_level and logger_level >= logging.ERROR:
logger.error("Infinity polling exception: %s", str(e))
@ -243,6 +317,14 @@ class AsyncTeleBot:
except asyncio.CancelledError:
return
except asyncio_helper.RequestTimeout as e:
logger.error(str(e))
if non_stop:
await asyncio.sleep(2)
continue
else:
return
except asyncio_helper.ApiTelegramException as e:
logger.error(str(e))
@ -1402,16 +1484,19 @@ class AsyncTeleBot:
result = await asyncio_helper.get_chat_member(self.token, chat_id, user_id)
return types.ChatMember.de_json(result)
async def send_message(
self, chat_id: Union[int, str], text: str,
disable_web_page_preview: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
disable_web_page_preview: Optional[bool]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None) -> types.Message:
"""
Use this method to send text messages.
@ -1429,6 +1514,7 @@ class AsyncTeleBot:
:param timeout:
:param entities:
:param allow_sending_without_reply:
:param protect_content:
:return: API reply.
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1437,11 +1523,12 @@ class AsyncTeleBot:
await asyncio_helper.send_message(
self.token, chat_id, text, disable_web_page_preview, reply_to_message_id,
reply_markup, parse_mode, disable_notification, timeout,
entities, allow_sending_without_reply))
entities, allow_sending_without_reply, protect_content))
async def forward_message(
self, chat_id: Union[int, str], from_chat_id: Union[int, str],
message_id: int, disable_notification: Optional[bool]=None,
message_id: int, disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
timeout: Optional[int]=None) -> types.Message:
"""
Use this method to forward messages of any kind.
@ -1449,11 +1536,12 @@ class AsyncTeleBot:
:param chat_id: which chat to forward
:param from_chat_id: which chat message from
:param message_id: message id
:param protect_content:
:param timeout:
:return: API reply.
"""
return types.Message.de_json(
await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout))
await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content))
async def copy_message(
self, chat_id: Union[int, str],
@ -1463,6 +1551,7 @@ class AsyncTeleBot:
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
@ -1480,12 +1569,13 @@ class AsyncTeleBot:
:param allow_sending_without_reply:
:param reply_markup:
:param timeout:
:param protect_content:
:return: API reply.
"""
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_to_message_id, allow_sending_without_reply, reply_markup,
timeout))
timeout, protect_content))
async def delete_message(self, chat_id: Union[int, str], message_id: int,
timeout: Optional[int]=None) -> bool:
@ -1504,7 +1594,8 @@ class AsyncTeleBot:
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send dices.
:param chat_id:
@ -1514,22 +1605,25 @@ class AsyncTeleBot:
:param reply_markup:
:param timeout:
:param allow_sending_without_reply:
:param protect_content:
:return: Message
"""
return types.Message.de_json(
await asyncio_helper.send_dice(
self.token, chat_id, emoji, disable_notification, reply_to_message_id,
reply_markup, timeout, allow_sending_without_reply)
reply_markup, timeout, allow_sending_without_reply, protect_content)
)
async def send_photo(
self, chat_id: Union[int, str], photo: Union[Any, str],
caption: Optional[str]=None, reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
caption: Optional[str]=None, parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,) -> types.Message:
"""
Use this method to send photos.
:param chat_id:
@ -1542,6 +1636,7 @@ class AsyncTeleBot:
:param timeout:
:param caption_entities:
:param allow_sending_without_reply:
:param protect_content:
:return: API reply.
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1550,7 +1645,7 @@ class AsyncTeleBot:
await asyncio_helper.send_photo(
self.token, chat_id, photo, caption, reply_to_message_id, reply_markup,
parse_mode, disable_notification, timeout, caption_entities,
allow_sending_without_reply))
allow_sending_without_reply, protect_content))
async def send_audio(
self, chat_id: Union[int, str], audio: Union[Any, str],
@ -1563,7 +1658,8 @@ class AsyncTeleBot:
timeout: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=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 format.
@ -1581,6 +1677,7 @@ class AsyncTeleBot:
:param thumb:
:param caption_entities:
:param allow_sending_without_reply:
:param protect_content:
:return: Message
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1589,7 +1686,7 @@ class AsyncTeleBot:
await asyncio_helper.send_audio(
self.token, chat_id, audio, caption, duration, performer, title, reply_to_message_id,
reply_markup, parse_mode, disable_notification, timeout, thumb,
caption_entities, allow_sending_without_reply))
caption_entities, allow_sending_without_reply, protect_content))
async def send_voice(
self, chat_id: Union[int, str], voice: Union[Any, str],
@ -1600,7 +1697,8 @@ class AsyncTeleBot:
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send audio files, if you want Telegram clients to display the file
as a playable voice message.
@ -1615,6 +1713,7 @@ class AsyncTeleBot:
:param timeout:
:param caption_entities:
:param allow_sending_without_reply:
:param protect_content:
:return: Message
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1623,10 +1722,10 @@ class AsyncTeleBot:
await asyncio_helper.send_voice(
self.token, chat_id, voice, caption, duration, reply_to_message_id, reply_markup,
parse_mode, disable_notification, timeout, caption_entities,
allow_sending_without_reply))
allow_sending_without_reply, protect_content))
async def send_document(
self, chat_id: Union[int, str], data: Union[Any, str],
self, chat_id: Union[int, str], document: Union[Any, str],
reply_to_message_id: Optional[int]=None,
caption: Optional[str]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
@ -1637,11 +1736,13 @@ class AsyncTeleBot:
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None,
visible_file_name: Optional[str]=None,
disable_content_type_detection: Optional[bool]=None) -> types.Message:
disable_content_type_detection: Optional[bool]=None,
data: Optional[Union[Any, str]]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send general files.
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param data: (document) File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data
:param document: (document) File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data
:param reply_to_message_id: If the message is a reply, ID of the original message
:param caption: Document caption (may also be used when resending documents by file_id), 0-1024 characters after entities parsing
:param reply_markup:
@ -1653,77 +1754,90 @@ class AsyncTeleBot:
:param allow_sending_without_reply:
:param visible_file_name: allows to async define file name that will be visible in the Telegram instead of original file name
:param disable_content_type_detection: Disables automatic server-side content type detection for files uploaded using multipart/form-data
:param data: function typo compatibility: do not use it
:param protect_content:
:return: API reply.
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
if data and not(document):
# function typo miss compatibility
document = data
return types.Message.de_json(
await asyncio_helper.send_data(
self.token, chat_id, data, 'document',
self.token, chat_id, document, 'document',
reply_to_message_id = reply_to_message_id, reply_markup = reply_markup, parse_mode = parse_mode,
disable_notification = disable_notification, timeout = timeout, caption = caption, thumb = thumb,
caption_entities = caption_entities, allow_sending_without_reply = allow_sending_without_reply,
disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name))
disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content))
async def send_sticker(
self, chat_id: Union[int, str], data: Union[Any, str],
self, chat_id: Union[int, str], sticker: Union[Any, str],
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None,
data: Union[Any, str]=None) -> types.Message:
"""
Use this method to send .webp stickers.
:param chat_id:
:param data:
:param sticker:
:param reply_to_message_id:
:param reply_markup:
:param disable_notification: to disable the notification
:param timeout: timeout
:param allow_sending_without_reply:
:param protect_content:
:return: API reply.
"""
if data and not(sticker):
# function typo miss compatibility
sticker = data
return types.Message.de_json(
await asyncio_helper.send_data(
self.token, chat_id, data, 'sticker',
self.token, chat_id, sticker, 'sticker',
reply_to_message_id=reply_to_message_id, reply_markup=reply_markup,
disable_notification=disable_notification, timeout=timeout,
allow_sending_without_reply=allow_sending_without_reply))
allow_sending_without_reply=allow_sending_without_reply, protect_content=protect_content))
async def send_video(
self, chat_id: Union[int, str], data: Union[Any, str],
duration: Optional[int]=None,
caption: Optional[str]=None,
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None,
supports_streaming: Optional[bool]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
width: Optional[int]=None,
self, chat_id: Union[int, str], video: Union[Any, str],
duration: Optional[int]=None,
width: Optional[int]=None,
height: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
caption: Optional[str]=None,
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
supports_streaming: Optional[bool]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
data: Optional[Union[Any, str]]=None) -> types.Message:
"""
Use this method to send video files, Telegram clients support mp4 videos.
:param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
:param data: InputFile or String : Video to send. You can either pass a file_id as String to resend
a video that is already on the Telegram server
:param duration: Integer : Duration of sent video in seconds
:param caption: String : Video caption (may also be used when resending videos by file_id).
:param parse_mode:
:param supports_streaming:
:param reply_to_message_id:
:param reply_markup:
:param disable_notification:
:param timeout:
:param thumb: InputFile or String : Thumbnail of the file sent
:param width:
:param height:
Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document).
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param video: Video to send. You can either pass a file_id as String to resend a video that is already on the Telegram servers, or upload a new video file using multipart/form-data.
:param duration: Duration of sent video in seconds
:param width: Video width
:param height: Video height
:param thumb: 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://<file_attach_name>” if the thumbnail was uploaded using multipart/form-data under <file_attach_name>.
:param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing
:param parse_mode: Mode for parsing entities in the video caption
:param caption_entities:
:param supports_streaming: Pass True, if the uploaded video is suitable for streaming
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
:param protect_content:
:param reply_to_message_id: If the message is a reply, ID of the original message
:param allow_sending_without_reply:
:return:
:param reply_markup:
:param timeout:
:param data: function typo miss compatibility: do not use it
"""
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
@ -1731,33 +1845,38 @@ class AsyncTeleBot:
await asyncio_helper.send_video(
self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup,
parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height,
caption_entities, allow_sending_without_reply))
caption_entities, allow_sending_without_reply, protect_content))
async def send_animation(
self, chat_id: Union[int, str], animation: Union[Any, str],
duration: Optional[int]=None,
caption: Optional[str]=None,
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
parse_mode: Optional[str]=None,
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
width: Optional[int]=None,
height: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
caption: Optional[str]=None,
parse_mode: Optional[str]=None,
caption_entities: Optional[List[types.MessageEntity]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None, ) -> types.Message:
"""
Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
:param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id
:param animation: InputFile or String : Animation to send. You can either pass a file_id as String to resend an
animation that is already on the Telegram server
:param duration: Integer : Duration of sent video in seconds
:param width: Integer : Video width
:param height: Integer : Video height
:param thumb: InputFile or String : Thumbnail of the file sent
:param caption: String : Animation caption (may also be used when resending animation by file_id).
:param parse_mode:
:param reply_to_message_id:
:param reply_markup:
:param disable_notification:
:param timeout:
:param thumb: InputFile or String : Thumbnail of the file sent
:param caption_entities:
:param allow_sending_without_reply:
:return:
@ -1768,7 +1887,7 @@ class AsyncTeleBot:
await asyncio_helper.send_animation(
self.token, chat_id, animation, duration, caption, reply_to_message_id,
reply_markup, parse_mode, disable_notification, timeout, thumb,
caption_entities, allow_sending_without_reply))
caption_entities, allow_sending_without_reply, width, height, protect_content))
async def send_video_note(
self, chat_id: Union[int, str], data: Union[Any, str],
@ -1779,7 +1898,8 @@ class AsyncTeleBot:
disable_notification: Optional[bool]=None,
timeout: Optional[int]=None,
thumb: Optional[Union[Any, str]]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. Use this method to send
video messages.
@ -1794,12 +1914,13 @@ class AsyncTeleBot:
:param timeout:
:param thumb: InputFile or String : Thumbnail of the file sent
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
return types.Message.de_json(
await asyncio_helper.send_video_note(
self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
disable_notification, timeout, thumb, allow_sending_without_reply))
disable_notification, timeout, thumb, allow_sending_without_reply, protect_content))
async def send_media_group(
self, chat_id: Union[int, str],
@ -1807,6 +1928,7 @@ class AsyncTeleBot:
types.InputMediaAudio, types.InputMediaDocument,
types.InputMediaPhoto, types.InputMediaVideo]],
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
reply_to_message_id: Optional[int]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> List[types.Message]:
@ -1818,11 +1940,12 @@ class AsyncTeleBot:
:param reply_to_message_id:
:param timeout:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
result = await asyncio_helper.send_media_group(
self.token, chat_id, media, disable_notification, reply_to_message_id, timeout,
allow_sending_without_reply)
allow_sending_without_reply, protect_content)
return [types.Message.de_json(msg) for msg in result]
async def send_location(
@ -1836,7 +1959,8 @@ class AsyncTeleBot:
horizontal_accuracy: Optional[float]=None,
heading: Optional[int]=None,
proximity_alert_radius: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
@ -1853,6 +1977,7 @@ class AsyncTeleBot:
:param heading:
:param proximity_alert_radius:
:param allow_sending_without_reply:
:param protect_content:
:return: API reply.
"""
return types.Message.de_json(
@ -1860,7 +1985,7 @@ class AsyncTeleBot:
self.token, chat_id, latitude, longitude, live_period,
reply_to_message_id, reply_markup, disable_notification, timeout,
horizontal_accuracy, heading, proximity_alert_radius,
allow_sending_without_reply))
allow_sending_without_reply, protect_content))
async def edit_message_live_location(
self, latitude: float, longitude: float,
@ -1924,7 +2049,8 @@ class AsyncTeleBot:
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
google_place_id: Optional[str]=None,
google_place_type: Optional[str]=None) -> types.Message:
google_place_type: Optional[str]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send information about a venue.
:param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel
@ -1942,13 +2068,14 @@ class AsyncTeleBot:
:param allow_sending_without_reply:
:param google_place_id:
:param google_place_type:
:param protect_content:
:return:
"""
return types.Message.de_json(
await asyncio_helper.send_venue(
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
disable_notification, reply_to_message_id, reply_markup, timeout,
allow_sending_without_reply, google_place_id, google_place_type)
allow_sending_without_reply, google_place_id, google_place_type, protect_content)
)
async def send_contact(
@ -1959,12 +2086,27 @@ class AsyncTeleBot:
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Use this method to send phone contacts.
:param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel
:param phone_number: String : Contact's phone number
:param first_name: String : Contact's first name
:param last_name: String : Contact's last name
:param vcard: String : Additional data about the contact in the form of a vCard, 0-2048 bytes
:param disable_notification:
:param reply_to_message_id:
:param reply_markup:
:param timeout:
:param allow_sending_without_reply:
:param protect_content:
"""
return types.Message.de_json(
await asyncio_helper.send_contact(
self.token, chat_id, phone_number, first_name, last_name, vcard,
disable_notification, reply_to_message_id, reply_markup, timeout,
allow_sending_without_reply)
allow_sending_without_reply, protect_content)
)
async def send_chat_action(
@ -2135,6 +2277,37 @@ class AsyncTeleBot:
"""
return await asyncio_helper.set_chat_administrator_custom_title(self.token, chat_id, user_id, custom_title)
async def ban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel.
The owner of the chat will not be able to send messages and join live
streams on behalf of the chat, unless it is unbanned first.
The bot must be an administrator in the supergroup or channel
for this to work and must have the appropriate administrator rights.
Returns True on success.
:params:
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param sender_chat_id: Unique identifier of the target sender chat
:return: True on success.
"""
return await asyncio_helper.ban_chat_sender_chat(self.token, chat_id, sender_chat_id)
async def unban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to unban a previously banned channel chat in a supergroup or channel.
The bot must be an administrator for this to work and must have the appropriate
administrator rights.
Returns True on success.
:params:
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
:param sender_chat_id: Unique identifier of the target sender chat
:return: True on success.
"""
return await asyncio_helper.unban_chat_sender_chat(self.token, chat_id, sender_chat_id)
async def set_chat_permissions(
self, chat_id: Union[int, str], permissions: types.ChatPermissions) -> bool:
"""
@ -2458,7 +2631,8 @@ class AsyncTeleBot:
reply_to_message_id: Optional[int]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None) -> types.Message:
allow_sending_without_reply: Optional[bool]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Used to send the game
:param chat_id:
@ -2468,12 +2642,13 @@ class AsyncTeleBot:
:param reply_markup:
:param timeout:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
result = await asyncio_helper.send_game(
self.token, chat_id, game_short_name, disable_notification,
reply_to_message_id, reply_markup, timeout,
allow_sending_without_reply)
allow_sending_without_reply, protect_content)
return types.Message.de_json(result)
async def set_game_score(
@ -2533,7 +2708,8 @@ class AsyncTeleBot:
timeout: Optional[int]=None,
allow_sending_without_reply: Optional[bool]=None,
max_tip_amount: Optional[int] = None,
suggested_tip_amounts: Optional[List[int]]=None) -> types.Message:
suggested_tip_amounts: Optional[List[int]]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Sends invoice
:param chat_id: Unique identifier for the target private chat
@ -2572,6 +2748,7 @@ class AsyncTeleBot:
: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:
:return:
"""
result = await asyncio_helper.send_invoice(
@ -2580,7 +2757,7 @@ class AsyncTeleBot:
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_to_message_id, reply_markup, provider_data, timeout, allow_sending_without_reply,
max_tip_amount, suggested_tip_amounts)
max_tip_amount, suggested_tip_amounts, protect_content)
return types.Message.de_json(result)
# noinspection PyShadowingBuiltins
@ -2599,7 +2776,8 @@ class AsyncTeleBot:
reply_markup: Optional[REPLY_MARKUP_TYPES]=None,
allow_sending_without_reply: Optional[bool]=None,
timeout: Optional[int]=None,
explanation_entities: Optional[List[types.MessageEntity]]=None) -> types.Message:
explanation_entities: Optional[List[types.MessageEntity]]=None,
protect_content: Optional[bool]=None) -> types.Message:
"""
Send polls
:param chat_id:
@ -2620,6 +2798,7 @@ class AsyncTeleBot:
:param reply_markup:
:param timeout:
:param explanation_entities:
:param protect_content:
:return:
"""
@ -2633,7 +2812,7 @@ class AsyncTeleBot:
is_anonymous, type, allows_multiple_answers, correct_option_id,
explanation, explanation_parse_mode, open_period, close_date, is_closed,
disable_notification, reply_to_message_id, allow_sending_without_reply,
reply_markup, timeout, explanation_entities))
reply_markup, timeout, explanation_entities, protect_content))
async def stop_poll(
self, chat_id: Union[int, str], message_id: int,

View File

@ -34,26 +34,39 @@ CONNECT_TIMEOUT = 15
READ_TIMEOUT = 30
LONG_POLLING_TIMEOUT = 10 # Should be positive, short polling should be used for testing purposes only (https://core.telegram.org/bots/api#getupdates)
REQUEST_TIMEOUT = 10
MAX_RETRIES = 3
logger = telebot.logger
RETRY_ON_ERROR = False
RETRY_TIMEOUT = 2
MAX_RETRIES = 15
async def _process_request(token, url, method='get', params=None, files=None, request_timeout=None):
params = compose_data(params, files)
params = prepare_data(params, files)
if request_timeout is None:
request_timeout = REQUEST_TIMEOUT
timeout = aiohttp.ClientTimeout(total=request_timeout)
got_result = False
current_try=0
async with await session_manager._get_new_session() as session:
async with session.request(method=method, url=API_URL.format(token, url), data=params, timeout=request_timeout) as response:
logger.debug("Request: method={0} url={1} params={2} files={3} request_timeout={4}".format(method, url, params, files, request_timeout).replace(token, token.split(':')[0] + ":{TOKEN}"))
json_result = await _check_result(url, response)
if json_result:
return json_result['result']
while not got_result and current_try<MAX_RETRIES-1:
current_try +=1
try:
response = await session.request(method=method, url=API_URL.format(token, url), data=params, timeout=timeout)
logger.debug("Request: method={0} url={1} params={2} files={3} request_timeout={4} current_try={5}".format(method, url, params, files, request_timeout, current_try).replace(token, token.split(':')[0] + ":{TOKEN}"))
json_result = await _check_result(url, response)
if json_result:
return json_result['result']
except (ApiTelegramException,ApiInvalidJSONException, ApiHTTPException) as e:
raise e
except:
pass
if not got_result:
raise RequestTimeout("Request timeout. Request: method={0} url={1} params={2} files={3} request_timeout={4}".format(method, url, params, files, request_timeout, current_try))
def guess_filename(obj):
def prepare_file(obj):
"""
Get file name from object
returns os.path.basename for a given file
:param obj:
:return:
@ -63,9 +76,9 @@ def guess_filename(obj):
return os.path.basename(name)
def compose_data(params=None, files=None):
def prepare_data(params=None, files=None):
"""
Prepare request data
prepare data for request.
:param params:
:param files:
@ -85,7 +98,7 @@ def compose_data(params=None, files=None):
else:
raise ValueError('Tuple must have exactly 2 elements: filename, fileobj')
else:
filename, fileobj = guess_filename(f) or key, f
filename, fileobj = prepare_file(f) or key, f
data.add_field(key, fileobj, filename=filename)
@ -228,7 +241,7 @@ async def send_message(
token, chat_id, text,
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, allow_sending_without_reply=None):
entities=None, allow_sending_without_reply=None, protect_content=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
@ -242,6 +255,7 @@ async def send_message(
:param timeout:
:param entities:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
method_name = 'sendMessage'
@ -262,6 +276,8 @@ async def send_message(
params['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities))
if allow_sending_without_reply is not None:
params['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
params['protect_content'] = protect_content
return await _process_request(token, method_name, params=params)
@ -333,19 +349,21 @@ async def get_chat_member(token, chat_id, user_id):
async def forward_message(
token, chat_id, from_chat_id, message_id,
disable_notification=None, timeout=None):
disable_notification=None, timeout=None, protect_content=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification is not None:
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None):
reply_markup=None, timeout=None, protect_content=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:
@ -364,13 +382,15 @@ async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, p
payload['allow_sending_without_reply'] = allow_sending_without_reply
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
async def send_dice(
token, chat_id,
emoji=None, disable_notification=None, reply_to_message_id=None,
reply_markup=None, timeout=None, allow_sending_without_reply=None):
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@ -385,6 +405,8 @@ async def send_dice(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
@ -392,7 +414,7 @@ async def send_photo(
token, chat_id, photo,
caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, allow_sending_without_reply=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -418,13 +440,15 @@ async def send_photo(
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_media_group(
token, chat_id, media,
disable_notification=None, reply_to_message_id=None,
timeout=None, allow_sending_without_reply=None):
timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendMediaGroup'
media_json, files = await convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@ -436,6 +460,8 @@ async def send_media_group(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(
token, method_url, params=payload,
method='post' if files else 'get',
@ -447,7 +473,7 @@ async def send_location(
live_period=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, allow_sending_without_reply=None):
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@ -468,6 +494,8 @@ async def send_location(
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
@ -519,7 +547,7 @@ async def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, google_place_id=None,
google_place_type=None):
google_place_type=None, protect_content=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@ -540,13 +568,15 @@ async def send_venue(
payload['google_place_id'] = google_place_id
if google_place_type:
payload['google_place_type'] = google_place_type
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@ -563,6 +593,8 @@ async def send_contact(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
@ -576,7 +608,8 @@ async def send_chat_action(token, chat_id, action, timeout=None):
async def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None):
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None,
protect_content=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -616,13 +649,15 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_animation(
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, width=None, height=None, protect_content=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@ -656,12 +691,18 @@ async def send_animation(
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if width:
payload['width'] = width
if height:
payload['height'] = height
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -687,11 +728,13 @@ async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_t
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None):
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@ -723,12 +766,14 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, repl
payload['thumb'] = thumb
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
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_to_message_id=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
caption_entities=None, allow_sending_without_reply=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -766,12 +811,14 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None):
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None):
method_url = await get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@ -912,6 +959,17 @@ async def set_chat_administrator_custom_title(token, chat_id, user_id, custom_ti
return await _process_request(token, method_url, params=payload, method='post')
async def ban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'banChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return await _process_request(token, method_url, params=payload, method='post')
async def unban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'unbanChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return await _process_request(token, method_url, params=payload, method='post')
async def set_chat_permissions(token, chat_id, permissions):
method_url = 'setChatPermissions'
payload = {
@ -1165,7 +1223,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_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@ -1178,6 +1236,8 @@ async def send_game(
payload['timeout'] = timeout
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
@ -1242,7 +1302,7 @@ async def send_invoice(
need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None,
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None):
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None, protect_content=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)
@ -1274,6 +1334,7 @@ async def send_invoice(
: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 protect_content:
:return:
"""
method_url = r'sendInvoice'
@ -1320,6 +1381,8 @@ async def send_invoice(
payload['max_tip_amount'] = max_tip_amount
if suggested_tip_amounts is not None:
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
if protect_content is not None:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
@ -1468,7 +1531,7 @@ async def send_poll(
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_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, explanation_entities=None):
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
@ -1510,6 +1573,8 @@ async def send_poll(
if explanation_entities:
payload['explanation_entities'] = json.dumps(
types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
return await _process_request(token, method_url, params=payload)
async def _convert_list_json_serializable(results):
@ -1632,4 +1697,10 @@ class ApiTelegramException(ApiException):
function_name,
result)
self.result_json = result_json
self.error_code = result_json['error_code']
self.error_code = result_json['error_code']
class RequestTimeout(Exception):
"""
This class represents a request timeout.
"""
pass

View File

@ -274,10 +274,11 @@ class Chat(JsonDeserializable):
return cls(**obj)
def __init__(self, id, type, title=None, username=None, first_name=None,
last_name=None, photo=None, bio=None, description=None, invite_link=None,
pinned_message=None, permissions=None, slow_mode_delay=None,
message_auto_delete_time=None, sticker_set_name=None, can_set_sticker_set=None,
linked_chat_id=None, location=None, **kwargs):
last_name=None, photo=None, bio=None, has_private_forwards=None,
description=None, invite_link=None, pinned_message=None,
permissions=None, slow_mode_delay=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, **kwargs):
self.id: int = id
self.type: str = type
self.title: str = title
@ -286,12 +287,14 @@ class Chat(JsonDeserializable):
self.last_name: str = last_name
self.photo: ChatPhoto = photo
self.bio: str = bio
self.has_private_forwards: bool = has_private_forwards
self.description: str = description
self.invite_link: str = invite_link
self.pinned_message: Message = pinned_message
self.permissions: ChatPermissions = permissions
self.slow_mode_delay: int = slow_mode_delay
self.message_auto_delete_time: int = message_auto_delete_time
self.has_protected_content: bool = has_protected_content
self.sticker_set_name: str = sticker_set_name
self.can_set_sticker_set: bool = can_set_sticker_set
self.linked_chat_id: int = linked_chat_id
@ -334,12 +337,16 @@ class Message(JsonDeserializable):
opts['forward_sender_name'] = obj.get('forward_sender_name')
if 'forward_date' in obj:
opts['forward_date'] = obj.get('forward_date')
if 'is_automatic_forward' in obj:
opts['is_automatic_forward'] = obj.get('is_automatic_forward')
if 'reply_to_message' in obj:
opts['reply_to_message'] = Message.de_json(obj['reply_to_message'])
if 'via_bot' in obj:
opts['via_bot'] = User.de_json(obj['via_bot'])
if 'edit_date' in obj:
opts['edit_date'] = obj.get('edit_date')
if 'has_protected_content' in obj:
opts['has_protected_content'] = obj.get('has_protected_content')
if 'media_group_id' in obj:
opts['media_group_id'] = obj.get('media_group_id')
if 'author_signature' in obj:
@ -503,9 +510,11 @@ class Message(JsonDeserializable):
self.forward_signature: Optional[str] = None
self.forward_sender_name: Optional[str] = None
self.forward_date: Optional[int] = None
self.is_automatic_forward: Optional[bool] = None
self.reply_to_message: Optional[Message] = None
self.via_bot: Optional[User] = None
self.edit_date: Optional[int] = None
self.has_protected_content: Optional[bool] = None
self.media_group_id: Optional[str] = None
self.author_signature: Optional[str] = None
self.text: Optional[str] = None
@ -573,7 +582,8 @@ class Message(JsonDeserializable):
# "url": "<a href=\"{url}\">{text}</a>", # @badiboy plain URLs have no text and do not need tags
"text_link": "<a href=\"{url}\">{text}</a>",
"strikethrough": "<s>{text}</s>",
"underline": "<u>{text}</u>"
"underline": "<u>{text}</u>",
"spoiler": "<span class=\"tg-spoiler\">{text}</span>",
}
if hasattr(self, "custom_subs"):

View File

@ -1,3 +1,3 @@
# Versions should comply with PEP440.
# This line is parsed in setup.py:
__version__ = '4.2.1'
__version__ = '4.3.0'

View File

@ -50,7 +50,7 @@ def test_json_message_with_dice():
def test_json_message_group():
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG","is_bot":true},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI"}'
json_string = r'{"message_id":10,"from":{"id":12345,"first_name":"g","last_name":"G","username":"GG","is_bot":true},"chat":{"id":-866,"type":"private","title":"\u4ea4"},"date":1435303157,"text":"HIHI","has_protected_content":true}'
msg = types.Message.de_json(json_string)
assert msg.text == 'HIHI'
assert len(msg.chat.title) != 0