Jason Tackaberry wrote: > On 2008-01-17 14:06, Dirk Meyer wrote: >> Yes, conceptually they are the same, but the implentation is a very >> different. 'main' needs a completly different JobServer. Right now we >> have MainThreadCallback is a simple class, we would have to greate a >> MainJobServer to inherit MainThreadCallback from JobServer. This is >> writing code without the API feeling different. >> > > It might well be the case that although they are similar in concept in > implementation they are so different that trying to reuse code will just > complicate things. I'm not too familiar with how jobserver works so I'd > have to look at it.
Please do. Attached a patch that handles ThreadCallback similar to Thread and Process but adds a __call__ method. > I find in_progress more readable actually, and more easily distinguished > from class names. But regardless, I'm going to oppose changing our > naming conventions now because this is a far, far more massive and > intrusive change than anything we've done so far (it affects almost > every other line of every kaa module) and the reason is only cosmetic. OK, it was just a test :)
Index: test/asynctest.py =================================================================== --- test/asynctest.py (revision 2969) +++ test/asynctest.py (working copy) @@ -202,6 +202,10 @@ time.sleep(0.1) kaa.notifier.step() kaa.notifier.shutdown() - + +def dummy(): + pass + +kaa.notifier.Timer(dummy).start(1) foo().connect(end) kaa.notifier.loop() Index: src/notifier/jobserver.py =================================================================== --- src/notifier/jobserver.py (revision 2969) +++ src/notifier/jobserver.py (working copy) @@ -6,7 +6,7 @@ # # ----------------------------------------------------------------------------- # kaa.notifier - Mainloop and callbacks -# Copyright (C) 2005, 2006 Dirk Meyer, Jason Tackaberry, et al. +# Copyright (C) 2005-2008 Dirk Meyer, Jason Tackaberry, et al. # # First Version: Dirk Meyer <[EMAIL PROTECTED]> # Maintainer: Dirk Meyer <[EMAIL PROTECTED]> @@ -39,7 +39,7 @@ # kaa notifier imports from callback import Signal, Callback -from async import InProgress +from async import InProgress, BackgroundTask from thread import MainThreadCallback import thread @@ -75,12 +75,10 @@ return decorator -class ThreadCallback(InProgress): +class ThreadCallback(BackgroundTask): """ A callback to run a function in a thread. This class is used by execute_in_thread, but it is also possible to use this call directly. - The class inherits from InProgress and will call the connected functions - on termination or exception. """ def __init__(self, function, *args, **kwargs): super(ThreadCallback, self).__init__() @@ -95,19 +93,37 @@ return self._server != None - def register(self, name, priority=0): + def set_thread(self, name, priority=0): """ - Register callback to a thread with the given name. + Set thread this callback should be executed it. """ - if self._server: - return self.priority = priority if not _threads.has_key(name): _threads[name] = _Thread(name) self._server = _threads[name] + + + @BackgroundTask.start_background_task() + def __call__(self): + """ + Execute the thread. set_thread _must_ before calling the + function or __call__ will crash. + """ + if not self._server: + raise RuntimeError('ThreadCallback not connected to a thread') self._server.add(self) + + def register(self, name=None, priority=0): + """ + Register callback to a thread with the given name. + """ + if self._server: + raise RuntimeError() + self.set_thread(name, priority) + return self() + def stop(self): """ Remove the callback from the thread schedule if still active. @@ -181,10 +197,10 @@ # process the job job._server = None try: - MainThreadCallback(job.finished, job._callback())() + MainThreadCallback(job.signals['completed'].emit, job._callback())() except Exception, e: e._exc_info = sys.exc_info() - MainThreadCallback(job.exception, e)() + MainThreadCallback(job.signals['exception'].emit, e)() # server stopped log.debug('stop thread %s' % self.name) 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.start_background_task() 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 start_background_task(): + 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 + + start_background_task = staticmethod(start_background_task) 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.start_background_task() 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)
-- A computer scientist is someone who, when told to 'Go to Hell', sees the 'go to', rather than the destination, as harmful.
pgpeJZBQLot3t.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 Freevo-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/freevo-devel