From 06aa4c6802478717124b57f03446992964cfa41d Mon Sep 17 00:00:00 2001 From: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Date: Fri, 25 Mar 2022 13:41:01 +0100 Subject: [PATCH 01/14] Fix: await coroutines Also put one logging line where it belongs --- examples/chatmemberbot.py | 4 ++-- examples/contexttypesbot.py | 2 +- examples/nestedconversationbot.py | 22 +++++++++++----------- examples/rawapibot.py | 3 +-- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/examples/chatmemberbot.py b/examples/chatmemberbot.py index c3606602be2..1d5899984e2 100644 --- a/examples/chatmemberbot.py +++ b/examples/chatmemberbot.py @@ -127,12 +127,12 @@ async def greet_chat_members(update: Update, context: CallbackContext.DEFAULT_TY member_name = update.chat_member.new_chat_member.user.mention_html() if not was_member and is_member: - update.effective_chat.send_message( + await update.effective_chat.send_message( f"{member_name} was added by {cause_name}. Welcome!", parse_mode=ParseMode.HTML, ) elif was_member and not is_member: - update.effective_chat.send_message( + await update.effective_chat.send_message( f"{member_name} is no longer with us. Thanks a lot, {cause_name} ...", parse_mode=ParseMode.HTML, ) diff --git a/examples/contexttypesbot.py b/examples/contexttypesbot.py index c931f92ca33..78f2b1282dd 100644 --- a/examples/contexttypesbot.py +++ b/examples/contexttypesbot.py @@ -88,7 +88,7 @@ async def count_click(update: Update, context: CustomContext) -> None: """Update the click count for the message.""" context.message_clicks += 1 await update.callback_query.answer() - update.effective_message.edit_text( + await update.effective_message.edit_text( f'This button was clicked {context.message_clicks} times.', reply_markup=InlineKeyboardMarkup.from_button( InlineKeyboardButton(text='Click me!', callback_data='button') diff --git a/examples/nestedconversationbot.py b/examples/nestedconversationbot.py index d80c5f7e997..d9974a8fd16 100644 --- a/examples/nestedconversationbot.py +++ b/examples/nestedconversationbot.py @@ -120,27 +120,27 @@ async def adding_self(update: Update, context: CallbackContext.DEFAULT_TYPE) -> async def show_data(update: Update, context: CallbackContext.DEFAULT_TYPE) -> str: """Pretty print gathered data.""" - def prettyprint(user_data: Dict[str, Any], level: str) -> str: - people = user_data.get(level) + def pretty_print(data: Dict[str, Any], level: str) -> str: + people = data.get(level) if not people: return '\nNo information yet.' - text = '' + return_str = '' if level == SELF: - for person in user_data[level]: - text += f"\nName: {person.get(NAME, '-')}, Age: {person.get(AGE, '-')}" + for person in data[level]: + return_str += f"\nName: {person.get(NAME, '-')}, Age: {person.get(AGE, '-')}" else: male, female = _name_switcher(level) - for person in user_data[level]: + for person in data[level]: gender = female if person[GENDER] == FEMALE else male - text += f"\n{gender}: Name: {person.get(NAME, '-')}, Age: {person.get(AGE, '-')}" - return text + return_str += f"\n{gender}: Name: {person.get(NAME, '-')}, Age: {person.get(AGE, '-')}" + return return_str user_data = context.user_data - text = f"Yourself:{prettyprint(user_data, SELF)}" - text += f"\n\nParents:{prettyprint(user_data, PARENTS)}" - text += f"\n\nChildren:{prettyprint(user_data, CHILDREN)}" + text = f"Yourself:{pretty_print(user_data, SELF)}" + text += f"\n\nParents:{pretty_print(user_data, PARENTS)}" + text += f"\n\nChildren:{pretty_print(user_data, CHILDREN)}" buttons = [[InlineKeyboardButton(text='Back', callback_data=str(END))]] keyboard = InlineKeyboardMarkup(buttons) diff --git a/examples/rawapibot.py b/examples/rawapibot.py index 19a9d512fe0..78c855fa46f 100644 --- a/examples/rawapibot.py +++ b/examples/rawapibot.py @@ -15,6 +15,7 @@ UPDATE_ID = None +logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') async def main() -> NoReturn: @@ -30,8 +31,6 @@ async def main() -> NoReturn: except IndexError: UPDATE_ID = None - logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') - while True: try: await echo(bot) From eeb4ce56da68e040d19c8a41f664c8a98380aec7 Mon Sep 17 00:00:00 2001 From: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Date: Sun, 27 Mar 2022 20:22:01 +0200 Subject: [PATCH 02/14] Feat: switch all markdown mentions to hml --- examples/deeplinking.py | 4 ++-- examples/echobot.py | 4 ++-- examples/inlinebot.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/deeplinking.py b/examples/deeplinking.py index f0644d16aef..3043155ce60 100644 --- a/examples/deeplinking.py +++ b/examples/deeplinking.py @@ -73,9 +73,9 @@ async def deep_linked_level_2(update: Update, context: CallbackContext.DEFAULT_T """Reached through the SO_COOL payload""" bot = context.bot url = helpers.create_deep_linked_url(bot.username, USING_ENTITIES) - text = f"You can also mask the deep-linked URLs as links: [▶️ CLICK HERE]({url})." + text = f"You can also mask the deep-linked URLs as links: ▶️ CLICK HERE." await update.message.reply_text( - text, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True + text, parse_mode=ParseMode.HTML, disable_web_page_preview=True ) diff --git a/examples/echobot.py b/examples/echobot.py index 95c34d2d084..584c77fc580 100644 --- a/examples/echobot.py +++ b/examples/echobot.py @@ -39,8 +39,8 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: """Send a message when the command /start is issued.""" user = update.effective_user - await update.message.reply_markdown_v2( - fr'Hi {user.mention_markdown_v2()}\!', + await update.message.reply_html( + fr'Hi {user.mention_html()}\!', reply_markup=ForceReply(selective=True), ) diff --git a/examples/inlinebot.py b/examples/inlinebot.py index c1cfac18547..499ed3f4df9 100644 --- a/examples/inlinebot.py +++ b/examples/inlinebot.py @@ -17,7 +17,7 @@ from telegram import InlineQueryResultArticle, InputTextMessageContent, Update from telegram.constants import ParseMode -from telegram.helpers import escape_markdown +from html import escape from telegram.ext import Application, InlineQueryHandler, CommandHandler, CallbackContext # Enable logging @@ -56,14 +56,14 @@ async def inlinequery(update: Update, context: CallbackContext.DEFAULT_TYPE) -> id=str(uuid4()), title="Bold", input_message_content=InputTextMessageContent( - f"*{escape_markdown(query)}*", parse_mode=ParseMode.MARKDOWN + f"*{escape(query)}*", parse_mode=ParseMode.HTML ), ), InlineQueryResultArticle( id=str(uuid4()), title="Italic", input_message_content=InputTextMessageContent( - f"_{escape_markdown(query)}_", parse_mode=ParseMode.MARKDOWN + f"_{escape(query)}_", parse_mode=ParseMode.MARKDOWN ), ), ] From 1ac48099b315b1534e79da705d0d2d673bf3f349 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 31 Mar 2022 09:11:01 +0200 Subject: [PATCH 03/14] Feat: readd pre-commits for examples --- .pre-commit-config.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b78c12611f7..ff7196ea707 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,6 +44,18 @@ repos: - APScheduler==3.6.3 - cachetools==4.2.2 - . # this basically does `pip install -e .`n + - id: mypy + name: mypy-examples + files: ^examples/.*\.py$ + args: + - --no-strict-optional + - --follow-imports=silent + additional_dependencies: + - certifi + - tornado>=6.1 + - APScheduler==3.6.3 + - cachetools==4.2.2 + - . # this basically does `pip install -e .` - repo: https://github.com/asottile/pyupgrade rev: v2.29.0 hooks: From 99ac29812ee5d87e1733d8fd9a173e553e032c67 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 31 Mar 2022 09:23:03 +0200 Subject: [PATCH 04/14] Fix: Apply Black --- examples/deeplinking.py | 4 +--- examples/nestedconversationbot.py | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/deeplinking.py b/examples/deeplinking.py index 3043155ce60..659c2245d3c 100644 --- a/examples/deeplinking.py +++ b/examples/deeplinking.py @@ -74,9 +74,7 @@ async def deep_linked_level_2(update: Update, context: CallbackContext.DEFAULT_T bot = context.bot url = helpers.create_deep_linked_url(bot.username, USING_ENTITIES) text = f"You can also mask the deep-linked URLs as links: ▶️ CLICK HERE." - await update.message.reply_text( - text, parse_mode=ParseMode.HTML, disable_web_page_preview=True - ) + await update.message.reply_text(text, parse_mode=ParseMode.HTML, disable_web_page_preview=True) async def deep_linked_level_3(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: diff --git a/examples/nestedconversationbot.py b/examples/nestedconversationbot.py index d9974a8fd16..d08137636f5 100644 --- a/examples/nestedconversationbot.py +++ b/examples/nestedconversationbot.py @@ -134,7 +134,9 @@ def pretty_print(data: Dict[str, Any], level: str) -> str: for person in data[level]: gender = female if person[GENDER] == FEMALE else male - return_str += f"\n{gender}: Name: {person.get(NAME, '-')}, Age: {person.get(AGE, '-')}" + return_str += ( + f"\n{gender}: Name: {person.get(NAME, '-')}, Age: {person.get(AGE, '-')}" + ) return return_str user_data = context.user_data From 188a79c41757f234a1c0a1cd33c25b2b233954d3 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 31 Mar 2022 09:38:11 +0200 Subject: [PATCH 05/14] Fix: mypy caught wrong application definition --- examples/arbitrarycallbackdatabot.py | 10 +++++----- examples/chatmemberbot.py | 2 +- examples/errorhandlerbot.py | 3 --- examples/inlinebot.py | 2 +- examples/inlinekeyboard.py | 6 +++--- examples/passportbot.py | 3 --- examples/persistentconversationbot.py | 3 --- 7 files changed, 10 insertions(+), 19 deletions(-) diff --git a/examples/arbitrarycallbackdatabot.py b/examples/arbitrarycallbackdatabot.py index 354ec934c2f..15adac4f994 100644 --- a/examples/arbitrarycallbackdatabot.py +++ b/examples/arbitrarycallbackdatabot.py @@ -97,13 +97,13 @@ def main() -> None: .build() ) - application.application.add_handler(CommandHandler('start', start)) - application.application.add_handler(CommandHandler('help', help_command)) - application.application.add_handler(CommandHandler('clear', clear)) - application.application.add_handler( + application.add_handler(CommandHandler('start', start)) + application.add_handler(CommandHandler('help', help_command)) + application.add_handler(CommandHandler('clear', clear)) + application.add_handler( CallbackQueryHandler(handle_invalid_button, pattern=InvalidCallbackData) ) - application.application.add_handler(CallbackQueryHandler(list_button)) + application.add_handler(CallbackQueryHandler(list_button)) # Run the bot until the user presses Ctrl-C application.run_polling() diff --git a/examples/chatmemberbot.py b/examples/chatmemberbot.py index 1d5899984e2..30f7138bc86 100644 --- a/examples/chatmemberbot.py +++ b/examples/chatmemberbot.py @@ -153,7 +153,7 @@ def main() -> None: # Run the bot until the user presses Ctrl-C # We pass 'allowed_updates' handle *all* updates including `chat_member` updates # To reset this, simply pass `allowed_updates=[]` - application.run_polling()(allowed_updates=Update.ALL_TYPES) + application.run_polling(allowed_updates=Update.ALL_TYPES) if __name__ == "__main__": diff --git a/examples/errorhandlerbot.py b/examples/errorhandlerbot.py index 8b0079d1648..80e2d049dea 100644 --- a/examples/errorhandlerbot.py +++ b/examples/errorhandlerbot.py @@ -72,9 +72,6 @@ def main() -> None: # Create the Application and pass it your bot's token. application = Application.builder().token(BOT_TOKEN).build() - # Get the application to register handlers - application = application.application - # Register the commands... application.add_handler(CommandHandler('start', start)) application.add_handler(CommandHandler('bad_command', bad_command)) diff --git a/examples/inlinebot.py b/examples/inlinebot.py index 499ed3f4df9..04da9c897e6 100644 --- a/examples/inlinebot.py +++ b/examples/inlinebot.py @@ -14,10 +14,10 @@ """ import logging from uuid import uuid4 +from html import escape from telegram import InlineQueryResultArticle, InputTextMessageContent, Update from telegram.constants import ParseMode -from html import escape from telegram.ext import Application, InlineQueryHandler, CommandHandler, CallbackContext # Enable logging diff --git a/examples/inlinekeyboard.py b/examples/inlinekeyboard.py index 730e70b23cd..b618d4b85ee 100644 --- a/examples/inlinekeyboard.py +++ b/examples/inlinekeyboard.py @@ -60,9 +60,9 @@ def main() -> None: # Create the Application and pass it your bot's token. application = Application.builder().token("TOKEN").build() - application.application.add_handler(CommandHandler('start', start)) - application.application.add_handler(CallbackQueryHandler(button)) - application.application.add_handler(CommandHandler('help', help_command)) + application.add_handler(CommandHandler('start', start)) + application.add_handler(CallbackQueryHandler(button)) + application.add_handler(CommandHandler('help', help_command)) # Run the bot until the user presses Ctrl-C application.run_polling() diff --git a/examples/passportbot.py b/examples/passportbot.py index 47d5402ab7d..469de003bd6 100644 --- a/examples/passportbot.py +++ b/examples/passportbot.py @@ -109,9 +109,6 @@ def main() -> None: Application.builder().token("TOKEN").private_key(private_key.read_bytes()).build() ) - # Get the application to register handlers - application = application.application - # On messages that include passport data call msg application.add_handler(MessageHandler(filters.PASSPORT_DATA, msg)) diff --git a/examples/persistentconversationbot.py b/examples/persistentconversationbot.py index 71eb2f5bcba..4aebcd58d83 100644 --- a/examples/persistentconversationbot.py +++ b/examples/persistentconversationbot.py @@ -135,9 +135,6 @@ def main() -> None: persistence = PicklePersistence(filepath='conversationbot') application = Application.builder().token("TOKEN").persistence(persistence).build() - # Get the application to register handlers - application = application.application - # Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY conv_handler = ConversationHandler( entry_points=[CommandHandler('start', start)], From 2d28f1201308ce4e53b0360b1d0c6ce9acc1f4c1 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 31 Mar 2022 09:46:58 +0200 Subject: [PATCH 06/14] Fix: missed contexttype --- examples/contexttypesbot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/contexttypesbot.py b/examples/contexttypesbot.py index 78f2b1282dd..6338ff0a39a 100644 --- a/examples/contexttypesbot.py +++ b/examples/contexttypesbot.py @@ -116,7 +116,6 @@ def main() -> None: context_types = ContextTypes(context=CustomContext, chat_data=ChatData) application = Application.builder().token("TOKEN").context_types(context_types).build() - application = application.application # run track_users in its own group to not interfere with the user handlers application.add_handler(TypeHandler(Update, track_users), group=-1) application.add_handler(CommandHandler("start", start)) From c3eda6f2b679ee65d0362f88bbc2e990b98aacf9 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 31 Mar 2022 09:57:26 +0200 Subject: [PATCH 07/14] Fix: Temporarily fixing black dependency --- .pre-commit-config.yaml | 2 ++ requirements-dev.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff7196ea707..31751c4477e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,6 +9,8 @@ repos: args: - --diff - --check + additional_dependencies: + - click==8.0.2 - repo: https://gitlab.com/pycqa/flake8 rev: 4.0.1 hooks: diff --git a/requirements-dev.txt b/requirements-dev.txt index ee7a8b6c744..9f3ae43d89d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,6 +4,8 @@ cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3 pre-commit # Make sure that the versions specified here match the pre-commit settings! black==21.9b0 +# hardpinned dependency for black +click==8.0.2 flake8==4.0.1 pylint==2.12.1 mypy==0.910 From 4007fe0212c79a3a1c54fc6f6608b1cde1dd76c2 Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Thu, 31 Mar 2022 19:24:16 +0200 Subject: [PATCH 08/14] Fix: Remove markdown leftovers Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com> --- examples/inlinebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/inlinebot.py b/examples/inlinebot.py index 04da9c897e6..3fc31937933 100644 --- a/examples/inlinebot.py +++ b/examples/inlinebot.py @@ -63,7 +63,7 @@ async def inlinequery(update: Update, context: CallbackContext.DEFAULT_TYPE) -> id=str(uuid4()), title="Italic", input_message_content=InputTextMessageContent( - f"_{escape(query)}_", parse_mode=ParseMode.MARKDOWN + f"{escape(query)}", parse_mode=ParseMode.HTML ), ), ] From 7ce6b7836b1cc88e12ba00bd1e192509135ada7e Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:30:43 +0530 Subject: [PATCH 09/14] verify examples by running them --- examples/contexttypesbot.py | 7 ++++ examples/conversationbot.py | 2 +- examples/conversationbot2.py | 2 +- examples/errorhandlerbot.py | 7 +--- examples/inlinebot.py | 12 +++--- examples/inlinekeyboard2.py | 20 +++++----- examples/persistentconversationbot.py | 2 +- examples/pollbot.py | 20 +++++----- examples/rawapibot.py | 57 +++++++++++++++------------ examples/timerbot.py | 9 ++--- 10 files changed, 73 insertions(+), 65 deletions(-) diff --git a/examples/contexttypesbot.py b/examples/contexttypesbot.py index 6338ff0a39a..8bbcbe5f3ed 100644 --- a/examples/contexttypesbot.py +++ b/examples/contexttypesbot.py @@ -10,6 +10,7 @@ bot. """ +import logging from collections import defaultdict from typing import DefaultDict, Optional, Set @@ -25,6 +26,12 @@ Application, ) +# Enable logging +logging.basicConfig( + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO +) +logger = logging.getLogger(__name__) + class ChatData: """Custom class for chat_data. Here we store data per message.""" diff --git a/examples/conversationbot.py b/examples/conversationbot.py index 691e982c13f..3fb171cfe78 100644 --- a/examples/conversationbot.py +++ b/examples/conversationbot.py @@ -69,7 +69,7 @@ async def photo(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: """Stores the photo and asks for a location.""" user = update.message.from_user photo_file = await update.message.photo[-1].get_file() - photo_file.download('user_photo.jpg') + await photo_file.download('user_photo.jpg') logger.info("Photo of %s: %s", user.first_name, 'user_photo.jpg') await update.message.reply_text( 'Gorgeous! Now, send me your location please, or send /skip if you don\'t want to.' diff --git a/examples/conversationbot2.py b/examples/conversationbot2.py index 6d5737e8f8b..2e8f854a7f0 100644 --- a/examples/conversationbot2.py +++ b/examples/conversationbot2.py @@ -89,7 +89,7 @@ async def received_information(update: Update, context: CallbackContext.DEFAULT_ await update.message.reply_text( "Neat! Just so you know, this is what you already told me:" - f"{facts_to_str(user_data)} You can tell me more, or change your opinion" + f"{facts_to_str(user_data)}You can tell me more, or change your opinion" " on something.", reply_markup=markup, ) diff --git a/examples/errorhandlerbot.py b/examples/errorhandlerbot.py index 80e2d049dea..4e59a0341dc 100644 --- a/examples/errorhandlerbot.py +++ b/examples/errorhandlerbot.py @@ -18,12 +18,9 @@ ) logger = logging.getLogger(__name__) -# The token you got from @botfather when you created the bot -BOT_TOKEN = "TOKEN" - # This can be your own ID, or one for a developer group/channel. # You can use the /start command of this bot to see your chat id. -DEVELOPER_CHAT_ID = 123456789 +DEVELOPER_CHAT_ID = 476269395 async def error_handler(update: object, context: CallbackContext.DEFAULT_TYPE) -> None: @@ -70,7 +67,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: def main() -> None: """Run the bot.""" # Create the Application and pass it your bot's token. - application = Application.builder().token(BOT_TOKEN).build() + application = Application.builder().token("TOKEN").build() # Register the commands... application.add_handler(CommandHandler('start', start)) diff --git a/examples/inlinebot.py b/examples/inlinebot.py index 3fc31937933..fb6f782e9e0 100644 --- a/examples/inlinebot.py +++ b/examples/inlinebot.py @@ -28,7 +28,7 @@ # Define a few command handlers. These usually take the two arguments update and -# context. Error handlers also receive the raised TelegramError object in error. +# context. async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: """Send a message when the command /start is issued.""" await update.message.reply_text('Hi!') @@ -39,8 +39,8 @@ async def help_command(update: Update, context: CallbackContext.DEFAULT_TYPE) -> await update.message.reply_text('Help!') -async def inlinequery(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: - """Handle the inline query.""" +async def inline_query(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: + """Handle the inline query. This is run when you type: @botusername """ query = update.inline_query.query if query == "": @@ -56,14 +56,14 @@ async def inlinequery(update: Update, context: CallbackContext.DEFAULT_TYPE) -> id=str(uuid4()), title="Bold", input_message_content=InputTextMessageContent( - f"*{escape(query)}*", parse_mode=ParseMode.HTML + f"{escape(query)}", parse_mode=ParseMode.HTML ), ), InlineQueryResultArticle( id=str(uuid4()), title="Italic", input_message_content=InputTextMessageContent( - f"{escape(query)}", parse_mode=ParseMode.HTML + f"{escape(query)}", parse_mode=ParseMode.HTML ), ), ] @@ -81,7 +81,7 @@ def main() -> None: application.add_handler(CommandHandler("help", help_command)) # on non command i.e message - echo the message on Telegram - application.add_handler(InlineQueryHandler(inlinequery)) + application.add_handler(InlineQueryHandler(inline_query)) # Run the bot until the user presses Ctrl-C application.run_polling() diff --git a/examples/inlinekeyboard2.py b/examples/inlinekeyboard2.py index cb95637e666..24f67b2adfd 100644 --- a/examples/inlinekeyboard2.py +++ b/examples/inlinekeyboard2.py @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) # Stages -FIRST, SECOND = range(2) +START_ROUTES, END_ROUTES = range(2) # Callback data ONE, TWO, THREE, FOUR = range(4) @@ -56,7 +56,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: # Send message with text and appended InlineKeyboard await update.message.reply_text("Start handler, Choose a route", reply_markup=reply_markup) # Tell ConversationHandler that we're in state `FIRST` now - return FIRST + return START_ROUTES async def start_over(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: @@ -77,7 +77,7 @@ async def start_over(update: Update, context: CallbackContext.DEFAULT_TYPE) -> i # originated the CallbackQuery. This gives the feeling of an # interactive menu. await query.edit_message_text(text="Start handler, Choose a route", reply_markup=reply_markup) - return FIRST + return START_ROUTES async def one(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: @@ -94,7 +94,7 @@ async def one(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: await query.edit_message_text( text="First CallbackQueryHandler, Choose a route", reply_markup=reply_markup ) - return FIRST + return START_ROUTES async def two(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: @@ -111,11 +111,11 @@ async def two(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: await query.edit_message_text( text="Second CallbackQueryHandler, Choose a route", reply_markup=reply_markup ) - return FIRST + return START_ROUTES async def three(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: - """Show new choice of buttons""" + """Show new choice of buttons. This is the end point of the conversation.""" query = update.callback_query await query.answer() keyboard = [ @@ -129,7 +129,7 @@ async def three(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: text="Third CallbackQueryHandler. Do want to start over?", reply_markup=reply_markup ) # Transfer to conversation state `SECOND` - return SECOND + return END_ROUTES async def four(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: @@ -146,7 +146,7 @@ async def four(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: await query.edit_message_text( text="Fourth CallbackQueryHandler, Choose a route", reply_markup=reply_markup ) - return FIRST + return START_ROUTES async def end(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: @@ -173,13 +173,13 @@ def main() -> None: conv_handler = ConversationHandler( entry_points=[CommandHandler('start', start)], states={ - FIRST: [ + START_ROUTES: [ CallbackQueryHandler(one, pattern='^' + str(ONE) + '$'), CallbackQueryHandler(two, pattern='^' + str(TWO) + '$'), CallbackQueryHandler(three, pattern='^' + str(THREE) + '$'), CallbackQueryHandler(four, pattern='^' + str(FOUR) + '$'), ], - SECOND: [ + END_ROUTES: [ CallbackQueryHandler(start_over, pattern='^' + str(ONE) + '$'), CallbackQueryHandler(end, pattern='^' + str(TWO) + '$'), ], diff --git a/examples/persistentconversationbot.py b/examples/persistentconversationbot.py index 4aebcd58d83..1e871de8b84 100644 --- a/examples/persistentconversationbot.py +++ b/examples/persistentconversationbot.py @@ -123,7 +123,7 @@ async def done(update: Update, context: CallbackContext.DEFAULT_TYPE) -> int: del context.user_data['choice'] await update.message.reply_text( - f"I learned these facts about you: {facts_to_str(context.user_data)} Until next time!", + f"I learned these facts about you: {facts_to_str(context.user_data)}Until next time!", reply_markup=ReplyKeyboardRemove(), ) return ConversationHandler.END diff --git a/examples/pollbot.py b/examples/pollbot.py index 2b7898cd1f3..dc4091f724a 100644 --- a/examples/pollbot.py +++ b/examples/pollbot.py @@ -69,9 +69,9 @@ async def poll(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: async def receive_poll_answer(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: """Summarize a users poll vote""" answer = update.poll_answer - poll_id = answer.poll_id + answered_poll = context.bot_data[answer.poll_id] try: - questions = context.bot_data[poll_id]["questions"] + questions = answered_poll["questions"] # this means this poll answer update is from an old poll, we can't do our answering then except KeyError: return @@ -83,16 +83,14 @@ async def receive_poll_answer(update: Update, context: CallbackContext.DEFAULT_T else: answer_string += questions[question_id] await context.bot.send_message( - context.bot_data[poll_id]["chat_id"], + answered_poll["chat_id"], f"{update.effective_user.mention_html()} feels {answer_string}!", parse_mode=ParseMode.HTML, ) - context.bot_data[poll_id]["answers"] += 1 + answered_poll["answers"] += 1 # Close poll after three participants voted - if context.bot_data[poll_id]["answers"] == 3: - await context.bot.stop_poll( - context.bot_data[poll_id]["chat_id"], context.bot_data[poll_id]["message_id"] - ) + if answered_poll["answers"] == 3: + await context.bot.stop_poll(answered_poll["chat_id"], answered_poll["message_id"]) async def quiz(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: @@ -158,12 +156,12 @@ def main() -> None: application = Application.builder().token("TOKEN").build() application.add_handler(CommandHandler('start', start)) application.add_handler(CommandHandler('poll', poll)) - application.add_handler(PollAnswerHandler(receive_poll_answer)) application.add_handler(CommandHandler('quiz', quiz)) - application.add_handler(PollHandler(receive_quiz_answer)) application.add_handler(CommandHandler('preview', preview)) - application.add_handler(MessageHandler(filters.POLL, receive_poll)) application.add_handler(CommandHandler('help', help_handler)) + application.add_handler(MessageHandler(filters.POLL, receive_poll)) + application.add_handler(PollAnswerHandler(receive_poll_answer)) + application.add_handler(PollHandler(receive_quiz_answer)) # Run the bot until the user presses Ctrl-C application.run_polling() diff --git a/examples/rawapibot.py b/examples/rawapibot.py index 78c855fa46f..eaa964d5b45 100644 --- a/examples/rawapibot.py +++ b/examples/rawapibot.py @@ -10,50 +10,57 @@ import logging from typing import NoReturn -import telegram +from telegram import Bot from telegram.error import NetworkError, Forbidden -UPDATE_ID = None -logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +logging.basicConfig( + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO +) +logger = logging.getLogger(__name__) async def main() -> NoReturn: """Run the bot.""" - global UPDATE_ID - # Telegram Bot Authorization Token - bot = telegram.Bot('TOKEN') - # get the first pending update_id, this is so we can skip over it in case - # we get an "Forbidden" exception. - try: - UPDATE_ID = (await bot.get_updates())[0].update_id - except IndexError: - UPDATE_ID = None - - while True: + # Here we use the `async with` syntax to properly initialize and shutdown resources. + async with Bot("TOKEN") as bot: + # get the first pending update_id, this is so we can skip over it in case + # we get a "Forbidden" exception. try: - await echo(bot) - except NetworkError: - await asyncio.sleep(1) - except Forbidden: - # The user has removed or blocked the bot. - UPDATE_ID += 1 + update_id = (await bot.get_updates())[0].update_id + except IndexError: + update_id = None + logger.info("listening for new messages...") + while True: + try: + update_id = await echo(bot, update_id) + except NetworkError: + await asyncio.sleep(1) + except Forbidden: + # The user has removed or blocked the bot. + update_id += 1 -async def echo(bot: telegram.Bot) -> None: + +async def echo(bot: Bot, update_id: int) -> None: """Echo the message the user sent.""" - global UPDATE_ID # Request updates after the last update_id - for update in await bot.get_updates(offset=UPDATE_ID, timeout=10): - UPDATE_ID = update.update_id + 1 + updates = await bot.get_updates(offset=update_id, timeout=10) + for update in updates: + next_update_id = update.update_id + 1 # your bot can receive updates without messages # and not all messages contain text if update.message and update.message.text: # Reply to the message + logger.info("Found message %s!", update.message.text) await update.message.reply_text(update.message.text) + return next_update_id if __name__ == '__main__': - asyncio.run(main()) + try: + asyncio.run(main()) + except KeyboardInterrupt: # Ignore exception when Ctrl-C is pressed + pass diff --git a/examples/timerbot.py b/examples/timerbot.py index 0d04241b5f8..8ff874dea96 100644 --- a/examples/timerbot.py +++ b/examples/timerbot.py @@ -31,7 +31,7 @@ # Define a few command handlers. These usually take the two arguments update and -# context. Error handlers also receive the raised TelegramError object in error. +# context. # Best practice would be to replace context with an underscore, # since context is an unused local variable. # This being an example and not having context present confusing beginners, @@ -59,7 +59,7 @@ def remove_job_if_exists(name: str, context: CallbackContext.DEFAULT_TYPE) -> bo async def set_timer(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: """Add a job to the queue.""" - chat_id = update.message.chat_id + chat_id = update.effective_message.chat_id try: # args[0] should contain the time for the timer in seconds due = int(context.args[0]) @@ -76,7 +76,7 @@ async def set_timer(update: Update, context: CallbackContext.DEFAULT_TYPE) -> No await update.message.reply_text(text) except (IndexError, ValueError): - await update.message.reply_text('Usage: /set ') + await update.effective_message.reply_text('Usage: /set ') async def unset(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: @@ -93,8 +93,7 @@ def main() -> None: application = Application.builder().token("TOKEN").build() # on different commands - answer in Telegram - application.add_handler(CommandHandler("start", start)) - application.add_handler(CommandHandler("help", start)) + application.add_handler(CommandHandler(["start", "help"], start)) application.add_handler(CommandHandler("set", set_timer)) application.add_handler(CommandHandler("unset", unset)) From bc955d3437906aaafece58973e03e3585630f4da Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 18:04:26 +0000 Subject: [PATCH 10/14] Autofix issues in 1 file Resolved issues in examples/rawapibot.py via DeepSource Autofix --- examples/rawapibot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/rawapibot.py b/examples/rawapibot.py index eaa964d5b45..c08a1b42fb9 100644 --- a/examples/rawapibot.py +++ b/examples/rawapibot.py @@ -22,7 +22,6 @@ async def main() -> NoReturn: """Run the bot.""" - # Here we use the `async with` syntax to properly initialize and shutdown resources. async with Bot("TOKEN") as bot: # get the first pending update_id, this is so we can skip over it in case From bcf0248743532dd346dd9a7dc96757eecf62daf4 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:36:41 +0530 Subject: [PATCH 11/14] dont use my dev chat id --- examples/errorhandlerbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/errorhandlerbot.py b/examples/errorhandlerbot.py index 4e59a0341dc..8f78be734ac 100644 --- a/examples/errorhandlerbot.py +++ b/examples/errorhandlerbot.py @@ -20,7 +20,7 @@ # This can be your own ID, or one for a developer group/channel. # You can use the /start command of this bot to see your chat id. -DEVELOPER_CHAT_ID = 476269395 +DEVELOPER_CHAT_ID = 123456789 async def error_handler(update: object, context: CallbackContext.DEFAULT_TYPE) -> None: From 31d178e201127c62802c7e5530cfa40d1ce4ef11 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Thu, 31 Mar 2022 23:39:05 +0530 Subject: [PATCH 12/14] remove unused backslash from string --- examples/echobot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/echobot.py b/examples/echobot.py index 584c77fc580..9a011091cff 100644 --- a/examples/echobot.py +++ b/examples/echobot.py @@ -40,7 +40,7 @@ async def start(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: """Send a message when the command /start is issued.""" user = update.effective_user await update.message.reply_html( - fr'Hi {user.mention_html()}\!', + fr'Hi {user.mention_html()}!', reply_markup=ForceReply(selective=True), ) From 411a5f03374af85259c2d30427b3ec68937baf89 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Sat, 2 Apr 2022 14:25:27 +0530 Subject: [PATCH 13/14] Apply suggestions from code review Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> --- examples/rawapibot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/rawapibot.py b/examples/rawapibot.py index c08a1b42fb9..2d451dc3b37 100644 --- a/examples/rawapibot.py +++ b/examples/rawapibot.py @@ -42,7 +42,7 @@ async def main() -> NoReturn: update_id += 1 -async def echo(bot: Bot, update_id: int) -> None: +async def echo(bot: Bot, update_id: int) -> int: """Echo the message the user sent.""" # Request updates after the last update_id updates = await bot.get_updates(offset=update_id, timeout=10) @@ -56,6 +56,7 @@ async def echo(bot: Bot, update_id: int) -> None: logger.info("Found message %s!", update.message.text) await update.message.reply_text(update.message.text) return next_update_id + return update_id if __name__ == '__main__': From f5f28388ea211d212d1704225c3c18b81e624eca Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Sun, 10 Apr 2022 15:43:36 +0200 Subject: [PATCH 14/14] Update passportbot.html, minor tweak in {passport, payment}bot.py --- examples/passportbot.html | 39 ++++++++++++++++++++++----------------- examples/passportbot.py | 4 ++-- examples/paymentbot.py | 8 ++++---- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/examples/passportbot.html b/examples/passportbot.html index 4e37f0c69c1..b25c51f6a50 100644 --- a/examples/passportbot.html +++ b/examples/passportbot.html @@ -3,27 +3,32 @@ Telegram passport test! - - - - - - + +

Telegram passport test

+ + + + diff --git a/examples/passportbot.py b/examples/passportbot.py index 469de003bd6..07efa9670f6 100644 --- a/examples/passportbot.py +++ b/examples/passportbot.py @@ -20,7 +20,7 @@ # Enable logging logging.basicConfig( - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO ) logger = logging.getLogger(__name__) @@ -83,7 +83,7 @@ async def msg(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: selfie_file = await data.selfie.get_file() print(data.type, selfie_file) await selfie_file.download() - if data.type in ( + if data.translation and data.type in ( 'passport', 'driver_license', 'identity_card', diff --git a/examples/paymentbot.py b/examples/paymentbot.py index 4ccafd1ed29..28ae5899b0e 100644 --- a/examples/paymentbot.py +++ b/examples/paymentbot.py @@ -24,6 +24,8 @@ ) logger = logging.getLogger(__name__) +PAYMENT_PROVIDER_TOKEN = 'TOKEN' + async def start_callback(update: Update, context: CallbackContext.DEFAULT_TYPE) -> None: """Displays info on how to use the bot.""" @@ -45,7 +47,6 @@ async def start_with_shipping_callback( # select a payload just for you to recognize its the donation from your bot payload = "Custom-Payload" # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token - provider_token = "PROVIDER_TOKEN" currency = "USD" # price in dollars price = 1 @@ -60,7 +61,7 @@ async def start_with_shipping_callback( title, description, payload, - provider_token, + PAYMENT_PROVIDER_TOKEN, currency, prices, need_name=True, @@ -81,7 +82,6 @@ async def start_without_shipping_callback( # select a payload just for you to recognize its the donation from your bot payload = "Custom-Payload" # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token - provider_token = "PROVIDER_TOKEN" currency = "USD" # price in dollars price = 1 @@ -91,7 +91,7 @@ async def start_without_shipping_callback( # optionally pass need_name=True, need_phone_number=True, # need_email=True, need_shipping_address=True, is_flexible=True await context.bot.send_invoice( - chat_id, title, description, payload, provider_token, currency, prices + chat_id, title, description, payload, PAYMENT_PROVIDER_TOKEN, currency, prices )