0

I have a while True statement, and inside that I have a for loop. I'd like to run the function first_start only once for each app.

I already tried the query below, but it don't seems to work:

while True:
    do_first_start = True
    for app in applications:
        if do_first_start:
            # Reloading page before start the bot
            await asyncio.create_task(first_start(app_name=bot))
            do_first_start = False

I also took a look on this question from @Marcus Ottosson, but I couldn't make it work as well.

My script:

while True:
    do_first_start = True
    for app in applications:
            bot = app.split(':')[1].strip()
            print('Going to bot: ' + str(bot))
            app = Desktop(backend="uia").windows(title=app)[0]
            app.set_focus()

            if do_first_start:
                # Reloading page before start the bot
                await asyncio.create_task(first_start(app_name=bot))
                do_first_start = False

            # Steps of this bot:
            # - Connect Wallet
            await asyncio.create_task(connect_wallet(app_name=bot))
            # - Login
            await asyncio.create_task(login_metamask(app_name=bot))
            # - Treasure Hunt
            await asyncio.create_task(treasure_hunt_game(refresh_only=True, app_name=bot))
            # - New map
            await asyncio.create_task(new_map(app_name=bot))
            # - Check for errors
            await asyncio.create_task(skip_error_on_game(app_name=bot))

What would be the best way to run the function only once in this case?

Guilherme Matheus
  • 573
  • 10
  • 30
  • Write `app` to a set after you've called `first_start()` for that app. Test if `app` is already in the set before calling `first_start()`. – jarmod Jan 21 '22 at 19:41
  • You're pretty close with the above, but you have to set the flag OUTSIDE of the while loop. The way you're doing it you're setting the flag to true on each iteration. – Jazz Weisman Jan 21 '22 at 19:54
  • However, if you want to run *each* `app`, you need to wait until the `for` loop is done to set `do_first_start = False`. – chepner Jan 21 '22 at 19:54
  • Can `applications` change between iterations of the `while` loop? – chepner Jan 21 '22 at 19:55
  • @chepner No! applications don't change. And I'd like to run each `app` as you said. – Guilherme Matheus Jan 21 '22 at 20:13

2 Answers2

0

Use a flag to keep track of whether this is the first iteration of the outer while True loop. Initialize this flag to true, then set it to false at the end of the loop.

firstloop = True
while True:
    for app in applications:
        if firstloop:
            # run first_start for this app
        # do other stuff with this app
    firstloop = False
John Gordon
  • 29,573
  • 7
  • 33
  • 58
0

I would probably just pull the code that starts the app out of the while loop altogether, then replace the while loop with an infinite sequence of repeating bots.

from itertools import cycle


# Iterate through applications *once*, starting the app
# and creating the related bot name for future use.
bots = []
for app in applications:
    bot = app.split(':')[1].strip()
    print('Going to bot: ' + str(bot))
    app = Desktop(backend="uia").windows(title=app)[0]
    app.set_focus()
    await asyncio.create_task(first_start(app_name=bot))
    bots.append((app, bot))

# Cycle through the bots in one loop rather than restarting
# the loop in an infinite loop.
for app, bot in cycle(bots): 
    app.set_focus()
    await asyncio.create_task(connect_wallet(app_name=bot))
    await asyncio.create_task(login_metamask(app_name=bot))
    await asyncio.create_task(treasure_hunt_game(refresh_only=True, app_name=bot))
    await asyncio.create_task(new_map(app_name=bot))
    await asyncio.create_task(skip_error_on_game(app_name=bot))
chepner
  • 497,756
  • 71
  • 530
  • 681
  • I didn't know this solution! Does `cycle` do the same as `while True`? `app` is the same `list ` as `bots` in this answer right? Should `cycle` run in `app list` instead of `bots` or not in this case? – Guilherme Matheus Jan 21 '22 at 20:11
  • `cycle` just creates an iterator that goes back to the beginning of the argument each time you finish one complete cycle. For example, `cycle([1,2])` yields `1, 2, 1, 2, 1, 2, 1, 2, ...`. – chepner Jan 21 '22 at 20:24
  • Your original `while` loop only used the actual value of `app` to create the value of `bot` and start the app; there's no need to do that repeatedly, so I saved the values of `bots` in the first loop to avoid reconstructing it each time from the original value of `app`. – chepner Jan 21 '22 at 20:25
  • Got it! Definitely your code looks better, however I still need to open the app in the loop using `app.set_focus()`, and use `bot` to run in those functions. What would be the best way in this case? – Guilherme Matheus Jan 21 '22 at 21:40
  • Should I change `applications` list to a nested list by appending `bot` into it (or chage to a dict)? So I can use both? Iterate `app` and `bot` then. – Guilherme Matheus Jan 22 '22 at 19:07
  • You can; I'm not sure I see the need to, since `app` isn't used in the second loop at all. – chepner Jan 22 '22 at 19:39
  • But `app` is being called only once after finishing `applications`, I need to call `app` in the `cycle` as well in order to call `app.set_focus()`, so I can run all `asyncio` functions. – Guilherme Matheus Jan 22 '22 at 19:42
  • Ok, then sure, a `dict` or list of pairs would be fine. (Not knowing what API you are using, it wasn't obvious that `app.set_focus()` was necessary for the subsequent calls.) – chepner Jan 22 '22 at 19:49
  • Updated to store a pair `(app, bot)` in the list `bots` for use in the second loop. – chepner Jan 22 '22 at 19:51
  • You're the man! Thank you very much. – Guilherme Matheus Jan 22 '22 at 20:12
  • I noticed that `app.set_focus()` is running before all `async` functions runs for each app. But I didn't understand why, can you help me please? – Guilherme Matheus Jan 23 '22 at 17:53