mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Compare commits
21 Commits
1f918dece5
...
fbf34f5953
Author | SHA1 | Date | |
---|---|---|---|
|
fbf34f5953 | ||
|
4347dd3dd9 | ||
|
d830ae0b15 | ||
|
4f198bc6f5 | ||
|
66615a41c4 | ||
|
a5ee5f816c | ||
|
fb52137bff | ||
|
7ee07f4dc7 | ||
|
f224069a34 | ||
|
6cca77f755 | ||
|
084289baa4 | ||
|
e2dbb88459 | ||
|
a2822c74ed | ||
|
4cd30c75ac | ||
|
f4b9480588 | ||
|
482589af49 | ||
|
bbe4a96984 | ||
|
60294d0c41 | ||
|
3035763277 | ||
|
51eabde320 | ||
|
a5305f551c |
84
README.md
84
README.md
@ -6,9 +6,10 @@
|
||||
|
||||
# <p align="center">pyTelegramBotAPI
|
||||
|
||||
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.
|
||||
<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">Supported 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#november-5-2021">5.4</a>!
|
||||
|
||||
## Contents
|
||||
|
||||
@ -43,7 +44,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)
|
||||
@ -52,6 +53,7 @@
|
||||
* [Proxy](#proxy)
|
||||
* [Testing](#testing)
|
||||
* [API conformance](#api-conformance)
|
||||
* [AsyncTeleBot](#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)
|
||||
@ -182,8 +184,8 @@ TeleBot supports the following filters:
|
||||
|content_types|list of strings (default `['text']`)|`True` if message.content_type is in the list of strings.|
|
||||
|regexp|a regular expression as a string|`True` if `re.search(regexp_arg)` returns `True` and `message.content_type == 'text'` (See [Python Regular Expressions](https://docs.python.org/2/library/re.html))|
|
||||
|commands|list of strings|`True` if `message.content_type == 'text'` and `message.text` starts with a command that is in the list of strings.|
|
||||
|chat_types|list of chat types|`True` if `message.chat.type` in your filter
|
||||
|func|a function (lambda or function reference)|`True` if the lambda or function reference returns `True`
|
||||
|chat_types|list of chat types|`True` if `message.chat.type` in your filter|
|
||||
|func|a function (lambda or function reference)|`True` if the lambda or function reference returns `True`|
|
||||
|
||||
Here are some examples of using the filters and message handlers:
|
||||
|
||||
@ -374,8 +376,8 @@ bot.add_custom_filter(IsAdmin())
|
||||
# Now, you can use it in handler.
|
||||
@bot.message_handler(is_admin=True)
|
||||
def admin_of_group(message):
|
||||
bot.send_message(message.chat.id, 'You are admin of this group'!)
|
||||
|
||||
bot.send_message(message.chat.id, 'You are admin of this group!')
|
||||
|
||||
```
|
||||
|
||||
|
||||
@ -555,26 +557,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.
|
||||
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:
|
||||
@ -712,6 +714,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/middleware)
|
||||
|
||||
### 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?
|
||||
@ -721,7 +769,7 @@ Telegram Bot API support new type Chat for message.chat.
|
||||
-
|
||||
```python
|
||||
if message.chat.type == "private":
|
||||
# private chat message
|
||||
# private chat message
|
||||
|
||||
if message.chat.type == "group":
|
||||
# group chat message
|
||||
|
87
examples/asynchronous_telebot/CallbackData_example.py
Normal file
87
examples/asynchronous_telebot/CallbackData_example.py
Normal file
@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
This Example will show you how to use CallbackData
|
||||
"""
|
||||
|
||||
from telebot.callback_data import CallbackData, CallbackDataFilter
|
||||
from telebot import types
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
from telebot.asyncio_filters import AdvancedCustomFilter
|
||||
|
||||
API_TOKEN = 'TOKEN'
|
||||
PRODUCTS = [
|
||||
{'id': '0', 'name': 'xiaomi mi 10', 'price': 400},
|
||||
{'id': '1', 'name': 'samsung s20', 'price': 800},
|
||||
{'id': '2', 'name': 'iphone 13', 'price': 1300}
|
||||
]
|
||||
|
||||
bot = AsyncTeleBot(API_TOKEN)
|
||||
products_factory = CallbackData('product_id', prefix='products')
|
||||
|
||||
|
||||
def products_keyboard():
|
||||
return types.InlineKeyboardMarkup(
|
||||
keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=product['name'],
|
||||
callback_data=products_factory.new(product_id=product["id"])
|
||||
)
|
||||
]
|
||||
for product in PRODUCTS
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def back_keyboard():
|
||||
return types.InlineKeyboardMarkup(
|
||||
keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='⬅',
|
||||
callback_data='back'
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class ProductsCallbackFilter(AdvancedCustomFilter):
|
||||
key = 'config'
|
||||
|
||||
async def check(self, call: types.CallbackQuery, config: CallbackDataFilter):
|
||||
return config.check(query=call)
|
||||
|
||||
|
||||
@bot.message_handler(commands=['products'])
|
||||
async def products_command_handler(message: types.Message):
|
||||
await bot.send_message(message.chat.id, 'Products:', reply_markup=products_keyboard())
|
||||
|
||||
|
||||
# Only product with field - product_id = 2
|
||||
@bot.callback_query_handler(func=None, config=products_factory.filter(product_id='2'))
|
||||
async def product_one_callback(call: types.CallbackQuery):
|
||||
await bot.answer_callback_query(callback_query_id=call.id, text='Not available :(', show_alert=True)
|
||||
|
||||
|
||||
# Any other products
|
||||
@bot.callback_query_handler(func=None, config=products_factory.filter())
|
||||
async def products_callback(call: types.CallbackQuery):
|
||||
callback_data: dict = products_factory.parse(callback_data=call.data)
|
||||
product_id = int(callback_data['product_id'])
|
||||
product = PRODUCTS[product_id]
|
||||
|
||||
text = f"Product name: {product['name']}\n" \
|
||||
f"Product price: {product['price']}"
|
||||
await bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
|
||||
text=text, reply_markup=back_keyboard())
|
||||
|
||||
|
||||
@bot.callback_query_handler(func=lambda c: c.data == 'back')
|
||||
async def back_callback(call: types.CallbackQuery):
|
||||
await bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
|
||||
text='Products:', reply_markup=products_keyboard())
|
||||
|
||||
|
||||
bot.add_custom_filter(ProductsCallbackFilter())
|
||||
bot.polling()
|
20
examples/asynchronous_telebot/download_file_example.py
Normal file
20
examples/asynchronous_telebot/download_file_example.py
Normal file
@ -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, '<i>Downloading your photo...</i>', 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='<i>Done!</i>', parse_mode='HTML')
|
||||
|
||||
|
||||
bot.polling(skip_pending=True)
|
27
examples/asynchronous_telebot/exception_handler.py
Normal file
27
examples/asynchronous_telebot/exception_handler.py
Normal file
@ -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)
|
@ -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()
|
48
examples/asynchronous_telebot/middleware/i18n.py
Normal file
48
examples/asynchronous_telebot/middleware/i18n.py
Normal file
@ -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()
|
27
examples/asynchronous_telebot/send_file_example.py
Normal file
27
examples/asynchronous_telebot/send_file_example.py
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
import telebot
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
|
||||
|
||||
|
||||
bot = AsyncTeleBot('TOKEN')
|
||||
|
||||
|
||||
@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)
|
14
examples/asynchronous_telebot/update_listener.py
Normal file
14
examples/asynchronous_telebot/update_listener.py
Normal file
@ -0,0 +1,14 @@
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
|
||||
# Update listeners are functions that are called when any update is received.
|
||||
|
||||
bot = AsyncTeleBot(token='TOKEN')
|
||||
|
||||
async def update_listener(messages):
|
||||
for message in messages:
|
||||
if message.text == '/start':
|
||||
await bot.send_message(message.chat.id, 'Hello!')
|
||||
|
||||
bot.set_update_listener(update_listener)
|
||||
|
||||
bot.polling()
|
@ -97,16 +97,15 @@ class AsyncTeleBot:
|
||||
|
||||
|
||||
def __init__(self, token: str, parse_mode: Optional[str]=None, offset=None,
|
||||
exception_handler=None,suppress_middleware_excepions=False) -> None: # TODO: ADD TYPEHINTS
|
||||
exception_handler=None) -> None: # TODO: ADD TYPEHINTS
|
||||
self.token = token
|
||||
|
||||
self.offset = offset
|
||||
self.token = token
|
||||
self.parse_mode = parse_mode
|
||||
self.update_listener = []
|
||||
self.suppress_middleware_excepions = suppress_middleware_excepions
|
||||
|
||||
self.exc_info = None
|
||||
|
||||
|
||||
self.exception_handler = exception_handler
|
||||
|
||||
@ -234,13 +233,23 @@ class AsyncTeleBot:
|
||||
try:
|
||||
|
||||
updates = await self.get_updates(offset=self.offset, allowed_updates=allowed_updates, timeout=timeout, request_timeout=request_timeout)
|
||||
if updates:
|
||||
self.offset = updates[-1].update_id + 1
|
||||
self._loop_create_task(self.process_new_updates(updates)) # Seperate task for processing updates
|
||||
if interval: await asyncio.sleep(interval)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
except asyncio.CancelledError:
|
||||
return
|
||||
|
||||
except asyncio_helper.ApiTelegramException as e:
|
||||
logger.error(str(e))
|
||||
|
||||
continue
|
||||
if non_stop:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error('Cause exception while getting updates.')
|
||||
if non_stop:
|
||||
@ -249,10 +258,6 @@ class AsyncTeleBot:
|
||||
continue
|
||||
else:
|
||||
raise e
|
||||
if updates:
|
||||
self.offset = updates[-1].update_id + 1
|
||||
self._loop_create_task(self.process_new_updates(updates)) # Seperate task for processing updates
|
||||
if interval: await asyncio.sleep(interval)
|
||||
|
||||
finally:
|
||||
self._polling = False
|
||||
@ -297,7 +302,12 @@ class AsyncTeleBot:
|
||||
break
|
||||
except Exception as e:
|
||||
handler_error = e
|
||||
logger.info(str(e))
|
||||
|
||||
if not middleware:
|
||||
if self.exception_handler:
|
||||
return self.exception_handler.handle(e)
|
||||
logging.error(str(e))
|
||||
return
|
||||
|
||||
if middleware:
|
||||
await middleware.post_process(message, data, handler_error)
|
||||
@ -448,7 +458,7 @@ class AsyncTeleBot:
|
||||
if len(self.update_listener) == 0:
|
||||
return
|
||||
for listener in self.update_listener:
|
||||
self._loop_create_task(listener, new_messages)
|
||||
self._loop_create_task(listener(new_messages))
|
||||
|
||||
async def _test_message_handler(self, message_handler, message):
|
||||
"""
|
||||
@ -466,6 +476,9 @@ class AsyncTeleBot:
|
||||
|
||||
return True
|
||||
|
||||
def set_update_listener(self, func):
|
||||
self.update_listener.append(func)
|
||||
|
||||
def add_custom_filter(self, custom_filter):
|
||||
"""
|
||||
Create custom filter.
|
||||
|
@ -8,7 +8,7 @@ try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import os
|
||||
API_URL = 'https://api.telegram.org/bot{0}/{1}'
|
||||
|
||||
from datetime import datetime
|
||||
@ -42,14 +42,55 @@ 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)
|
||||
async with await session_manager._get_new_session() as session:
|
||||
async with session.get(API_URL.format(token, url), params=params, data=files, timeout=request_timeout) as response:
|
||||
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']
|
||||
|
||||
|
||||
def guess_filename(obj):
|
||||
"""
|
||||
Get file name from object
|
||||
|
||||
:param obj:
|
||||
:return:
|
||||
"""
|
||||
name = getattr(obj, 'name', None)
|
||||
if name and isinstance(name, str) and name[0] != '<' and name[-1] != '>':
|
||||
return os.path.basename(name)
|
||||
|
||||
|
||||
def compose_data(params=None, files=None):
|
||||
"""
|
||||
Prepare request data
|
||||
|
||||
:param params:
|
||||
:param files:
|
||||
:return:
|
||||
"""
|
||||
data = aiohttp.formdata.FormData(quote_fields=False)
|
||||
|
||||
if params:
|
||||
for key, value in params.items():
|
||||
data.add_field(key, str(value))
|
||||
|
||||
if files:
|
||||
for key, f in files.items():
|
||||
if isinstance(f, tuple):
|
||||
if len(f) == 2:
|
||||
filename, fileobj = f
|
||||
else:
|
||||
raise ValueError('Tuple must have exactly 2 elements: filename, fileobj')
|
||||
else:
|
||||
filename, fileobj = guess_filename(f) or key, f
|
||||
|
||||
data.add_field(key, fileobj, filename=filename)
|
||||
|
||||
return data
|
||||
|
||||
async def _convert_markup(markup):
|
||||
if isinstance(markup, types.JsonSerializable):
|
||||
return markup.to_json()
|
||||
@ -731,7 +772,7 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform
|
||||
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):
|
||||
method_url = get_method_by_type(data_type)
|
||||
method_url = await get_method_by_type(data_type)
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not util.is_string(data):
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Versions should comply with PEP440.
|
||||
# This line is parsed in setup.py:
|
||||
__version__ = '4.2.0'
|
||||
__version__ = '4.2.1'
|
||||
|
Loading…
Reference in New Issue
Block a user