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:
- I have read some other stackoverflow post that related to this problem but it is kinda different because either they don't have
input()
in the answer file they want to check, or they do input viasys.args
. - I have tried
pexpect
but but apparently it doesn't apply to windows os - I have tried
wexpect
it is likepexpect
but for windows, but i have an installation problem withpywin32
- I tried
runpy
but we have to input manually - I tried
subprocess
module
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 :)
CodePudding user response:
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)
CodePudding user response:
A much better design is to refactor the code to not require interactive I/O.
a.py
:
def make_res(a):
return a*2
def main():
a = input('input a: ')
res = make_res(a)
print(res)
if __name__ == "__main__":
main()
answer_check.py
:
from .a import make_res
if make_res(value) == desired_output:
score = 100
CodePudding user response:
After a bit of testing myself, you could use subprocess to invoke the script to be tested from the test script and then import the script being tested as a module and call the variables. I set it up like this
import importlib
import subprocess
script='a'
subprocess.call(script '.py', shell=True)
script=importlib.import_module(script, package=None)
a=script.a
res=script.res
if a*2 == res:
score=100
And then the tested script needs a small correction to make the input actually be a number, so just put int() around the input like this
a= int(input('input a: '))
res= a*2
CodePudding user response:
Missing: timeout=None
import pexpect
child = pexpect.spawn('python3 test.py')
fout = open('mylog.txt','wb')
child.logfile = fout
child.expect('input a: ', timeout=None)
child.sendline('2')
child.expect('22', timeout=None)