more work on long operation framework.

svn: r8126
This commit is contained in:
Richard Taylor 2007-02-16 08:55:50 +00:00
parent bf831a400d
commit d912167cab
3 changed files with 178 additions and 14 deletions

View File

@ -1,3 +1,7 @@
2007-02-16 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/GrampsDb/_LongOpStatus.py: more work on long operation framework
* src/GrampsDb/_CursorIterator.py: more work on long operation framework
2007-02-15 Don Allingham <don@gramps-project.org>
* src/GrampsDbUtils/_GedcomParse.py: refactoring
* src/GrampsDbUtils/_GedcomUtils.py: refactoring

View File

@ -1,19 +1,11 @@
class LongOpStatus(object):
def __init__(self):
self._cancel = False
def cancel(self):
self._cancel = True
def shouldCancel(self):
return self._cancel
from _LongOpStatus import LongOpStatus
class CursorIterator(object):
def __init__(self,db,cursor):
self._db = db
self._cursor = cursor
#self._status = LongOpStatus(total_steps=cursor.get_length(),interval=10)
self._status = LongOpStatus()
def __iter__(self):
@ -30,18 +22,21 @@ class CursorIterator(object):
yield next
# check for cancel
#if self._status.shouldCancel():
#if self._status.should_cancel():
# raise GrampsDbUserCancel
# emit heartbeat
self._db.emit('long-op-heartbeat')
self._status.heartbeat()
next = self._cursor.next()
# emit stop signal
self._db.emit('long-op-end')
self._status.end()
self._cursor.close()
raise StopIteration
except:
# Not allowed to use 'finally' because we
# yeild inside the try clause.
self._cursor.close()
self._db.emit('long-op-end')
self._status_end()
raise

View File

@ -0,0 +1,165 @@
import time
from _GrampsDBCallback import GrampsDBCallback
class LongOpStatus(GrampsDBCallback):
"""LongOpStatus provides a way of communicating the status of a long
running operations. The intended use is that when a long running operation
is about to start it should create an instance of this class and emit
it so that any listeners can pick it up and use it to record the status
of the operation.
Signals
=======
op-heartbeat - emitted every 'interval' calls to heartbeat.
op-end - emitted once when the operation completes.
Example usage:
class MyClass(GrampsDBCallback):
__signals__ = {
'op-start' : object
}
def long(self):
status = LongOpStatus("doing long job", 100, 10)
for i in xrange(0,99):
time.sleep(0.1)
status.heartbeat()
status.end()
class MyListener(object):
def __init__(self):
self._op = MyClass()
self._op.connect('op-start', self.start)
self._current_op = None
def start(self,long_op):
self._current_op.connect('op-heartbeat', self.heartbeat)
self._current_op.connect('op-end', self.stop)
def hearbeat(self):
# update status display
def stop(self):
# close the status display
self._current_op = None
"""
__signals__ = {
'op-heartbeat' : None,
'op-end' : None
}
def __init__(self,msg="",total_steps=None,interval=1,can_cancel=False):
"""
@param msg: A Message to indicated the purpose of the operation.
@type msg: string
@param total_steps: The total number of steps that the operation
will perform.
@type total_steps:
@param interval: The number of iterations between emissions.
@type interval:
@param can_cancel: Set to True if the operation can be cancelled.
If this is set the operation that creates the status object should
check the 'should_cancel' method regularly so that it can cancel
the operation.
@type can_cancel:
"""
GrampsDBCallback.__init__(self)
self._msg = msg
self._total = total_steps
self._interval = interval
self._can_cancel = can_cancel
self._cancel = False
self._count = 0
self._countdown = interval
self._secs_left = 0
self._start = time.time()
def heartbeat(self):
"""This should be called for each step in the operation. It will
emit a 'op-heartbeat' every 'interval' steps. It recalcuates the
'estimated_secs_to_complete' from the time taken for previous
steps.
"""
self._countdown -= 1
if self._countdown <= 0:
elapsed = time.time() - self._start
self._secs_left = \
( elapsed / self._interval ) \
* (self._total - self._count)
self._count += self._interval
self._countdown = self._interval
self._start = time.time()
self.emit('op-heartbeat')
def estimated_secs_to_complete(self):
"""Return the number of seconds estimated left before operation
completes. This will change as 'hearbeat' is called.
@return: estimated seconds to complete.
@rtype: int
"""
return self._secs_left
def cancel(self):
"""Inform the operation that it should complete.
"""
self._cancel = True
self.end()
def end(self):
"""End the operation. Causes the 'op-end' signal to be emitted.
"""
self.emit('op-end')
def should_cancel(self):
"""Returns true of the user has asked for the operation to be cancelled.
@return: True of the operation should be cancelled.
@rtype: bool
"""
return self._cancel
def can_cancel(self):
return self._can_cancel
def get_msg(self):
return msg
def set_msg(self, msg):
self._msg = msg
if __name__ == '__main__':
s = LongOpStatus("msg", 100, 10)
def heartbeat():
print "heartbeat ", s.estimated_secs_to_complete()
def end():
print "end"
s.connect('op-heartbeat', heartbeat)
s.connect('op-end', end)
for i in xrange(0,99):
time.sleep(0.1)
s.heartbeat()
s.end()