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 IdleLoop functionality in this module is intended to be
run from within a wx application. However, it will still work
without wx, albeit with slightly modified behaviour.
Idle tasks
This class contains logic for running tasks via |
|
Equivalent to calling |
|
Equivalent to calling |
|
Blocks for the specified number of seconds, yielding to the main |
The IdleLoop class provides a simple way to run a task on an wx
EVT_IDLE event handler. A single IdleLoop instance is created when
this module is imported; it can be accessed via the idleLoop attribute,
and via the module-level idle() and idleWhen() functions.
The IdleLoop.idle() method effectively performs the same job as the
run() function (described below), but is more suitable for short tasks
which do not warrant running in a separate thread.
Thread tasks
Run the given |
|
Creates and starts a new |
|
The |
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 (via idle()). 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/notification
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._canHaveGui()[source]
Return
Trueif wxPython is installed, and a display is available,Falseotherwise.
- fsl.utils.idle._haveGui()[source]
Return
Trueif wxPython is installed, a display is available, and awx.Appexists,Falseotherwise.
- class fsl.utils.idle.IdleTask(name, task, schedtime, after, timeout, args, kwargs)[source]
Bases:
objectContainer object used by the
IdleLoopclass. Used to encapsulate information about a queued task.- __dict__ = mappingproxy({'__module__': 'fsl.utils.idle', '__doc__': 'Container object used by the :class:`IdleLoop` class.\n Used to encapsulate information about a queued task.\n ', '__init__': <function IdleTask.__init__>, '__dict__': <attribute '__dict__' of 'IdleTask' objects>, '__weakref__': <attribute '__weakref__' of 'IdleTask' objects>, '__annotations__': {}})
- __module__ = 'fsl.utils.idle'
- __weakref__
list of weak references to the object (if defined)
- class fsl.utils.idle.IdleLoop[source]
Bases:
objectThis class contains logic for running tasks via
wx.EVT_IDLEevents.A single
IdleLoopinstance is created when this module is first imported - it is accessed via the module-levelidleLoopattribute.In normal circumstances, this
idleLoopinstance should be treated as a singleton, although this is not enforced in any way.The
EVT_IDLEevent is generated automatically bywxduring periods of inactivity. However, there are some circumstances in whichEVT_IDLEwill not be generated, and pending events may be left on the queue. For this reason, theIdleLoopwill occasionally use awx.Timerto ensure that it continues to be called. The time-out used by thisTimercan be queried and set via thecallRate()property.- __init__()[source]
Create an
IdleLoop.This method does not do much - the real initialisation takes place on the first call to
idle().
- property registered
Boolean flag indicating whether a handler has been registered on
wx.EVT_IDLEevents. Checked and set in theidle()method.
- property queue
A
Queueof functions which are to be run on thewx.EVT_IDLEloop.
- property queueDict
A
dictcontaining the names of all named tasks which are currently queued on the idle loop (see thenameparameter to theidle()method).
- property timer
A
wx.Timerinstance which is used to periodically trigger the_wxIdleLoop()in circumstances wherewx.EVT_IDLEevents may not be generated. This is created in the first call toidle().
- property callRate
Minimum time (in milliseconds) between consecutive calls to the idle loop (
__idleLoop()). Ifwx.EVT_IDLEevents are not being fired, thetimer()is used to maintain the idle loop at this rate.
- property allowErrors
Used for testing/debugging. If
True, and a function called on the idle loop raises an error, that error will not be caught, and the idle loop will stop.
- property neverQueue
If
True, tasks passed toidle()will never be queued, and instead will always be executed directly/synchonously. See also thesynchronous()context manager.
- synchronous()[source]
Context manager which can be used to tenporarily set
neverQueue()toTrue, restoring its previous value afterwards.
- reset()[source]
Reset the internal idle loop state.
In a normal execution environment, this method will never need to be called. However, in an execution environment where multiple
wx.Appinstances are created, run, and destroyed sequentially, this function will need to be called after eachwx.Apphas been destroyed. Otherwise theidlefunction will not work during exeution of subsequentwx.Appinstances.
- inIdle(taskName)[source]
Returns
Trueif a task with the given name is queued on the idle loop (or is currently running),Falseotherwise.
- cancelIdle(taskName)[source]
If a task with the given
taskNameis in the idle queue, it is cancelled. If the task is already running, it cannot be cancelled.A
KeyErroris raised if no task calledtaskNameexists.
- idle(task, *args, **kwargs)[source]
Run the given task on a
wx.EVT_IDLEevent.- 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
inIdle().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 givennameis already enqueud, that function is dropped from the queue, and the new task is enqueued. Defaults toFalse. This argument takes precedence over theskipIfQueuedargument.skipIfQueued – Optional. If provided, must be provided as a keyword argument. If
True, and a task with the givennameis already enqueud, (or is running), the function is not called. Defaults toFalse.alwaysQueue – Optional. If provided, must be provided as a keyword argument. If
True, and awx.MainLoopis not running, the task is enqueued anyway, under the assumption that awx.MainLoopwill be started in the future. Note that, ifwx.Apphas not yet been created, another call toidlemust be made after the app has been created for the original task to be executed. Ifwxis 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.Appis not running, orneverQueue()has been set toTrue, thetimeout,name,dropIfQueued,skipIfQueued, andalwaysQueuearguments are ignored. Instead, the call will sleep forafterseconds, and then thetaskwill be called directly.Note
If the
afterargument 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 theskipIfQueuedordropIfQueuedarguments, 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, oralwaysQueue.
- idleWhen(func, condition, *args, **kwargs)[source]
Poll the
conditionfunction periodically, and schedulefunconidle()when it returnsTrue.- Parameters:
func – Function to call.
condition – Function which returns
TrueorFalse. Thefuncfunction is only called when theconditionfunction returnsTrue.pollTime – Must be passed as a keyword argument. Time (in seconds) to wait between successive calls to
when. Defaults to0.2.
- __idleLoop(ev)
This method is called on
wx.EVT_IDLEevents, and occasionally onwx.EVT_TIMERevents via thetimer(). If there is a function on thequeue(), it is popped and called.
- __dict__ = mappingproxy({'__module__': 'fsl.utils.idle', '__doc__': 'This class contains logic for running tasks via ``wx.EVT_IDLE`` events.\n\n A single ``IdleLoop`` instance is created when this module is first\n imported - it is accessed via the module-level :attr:`idleLoop` attribute.\n\n In normal circumstances, this ``idleLoop`` instance should be treated as a\n singleton, although this is not enforced in any way.\n\n The ``EVT_IDLE`` event is generated automatically by ``wx`` during periods\n of inactivity. However, there are some circumstances in which ``EVT_IDLE``\n will not be generated, and pending events may be left on the queue. For\n this reason, the ``IdleLoop`` will occasionally use a ``wx.Timer`` to\n ensure that it continues to be called. The time-out used by this ``Timer``\n can be queried and set via the :meth:`callRate` property.\n ', '__init__': <function IdleLoop.__init__>, 'registered': <property object>, 'queue': <property object>, 'queueDict': <property object>, 'timer': <property object>, 'callRate': <property object>, 'allowErrors': <property object>, 'neverQueue': <property object>, 'synchronous': <function IdleLoop.synchronous>, 'reset': <function IdleLoop.reset>, 'inIdle': <function IdleLoop.inIdle>, 'cancelIdle': <function IdleLoop.cancelIdle>, 'idle': <function IdleLoop.idle>, 'idleWhen': <function IdleLoop.idleWhen>, '_IdleLoop__idleLoop': <function IdleLoop.__idleLoop>, '__dict__': <attribute '__dict__' of 'IdleLoop' objects>, '__weakref__': <attribute '__weakref__' of 'IdleLoop' objects>, '__annotations__': {}})
- __module__ = 'fsl.utils.idle'
- __weakref__
list of weak references to the object (if defined)
- fsl.utils.idle.idleLoop = <fsl.utils.idle.IdleLoop object>
A singleton
IdleLoopinstance, created when this module is imported.
- fsl.utils.idle.idle(*args, **kwargs)[source]
Equivalent to calling
IdleLoop.idle()on theidleLoopsingleton.
- fsl.utils.idle.idleWhen(*args, **kwargs)[source]
Equivalent to calling
IdleLoop.idleWhen()on theidleLoopsingleton.
- fsl.utils.idle.block(secs, delta=0.01, until=None)[source]
Blocks for the specified number of seconds, yielding to the main
wxloop.If
wxis not available, or awxapplication is not running, this function is equivalent totime.sleep(secs).If
untilis provided, this function will block untiluntilreturnsTrue, orsecshave elapsed, whichever comes first.- Parameters:
secs – Time in seconds to block
delta – Time in seconds to sleep between successive yields to
wx.until – Function which returns
TrueorFalse, and which determins when calls toblockwill return.
- fsl.utils.idle.run(task, onFinish=None, onError=None, name=None)[source]
Run the given
taskin a separate thread.- Parameters:
task – The function to run. Must accept no arguments.
onFinish – An optional function to schedule (on the
wx.MainLoop, viaidle()) once thetaskhas finished.onError – An optional function to be called (on the
wx.MainLoop, viaidle()) if thetaskraises an error. Passed theExceptionthat was raised.name – An optional name to use for this task in log statements.
- Returns:
A reference to the
Threadthat was created.
Note
If a
wxapplication is not running, thetaskandonFinishfunctions will simply be called directly, and the return value will beNone.
- fsl.utils.idle.wait(threads, task, *args, **kwargs)[source]
Creates and starts a new
Threadwhich waits for all of theThreadinstances to finish (byjoin``ing them), and then runs the given ``taskviaidle().If the
directparameter isTrue, or awx.Appis not running, this functionjoin``s the threads directly instead of creating a new ``Threadto do so.- Parameters:
threads – A
Thread, or a sequence ofThreadinstances to join. Elements in the sequence may beNone.task – The task to run once all
threadshave completed.wait_direct – Must be passed as a keyword argument. If
True, this function call willjoinall of thethreads, and then call thetask. Otherwise (the default), this function will create a new thread tojointhethreads, and will return immediately.
All other arguments are passed to the
taskfunction.Note
This function will not support
taskfunctions which expect a keyword argument calledwait_direct.
- class fsl.utils.idle.Task(name, func, onFinish, onError, args, kwargs)[source]
Bases:
objectContainer object which encapsulates a task that is run by a
TaskThread.- __dict__ = mappingproxy({'__module__': 'fsl.utils.idle', '__doc__': 'Container object which encapsulates a task that is run by a\n :class:`TaskThread`.\n ', '__init__': <function Task.__init__>, '__dict__': <attribute '__dict__' of 'Task' objects>, '__weakref__': <attribute '__weakref__' of 'Task' objects>, '__annotations__': {}})
- __module__ = 'fsl.utils.idle'
- __weakref__
list of weak references to the object (if defined)
- exception fsl.utils.idle.TaskThreadVeto[source]
Bases:
ExceptionTask functions which are added to a
TaskThreadmay raise aTaskThreadVetoerror to skip processing of the task’sonFinishhandler (if one has been specified). See theTaskThread.enqueue()method for more details.- __module__ = 'fsl.utils.idle'
- __weakref__
list of weak references to the object (if defined)
- class fsl.utils.idle.TaskThread(*args, **kwargs)[source]
Bases:
ThreadThe
TaskThreadis a simple thread which runs tasks. Tasks may be enqueued and dequeued.- enqueue(func, *args, **kwargs)[source]
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()orisQueued()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, and must itself accept no arguments. If thefuncraises a :class`TaskThreadVeto` error, this function will not be called.onError – An optional function to be called (via
idle()) if the task funtion raises anException. Must be provided as a keyword argument, and must itself accept the raisedExceptionobject as a single argument. If thefuncraises 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
taskNameis not unique (i.e. another task with the same name may already be enqueued), theisQueued()method will probably return invalid results.Warning
Make sure that your task function is not expecting keyword arguments called
taskName,onFinish, oronError!
- __module__ = 'fsl.utils.idle'
- fsl.utils.idle.mutex(*args, **kwargs)[source]
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
mutexdecorator 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
@mutexdecorator will ensure that, at any point in time, only one thread is running either of thedangerousMethod1ordangerousMethod2methods.See the
MutexFactory`
- class fsl.utils.idle.MutexFactory(function)[source]
Bases:
objectThe
MutexFactoryis a placeholder for methods which have been decorated with themutex()decorator. When the method of a class is decorated with@mutex, aMutexFactoryis 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
MutexFactoryadds an attribute called_async_mutex_lockto all instances that have@mutex-decorated methods.- __dict__ = mappingproxy({'__module__': 'fsl.utils.idle', '__doc__': 'The ``MutexFactory`` is a placeholder for methods which have been\n decorated with the :func:`mutex` decorator. When the method of a class\n is decorated with ``@mutex``, a ``MutexFactory`` is created.\n\n Later on, when the method is accessed on an instance, the :meth:`__get__`\n method creates the true decorator function, and replaces the instance\n method with that decorator.\n\n .. note:: The ``MutexFactory`` adds an attribute called\n ``_async_mutex_lock`` to all instances that have\n ``@mutex``-decorated methods.\n ', 'createLock': <unlocked _thread.lock object>, '__init__': <function MutexFactory.__init__>, '__get__': <function MutexFactory.__get__>, '__dict__': <attribute '__dict__' of 'MutexFactory' objects>, '__weakref__': <attribute '__weakref__' of 'MutexFactory' objects>, '__annotations__': {}})
- __module__ = 'fsl.utils.idle'
- __weakref__
list of weak references to the object (if defined)
- createLock = <unlocked _thread.lock object>
This lock is used by all
MutexFactoryinstances 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.Lockis created, to be shared by all mutexed methods of that instance. ThecreateLockis used to ensure that this can only occur once for each instance.
- __get__(instance, cls)[source]
When this
MutexFactoryis accessed through an instance, a decorator function is created which enforces mutually exclusive access to the decorated method. A singlethreading.Lockobject is shared between all@mutex-decorated methods on a single instance.If this
MutexFactoryis accessed through a class, the decorated function is returned.