From 1b7aea432005a7b017763767cca22611650fdc26 Mon Sep 17 00:00:00 2001 From: tehcneko <88844448+tehcneko@users.noreply.github.com> Date: Thu, 10 Feb 2022 14:15:15 +0800 Subject: [PATCH 1/3] Update python-telegram-bot to 13 --- bot.py | 174 ++++++++++++++++++++-------------------- internationalization.py | 8 +- requirements.txt | 2 +- settings.py | 39 +++++---- shared_vars.py | 2 +- simple_commands.py | 26 +++--- utils.py | 10 +-- 7 files changed, 128 insertions(+), 133 deletions(-) diff --git a/bot.py b/bot.py index 994d201..4ce5ce1 100644 --- a/bot.py +++ b/bot.py @@ -21,9 +21,9 @@ import logging from datetime import datetime from telegram import ParseMode, InlineKeyboardMarkup, \ - InlineKeyboardButton + InlineKeyboardButton, Update from telegram.ext import InlineQueryHandler, ChosenInlineResultHandler, \ - CommandHandler, MessageHandler, Filters, CallbackQueryHandler + CommandHandler, MessageHandler, Filters, CallbackQueryHandler, CallbackContext from telegram.ext.dispatcher import run_async import card as c @@ -51,7 +51,7 @@ logging.basicConfig( logger = logging.getLogger(__name__) @user_locale -def notify_me(bot, update): +def notify_me(update: Update, context: CallbackContext): """Handler for /notify_me command, pm people for next game""" chat_id = update.message.chat_id if update.message.chat.type == 'private': @@ -67,12 +67,12 @@ def notify_me(bot, update): @user_locale -def new_game(bot, update): +def new_game(update: Update, context: CallbackContext): """Handler for the /new command""" chat_id = update.message.chat_id if update.message.chat.type == 'private': - help_handler(bot, update) + help_handler(update, context) else: @@ -89,88 +89,88 @@ def new_game(bot, update): game.starter = update.message.from_user game.owner.append(update.message.from_user.id) game.mode = DEFAULT_GAMEMODE - send_async(bot, chat_id, + send_async(context.bot, chat_id, text=_("Created a new game! Join the game with /join " "and start the game with /start")) @user_locale -def kill_game(bot, update): +def kill_game(update: Update, context: CallbackContext): """Handler for the /kill command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if update.message.chat.type == 'private': - help_handler(bot, update) + help_handler(update, context) return if not games: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] - if user_is_creator_or_admin(user, game, bot, chat): + if user_is_creator_or_admin(user, game, context.bot, chat): try: gm.end_game(chat, user) - send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) + send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) except NoGameInChatError: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("The game is not started yet. " "Join the game with /join and start the game with /start"), reply_to_message_id=update.message.message_id) else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) @user_locale -def join_game(bot, update): +def join_game(update: Update, context: CallbackContext): """Handler for the /join command""" chat = update.message.chat if update.message.chat.type == 'private': - help_handler(bot, update) + help_handler(update, context) return try: gm.join_game(update.message.from_user, chat) except LobbyClosedError: - send_async(bot, chat.id, text=_("The lobby is closed")) + send_async(context.bot, chat.id, text=_("The lobby is closed")) except NoGameInChatError: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) except AlreadyJoinedError: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("You already joined the game. Start the game " "with /start"), reply_to_message_id=update.message.message_id) except DeckEmptyError: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There are not enough cards left in the deck for " "new players to join."), reply_to_message_id=update.message.message_id) else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Joined the game"), reply_to_message_id=update.message.message_id) @user_locale -def leave_game(bot, update): +def leave_game(update: Update, context: CallbackContext): """Handler for the /leave command""" chat = update.message.chat user = update.message.from_user @@ -178,7 +178,7 @@ def leave_game(bot, update): player = gm.player_for_user_in_chat(user, chat) if player is None: - send_async(bot, chat.id, text=_("You are not playing in a game in " + send_async(context.bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) return @@ -190,23 +190,23 @@ def leave_game(bot, update): gm.leave_game(user, chat) except NoGameInChatError: - send_async(bot, chat.id, text=_("You are not playing in a game in " + send_async(context.bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) except NotEnoughPlayersError: gm.end_game(chat, user) - send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) + send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) else: if game.started: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id) else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=__("{name} left the game before it started.", multi=game.translate).format( name=display_name(user)), @@ -214,11 +214,11 @@ def leave_game(bot, update): @user_locale -def kick_player(bot, update): +def kick_player(update: Update, context: CallbackContext): """Handler for the /kick command""" if update.message.chat.type == 'private': - help_handler(bot, update) + help_handler(update, context) return chat = update.message.chat @@ -228,20 +228,20 @@ def kick_player(bot, update): game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) return if not game.started: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("The game is not started yet. " "Join the game with /join and start the game with /start"), reply_to_message_id=update.message.message_id) return - if user_is_creator_or_admin(user, game, bot, chat): + if user_is_creator_or_admin(user, game, context.bot, chat): if update.message.reply_to_message: kicked = update.message.reply_to_message.from_user @@ -250,40 +250,40 @@ def kick_player(bot, update): gm.leave_game(kicked, chat) except NoGameInChatError: - send_async(bot, chat.id, text=_("Player {name} is not found in the current game.".format(name=display_name(kicked))), + send_async(context.bot, chat.id, text=_("Player {name} is not found in the current game.".format(name=display_name(kicked))), reply_to_message_id=update.message.message_id) return except NotEnoughPlayersError: gm.end_game(chat, user) - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("{0} was kicked by {1}".format(display_name(kicked), display_name(user)))) - send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) + send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) return - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("{0} was kicked by {1}".format(display_name(kicked), display_name(user)))) else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Please reply to the person you want to kick and type /kick again."), reply_to_message_id=update.message.message_id) return - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id) else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) -def select_game(bot, update): +def select_game(update: Update, context: CallbackContext): """Handler for callback queries to select the current game""" chat_id = int(update.callback_query.data) @@ -303,12 +303,12 @@ def select_game(bot, update): def selected(bot): back = [[InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='')]] - bot.answerCallbackQuery(update.callback_query.id, + context.bot.answerCallbackQuery(update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) - bot.editMessageText(chat_id=update.callback_query.message.chat_id, + context.bot.editMessageText(chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "Make sure that you switch to the correct " @@ -322,7 +322,7 @@ def select_game(bot, update): @game_locales -def status_update(bot, update): +def status_update(update: Update, context: CallbackContext): """Remove player from game if user leaves the group""" chat = update.message.chat @@ -337,17 +337,17 @@ def status_update(bot, update): pass except NotEnoughPlayersError: gm.end_game(chat, user) - send_async(bot, chat.id, text=__("Game ended!", + send_async(context.bot, chat.id, text=__("Game ended!", multi=game.translate)) else: - send_async(bot, chat.id, text=__("Removing {name} from the game", + send_async(context.bot, chat.id, text=__("Removing {name} from the game", multi=game.translate) .format(name=display_name(user))) @game_locales @user_locale -def start_game(bot, update, args, job_queue): +def start_game(update: Update, context: CallbackContext): """Handler for the /start command""" if update.message.chat.type != 'private': @@ -356,16 +356,16 @@ def start_game(bot, update, args, job_queue): try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There is no game running in this chat. Create " "a new one with /new")) return if game.started: - send_async(bot, chat.id, text=_("The game has already started")) + send_async(context.bot, chat.id, text=_("The game has already started")) elif len(game.players) < MIN_PLAYERS: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=__("At least {minplayers} players must /join the game " "before you can start it").format(minplayers=MIN_PLAYERS)) @@ -387,19 +387,19 @@ def start_game(bot, update, args, job_queue): def send_first(): """Send the first card and player""" - bot.sendSticker(chat.id, + context.bot.sendSticker(chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) - bot.sendMessage(chat.id, + context.bot.sendMessage(chat.id, text=first_message, reply_markup=InlineKeyboardMarkup(choice), timeout=TIMEOUT) send_first() - start_player_countdown(bot, game, job_queue) + start_player_countdown(context.bot, game, context.job_queue) - elif len(args) and args[0] == 'select': + elif len(context.args) and context.args[0] == 'select': players = gm.userid_players[update.message.from_user.id] groups = list() @@ -414,23 +414,23 @@ def start_game(bot, update, args, job_queue): callback_data=str(player.game.chat.id))] ) - send_async(bot, update.message.chat_id, + send_async(context.bot, update.message.chat_id, text=_('Please select the group you want to play in.'), reply_markup=InlineKeyboardMarkup(groups)) else: - help_handler(bot, update) + help_handler(update, context) @user_locale -def close_game(bot, update): +def close_game(update: Update, context: CallbackContext): """Handler for the /close command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return @@ -438,12 +438,12 @@ def close_game(bot, update): if user.id in game.owner: game.open = False - send_async(bot, chat.id, text=_("Closed the lobby. " + send_async(context.bot, chat.id, text=_("Closed the lobby. " "No more players can join this game.")) return else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) @@ -451,14 +451,14 @@ def close_game(bot, update): @user_locale -def open_game(bot, update): +def open_game(update: Update, context: CallbackContext): """Handler for the /open command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return @@ -466,11 +466,11 @@ def open_game(bot, update): if user.id in game.owner: game.open = True - send_async(bot, chat.id, text=_("Opened the lobby. " + send_async(context.bot, chat.id, text=_("Opened the lobby. " "New players may /join the game.")) return else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) @@ -478,14 +478,14 @@ def open_game(bot, update): @user_locale -def enable_translations(bot, update): +def enable_translations(update: Update, context: CallbackContext): """Handler for the /enable_translations command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return @@ -493,12 +493,12 @@ def enable_translations(bot, update): if user.id in game.owner: game.translate = True - send_async(bot, chat.id, text=_("Enabled multi-translations. " + send_async(context.bot, chat.id, text=_("Enabled multi-translations. " "Disable with /disable_translations")) return else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) @@ -506,14 +506,14 @@ def enable_translations(bot, update): @user_locale -def disable_translations(bot, update): +def disable_translations(update: Update, context: CallbackContext): """Handler for the /disable_translations command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("There is no running game in this chat.")) return @@ -521,13 +521,13 @@ def disable_translations(bot, update): if user.id in game.owner: game.translate = False - send_async(bot, chat.id, text=_("Disabled multi-translations. " + send_async(context.bot, chat.id, text=_("Disabled multi-translations. " "Enable them again with " "/enable_translations")) return else: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Only the game creator ({name}) and admin can do that.") .format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) @@ -536,14 +536,14 @@ def disable_translations(bot, update): @game_locales @user_locale -def skip_player(bot, update): +def skip_player(update: Update, context: CallbackContext): """Handler for the /skip command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if not player: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("You are not playing in a game in this chat.")) return @@ -558,19 +558,19 @@ def skip_player(bot, update): # You can skip yourself even if you have time left (you'll still draw) if delta < skipped_player.waiting_time and player != skipped_player: n = skipped_player.waiting_time - delta - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Please wait {time} second", "Please wait {time} seconds", n) .format(time=n), reply_to_message_id=update.message.message_id) else: - do_skip(bot, player) + do_skip(context.bot, player) @game_locales @user_locale -def reply_to_query(bot, update): +def reply_to_query(update: Update, context: CallbackContext): """ Handler for inline queries. Builds the result list for inline queries and answers to the client. @@ -638,13 +638,13 @@ def reply_to_query(bot, update): if players and game and len(players) > 1: switch = _('Current game: {game}').format(game=game.chat.title) - answer_async(bot, update.inline_query.id, results, cache_time=0, + answer_async(context.bot, update.inline_query.id, results, cache_time=0, switch_pm_text=switch, switch_pm_parameter='select') @game_locales @user_locale -def process_result(bot, update, job_queue): +def process_result(update: Update, context: CallbackContext): """ Handler for chosen inline results. Checks the players actions and acts accordingly. @@ -671,38 +671,38 @@ def process_result(bot, update, job_queue): mode = result_id[5:] game.set_mode(mode) logger.info("Gamemode changed to {mode}".format(mode = mode)) - send_async(bot, chat.id, text=__("Gamemode changed to {mode}".format(mode = mode))) + send_async(context.bot, chat.id, text=__("Gamemode changed to {mode}".format(mode = mode))) return elif len(result_id) == 36: # UUID result return elif int(anti_cheat) != last_anti_cheat: - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=__("Cheat attempt by {name}", multi=game.translate) .format(name=display_name(player.user))) return elif result_id == 'call_bluff': - reset_waiting_time(bot, player) - do_call_bluff(bot, player) + reset_waiting_time(context.bot, player) + do_call_bluff(context.bot, player) elif result_id == 'draw': - reset_waiting_time(bot, player) - do_draw(bot, player) + reset_waiting_time(context.bot, player) + do_draw(context.bot, player) elif result_id == 'pass': game.turn() elif result_id in c.COLORS: game.choose_color(result_id) else: - reset_waiting_time(bot, player) - do_play_card(bot, player, result_id) + reset_waiting_time(context.bot, player) + do_play_card(context.bot, player, result_id) if game_is_running(game): nextplayer_message = ( __("Next player: {name}", multi=game.translate) .format(name=display_name(game.current_player.user))) choice = [[InlineKeyboardButton(text=_("Make your choice!"), switch_inline_query_current_chat='')]] - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=nextplayer_message, reply_markup=InlineKeyboardMarkup(choice)) - start_player_countdown(bot, game, job_queue) + start_player_countdown(context.bot, game, job_queue) def reset_waiting_time(bot, player): diff --git a/internationalization.py b/internationalization.py index 784a0d6..072ee12 100644 --- a/internationalization.py +++ b/internationalization.py @@ -101,7 +101,7 @@ def __(singular, plural=None, n=1, multi=False): def user_locale(func): @wraps(func) @db_session - def wrapped(bot, update, *pargs, **kwargs): + def wrapped(update, context, *pargs, **kwargs): user = _user_chat_from_update(update)[0] with db_session: @@ -112,7 +112,7 @@ def user_locale(func): else: _.push('en_US') - result = func(bot, update, *pargs, **kwargs) + result = func(update, context, *pargs, **kwargs) _.pop() return result return wrapped @@ -121,7 +121,7 @@ def user_locale(func): def game_locales(func): @wraps(func) @db_session - def wrapped(bot, update, *pargs, **kwargs): + def wrapped(update, context, *pargs, **kwargs): user, chat = _user_chat_from_update(update) player = gm.player_for_user_in_chat(user, chat) locales = list() @@ -141,7 +141,7 @@ def game_locales(func): _.push(loc) locales.append(loc) - result = func(bot, update, *pargs, **kwargs) + result = func(update, context, *pargs, **kwargs) while _.code: _.pop() diff --git a/requirements.txt b/requirements.txt index e2d30a7..74133c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -python-telegram-bot==8.1.1 +python-telegram-bot==13.11 pony diff --git a/settings.py b/settings.py index 622d897..9748d6b 100644 --- a/settings.py +++ b/settings.py @@ -18,8 +18,8 @@ # along with this program. If not, see . -from telegram import ReplyKeyboardMarkup -from telegram.ext import CommandHandler, RegexHandler +from telegram import ReplyKeyboardMarkup, Update +from telegram.ext import CommandHandler, Filters, MessageHandler, CallbackContext from utils import send_async from user_setting import UserSetting @@ -29,11 +29,11 @@ from internationalization import _, user_locale @user_locale -def show_settings(bot, update): +def show_settings(update: Update, context: CallbackContext): chat = update.message.chat if update.message.chat.type != 'private': - send_async(bot, chat.id, + send_async(context.bot, chat.id, text=_("Please edit your settings in a private chat with " "the bot.")) return @@ -49,27 +49,27 @@ def show_settings(bot, update): stats = '❌' + ' ' + _("Delete all statistics") kb = [[stats], ['🌍' + ' ' + _("Language")]] - send_async(bot, chat.id, text='πŸ”§' + ' ' + _("Settings"), + send_async(context.bot, chat.id, text='πŸ”§' + ' ' + _("Settings"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True)) @user_locale -def kb_select(bot, update, groups): +def kb_select(update: Update, context: CallbackContext): chat = update.message.chat user = update.message.from_user - option = groups[0] + option = context.match[1] if option == 'πŸ“Š': us = UserSetting.get(id=user.id) us.stats = True - send_async(bot, chat.id, text=_("Enabled statistics!")) + send_async(context.bot, chat.id, text=_("Enabled statistics!")) elif option == '🌍': kb = [[locale + ' - ' + descr] for locale, descr in sorted(available_locales.items())] - send_async(bot, chat.id, text=_("Select locale"), + send_async(context.bot, chat.id, text=_("Select locale"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True)) @@ -79,28 +79,27 @@ def kb_select(bot, update, groups): us.first_places = 0 us.games_played = 0 us.cards_played = 0 - send_async(bot, chat.id, text=_("Deleted and disabled statistics!")) + send_async(context.bot, chat.id, text=_("Deleted and disabled statistics!")) @user_locale -def locale_select(bot, update, groups): +def locale_select(update: Update, context: CallbackContext): chat = update.message.chat user = update.message.from_user - option = groups[0] + option = context.match[1] if option in available_locales: us = UserSetting.get(id=user.id) us.lang = option _.push(option) - send_async(bot, chat.id, text=_("Set locale!")) + send_async(context.bot, chat.id, text=_("Set locale!")) _.pop() - def register(): dispatcher.add_handler(CommandHandler('settings', show_settings)) - dispatcher.add_handler(RegexHandler('^([' + 'πŸ“Š' + - '🌍' + - '❌' + ']) .+$', - kb_select, pass_groups=True)) - dispatcher.add_handler(RegexHandler(r'^(\w\w_\w\w) - .*', - locale_select, pass_groups=True)) + dispatcher.add_handler(MessageHandler(Filters.regex('^([' + 'πŸ“Š' + + '🌍' + + '❌' + ']) .+$'), + kb_select)) + dispatcher.add_handler(MessageHandler(Filters.regex(r'^(\w\w_\w\w) - .*'), + locale_select)) diff --git a/shared_vars.py b/shared_vars.py index a2e1993..86927f9 100644 --- a/shared_vars.py +++ b/shared_vars.py @@ -30,5 +30,5 @@ db.bind('sqlite', os.getenv('UNO_DB', 'uno.sqlite3'), create_db=True) db.generate_mapping(create_tables=True) gm = GameManager() -updater = Updater(token=TOKEN, workers=WORKERS) +updater = Updater(token=TOKEN, workers=WORKERS, use_context=True) dispatcher = updater.dispatcher diff --git a/simple_commands.py b/simple_commands.py index 002f9ca..458ac41 100644 --- a/simple_commands.py +++ b/simple_commands.py @@ -17,8 +17,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from telegram import ParseMode -from telegram.ext import CommandHandler +from telegram import ParseMode, Update +from telegram.ext import CommandHandler, CallbackContext from user_setting import UserSetting from utils import send_async @@ -26,7 +26,7 @@ from shared_vars import dispatcher from internationalization import _, user_locale @user_locale -def help_handler(bot, update): +def help_handler(update: Update, context: CallbackContext): """Handler for the /help command""" help_text = _("Follow these steps:\n\n" "1. Add this bot to a group\n" @@ -64,11 +64,11 @@ def help_handler(bot, update): "update channel" " and buy an UNO card game.") - send_async(bot, update.message.chat_id, text=help_text, + send_async(context.bot, update.message.chat_id, text=help_text, parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale -def modes(bot, update): +def modes(update: Update, context: CallbackContext): """Handler for the /help command""" modes_explanation = _("This UNO bot has four game modes: Classic, Sanic, Wild and Text.\n\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto skip.\n" @@ -77,11 +77,11 @@ def modes(bot, update): " ✍️ The Text mode uses the conventional UNO deck but instead of stickers it uses the text.\n\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a space, " "just like when playing a card, and all gamemode options should appear.") - send_async(bot, update.message.chat_id, text=modes_explanation, + send_async(context.bot, update.message.chat_id, text=modes_explanation, parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale -def source(bot, update): +def source(update: Update, context: CallbackContext): """Handler for the /help command""" source_text = _("This bot is Free Software and licensed under the AGPL. " "The code is available here: \n" @@ -94,25 +94,25 @@ def source(bot, update): "Originals available on http://game-icons.net\n" "Icons edited by Ι³ick") - send_async(bot, update.message.chat_id, text=source_text + '\n' + + send_async(context.bot, update.message.chat_id, text=source_text + '\n' + attributions, parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale -def news(bot, update): +def news(update: Update, context: CallbackContext): """Handler for the /news command""" - send_async(bot, update.message.chat_id, + send_async(context.bot, update.message.chat_id, text=_("All news here: https://telegram.me/unobotupdates"), disable_web_page_preview=True) @user_locale -def stats(bot, update): +def stats(update: Update, context: CallbackContext): user = update.message.from_user us = UserSetting.get(id=user.id) if not us or not us.stats: - send_async(bot, update.message.chat_id, + send_async(context.bot, update.message.chat_id, text=_("You did not enable statistics. Use /settings in " "a private chat with the bot to enable them.")) else: @@ -140,7 +140,7 @@ def stats(bot, update): n).format(number=n) ) - send_async(bot, update.message.chat_id, + send_async(context.bot, update.message.chat_id, text='\n'.join(stats_text)) diff --git a/utils.py b/utils.py index e32f51e..20768a5 100644 --- a/utils.py +++ b/utils.py @@ -20,11 +20,9 @@ import logging -from telegram.ext.dispatcher import run_async - from internationalization import _, __ from mwt import MWT -from shared_vars import gm +from shared_vars import gm, dispatcher logger = logging.getLogger(__name__) @@ -82,26 +80,24 @@ def error(bot, update, error): logger.exception(error) -@run_async def send_async(bot, *args, **kwargs): """Send a message asynchronously""" if 'timeout' not in kwargs: kwargs['timeout'] = TIMEOUT try: - bot.sendMessage(*args, **kwargs) + dispatcher.run_async(bot.sendMessage, *args, **kwargs) except Exception as e: error(None, None, e) -@run_async def answer_async(bot, *args, **kwargs): """Answer an inline query asynchronously""" if 'timeout' not in kwargs: kwargs['timeout'] = TIMEOUT try: - bot.answerInlineQuery(*args, **kwargs) + dispatcher.run_async(bot.answerInlineQuery, *args, **kwargs) except Exception as e: error(None, None, e) From f11df72b0b221cfae8825f60d59a84a2fcc85394 Mon Sep 17 00:00:00 2001 From: tehcneko <88844448+tehcneko@users.noreply.github.com> Date: Sun, 13 Feb 2022 22:34:17 +0800 Subject: [PATCH 2/3] Fix --- actions.py | 9 +++++---- bot.py | 16 +++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/actions.py b/actions.py index deefea6..9a03bd2 100644 --- a/actions.py +++ b/actions.py @@ -6,6 +6,7 @@ import card as c from datetime import datetime from telegram import Message, Chat +from telegram.ext import CallbackContext from config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME from errors import DeckEmptyError, NotEnoughPlayersError @@ -205,9 +206,9 @@ def start_player_countdown(bot, game, job_queue): player.game.job = job -def skip_job(bot, job): - player = job.context.player +def skip_job(context: CallbackContext): + player = context.job.context.player game = player.game if game_is_running(game): - job_queue = job.context.job_queue - do_skip(bot, player, job_queue) + job_queue = context.job.context.job_queue + do_skip(context.bot, player, job_queue) diff --git a/bot.py b/bot.py index 4ce5ce1..b1ccf5d 100644 --- a/bot.py +++ b/bot.py @@ -299,16 +299,15 @@ def select_game(update: Update, context: CallbackContext): text=_("Game not found.")) return - @run_async - def selected(bot): + def selected(): back = [[InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='')]] - context.bot.answerCallbackQuery(update.callback_query.id, + dispatcher.run_async(context.bot.answerCallbackQuery, update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) - context.bot.editMessageText(chat_id=update.callback_query.message.chat_id, + dispatcher.run_async(context.bot.editMessageText, chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "Make sure that you switch to the correct " @@ -318,7 +317,7 @@ def select_game(update: Update, context: CallbackContext): parse_mode=ParseMode.HTML, timeout=TIMEOUT) - selected(bot) + selected() @game_locales @@ -383,15 +382,14 @@ def start_game(update: Update, context: CallbackContext): multi=game.translate) .format(name=display_name(game.current_player.user))) - @run_async def send_first(): """Send the first card and player""" - context.bot.sendSticker(chat.id, + dispatcher.run_async(context.bot.sendSticker, chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) - context.bot.sendMessage(chat.id, + dispatcher.run_async(context.bot.sendMessage, chat.id, text=first_message, reply_markup=InlineKeyboardMarkup(choice), timeout=TIMEOUT) @@ -702,7 +700,7 @@ def process_result(update: Update, context: CallbackContext): send_async(context.bot, chat.id, text=nextplayer_message, reply_markup=InlineKeyboardMarkup(choice)) - start_player_countdown(context.bot, game, job_queue) + start_player_countdown(context.bot, game, context.job_queue) def reset_waiting_time(bot, player): From c9e52174e12d8fa62841a46750837f18e2a8caa5 Mon Sep 17 00:00:00 2001 From: NekoInverter Date: Thu, 3 Mar 2022 16:18:53 +0800 Subject: [PATCH 3/3] Apply fixes from @jh0ker --- actions.py | 6 +++++- bot.py | 13 +++++++------ internationalization.py | 19 ++++--------------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/actions.py b/actions.py index 9a03bd2..58a45a6 100644 --- a/actions.py +++ b/actions.py @@ -7,6 +7,7 @@ from datetime import datetime from telegram import Message, Chat from telegram.ext import CallbackContext +from apscheduler.jobstores.base import JobLookupError from config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME from errors import DeckEmptyError, NotEnoughPlayersError @@ -192,7 +193,10 @@ def start_player_countdown(bot, game, job_queue): if game.mode == 'fast': if game.job: - game.job.schedule_removal() + try: + game.job.schedule_removal() + except JobLookupError: + pass job = job_queue.run_once( #lambda x,y: do_skip(bot, player), diff --git a/bot.py b/bot.py index b1ccf5d..b2825d5 100644 --- a/bot.py +++ b/bot.py @@ -49,6 +49,7 @@ logging.basicConfig( level=logging.INFO ) logger = logging.getLogger(__name__) +logging.getLogger('apscheduler').setLevel(logging.WARNING) @user_locale def notify_me(update: Update, context: CallbackContext): @@ -302,12 +303,12 @@ def select_game(update: Update, context: CallbackContext): def selected(): back = [[InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='')]] - dispatcher.run_async(context.bot.answerCallbackQuery, update.callback_query.id, + context.bot.answerCallbackQuery(update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) - dispatcher.run_async(context.bot.editMessageText, chat_id=update.callback_query.message.chat_id, + context.bot.editMessageText(chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "Make sure that you switch to the correct " @@ -317,7 +318,7 @@ def select_game(update: Update, context: CallbackContext): parse_mode=ParseMode.HTML, timeout=TIMEOUT) - selected() + dispatcher.run_async(selected) @game_locales @@ -385,16 +386,16 @@ def start_game(update: Update, context: CallbackContext): def send_first(): """Send the first card and player""" - dispatcher.run_async(context.bot.sendSticker, chat.id, + context.bot.sendSticker(chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) - dispatcher.run_async(context.bot.sendMessage, chat.id, + context.bot.sendMessage(chat.id, text=first_message, reply_markup=InlineKeyboardMarkup(choice), timeout=TIMEOUT) - send_first() + dispatcher.run_async(send_first) start_player_countdown(context.bot, game, context.job_queue) elif len(context.args) and context.args[0] == 'select': diff --git a/internationalization.py b/internationalization.py index 072ee12..f56a20c 100644 --- a/internationalization.py +++ b/internationalization.py @@ -151,21 +151,10 @@ def game_locales(func): def _user_chat_from_update(update): + user = update.effective_user + chat = update.effective_chat - try: - user = update.message.from_user - chat = update.message.chat - except (NameError, AttributeError): - try: - user = update.inline_query.from_user - chat = gm.userid_current[user.id].game.chat - except KeyError: - chat = None - except (NameError, AttributeError): - try: - user = update.chosen_inline_result.from_user - chat = gm.userid_current[user.id].game.chat - except (NameError, AttributeError, KeyError): - chat = None + if chat is None and user is not None and user.id in gm.userid_current: + chat = gm.userid_current.get(user.id).game.chat return user, chat