pythonautomationsubprocesspexpectwexpect

How to write a code to get another python script output that require an input


I want to give score to several python scripts written by different people and i want to automate the answer check since the given question is same. So we send an input to another python file, we get the output (the terminal/console output) then we compare it, all that within a python file (Like hackerrank, uri, or another competitive programming website)

For example the problem is to multiply the given input by 2. Then i have one python script answer_check.py to automate answer checking, and i have another python script which is one of the answer a.py.

a.py:

a= int(input('input a: '))
res= a*2

print(res)

answer_check.py:

# Some code to send input to a.py

# Then some code to get the console output from a given input

if given_output==desired_output:
    score= 100

What i have tried:

from subprocess import Popen, PIPE

p = Popen("python a.py", stdin=PIPE, stdout=PIPE, shell=False)
out = p.communicate(input='1', timeout=5)
print(out)

But it give me this error

  File "a.py", line 1, in <module>
    a= input('input a: ')
EOFError: EOF when reading a line
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp1252'>
OSError: [Errno 22] Invalid argument

If you know please answer even though it is on another language :)


Solution

  • subprocess.Popen.communicate docs claims that

    Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate and set the returncode attribute. The optional input argument should be data to be sent to the child process, or None, if no data should be sent to the child. If streams were opened in text mode, input must be a string. Otherwise, it must be bytes.

    So you should provide bytes, not str, that is your example should be altered to

    from subprocess import Popen, PIPE
    
    p = Popen("python a.py", stdin=PIPE, stdout=PIPE, shell=False)
    out = p.communicate(input=b'1', timeout=5)
    print(out)
    

    If you need to prepare input from str use .encode() for example

    from subprocess import Popen, PIPE
    myinput = '1'
    p = Popen("python a.py", stdin=PIPE, stdout=PIPE, shell=False)
    out = p.communicate(input=myinput.encode(), timeout=5)
    print(out)