fsl.utils.idle

This module provides functions and classes for running tasks asynchronously, either in an idle loop, or on a separate thread.

Note

The idle functions in this module are intended to be run from within a wx application. However, they will still work without wx, albeit with slightly modified behaviour.

Idle tasks

idle Run the given task on a wx.EVT_IDLE event.
idleWhen Poll the condition function periodically, and schedule func on idle() when it returns True.
inIdle Returns True if a task with the given name is queued on the idle loop (or is currently running), False otherwise.
cancelIdle If a task with the given taskName is in the idle queue, it is cancelled.
idleReset Reset the internal idle() queue state.
getIdleTimeout Returns the current wx idle loop time out/call rate.
setIdleTimeout Set the wx idle loop time out/call rate.

The idle() function is a simple way to run a task on an wx EVT_IDLE event handler. This effectively performs the same job as the run() function, but is more suitable for short tasks which do not warrant running in a separate thread.

The EVT_IDLE event is generated automatically by wx. However, there are some circumstances in which EVT_IDLE will not be generated, and pending events may be left on the queue. For this reason, the _wxIdleLoop() will occasionally use a wx.Timer to ensure that it continues to be called. The time-out used by this Timer can be queried and set via the getIdleTimeout() and setIdleTimeout() functions.

Thread tasks

run Run the given task in a separate thread.
wait Creates and starts a new Thread which waits for all of the Thread instances to finsih (by join``ing them), and then runs the given ``task via idle().
TaskThread The TaskThread is a simple thread which runs tasks.

The run() function simply runs a task in a separate thread. This doesn’t seem like a worthy task to have a function of its own, but the run() function additionally provides the ability to schedule another function to run on the wx.MainLoop when the original function has completed. This therefore gives us a simple way to run a computationally intensitve task off the main GUI thread (preventing the GUI from locking up), and to perform some clean up/refresh afterwards.

The wait() function is given one or more Thread instances, and a task to run. It waits until all the threads have finished, and then runs the task (via idle()).

The TaskThread class is a simple thread which runs a queue of tasks.

Other facilities

The idle module also defines the mutex() decorator, which is intended to be used to mark the methods of a class as being mutually exclusive. The mutex decorator uses the MutexFactory class to do its work.

fsl.utils.idle.run(task, onFinish=None, onError=None, name=None)

Run the given task in a separate thread.

Parameters:
  • task – The function to run. Must accept no arguments.
  • onFinish – An optional function to schedule (on the wx.MainLoop, via idle()) once the task has finished.
  • onError – An optional function to be called (on the wx.MainLoop, via idle()) if the task raises an error. Passed the Exception that was raised.
  • name – An optional name to use for this task in log statements.
Returns:

A reference to the Thread that was created.

Note

If a wx application is not running, the task and onFinish functions will simply be called directly, and the return value will be None.

fsl.utils.idle.idleReset()

Reset the internal idle() queue state.

In a normal execution environment, this function will never need to be called. However, in an execution environment where multiple wx.App instances are created, run, and destroyed sequentially, this function will need to be called after each wx.App has been destroyed. Otherwise the idle function will not work during exeution of subsequent wx.App instances.

fsl.utils.idle.getIdleTimeout()

Returns the current wx idle loop time out/call rate.

fsl.utils.idle.setIdleTimeout(timeout=None)

Set the wx idle loop time out/call rate. If timeout is not provided, or is set to None, the timeout is set to 200 milliseconds.

class fsl.utils.idle.IdleTask(name, task, schedtime, after, timeout, args, kwargs)

Bases: object

Container object used by the idle() and _wxIdleLoop() functions.

fsl.utils.idle.inIdle(taskName)

Returns True if a task with the given name is queued on the idle loop (or is currently running), False otherwise.

fsl.utils.idle.cancelIdle(taskName)

If a task with the given taskName is in the idle queue, it is cancelled. If the task is already running, it cannot be cancelled.

A KeyError is raised if no task called taskName exists.

fsl.utils.idle.idle(task, *args, **kwargs)

Run the given task on a wx.EVT_IDLE event.

Parameters:
  • task – The task to run.
  • name – Optional. If provided, must be provided as a keyword argument. Specifies a name that can be used to query the state of this task via the inIdle() function.
  • after – Optional. If provided, must be provided as a keyword argument. A time, in seconds, which specifies the amount of time to wait before running this task after it has been scheduled.
  • timeout – Optional. If provided, must be provided as a keyword argument. Specifies a time out, in seconds. If this amount of time passes before the function gets scheduled to be called on the idle loop, the function is not called, and is dropped from the queue.
  • dropIfQueued – Optional. If provided, must be provided as a keyword argument. If True, and a task with the given name is already enqueud, that function is dropped from the queue, and the new task is enqueued. Defaults to False. This argument takes precedence over the skipIfQueued argument.
  • skipIfQueued – Optional. If provided, must be provided as a keyword argument. If True, and a task with the given name is already enqueud, (or is running), the function is not called. Defaults to False.
  • alwaysQueue – Optional. If provided, must be provided as a keyword argument. If True, and a wx.MainLoop is not running, the task is enqueued anyway, under the assumption that a wx.MainLoop will be started in the future. Note that, if wx.App has not yet been created, another call to idle must be made after the app has been created for the original task to be executed. If wx is not available, this parameter will be ignored, and the task executed directly.

All other arguments are passed through to the task function.

If a wx.App is not running, the timeout, name and skipIfQueued arguments are ignored. Instead, the call will sleep for after seconds, and then the task is called directly.

Note

If the after argument is used, there is no guarantee that the task will be executed in the order that it is scheduled. This is because, if the required time has not elapsed when the task is popped from the queue, it will be re-queued.

Note

If you schedule multiple tasks with the same name, and you do not use the skipIfQueued or dropIfQueued arguments, all of those tasks will be executed, but you will only be able to query/cancel the most recently enqueued task.

Note

You will run into difficulties if you schedule a function that expects/accepts its own keyword arguments called name, skipIfQueued, dropIfQueued, after, timeout, or alwaysQueue.

fsl.utils.idle.idleWhen(func, condition, *args, **kwargs)

Poll the condition function periodically, and schedule func on idle() when it returns True.

Parameters:
  • func – Function to call.
  • condition – Function which returns True or False. The func function is only called when the condition function returns True.
  • pollTime – Must be passed as a keyword argument. Time (in seconds) to wait between successive calls to when. Defaults to 0.2.
fsl.utils.idle.wait(threads, task, *args, **kwargs)

Creates and starts a new Thread which waits for all of the Thread instances to finsih (by join``ing them), and then runs the given ``task via idle().

If the direct parameter is True, or a wx.App is not running, this function join``s the threads directly instead of creating a new ``Thread to do so.

Parameters:
  • threads – A Thread, or a sequence of Thread instances to join. Elements in the sequence may be None.
  • task – The task to run once all threads have completed.
  • wait_direct – Must be passed as a keyword argument. If True, this function call will join all of the threads, and then call the task. Otherwise (the default), this function will create a new thread to join the threads, and will return immediately.

All other arguments are passed to the task function.

Note

This function will not support task functions which expect a keyword argument called wait_direct.

class fsl.utils.idle.Task(name, func, onFinish, args, kwargs)

Bases: object

Container object which encapsulates a task that is run by a TaskThread.

exception fsl.utils.idle.TaskThreadVeto

Bases: Exception

Task functions which are added to a TaskThread may raise a TaskThreadVeto error to skip processing of the task’s onFinish handler (if one has been specified). See the TaskThread.enqueue() method for more details.

class fsl.utils.idle.TaskThread(*args, **kwargs)

Bases: threading.Thread

The TaskThread is a simple thread which runs tasks. Tasks may be enqueued and dequeued.

enqueue(func, *args, **kwargs)

Enqueue a task to be executed.

Parameters:
  • func – The task function.
  • taskName – Task name. Must be specified as a keyword argument. Does not necessarily have to be a string, but must be hashable. If you wish to use the dequeue() or isQueued() methods, you must provide a task name.
  • onFinish – An optional function to be called (via idle()) when the task funtion has finished. Must be provided as a keyword argument. If the func raises a :class`TaskThreadVeto` error, this function will not be called.

All other arguments are passed through to the task function when it is executed.

Note

If the specified taskName is not unique (i.e. another task with the same name may already be enqueued), the isQueued() method will probably return invalid results.

Warning

Make sure that your task function is not expecting keyword arguments called taskName or onFinish!

isQueued(name)

Returns True if a task with the given name is enqueued, False otherwise.

dequeue(name)

Dequeues a previously enqueued task.

Parameters:name – The task to dequeue.
stop()

Stop the TaskThread after any currently running task has completed.

waitUntilIdle()

Causes the calling thread to block until the task queue is empty.

run()

Run the TaskThread.

fsl.utils.idle.mutex(*args, **kwargs)

Decorator for use on methods of a class, which makes the method call mutually exclusive.

If you define a class which has one or more methods that must only be accessed by one thread at a time, you can use the mutex decorator to enforce this restriction. As a contrived example:

class Example(object):

    def __init__(self):
        self.__sharedData = []

    @mutex
    def dangerousMethod1(self, message):
        sefl.__sharedData.append(message)

    @mutex
    def dangerousMethod2(self):
        return sefl.__sharedData.pop()

The @mutex decorator will ensure that, at any point in time, only one thread is running either of the dangerousMethod1 or dangerousMethod2 methods.

See the MutexFactory`

class fsl.utils.idle.MutexFactory(function)

Bases: object

The MutexFactory is a placeholder for methods which have been decorated with the mutex() decorator. When the method of a class is decorated with @mutex, a MutexFactory is created.

Later on, when the method is accessed on an instance, the __get__() method creates the true decorator function, and replaces the instance method with that decorator.

Note

The MutexFactory adds an attribute called _async_mutex_lock to all instances that have @mutex-decorated methods.

createLock = <unlocked _thread.lock object>

This lock is used by all MutexFactory instances when a decorated instance method is accessed for the first time.

The first time that a mutexed method is accessed on an instance, a new threading.Lock is created, to be shared by all mutexed methods of that instance. The createLock is used to ensure that this can only occur once for each instance.