views:

878

answers:

3

Possible Duplicate:
subprocess with timeout

What is the easiest way to do the following in Python:

  • Run an external process
  • Capture stdout in a string, stderr, and exit status
  • Set a timeout.

I would like something like this:

import proc

try:
    status, stdout, stderr = proc.run(["ls", "-l"], timeout=10)
except proc.Timeout:
    print "failed"
+2  A: 

I hate doing the work by myself. Just copy this into your proc.py module.

import subprocess
import time
import sys

class Timeout(Exception):
    pass

def run(command, timeout=10):
    proc = subprocess.Popen(command, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poll_seconds = .250
    deadline = time.time()+timeout
    while time.time() < deadline and proc.poll() == None:
        time.sleep(poll_seconds)

    if proc.poll() == None:
        if float(sys.version[:3]) >= 2.6:
            proc.terminate()
        raise Timeout()

    stdout, stderr = proc.communicate()
    return stdout, stderr, proc.returncode

if __name__=="__main__":
    print run(["ls", "-l"])
    print run(["find", "/"], timeout=3) #should timeout
flybywire
This version might timeout due to pipe buffer overflow (when stdout or stderr ~64K).
J.F. Sebastian
If the command times out, you won't get any output generated up to the timeout.
Mike Mazur
A: 

OSAF's build_lib shows how we run commans on Windows, Linux and Mac while capturing stdout, stderr and exit values while also supporting redirecting and teeing output. The last two requirements, along with us wanting the run to output stuff without buffering was what added the extra complexity.

Heikki Toivonen
+1  A: 

Note on linux with coreutils >= 7.0 you can prepend timeout to the command like:

timeout 1 sleep 1000
pixelbeat