3

A post in 2011 answered this question for NUnit: How to unit test a method that runs into an infinite loop for some input?

Is there a similar TimeoutAttribute in PyUnit that I can use in the same fashion?

I did some searching and found "Duration", but that didn't seem the same.

Community
  • 1
  • 1
Murkantilism
  • 1,060
  • 1
  • 16
  • 31

1 Answers1

3

There doesn't appear there is anything in pyunit itself, but as a work around you can roll your own. Here is how to do it using the multiprocessing package.

from functools import wraps
from multiprocessing import Process

class TimeoutError(Exception):
    pass

def timeout(seconds=5, error_message="Timeout"):
    def decorator(func):
        def wrapper(*args, **kwargs):
            process = Process(None, func, None, args, kwargs)
            process.start()
            process.join(seconds)
            if process.is_alive():
                process.terminate()
                raise TimeoutError(error_message)

        return wraps(func)(wrapper)
    return decorator

Here is an example of how to use it:

import time

@timeout()
def test_timeout(a, b, c):
    time.sleep(1)

@timeout(1)
def test_timeout2():
    time.sleep(2)

if __name__ == '__main__':
    test_timeout(1, 2, 3)

    test_value = False
    try:
        test_timeout2()
    except TimeoutError as e:
        test_value = True

    assert test_value
Joe
  • 3,059
  • 2
  • 22
  • 28
  • Thanks for the reply! I'm having trouble getting the example to run. I get an error - TypeError: 'NoneType' object is not callable. This appears at both decorator lines. Currently I have everything in the same file. – Murkantilism Jan 18 '13 at 15:20
  • I updated it, and now it should work on Linux. I'll see if I can get it working on Windows later. – Joe Jan 18 '13 at 18:14
  • Cool, a windows solution would be much appreciated! – Murkantilism Jan 18 '13 at 19:02
  • @Murkantilism I couldn't find a good solution for Windows. It might be possible switching to threading, but then you have to use a non-public api to kill the thread. I'm not sure what side effects that would have. You can use the decorator as a function like `timeout(2)(func)(args)`. It seems a decorator changes the function in a way that doesn't allow it to be pickled, which is required for using a Process on Windows. – Joe Jan 19 '13 at 15:53