Hi Jason and everyone else, attached a patch how I think a BackgroundTask should look like. I added BackgroundTask to async.py and use it in Process and Thread. Tell me what you think.
On a site-notice: We have Thread() that has a start() function. This class calls a function in a new thread. This class is a BackgroundTask. On the other side we have ThreadCallback which has a register function to schedule the task in a thread with a given name. This object is an InProgress object. This is confusing. First of all ThreadCallback should be a BackgroundTask _having_ an InProgress object. I also think 'register' should be called 'schedule' or even better, try to merge Thread and ThreadCallback. And why do we call MainThreadCallback using __call__? OK, we do the same for Callback, but MainThreadCallback takes some time. Maybe the function should be called start, too. Comments please Dischi
Index: src/notifier/thread.py
===================================================================
--- src/notifier/thread.py (revision 2969)
+++ src/notifier/thread.py (working copy)
@@ -60,7 +60,7 @@
# notifier imports
import nf_wrapper as notifier
from callback import Callback, Signal
-from async import InProgress
+from async import InProgress, BackgroundTask
# get logging object
log = logging.getLogger('notifier')
@@ -127,7 +127,7 @@
return None
-class Thread(threading.Thread):
+class Thread(threading.Thread, BackgroundTask):
"""
Notifier aware wrapper for threads. When a thread is started, it is
impossible to fork the current process into a second one without exec both
@@ -135,16 +135,12 @@
"""
def __init__(self, function, *args, **kargs):
threading.Thread.__init__(self)
+ BackgroundTask.__init__(self)
self.function = function
self.args = args
self.kargs = kargs
- self.signals = {
- "completed": Signal(),
- "exception": Signal()
- }
-
def wait_on_exit(self, wait=False):
"""
Wait for the thread on application exit. Default is True.
@@ -162,15 +158,12 @@
self.join()
+ @BackgroundTask.startBackgroundTask()
def start(self):
"""
Start the thread and return an InProgress object.
"""
- r = InProgress()
- self.signals['completed'].connect_once(r.finished)
- self.signals['exception'].connect_once(r.exception)
super(Thread, self).start()
- return r
def run(self):
Index: src/notifier/async.py
===================================================================
--- src/notifier/async.py (revision 2969)
+++ src/notifier/async.py (working copy)
@@ -29,7 +29,7 @@
#
# -----------------------------------------------------------------------------
-__all__ = [ 'InProgress' ]
+__all__ = [ 'InProgress', 'BackgroundTask' ]
# python imports
import logging
@@ -200,3 +200,32 @@
will be emited only once.
"""
return Signal._connect(self, callback, args, kwargs, True, weak, pos)
+
+
+class BackgroundTask(object):
+ """
+ Task running in the background. This objects provides a 'completed' and
+ an 'exception' signal and a decorator to create an InProgress object.
+ """
+ def __init__(self):
+ self.signals = {
+ 'completed': Signal(),
+ 'exception': Signal()
+ }
+
+ def startBackgroundTask():
+ def decorator(func):
+ def newfunc(*args, **kwargs):
+ async = InProgress()
+ self.signals['completed'].connect_once(async.finished)
+ self.signals['exception'].connect_once(async.exception)
+ func(*args, **kwargs)
+ return async
+ try:
+ newfunc.func_name = func.func_name
+ except TypeError:
+ pass
+ return newfunc
+ return decorator
+
+ startBackgroundTask = staticmethod(startBackgroundTask)
Index: src/notifier/popen.py
===================================================================
--- src/notifier/popen.py (revision 2969)
+++ src/notifier/popen.py (working copy)
@@ -58,14 +58,14 @@
import nf_wrapper as notifier
from callback import Signal, Callback
from thread import MainThreadCallback, is_mainthread
-from async import InProgress
+from async import InProgress, BackgroundTask
# get logging object
log = logging.getLogger('notifier')
# FIXME: rewrite :)
-class Process(object):
+class Process(BackgroundTask):
"""
Base class for started child processes
"""
@@ -75,14 +75,11 @@
of arguments (similar to popen2). If debugname is given, the stdout
and stderr will also be written.
"""
-
+ BackgroundTask.__init__(self)
# Setup signal handlers for the process; allows the class to be
# useful without subclassing.
- self.signals = {
- "stderr": Signal(),
- "stdout": Signal(),
- "completed": Signal(),
- }
+ self.signals['stderr'] = Signal()
+ self.signals['stdout'] = Signal()
self._cmd = self._normalize_cmd(cmd)
self._stop_cmd = None
@@ -91,7 +88,6 @@
self.stopping = False
self.__kill_timer = None
self.child = None
- self.in_progress = None
def _normalize_cmd(self, cmd):
@@ -134,6 +130,7 @@
return cmdlist
+ @BackgroundTask.startBackgroundTask()
def start(self, args = None):
"""
Starts the process. If args is not None, it can be either a list or
@@ -166,8 +163,6 @@
MainThreadCallback(proclist.append, self, self.__child_died )
else:
proclist.append( self, self.__child_died )
- self.in_progress = InProgress()
- return self.in_progress
def get_pid(self):
@@ -330,8 +325,6 @@
self.child = None
if self.__kill_timer:
notifier.timer_remove( self.__kill_timer )
- self.in_progress.finished(status >> 8)
- self.in_progress = None
self.signals['completed'].emit(status >> 8)
--
If the facts don't fit the theory, change the facts.
-- Albert Einstein
pgp72RPj5JLiV.pgp
Description: PGP signature
------------------------------------------------------------------------- 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-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/freevo-devel
