From e0ffe0b4f5ce6dce8bddde9c22d2107770327580 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 30 Aug 2022 21:24:54 +0400 Subject: [PATCH 01/11] Added reloader to ext --- telebot/ext/reloader.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 telebot/ext/reloader.py diff --git a/telebot/ext/reloader.py b/telebot/ext/reloader.py new file mode 100644 index 0000000..6ec08a5 --- /dev/null +++ b/telebot/ext/reloader.py @@ -0,0 +1,27 @@ + +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) From 0f7ab0d05f7023e6d54b5883d3541a30cd999ad7 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 30 Aug 2022 21:25:41 +0400 Subject: [PATCH 02/11] Added colorful logs, file restarts on changes to sync --- telebot/__init__.py | 47 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 026d32e..de1b712 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -131,6 +131,9 @@ class TeleBot: :param use_class_middlewares: Use class middlewares, defaults to False :type use_class_middlewares: :obj:`bool`, optional + + :param colorful_logs: Outputs colorful logs + :type colorful_logs: :obj:`bool`, optional """ def __init__( @@ -139,7 +142,8 @@ 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, + colorful_logs: Optional[bool]=False ): self.token = token self.parse_mode = parse_mode @@ -147,6 +151,16 @@ class TeleBot: self.skip_pending = skip_pending self.suppress_middleware_excepions = suppress_middleware_excepions + 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.' + ) + + self.__stop_polling = threading.Event() self.last_update_id = last_update_id self.exc_info = None @@ -838,7 +852,8 @@ class TeleBot: 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, *args, **kwargs): """ Wrap polling with infinite loop and exception handling to avoid bot stops polling. @@ -864,6 +879,9 @@ class TeleBot: so unwanted updates may be received for a short period of time. :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` + :return: """ if skip_pending: @@ -872,7 +890,8 @@ class TeleBot: while not self.__stop_polling.is_set(): try: 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=restart_on_change, + *args, **kwargs) except Exception as e: if logger_level and logger_level >= logging.ERROR: logger.error("Infinity polling exception: %s", str(e)) @@ -889,7 +908,7 @@ class TeleBot: 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, 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): """ 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. @@ -932,6 +951,9 @@ class TeleBot: :param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility. :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` :return: """ @@ -941,6 +963,23 @@ class TeleBot: if skip_pending: self.__skip_updates() + + if restart_on_change: + 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.' + ) + + event_handler = EventHandler() + path = sys.argv[1] if len(sys.argv) > 1 else '.' + observer = Observer() + observer.schedule(event_handler, path, recursive=True) + observer.start() + + logger.info('Starting your bot with username: [@%s]', self.user.username) if self.threaded: self.__threaded_polling(non_stop=non_stop, interval=interval, timeout=timeout, long_polling_timeout=long_polling_timeout, From 9216f15c16d56033e7dcbbdc414580ab1c5b43b0 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 30 Aug 2022 21:26:41 +0400 Subject: [PATCH 03/11] Logs, file restarts, loggers to async Added colorful logs, file restarts on changes, improved logger, added cached version of user-bot to async --- telebot/async_telebot.py | 67 +++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 68e1768..9cf5e9f 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -3,6 +3,7 @@ from datetime import datetime import logging import re +import sys import time import traceback from typing import Any, Awaitable, Callable, List, Optional, Union @@ -18,12 +19,11 @@ from telebot.asyncio_handler_backends import BaseMiddleware, CancelUpdate, SkipH from inspect import signature -from telebot import logger - from telebot import util, types, asyncio_helper import asyncio from telebot import asyncio_filters +logger = logging.getLogger('TeleBot') REPLY_MARKUP_TYPES = Union[ types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, @@ -99,10 +99,14 @@ class AsyncTeleBot: :param state_storage: Storage for states, defaults to StateMemoryStorage() :type state_storage: :class:`telebot.asyncio_storage.StateMemoryStorage`, 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()) -> None: + exception_handler: Optional[ExceptionHandler]=None, state_storage: Optional[StateStorageBase]=StateMemoryStorage(), + colorful_logs: Optional[bool]=False) -> None: self.token = token self.offset = offset @@ -110,6 +114,15 @@ class AsyncTeleBot: self.parse_mode = parse_mode self.update_listener = [] + 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.' + ) + self.exception_handler = exception_handler @@ -135,6 +148,12 @@ class AsyncTeleBot: self.middlewares = [] + self._user = None # set during polling + + @property + def user(self): + return self._user + async def close_session(self): """ Closes existing session of aiohttp. @@ -176,7 +195,7 @@ class AsyncTeleBot: 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, - none_stop: Optional[bool]=None): + none_stop: Optional[bool]=None, restart_on_change: Optional[bool]=False): """ 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. @@ -217,6 +236,9 @@ class AsyncTeleBot: :param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility. :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` :return: """ @@ -226,10 +248,11 @@ class AsyncTeleBot: if skip_pending: await self.skip_updates() - await self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates) + await self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates, restart_on_change) 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, *args, **kwargs): """ Wrap polling with infinite loop and exception handling to avoid bot stops polling. @@ -256,6 +279,9 @@ class AsyncTeleBot: so unwanted updates may be received for a short period of time. :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` + :return: None """ if skip_pending: @@ -264,7 +290,7 @@ class AsyncTeleBot: while self._polling: try: await self._process_polling(non_stop=False, timeout=timeout, request_timeout=request_timeout, - allowed_updates=allowed_updates, *args, **kwargs) + allowed_updates=allowed_updates, restart_on_change=restart_on_change, *args, **kwargs) except Exception as e: if logger_level and logger_level >= logging.ERROR: logger.error("Infinity polling exception: %s", str(e)) @@ -278,7 +304,7 @@ class AsyncTeleBot: logger.error("Break infinity polling") async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout: int=20, - request_timeout: int=None, allowed_updates: Optional[List[str]]=None): + request_timeout: int=None, allowed_updates: Optional[List[str]]=None, restart_on_change: Optional[bool]=False): """ Function to process polling. @@ -294,9 +320,34 @@ class AsyncTeleBot: 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. + + :param restart_on_change: Restart a file on file(s) change. Defaults to False + :type restart_on_change: :obj:`bool` + :return: """ + + self._user = await self.get_me() + + + if restart_on_change: + 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.' + ) + + event_handler = EventHandler() + path = sys.argv[1] if len(sys.argv) > 1 else '.' + observer = Observer() + observer.schedule(event_handler, path, recursive=True) + observer.start() + + logger.info('Starting your bot with username: [@%s]', self.user.username) + self._polling = True try: From 1b1d6c8239cb8d83508000baa098990cdcb724a7 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 30 Aug 2022 21:26:56 +0400 Subject: [PATCH 04/11] Improved asyncio helper's logger --- telebot/asyncio_helper.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 06575db..f3e58bd 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -13,8 +13,10 @@ API_URL = 'https://api.telegram.org/bot{0}/{1}' from datetime import datetime -from telebot import util, logger +from telebot import util +import logging +logger = logging.getLogger('TeleBot') proxy = None session = None From 96e137f5e60c59076c721cdbb5430cf5ccd537f1 Mon Sep 17 00:00:00 2001 From: _run Date: Fri, 16 Sep 2022 22:39:40 +0400 Subject: [PATCH 05/11] Update setup.py --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 2e60d91..5180f56 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,9 @@ setup(name='pyTelegramBotAPI', 'aiohttp': 'aiohttp', 'fastapi': 'fastapi', 'uvicorn': 'uvicorn', + 'psutil': 'psutil', + 'coloredlogs': 'coloredlogs', + 'watchdog': 'watchdog' }, classifiers=[ 'Development Status :: 5 - Production/Stable', From eb576d83fb6d5b6c19d51ad12eb0cc61605ff478 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Sep 2022 23:22:21 +0400 Subject: [PATCH 06/11] Fixed a bug, made improvements in reload system Didn't test that much, there is still some stuff to do --- telebot/__init__.py | 45 ++++++++++++++++++--------- telebot/async_telebot.py | 64 ++++++++++++++++++++++++--------------- telebot/asyncio_helper.py | 2 +- telebot/ext/reloader.py | 4 +-- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 63c10a8..cfe6104 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -880,10 +880,27 @@ class TeleBot: for listener in self.update_listener: self._exec_task(listener, new_messages) + def _setup_change_detector(self): + 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: + path = sys.argv[1] if len(sys.argv) > 1 else '.' # current directory + + self.observer = Observer() + self.observer.schedule(self.event_handler, path, recursive=True) + self.observer.start() 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, - restart_on_change: Optional[bool]=False, *args, **kwargs): + 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. @@ -912,11 +929,18 @@ class TeleBot: :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: """ if skip_pending: self.__skip_updates() + if restart_on_change: + self._setup_change_detector(path_to_watch) + restart_on_change = False + while not self.__stop_polling.is_set(): try: self.polling(non_stop=True, timeout=timeout, long_polling_timeout=long_polling_timeout, @@ -938,7 +962,7 @@ class TeleBot: 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, logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None, - none_stop: Optional[bool]=None, restart_on_change: Optional[bool]=False): + 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 allows the bot to retrieve Updates automatically and notify listeners and message handlers accordingly. @@ -984,6 +1008,9 @@ class TeleBot: :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: """ @@ -995,19 +1022,7 @@ class TeleBot: self.__skip_updates() if restart_on_change: - 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.' - ) - - event_handler = EventHandler() - path = sys.argv[1] if len(sys.argv) > 1 else '.' - observer = Observer() - observer.schedule(event_handler, path, recursive=True) - observer.start() + self._setup_change_detector(path_to_watch) logger.info('Starting your bot with username: [@%s]', self.user.username) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index b705a36..9e99f93 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -5,6 +5,7 @@ import logging import re import traceback from typing import Any, Awaitable, Callable, List, Optional, Union +import sys # this imports are used to avoid circular import error import telebot.util @@ -213,9 +214,27 @@ class AsyncTeleBot: json_updates = await asyncio_helper.get_updates(self.token, offset, limit, timeout, allowed_updates, request_timeout) return [types.Update.de_json(ju) for ju in json_updates] + def _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: + path = sys.argv[1] if len(sys.argv) > 1 else '.' # current directory + + self.observer = Observer() + self.observer.schedule(self.event_handler, path, recursive=True) + self.observer.start() + 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, - none_stop: Optional[bool]=None, restart_on_change: Optional[bool]=False): + 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. This allows the bot to retrieve Updates automagically and notify listeners and message handlers accordingly. @@ -259,6 +278,9 @@ class AsyncTeleBot: :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: """ @@ -268,11 +290,15 @@ class AsyncTeleBot: if skip_pending: await self.skip_updates() - await self._process_polling(non_stop, interval, timeout, request_timeout, allowed_updates, restart_on_change) + + if restart_on_change: + self._setup_change_detector(path_to_watch) + + 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, logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None, - restart_on_change: Optional[bool]=False, *args, **kwargs): + 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. @@ -302,15 +328,24 @@ class AsyncTeleBot: :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 """ if skip_pending: await self.skip_updates() self._polling = True + + if restart_on_change: + restart_on_change = False + + self._setup_change_detector(path_to_watch) + while self._polling: try: await self._process_polling(non_stop=False, timeout=timeout, request_timeout=request_timeout, - allowed_updates=allowed_updates, restart_on_change=restart_on_change, *args, **kwargs) + allowed_updates=allowed_updates, *args, **kwargs) except Exception as e: if logger_level and logger_level >= logging.ERROR: logger.error("Infinity polling exception: %s", str(e)) @@ -324,7 +359,7 @@ class AsyncTeleBot: logger.error("Break infinity polling") async def _process_polling(self, non_stop: bool=False, interval: int=0, timeout: int=20, - request_timeout: int=None, allowed_updates: Optional[List[str]]=None, restart_on_change: Optional[bool]=False): + request_timeout: int=None, allowed_updates: Optional[List[str]]=None): """ Function to process polling. @@ -341,30 +376,11 @@ class AsyncTeleBot: 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. - :param restart_on_change: Restart a file on file(s) change. Defaults to False - :type restart_on_change: :obj:`bool` - :return: """ self._user = await self.get_me() - - - if restart_on_change: - 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.' - ) - - event_handler = EventHandler() - path = sys.argv[1] if len(sys.argv) > 1 else '.' - observer = Observer() - observer.schedule(event_handler, path, recursive=True) - observer.start() logger.info('Starting your bot with username: [@%s]', self.user.username) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 03288e3..7e8958a 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -71,7 +71,7 @@ async def _process_request(token, url, method='get', params=None, files=None, ** else: # 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 # otherwise, we will use timeout parameter applied for payload. diff --git a/telebot/ext/reloader.py b/telebot/ext/reloader.py index 6ec08a5..d57453f 100644 --- a/telebot/ext/reloader.py +++ b/telebot/ext/reloader.py @@ -8,11 +8,9 @@ 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)) + logger.info('* Detected changes in: %s, reloading', (event.src_path)) restart_file() def restart_file(): From 04ff428bbab2b33941acad3c71dd1de103a2a2e4 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 1 Oct 2022 21:02:40 +0400 Subject: [PATCH 07/11] Added option to specify path to watch --- telebot/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index cfe6104..e5aad03 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -880,7 +880,7 @@ class TeleBot: for listener in self.update_listener: self._exec_task(listener, new_messages) - def _setup_change_detector(self): + def _setup_change_detector(self, path_to_watch: str): try: from watchdog.observers import Observer from telebot.ext.reloader import EventHandler From ea69b8093d350ca21a9e25d1aa17787865075a29 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 1 Oct 2022 21:15:24 +0400 Subject: [PATCH 08/11] Added some notes --- telebot/__init__.py | 12 ++++++++++++ telebot/async_telebot.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index e5aad03..98f2aca 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -95,6 +95,10 @@ class TeleBot: See more examples in examples/ directory: 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 :type token: :obj:`str` @@ -904,6 +908,10 @@ class TeleBot: """ 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. :type timeout: :obj:`int` @@ -974,6 +982,10 @@ class TeleBot: .. deprecated:: 4.1.1 Use :meth:`infinity_polling` instead. + .. note:: + + Install watchdog and psutil before using restart_on_change option. + :param interval: Delay between two update retrivals :type interval: :obj:`int` diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 9e99f93..4279fbd 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -82,6 +82,10 @@ class AsyncTeleBot: See more examples in examples/ directory: 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 :type token: :obj:`str` @@ -248,6 +252,10 @@ class AsyncTeleBot: Set non_stop=True if you want your bot to continue receiving updates 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. :type non_stop: :obj:`bool` @@ -276,7 +284,7 @@ class AsyncTeleBot: :param none_stop: Deprecated, use non_stop. Old typo, kept for backward compatibility. :type none_stop: :obj:`bool` - :param restart_on_change: Restart a file on file(s) change. Defaults to False + :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 @@ -302,6 +310,9 @@ class AsyncTeleBot: """ 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) :type timeout: :obj:`int` From 27e0197855f2b7ddff48d38b4c0949df20f971af Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 1 Oct 2022 21:28:53 +0400 Subject: [PATCH 09/11] Added examples and made it possible to specify --path path for path --- .../asynchronous_telebot/detect_changes.py | 28 +++++++++++++++++++ examples/detect_changes.py | 28 +++++++++++++++++++ telebot/__init__.py | 4 ++- telebot/async_telebot.py | 3 +- 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 examples/asynchronous_telebot/detect_changes.py create mode 100644 examples/detect_changes.py diff --git a/examples/asynchronous_telebot/detect_changes.py b/examples/asynchronous_telebot/detect_changes.py new file mode 100644 index 0000000..0a0e142 --- /dev/null +++ b/examples/asynchronous_telebot/detect_changes.py @@ -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)) diff --git a/examples/detect_changes.py b/examples/detect_changes.py new file mode 100644 index 0000000..da2a2c8 --- /dev/null +++ b/examples/detect_changes.py @@ -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 = '' + +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) diff --git a/telebot/__init__.py b/telebot/__init__.py index 98f2aca..9d4c021 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -896,7 +896,9 @@ class TeleBot: self.event_handler = EventHandler() path = path_to_watch if path_to_watch else None if path is None: - path = sys.argv[1] if len(sys.argv) > 1 else '.' # current directory + # 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.observer = Observer() self.observer.schedule(self.event_handler, path, recursive=True) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 4279fbd..148bb40 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -230,7 +230,8 @@ class AsyncTeleBot: self.event_handler = EventHandler() path = path_to_watch if path_to_watch else None if path is None: - path = sys.argv[1] if len(sys.argv) > 1 else '.' # current directory + # 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.observer = Observer() self.observer.schedule(self.event_handler, path, recursive=True) From b523cec22f0367c1e8abb2c86cba6a50d7f088cd Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 1 Oct 2022 22:32:41 +0400 Subject: [PATCH 10/11] Improved code readability --- telebot/__init__.py | 3 +-- telebot/async_telebot.py | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 9d4c021..1b78cee 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -949,12 +949,11 @@ class TeleBot: if restart_on_change: self._setup_change_detector(path_to_watch) - restart_on_change = False while not self.__stop_polling.is_set(): try: self.polling(non_stop=True, timeout=timeout, long_polling_timeout=long_polling_timeout, - logger_level=logger_level, allowed_updates=allowed_updates, restart_on_change=restart_on_change, + logger_level=logger_level, allowed_updates=allowed_updates, restart_on_change=False, *args, **kwargs) except Exception as e: if logger_level and logger_level >= logging.ERROR: diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 148bb40..a2efc41 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -350,8 +350,6 @@ class AsyncTeleBot: self._polling = True if restart_on_change: - restart_on_change = False - self._setup_change_detector(path_to_watch) while self._polling: From 2d1f39085d4f5ff800595c65b75571eb121dfc13 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 1 Oct 2022 22:34:49 +0400 Subject: [PATCH 11/11] Improved code readability x 2 --- telebot/__init__.py | 6 +++--- telebot/async_telebot.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 1b78cee..12ecf73 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -900,9 +900,9 @@ class TeleBot: path = sys.argv[sys.argv.index('--path') + 1] if '--path' in sys.argv else '.' - self.observer = Observer() - self.observer.schedule(self.event_handler, path, recursive=True) - self.observer.start() + 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, logger_level: Optional[int]=logging.ERROR, allowed_updates: Optional[List[str]]=None, diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index a2efc41..0aa1097 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -233,9 +233,9 @@ class AsyncTeleBot: # 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.observer = Observer() - self.observer.schedule(self.event_handler, path, recursive=True) - self.observer.start() + 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, request_timeout: Optional[int]=None, allowed_updates: Optional[List[str]]=None,