Search code examples
pythoncuser-interfacesubprocesspopen

Capture output from external C program with python GUI in realtime


I have a threaded C program that I want to launch using a Python GUI in a Unix environment. I want to be able to change the state of the GUI by gathering output from the C program.

For instance, this is output from my C program using printf:

Thread on tile 1: On
Thread on tile 2: OFF
Thread on tile 3: Disable
...
Thread on tile 61: ON

I would update my GUI based on the output. What makes the problem difficult is both my GUI and the C program need to run simultaneously and updates happening in realtime. I also need to be able to send commands to the C program from my GUI.

I'm new to Python, C, and Unix (I know, complete rookie status). I've read up on subprocess, Popen, and pexpect, but not sure how to put it all together of if this is even possible at all.

Thanks in advance


Solution

  • There's a toughie. I've run into this problem in the past (with no truly satisfactory solution):

    https://groups.google.com/forum/?fromgroups#!topic/comp.lang.python/79uoHgAbg18

    As suggested there, take a look at this custom module:

    http://pypi.python.org/pypi/sarge/0.1
    http://sarge.readthedocs.org/en/latest/

    Edit @Richard (not enough rep to comment): The problem with pipes is that unless they are attached to an interactive terminal, they are fully buffered -- meaning that none of the output is passed through the pipe to the Python until the C prog is done running, which certainly doesn't qualify as a real time.

    Edit 2: Based on Richard's link and some earlier thinking I had done, it occurred to me that it might be possible to manually loop over the pipe by treating it as a file object and only reading one line at a time:

    from time import sleep
    # Assume proc is the Popen object
    wait_time = 1 # 1 second, same delay as `tail -f`
    while True: # Or whatever condition you need
        line = proc.stdout.readline()
        if line != '' and line != '\n':
            parse_line_do_stuff()
    
        sleep(wait_time)
    

    This assumes that readline() is non-blocking, and further assumes that the pipe is at most line buffered, and even then it might not work. I've never tried it.