Rahul Lenkala
Rahul Lenkala

Reputation: 29

i want develop a python script which compiles and runs c programs using gcc

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

Upvotes: 0

Views: 108

Answers (2)

VietHTran
VietHTran

Reputation: 2318

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()

Upvotes: 1

Masklinn
Masklinn

Reputation: 42462

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.

Upvotes: 0

Related Questions