Author: tack
Date: Sat Feb 16 10:23:39 2008
New Revision: 3107

Log:
New AsyncException class, which is a more generic RemoteException
(RemoteException now subclasses it); when traceback is not available in
InProgress.get_result(), raise an AsyncException so that the traceback
is more useful.


Modified:
   trunk/base/src/notifier/async.py
   trunk/base/src/rpc.py

Modified: trunk/base/src/notifier/async.py
==============================================================================
--- trunk/base/src/notifier/async.py    (original)
+++ trunk/base/src/notifier/async.py    Sat Feb 16 10:23:39 2008
@@ -29,7 +29,8 @@
 #
 # -----------------------------------------------------------------------------
 
-__all__ = [ 'TimeoutException', 'InProgress', 'InProgressCallback' ]
+__all__ = [ 'TimeoutException', 'InProgress', 'InProgressCallback', 
'AsyncException',
+            'AsyncExceptionBase', 'make_exception_class' ]
 
 # python imports
 import sys
@@ -38,6 +39,7 @@
 import time
 import _weakref
 import threading
+import types
 
 # kaa.notifier imports
 from callback import Callback
@@ -46,9 +48,59 @@
 # get logging object
 log = logging.getLogger('notifier.async')
 
+
+def make_exception_class(name, bases, dict):
+    """
+    Class generator for AsyncException.  Creates AsyncException class
+    which derives the class of a particular Exception instance.
+    """
+    def create(exc, stack, *args):
+        from new import classobj
+        e = classobj(name, (exc.__class__,) + bases, dict)(*exc.args)
+        e._set_info(exc.__class__.__name__, stack, *args)
+        return e
+
+    return create
+
+
+class AsyncExceptionBase(Exception):
+    """
+    Base class for asynchronous exceptions.  This class can be used to raise
+    exceptions where the traceback object is not available.  The stack is
+    stored (which is safe to reference and can be pickled) instead, and when
+    AsyncExceptionBase instances are printed, the original traceback will
+    be printed.
+    """
+    def _set_info(self, exc_name, stack, *args):
+        self._kaa_exc_name = exc_name
+        self._kaa_exc_stack = stack
+        self._kaa_exc_args = args
+
+    def _get_header(self):
+        return 'Exception raised asynchronously; traceback follows:'
+
+    def __str__(self):
+        dump = ''.join(traceback.format_list(self._kaa_exc_stack))
+        # Python 2.5 always has self.message; for Python 2.4, fall back to
+        # first argument if it's a string.
+        msg = (hasattr(self, 'message') and self.message) or \
+              (self.args and isinstance(self.args[0], basestring) and 
self.args[0])
+        if msg:
+            info = '%s: %s' % (self._kaa_exc_name, msg)
+        else:
+            info = self._kaa_exc_name
+
+        return self._get_header() + '\n' + dump + info
+
+
+class AsyncException(AsyncExceptionBase):
+    __metaclass__ = make_exception_class
+
+
 class TimeoutException(Exception):
     pass
 
+
 class InProgress(Signal):
     """
     An InProgress class used to return from function calls that need more time
@@ -190,6 +242,7 @@
         self._finished = True
         self._exception = type, value, tb
         self._unhandled_exception = True
+        stack = traceback.extract_tb(tb)
 
         # Attach a stringified traceback to the exception object.  Right now,
         # this is the best we can do for asynchronous handlers.
@@ -228,7 +281,7 @@
 
         # Remove traceback from stored exception.  If any waiting threads
         # haven't gotten it by now, it's too late.
-        self._exception = type, value, None
+        self._exception = type, value, stack
 
         # cleanup
         self.disconnect_all()
@@ -285,9 +338,15 @@
             raise RuntimeError('operation not finished')
         if self._exception:
             self._unhandled_exception = None
-            type, value, tb = self._exception
-            # Special 3-argument form of raise; preserves traceback
-            raise type, value, tb
+            exc_type, exc_value, exc_tb_or_stack = self._exception
+            if type(exc_tb_or_stack) == types.TracebackType:
+                # We have the traceback, so we can raise using it.
+                raise exc_type, exc_value, exc_tb_or_stack
+            else:
+                # No traceback, so construct an AsyncException based on the
+                # stack.
+                raise AsyncException(exc_value, exc_tb_or_stack)
+
         return self._result
 
 

Modified: trunk/base/src/rpc.py
==============================================================================
--- trunk/base/src/rpc.py       (original)
+++ trunk/base/src/rpc.py       Sat Feb 16 10:23:39 2008
@@ -89,11 +89,11 @@
 import sys
 import sha
 import time
-from new import classobj
 import traceback
 
 # kaa imports
 import kaa
+from notifier.async import make_exception_class, AsyncExceptionBase
 
 # get logging object
 log = logging.getLogger('rpc')
@@ -101,21 +101,7 @@
 class ConnectError(Exception):
     pass
 
-
-def make_exception_class(name, bases, dict):
-    """
-    Class generator for RemoteException.  Creates RemoteException class
-    which derives the class of a particular Exception instance.
-    """
-    def create(exc, cmd, stack):
-        e = classobj(name, (exc.__class__,) + bases, dict)(*exc.args)
-        e._set_info(exc.__class__.__name__, cmd, stack)
-        return e
-
-    return create
-
-
-class RemoteException(Exception):
+class RemoteException(AsyncExceptionBase):
     """
     Raised when remote RPC calls raise exceptions.  Instances of this class
     inherit the actual remote exception class, so this works:
@@ -129,25 +115,8 @@
     traceback of the remote stack.
     """
     __metaclass__ = make_exception_class
-
-    def _set_info(self, exc_name, cmd, stack):
-        self._rpc_exc_name = exc_name
-        self._rpc_cmd = cmd
-        self._rpc_stack = stack
-
-    def __str__(self):
-        dump = ''.join(traceback.format_list(self._rpc_stack))
-        # Python 2.5 always has self.message; for Python 2.4, fall back to
-        # first argument if it's a string.
-        msg = (hasattr(self, 'message') and self.message) or \
-              (self.args and isinstance(self.args[0], basestring) and 
self.args[0])
-        if msg:
-            info = '%s: %s' % (self._rpc_exc_name, msg)
-        else:
-            info = self._rpc_exc_name
-
-        return "Exception during RPC call '%s'; remote traceback follows:\n" % 
self._rpc_cmd + \
-               dump + info
+    def _get_header(self):
+        return "Exception during RPC call '%s'; remote traceback follows:" % 
self._kaa_exc_args[0]
 
 
 class Server(object):
@@ -553,7 +522,7 @@
             if callback is None:
                 return True
             del self._rpc_in_progress[seq]
-            remote_exc = RemoteException(exc_value, cmd, stack)
+            remote_exc = RemoteException(exc_value, stack, cmd)
             callback.throw(remote_exc.__class__, remote_exc, None)
             return True
 

-------------------------------------------------------------------------
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

Reply via email to