Author: dmeyer
Date: Thu Mar 20 11:39:14 2008
New Revision: 3207
Log:
Add parameter 'progress' to kaa.threaded and kaa.coroutine.
When progress is True, the first argument to the function is
an InProgress.Progress object that will be bound to the
returning InProgress to monitor the progress as caller.
Added:
trunk/base/test/progress.py
Modified:
trunk/base/src/net/url.py
trunk/base/src/notifier/async.py
trunk/base/src/notifier/coroutine.py
trunk/base/src/notifier/thread.py
trunk/beacon/test/clear_thumbnails.py
trunk/feedmanager/src/core.py
Modified: trunk/base/src/net/url.py
==============================================================================
--- trunk/base/src/net/url.py (original)
+++ trunk/base/src/net/url.py Thu Mar 20 11:39:14 2008
@@ -141,11 +141,12 @@
# stupid url encoding in url
url = url[:8+url[8:].find('/')] + \
urllib.quote(url[8+url[8:].find('/'):])
+ # FIXME: use kaa.threaded()
s = InProgress.Progress()
t = ThreadCallback(download, url, filename, tmpname, s)
t.wait_on_exit(False)
async = t()
- async.set_status(s)
+ async.progress = s
return async
Modified: trunk/base/src/notifier/async.py
==============================================================================
--- trunk/base/src/notifier/async.py (original)
+++ trunk/base/src/notifier/async.py Thu Mar 20 11:39:14 2008
@@ -44,6 +44,7 @@
# kaa.notifier imports
from callback import Callback
from signals import Signal
+from kaa.utils import property
# get logging object
log = logging.getLogger('notifier.async')
@@ -119,33 +120,30 @@
class Progress(Signal):
"""
Generic progress status object for InProgress. This object can be
- connected to an InProgress object using set_status and the caller
+ used as 'progress' member of an InProgress object and the caller
can monitor the progress.
"""
- def __init__(self):
+ def __init__(self, max=0):
super(InProgress.Progress, self).__init__()
- self.percentage = 0
+ self.start_time = time.time()
self.pos = 0
- self.max = 0
+ self.max = max
- def set(self, pos, max=None):
+ def set(self, pos=None, max=None):
"""
Set new status. The new status is pos of max.
"""
if max is not None:
self.max = max
- self.pos = pos
+ if pos is not None:
+ self.pos = pos
if pos > self.max:
self.max = pos
- if self.max:
- self.percentage = (self.pos * 100) / self.max
- else:
- self.percentage = 0
- self.emit()
+ self.emit(self)
- def update(self, diff):
+ def update(self, diff=1):
"""
Update position by the given difference.
"""
@@ -162,7 +160,19 @@
s = '|%%%ss|' % (width-2)
return s % ("="*n + ">").ljust(width-2)
+ @property
+ def eta(self):
+ if not self.pos:
+ return 0
+ sec = (time.time() - self.start_time) / self.pos
+ return sec * (self.max - self.pos)
+ @property
+ def percentage(self):
+ if self.max:
+ return (self.pos * 100) / self.max
+ return 0
+
def __init__(self):
"""
Create an InProgress object.
@@ -172,27 +182,7 @@
self._finished = False
self._finished_event = threading.Event()
self._unhandled_exception = None
- self.status = None
-
-
- def set_status(self, s):
- """
- Connect a status object to the InProgress object. The status object
- has to be updated by the creator of that object. The status should
- be a Signal so the monitoring function can connect to it to get
- notified on updates.
- """
- self.status = s
-
-
- def get_status(self):
- """
- Return status object if connected or return True if the function is
- still in progress or False if not.
- """
- if self.status is not None:
- return self.status
- return not self._finished
+ self.progress = None
def finish(self, result):
Modified: trunk/base/src/notifier/coroutine.py
==============================================================================
--- trunk/base/src/notifier/coroutine.py (original)
+++ trunk/base/src/notifier/coroutine.py Thu Mar 20 11:39:14 2008
@@ -81,7 +81,7 @@
return func.next()
-def coroutine(interval = 0, synchronize = False):
+def coroutine(interval = 0, synchronize = False, progress=False):
"""
Functions with this decorator uses yield to break and to return the
results. Special yield values for break are NotFinished or
@@ -89,7 +89,9 @@
be protected against parallel calls, which can be used avoid
multithreading pitfalls such as deadlocks or race conditions.
If a decorated function is currently being executed, new
- invocations will be queued.
+ invocations will be queued. If progress is True, the first argument
+ to the function is an InProgress.Progress object to return execution
+ progress.
A function decorated with this decorator will always return an
InProgress object. It may already be finished. If it is not finished,
@@ -98,6 +100,12 @@
"""
def decorator(func):
def newfunc(*args, **kwargs):
+ def wrap(obj):
+ if progress:
+ obj.progress = args[0]
+ return obj
+ if progress:
+ args = [ InProgress.Progress(), ] + list(args)
result = func(*args, **kwargs)
if not hasattr(result, 'next'):
# Decorated function doesn't have a next attribute, which
@@ -111,7 +119,7 @@
function = result
if synchronize and func._lock is not None and not
func._lock.is_finished():
# Function is currently called by someone else
- return CoroutineInProgressLock(func, function, interval)
+ return wrap(CoroutineInProgressLock(func, function, interval))
async = None
while True:
try:
@@ -123,7 +131,7 @@
# exception handling, return finished InProgress
ip = InProgress()
ip.throw(*sys.exc_info())
- return ip
+ return wrap(ip)
if isinstance(result, InProgress):
if result.is_finished():
# InProgress return that is already finished, go on
@@ -133,14 +141,14 @@
# everything went fine, return result in an InProgress
ip = InProgress()
ip.finish(result)
- return ip
+ return wrap(ip)
# we need a CoroutineInProgress to finish this later
# result is either NotFinished or InProgress
- progress = CoroutineInProgress(function, interval, result)
+ ip = CoroutineInProgress(function, interval, result)
if synchronize:
- func._lock = progress
+ func._lock = ip
# return the CoroutineInProgress
- return progress
+ return wrap(ip)
if synchronize:
func._lock = None
Modified: trunk/base/src/notifier/thread.py
==============================================================================
--- trunk/base/src/notifier/thread.py (original)
+++ trunk/base/src/notifier/thread.py Thu Mar 20 11:39:14 2008
@@ -91,13 +91,14 @@
# For threaded decorator
MAINTHREAD = object()
-def threaded(name=None, priority=0, async=True):
+def threaded(name=None, priority=0, async=True, progress=False):
"""
The decorator makes sure the function is always called in the thread
with the given name. The function will return an InProgress object if
async=True (default), otherwise it will cause invoking the decorated
function to block (the main loop is kept alive) and its result is
- returned.
+ returned. If progress is True, the first argument to the function is
+ an InProgress.Progress object to return execution progress.
If name=kaa.MAINTHREAD, the decorated function will be invoked from
the main thread. (In this case, currently the priority kwarg is
@@ -106,11 +107,13 @@
def decorator(func):
def newfunc(*args, **kwargs):
+ if progress:
+ args = [ InProgress.Progress(), ] + list(args)
if name is MAINTHREAD:
if not async and is_mainthread():
# Fast-path case: mainthread synchronous call from the
mainthread
return func(*args, **kwargs)
- callback = MainThreadCallback(func)
+ callback = MainThreadCallback(func)
elif name:
callback = NamedThreadCallback((name, priority), func)
else:
@@ -121,6 +124,8 @@
in_progress = callback(*args, **kwargs)
if not async:
return in_progress.wait()
+ if progress:
+ in_progress.progress = args[0]
return in_progress
try:
Added: trunk/base/test/progress.py
==============================================================================
--- (empty file)
+++ trunk/base/test/progress.py Thu Mar 20 11:39:14 2008
@@ -0,0 +1,38 @@
+import sys
+import kaa
+import time
+
+def update(progress):
+ eta = int(progress.eta)
+ sys.stdout.write('\r' + progress.get_progressbar(40))
+ sys.stdout.write(' ETA %02d:%02d' % (eta / 60, eta % 60))
+ sys.stdout.flush()
+
[EMAIL PROTECTED](progress=True)
+def scan1(progress):
+ progress.set(max=20)
+ for i in range(20):
+ progress.update()
+ time.sleep(0.1)
+
[EMAIL PROTECTED](interval=0.1, progress=True)
+def scan2(progress):
+ progress.set(max=20)
+ for i in range(20):
+ progress.update()
+ yield kaa.NotFinished
+
[EMAIL PROTECTED]()
+def test():
+ async = scan1()
+ async.progress.connect(update)
+ yield async
+ print
+ async = scan2()
+ async.progress.connect(update)
+ yield async
+ print
+ sys.exit(0)
+
+test()
+kaa.main.run()
Modified: trunk/beacon/test/clear_thumbnails.py
==============================================================================
--- trunk/beacon/test/clear_thumbnails.py (original)
+++ trunk/beacon/test/clear_thumbnails.py Thu Mar 20 11:39:14 2008
@@ -11,41 +11,51 @@
FORCE=True
+def update(progress):
+ eta = int(progress.eta)
+ sys.stdout.write('\r' + progress.get_progressbar(40))
+ sys.stdout.write(' %s/%s' % (progress.pos, progress.max))
+ sys.stdout.write(' ETA %02d:%02d' % (eta / 60, eta % 60))
+ sys.stdout.flush()
+
+
+def scan(files, progress):
+ for thumbnail in files:
+ progress.update()
+ metadata = kaa.metadata.parse(thumbnail)
+ if not metadata:
+ if FORCE:
+ os.unlink(thumbnail)
+ num_deleted += 1
+ continue
+ uri = metadata['Thumb::URI']
+ if not uri:
+ if FORCE:
+ os.unlink(thumbnail)
+ num_deleted += 1
+ continue
+ uri = kaa.unicode_to_str(uri)
+ if not uri.startswith('file://'):
+ if FORCE:
+ os.unlink(thumbnail)
+ num_deleted += 1
+ continue
+ if not os.path.isfile(uri[7:]):
+ os.unlink(thumbnail)
+ num_deleted += 1
+
+sys.stdout.write('scan thumbnail directory')
+sys.stdout.flush()
+
for directory in ('fail/kaa', 'large', 'normal'):
path = os.path.expanduser('~/.thumbnails/' + directory)
if os.path.isdir(path):
for thumbnail in os.listdir(path):
files.append(path + '/' + thumbnail)
-for pos, thumbnail in enumerate(files):
-
- n = int((pos / float(len(files))) * 50)
- sys.stdout.write("|%51s| %d / %d\r" % (("="*n + ">").ljust(51), pos,
len(files)))
- sys.stdout.flush()
-
- metadata = kaa.metadata.parse(thumbnail)
- if not metadata:
- if FORCE:
- os.unlink(thumbnail)
- num_deleted += 1
- continue
- uri = metadata['Thumb::URI']
- if not uri:
- if FORCE:
- os.unlink(thumbnail)
- num_deleted += 1
- continue
- uri = kaa.unicode_to_str(uri)
- if not uri.startswith('file://'):
- if FORCE:
- os.unlink(thumbnail)
- num_deleted += 1
- continue
- if not os.path.isfile(uri[7:]):
- os.unlink(thumbnail)
- num_deleted += 1
-
+progress = kaa.InProgress.Progress(len(files))
+progress.connect(update)
+scan(files, progress)
print
print 'Checked %s thumbnails' % len(files)
print 'Deleted %s files' % num_deleted
-
Modified: trunk/feedmanager/src/core.py
==============================================================================
--- trunk/feedmanager/src/core.py (original)
+++ trunk/feedmanager/src/core.py Thu Mar 20 11:39:14 2008
@@ -234,7 +234,7 @@
else:
async = entry.fetch(filename)
if verbose:
- async.get_status().connect(print_status,
async.get_status())
+ async.progress.connect(print_status)
yield async
if not os.path.isfile(filename):
log.error('error fetching', entry.url)
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog