0

I want to write a program in Python which takes a C program as input, executes it against the test cases which are also as inputs and print the output for each test case. I am using Windows

I tried with subprocess.run but it is not accepting inputs at runtime (i.e dynamically)

from subprocess import *
p1=run("rah.exe",input=input(),stdout=PIPE,stderr=STDOUT,universal_newlines=True)
print(p1.stdout)

C code:

#include<stdio.h>
void main()
{
 printf("Enter a number");
 int a;
 scanf("%d",&a);
 for(int i=0;i<a;i++)
 {
 printf("%d",i);
 }
}

Expected Output on python idle:

Enter a number
5
01234 

Actual Output:

5
Enter a number 01234
hynekcer
15.7k6 gold badges66 silver badges102 bronze badges
asked Apr 9, 2019 at 19:30
2
  • 1
    It is accepting inputs at runtime, you are just calling input before run. You probably want to look at Popen.communicate Commented Apr 9, 2019 at 19:43
  • can u please provide me the exact code Commented Apr 9, 2019 at 20:54

2 Answers 2

1

I agree with @juanpa.arrivillaga's suggestion. You can use subprocess.Popen and communicate() for that:

import subprocess
import sys
p = subprocess.Popen('rah.exe', stdout=sys.stdout, stderr=sys.stderr)
p.communicate()

Update: The script above won't work on IDLE because IDLE changes the IO objects sys.stdout, sys.stderr which breaks the fileno() function. If possible, you should put the code into the a python file (for example script.py) and then run it from the Windows command line using the command:

python script.py

or if not, you can do something similar to IDLE on the command line on Windows by entering the command:

python

which will start a console similar to IDLE but without the changed IO objects. There you should enter the following lines to get the similar result:

import subprocess
import sys
_ = subprocess.Popen('rah.exe', stdout=sys.stdout,stderr=sys.stderr).communicate()
answered Apr 9, 2019 at 20:13
Sign up to request clarification or add additional context in comments.

3 Comments

That is all the code you need for the Python script. Did you encounter any errors while running it?
yess Traceback (most recent call last): File "C:\Python\python\temp2.py", line 3, in <module> p = Popen('rah.exe', stdout=sys.stdout, stderr=sys.stderr,universal_newlines=True) File "C:\Python\python\lib\subprocess.py", line 728, in init errread, errwrite) = self._get_handles(stdin, stdout, stderr) File "C:\Python\python\lib\subprocess.py", line 1057, in _get_handles c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) io.UnsupportedOperation: fileno >>>
Is it required that the code have to be run on IDLE? Since IDLE changes the IO objects which breaks the fileno() function. I've updated my answer for the alternative ways that you can use to run the code.
0

I tried with subprocess.run but it is not accepting inputs at runtime (i.e dynamically)

If you don't do anything, the subprocess will simply inherit their parent's stdin.

That aside, because you're intercepting the output of the subprocess and printing it afterwards you won't get the interleaving you're writing in your "expected output": the input is not going to echo back, so you just get what's being written to the subprocess's stdout, which is both printfs.

If you want to dynamically interact with the subprocess, you'll have to create a proper Popen object, pipe everything, and use stdin.write() and stdout.read(). And because you'll have to deal with pipe buffering it's going to be painful.

If you're going to do that a lot, you may want to take a look at pexpect: "interactive" subprocesses is pretty much its bread and butter.

This about works:

from subprocess import Popen, PIPE
from fcntl import fcntl, F_GETFL, F_SETFL
from os import O_NONBLOCK
import select
p = Popen(['./a.out'], stdin=PIPE, stdout=PIPE)
fcntl(p.stdout, F_SETFL, fcntl(p.stdout, F_GETFL) | O_NONBLOCK)
select.select([p.stdout], [], [])
print(p.stdout.read().decode())
d = input()
p.stdin.write(d.encode() + b'\n')
p.stdin.flush()
select.select([p.stdout], [], [])
print(p.stdout.read().decode())
#include<stdio.h>
int main() {
 printf("Enter a number");
 fflush(stdout);
 int a;
 scanf("%d",&a);
 for(int i=0;i<a;i++)
 {
 printf("%d",i);
 }
 fflush(stdout);
 return 0;
}

Note that it requires explicitly flushing the subprocess's stdout and the writing and configuring the stdout to be non-blocking in the caller and explicitly select()ing for data on the pipe. Alternatively you could create the subprocess with unbuffered pipes (bufsize=0) then select() and read bytes one by one.

answered Apr 9, 2019 at 20:18

1 Comment

I want this script to as interactive as excueting the same c program in cmg using gcc

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.