0

When I initiate the beep test command, it does not play the audio and instead brings back the menu, then plays the timer that then prints the message, almost like multiprocessing.Process() got skipped. Did I forget to call a function?

I tried a range of things, up to having a separate .py file imported to replace multitasking(), but the logical error remained through every of my attempts. A note is that the .py file works on its own, maybe the ifs or third party functions could be messing with the code.

import os, playsound, multiprocessing, time

cwd= os.getcwd()
def beep_test():
    audio= "".join((cwd+"\\BTsound.mp3"))
    playsound.playsound(audio,True)

def multitasking():
            sound_process = multiprocessing.Process(target=beep_test)
            sound_process.start()

            timer = 10

            while timer > 0 and sound_process.is_alive(): 
                time.sleep(1) 
                print(f"..{timer}") 
                timer -= 1

            if timer == 0: 
                sound_process.terminate()
                print("Time's up, runners must grab a water bottle and walk around. Do not sit down.")

comm_mode=input("""How would you like to input your commands?
1. Silent (Typed)
2. Prod (Speech Recognition)
""")
if __name__ == "__main__":
    if "1" in comm_mode:
        while True:
            try:
                message = input("Type 'ghost' to begin.\n")
            except:
                message = input("")
            if "ghost" in message:
                print("GHOST online")
                message = input("What do you need?\n")

                if "begin beep test" in message:
                    multitasking()
                            
    else:
        print("Don't worry about it, error's on 1.")

The different function is this one:

import os, playsound, multiprocessing, time
cwd = os.getcwd()
def beep_test():
    audio= "".join((cwd+"\\beep-test-audio.mp3"))
    playsound.playsound(audio,True)

def thingy():
        sound_process = multiprocessing.Process(target=beep_test)
        sound_process.start()

        timer = 10

        while timer > 0 and sound_process.is_alive(): 
            time.sleep(1) 
            print(f"..{timer}") 
            timer -= 1

        if timer == 0: 
            sound_process.terminate()
            print("Time's up, runners must grab a water bottle and walk around. Do not sit down.")

print(__name__)
if __name__ == "__main__":
    
    thingy()
  • Strangely it seems like you forgot to mention what you've done so far to regarding basic [debugging](https://www.jetbrains.com/help/pycharm/debugging-your-first-python-application.html) of this...I mean, you surely debugged it before posting here, right? Did you put in breakpoints or print statements to see which lines were getting hit? Do you have the output of those sessions? Can you share that debugging info here so we don't have to do it all over again ourselves? – Random Davis May 05 '23 at 16:02
  • @RandomDavis I've troubleshot it, but I haven't exactly used the debug feature of VSCode. I'll check it out to see if anything pops up. Edit: Just checked it, it only mentions a frozen module – Cassidy Mettraux May 05 '23 at 16:05
  • putting `comm_mode=input("""How ....` outside `if __name__ .... ` will cause it to be executed in child processes when the child imports the main file in order to get access to the `target` function. stdin is not forwarded to the child, so it will wait forever on `input`. – Aaron May 05 '23 at 16:36
  • That seemed to have fixed my issue, thank @Aaron. – Cassidy Mettraux May 05 '23 at 16:44

1 Answers1

0

This is a problem of having side-effects on import. Python multiprocessing starts a fresh process which then must import the main file to access the target function (as well as user defined class definitions if the target is a method, or the args contain instances of such a class.)

Leaving an input statement outside if __name__ == "__main__": will cause the child process to execute that input statement during that import, and wait for some text to arrive on the sys.stdin file handle. There is not a new stdin created for the child however, and the child actually has stdin redirected to os.devnull. The child will therefore be stuck waiting for input to come in from a specifically empty file handle.

The solution is to move the input(... statement inside the import protection of if __name__ == "__main__":.

Even when you don't plan on using multiprocessing it's a good habit to use import protection and put your scripts inside a "main" function which is called behind this protection. This way if you want to re-use a function you made in the future, there is no work to be done to convert your script to a library which doesn't do all sorts of unwanted things just from importing it.

Aaron
  • 10,133
  • 1
  • 24
  • 40