-2

I'm working on a bot with the Python-Telegram-Bot API. Right now I'm updating the bot menu with InlineKeyboardButtons instead of ?menu, ?info type of commands (like on Discord). But I came across some trouble. Let me explain step by step what the command is supposed to do:

Step 1 - User opens up the menu (a commandhandler)

Step 2 - InlineKeyboardButtons load, one of them has an option called "Jokenpo" for the game

Step 3 - I set its callback_data to load a message greeting the player and showing the rules (def jkpMenu).

Step 4 - Then def jkpMenu is supposed to go to the next state, that is def jokenpo. During the function, there's a loop for receiving input like paper, rock, scissors that keeps repeting until user types stop or loses their lives.

varScore = 0
varLives = 5
varTie = 0
JKP = range(2)

...

def menuTest(update: Update, _: CallbackContext) -> int:
    commands = [
        [InlineKeyboardButton(text=' | Changelog',  callback_data='clog'), InlineKeyboardButton(text=' | Info',  callback_data='info')],
        [InlineKeyboardButton(text=' | Jokenpo',  callback_data='jokenpo')]]
    update.message.reply_text("Menu:\n", reply_markup=InlineKeyboardMarkup(commands))

def comQuery(update: Update, context: CallbackContext) -> None:
    query = update.callback_query
    query.answer()
    if query.data == 'clog':        changelog(update, context)
    if query.data == 'info':        myInfo(update, context) 
    if query.data == 'jokenpo':     jkpMenu(update, context)

#Jokenpo 1: greetings and rules
def jkpMenu(update: Update, _: CallbackContext) ->JKP:
    update.callback_query.message.reply_text('Jokenpo mode. Please type "rock", "paper" or "scissors" to continue')
    return JKP

#Jokenpo 2: 
def jokenpo(update: Update, _:CallbackContext):
    msgUser = update.callback_query.message.text.lower()
    global varScore
    global varLives
    global varTie
    while True:
        computer = ("rock", "paper", "scissors")
        computer = random.choice(computer)
        if (msgUser== "rock" and computer == "paper") or (msgUser== "paper" and computer == "scissors") or (msgUser=="scissors" and computer == "rock"):
            update.callback_query.message.reply_text("Computer chooses <i>" + computer + "</i>. <b>You lose!</b>", parse_mode ='HTML')
            varLives -= 1
        if (msgUser== "rock" and computer == "scissors") or (msgUser == "paper" and computer == "rock") or (msgUser == "scissors" and computer == "paper"):
            update.callback_query.message.reply_text("Computer chooses <i>" + computer + "</i>. <b>You win!</b>", parse_mode ='HTML')
            varScore +=1
        if (msgUser== computer):
            update.callback_query.message.reply_text("We both chose <i>" + computer +"</i>. <b>It's a tie!</b>", parse_mode ='HTML')
            varTie +=1
        if (msgUser== "status"):
            update.callback_query.message.reply_text("Your current score: " + str(varScore) + " points.\nYou have "+ str(varLives)+ " lives left.\nWe tied " + str(varTie) +' times.')
        if (msgUser== "sair") or (varLives == 0):
            update.callback_query.message.reply_text("Game finished. You made <b>" + str(varScore) + "</b> points.\nWe tied " + str(varTie) +' times.\n', parse_mode ='HTML')
            varScore = 0
            varTie = 0
            varLives = 5
            return ConversationHandler.END
        update.callback_query.message.reply_text('Please choose: paper, rock or scissors? ')
        return

...
...

def(main):
convHandler = ConversationHandler(
        entry_points=[jokenpo],
        fallbacks=[],
        states = {
            JKP: [MessageHandler(Filters.text, jokenpo)]
        })
    dp.add_handler(convHandler)

Problem is: I managed to do that before, when I used CommandHandlers to access the function and it worked. But now it only reaches the first function (Step 3), it seems it doesn't return to the state I wanted. When I changed return JKP for return jokenpo(update,_) it did access def jokenpo, but it didn't wait for any answer.

When I set the inline buttons, since they use CallbackContext, I'm confused on how to handle arguments.

I copied only some part of the code, not it complete, since the other parts are related to other functions. Any help is appreciated.

1 Answers1

1

I see several issues in your code snippet & description:

  1. using global variables is in general bad practice. If you want to store user/chat related data, I suggest to use PTBs built-in mechanism for that. see here.
  2. The while True loop in jokenpo doesn't make any sense. In fact, at the end of the body of the loop, you return anyway, so the body is executed exactly once.
  3. As entry points for your conversation you use entry_points = [jokenpo], but jokenpo is a function and not a handler
  4. In the state JKP you have a handler MessageHandler(Filters.text, jokenpo). This means that the update that will be passed to jokenpo will have update.(edited_)message/channel_post, but never update.callback_query - yet you try to access this attribute within jokenpo.
  5. "Then def jkpMenu is supposed to go to the next state, that is def jokenpo" - the callback jkpMenu is not part of your ConversationHandler at all and hence the return value will be ignored completely.
  6. "When I changed return JKP for return jokenpo(update,_) it did access def jokenpo, but it didn't wait for any answer." Sure - you called the function. But waiting for input can only work if the conversationhandler is started, which this doesn't do
  7. "When I set the inline buttons, since they use CallbackContext, I'm confused on how to handle arguments." This one I just don't understand. What do you mean by "arguments" in the context of inline buttons and what does that have to do with CallbackContext?

I have the impression that you need to deepen your understanding of how PTB is supposed to be used, especially ConversationHandler. I suggest to have a look at the introductory example. Following the flow chart & tracking the executed code while running the example should help to get a better understanding of what's going on. Also reading the documentation of ConversationHandler should clarify some things.


Disclaimer: I'm currently the maintainer of python-telegram-bot.

Also for completeness sake: This was already discussed to some extend in the usergroup of PTB, see https://t.me/pythontelegrambotgroup/513856

CallMeStag
  • 5,467
  • 1
  • 7
  • 22