From a5305f551c50a0ff06e787fe856c41868eefb94b Mon Sep 17 00:00:00 2001 From: _run Date: Fri, 3 Dec 2021 21:13:02 +0500 Subject: [PATCH 1/7] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1908e45..492a1bf 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ * [Reply markup](#reply-markup) * [Advanced use of the API](#advanced-use-of-the-api) * [Using local Bot API Server](#using-local-bot-api-sever) - * [Asynchronous delivery of messages](#asynchronous-delivery-of-messages) + * [Asynchronous TeleBot](#asynchronous-telebot) * [Sending large text messages](#sending-large-text-messages) * [Controlling the amount of Threads used by TeleBot](#controlling-the-amount-of-threads-used-by-telebot) * [The listener mechanism](#the-listener-mechanism) @@ -555,26 +555,26 @@ apihelper.API_URL = "http://localhost:4200/bot{0}/{1}" *Note: 4200 is an example port* -### Asynchronous delivery of messages -There exists an implementation of TeleBot which executes all `send_xyz` and the `get_me` functions asynchronously. This can speed up your bot __significantly__, but it has unwanted side effects if used without caution. +### Asynchronous TeleBot +New: There is an asynchronous implementation of telebot. It is more flexible. To enable this behaviour, create an instance of AsyncTeleBot instead of TeleBot. ```python tb = telebot.AsyncTeleBot("TOKEN") ``` -Now, every function that calls the Telegram API is executed in a separate Thread. The functions are modified to return an AsyncTask instance (defined in util.py). Using AsyncTeleBot allows you to do the following: +Now, every function that calls the Telegram API is executed in a separate asynchronous task. +Using AsyncTeleBot allows you to do the following: ```python import telebot tb = telebot.AsyncTeleBot("TOKEN") -task = tb.get_me() # Execute an API call -# Do some other operations... -a = 0 -for a in range(100): - a += 10 -result = task.wait() # Get the result of the execution +@tb.message_handler(commands=['start']) +async def start_message(message): + await bot.send_message(message.chat.id, 'Hello'!) + ``` -*Note: if you execute send_xyz functions after eachother without calling wait(), the order in which messages are delivered might be wrong.* + +See more in [examples](https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot) ### Sending large text messages Sometimes you must send messages that exceed 5000 characters. The Telegram API can not handle that many characters in one request, so we need to split the message in multiples. Here is how to do that using the API: From 51eabde320b99520f7ed64876fd9b01a799fd0c2 Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 4 Dec 2021 21:11:51 +0500 Subject: [PATCH 2/7] Update --- .../download_file_example.py | 20 ++++++++ .../asynchronous_telebot/exception_handler.py | 27 +++++++++++ .../middleware/flooding_middleware.py | 39 +++++++++++++++ .../asynchronous_telebot/middleware/i18n.py | 48 +++++++++++++++++++ .../asynchronous_telebot/send_file_example.py | 27 +++++++++++ 5 files changed, 161 insertions(+) create mode 100644 examples/asynchronous_telebot/download_file_example.py create mode 100644 examples/asynchronous_telebot/exception_handler.py create mode 100644 examples/asynchronous_telebot/middleware/flooding_middleware.py create mode 100644 examples/asynchronous_telebot/middleware/i18n.py create mode 100644 examples/asynchronous_telebot/send_file_example.py diff --git a/examples/asynchronous_telebot/download_file_example.py b/examples/asynchronous_telebot/download_file_example.py new file mode 100644 index 0000000..5105d9d --- /dev/null +++ b/examples/asynchronous_telebot/download_file_example.py @@ -0,0 +1,20 @@ + +import telebot +from telebot.async_telebot import AsyncTeleBot + + + +bot = AsyncTeleBot('TOKEN') + + +@bot.message_handler(content_types=['photo']) +async def new_message(message: telebot.types.Message): + result_message = await bot.send_message(message.chat.id, 'Downloading your photo...', parse_mode='HTML', disable_web_page_preview=True) + file_path = await bot.get_file(message.photo[-1].file_id) + downloaded_file = await bot.download_file(file_path.file_path) + with open('file.jpg', 'wb') as new_file: + new_file.write(downloaded_file) + await bot.edit_message_text(chat_id=message.chat.id, message_id=result_message.id, text='Done!', parse_mode='HTML') + + +bot.polling(skip_pending=True) diff --git a/examples/asynchronous_telebot/exception_handler.py b/examples/asynchronous_telebot/exception_handler.py new file mode 100644 index 0000000..f1da60f --- /dev/null +++ b/examples/asynchronous_telebot/exception_handler.py @@ -0,0 +1,27 @@ + +import telebot +from telebot.async_telebot import AsyncTeleBot + + +import logging + +logger = telebot.logger +telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console. + +class ExceptionHandler(telebot.ExceptionHandler): + def handle(self, exception): + logger.error(exception) + +bot = AsyncTeleBot('TOKEN',exception_handler=ExceptionHandler()) + + + + +@bot.message_handler(commands=['photo']) +async def photo_send(message: telebot.types.Message): + await bot.send_message(message.chat.id, 'Hi, this is an example of exception handlers.') + raise Exception('test') # Exception goes to ExceptionHandler if it is set + + + +bot.polling(skip_pending=True) diff --git a/examples/asynchronous_telebot/middleware/flooding_middleware.py b/examples/asynchronous_telebot/middleware/flooding_middleware.py new file mode 100644 index 0000000..de70702 --- /dev/null +++ b/examples/asynchronous_telebot/middleware/flooding_middleware.py @@ -0,0 +1,39 @@ +# Just a little example of middleware handlers + +import telebot +from telebot.asyncio_handler_backends import BaseMiddleware +from telebot.async_telebot import AsyncTeleBot +from telebot.async_telebot import CancelUpdate +bot = AsyncTeleBot('TOKEN') + + +class SimpleMiddleware(BaseMiddleware): + def __init__(self, limit) -> None: + self.last_time = {} + self.limit = limit + self.update_types = ['message'] + # Always specify update types, otherwise middlewares won't work + + + async def pre_process(self, message, data): + if not message.from_user.id in self.last_time: + # User is not in a dict, so lets add and cancel this function + self.last_time[message.from_user.id] = message.date + return + if message.date - self.last_time[message.from_user.id] < self.limit: + # User is flooding + await bot.send_message(message.chat.id, 'You are making request too often') + return CancelUpdate() + self.last_time[message.from_user.id] = message.date + + + async def post_process(self, message, data, exception): + pass + +bot.setup_middleware(SimpleMiddleware(2)) + +@bot.message_handler(commands=['start']) +async def start(message): + await bot.send_message(message.chat.id, 'Hello!') + +bot.polling() \ No newline at end of file diff --git a/examples/asynchronous_telebot/middleware/i18n.py b/examples/asynchronous_telebot/middleware/i18n.py new file mode 100644 index 0000000..3c3196e --- /dev/null +++ b/examples/asynchronous_telebot/middleware/i18n.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# This example shows how to implement i18n (internationalization) l10n (localization) to create +# multi-language bots with middleware handler. +# +# Also, you could check language code in handler itself too. +# But this example just to show the work of middlewares. + +import telebot +from telebot.async_telebot import AsyncTeleBot +from telebot import asyncio_handler_backends +import logging + +logger = telebot.logger +telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console. + +TRANSLATIONS = { + 'hello': { + 'en': 'hello', + 'ru': 'привет', + 'uz': 'salom' + } +} + + + +bot = AsyncTeleBot('TOKEN') + + +class LanguageMiddleware(asyncio_handler_backends.BaseMiddleware): + def __init__(self): + self.update_types = ['message'] # Update types that will be handled by this middleware. + async def pre_process(self, message, data): + data['response'] = TRANSLATIONS['hello'][message.from_user.language_code] + async def post_process(self, message, data, exception): + if exception: # You can get exception occured in handler. + logger.exception(str(exception)) + +bot.setup_middleware(LanguageMiddleware()) # do not forget to setup + +@bot.message_handler(commands=['start']) +async def start(message, data: dict): + # you can get the data in handler too. + # Not necessary to create data parameter in handler function. + await bot.send_message(message.chat.id, data['response']) + + +bot.polling() diff --git a/examples/asynchronous_telebot/send_file_example.py b/examples/asynchronous_telebot/send_file_example.py new file mode 100644 index 0000000..64e3047 --- /dev/null +++ b/examples/asynchronous_telebot/send_file_example.py @@ -0,0 +1,27 @@ + +import telebot +from telebot.async_telebot import AsyncTeleBot + + + +bot = AsyncTeleBot('1297441208:AAH-Z-YbiK_pQ1jTuHXYa-hA_PLZQVQ6qsw') + + +@bot.message_handler(commands=['photo']) +async def photo_send(message: telebot.types.Message): + with open('test.png', 'rb') as new_file: + await bot.send_photo(message.chat.id, new_file) + +@bot.message_handler(commands=['document']) +async def document_send(message: telebot.types.Message): + with open('test.docx', 'rb') as new_file: + await bot.send_document(message.chat.id, new_file) + +@bot.message_handler(commands=['photos']) +async def photos_send(message: telebot.types.Message): + with open('test.png', 'rb') as new_file, open('test2.png', 'rb') as new_file2: + await bot.send_media_group(message.chat.id, [telebot.types.InputMediaPhoto(new_file), telebot.types.InputMediaPhoto(new_file2)]) + + + +bot.polling(skip_pending=True) From 3035763277f9729ec28ef0c41f217a847029afad Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 4 Dec 2021 21:22:00 +0500 Subject: [PATCH 3/7] Update send_file_example.py --- examples/asynchronous_telebot/send_file_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/asynchronous_telebot/send_file_example.py b/examples/asynchronous_telebot/send_file_example.py index 64e3047..e67f8d8 100644 --- a/examples/asynchronous_telebot/send_file_example.py +++ b/examples/asynchronous_telebot/send_file_example.py @@ -4,7 +4,7 @@ from telebot.async_telebot import AsyncTeleBot -bot = AsyncTeleBot('1297441208:AAH-Z-YbiK_pQ1jTuHXYa-hA_PLZQVQ6qsw') +bot = AsyncTeleBot('TOKEN') @bot.message_handler(commands=['photo']) From 60294d0c4142273455cdb15c51bc4607a7f71634 Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 4 Dec 2021 21:22:44 +0500 Subject: [PATCH 4/7] Update README.md --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/README.md b/README.md index 492a1bf..ebd37a7 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ * [Proxy](#proxy) * [Testing](#testing) * [API conformance](#api-conformance) + * [Asynchronous TeleBot](#asynctelebot) * [F.A.Q.](#faq) * [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) @@ -712,6 +713,52 @@ Result will be: * ✔ [Bot API 2.0](https://core.telegram.org/bots/api-changelog#april-9-2016) +## AsyncTeleBot +### Asynchronous version of telebot +We have a fully asynchronous version of TeleBot. +This class is not controlled by threads. Asyncio tasks are created to execute all the stuff. + +### EchoBot +Echo Bot example on AsyncTeleBot: + +```python +# This is a simple echo bot using the decorator mechanism. +# It echoes any incoming text messages. + +from telebot.async_telebot import AsyncTeleBot +bot = AsyncTeleBot('TOKEN') + + + +# Handle '/start' and '/help' +@bot.message_handler(commands=['help', 'start']) +async def send_welcome(message): + await bot.reply_to(message, """\ +Hi there, I am EchoBot. +I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\ +""") + + +# Handle all other messages with content_type 'text' (content_types defaults to ['text']) +@bot.message_handler(func=lambda message: True) +async def echo_message(message): + await bot.reply_to(message, message.text) + + +bot.polling() +``` +As you can see here, keywords are await and async. + +### Why should I use async? +Asynchronous tasks depend on processor performance. Many asynchronous tasks can run parallelly, while thread tasks will block each other. + +### Differences in AsyncTeleBot +AsyncTeleBot has different middlewares. See example on [middlewares](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot) + +### Examples +See more examples in our [examples](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot) folder + + ## F.A.Q. ### How can I distinguish a User and a GroupChat in message.chat? From bbe4a96984dc173a74dec0c8484576e27c937c11 Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 4 Dec 2021 21:23:23 +0500 Subject: [PATCH 5/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebd37a7..995abb6 100644 --- a/README.md +++ b/README.md @@ -753,7 +753,7 @@ As you can see here, keywords are await and async. Asynchronous tasks depend on processor performance. Many asynchronous tasks can run parallelly, while thread tasks will block each other. ### Differences in AsyncTeleBot -AsyncTeleBot has different middlewares. See example on [middlewares](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot) +AsyncTeleBot has different middlewares. See example on [middlewares](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot/middleware) ### Examples See more examples in our [examples](https://github.com/coder2020official/pyTelegramBotAPI/tree/master/examples/asynchronous_telebot) folder From 482589af4935d8425f32379106ec38ddae9123db Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 4 Dec 2021 21:25:14 +0500 Subject: [PATCH 6/7] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 995abb6..7e1d499 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ #

pyTelegramBotAPI

A simple, but extensible Python implementation for the Telegram Bot API. +

Supports both sync and async ways.. ##

Supported Bot API version: 5.4! From f4b9480588ddc44bcc4e862423eb1fe993f9fc69 Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 4 Dec 2021 21:25:47 +0500 Subject: [PATCH 7/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e1d499..d1b13d0 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ #

pyTelegramBotAPI

A simple, but extensible Python implementation for the Telegram Bot API. -

Supports both sync and async ways.. +

Supports both sync and async ways. ##

Supported Bot API version: 5.4!