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 [email protected] https://lists.sourceforge.net/lists/listinfo/freevo-devel
