How to terminate wait_for() when a condition is no longer met?

Question:

My discord.py command for a bot is supposed to activate a while loop under the condition that a specific variable has a certain value (with a wait_for() coroutine within it):

cond = True

@bot.command()
async def test(ctx):
    global cond

    def check(m):
        m.author == ctx.message.author and m.channel == ctx.message.channel

    while cond is True: 
        try:
            msg = await bot.wait_for('message', check=check, timeout=7200) # 2 hours
            print('Message found!')

        except asyncio.TimeoutError:
            print('No message was found.')

It only executes while cond is True, however cond can change while wait_for() is running (I used a global variable for the example), and since this is a while loop it doesn’t terminate during runtime if the condition is no longer met, rather it applies to the next iteration.

I want wait_for() immediately terminate soon as cond is no longer True, and any code following to not execute (including the except block). Alternatively the while loop could be terminated some way while wait_for() is running.

How can I achieve this?

Asked By: Angel

||

Answers:

We know that wait_for immediatly terminates when its condition is met. We can use this to just add the loop condition into the wait_for condition as follows:

(wait_for condition) or not (loop condition)

The if the loop condition does no longer hold, we exit the wait_for. After we exit we also have to check if we exited the wait_for because of the loop condition or the actual thing we’re waiting for. We only actually execute the code if it’s the former.

Hence you can rewrite the code as follows:

cond = True

@bot.command()
async def test(ctx):
    global cond

    def check(m):
        (m.author == ctx.message.author and m.channel == ctx.message.channel) or not cond

    while cond is True: 
        try:
            msg = await bot.wait_for('message', check=check, timeout=7200) # 2 hours       
            if (cond):
                # we only want to continue here if the loop condition still holds
                print('Message found!')

        except asyncio.TimeoutError:
            print('No message was found.')
Answered By: chluebi
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.