mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Merge pull request #1693 from coder2020official/conflicts
Logging improvements(still not 100%), file restarts on file changes(needs tests), and more
This commit is contained in:
commit
82ad37fed8
28
examples/asynchronous_telebot/detect_changes.py
Normal file
28
examples/asynchronous_telebot/detect_changes.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/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)
|
||||||
|
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
# only new versions(4.7.0+)
|
||||||
|
asyncio.run(bot.polling(restart_on_change=True))
|
28
examples/detect_changes.py
Normal file
28
examples/detect_changes.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# This is a simple echo bot using the decorator mechanism.
|
||||||
|
# It echoes any incoming text messages.
|
||||||
|
|
||||||
|
import telebot
|
||||||
|
|
||||||
|
API_TOKEN = '<api_token>'
|
||||||
|
|
||||||
|
bot = telebot.TeleBot(API_TOKEN)
|
||||||
|
|
||||||
|
|
||||||
|
# Handle '/start' and '/help'
|
||||||
|
@bot.message_handler(commands=['help', 'start'])
|
||||||
|
def send_welcome(message):
|
||||||
|
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)
|
||||||
|
def echo_message(message):
|
||||||
|
bot.reply_to(message, message.text)
|
||||||
|
|
||||||
|
# only versions greater than 4.7.0
|
||||||
|
bot.infinity_polling(restart_on_change=True)
|
3
setup.py
3
setup.py
@ -31,6 +31,9 @@ setup(name='pyTelegramBotAPI',
|
|||||||
'aiohttp': 'aiohttp',
|
'aiohttp': 'aiohttp',
|
||||||
'fastapi': 'fastapi',
|
'fastapi': 'fastapi',
|
||||||
'uvicorn': 'uvicorn',
|
'uvicorn': 'uvicorn',
|
||||||
|
'psutil': 'psutil',
|
||||||
|
'coloredlogs': 'coloredlogs',
|
||||||
|
'watchdog': 'watchdog'
|
||||||
},
|
},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
@ -95,6 +95,10 @@ class TeleBot:
|
|||||||
See more examples in examples/ directory:
|
See more examples in examples/ directory:
|
||||||
https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples
|
https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Install coloredlogs module to specify colorful_logs=True
|
||||||
|
|
||||||
|
|
||||||
:param token: Token of a bot, should be obtained from @BotFather
|
:param token: Token of a bot, should be obtained from @BotFather
|
||||||
:type token: :obj:`str`
|
:type token: :obj:`str`
|
||||||
@ -131,7 +135,7 @@ class TeleBot:
|
|||||||
|
|
||||||
:param use_class_middlewares: Use class middlewares, defaults to False
|
:param use_class_middlewares: Use class middlewares, defaults to False
|
||||||
:type use_class_middlewares: :obj:`bool`, optional
|
:type use_class_middlewares: :obj:`bool`, optional
|
||||||
|
|
||||||
:param disable_web_page_preview: Default value for disable_web_page_preview, defaults to None
|
:param disable_web_page_preview: Default value for disable_web_page_preview, defaults to None
|
||||||
:type disable_web_page_preview: :obj:`bool`, optional
|
:type disable_web_page_preview: :obj:`bool`, optional
|
||||||
|
|
||||||
@ -143,6 +147,10 @@ class TeleBot:
|
|||||||
|
|
||||||
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
|
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
|
||||||
:type allow_sending_without_reply: :obj:`bool`, optional
|
:type allow_sending_without_reply: :obj:`bool`, optional
|
||||||
|
|
||||||
|
|
||||||
|
:param colorful_logs: Outputs colorful logs
|
||||||
|
:type colorful_logs: :obj:`bool`, optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -155,7 +163,8 @@ class TeleBot:
|
|||||||
disable_web_page_preview: Optional[bool]=None,
|
disable_web_page_preview: Optional[bool]=None,
|
||||||
disable_notification: Optional[bool]=None,
|
disable_notification: Optional[bool]=None,
|
||||||
protect_content: Optional[bool]=None,
|
protect_content: Optional[bool]=None,
|
||||||
allow_sending_without_reply: Optional[bool]=None
|
allow_sending_without_reply: Optional[bool]=None,
|
||||||
|
colorful_logs: Optional[bool]=False
|
||||||
):
|
):
|
||||||
|
|
||||||
# update-related
|
# update-related
|
||||||
@ -171,6 +180,16 @@ class TeleBot:
|
|||||||
self.protect_content = protect_content
|
self.protect_content = protect_content
|
||||||
self.allow_sending_without_reply = allow_sending_without_reply
|
self.allow_sending_without_reply = allow_sending_without_reply
|
||||||
|
|
||||||
|
# logs-related
|
||||||
|
if colorful_logs:
|
||||||
|
try:
|
||||||
|
import coloredlogs
|
||||||
|
coloredlogs.install(logger=logger, level=logger.level)
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'Install colorredlogs module to use colorful_logs option.'
|
||||||
|
)
|
||||||
|
|
||||||
# threading-related
|
# threading-related
|
||||||
self.__stop_polling = threading.Event()
|
self.__stop_polling = threading.Event()
|
||||||
self.exc_info = None
|
self.exc_info = None
|
||||||
@ -865,12 +884,36 @@ class TeleBot:
|
|||||||
for listener in self.update_listener:
|
for listener in self.update_listener:
|
||||||
self._exec_task(listener, new_messages)
|
self._exec_task(listener, new_messages)
|
||||||
|
|
||||||
|
def _setup_change_detector(self, path_to_watch: str):
|
||||||
|
try:
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
from telebot.ext.reloader import EventHandler
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'Please install watchdog and psutil before using restart_on_change option.'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.event_handler = EventHandler()
|
||||||
|
path = path_to_watch if path_to_watch else None
|
||||||
|
if path is None:
|
||||||
|
# Make it possible to specify --path argument to the script
|
||||||
|
path = sys.argv[sys.argv.index('--path') + 1] if '--path' in sys.argv else '.'
|
||||||
|
|
||||||
|
|
||||||
|
self.event_observer = Observer()
|
||||||
|
self.event_observer.schedule(self.event_handler, path, recursive=True)
|
||||||
|
self.event_observer.start()
|
||||||
|
|
||||||
def infinity_polling(self, timeout: Optional[int]=20, skip_pending: Optional[bool]=False, long_polling_timeout: Optional[int]=20,
|
def infinity_polling(self, timeout: Optional[int]=20, skip_pending: Optional[bool]=False, long_polling_timeout: Optional[int]=20,
|
||||||
logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None, *args, **kwargs):
|
logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None,
|
||||||
|
restart_on_change: Optional[bool]=False, path_to_watch: Optional[str]=None, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Wrap polling with infinite loop and exception handling to avoid bot stops polling.
|
Wrap polling with infinite loop and exception handling to avoid bot stops polling.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Install watchdog and psutil before using restart_on_change option.
|
||||||
|
|
||||||
:param timeout: Request connection timeout.
|
:param timeout: Request connection timeout.
|
||||||
:type timeout: :obj:`int`
|
:type timeout: :obj:`int`
|
||||||
|
|
||||||
@ -893,15 +936,25 @@ class TeleBot:
|
|||||||
so unwanted updates may be received for a short period of time.
|
so unwanted updates may be received for a short period of time.
|
||||||
:type allowed_updates: :obj:`list` of :obj:`str`
|
:type allowed_updates: :obj:`list` of :obj:`str`
|
||||||
|
|
||||||
|
:param restart_on_change: Restart a file on file(s) change. Defaults to False
|
||||||
|
:type restart_on_change: :obj:`bool`
|
||||||
|
|
||||||
|
:param path_to_watch: Path to watch for changes. Defaults to current directory
|
||||||
|
:type path_to_watch: :obj:`str`
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if skip_pending:
|
if skip_pending:
|
||||||
self.__skip_updates()
|
self.__skip_updates()
|
||||||
|
|
||||||
|
if restart_on_change:
|
||||||
|
self._setup_change_detector(path_to_watch)
|
||||||
|
|
||||||
while not self.__stop_polling.is_set():
|
while not self.__stop_polling.is_set():
|
||||||
try:
|
try:
|
||||||
self.polling(non_stop=True, timeout=timeout, long_polling_timeout=long_polling_timeout,
|
self.polling(non_stop=True, timeout=timeout, long_polling_timeout=long_polling_timeout,
|
||||||
logger_level=logger_level, allowed_updates=allowed_updates, *args, **kwargs)
|
logger_level=logger_level, allowed_updates=allowed_updates, restart_on_change=False,
|
||||||
|
*args, **kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if logger_level and logger_level >= logging.ERROR:
|
if logger_level and logger_level >= logging.ERROR:
|
||||||
logger.error("Infinity polling exception: %s", str(e))
|
logger.error("Infinity polling exception: %s", str(e))
|
||||||
@ -918,7 +971,7 @@ class TeleBot:
|
|||||||
def polling(self, non_stop: Optional[bool]=False, skip_pending: Optional[bool]=False, interval: Optional[int]=0,
|
def polling(self, non_stop: Optional[bool]=False, skip_pending: Optional[bool]=False, interval: Optional[int]=0,
|
||||||
timeout: Optional[int]=20, long_polling_timeout: Optional[int]=20,
|
timeout: Optional[int]=20, long_polling_timeout: Optional[int]=20,
|
||||||
logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None,
|
logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None,
|
||||||
none_stop: Optional[bool]=None):
|
none_stop: Optional[bool]=None, restart_on_change: Optional[bool]=False, path_to_watch: Optional[str]=None):
|
||||||
"""
|
"""
|
||||||
This function creates a new Thread that calls an internal __retrieve_updates function.
|
This function creates a new Thread that calls an internal __retrieve_updates function.
|
||||||
This allows the bot to retrieve Updates automatically and notify listeners and message handlers accordingly.
|
This allows the bot to retrieve Updates automatically and notify listeners and message handlers accordingly.
|
||||||
@ -930,6 +983,10 @@ class TeleBot:
|
|||||||
.. deprecated:: 4.1.1
|
.. deprecated:: 4.1.1
|
||||||
Use :meth:`infinity_polling` instead.
|
Use :meth:`infinity_polling` instead.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Install watchdog and psutil before using restart_on_change option.
|
||||||
|
|
||||||
:param interval: Delay between two update retrivals
|
:param interval: Delay between two update retrivals
|
||||||
:type interval: :obj:`int`
|
:type interval: :obj:`int`
|
||||||
|
|
||||||
@ -961,6 +1018,12 @@ class TeleBot:
|
|||||||
|
|
||||||
:param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility.
|
:param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility.
|
||||||
:type none_stop: :obj:`bool`
|
:type none_stop: :obj:`bool`
|
||||||
|
|
||||||
|
:param restart_on_change: Restart a file on file(s) change. Defaults to False
|
||||||
|
:type restart_on_change: :obj:`bool`
|
||||||
|
|
||||||
|
:param path_to_watch: Path to watch for changes. Defaults to None
|
||||||
|
:type path_to_watch: :obj:`str`
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@ -970,6 +1033,11 @@ class TeleBot:
|
|||||||
|
|
||||||
if skip_pending:
|
if skip_pending:
|
||||||
self.__skip_updates()
|
self.__skip_updates()
|
||||||
|
|
||||||
|
if restart_on_change:
|
||||||
|
self._setup_change_detector(path_to_watch)
|
||||||
|
|
||||||
|
logger.info('Starting your bot with username: [@%s]', self.user.username)
|
||||||
|
|
||||||
if self.threaded:
|
if self.threaded:
|
||||||
self.__threaded_polling(non_stop=non_stop, interval=interval, timeout=timeout, long_polling_timeout=long_polling_timeout,
|
self.__threaded_polling(non_stop=non_stop, interval=interval, timeout=timeout, long_polling_timeout=long_polling_timeout,
|
||||||
|
@ -5,6 +5,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any, Awaitable, Callable, List, Optional, Union
|
from typing import Any, Awaitable, Callable, List, Optional, Union
|
||||||
|
import sys
|
||||||
|
|
||||||
# this imports are used to avoid circular import error
|
# this imports are used to avoid circular import error
|
||||||
import telebot.util
|
import telebot.util
|
||||||
@ -17,12 +18,11 @@ from telebot.asyncio_handler_backends import BaseMiddleware, CancelUpdate, SkipH
|
|||||||
|
|
||||||
from inspect import signature
|
from inspect import signature
|
||||||
|
|
||||||
from telebot import logger
|
|
||||||
|
|
||||||
from telebot import util, types, asyncio_helper
|
from telebot import util, types, asyncio_helper
|
||||||
import asyncio
|
import asyncio
|
||||||
from telebot import asyncio_filters
|
from telebot import asyncio_filters
|
||||||
|
|
||||||
|
logger = logging.getLogger('TeleBot')
|
||||||
|
|
||||||
REPLY_MARKUP_TYPES = Union[
|
REPLY_MARKUP_TYPES = Union[
|
||||||
types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup,
|
types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup,
|
||||||
@ -82,6 +82,10 @@ class AsyncTeleBot:
|
|||||||
See more examples in examples/ directory:
|
See more examples in examples/ directory:
|
||||||
https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples
|
https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Install coloredlogs module to specify colorful_logs=True
|
||||||
|
|
||||||
|
|
||||||
:param token: Token of a bot, obtained from @BotFather
|
:param token: Token of a bot, obtained from @BotFather
|
||||||
:type token: :obj:`str`
|
:type token: :obj:`str`
|
||||||
@ -109,6 +113,9 @@ class AsyncTeleBot:
|
|||||||
|
|
||||||
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
|
:param allow_sending_without_reply: Default value for allow_sending_without_reply, defaults to None
|
||||||
:type allow_sending_without_reply: :obj:`bool`, optional
|
:type allow_sending_without_reply: :obj:`bool`, optional
|
||||||
|
|
||||||
|
:param colorful_logs: Outputs colorful logs
|
||||||
|
:type colorful_logs: :obj:`bool`, optional
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -118,12 +125,23 @@ class AsyncTeleBot:
|
|||||||
disable_web_page_preview: Optional[bool]=None,
|
disable_web_page_preview: Optional[bool]=None,
|
||||||
disable_notification: Optional[bool]=None,
|
disable_notification: Optional[bool]=None,
|
||||||
protect_content: Optional[bool]=None,
|
protect_content: Optional[bool]=None,
|
||||||
allow_sending_without_reply: Optional[bool]=None) -> None:
|
allow_sending_without_reply: Optional[bool]=None,
|
||||||
|
colorful_logs: Optional[bool]=False) -> None:
|
||||||
|
|
||||||
# update-related
|
# update-related
|
||||||
self.token = token
|
self.token = token
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
|
|
||||||
|
# logs-related
|
||||||
|
if colorful_logs:
|
||||||
|
try:
|
||||||
|
import coloredlogs
|
||||||
|
coloredlogs.install(logger=logger, level=logger.level)
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'Install colorredlogs module to use colorful_logs option.'
|
||||||
|
)
|
||||||
|
|
||||||
# properties
|
# properties
|
||||||
self.parse_mode = parse_mode
|
self.parse_mode = parse_mode
|
||||||
self.disable_web_page_preview = disable_web_page_preview
|
self.disable_web_page_preview = disable_web_page_preview
|
||||||
@ -155,6 +173,12 @@ class AsyncTeleBot:
|
|||||||
self.state_handlers = []
|
self.state_handlers = []
|
||||||
self.middlewares = []
|
self.middlewares = []
|
||||||
|
|
||||||
|
self._user = None # set during polling
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user(self):
|
||||||
|
return self._user
|
||||||
|
|
||||||
async def close_session(self):
|
async def close_session(self):
|
||||||
"""
|
"""
|
||||||
Closes existing session of aiohttp.
|
Closes existing session of aiohttp.
|
||||||
@ -194,9 +218,28 @@ class AsyncTeleBot:
|
|||||||
json_updates = await asyncio_helper.get_updates(self.token, offset, limit, timeout, allowed_updates, request_timeout)
|
json_updates = await asyncio_helper.get_updates(self.token, offset, limit, timeout, allowed_updates, request_timeout)
|
||||||
return [types.Update.de_json(ju) for ju in json_updates]
|
return [types.Update.de_json(ju) for ju in json_updates]
|
||||||
|
|
||||||
|
def _setup_change_detector(self, path_to_watch: str) -> None:
|
||||||
|
try:
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
from telebot.ext.reloader import EventHandler
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'Please install watchdog and psutil before using restart_on_change option.'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.event_handler = EventHandler()
|
||||||
|
path = path_to_watch if path_to_watch else None
|
||||||
|
if path is None:
|
||||||
|
# Make it possible to specify --path argument to the script
|
||||||
|
path = sys.argv[sys.argv.index('--path') + 1] if '--path' in sys.argv else '.'
|
||||||
|
|
||||||
|
self.event_observer = Observer()
|
||||||
|
self.event_observer.schedule(self.event_handler, path, recursive=True)
|
||||||
|
self.event_observer.start()
|
||||||
|
|
||||||
async def polling(self, non_stop: bool=False, skip_pending=False, interval: int=0, timeout: int=20,
|
async def polling(self, non_stop: bool=False, skip_pending=False, interval: int=0, timeout: int=20,
|
||||||
request_timeout: Optional[int]=None, allowed_updates: Optional[List[str]]=None,
|
request_timeout: Optional[int]=None, allowed_updates: Optional[List[str]]=None,
|
||||||
none_stop: Optional[bool]=None):
|
none_stop: Optional[bool]=None, restart_on_change: Optional[bool]=False, path_to_watch: Optional[str]=None):
|
||||||
"""
|
"""
|
||||||
Runs bot in long-polling mode in a main loop.
|
Runs bot in long-polling mode in a main loop.
|
||||||
This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly.
|
This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly.
|
||||||
@ -210,6 +253,10 @@ class AsyncTeleBot:
|
|||||||
Set non_stop=True if you want your bot to continue receiving updates
|
Set non_stop=True if you want your bot to continue receiving updates
|
||||||
if there is an error.
|
if there is an error.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Install watchdog and psutil before using restart_on_change option.
|
||||||
|
|
||||||
:param non_stop: Do not stop polling when an ApiException occurs.
|
:param non_stop: Do not stop polling when an ApiException occurs.
|
||||||
:type non_stop: :obj:`bool`
|
:type non_stop: :obj:`bool`
|
||||||
|
|
||||||
@ -237,6 +284,12 @@ class AsyncTeleBot:
|
|||||||
|
|
||||||
:param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility.
|
:param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility.
|
||||||
:type none_stop: :obj:`bool`
|
:type none_stop: :obj:`bool`
|
||||||
|
|
||||||
|
:param restart_on_change: Restart a file on file(s) change. Defaults to False.
|
||||||
|
:type restart_on_change: :obj:`bool`
|
||||||
|
|
||||||
|
:param path_to_watch: Path to watch for changes. Defaults to current directory
|
||||||
|
:type path_to_watch: :obj:`str`
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@ -246,13 +299,21 @@ class AsyncTeleBot:
|
|||||||
|
|
||||||
if skip_pending:
|
if skip_pending:
|
||||||
await self.skip_updates()
|
await self.skip_updates()
|
||||||
|
|
||||||
|
if restart_on_change:
|
||||||
|
self._setup_change_detector(path_to_watch)
|
||||||
|
|
||||||
await self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates)
|
await self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates)
|
||||||
|
|
||||||
async def infinity_polling(self, timeout: Optional[int]=20, skip_pending: Optional[bool]=False, request_timeout: Optional[int]=None,
|
async def infinity_polling(self, timeout: Optional[int]=20, skip_pending: Optional[bool]=False, request_timeout: Optional[int]=None,
|
||||||
logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None, *args, **kwargs):
|
logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None,
|
||||||
|
restart_on_change: Optional[bool]=False, path_to_watch: Optional[str]=None, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Wrap polling with infinite loop and exception handling to avoid bot stops polling.
|
Wrap polling with infinite loop and exception handling to avoid bot stops polling.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Install watchdog and psutil before using restart_on_change option.
|
||||||
|
|
||||||
:param timeout: Timeout in seconds for get_updates(Defaults to None)
|
:param timeout: Timeout in seconds for get_updates(Defaults to None)
|
||||||
:type timeout: :obj:`int`
|
:type timeout: :obj:`int`
|
||||||
|
|
||||||
@ -276,11 +337,21 @@ class AsyncTeleBot:
|
|||||||
so unwanted updates may be received for a short period of time.
|
so unwanted updates may be received for a short period of time.
|
||||||
:type allowed_updates: :obj:`list` of :obj:`str`
|
:type allowed_updates: :obj:`list` of :obj:`str`
|
||||||
|
|
||||||
|
:param restart_on_change: Restart a file on file(s) change. Defaults to False
|
||||||
|
:type restart_on_change: :obj:`bool`
|
||||||
|
|
||||||
|
:param path_to_watch: Path to watch for changes. Defaults to current directory
|
||||||
|
:type path_to_watch: :obj:`str`
|
||||||
|
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
if skip_pending:
|
if skip_pending:
|
||||||
await self.skip_updates()
|
await self.skip_updates()
|
||||||
self._polling = True
|
self._polling = True
|
||||||
|
|
||||||
|
if restart_on_change:
|
||||||
|
self._setup_change_detector(path_to_watch)
|
||||||
|
|
||||||
while self._polling:
|
while self._polling:
|
||||||
try:
|
try:
|
||||||
await self._process_polling(non_stop=False, timeout=timeout, request_timeout=request_timeout,
|
await self._process_polling(non_stop=False, timeout=timeout, request_timeout=request_timeout,
|
||||||
@ -314,9 +385,15 @@ class AsyncTeleBot:
|
|||||||
|
|
||||||
Please note that this parameter doesn't affect updates created before the call to the get_updates,
|
Please note that this parameter doesn't affect updates created before the call to the get_updates,
|
||||||
so unwanted updates may be received for a short period of time.
|
so unwanted updates may be received for a short period of time.
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self._user = await self.get_me()
|
||||||
|
|
||||||
|
logger.info('Starting your bot with username: [@%s]', self.user.username)
|
||||||
|
|
||||||
self._polling = True
|
self._polling = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -13,8 +13,10 @@ API_URL = 'https://api.telegram.org/bot{0}/{1}'
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from telebot import util, logger
|
from telebot import util
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger('TeleBot')
|
||||||
|
|
||||||
proxy = None
|
proxy = None
|
||||||
session = None
|
session = None
|
||||||
@ -69,7 +71,7 @@ async def _process_request(token, url, method='get', params=None, files=None, **
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
# let's check for timeout in params
|
# let's check for timeout in params
|
||||||
request_timeout = params.pop('timeout', None)
|
request_timeout = params.pop('timeout', None) if params else None
|
||||||
# we will apply default request_timeout if there is no timeout in params
|
# we will apply default request_timeout if there is no timeout in params
|
||||||
# otherwise, we will use timeout parameter applied for payload.
|
# otherwise, we will use timeout parameter applied for payload.
|
||||||
|
|
||||||
|
25
telebot/ext/reloader.py
Normal file
25
telebot/ext/reloader.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
from watchdog.events import FileSystemEvent
|
||||||
|
import psutil
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger('TeleBot')
|
||||||
|
|
||||||
|
class EventHandler(FileSystemEventHandler):
|
||||||
|
def on_any_event(self, event: FileSystemEvent):
|
||||||
|
logger.info('* Detected changes in: %s, reloading', (event.src_path))
|
||||||
|
restart_file()
|
||||||
|
|
||||||
|
def restart_file():
|
||||||
|
try:
|
||||||
|
p = psutil.Process(os.getpid())
|
||||||
|
for handler in p.open_files() + p.connections():
|
||||||
|
os.close(handler.fd)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
python = sys.executable
|
||||||
|
os.execl(python, python, *sys.argv)
|
Loading…
Reference in New Issue
Block a user