From 28662876a22e813c608acebf258db2051d9cef6d Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 21 May 2022 17:09:59 +0500 Subject: [PATCH 01/54] Add workspace exception in gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2586c71..fa4a91e 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ testMain.py #VS Code .vscode/ .DS_Store +*.code-workspace # documentation _build/ From 33375ac135c41d1e1cd03df2ec84e55155f2a569 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 21 May 2022 17:10:29 +0500 Subject: [PATCH 02/54] Added ability to set default parse_mode for explanation_parse_mode in send_poll --- telebot/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telebot/__init__.py b/telebot/__init__.py index 09b3002..abadfe5 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -2510,6 +2510,8 @@ class TeleBot: 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( apihelper.send_poll( self.token, chat_id, From d954f8f5b33c71d184c25670ccc4e5b385933d76 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 21 May 2022 17:10:45 +0500 Subject: [PATCH 03/54] Fixed default parse mode in asynctelebot --- telebot/async_telebot.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 35c2da8..e2df525 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -1674,6 +1674,8 @@ class AsyncTeleBot: :param protect_content: :return: API reply. """ + parse_mode = self.parse_mode if (parse_mode is None) else parse_mode + return types.MessageID.de_json( await asyncio_helper.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, @@ -3112,6 +3114,8 @@ class AsyncTeleBot: 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, From d6e93f85f1a29ba27e395becf7653b9ea5168dfb Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 21 May 2022 17:10:57 +0500 Subject: [PATCH 04/54] Improved the comment for quick_markup --- telebot/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telebot/util.py b/telebot/util.py index f116d9e..31522e5 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -370,7 +370,8 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.I 'switch_inline_query_current_chat': None, 'callback_game': None, 'pay': None, - 'login_url': None + 'login_url': None, + 'web_app': None } :param values: a dict containing all buttons to create in this format: {text: kwargs} {str:} From ccc09ffaf33c6af10c8ab268c5d8d4485f14ae0e Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 21 May 2022 17:38:16 +0500 Subject: [PATCH 05/54] Aiohttp client session management improvements. --- telebot/asyncio_helper.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index dde8c85..84837d9 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1,6 +1,7 @@ import asyncio # for future uses import aiohttp from telebot import types +import ssl, certifi try: import ujson as json @@ -19,21 +20,23 @@ session = None FILE_URL = None -CONNECT_TIMEOUT = 15 -READ_TIMEOUT = 30 - -LONG_POLLING_TIMEOUT = 10 # Should be positive, short polling should be used for testing purposes only (https://core.telegram.org/bots/api#getupdates) -REQUEST_TIMEOUT = 10 +REQUEST_TIMEOUT = None MAX_RETRIES = 3 REQUEST_LIMIT = 50 class SessionManager: def __init__(self) -> None: - self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=REQUEST_LIMIT)) + self.ssl_context = ssl.create_default_context(cafile=certifi.where()) + self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector( + limit=REQUEST_LIMIT, ssl=self.ssl_context + )) + async def create_session(self): - self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=REQUEST_LIMIT)) + self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector( + limit=REQUEST_LIMIT, ssl=self.ssl_context + )) return self.session async def get_session(self): @@ -61,10 +64,11 @@ async def _process_request(token, url, method='get', params=None, files=None, re current_try +=1 try: async with session.request(method=method, url=API_URL.format(token, url), data=params, timeout=timeout, proxy=proxy) as resp: + got_result = True logger.debug("Request: method={0} url={1} params={2} files={3} request_timeout={4} current_try={5}".format(method, url, params, files, request_timeout, current_try).replace(token, token.split(':')[0] + ":{TOKEN}")) + json_result = await _check_result(url, resp) if json_result: - got_result = True return json_result['result'] except (ApiTelegramException,ApiInvalidJSONException, ApiHTTPException) as e: raise e From 0c59d1187ecaaea1cc4a167623476e9d1ccd36b7 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sun, 22 May 2022 00:11:16 +0500 Subject: [PATCH 06/54] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index b5086dc..53bf95b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ pytest requests==2.20.0 wheel==0.24.0 aiohttp>=3.8.0,<3.9.0 +certifi From 8da749ee051046717adf8c46efeac80531784272 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sun, 22 May 2022 01:02:55 +0500 Subject: [PATCH 07/54] Remove ssl --- requirements.txt | 3 +-- telebot/asyncio_helper.py | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 53bf95b..d2b8256 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ pytest requests==2.20.0 wheel==0.24.0 -aiohttp>=3.8.0,<3.9.0 -certifi +aiohttp>=3.8.0,<3.9.0 \ No newline at end of file diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 84837d9..63c1a53 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1,7 +1,6 @@ import asyncio # for future uses import aiohttp from telebot import types -import ssl, certifi try: import ujson as json @@ -27,15 +26,14 @@ REQUEST_LIMIT = 50 class SessionManager: def __init__(self) -> None: - self.ssl_context = ssl.create_default_context(cafile=certifi.where()) self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector( - limit=REQUEST_LIMIT, ssl=self.ssl_context + limit=REQUEST_LIMIT )) async def create_session(self): self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector( - limit=REQUEST_LIMIT, ssl=self.ssl_context + limit=REQUEST_LIMIT )) return self.session From 6bb47e9a449a0058ffd9c8bd1605116ec1ff5472 Mon Sep 17 00:00:00 2001 From: Advik Singh Somvanshi Date: Sun, 22 May 2022 01:38:32 +0530 Subject: [PATCH 08/54] Update create_invite_link.py Added .types while importing inline markup keyboards (fix) Removed threading import since message is not to be deleted --- examples/create_invite_link.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/create_invite_link.py b/examples/create_invite_link.py index 71c6ed4..9413549 100644 --- a/examples/create_invite_link.py +++ b/examples/create_invite_link.py @@ -1,7 +1,7 @@ -import telebot, threading +import telebot from time import sleep, time -from telebot import InlineKeyboardMarkup as ikm #Only for creating Inline Buttons, not necessary for creating Invite Links -from telebot import InlineKeyboardButton as ikb #Only for creating Inline Buttons, not necessary for creating Invite Links +from telebot.types import InlineKeyboardMarkup as ikm #Only for creating Inline Buttons, not necessary for creating Invite Links +from telebot.types import InlineKeyboardButton as ikb #Only for creating Inline Buttons, not necessary for creating Invite Links Token = "api_token" #Your Bot Access Token Group_ID = -1234567890 #Group ID for which invite link is to be created From 7edaa51995604fb11d3b6cf298c6b5510a98d178 Mon Sep 17 00:00:00 2001 From: Advik Singh Somvanshi Date: Sun, 22 May 2022 01:43:24 +0530 Subject: [PATCH 09/54] Update create_invite_link.py Removed while loop --- examples/create_invite_link.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/create_invite_link.py b/examples/create_invite_link.py index 9413549..e7fc2ed 100644 --- a/examples/create_invite_link.py +++ b/examples/create_invite_link.py @@ -29,8 +29,4 @@ def newmember(msg): -while True: - try: - bot.infinity_polling() - except: - sleep(0.04) +bot.infinity_polling() From d6ec104829d30c611ae42c12c6efda5cea7c76c2 Mon Sep 17 00:00:00 2001 From: Advik Singh Somvanshi Date: Sun, 22 May 2022 01:48:48 +0530 Subject: [PATCH 10/54] Update create_invite_link.py Imported both inline keyboards in same line:| --- examples/create_invite_link.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/create_invite_link.py b/examples/create_invite_link.py index e7fc2ed..6259b92 100644 --- a/examples/create_invite_link.py +++ b/examples/create_invite_link.py @@ -1,7 +1,6 @@ import telebot from time import sleep, time -from telebot.types import InlineKeyboardMarkup as ikm #Only for creating Inline Buttons, not necessary for creating Invite Links -from telebot.types import InlineKeyboardButton as ikb #Only for creating Inline Buttons, not necessary for creating Invite Links +from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton #Only for creating Inline Buttons, not necessary for creating Invite Links Token = "api_token" #Your Bot Access Token Group_ID = -1234567890 #Group ID for which invite link is to be created @@ -19,8 +18,8 @@ def newmember(msg): #Create an invite link class that contains info about the created invite link using create_chat_invite_link() with parameters invite = bot.create_chat_invite_link(Group_ID, member_limit=1, expire_date=int(time())+45) #Here, the link will auto-expire in 45 seconds InviteLink = invite.invite_link #Get the actual invite link from 'invite' class - mrkplink = ikm() #Created Inline Markup Keyboard - mrkplink.add(ikb("Join our group 🚀", url=InviteLink)) #Added Invite Link to Inline Markup Keyboard + mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup + mrkplink.add(InlineKeyboardButton("Join our group 🚀", url=InviteLink)) #Added Invite Link to Inline Keyboard bot.send_message(msg.chat.id, f"Hey there {msg.from_user.first_name}, Click the link below to join our Official Group." reply_markup=mrkplink) #This will send a message with the newly-created invite link as markup button. From 74d0604c053329d77c1a795f67557c8ac6ad7f80 Mon Sep 17 00:00:00 2001 From: Advik Singh Somvanshi Date: Sun, 22 May 2022 01:54:02 +0530 Subject: [PATCH 11/54] Update create_invite_link.py Bug fix (Real FINAL FIX!!) --- examples/create_invite_link.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/create_invite_link.py b/examples/create_invite_link.py index 6259b92..ffbc8b9 100644 --- a/examples/create_invite_link.py +++ b/examples/create_invite_link.py @@ -20,7 +20,7 @@ def newmember(msg): InviteLink = invite.invite_link #Get the actual invite link from 'invite' class mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup mrkplink.add(InlineKeyboardButton("Join our group 🚀", url=InviteLink)) #Added Invite Link to Inline Keyboard - bot.send_message(msg.chat.id, f"Hey there {msg.from_user.first_name}, Click the link below to join our Official Group." reply_markup=mrkplink) + bot.send_message(msg.chat.id, f"Hey there {msg.from_user.first_name}, Click the link below to join our Official Group.", reply_markup=mrkplink) #This will send a message with the newly-created invite link as markup button. #The member limit will be 1 and expiring time will be 45 sec. From 1d0efce76ec8695498f788348bd21f34f232d9d3 Mon Sep 17 00:00:00 2001 From: Advik Singh Somvanshi Date: Sun, 22 May 2022 02:17:21 +0530 Subject: [PATCH 12/54] Update create_invite_link.py Fix --- examples/create_invite_link.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/create_invite_link.py b/examples/create_invite_link.py index ffbc8b9..4679898 100644 --- a/examples/create_invite_link.py +++ b/examples/create_invite_link.py @@ -1,6 +1,7 @@ import telebot from time import sleep, time from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton #Only for creating Inline Buttons, not necessary for creating Invite Links +mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup Token = "api_token" #Your Bot Access Token Group_ID = -1234567890 #Group ID for which invite link is to be created @@ -18,8 +19,9 @@ def newmember(msg): #Create an invite link class that contains info about the created invite link using create_chat_invite_link() with parameters invite = bot.create_chat_invite_link(Group_ID, member_limit=1, expire_date=int(time())+45) #Here, the link will auto-expire in 45 seconds InviteLink = invite.invite_link #Get the actual invite link from 'invite' class - mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup + mrkplink.add(InlineKeyboardButton("Join our group 🚀", url=InviteLink)) #Added Invite Link to Inline Keyboard + bot.send_message(msg.chat.id, f"Hey there {msg.from_user.first_name}, Click the link below to join our Official Group.", reply_markup=mrkplink) #This will send a message with the newly-created invite link as markup button. From 72aaf44dc76bdab03ab626f1e51340fba008687f Mon Sep 17 00:00:00 2001 From: _run Date: Sun, 22 May 2022 01:50:38 +0500 Subject: [PATCH 13/54] Update README.md --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f0b03ba..a1a9f2d 100644 --- a/README.md +++ b/README.md @@ -358,7 +358,25 @@ def start(message): There are other examples using middleware handler in the [examples/middleware](examples/middleware) directory. #### Class-based middlewares -There are class-based middlewares. Check out in [examples](https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples/middleware/class_based) +There are class-based middlewares. +Basic class-based middleware looks like this: +```python +class Middleware(BaseMiddleware): + def __init__(self): + self.update_types = ['message'] + def pre_process(self, message, data): + data['foo'] = 'Hello' # just for example + # we edited the data. now, this data is passed to handler. + # return SkipHandler() -> this will skip handler + # return CancelUpdate() -> this will cancel update + def post_process(self, message, data, exception=None): + print(data['foo']) + if exception: # check for exception + print(exception) +``` +Class-based middleware should have to functions: post and pre process. +So, as you can see, class-based middlewares work before and after handler execution. +For more, check out in [examples](https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples/middleware/class_based) #### Custom filters Also, you can use built-in custom filters. Or, you can create your own filter. From ee7adb00dfcb9495ddbf078638b8b5391f0ade29 Mon Sep 17 00:00:00 2001 From: Advik Singh Somvanshi Date: Mon, 23 May 2022 13:27:48 +0530 Subject: [PATCH 14/54] Re-fix inlinekeyboardmarkup --- examples/create_invite_link.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/create_invite_link.py b/examples/create_invite_link.py index 4679898..eb8cebf 100644 --- a/examples/create_invite_link.py +++ b/examples/create_invite_link.py @@ -1,7 +1,6 @@ import telebot from time import sleep, time from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton #Only for creating Inline Buttons, not necessary for creating Invite Links -mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup Token = "api_token" #Your Bot Access Token Group_ID = -1234567890 #Group ID for which invite link is to be created @@ -20,6 +19,7 @@ def newmember(msg): invite = bot.create_chat_invite_link(Group_ID, member_limit=1, expire_date=int(time())+45) #Here, the link will auto-expire in 45 seconds InviteLink = invite.invite_link #Get the actual invite link from 'invite' class + mrkplink = InlineKeyboardMarkup() #Created Inline Keyboard Markup mrkplink.add(InlineKeyboardButton("Join our group 🚀", url=InviteLink)) #Added Invite Link to Inline Keyboard bot.send_message(msg.chat.id, f"Hey there {msg.from_user.first_name}, Click the link below to join our Official Group.", reply_markup=mrkplink) From 82f056e88af8233b9b413d8aec1c1c322c09d9bc Mon Sep 17 00:00:00 2001 From: Soham Datta <83786816+TECH-SAVVY-GUY@users.noreply.github.com> Date: Mon, 30 May 2022 14:52:49 +0530 Subject: [PATCH 15/54] Added `WebApp` functions `validate_WebApp_data()` - Use to validate the data received by the WebApp from Telegram. `parse_WebApp_data()` - Use to parse the data sent to the WebApp from the bot's backend. --- telebot/util.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/telebot/util.py b/telebot/util.py index 31522e5..f8e4db5 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -5,6 +5,10 @@ import string import threading import traceback from typing import Any, Callable, List, Dict, Optional, Union +import hmac +import json +from hashlib import sha256 +from urllib.parse import parse_qsl # noinspection PyPep8Naming import queue as Queue @@ -518,3 +522,36 @@ def antiflood(function, *args, **kwargs): msg = function(*args, **kwargs) finally: return msg + + +def parse_WebApp_data(token: str, raw_init_data: str): + is_valid = validate_WebApp_data(token, raw_init_data) + if not is_valid: + return False + + result = {} + for key, value in parse_qsl(raw_init_data): + try: + value = json.loads(value) + except json.JSONDecodeError: + result[key] = value + else: + result[key] = value + return result + + +def validate_WebApp_data(token, raw_init_data): + try: + parsed_data = dict(parse_qsl(raw_init_data)) + except ValueError: + return False + if "hash" not in parsed_data: + return False + + init_data_hash = parsed_data.pop('hash') + data_check_string = "\n".join(f"{key}={value}" for key, value in sorted(parsed_data.items())) + secret_key = hmac.new(key=b"WebAppData", msg=token.encode(), digestmod=sha256) + + return hmac.new(secret_key.digest(), data_check_string.encode(), sha256).hexdigest() == init_data_hash + + From 4401780ba9754653ee0075dc6638b01a641d90f3 Mon Sep 17 00:00:00 2001 From: Soham Datta <83786816+TECH-SAVVY-GUY@users.noreply.github.com> Date: Mon, 30 May 2022 17:18:03 +0530 Subject: [PATCH 16/54] Update `WebApp()` functions Adjusted function name case to pythonic style. --- telebot/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/util.py b/telebot/util.py index f8e4db5..4385228 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -524,7 +524,7 @@ def antiflood(function, *args, **kwargs): return msg -def parse_WebApp_data(token: str, raw_init_data: str): +def parse_webapp_data(token: str, raw_init_data: str): is_valid = validate_WebApp_data(token, raw_init_data) if not is_valid: return False @@ -540,7 +540,7 @@ def parse_WebApp_data(token: str, raw_init_data: str): return result -def validate_WebApp_data(token, raw_init_data): +def validate_webapp_data(token, raw_init_data): try: parsed_data = dict(parse_qsl(raw_init_data)) except ValueError: From 42ce47914d7afe56cdfb1146c8cff423fc72f3c4 Mon Sep 17 00:00:00 2001 From: Soham Datta <83786816+TECH-SAVVY-GUY@users.noreply.github.com> Date: Mon, 30 May 2022 17:21:33 +0530 Subject: [PATCH 17/54] Fix typo in `WebApp()` functions --- telebot/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/util.py b/telebot/util.py index 4385228..2561c21 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -524,7 +524,7 @@ def antiflood(function, *args, **kwargs): return msg -def parse_webapp_data(token: str, raw_init_data: str): +def parse_web_app_data(token: str, raw_init_data: str): is_valid = validate_WebApp_data(token, raw_init_data) if not is_valid: return False @@ -540,7 +540,7 @@ def parse_webapp_data(token: str, raw_init_data: str): return result -def validate_webapp_data(token, raw_init_data): +def validate_web_app_data(token, raw_init_data): try: parsed_data = dict(parse_qsl(raw_init_data)) except ValueError: From 28ae0867f834fde91c1c2d7267a195283aad4876 Mon Sep 17 00:00:00 2001 From: Tushar maharana <54012021+tusharhero@users.noreply.github.com> Date: Tue, 31 May 2022 22:58:03 +0530 Subject: [PATCH 18/54] Added my bot made using pyTelegramBotAPI source code available here https://github.com/tusharhero/bincode-telegram-bot --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a1a9f2d..713f477 100644 --- a/README.md +++ b/README.md @@ -845,6 +845,7 @@ Here are some examples of template: ## Bots using this library +* [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. * [SiteAlert bot](https://telegram.me/SiteAlert_bot) ([source](https://github.com/ilteoood/SiteAlert-Python)) by *ilteoood* - Monitors websites and sends a notification on changes * [TelegramLoggingBot](https://github.com/aRandomStranger/TelegramLoggingBot) by *aRandomStranger* * [Telegram LMGTFY_bot](https://github.com/GabrielRF/telegram-lmgtfy_bot) by *GabrielRF* - Let me Google that for you. From 7cdb48c3e075bbe57ea49b3b460c7d5e6e25871c Mon Sep 17 00:00:00 2001 From: Tushar maharana <54012021+tusharhero@users.noreply.github.com> Date: Wed, 1 Jun 2022 10:22:22 +0530 Subject: [PATCH 19/54] brought my bot ot end --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 713f477..b344feb 100644 --- a/README.md +++ b/README.md @@ -845,7 +845,6 @@ Here are some examples of template: ## Bots using this library -* [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. * [SiteAlert bot](https://telegram.me/SiteAlert_bot) ([source](https://github.com/ilteoood/SiteAlert-Python)) by *ilteoood* - Monitors websites and sends a notification on changes * [TelegramLoggingBot](https://github.com/aRandomStranger/TelegramLoggingBot) by *aRandomStranger* * [Telegram LMGTFY_bot](https://github.com/GabrielRF/telegram-lmgtfy_bot) by *GabrielRF* - Let me Google that for you. @@ -897,5 +896,5 @@ Here are some examples of template: * [Pyfram-telegram-bot](https://github.com/skelly37/pyfram-telegram-bot) Query wolframalpha.com and make use of its API through Telegram. * [TranslateThisVideoBot](https://gitlab.com/WuerfelDev/translatethisvideo) This Bot can understand spoken text in videos and translate it to English * [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX. - +* [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** From 5a60846c7fd544c42312cea1013c8fac4b416ad8 Mon Sep 17 00:00:00 2001 From: Andrey M Date: Wed, 1 Jun 2022 19:07:54 +0300 Subject: [PATCH 20/54] add hydrolib_bot to Bots using this library --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b344feb..ef79d1e 100644 --- a/README.md +++ b/README.md @@ -897,4 +897,6 @@ Here are some examples of template: * [TranslateThisVideoBot](https://gitlab.com/WuerfelDev/translatethisvideo) This Bot can understand spoken text in videos and translate it to English * [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX. * [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. +* [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...). + **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** From e689e968dbd240b08ca88f8a487a33c25ce2e452 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Sat, 4 Jun 2022 21:33:05 +0500 Subject: [PATCH 21/54] Fix bug with unsaving data --- telebot/asyncio_storage/pickle_storage.py | 2 ++ telebot/storage/pickle_storage.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/telebot/asyncio_storage/pickle_storage.py b/telebot/asyncio_storage/pickle_storage.py index 4928d4a..49fe3be 100644 --- a/telebot/asyncio_storage/pickle_storage.py +++ b/telebot/asyncio_storage/pickle_storage.py @@ -51,9 +51,11 @@ class StatePickleStorage(StateStorageBase): if chat_id in self.data: if user_id in self.data[chat_id]: self.data[chat_id][user_id]['state'] = state + self.update_data() return True else: self.data[chat_id][user_id] = {'state': state, 'data': {}} + self.update_data() return True self.data[chat_id] = {user_id: {'state': state, 'data': {}}} self.update_data() diff --git a/telebot/storage/pickle_storage.py b/telebot/storage/pickle_storage.py index 39b10a3..ff72ac3 100644 --- a/telebot/storage/pickle_storage.py +++ b/telebot/storage/pickle_storage.py @@ -57,9 +57,11 @@ class StatePickleStorage(StateStorageBase): if chat_id in self.data: if user_id in self.data[chat_id]: self.data[chat_id][user_id]['state'] = state + self.update_data() return True else: self.data[chat_id][user_id] = {'state': state, 'data': {}} + self.update_data() return True self.data[chat_id] = {user_id: {'state': state, 'data': {}}} self.update_data() From b2662274f93d09326cc1502d9c109a0cb665ae7d Mon Sep 17 00:00:00 2001 From: e323w <88164836+e323w@users.noreply.github.com> Date: Wed, 15 Jun 2022 03:24:51 +0400 Subject: [PATCH 22/54] Fixed async long polling --- telebot/asyncio_helper.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 63c1a53..a7bcccf 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -217,11 +217,11 @@ async def get_updates(token, offset=None, limit=None, params = {} if offset: params['offset'] = offset - elif limit: + if limit: params['limit'] = limit - elif timeout: + if timeout: params['timeout'] = timeout - elif allowed_updates: + if allowed_updates: params['allowed_updates'] = allowed_updates return await _process_request(token, method_name, params=params, request_timeout=request_timeout) From 24cdcb1bcc6c576b428180f1f463fdcffc69bb97 Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 21 Jun 2022 14:22:57 +0500 Subject: [PATCH 23/54] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ef79d1e..027139d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

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

Both synchronous and asynchronous.

-##

Supported Bot API version: 6.0! +##

Supported Bot API version: 6.1!

Official documentation

@@ -727,6 +727,7 @@ Result will be: ## API conformance +* ✔ [Bot API 6.1](https://core.telegram.org/bots/api#june-20-2022) * ✔ [Bot API 6.0](https://core.telegram.org/bots/api#april-16-2022) * ✔ [Bot API 5.7](https://core.telegram.org/bots/api#january-31-2022) * ✔ [Bot API 5.6](https://core.telegram.org/bots/api#december-30-2021) From 0d0f9ef33015c8d6ced5ed218777b678dab3e979 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 21 Jun 2022 15:20:55 +0500 Subject: [PATCH 24/54] Added secret token and create_invoice_link --- telebot/__init__.py | 68 ++++++++++++++++++++++++++++++++++++++++++-- telebot/apihelper.py | 43 +++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index abadfe5..85454c5 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -261,7 +261,7 @@ class TeleBot: self.reply_backend.load_handlers(filename, del_file_after_loading) def set_webhook(self, url=None, certificate=None, max_connections=None, allowed_updates=None, ip_address=None, - drop_pending_updates = None, timeout=None): + drop_pending_updates = None, timeout=None, secret_token=None): """ Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, @@ -286,10 +286,11 @@ class TeleBot: resolved through DNS :param drop_pending_updates: Pass True to drop all pending updates :param timeout: Integer. Request connection timeout + :param secret_token: Secret token to be used to verify the webhook request. :return: API reply. """ return apihelper.set_webhook(self.token, url, certificate, max_connections, allowed_updates, ip_address, - drop_pending_updates, timeout) + drop_pending_updates, timeout, secret_token) def delete_webhook(self, drop_pending_updates=None, timeout=None): """ @@ -2462,6 +2463,69 @@ class TeleBot: max_tip_amount, suggested_tip_amounts, protect_content) return types.Message.de_json(result) + + def create_invoice_link(self, + title: str, description: str, payload:str, provider_token: str, + currency: str, prices: List[types.LabeledPrice], + max_tip_amount: Optional[int] = None, + suggested_tip_amounts: Optional[List[int]]=None, + provider_data: Optional[str]=None, + photo_url: Optional[str]=None, + photo_size: Optional[int]=None, + photo_width: Optional[int]=None, + photo_height: Optional[int]=None, + need_name: Optional[bool]=None, + need_phone_number: Optional[bool]=None, + need_email: Optional[bool]=None, + need_shipping_address: Optional[bool]=None, + send_phone_number_to_provider: Optional[bool]=None, + send_email_to_provider: Optional[bool]=None, + is_flexible: Optional[bool]=None) -> str: + + """ + Use this method to create a link for an invoice. + Returns the created invoice link as String on success. + + Telegram documentation: + https://core.telegram.org/bots/api#createinvoicelink + + :param title: Product name, 1-32 characters + :param description: Product description, 1-255 characters + :param payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, + use for your internal processes. + :param provider_token: Payments provider token, obtained via @Botfather + :param currency: Three-letter ISO 4217 currency code, + see https://core.telegram.org/bots/payments#supported-currencies + :param prices: Price breakdown, a list of components + (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.) + :param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency + :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest + :param provider_data: A JSON-serialized data about the invoice, which will be shared with the payment provider. + A detailed description of required fields should be provided by the payment provider. + :param photo_url: URL of the product photo for the invoice. Can be a photo of the goods + :param photo_size: Photo size in bytes + :param photo_width: Photo width + :param photo_height: Photo height + :param need_name: Pass True, if you require the user's full name to complete the order + :param need_phone_number: Pass True, if you require the user's phone number to complete the order + :param need_email: Pass True, if you require the user's email to complete the order + :param need_shipping_address: Pass True, if you require the user's shipping address to complete the order + :param send_phone_number_to_provider: Pass True, if user's phone number should be sent to provider + :param send_email_to_provider: Pass True, if user's email address should be sent to provider + :param is_flexible: Pass True, if the final price depends on the shipping method + + :return: Created invoice link as String on success. + """ + result = apihelper.create_invoice_link( + self.token, title, description, payload, provider_token, + currency, prices, max_tip_amount, suggested_tip_amounts, provider_data, + photo_url, photo_size, photo_width, photo_height, need_name, need_phone_number, + need_email, need_shipping_address, send_phone_number_to_provider, + send_email_to_provider, is_flexible) + return result + + + # noinspection PyShadowingBuiltins # TODO: rewrite this method like in API def send_poll( diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 8d4b2f7..ff8c8e2 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -268,7 +268,7 @@ def send_message( def set_webhook(token, url=None, certificate=None, max_connections=None, allowed_updates=None, ip_address=None, - drop_pending_updates = None, timeout=None): + drop_pending_updates = None, timeout=None, secret_token=None): method_url = r'setWebhook' payload = { 'url': url if url else "", @@ -286,6 +286,8 @@ def set_webhook(token, url=None, certificate=None, max_connections=None, allowed payload['drop_pending_updates'] = drop_pending_updates if timeout: payload['timeout'] = timeout + if secret_token: + payload['secret_token'] = secret_token return _make_request(token, method_url, params=payload, files=files) @@ -1622,6 +1624,45 @@ def answer_web_app_query(token, web_app_query_id, result: types.InlineQueryResul return _make_request(token, method_url, params=payload, method='post') +def create_invoice_link(token, title, description, payload, provider_token, + currency, prices, max_tip_amount=None, suggested_tip_amounts=None, provider_data=None, + photo_url=None, photo_size=None, photo_width=None, photo_height=None, need_name=None, need_phone_number=None, + need_email=None, need_shipping_address=None, send_phone_number_to_provider=None, + send_email_to_provider=None, is_flexible=None): + method_url = r'createInvoiceLink' + payload = {'title': title, 'description': description, 'payload': payload, 'provider_token': provider_token, + 'currency': currency, 'prices': _convert_list_json_serializable(prices)} + if max_tip_amount: + payload['max_tip_amount'] = max_tip_amount + if suggested_tip_amounts: + payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts) + if provider_data: + payload['provider_data'] = provider_data + if photo_url: + payload['photo_url'] = photo_url + if photo_size: + payload['photo_size'] = photo_size + if photo_width: + payload['photo_width'] = photo_width + if photo_height: + payload['photo_height'] = photo_height + if need_name: + payload['need_name'] = need_name + if need_phone_number: + payload['need_phone_number'] = need_phone_number + if need_email: + payload['need_email'] = need_email + if need_shipping_address: + payload['need_shipping_address'] = need_shipping_address + if send_phone_number_to_provider: + payload['send_phone_number_to_provider'] = send_phone_number_to_provider + if send_email_to_provider: + payload['send_email_to_provider'] = send_email_to_provider + if is_flexible: + payload['is_flexible'] = is_flexible + return _make_request(token, method_url, params=payload, method='post') + + # noinspection PyShadowingBuiltins def send_poll( token, chat_id, From f52124827fa813936c89c36543aedc37c01cf1ed Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 21 Jun 2022 15:21:35 +0500 Subject: [PATCH 25/54] Added all new changes for types (is_premium, added_to_attachment_menu, and etc) --- telebot/types.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index ff08fc6..4b252b9 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -215,7 +215,8 @@ class User(JsonDeserializable, Dictionaryable, JsonSerializable): return cls(**obj) def __init__(self, id, is_bot, first_name, last_name=None, username=None, language_code=None, - can_join_groups=None, can_read_all_group_messages=None, supports_inline_queries=None, **kwargs): + can_join_groups=None, can_read_all_group_messages=None, supports_inline_queries=None, + is_premium=None, added_to_attachment_menu=None, **kwargs): self.id: int = id self.is_bot: bool = is_bot self.first_name: str = first_name @@ -225,6 +226,9 @@ class User(JsonDeserializable, Dictionaryable, JsonSerializable): self.can_join_groups: bool = can_join_groups self.can_read_all_group_messages: bool = can_read_all_group_messages self.supports_inline_queries: bool = supports_inline_queries + self.is_premium: bool = is_premium + self.added_to_attachment_menu: bool = added_to_attachment_menu + @property def full_name(self): @@ -280,7 +284,8 @@ class Chat(JsonDeserializable): description=None, invite_link=None, pinned_message=None, permissions=None, slow_mode_delay=None, message_auto_delete_time=None, has_protected_content=None, sticker_set_name=None, - can_set_sticker_set=None, linked_chat_id=None, location=None, **kwargs): + can_set_sticker_set=None, linked_chat_id=None, location=None, + join_to_send_messages=None, join_by_request=None, **kwargs): self.id: int = id self.type: str = type self.title: str = title @@ -289,6 +294,8 @@ class Chat(JsonDeserializable): self.last_name: str = last_name self.photo: ChatPhoto = photo self.bio: str = bio + self.join_to_send_messages: bool = join_to_send_messages + self.join_by_request: bool = join_by_request self.has_private_forwards: bool = has_private_forwards self.description: str = description self.invite_link: str = invite_link @@ -2576,10 +2583,13 @@ class Sticker(JsonDeserializable): obj['thumb'] = None if 'mask_position' in obj: obj['mask_position'] = MaskPosition.de_json(obj['mask_position']) + if 'premium_animation': + obj['premium_animation'] = File.de_json(obj['premium_animation']) return cls(**obj) def __init__(self, file_id, file_unique_id, width, height, is_animated, - is_video, thumb=None, emoji=None, set_name=None, mask_position=None, file_size=None, **kwargs): + is_video, thumb=None, emoji=None, set_name=None, mask_position=None, file_size=None, + premium_animation=None, **kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id self.width: int = width @@ -2591,6 +2601,7 @@ class Sticker(JsonDeserializable): self.set_name: str = set_name self.mask_position: MaskPosition = mask_position self.file_size: int = file_size + self.premium_animation: File = premium_animation From 7d931abe376195f7fd8b8e859d213dacbd942125 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 21 Jun 2022 15:22:00 +0500 Subject: [PATCH 26/54] Added secret token and create_invoice_link for asynctelebot --- telebot/async_telebot.py | 66 +++++++++++++++++++++++++++++++++++++-- telebot/asyncio_helper.py | 45 +++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index e2df525..1566657 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -1384,7 +1384,7 @@ class AsyncTeleBot: self.current_states = StatePickleStorage(file_path=filename) async def set_webhook(self, url=None, certificate=None, max_connections=None, allowed_updates=None, ip_address=None, - drop_pending_updates = None, timeout=None): + drop_pending_updates = None, timeout=None, secret_token=None): """ Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, @@ -1409,10 +1409,11 @@ class AsyncTeleBot: resolved through DNS :param drop_pending_updates: Pass True to drop all pending updates :param timeout: Integer. Request connection timeout + :param secret_token: Secret token to be used to verify the webhook :return: """ return await asyncio_helper.set_webhook(self.token, url, certificate, max_connections, allowed_updates, ip_address, - drop_pending_updates, timeout) + drop_pending_updates, timeout, secret_token) @@ -3066,6 +3067,67 @@ class AsyncTeleBot: max_tip_amount, suggested_tip_amounts, protect_content) return types.Message.de_json(result) + + async def create_invoice_link(self, + title: str, description: str, payload:str, provider_token: str, + currency: str, prices: List[types.LabeledPrice], + max_tip_amount: Optional[int] = None, + suggested_tip_amounts: Optional[List[int]]=None, + provider_data: Optional[str]=None, + photo_url: Optional[str]=None, + photo_size: Optional[int]=None, + photo_width: Optional[int]=None, + photo_height: Optional[int]=None, + need_name: Optional[bool]=None, + need_phone_number: Optional[bool]=None, + need_email: Optional[bool]=None, + need_shipping_address: Optional[bool]=None, + send_phone_number_to_provider: Optional[bool]=None, + send_email_to_provider: Optional[bool]=None, + is_flexible: Optional[bool]=None) -> str: + + """ + Use this method to create a link for an invoice. + Returns the created invoice link as String on success. + + Telegram documentation: + https://core.telegram.org/bots/api#createinvoicelink + + :param title: Product name, 1-32 characters + :param description: Product description, 1-255 characters + :param payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, + use for your internal processes. + :param provider_token: Payments provider token, obtained via @Botfather + :param currency: Three-letter ISO 4217 currency code, + see https://core.telegram.org/bots/payments#supported-currencies + :param prices: Price breakdown, a list of components + (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.) + :param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency + :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest + :param provider_data: A JSON-serialized data about the invoice, which will be shared with the payment provider. + A detailed description of required fields should be provided by the payment provider. + :param photo_url: URL of the product photo for the invoice. Can be a photo of the goods + :param photo_size: Photo size in bytes + :param photo_width: Photo width + :param photo_height: Photo height + :param need_name: Pass True, if you require the user's full name to complete the order + :param need_phone_number: Pass True, if you require the user's phone number to complete the order + :param need_email: Pass True, if you require the user's email to complete the order + :param need_shipping_address: Pass True, if you require the user's shipping address to complete the order + :param send_phone_number_to_provider: Pass True, if user's phone number should be sent to provider + :param send_email_to_provider: Pass True, if user's email address should be sent to provider + :param is_flexible: Pass True, if the final price depends on the shipping method + + :return: Created invoice link as String on success. + """ + result = await asyncio_helper.create_invoice_link( + self.token, title, description, payload, provider_token, + currency, prices, max_tip_amount, suggested_tip_amounts, provider_data, + photo_url, photo_size, photo_width, photo_height, need_name, need_phone_number, + need_email, need_shipping_address, send_phone_number_to_provider, + send_email_to_provider, is_flexible) + return result + # noinspection PyShadowingBuiltins async def send_poll( self, chat_id: Union[int, str], question: str, options: List[str], diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index a7bcccf..51b60e9 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -171,7 +171,7 @@ async def download_file(token, file_path): async def set_webhook(token, url=None, certificate=None, max_connections=None, allowed_updates=None, ip_address=None, - drop_pending_updates = None, timeout=None): + drop_pending_updates = None, timeout=None, secret_token=None): method_url = r'setWebhook' payload = { 'url': url if url else "", @@ -189,6 +189,8 @@ async def set_webhook(token, url=None, certificate=None, max_connections=None, a payload['drop_pending_updates'] = drop_pending_updates if timeout: payload['timeout'] = timeout + if secret_token: + payload['secret_token'] = secret_token return await _process_request(token, method_url, params=payload, files=files) @@ -1599,6 +1601,47 @@ async def delete_sticker_from_set(token, sticker): return await _process_request(token, method_url, params=payload, method='post') + +async def create_invoice_link(token, title, description, payload, provider_token, + currency, prices, max_tip_amount=None, suggested_tip_amounts=None, provider_data=None, + photo_url=None, photo_size=None, photo_width=None, photo_height=None, need_name=None, need_phone_number=None, + need_email=None, need_shipping_address=None, send_phone_number_to_provider=None, + send_email_to_provider=None, is_flexible=None): + method_url = r'createInvoiceLink' + payload = {'title': title, 'description': description, 'payload': payload, 'provider_token': provider_token, + 'currency': currency, 'prices': await _convert_list_json_serializable(prices)} + if max_tip_amount: + payload['max_tip_amount'] = max_tip_amount + if suggested_tip_amounts: + payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts) + if provider_data: + payload['provider_data'] = provider_data + if photo_url: + payload['photo_url'] = photo_url + if photo_size: + payload['photo_size'] = photo_size + if photo_width: + payload['photo_width'] = photo_width + if photo_height: + payload['photo_height'] = photo_height + if need_name: + payload['need_name'] = need_name + if need_phone_number: + payload['need_phone_number'] = need_phone_number + if need_email: + payload['need_email'] = need_email + if need_shipping_address: + payload['need_shipping_address'] = need_shipping_address + if send_phone_number_to_provider: + payload['send_phone_number_to_provider'] = send_phone_number_to_provider + if send_email_to_provider: + payload['send_email_to_provider'] = send_email_to_provider + if is_flexible: + payload['is_flexible'] = is_flexible + return await _process_request(token, method_url, params=payload, method='post') + + + # noinspection PyShadowingBuiltins async def send_poll( token, chat_id, From d7f34ae37052e2ae61adef97e4f8a9d800ac6c76 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 21 Jun 2022 15:27:45 +0500 Subject: [PATCH 27/54] Fix the typo --- telebot/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 4b252b9..ee67cb9 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -2583,7 +2583,7 @@ class Sticker(JsonDeserializable): obj['thumb'] = None if 'mask_position' in obj: obj['mask_position'] = MaskPosition.de_json(obj['mask_position']) - if 'premium_animation': + if 'premium_animation' in obj: obj['premium_animation'] = File.de_json(obj['premium_animation']) return cls(**obj) From a7fb8a2becd5a5c5de8c49e16a0664579598ac46 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 21 Jun 2022 15:28:01 +0500 Subject: [PATCH 28/54] Implemented some tests --- tests/test_types.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/test_types.py b/tests/test_types.py index dedee19..29a5075 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -6,10 +6,13 @@ from telebot import types def test_json_user(): - jsonstring = r'{"id":101176298,"first_name":"RDSSBOT","last_name":")))","username":"rdss_bot","is_bot":true}' + jsonstring = r'{"id":101176298,"first_name":"RDSSBOT","last_name":")))","username":"rdss_bot","is_bot":true, "is_premium":true, "added_to_attachment_menu": true}' u = types.User.de_json(jsonstring) assert u.id == 101176298 assert u.full_name == 'RDSSBOT )))' + assert u.is_premium is True + assert u.added_to_attachment_menu is True + def test_json_message(): @@ -155,12 +158,14 @@ def test_json_update(): def test_json_chat(): - json_string = r'{"id": -111111,"title": "Test Title","type": "group"}' + json_string = r'{"id": -111111,"title": "Test Title","type": "group", "join_to_send_messages": true, "join_by_request": true}' chat = types.Chat.de_json(json_string) assert chat.id == -111111 assert chat.type == 'group' assert chat.title == 'Test Title' - + assert chat.join_to_send_messages is True + assert chat.join_by_request is True + def test_InlineQueryResultCachedPhoto(): iq = types.InlineQueryResultCachedPhoto('aaa', 'Fileid') From 87698027447bdb09db3b0ffc99f48e2d4f0cfc37 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Tue, 21 Jun 2022 15:44:42 +0500 Subject: [PATCH 29/54] Bump version to 4.6.0 --- docs/source/conf.py | 2 +- telebot/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8344e6d..20ef458 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,7 @@ copyright = '2022, coder2020official' author = 'coder2020official' # The full version, including alpha/beta/rc tags -release = '4.5.1' +release = '4.6.0' # -- General configuration --------------------------------------------------- diff --git a/telebot/version.py b/telebot/version.py index 6293a17..ff913fb 100644 --- a/telebot/version.py +++ b/telebot/version.py @@ -1,3 +1,3 @@ # Versions should comply with PEP440. # This line is parsed in setup.py: -__version__ = '4.5.1' +__version__ = '4.6.0' From dd8125cbd0f92963fc80ecfc1db395ad93cad79a Mon Sep 17 00:00:00 2001 From: Alex Poklonsky Date: Thu, 23 Jun 2022 09:09:37 +0300 Subject: [PATCH 30/54] Rename `midddleware` to `middleware` in examples. --- .../middleware/i18n_middleware_example/main.py | 2 +- .../{i18n_base_midddleware.py => i18n_base_middleware.py} | 0 examples/middleware/class_based/i18n_middleware/main.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename examples/middleware/class_based/i18n_middleware/{i18n_base_midddleware.py => i18n_base_middleware.py} (100%) diff --git a/examples/asynchronous_telebot/middleware/i18n_middleware_example/main.py b/examples/asynchronous_telebot/middleware/i18n_middleware_example/main.py index 1faeaad..675c140 100644 --- a/examples/asynchronous_telebot/middleware/i18n_middleware_example/main.py +++ b/examples/asynchronous_telebot/middleware/i18n_middleware_example/main.py @@ -56,7 +56,7 @@ import keyboards from telebot import types from telebot.async_telebot import AsyncTeleBot from telebot.asyncio_filters import TextMatchFilter, TextFilter -from i18n_base_midddleware import I18N +from i18n_base_middleware import I18N from telebot.asyncio_storage.memory_storage import StateMemoryStorage diff --git a/examples/middleware/class_based/i18n_middleware/i18n_base_midddleware.py b/examples/middleware/class_based/i18n_middleware/i18n_base_middleware.py similarity index 100% rename from examples/middleware/class_based/i18n_middleware/i18n_base_midddleware.py rename to examples/middleware/class_based/i18n_middleware/i18n_base_middleware.py diff --git a/examples/middleware/class_based/i18n_middleware/main.py b/examples/middleware/class_based/i18n_middleware/main.py index 66ae420..161f1a5 100644 --- a/examples/middleware/class_based/i18n_middleware/main.py +++ b/examples/middleware/class_based/i18n_middleware/main.py @@ -53,7 +53,7 @@ import asyncio from typing import Union import keyboards -from i18n_base_midddleware import I18N +from i18n_base_middleware import I18N from telebot import TeleBot from telebot import types, StateMemoryStorage from telebot.custom_filters import TextMatchFilter, TextFilter From 1342cab25933ff7904b918003bb503f73003e60b Mon Sep 17 00:00:00 2001 From: coder2020official Date: Thu, 23 Jun 2022 12:05:26 +0500 Subject: [PATCH 31/54] Fix boolean parameters --- telebot/apihelper.py | 2 +- telebot/asyncio_helper.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index ff8c8e2..fc76a00 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1658,7 +1658,7 @@ def create_invoice_link(token, title, description, payload, provider_token, payload['send_phone_number_to_provider'] = send_phone_number_to_provider if send_email_to_provider: payload['send_email_to_provider'] = send_email_to_provider - if is_flexible: + if is_flexible is not None: payload['is_flexible'] = is_flexible return _make_request(token, method_url, params=payload, method='post') diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 51b60e9..1c01893 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1636,7 +1636,7 @@ async def create_invoice_link(token, title, description, payload, provider_token payload['send_phone_number_to_provider'] = send_phone_number_to_provider if send_email_to_provider: payload['send_email_to_provider'] = send_email_to_provider - if is_flexible: + if is_flexible is not None: payload['is_flexible'] = is_flexible return await _process_request(token, method_url, params=payload, method='post') From 7f9dac414796c99493bd09c5ff6ff553f64f2982 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Thu, 23 Jun 2022 12:46:27 +0500 Subject: [PATCH 32/54] Fix previous commit --- telebot/apihelper.py | 12 ++++++------ telebot/asyncio_helper.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index fc76a00..07f2f57 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1646,17 +1646,17 @@ def create_invoice_link(token, title, description, payload, provider_token, payload['photo_width'] = photo_width if photo_height: payload['photo_height'] = photo_height - if need_name: + if need_name is not None: payload['need_name'] = need_name - if need_phone_number: + if need_phone_number is not None: payload['need_phone_number'] = need_phone_number - if need_email: + if need_email is not None: payload['need_email'] = need_email - if need_shipping_address: + if need_shipping_address is not None: payload['need_shipping_address'] = need_shipping_address - if send_phone_number_to_provider: + if send_phone_number_to_provider is not None: payload['send_phone_number_to_provider'] = send_phone_number_to_provider - if send_email_to_provider: + if send_email_to_provider is not None: payload['send_email_to_provider'] = send_email_to_provider if is_flexible is not None: payload['is_flexible'] = is_flexible diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 1c01893..168edff 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1624,17 +1624,17 @@ async def create_invoice_link(token, title, description, payload, provider_token payload['photo_width'] = photo_width if photo_height: payload['photo_height'] = photo_height - if need_name: + if need_name is not None: payload['need_name'] = need_name - if need_phone_number: + if need_phone_number is not None: payload['need_phone_number'] = need_phone_number - if need_email: + if need_email is not None: payload['need_email'] = need_email - if need_shipping_address: + if need_shipping_address is not None: payload['need_shipping_address'] = need_shipping_address - if send_phone_number_to_provider: + if send_phone_number_to_provider is not None: payload['send_phone_number_to_provider'] = send_phone_number_to_provider - if send_email_to_provider: + if send_email_to_provider is not None: payload['send_email_to_provider'] = send_email_to_provider if is_flexible is not None: payload['is_flexible'] = is_flexible From 1686ce4f445d3bf1982242c2eb887b490e1e8d98 Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 25 Jun 2022 21:48:44 +0500 Subject: [PATCH 33/54] Middleware update: everything in data will be passed to handler if needed. --- telebot/__init__.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 85454c5..278721e 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -3998,6 +3998,7 @@ class TeleBot: return elif isinstance(result, SkipHandler) and skip_handler is False: skip_handler = True + try: if handlers and not skip_handler: @@ -4009,24 +4010,23 @@ class TeleBot: params.append(i) if len(params) == 1: handler['function'](message) - - elif len(params) == 2: - if handler.get('pass_bot') is True: - handler['function'](message, self) - - elif handler.get('pass_bot') is False: - handler['function'](message, data) - - elif len(params) == 3: - if params[2] == 'bot' and handler.get('pass_bot') is True: - handler['function'](message, data, self) + else: + if "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 - elif not handler.get('pass_bot'): - raise RuntimeError('Your handler accepts 3 parameters but pass_bot is False. Please re-check your handler.') - else: - handler['function'](message, self, data) - + if len(data) > len(params) -2: + logger.error("You are passing more data than the handler needs. Check your handler: {}".format(handler['function'])) + return + if handler.get('pass_bot'): data["bot"] = self + handler["function"](message, **data) + except Exception as e: handler_error = e From a2893945b2c80650c0745f63f9e8b6e8e4ae81df Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 25 Jun 2022 22:15:53 +0500 Subject: [PATCH 34/54] Async changes and sync improvements --- telebot/__init__.py | 11 ++++++++--- telebot/async_telebot.py | 37 ++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 278721e..23887c1 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -9,6 +9,7 @@ import time import traceback from typing import Any, Callable, List, Optional, Union + # these imports are used to avoid circular import error import telebot.util import telebot.types @@ -3977,7 +3978,7 @@ class TeleBot: middlewares = [i for i in self.middlewares if update_type in i.update_types] return middlewares - def _run_middlewares_and_handler(self, message, handlers, middlewares, *args, **kwargs): + def _run_middlewares_and_handler(self, message, handlers, middlewares): """ This class is made to run handler and middleware in queue. @@ -4021,10 +4022,11 @@ class TeleBot: return else: - if len(data) > len(params) -2: + if handler.get('pass_bot'): data["bot"] = self + if len(data) > len(params) - 1: # remove the message parameter logger.error("You are passing more data than the handler needs. Check your handler: {}".format(handler['function'])) return - if handler.get('pass_bot'): data["bot"] = self + handler["function"](message, **data) except Exception as e: @@ -4035,6 +4037,9 @@ class TeleBot: return self.exception_handler.handle(e) logging.error(str(e)) return + # remove the bot from data + if "bot" in data: + del data["bot"] if middlewares: for middleware in middlewares: middleware.post_process(message, data, handler_error) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 1566657..f41f5cd 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -277,7 +277,7 @@ class AsyncTeleBot: handler_error = None data = {} process_handler = True - + params = [] if middlewares: for middleware in middlewares: middleware_result = await middleware.pre_process(message, data) @@ -295,27 +295,27 @@ class AsyncTeleBot: continue elif process_update: try: - params = [] - for i in signature(handler['function']).parameters: params.append(i) if len(params) == 1: await handler['function'](message) - break - elif len(params) == 2: - if handler['pass_bot']: - await handler['function'](message, self) - break + else: + if "data" in params: + if len(params) == 2: + await handler['function'](message, data) + elif len(params) == 3: + await 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: - await handler['function'](message, data) - break - elif len(params) == 3: - if handler['pass_bot'] and params[1] == 'bot': - await handler['function'](message, self, data) - break - else: - await handler['function'](message, data) - break + + if handler.get('pass_bot'): data["bot"] = self + if len(data) > len(params) - 1: + logger.error("You are passing more data than the handler needs. Check your handler: {}".format(handler['function'])) + return + await handler["function"](message, **data) except Exception as e: handler_error = e @@ -324,6 +324,9 @@ class AsyncTeleBot: return self.exception_handler.handle(e) logging.error(str(e)) return + # remove the bot from data + if "bot" in data: + del data["bot"] if middlewares: for middleware in middlewares: From 6e8abc709e592b2b8dcaccd579726bf2cb63767c Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 28 Jun 2022 19:51:51 +0500 Subject: [PATCH 35/54] Pass only the necessary data --- telebot/__init__.py | 15 ++++++++++----- telebot/async_telebot.py | 20 ++++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 23887c1..f034cca 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -4022,12 +4022,19 @@ class TeleBot: return else: - if handler.get('pass_bot'): data["bot"] = self - if len(data) > len(params) - 1: # remove the message parameter + + 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 data than the handler needs. Check your handler: {}".format(handler['function'])) return - handler["function"](message, **data) + handler["function"](message, **data_copy) except Exception as e: handler_error = e @@ -4038,8 +4045,6 @@ class TeleBot: logging.error(str(e)) return # remove the bot from data - if "bot" in data: - del data["bot"] if middlewares: for middleware in middlewares: middleware.post_process(message, data, handler_error) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index f41f5cd..5c7f50c 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -309,13 +309,20 @@ class AsyncTeleBot: logger.error("It is not allowed to pass data and values inside data to the handler. Check your handler: {}".format(handler['function'])) return - else: - - if handler.get('pass_bot'): data["bot"] = self - if len(data) > len(params) - 1: + 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 data than the handler needs. Check your handler: {}".format(handler['function'])) return - await handler["function"](message, **data) + + handler["function"](message, **data_copy) except Exception as e: handler_error = e @@ -324,9 +331,6 @@ class AsyncTeleBot: return self.exception_handler.handle(e) logging.error(str(e)) return - # remove the bot from data - if "bot" in data: - del data["bot"] if middlewares: for middleware in middlewares: From fbb9a73fc040b54845c87c281cd7521c9843ad25 Mon Sep 17 00:00:00 2001 From: _run Date: Wed, 29 Jun 2022 14:52:37 +0500 Subject: [PATCH 36/54] F###, forgot to put await --- telebot/async_telebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 5c7f50c..dce9dec 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -322,7 +322,7 @@ class AsyncTeleBot: logger.error("You are passing more data than the handler needs. Check your handler: {}".format(handler['function'])) return - handler["function"](message, **data_copy) + await handler["function"](message, **data_copy) except Exception as e: handler_error = e From fec47cecafa511c25cec591547cda13fd933f9b4 Mon Sep 17 00:00:00 2001 From: _run Date: Wed, 29 Jun 2022 20:21:42 +0500 Subject: [PATCH 37/54] Add the possibility to getbase class of a State object --- telebot/asyncio_handler_backends.py | 1 + telebot/handler_backends.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/telebot/asyncio_handler_backends.py b/telebot/asyncio_handler_backends.py index e5e2e4f..4ef4555 100644 --- a/telebot/asyncio_handler_backends.py +++ b/telebot/asyncio_handler_backends.py @@ -29,6 +29,7 @@ class StatesGroup: if not name.startswith('__') and not callable(value) and isinstance(value, State): # change value of that variable value.name = ':'.join((cls.__name__, name)) + value.group = cls class SkipHandler: diff --git a/telebot/handler_backends.py b/telebot/handler_backends.py index b838231..4304317 100644 --- a/telebot/handler_backends.py +++ b/telebot/handler_backends.py @@ -163,6 +163,10 @@ class StatesGroup: if not name.startswith('__') and not callable(value) and isinstance(value, State): # change value of that variable value.name = ':'.join((cls.__name__, name)) + value.group = cls + + + class BaseMiddleware: From ca525b5bead9497d3bf531a7a94353cef0074f6d Mon Sep 17 00:00:00 2001 From: _run Date: Wed, 29 Jun 2022 21:06:36 +0500 Subject: [PATCH 38/54] Copyright changes --- telebot/callback_data.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/telebot/callback_data.py b/telebot/callback_data.py index 17bf27f..952030c 100644 --- a/telebot/callback_data.py +++ b/telebot/callback_data.py @@ -1,3 +1,11 @@ +# https://github.com/aiogram/aiogram/blob/dev-2.x/LICENSE +""" +This file was added during the pull request. The maintainers overlooked that +it was copied "as is" from another project and they do not consider it as a +right way to develop a project. However, due to backward compatibility we had +to leave this file in the project with the above copyright added, +as it is required by the original project license. +""" import typing From c36f3a228e3b0a964c2e80977a9ffdb906070b26 Mon Sep 17 00:00:00 2001 From: _run Date: Wed, 29 Jun 2022 21:17:57 +0500 Subject: [PATCH 39/54] Update callback_data.py --- telebot/callback_data.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/telebot/callback_data.py b/telebot/callback_data.py index 952030c..c85b9e3 100644 --- a/telebot/callback_data.py +++ b/telebot/callback_data.py @@ -1,4 +1,24 @@ -# https://github.com/aiogram/aiogram/blob/dev-2.x/LICENSE +""" +Copyright (c) 2017-2018 Alex Root Junior + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. +""" + """ This file was added during the pull request. The maintainers overlooked that it was copied "as is" from another project and they do not consider it as a From ce0a974c918a44d4a1fdc2006ddc9330ef8dad37 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Wed, 29 Jun 2022 19:24:27 +0300 Subject: [PATCH 40/54] Copyright update --- telebot/__init__.py | 10 +++++----- telebot/callback_data.py | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 85454c5..ee73b3f 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -385,7 +385,7 @@ class TeleBot: new_poll_answers = None new_my_chat_members = None new_chat_members = None - chat_join_request = None + new_chat_join_request = None for update in updates: if apihelper.ENABLE_MIDDLEWARE: @@ -442,8 +442,8 @@ class TeleBot: if new_chat_members is None: new_chat_members = [] new_chat_members.append(update.chat_member) if update.chat_join_request: - if chat_join_request is None: chat_join_request = [] - chat_join_request.append(update.chat_join_request) + if new_chat_join_request is None: new_chat_join_request = [] + new_chat_join_request.append(update.chat_join_request) if new_messages: self.process_new_messages(new_messages) @@ -471,8 +471,8 @@ class TeleBot: self.process_new_my_chat_member(new_my_chat_members) if new_chat_members: self.process_new_chat_member(new_chat_members) - if chat_join_request: - self.process_new_chat_join_request(chat_join_request) + if new_chat_join_request: + self.process_new_chat_join_request(new_chat_join_request) def process_new_messages(self, new_messages): self._notify_next_handlers(new_messages) diff --git a/telebot/callback_data.py b/telebot/callback_data.py index 17bf27f..58fa0d5 100644 --- a/telebot/callback_data.py +++ b/telebot/callback_data.py @@ -1,3 +1,30 @@ +""" +Copyright (c) 2017-2018 Alex Root Junior + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + + +This file was added during the pull request. The maintainers overlooked that it was copied +"as is" from another project and they do not consider it as a right way to develop a project. +However, due to backward compatibility we had to leave this file in the project with the above +copyright added, as it is required by the original project license. +""" + import typing From 419bc5878f52ea84c6518b89e5c2d0cc69f1765c Mon Sep 17 00:00:00 2001 From: _run Date: Thu, 30 Jun 2022 17:06:39 +0500 Subject: [PATCH 41/54] Fix typehint for ```set_state``` --- telebot/__init__.py | 4 ++-- telebot/async_telebot.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index f034cca..a7f3694 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -34,7 +34,7 @@ logger.addHandler(console_output_handler) logger.setLevel(logging.ERROR) from telebot import apihelper, util, types -from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend, BaseMiddleware, CancelUpdate, SkipHandler +from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend, BaseMiddleware, CancelUpdate, SkipHandler, State from telebot.custom_filters import SimpleCustomFilter, AdvancedCustomFilter @@ -2927,7 +2927,7 @@ class TeleBot: - def set_state(self, user_id: int, state: Union[int, str], chat_id: int=None) -> None: + def set_state(self, user_id: int, state: Union[int, str, State], chat_id: int=None) -> None: """ Sets a new state of a user. diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index dce9dec..9571c04 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -14,7 +14,7 @@ import telebot.types # storages from telebot.asyncio_storage import StateMemoryStorage, StatePickleStorage -from telebot.asyncio_handler_backends import CancelUpdate, SkipHandler +from telebot.asyncio_handler_backends import CancelUpdate, SkipHandler, State from inspect import signature @@ -3455,7 +3455,7 @@ class AsyncTeleBot: return await asyncio_helper.delete_sticker_from_set(self.token, sticker) - async def set_state(self, user_id: int, state: str, chat_id: int=None): + async def set_state(self, user_id: int, state: Union[State, int, str], chat_id: int=None): """ Sets a new state of a user. From 6d12b1f2a7a3fb62337af62bf55d1e785e465146 Mon Sep 17 00:00:00 2001 From: _run Date: Thu, 30 Jun 2022 17:10:14 +0500 Subject: [PATCH 42/54] Update callback_data.py --- telebot/callback_data.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/telebot/callback_data.py b/telebot/callback_data.py index c85b9e3..58fa0d5 100644 --- a/telebot/callback_data.py +++ b/telebot/callback_data.py @@ -17,15 +17,14 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This file was added during the pull request. The maintainers overlooked that it was copied +"as is" from another project and they do not consider it as a right way to develop a project. +However, due to backward compatibility we had to leave this file in the project with the above +copyright added, as it is required by the original project license. """ -""" -This file was added during the pull request. The maintainers overlooked that -it was copied "as is" from another project and they do not consider it as a -right way to develop a project. However, due to backward compatibility we had -to leave this file in the project with the above copyright added, -as it is required by the original project license. -""" import typing From d14064a84d6cd7a00c062d8364f10131109fe032 Mon Sep 17 00:00:00 2001 From: _run Date: Thu, 30 Jun 2022 17:51:58 +0500 Subject: [PATCH 43/54] Fix group and supergroup issues --- telebot/asyncio_filters.py | 2 +- telebot/custom_filters.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/asyncio_filters.py b/telebot/asyncio_filters.py index c594d31..8819be5 100644 --- a/telebot/asyncio_filters.py +++ b/telebot/asyncio_filters.py @@ -307,7 +307,7 @@ class StateFilter(AdvancedCustomFilter): elif isinstance(text, State): text = text.name - if message.chat.type == 'group': + if message.chat.type in ['group', 'supergroup']: group_state = await self.bot.current_states.get_state(user_id, chat_id) if group_state == text: return True diff --git a/telebot/custom_filters.py b/telebot/custom_filters.py index abeffdd..02edd07 100644 --- a/telebot/custom_filters.py +++ b/telebot/custom_filters.py @@ -315,7 +315,7 @@ class StateFilter(AdvancedCustomFilter): elif isinstance(text, State): text = text.name - if message.chat.type == 'group': + if message.chat.type in ['group', 'supergroup']: group_state = self.bot.current_states.get_state(user_id, chat_id) if group_state == text: return True From 5939e754bbd1619566f66eeb0b50887e9590ccc5 Mon Sep 17 00:00:00 2001 From: _run Date: Fri, 1 Jul 2022 15:29:34 +0500 Subject: [PATCH 44/54] Update asyncio_helper.py --- telebot/asyncio_helper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 168edff..17575e7 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -149,7 +149,7 @@ async def get_file(token, file_id): async def get_file_url(token, file_id): if FILE_URL is None: - return "https://api.telegram.org/file/bot{0}/{1}".format(token, get_file(token, file_id)['file_path']) + return "https://api.telegram.org/file/bot{0}/{1}".format(token, await get_file(token, file_id)['file_path']) else: # noinspection PyUnresolvedReferences return FILE_URL.format(token, get_file(token, file_id)['file_path']) @@ -1821,4 +1821,4 @@ class RequestTimeout(Exception): """ This class represents a request timeout. """ - pass \ No newline at end of file + pass From c920809fa9d3e800343f13eb74e2e44c5a9e9859 Mon Sep 17 00:00:00 2001 From: _run Date: Fri, 1 Jul 2022 15:39:42 +0500 Subject: [PATCH 45/54] Update asyncio_helper.py --- telebot/asyncio_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 17575e7..75492af 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -152,7 +152,7 @@ async def get_file_url(token, file_id): return "https://api.telegram.org/file/bot{0}/{1}".format(token, await get_file(token, file_id)['file_path']) else: # noinspection PyUnresolvedReferences - return FILE_URL.format(token, get_file(token, file_id)['file_path']) + return FILE_URL.format(token, await get_file(token, file_id)['file_path']) async def download_file(token, file_path): From ef86453126fe0603240fc21bb8cb27d39e10acdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=92=95=E8=B0=B7=E9=85=B1?= <74496778+GooGuJiang@users.noreply.github.com> Date: Sat, 2 Jul 2022 14:23:31 +0800 Subject: [PATCH 46/54] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 027139d..b1099da 100644 --- a/README.md +++ b/README.md @@ -899,5 +899,6 @@ Here are some examples of template: * [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX. * [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. * [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...). +* [Gugumoe-bot](http://t.me/gugumoe_bot)([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) A functional robot. **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** From cf3a85d6997e2a35dd6e8f2bf58206ef6d0431a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=92=95=E8=B0=B7=E9=85=B1?= <74496778+GooGuJiang@users.noreply.github.com> Date: Sat, 2 Jul 2022 14:31:37 +0800 Subject: [PATCH 47/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b1099da..091c540 100644 --- a/README.md +++ b/README.md @@ -899,6 +899,6 @@ Here are some examples of template: * [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX. * [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. * [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...). -* [Gugumoe-bot](http://t.me/gugumoe_bot)([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) A functional robot. +* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang Robot. **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** From 6d52090ef9ccfafa76fe8e4f77614eba6ee4c909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=92=95=E8=B0=B7=E9=85=B1?= <74496778+GooGuJiang@users.noreply.github.com> Date: Sat, 2 Jul 2022 15:06:46 +0800 Subject: [PATCH 48/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 091c540..f58349f 100644 --- a/README.md +++ b/README.md @@ -899,6 +899,6 @@ Here are some examples of template: * [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX. * [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. * [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...). -* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang Robot. +* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) A multifunctional robot, such as OSU game information query, IP test, animation screenshot search and other functions. **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** From badf98214780f225c67b91cf3a3e41619fde8caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=92=95=E8=B0=B7=E9=85=B1?= <74496778+GooGuJiang@users.noreply.github.com> Date: Sat, 2 Jul 2022 15:08:06 +0800 Subject: [PATCH 49/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f58349f..1bc6978 100644 --- a/README.md +++ b/README.md @@ -899,6 +899,6 @@ Here are some examples of template: * [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX. * [Bincode-telegram-bot](https://github.com/tusharhero/bincode-telegram-bot) by [tusharhero](https://github.com/tusharhero) - Makes [bincodes](https://github.com/tusharhero/bincode) from text provides and also converts them back to text. * [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...). -* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) A multifunctional robot, such as OSU game information query, IP test, animation screenshot search and other functions. +* [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. **Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.** From 1fb14e28d42daa81612cc95fccf277115e60bbd4 Mon Sep 17 00:00:00 2001 From: _run Date: Sat, 2 Jul 2022 21:07:00 +0500 Subject: [PATCH 50/54] Fix handler execution and #1594 --- telebot/async_telebot.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 9571c04..3ca7207 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -118,7 +118,20 @@ class AsyncTeleBot: """ await asyncio_helper.session_manager.session.close() async def get_updates(self, offset: Optional[int]=None, limit: Optional[int]=None, - timeout: Optional[int]=None, allowed_updates: Optional[List]=None, request_timeout: Optional[int]=None) -> List[types.Update]: + timeout: Optional[int]=20, allowed_updates: Optional[List]=None, request_timeout: Optional[int]=None) -> List[types.Update]: + """ + Use this method to receive incoming updates using long polling (wiki). + An Array of Update objects is returned. + + Telegram documentation: https://core.telegram.org/bots/api#making-requests + + :param allowed_updates: Array of string. List the types of updates you want your bot to receive. + :param offset: Integer. Identifier of the first update to be returned. + :param limit: Integer. Limits the number of updates to be retrieved. + :param timeout: Integer. Request connection timeout + :param request_timeout: Timeout in seconds for a request. + :return: array of Updates + """ 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] @@ -299,12 +312,15 @@ class AsyncTeleBot: params.append(i) if len(params) == 1: await handler['function'](message) + break else: if "data" in params: if len(params) == 2: await handler['function'](message, data) + break elif len(params) == 3: await handler['function'](message, data=data, bot=self) + break else: logger.error("It is not allowed to pass data and values inside data to the handler. Check your handler: {}".format(handler['function'])) return @@ -323,14 +339,13 @@ class AsyncTeleBot: return await handler["function"](message, **data_copy) + break except Exception as e: handler_error = e - if not middlewares: - if self.exception_handler: - return self.exception_handler.handle(e) - logging.error(str(e)) - return + if self.exception_handler: + self.exception_handler.handle(e) + else: logger.error(str(e)) if middlewares: for middleware in middlewares: From f3b1f97362458f94b214d58a2a23306877d821ad Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sun, 3 Jul 2022 23:33:55 +0300 Subject: [PATCH 51/54] ChatMember is now typed https://core.telegram.org/bots/api#chatmember --- telebot/async_telebot.py | 2 +- telebot/types.py | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index dce9dec..a69f34b 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -108,7 +108,6 @@ class AsyncTeleBot: self.current_states = state_storage - self.middlewares = [] async def close_session(self): @@ -117,6 +116,7 @@ class AsyncTeleBot: Use this function if you stop polling. """ await asyncio_helper.session_manager.session.close() + async def get_updates(self, offset: Optional[int]=None, limit: Optional[int]=None, timeout: Optional[int]=None, allowed_updates: Optional[List]=None, request_timeout: Optional[int]=None) -> List[types.Update]: json_updates = await asyncio_helper.get_updates(self.token, offset, limit, timeout, allowed_updates, request_timeout) diff --git a/telebot/types.py b/telebot/types.py index ee67cb9..e49e86a 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1280,7 +1280,22 @@ class ChatMember(JsonDeserializable): if json_string is None: return None obj = cls.check_json(json_string) obj['user'] = User.de_json(obj['user']) - return cls(**obj) + member_type = obj['status'] + if member_type == "creator": + return ChatMemberOwner(**obj) + elif member_type == "administrator": + return ChatMemberAdministrator(**obj) + elif member_type == "member": + return ChatMemberMember(**obj) + elif member_type == "restricted": + return ChatMemberRestricted(**obj) + elif member_type == "left": + return ChatMemberLeft(**obj) + elif member_type == "kicked": + return ChatMemberBanned(**obj) + else: + # Should not be here + return cls(**obj) def __init__(self, user, status, custom_title=None, is_anonymous=None, can_be_edited=None, can_post_messages=None, can_edit_messages=None, can_delete_messages=None, @@ -1318,6 +1333,7 @@ class ChatMember(JsonDeserializable): class ChatMemberOwner(ChatMember): pass + class ChatMemberAdministrator(ChatMember): pass From 0aa9f0fb42ad5e4c79fa49b7c42db31c5f84bd96 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Mon, 4 Jul 2022 22:26:24 +0300 Subject: [PATCH 52/54] Update type fix --- telebot/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/util.py b/telebot/util.py index 2561c21..62ebe7f 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -49,7 +49,7 @@ content_type_service = [ ] update_types = [ - "update_id", "message", "edited_message", "channel_post", "edited_channel_post", "inline_query", + "message", "edited_message", "channel_post", "edited_channel_post", "inline_query", "chosen_inline_result", "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer", "my_chat_member", "chat_member", "chat_join_request" ] From 81cbddb8cd67368666ba0e708b60d3e9eefb6b13 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Mon, 4 Jul 2022 22:36:42 +0300 Subject: [PATCH 53/54] Added source data (json_string) to CallbackQuery --- telebot/types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index e49e86a..5a8fcf2 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1248,9 +1248,10 @@ class CallbackQuery(JsonDeserializable): obj['from_user'] = User.de_json(obj.pop('from')) if 'message' in obj: obj['message'] = Message.de_json(obj.get('message')) + obj['json_string'] = json_string return cls(**obj) - def __init__(self, id, from_user, data, chat_instance, message=None, inline_message_id=None, game_short_name=None, **kwargs): + def __init__(self, id, from_user, data, chat_instance, json_string, message=None, inline_message_id=None, game_short_name=None, **kwargs): self.id: int = id self.from_user: User = from_user self.message: Message = message @@ -1258,6 +1259,7 @@ class CallbackQuery(JsonDeserializable): self.chat_instance: str = chat_instance self.data: str = data self.game_short_name: str = game_short_name + self.json = json_string class ChatPhoto(JsonDeserializable): From 78251cdf43941a6dea5ce34d31a12433b63be542 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Mon, 4 Jul 2022 22:41:01 +0300 Subject: [PATCH 54/54] ChatMember type checking reordered --- telebot/types.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 5a8fcf2..5bab9c4 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1283,20 +1283,21 @@ class ChatMember(JsonDeserializable): obj = cls.check_json(json_string) obj['user'] = User.de_json(obj['user']) member_type = obj['status'] - if member_type == "creator": - return ChatMemberOwner(**obj) - elif member_type == "administrator": - return ChatMemberAdministrator(**obj) - elif member_type == "member": + # Ordered according to estimated appearance frequency. + if member_type == "member": return ChatMemberMember(**obj) - elif member_type == "restricted": - return ChatMemberRestricted(**obj) elif member_type == "left": return ChatMemberLeft(**obj) elif member_type == "kicked": return ChatMemberBanned(**obj) + elif member_type == "restricted": + return ChatMemberRestricted(**obj) + elif member_type == "administrator": + return ChatMemberAdministrator(**obj) + elif member_type == "creator": + return ChatMemberOwner(**obj) else: - # Should not be here + # Should not be here. For "if something happen" compatibility return cls(**obj) def __init__(self, user, status, custom_title=None, is_anonymous=None, can_be_edited=None,