mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Merge branch 'master' into conflicts
This commit is contained in:
commit
d3080b6d4e
@ -885,5 +885,6 @@ Here are some examples of template:
|
||||
* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang is a multi-functional robot, such as OSU game information query, IP test, animation screenshot search and other functions.
|
||||
* [Feedback-bot](https://github.com/coder2020official/feedbackbot) A feedback bot for user-admin communication. Made on AsyncTeleBot, using [template](https://github.com/coder2020official/asynctelebot_template).
|
||||
* [TeleServ](https://github.com/ablakely/TeleServ) by [ablakely](https://github.com/ablakely) This is a Telegram to IRC bridge which links as an IRC server and makes Telegram users appear as native IRC users.
|
||||
* [Simple Store Bot](https://github.com/AntonGlyzin/myshopbot) by [Anton Glyzin](https://github.com/AntonGlyzin) This is a simple telegram-store with an admin panel. Designed according to a template.
|
||||
|
||||
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**
|
||||
|
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Asynchronous Telegram Echo Bot example.
|
||||
|
||||
This is a simple bot that echoes each message that is received onto the chat.
|
||||
It uses the Starlette ASGI framework to receive updates via webhook requests.
|
||||
"""
|
||||
|
||||
import uvicorn
|
||||
from starlette.applications import Starlette
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import PlainTextResponse, Response
|
||||
from starlette.routing import Route
|
||||
from telebot.async_telebot import AsyncTeleBot
|
||||
from telebot.types import Message, Update
|
||||
|
||||
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"
|
||||
WEBHOOK_SSL_CERT = "./webhook_cert.pem" # Path to the ssl certificate
|
||||
WEBHOOK_SSL_PRIV = "./webhook_pkey.pem" # Path to the ssl private key
|
||||
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}/telegram"
|
||||
WEBHOOK_SECRET_TOKEN = "SECRET_TOKEN"
|
||||
|
||||
logger = telebot.logger
|
||||
telebot.logger.setLevel(logging.INFO)
|
||||
|
||||
bot = AsyncTeleBot(token=API_TOKEN)
|
||||
|
||||
# BOT HANDLERS
|
||||
@bot.message_handler(commands=["help", "start"])
|
||||
async def send_welcome(message: Message):
|
||||
"""
|
||||
Handle '/start' and '/help'
|
||||
"""
|
||||
await bot.reply_to(
|
||||
message,
|
||||
("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you."),
|
||||
)
|
||||
|
||||
|
||||
@bot.message_handler(func=lambda _: True, content_types=["text"])
|
||||
async def echo_message(message: Message):
|
||||
"""
|
||||
Handle all other messages
|
||||
"""
|
||||
await bot.reply_to(message, message.text)
|
||||
|
||||
|
||||
# WEBSERVER HANDLERS
|
||||
async def telegram(request: Request) -> Response:
|
||||
"""Handle incoming Telegram updates."""
|
||||
token_header_name = "X-Telegram-Bot-Api-Secret-Token"
|
||||
if request.headers.get(token_header_name) != WEBHOOK_SECRET_TOKEN:
|
||||
return PlainTextResponse("Forbidden", status_code=403)
|
||||
await bot.process_new_updates([Update.de_json(await request.json())])
|
||||
return Response()
|
||||
|
||||
|
||||
async def startup() -> None:
|
||||
"""Register webhook for telegram updates."""
|
||||
webhook_info = await bot.get_webhook_info(30)
|
||||
if WEBHOOK_URL != webhook_info.url:
|
||||
logger.debug(
|
||||
f"updating webhook url, old: {webhook_info.url}, new: {WEBHOOK_URL}"
|
||||
)
|
||||
if not await bot.set_webhook(
|
||||
url=WEBHOOK_URL, secret_token=WEBHOOK_SECRET_TOKEN
|
||||
):
|
||||
raise RuntimeError("unable to set webhook")
|
||||
|
||||
|
||||
app = Starlette(
|
||||
routes=[
|
||||
Route("/telegram", telegram, methods=["POST"]),
|
||||
],
|
||||
on_startup=[startup],
|
||||
)
|
||||
|
||||
|
||||
uvicorn.run(
|
||||
app,
|
||||
host=WEBHOOK_HOST,
|
||||
port=WEBHOOK_LISTEN,
|
||||
ssl_certfile=WEBHOOK_SSL_CERT,
|
||||
ssl_keyfile=WEBHOOK_SSL_PRIV,
|
||||
)
|
@ -131,6 +131,19 @@ class TeleBot:
|
||||
|
||||
:param use_class_middlewares: Use class middlewares, defaults to False
|
||||
:type use_class_middlewares: :obj:`bool`, optional
|
||||
|
||||
:param disable_web_page_preview: Default value for disable_web_page_preview, defaults to None
|
||||
:type disable_web_page_preview: :obj:`bool`, optional
|
||||
|
||||
:param disable_notification: Default value for disable_notification, defaults to None
|
||||
:type disable_notification: :obj:`bool`, optional
|
||||
|
||||
:param protect_content: Default value for protect_content, defaults to None
|
||||
:type protect_content: :obj:`bool`, optional
|
||||
|
||||
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
|
||||
:type allow_sending_without_reply: :obj:`bool`, optional
|
||||
|
||||
|
||||
:param colorful_logs: Outputs colorful logs
|
||||
:type colorful_logs: :obj:`bool`, optional
|
||||
@ -142,15 +155,28 @@ class TeleBot:
|
||||
next_step_backend: Optional[HandlerBackend]=None, reply_backend: Optional[HandlerBackend]=None,
|
||||
exception_handler: Optional[ExceptionHandler]=None, last_update_id: Optional[int]=0,
|
||||
suppress_middleware_excepions: Optional[bool]=False, state_storage: Optional[StateStorageBase]=StateMemoryStorage(),
|
||||
use_class_middlewares: Optional[bool]=False,
|
||||
use_class_middlewares: Optional[bool]=False,
|
||||
disable_web_page_preview: Optional[bool]=None,
|
||||
disable_notification: Optional[bool]=None,
|
||||
protect_content: Optional[bool]=None,
|
||||
allow_sending_without_reply: Optional[bool]=None,
|
||||
colorful_logs: Optional[bool]=False
|
||||
):
|
||||
self.token = token
|
||||
self.parse_mode = parse_mode
|
||||
self.update_listener = []
|
||||
self.skip_pending = skip_pending
|
||||
self.suppress_middleware_excepions = suppress_middleware_excepions
|
||||
|
||||
# update-related
|
||||
self.token = token
|
||||
self.skip_pending = skip_pending # backward compatibility
|
||||
self.last_update_id = last_update_id
|
||||
|
||||
# propertys
|
||||
self.suppress_middleware_excepions = suppress_middleware_excepions
|
||||
self.parse_mode = parse_mode
|
||||
self.disable_web_page_preview = disable_web_page_preview
|
||||
self.disable_notification = disable_notification
|
||||
self.protect_content = protect_content
|
||||
self.allow_sending_without_reply = allow_sending_without_reply
|
||||
|
||||
# logs-related
|
||||
if colorful_logs:
|
||||
try:
|
||||
import coloredlogs
|
||||
@ -159,12 +185,13 @@ class TeleBot:
|
||||
raise ImportError(
|
||||
'Install colorredlogs module to use colorful_logs option.'
|
||||
)
|
||||
|
||||
|
||||
# threading-related
|
||||
self.__stop_polling = threading.Event()
|
||||
self.last_update_id = last_update_id
|
||||
self.exc_info = None
|
||||
|
||||
# states & register_next_step_handler
|
||||
self.current_states = state_storage
|
||||
self.next_step_backend = next_step_backend
|
||||
if not self.next_step_backend:
|
||||
self.next_step_backend = MemoryHandlerBackend()
|
||||
@ -173,8 +200,9 @@ class TeleBot:
|
||||
if not self.reply_backend:
|
||||
self.reply_backend = MemoryHandlerBackend()
|
||||
|
||||
# handlers
|
||||
self.exception_handler = exception_handler
|
||||
|
||||
self.update_listener = []
|
||||
self.message_handlers = []
|
||||
self.edited_message_handlers = []
|
||||
self.channel_post_handlers = []
|
||||
@ -192,8 +220,7 @@ class TeleBot:
|
||||
self.custom_filters = {}
|
||||
self.state_handlers = []
|
||||
|
||||
self.current_states = state_storage
|
||||
|
||||
# middlewares
|
||||
self.use_class_middlewares = use_class_middlewares
|
||||
if apihelper.ENABLE_MIDDLEWARE and not use_class_middlewares:
|
||||
self.typed_middleware_handlers = {
|
||||
@ -219,6 +246,8 @@ class TeleBot:
|
||||
'You are using class based middlewares while having ENABLE_MIDDLEWARE set to True. This is not recommended.'
|
||||
)
|
||||
self.middlewares = [] if use_class_middlewares else None
|
||||
|
||||
# threads
|
||||
self.threaded = threaded
|
||||
if self.threaded:
|
||||
self.worker_pool = util.ThreadPool(self, num_threads=num_threads)
|
||||
@ -483,6 +512,7 @@ class TeleBot:
|
||||
webhook_url = "{}://{}:{}/{}".format(protocol, listen, port, url_path)
|
||||
|
||||
if certificate and certificate_key:
|
||||
# noinspection PyTypeChecker
|
||||
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
ssl_ctx.load_cert_chain(certificate, certificate_key)
|
||||
|
||||
@ -1126,11 +1156,6 @@ class TeleBot:
|
||||
|
||||
|
||||
def _exec_task(self, task, *args, **kwargs):
|
||||
if kwargs:
|
||||
if kwargs.pop('task_type', "") == 'handler':
|
||||
if kwargs.pop('pass_bot', False):
|
||||
kwargs['bot'] = self
|
||||
|
||||
if self.threaded:
|
||||
self.worker_pool.put(task, *args, **kwargs)
|
||||
else:
|
||||
@ -1483,6 +1508,10 @@ class TeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_message(
|
||||
@ -1521,6 +1550,9 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content))
|
||||
|
||||
@ -1583,6 +1615,11 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
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,
|
||||
@ -1660,6 +1697,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_dice(
|
||||
self.token, chat_id, emoji, disable_notification, reply_to_message_id,
|
||||
@ -1723,6 +1764,9 @@ class TeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_photo(
|
||||
@ -1808,6 +1852,9 @@ class TeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_audio(
|
||||
@ -1876,6 +1923,9 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_voice(
|
||||
@ -1956,6 +2006,10 @@ class TeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if data and not(document):
|
||||
# function typo miss compatibility
|
||||
document = data
|
||||
@ -2020,9 +2074,14 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if data and not(sticker):
|
||||
# function typo miss compatibility
|
||||
sticker = data
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_data(
|
||||
self.token, chat_id, sticker, 'sticker',
|
||||
@ -2110,6 +2169,10 @@ class TeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if data and not(video):
|
||||
# function typo miss compatibility
|
||||
video = data
|
||||
@ -2196,6 +2259,9 @@ class TeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_animation(
|
||||
@ -2263,6 +2329,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_video_note(
|
||||
self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
|
||||
@ -2309,6 +2379,10 @@ class TeleBot:
|
||||
:return: On success, an array of Messages that were sent is returned.
|
||||
:rtype: List[types.Message]
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
result = apihelper.send_media_group(
|
||||
self.token, chat_id, media, disable_notification, reply_to_message_id, timeout,
|
||||
allow_sending_without_reply, protect_content)
|
||||
@ -2377,6 +2451,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_location(
|
||||
self.token, chat_id, latitude, longitude, live_period,
|
||||
@ -2548,6 +2626,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_venue(
|
||||
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
|
||||
@ -2610,6 +2692,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
apihelper.send_contact(
|
||||
self.token, chat_id, phone_number, first_name, last_name, vcard,
|
||||
@ -3361,6 +3447,8 @@ class TeleBot:
|
||||
:return: True on success.
|
||||
:rtype: :obj:`bool`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
|
||||
return apihelper.pin_chat_message(self.token, chat_id, message_id, disable_notification)
|
||||
|
||||
def unpin_chat_message(self, chat_id: Union[int, str], message_id: Optional[int]=None) -> bool:
|
||||
@ -3442,6 +3530,7 @@ class TeleBot:
|
||||
:rtype: :obj:`types.Message` or :obj:`bool`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
|
||||
|
||||
result = apihelper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
|
||||
entities, disable_web_page_preview, reply_markup)
|
||||
@ -3554,6 +3643,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
result = apihelper.send_game(
|
||||
self.token, chat_id, game_short_name, disable_notification,
|
||||
reply_to_message_id, reply_markup, timeout,
|
||||
@ -3756,6 +3849,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
result = apihelper.send_invoice(
|
||||
self.token, chat_id, title, description, invoice_payload, provider_token,
|
||||
currency, prices, start_parameter, photo_url, photo_size, photo_width,
|
||||
@ -3957,6 +4054,10 @@ class TeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if isinstance(question, types.Poll):
|
||||
raise RuntimeError("The send_poll signature was changed, please see send_poll function details.")
|
||||
|
||||
@ -4829,8 +4930,14 @@ class TeleBot:
|
||||
if not isinstance(regexp, str):
|
||||
logger.error(f"{method_name}: Regexp filter should be string. Not able to use the supplied type.")
|
||||
|
||||
def message_handler(self, commands: Optional[List[str]]=None, regexp: Optional[str]=None, func: Optional[Callable]=None,
|
||||
content_types: Optional[List[str]]=None, chat_types: Optional[List[str]]=None, **kwargs):
|
||||
def message_handler(
|
||||
self,
|
||||
commands: Optional[List[str]]=None,
|
||||
regexp: Optional[str]=None,
|
||||
func: Optional[Callable]=None,
|
||||
content_types: Optional[List[str]]=None,
|
||||
chat_types: Optional[List[str]]=None,
|
||||
**kwargs):
|
||||
"""
|
||||
Handles New incoming message of any kind - text, photo, sticker, etc.
|
||||
As a parameter to the decorator function, it passes :class:`telebot.types.Message` object.
|
||||
@ -5914,7 +6021,7 @@ class TeleBot:
|
||||
return False
|
||||
|
||||
# middleware check-up method
|
||||
def _check_middleware(self, update_type):
|
||||
def _get_middlewares(self, update_type):
|
||||
"""
|
||||
Check middleware
|
||||
|
||||
@ -5928,100 +6035,115 @@ class TeleBot:
|
||||
|
||||
def _run_middlewares_and_handler(self, message, handlers, middlewares, update_type):
|
||||
"""
|
||||
This class is made to run handler and middleware in queue.
|
||||
This method is made to run handlers and middlewares in queue.
|
||||
|
||||
:param handler: handler that should be executed.
|
||||
:param middleware: middleware that should be executed.
|
||||
:param message: received message (update part) to process with handlers and/or middlewares
|
||||
:param handlers: all created handlers (not filtered)
|
||||
:param middlewares: middlewares that should be executed (already filtered)
|
||||
:param update_type: handler/update type (Update field name)
|
||||
:return:
|
||||
"""
|
||||
data = {}
|
||||
params =[]
|
||||
handler_error = None
|
||||
skip_handlers = False
|
||||
|
||||
if middlewares:
|
||||
for middleware in middlewares:
|
||||
if middleware.update_sensitive:
|
||||
if hasattr(middleware, f'pre_process_{update_type}'):
|
||||
result = getattr(middleware, f'pre_process_{update_type}')(message, data)
|
||||
else:
|
||||
logger.error('Middleware {} does not have pre_process_{} method. pre_process function execution was skipped.'.format(middleware.__class__.__name__, update_type))
|
||||
result = None
|
||||
else:
|
||||
result = middleware.pre_process(message, data)
|
||||
# We will break this loop if CancelUpdate is returned
|
||||
# Also, we will not run other middlewares
|
||||
if isinstance(result, CancelUpdate):
|
||||
return
|
||||
elif isinstance(result, SkipHandler):
|
||||
skip_handlers = True
|
||||
|
||||
if handlers and not(skip_handlers):
|
||||
try:
|
||||
if not self.use_class_middlewares:
|
||||
if handlers:
|
||||
for handler in handlers:
|
||||
process_handler = self._test_message_handler(handler, message)
|
||||
if not process_handler: continue
|
||||
for i in inspect.signature(handler['function']).parameters:
|
||||
params.append(i)
|
||||
if len(params) == 1:
|
||||
handler['function'](message)
|
||||
elif "data" in params:
|
||||
if len(params) == 2:
|
||||
handler['function'](message, data)
|
||||
elif len(params) == 3:
|
||||
handler['function'](message, data=data, bot=self)
|
||||
if self._test_message_handler(handler, message):
|
||||
if handler.get('pass_bot', False):
|
||||
handler['function'](message, bot = self)
|
||||
else:
|
||||
logger.error("It is not allowed to pass data and values inside data to the handler. Check your handler: {}".format(handler['function']))
|
||||
return
|
||||
else:
|
||||
data_copy = data.copy()
|
||||
for key in list(data_copy):
|
||||
# remove data from data_copy if handler does not accept it
|
||||
if key not in params:
|
||||
del data_copy[key]
|
||||
if handler.get('pass_bot'):
|
||||
data_copy["bot"] = self
|
||||
if len(data_copy) > len(params) - 1: # remove the message parameter
|
||||
logger.error("You are passing more parameters than the handler needs. Check your handler: {}".format(handler['function']))
|
||||
return
|
||||
handler["function"](message, **data_copy)
|
||||
break
|
||||
except Exception as e:
|
||||
handler_error = e
|
||||
if self.exception_handler:
|
||||
self.exception_handler.handle(e)
|
||||
else:
|
||||
logging.error(str(e))
|
||||
logger.debug("Exception traceback:\n%s", traceback.format_exc())
|
||||
handler['function'](message)
|
||||
break
|
||||
else:
|
||||
data = {}
|
||||
params =[]
|
||||
handler_error = None
|
||||
skip_handlers = False
|
||||
|
||||
if middlewares:
|
||||
for middleware in middlewares:
|
||||
if middleware.update_sensitive:
|
||||
if hasattr(middleware, f'post_process_{update_type}'):
|
||||
getattr(middleware, f'post_process_{update_type}')(message, data, handler_error)
|
||||
if middlewares:
|
||||
for middleware in middlewares:
|
||||
if middleware.update_sensitive:
|
||||
if hasattr(middleware, f'pre_process_{update_type}'):
|
||||
result = getattr(middleware, f'pre_process_{update_type}')(message, data)
|
||||
else:
|
||||
logger.error('Middleware {} does not have pre_process_{} method. pre_process function execution was skipped.'.format(middleware.__class__.__name__, update_type))
|
||||
result = None
|
||||
else:
|
||||
logger.error("Middleware: {} does not have post_process_{} method. Post process function was not executed.".format(middleware.__class__.__name__, update_type))
|
||||
else:
|
||||
middleware.post_process(message, data, handler_error)
|
||||
result = middleware.pre_process(message, data)
|
||||
# We will break this loop if CancelUpdate is returned
|
||||
# Also, we will not run other middlewares
|
||||
if isinstance(result, CancelUpdate):
|
||||
return
|
||||
elif isinstance(result, SkipHandler):
|
||||
skip_handlers = True
|
||||
|
||||
if handlers and not(skip_handlers):
|
||||
try:
|
||||
for handler in handlers:
|
||||
process_handler = self._test_message_handler(handler, message)
|
||||
if not process_handler: continue
|
||||
for i in inspect.signature(handler['function']).parameters:
|
||||
params.append(i)
|
||||
if len(params) == 1:
|
||||
handler['function'](message)
|
||||
elif "data" in params:
|
||||
if len(params) == 2:
|
||||
handler['function'](message, data)
|
||||
elif len(params) == 3:
|
||||
handler['function'](message, data=data, bot=self)
|
||||
else:
|
||||
logger.error("It is not allowed to pass data and values inside data to the handler. Check your handler: {}".format(handler['function']))
|
||||
return
|
||||
else:
|
||||
data_copy = data.copy()
|
||||
for key in list(data_copy):
|
||||
# remove data from data_copy if handler does not accept it
|
||||
if key not in params:
|
||||
del data_copy[key]
|
||||
if handler.get('pass_bot'):
|
||||
data_copy["bot"] = self
|
||||
if len(data_copy) > len(params) - 1: # remove the message parameter
|
||||
logger.error("You are passing more parameters than the handler needs. Check your handler: {}".format(handler['function']))
|
||||
return
|
||||
handler["function"](message, **data_copy)
|
||||
break
|
||||
except Exception as e:
|
||||
handler_error = e
|
||||
if self.exception_handler:
|
||||
self.exception_handler.handle(e)
|
||||
else:
|
||||
logger.error(str(e))
|
||||
logger.debug("Exception traceback:\n%s", traceback.format_exc())
|
||||
|
||||
if middlewares:
|
||||
for middleware in middlewares:
|
||||
if middleware.update_sensitive:
|
||||
if hasattr(middleware, f'post_process_{update_type}'):
|
||||
getattr(middleware, f'post_process_{update_type}')(message, data, handler_error)
|
||||
else:
|
||||
logger.error("Middleware: {} does not have post_process_{} method. Post process function was not executed.".format(middleware.__class__.__name__, update_type))
|
||||
else:
|
||||
middleware.post_process(message, data, handler_error)
|
||||
|
||||
def _notify_command_handlers(self, handlers, new_messages, update_type):
|
||||
"""
|
||||
Notifies command handlers.
|
||||
|
||||
:param handlers:
|
||||
:param new_messages:
|
||||
:param handlers: all created handlers
|
||||
:param new_messages: received messages to proceed
|
||||
:param update_type: handler/update type (Update fields)
|
||||
:return:
|
||||
"""
|
||||
if not(handlers) and not(self.use_class_middlewares):
|
||||
return
|
||||
|
||||
if self.use_class_middlewares:
|
||||
middlewares = self._get_middlewares(update_type)
|
||||
else:
|
||||
middlewares = None
|
||||
for message in new_messages:
|
||||
if not self.use_class_middlewares:
|
||||
for message_handler in handlers:
|
||||
if self._test_message_handler(message_handler, message):
|
||||
self._exec_task(message_handler['function'], message, pass_bot=message_handler['pass_bot'], task_type='handler')
|
||||
break
|
||||
else:
|
||||
middleware = self._check_middleware(update_type)
|
||||
self._exec_task(self._run_middlewares_and_handler, message, handlers=handlers, middlewares=middleware, update_type=update_type)
|
||||
return
|
||||
self._exec_task(
|
||||
self._run_middlewares_and_handler,
|
||||
message,
|
||||
handlers=handlers,
|
||||
middlewares=middlewares,
|
||||
update_type=update_type)
|
||||
|
@ -3,8 +3,6 @@ from datetime import datetime
|
||||
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from typing import Any, Awaitable, Callable, List, Optional, Union
|
||||
|
||||
@ -99,21 +97,37 @@ class AsyncTeleBot:
|
||||
:param state_storage: Storage for states, defaults to StateMemoryStorage()
|
||||
:type state_storage: :class:`telebot.asyncio_storage.StateMemoryStorage`, optional
|
||||
|
||||
:param disable_web_page_preview: Default value for disable_web_page_preview, defaults to None
|
||||
:type disable_web_page_preview: :obj:`bool`, optional
|
||||
|
||||
:param disable_notification: Default value for disable_notification, defaults to None
|
||||
:type disable_notification: :obj:`bool`, optional
|
||||
|
||||
:param protect_content: Default value for protect_content, defaults to None
|
||||
:type protect_content: :obj:`bool`, optional
|
||||
|
||||
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
|
||||
:type allow_sending_without_reply: :obj:`bool`, optional
|
||||
|
||||
:param colorful_logs: Outputs colorful logs
|
||||
:type colorful_logs: :obj:`bool`, optional
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[int]=None,
|
||||
exception_handler: Optional[ExceptionHandler]=None, state_storage: Optional[StateStorageBase]=StateMemoryStorage(),
|
||||
exception_handler: Optional[ExceptionHandler]=None,
|
||||
state_storage: Optional[StateStorageBase]=StateMemoryStorage(),
|
||||
disable_web_page_preview: Optional[bool]=None,
|
||||
disable_notification: Optional[bool]=None,
|
||||
protect_content: Optional[bool]=None,
|
||||
allow_sending_without_reply: Optional[bool]=None,
|
||||
colorful_logs: Optional[bool]=False) -> None:
|
||||
|
||||
# update-related
|
||||
self.token = token
|
||||
|
||||
self.offset = offset
|
||||
self.token = token
|
||||
self.parse_mode = parse_mode
|
||||
self.update_listener = []
|
||||
|
||||
# logs-related
|
||||
if colorful_logs:
|
||||
try:
|
||||
import coloredlogs
|
||||
@ -122,11 +136,20 @@ class AsyncTeleBot:
|
||||
raise ImportError(
|
||||
'Install colorredlogs module to use colorful_logs option.'
|
||||
)
|
||||
|
||||
# properties
|
||||
self.parse_mode = parse_mode
|
||||
self.disable_web_page_preview = disable_web_page_preview
|
||||
self.disable_notification = disable_notification
|
||||
self.protect_content = protect_content
|
||||
self.allow_sending_without_reply = allow_sending_without_reply
|
||||
|
||||
# states
|
||||
self.current_states = state_storage
|
||||
|
||||
|
||||
# handlers
|
||||
self.update_listener = []
|
||||
self.exception_handler = exception_handler
|
||||
|
||||
self.message_handlers = []
|
||||
self.edited_message_handlers = []
|
||||
self.channel_post_handlers = []
|
||||
@ -143,9 +166,6 @@ class AsyncTeleBot:
|
||||
self.chat_join_request_handlers = []
|
||||
self.custom_filters = {}
|
||||
self.state_handlers = []
|
||||
|
||||
self.current_states = state_storage
|
||||
|
||||
self.middlewares = []
|
||||
|
||||
self._user = None # set during polling
|
||||
@ -296,7 +316,7 @@ class AsyncTeleBot:
|
||||
logger.error("Infinity polling exception: %s", str(e))
|
||||
if logger_level and logger_level >= logging.DEBUG:
|
||||
logger.error("Exception traceback:\n%s", traceback.format_exc())
|
||||
time.sleep(3)
|
||||
await asyncio.sleep(3)
|
||||
continue
|
||||
if logger_level and logger_level >= logging.INFO:
|
||||
logger.error("Infinity polling: polling exited")
|
||||
@ -390,7 +410,8 @@ class AsyncTeleBot:
|
||||
await self.close_session()
|
||||
logger.warning('Polling is stopped.')
|
||||
|
||||
def _loop_create_task(self, coro):
|
||||
@staticmethod
|
||||
def _loop_create_task(coro):
|
||||
return asyncio.create_task(coro)
|
||||
|
||||
async def _process_updates(self, handlers, messages, update_type):
|
||||
@ -402,12 +423,22 @@ class AsyncTeleBot:
|
||||
:return:
|
||||
"""
|
||||
tasks = []
|
||||
middlewares = await self._get_middlewares(update_type)
|
||||
for message in messages:
|
||||
middleware = await self.process_middlewares(update_type)
|
||||
tasks.append(self._run_middlewares_and_handlers(handlers, message, middleware, update_type))
|
||||
tasks.append(self._run_middlewares_and_handlers(message, handlers, middlewares, update_type))
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
async def _run_middlewares_and_handlers(self, handlers, message, middlewares, update_type):
|
||||
async def _run_middlewares_and_handlers(self, message, handlers, middlewares, update_type):
|
||||
"""
|
||||
This method is made to run handlers and middlewares in queue.
|
||||
|
||||
:param message: received message (update part) to process with handlers and/or middlewares
|
||||
:param handlers: all created handlers (not filtered)
|
||||
:param middlewares: middlewares that should be executed (already filtered)
|
||||
:param update_type: handler/update type (Update field name)
|
||||
:return:
|
||||
"""
|
||||
|
||||
handler_error = None
|
||||
data = {}
|
||||
skip_handlers = False
|
||||
@ -477,7 +508,7 @@ class AsyncTeleBot:
|
||||
else:
|
||||
logger.error('Middleware {} does not have post_process_{} method. post_process function execution was skipped.'.format(middleware.__class__.__name__, update_type))
|
||||
else: await middleware.post_process(message, data, handler_error)
|
||||
# update handling
|
||||
|
||||
async def process_new_updates(self, updates: List[types.Update]):
|
||||
"""
|
||||
Process new updates.
|
||||
@ -666,7 +697,7 @@ class AsyncTeleBot:
|
||||
"""
|
||||
await self._process_updates(self.chat_join_request_handlers, chat_join_request, 'chat_join_request')
|
||||
|
||||
async def process_middlewares(self, update_type):
|
||||
async def _get_middlewares(self, update_type):
|
||||
"""
|
||||
:meta private:
|
||||
"""
|
||||
@ -2328,6 +2359,10 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_message(
|
||||
@ -2366,6 +2401,9 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content))
|
||||
|
||||
@ -2428,6 +2466,9 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_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,
|
||||
@ -2506,6 +2547,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_dice(
|
||||
self.token, chat_id, emoji, disable_notification, reply_to_message_id,
|
||||
@ -2568,6 +2613,9 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_photo(
|
||||
@ -2652,6 +2700,9 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_audio(
|
||||
@ -2719,6 +2770,9 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_voice(
|
||||
@ -2798,6 +2852,10 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if data and not(document):
|
||||
# function typo miss compatibility
|
||||
document = data
|
||||
@ -2858,6 +2916,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if data and not(sticker):
|
||||
# function typo miss compatibility
|
||||
logger.warning("send_sticker: data parameter is deprecated. Use sticker instead.")
|
||||
@ -2949,6 +3011,10 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
if data and not(video):
|
||||
# function typo miss compatibility
|
||||
logger.warning("send_sticker: data parameter is deprecated. Use video instead.")
|
||||
@ -3036,6 +3102,9 @@ class AsyncTeleBot:
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_animation(
|
||||
@ -3102,6 +3171,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_video_note(
|
||||
self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup,
|
||||
@ -3147,6 +3220,10 @@ class AsyncTeleBot:
|
||||
:return: On success, an array of Messages that were sent is returned.
|
||||
:rtype: List[types.Message]
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
result = await asyncio_helper.send_media_group(
|
||||
self.token, chat_id, media, disable_notification, reply_to_message_id, timeout,
|
||||
allow_sending_without_reply, protect_content)
|
||||
@ -3214,6 +3291,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_location(
|
||||
self.token, chat_id, latitude, longitude, live_period,
|
||||
@ -3384,6 +3465,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_venue(
|
||||
self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type,
|
||||
@ -3445,6 +3530,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :class:`telebot.types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_contact(
|
||||
self.token, chat_id, phone_number, first_name, last_name, vcard,
|
||||
@ -4205,6 +4294,8 @@ class AsyncTeleBot:
|
||||
:return: True on success.
|
||||
:rtype: :obj:`bool`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
|
||||
return await asyncio_helper.pin_chat_message(self.token, chat_id, message_id, disable_notification)
|
||||
|
||||
async def unpin_chat_message(self, chat_id: Union[int, str], message_id: Optional[int]=None) -> bool:
|
||||
@ -4286,6 +4377,7 @@ class AsyncTeleBot:
|
||||
:rtype: :obj:`types.Message` or :obj:`bool`
|
||||
"""
|
||||
parse_mode = self.parse_mode if (parse_mode is None) else parse_mode
|
||||
disable_web_page_preview = self.disable_web_page_preview if (disable_web_page_preview is None) else disable_web_page_preview
|
||||
|
||||
result = await asyncio_helper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode,
|
||||
entities, disable_web_page_preview, reply_markup)
|
||||
@ -4398,6 +4490,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
result = await asyncio_helper.send_game(
|
||||
self.token, chat_id, game_short_name, disable_notification,
|
||||
reply_to_message_id, reply_markup, timeout,
|
||||
@ -4599,6 +4695,10 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
|
||||
result = await asyncio_helper.send_invoice(
|
||||
self.token, chat_id, title, description, invoice_payload, provider_token,
|
||||
currency, prices, start_parameter, photo_url, photo_size, photo_width,
|
||||
@ -4800,12 +4900,14 @@ class AsyncTeleBot:
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
|
||||
protect_content = self.protect_content if (protect_content is None) else protect_content
|
||||
allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply
|
||||
explanation_parse_mode = self.parse_mode if (explanation_parse_mode is None) else explanation_parse_mode
|
||||
|
||||
if isinstance(question, types.Poll):
|
||||
raise RuntimeError("The send_poll signature was changed, please see send_poll function details.")
|
||||
|
||||
explanation_parse_mode = self.parse_mode if (explanation_parse_mode is None) else explanation_parse_mode
|
||||
|
||||
return types.Message.de_json(
|
||||
await asyncio_helper.send_poll(
|
||||
self.token, chat_id,
|
||||
|
@ -420,7 +420,7 @@ class StateFilter(AdvancedCustomFilter):
|
||||
text = text.name
|
||||
|
||||
if message.chat.type in ['group', 'supergroup']:
|
||||
group_state = await self.bot.current_states.get_state(user_id, chat_id)
|
||||
group_state = await self.bot.current_states.get_state(chat_id, user_id)
|
||||
if group_state == text:
|
||||
return True
|
||||
elif type(text) is list and group_state in text:
|
||||
@ -428,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
|
||||
|
||||
|
||||
else:
|
||||
user_state = await self.bot.current_states.get_state(user_id, chat_id)
|
||||
user_state = await self.bot.current_states.get_state(chat_id, user_id)
|
||||
if user_state == text:
|
||||
return True
|
||||
elif type(text) is list and user_state in text:
|
||||
|
@ -23,7 +23,7 @@ session = None
|
||||
|
||||
FILE_URL = None
|
||||
|
||||
REQUEST_TIMEOUT = None
|
||||
REQUEST_TIMEOUT = 300
|
||||
MAX_RETRIES = 3
|
||||
|
||||
REQUEST_LIMIT = 50
|
||||
@ -58,10 +58,29 @@ class SessionManager:
|
||||
|
||||
session_manager = SessionManager()
|
||||
|
||||
async def _process_request(token, url, method='get', params=None, files=None, request_timeout=None):
|
||||
async def _process_request(token, url, method='get', params=None, files=None, **kwargs):
|
||||
# Let's resolve all timeout parameters.
|
||||
# getUpdates parameter may contain 2 parameters: request_timeout & timeout.
|
||||
# other methods may contain timeout parameter that should be applied to
|
||||
# ClientTimeout only.
|
||||
# timeout should be added to params for getUpdates. All other timeout's should be used
|
||||
# for request timeout.
|
||||
# here we got request_timeout, so this is getUpdates method.
|
||||
if 'request_timeout' in kwargs:
|
||||
request_timeout = kwargs.pop('request_timeout')
|
||||
|
||||
else:
|
||||
# let's check for timeout in params
|
||||
request_timeout = params.pop('timeout', None)
|
||||
# we will apply default request_timeout if there is no timeout in params
|
||||
# otherwise, we will use timeout parameter applied for payload.
|
||||
|
||||
request_timeout = REQUEST_TIMEOUT if request_timeout is None else request_timeout
|
||||
|
||||
|
||||
# Preparing data by adding all parameters and files to FormData
|
||||
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
|
||||
@ -161,15 +180,13 @@ async def get_file_url(token, file_id):
|
||||
async def download_file(token, file_path):
|
||||
if FILE_URL is None:
|
||||
url = "https://api.telegram.org/file/bot{0}/{1}".format(token, file_path)
|
||||
else:
|
||||
# noinspection PyUnresolvedReferences
|
||||
url = FILE_URL.format(token, file_path)
|
||||
async with await session_manager.get_session() as session:
|
||||
async with session.get(url, proxy=proxy) as response:
|
||||
result = await response.read()
|
||||
if response.status != 200:
|
||||
raise ApiHTTPException('Download file', result)
|
||||
|
||||
else: url = FILE_URL.format(token, file_path)
|
||||
session = await session_manager.get_session()
|
||||
async with session.get(url, proxy=proxy) as response:
|
||||
if response.status != 200:
|
||||
raise ApiHTTPException('Download file', result)
|
||||
result = await response.read()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
@ -428,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
|
||||
text = text.name
|
||||
|
||||
if message.chat.type in ['group', 'supergroup']:
|
||||
group_state = self.bot.current_states.get_state(user_id, chat_id)
|
||||
group_state = self.bot.current_states.get_state(chat_id, user_id)
|
||||
if group_state == text:
|
||||
return True
|
||||
elif type(text) is list and group_state in text:
|
||||
@ -436,7 +436,7 @@ class StateFilter(AdvancedCustomFilter):
|
||||
|
||||
|
||||
else:
|
||||
user_state = self.bot.current_states.get_state(user_id, chat_id)
|
||||
user_state = self.bot.current_states.get_state(chat_id, user_id)
|
||||
if user_state == text:
|
||||
return True
|
||||
elif type(text) is list and user_state in text:
|
||||
|
@ -1,6 +1,5 @@
|
||||
"""
|
||||
This file is used by TeleBot.run_webhooks() function.
|
||||
|
||||
Fastapi is required to run this script.
|
||||
"""
|
||||
|
||||
@ -15,15 +14,11 @@ try:
|
||||
except ImportError:
|
||||
fastapi_installed = False
|
||||
|
||||
|
||||
from telebot.types import Update
|
||||
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
|
||||
|
||||
class SyncWebhookListener:
|
||||
def __init__(self, bot,
|
||||
secret_token: str, host: Optional[str]="127.0.0.1",
|
||||
@ -33,13 +28,13 @@ class SyncWebhookListener:
|
||||
debug: Optional[bool]=False
|
||||
) -> None:
|
||||
"""
|
||||
Aynchronous implementation of webhook listener
|
||||
for asynchronous version of telebot.
|
||||
Synchronous implementation of webhook listener
|
||||
for synchronous version of telebot.
|
||||
Not supposed to be used manually by user.
|
||||
Use AsyncTeleBot.run_webhooks() instead.
|
||||
Use TeleBot.run_webhooks() instead.
|
||||
|
||||
:param bot: AsyncTeleBot instance.
|
||||
:type bot: telebot.async_telebot.AsyncTeleBot
|
||||
:param bot: TeleBot instance.
|
||||
:type bot: telebot.TeleBot
|
||||
|
||||
:param secret_token: Telegram secret token
|
||||
:type secret_token: str
|
||||
@ -77,7 +72,8 @@ class SyncWebhookListener:
|
||||
self._prepare_endpoint_urls()
|
||||
|
||||
|
||||
def _check_dependencies(self):
|
||||
@staticmethod
|
||||
def _check_dependencies():
|
||||
if not fastapi_installed:
|
||||
raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.')
|
||||
|
||||
|
@ -41,7 +41,10 @@ class StateStorageBase:
|
||||
|
||||
def get_state(self, chat_id, user_id):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def get_interactive_data(self, chat_id, user_id):
|
||||
raise NotImplementedError
|
||||
|
||||
def save(self, chat_id, user_id, data):
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -3,6 +3,7 @@ from telebot.storage.base_storage import StateStorageBase, StateContext
|
||||
|
||||
class StateMemoryStorage(StateStorageBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.data = {}
|
||||
#
|
||||
# {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...}
|
||||
|
@ -5,8 +5,8 @@ import pickle
|
||||
|
||||
|
||||
class StatePickleStorage(StateStorageBase):
|
||||
# noinspection PyMissingConstructor
|
||||
def __init__(self, file_path="./.state-save/states.pkl") -> None:
|
||||
super().__init__()
|
||||
self.file_path = file_path
|
||||
self.create_dir()
|
||||
self.data = self.read()
|
||||
|
@ -16,6 +16,7 @@ class StateRedisStorage(StateStorageBase):
|
||||
TeleBot(storage=StateRedisStorage())
|
||||
"""
|
||||
def __init__(self, host='localhost', port=6379, db=0, password=None, prefix='telebot_'):
|
||||
super().__init__()
|
||||
self.redis = ConnectionPool(host=host, port=port, db=db, password=password)
|
||||
#self.con = Redis(connection_pool=self.redis) -> use this when necessary
|
||||
#
|
||||
|
@ -647,15 +647,15 @@ def antiflood(function: Callable, *args, **kwargs):
|
||||
"""
|
||||
from telebot.apihelper import ApiTelegramException
|
||||
from time import sleep
|
||||
msg = None
|
||||
|
||||
try:
|
||||
msg = function(*args, **kwargs)
|
||||
return function(*args, **kwargs)
|
||||
except ApiTelegramException as ex:
|
||||
if ex.error_code == 429:
|
||||
sleep(ex.result_json['parameters']['retry_after'])
|
||||
msg = function(*args, **kwargs)
|
||||
finally:
|
||||
return msg
|
||||
return function(*args, **kwargs)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def parse_web_app_data(token: str, raw_init_data: str):
|
||||
|
Loading…
Reference in New Issue
Block a user