Search code examples
pythonshellsandbox

Sandbox shell programs on time


I'm writing a grading robot for a Python programming class, and the students' submissions may loop infinitely. I want to sandbox a shell call to their program so that it can't run longer than a specific amount of time. I'd like to run, say,

restrict --msec=100 --default=-1 python -c "while True: pass"

and have it return -1 if the program runs longer than 100ms, and otherwise return the value of the executed expression (in this case, the output of the python program)

Does Python support this internally? I'm also writing the grading robot in Perl, so I could use some Perl module wrapped around the call to the shell script.


Solution

  • Use apply_async to call the student's function, (foo in the example below). Use the get method with a timeout to get the result if it returns in 0.1 seconds or less, otherwise get raise a TimeoutError:

    import multiprocessing as mp
    import time
    import sys
    
    def foo(x):
        time.sleep(x)
        return x*x
    
    pool = mp.Pool(1)
    
    for x in (0.01, 1.0):
        try:
            result = pool.apply_async(foo, args = (x,)).get(timeout = 0.1)
        except KeyboardInterrupt:
            pool.terminate()
            sys.exit("Cancelled")
        except mp.TimeoutError:
            print('Timed out')
        else:
            print "Result: {r}".format(r = result)
    

    Or, if the student submits a script instead of function, then you could use jcollado's Command class.