0

I have a major issue that too many Pygame users has, I want to take input from user in Pygame. I probably check all informations in internet,include stackoverflow, nothing solved.

So I decide to make a solution, I created another Python script(I convert it to .exe so subprocess can open it) that asking question to user before Pygame is running, after then that script saving user's data into a .txt file(like a database).Then in Pygame I opening that .txt file and taking the data. Therocially it's working, but problem is, I have to tell Pygame, while subprocess is processing, wait for it. That's how I can dodge errors like IndexError etc. Because I'm using readlines() and untill that .exe file is closed, Pygame has to wait, if not; readlines() giving data as list and it throwing IndexError normally. So Pygame has to wait untill I put the data in that .exe file. Let me explain with my codes;

This is the script that taking data from user(I converted it to exe already so subprocess can open):

#!/usr/bin/env python
# -*-coding:utf-8-*-

while True:
    user=input("Please enter your name: ")
    try:
        user_age=int(input("Please enter your age: "))
    except ValueError:
        print ("Invalid characters for 'age', try again.")
        continue
    ask_conf=input("Are you confirm these informations?(Y/N): ")
    if ask_conf.lower()=="y":
        with open("informations.txt","w") as f: #create the file
            f.write(user+"\n")
            f.write(str(user_age))
        break
    else:
        continue

And then, in Pygame, I'am opening this .exe file, but Pygame won't wait and normally I'm getting error.

pygame.init()
subprocess.Popen(["wtf.exe"]) #the exe file that taking data from user 
                              #and saving it in "informations.txt"
#codes..
....
....
author = pygame.font.SysFont("comicsansms",25)
with open("informations.txt") as f:
    rd=f.readlines()
author1 = author.render("{}".format(rd[0][0:-1]),True,blue) #Pygame won't wait 
                                                            #so getting IndexError here
age = pygame.font.SysFont("comicsansms",25)
age1 = age.render("{}".format(rd[1]),True,blue)
...
...
...
gameDisplay.blit(author1,(680,15))
gameDisplay.blit(age1,(720,40))

This method is almost working, I thought finally I got the solution of this input problem in Pygame.But I don't know how to tell Pygame, wait untill I'm done with .exe file, then process your codes.

  • You could use `os.system("wtf.exe")` instead. – Constantinius Jan 03 '15 at 20:44
  • you do not need to convert Python script to exe, to run it as a subprocess (`[sys.executable, '/path/to/script']` as a command would work). You do not need to run a Python script as a subprocess in order to execute some Python code without blocking the pygame event loop (you could use `threading`, `multiprocessing`, `concurrent.futures`, `asyncio` modules instead). You should not use `input()` to get user input in a GUI application e.g., see [code near `evt.unicode.isalpha()`](http://stackoverflow.com/a/14112370/4279) for one possible alternative. – jfs Jan 05 '15 at 08:36

1 Answers1

1

Use the communicate method:

Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.

So this is the code to do it:

process = subprocess.Popen(["wtf.exe"])
# block until process done
output, errors = process.communicate()

Edit:

As @Padraic suggests, you can use check_call, which is more informative when failing:

try:
    subprocess.check_call([’wtf.exe’])
except subprocess.CalledProcessError:
    pass # handle errors in the called executable
except OSError:
    pass # executable not found

Another option is call:

Run the command described by args. Wait for command to complete, then return the returncode attribute.

So something like this:

returncode = subprocess.call(["wtf.exe"])

And you can also use wait if you don't care about the data and just want the return code to see if something bad happened. But documentation says you should prefer communicate:

Warning: This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.

Community
  • 1
  • 1
Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88
  • It solved.I actually want to learn how this _communicate()_ works? _output,errors_ ? Can you explain it more please and let me check it as correct answer. –  Jan 03 '15 at 20:48
  • check_call may be a better option. – Padraic Cunningham Jan 03 '15 at 20:50
  • @PadraicCunningham What is the difference between them, could you tell me please? –  Jan 03 '15 at 20:50
  • @PadraicCunningham Why is it favoured over `call`? I use `communicate` most of the time anyway... – Reut Sharabani Jan 03 '15 at 20:51
  • @grrr I added information from the docs for each method, and the names for each function are actual links to the docs. – Reut Sharabani Jan 03 '15 at 20:52
  • if you get a non zero value returned check_call will will raise an error which may be preferable unless you wanted to ignore errors. – Padraic Cunningham Jan 03 '15 at 20:53
  • @PadraicCunningham , yeah, just saw that in the docs and in SO, updated answer. – Reut Sharabani Jan 03 '15 at 20:55
  • @ReutSharabani Can I use _subprocess.Popen_ with whole path of file? like _subprocess.Popen([r"C:\Users\pc\Desktop\DENIYORUZFENA\wtf.exe"])_ –  Jan 03 '15 at 21:07
  • @grrr I'm not too familiar with windows, but if you can do it in the terminal, it'll probably work. – Reut Sharabani Jan 03 '15 at 21:27
  • downvote. Don't use `.communicate()` unless you want to pass input/read subprocess' output i.e., remove `Popen().communicate()` (or add something like `stdout=PIPE` to the code), leave `call(cmd)` or `p = Popen(cmd); ...; p.wait()`. – jfs Jan 05 '15 at 07:14