a function that raises an exception in another thread, including the main
thread.

two context managers that may stop its inner block activity on timeout.

two decorators that may stop its decorated callables on timeout.

Developed and tested with CPython 2.6, 2.7 and 3.3 on MacOSX. Should work on
any OS (xBSD, Linux, Windows) except when explicitly mentioned.

Note

Signal based timeout controls, namely SignalTimeout context manager and
signal_timeoutable decorator won’t work in Windows that has no support
for signal.SIGALRM. Any help to work around this is welcome.

Threading based resources will only work with CPython implementations
since we use CPython specific low level API. This excludes Iron Python,
Jython, Pypy, …

Will not stop the execution of blocking Python atomic instructions that
acquire the GIL. In example, if the destination thread is actually
executing a time.sleep(20), the asynchronous exception is effective
after its execution.

A context manager that “kills” its inner block execution that exceeds the
provided time.

ThreadingTimeout(seconds, swallow_exc=True)

seconds is the number of seconds allowed to the execution of the context
managed block.

swallow_exc : if False, the possible stopit.TimeoutException will
be re-raised when quitting the context managed block. Attention: a
True value does not swallow other potential exceptions.

Methods and attributes

of a stopit.ThreadingTimeout context manager.

Method / Attribute

Description

.cancel()

Cancels the timeout control. This method is intended for use within the
block that’s under timeout control, specifically to cancel the timeout
control. Means that all code executed after this call may be executed
till the end.

.state

This attribute indicated the actual status of the timeout control. It
may take the value of the EXECUTED, EXECUTING, TIMED_OUT,
INTERRUPTED or CANCELED attributes. See below.

.EXECUTING

The timeout control is under execution. We are typically executing
within the code under control of the context manager.

.EXECUTED

Good news: the code under timeout control completed normally within the
assigned time frame.

.TIMED_OUT

Bad news: the code under timeout control has been sleeping too long.
The objects supposed to be created or changed within the timeout
controlled block should be considered as non existing or corrupted.
Don’t play with them otherwise informed.

.INTERRUPTED

The code under timeout control may itself raise explicit
stopit.TimeoutException for any application logic reason that may
occur. This intentional exit can be spotted from outside the timeout
controlled block with this state value.

.CANCELED

The timeout control has been intentionally canceled and the code
running under timeout control did complete normally. But perhaps after
the assigned time frame.

A typical usage:

importstopit# ...withstopit.ThreadingTimeout(10)asto_ctx_mgr:assertto_ctx_mgr.state==to_ctx_mgr.EXECUTING# Something potentially very long but which# ...# OK, let's check what happenedifto_ctx_mrg.state==to_ctx_mrg.EXECUTED:# All's fine, everything was executed within 10 secondselifto_ctx_mrg.state==to_ctx_mrg.EXECUTING:# Hmm, that's not possible outside the blockelifto_ctx_mrg.state==to_ctx_mrg.TIMED_OUT:# Eeek the 10 seconds timeout occurred while executing the blockelifto_ctx_mrg.state==to_ctx_mrg.INTERRUPTED:# Oh you raised specifically the TimeoutException in the blockelifto_ctx_mrg.state==to_ctx_mrg.CANCELED:# Oh you called to_ctx_mgr.cancel() method within the block but it# executed till the endelse:# That's not possible

Notice that the context manager object may be considered as a boolean
indicating (if True) that the block executed normally:

ifto_ctx_mgr:# Yes, the code under timeout control completed# Objects it created or changed may be considered consistent

A decorator that kills the function or method it decorates, if it does not
return within a given time frame.

stopit.threading_timeoutable([default [, timeout_param]])

default is the value to be returned by the decorated function or method of
when its execution timed out, to notify the caller code that the function
did not complete within the assigned time frame.

If this parameter is not provided, the decorated function or method will
return a None value when its execution times out.

@stopit.threading_timeoutable(default='not finished')definfinite_loop():# As its name says...result=infinite_loop(timeout=5)assertresult=='not finished'

timeout_param: The function or method you have decorated may require a
timeout named parameter for whatever reason. This empowers you to change
the name of the timeout parameter in the decorated function signature to
whatever suits, and prevent a potential naming conflict.

@stopit.threading_timeoutable(timeout_param='my_timeout')defsome_slow_function(a,b,timeout='whatever'):# As its name says...result=some_slow_function(1,2,timeout="something",my_timeout=2)

As you noticed above, you just need to add the timeout parameter when
calling the function or method. Or whatever other name for this you chose with
the timeout_param of the decorator. When calling the real inner function
or method, this parameter is removed.

Can’t interrupt a long Python atomic instruction. e.g. if
time.sleep(20.0) is actually executing, the timeout will take
effect at the end of the execution of this line.

Don’t care of it

Thread safety

Yes : Thread safe as long as each thread uses its own ThreadingTimeout
context manager or threading_timeoutable decorator.

Not thread safe. Could yield unpredictable results in a
multithreads application.

Nestable context managers

Yes : you can nest threading based context managers

No : never nest a signaling based context manager in another one.
The innermost context manager will automatically cancel the timeout
control of outer ones.

Accuracy

Any positive floating value is accepted as timeout value. The accuracy
depends on the GIL interval checking of your platform. See the doc on
sys.getcheckinterval and sys.setcheckinterval for your Python
version.

Due to the use of signal.SIGALRM, we need provide an integer number
of seconds. So a timeout of 0.6 seconds will ve automatically
converted into a timeout of zero second!

Supported platforms

Any CPython 2.6, 2.7 or 3.3 on any OS with threading support.

Any Python 2.6, 2.7 or 3.3 with signal.SIGALRM support. This
excludes Windows boxes

Important: the way CPython supports threading and asynchronous features has
impacts on the accuracy of the timeout. In other words, if you assign a 2.0
seconds timeout to a context managed block or a decorated callable, the
effective code block / callable execution interruption may occur some
fractions of seconds after this assigned timeout.

For more background about this issue - that cannot be fixed - please read
Python gurus thoughts about Python threading, the GIL and context switching
like these ones:

If this is a real issue for users (want a precise timeout and not an
approximative one), a future release will add the optional check_interval
parameter to the context managers and decorators. This parameter will enable
to lower temporarily the threads switching check interval, having a more
accurate timeout at the expense of the overall performances while the context
managed block or decorated functions are executing.

The context manager stops the execution of its inner block after a given time.
You may manage the way the timeout occurs using a try: ... except: ...
construct or by inspecting the context manager state attribute after the
block.

This is a NIH package which is mainly a theft of Gabriel Ahtune’s recipe with
tests, minor improvements and refactorings, documentation and setuptools
awareness I made since I’m somehow tired to copy/paste this recipe among
projects that need timeout control.