error.py
205 lines
| 5.6 KiB
| text/x-python
|
PythonLexer
Brian E Granger
|
r1234 | # encoding: utf-8 | ||
"""Classes and functions for kernel related errors and exceptions.""" | ||||
__docformat__ = "restructuredtext en" | ||||
Fernando Perez
|
r2133 | # Tell nose to skip this module | ||
__test__ = {} | ||||
Brian E Granger
|
r1234 | #------------------------------------------------------------------------------- | ||
# Copyright (C) 2008 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#------------------------------------------------------------------------------- | ||||
#------------------------------------------------------------------------------- | ||||
# Imports | ||||
#------------------------------------------------------------------------------- | ||||
Fernando Perez
|
r2133 | from twisted.python import failure | ||
Brian E Granger
|
r1234 | |||
from IPython.kernel.core import error | ||||
#------------------------------------------------------------------------------- | ||||
# Error classes | ||||
#------------------------------------------------------------------------------- | ||||
class KernelError(error.IPythonError): | ||||
pass | ||||
class NotDefined(KernelError): | ||||
def __init__(self, name): | ||||
self.name = name | ||||
self.args = (name,) | ||||
def __repr__(self): | ||||
return '<NotDefined: %s>' % self.name | ||||
__str__ = __repr__ | ||||
class QueueCleared(KernelError): | ||||
pass | ||||
class IdInUse(KernelError): | ||||
pass | ||||
class ProtocolError(KernelError): | ||||
pass | ||||
class ConnectionError(KernelError): | ||||
pass | ||||
class InvalidEngineID(KernelError): | ||||
pass | ||||
class NoEnginesRegistered(KernelError): | ||||
pass | ||||
class InvalidClientID(KernelError): | ||||
pass | ||||
class InvalidDeferredID(KernelError): | ||||
pass | ||||
class SerializationError(KernelError): | ||||
pass | ||||
class MessageSizeError(KernelError): | ||||
pass | ||||
class PBMessageSizeError(MessageSizeError): | ||||
pass | ||||
class ResultNotCompleted(KernelError): | ||||
pass | ||||
class ResultAlreadyRetrieved(KernelError): | ||||
pass | ||||
class ClientError(KernelError): | ||||
pass | ||||
class TaskAborted(KernelError): | ||||
pass | ||||
class TaskTimeout(KernelError): | ||||
pass | ||||
class NotAPendingResult(KernelError): | ||||
pass | ||||
class UnpickleableException(KernelError): | ||||
pass | ||||
class AbortedPendingDeferredError(KernelError): | ||||
pass | ||||
class InvalidProperty(KernelError): | ||||
pass | ||||
class MissingBlockArgument(KernelError): | ||||
pass | ||||
class StopLocalExecution(KernelError): | ||||
pass | ||||
class SecurityError(KernelError): | ||||
pass | ||||
Brian Granger
|
r1944 | class FileTimeoutError(KernelError): | ||
pass | ||||
Brian Granger
|
r1952 | class TaskRejectError(KernelError): | ||
"""Exception to raise when a task should be rejected by an engine. | ||||
This exception can be used to allow a task running on an engine to test | ||||
if the engine (or the user's namespace on the engine) has the needed | ||||
task dependencies. If not, the task should raise this exception. For | ||||
the task to be retried on another engine, the task should be created | ||||
with the `retries` argument > 1. | ||||
The advantage of this approach over our older properties system is that | ||||
tasks have full access to the user's namespace on the engines and the | ||||
properties don't have to be managed or tested by the controller. | ||||
""" | ||||
Brian E Granger
|
r1234 | class CompositeError(KernelError): | ||
def __init__(self, message, elist): | ||||
Exception.__init__(self, *(message, elist)) | ||||
self.message = message | ||||
self.elist = elist | ||||
def _get_engine_str(self, ev): | ||||
try: | ||||
ei = ev._ipython_engine_info | ||||
except AttributeError: | ||||
return '[Engine Exception]' | ||||
else: | ||||
return '[%i:%s]: ' % (ei['engineid'], ei['method']) | ||||
def _get_traceback(self, ev): | ||||
try: | ||||
tb = ev._ipython_traceback_text | ||||
except AttributeError: | ||||
return 'No traceback available' | ||||
else: | ||||
return tb | ||||
def __str__(self): | ||||
s = str(self.message) | ||||
for et, ev, etb in self.elist: | ||||
engine_str = self._get_engine_str(ev) | ||||
s = s + '\n' + engine_str + str(et.__name__) + ': ' + str(ev) | ||||
return s | ||||
def print_tracebacks(self, excid=None): | ||||
if excid is None: | ||||
for (et,ev,etb) in self.elist: | ||||
print self._get_engine_str(ev) | ||||
print self._get_traceback(ev) | ||||
else: | ||||
try: | ||||
et,ev,etb = self.elist[excid] | ||||
except: | ||||
raise IndexError("an exception with index %i does not exist"%excid) | ||||
else: | ||||
print self._get_engine_str(ev) | ||||
print self._get_traceback(ev) | ||||
def raise_exception(self, excid=0): | ||||
try: | ||||
et,ev,etb = self.elist[excid] | ||||
except: | ||||
raise IndexError("an exception with index %i does not exist"%excid) | ||||
else: | ||||
raise et, ev, etb | ||||
def collect_exceptions(rlist, method): | ||||
elist = [] | ||||
for r in rlist: | ||||
if isinstance(r, failure.Failure): | ||||
r.cleanFailure() | ||||
et, ev, etb = r.type, r.value, r.tb | ||||
# Sometimes we could have CompositeError in our list. Just take | ||||
# the errors out of them and put them in our new list. This | ||||
# has the effect of flattening lists of CompositeErrors into one | ||||
# CompositeError | ||||
if et==CompositeError: | ||||
for e in ev.elist: | ||||
elist.append(e) | ||||
else: | ||||
elist.append((et, ev, etb)) | ||||
if len(elist)==0: | ||||
return rlist | ||||
else: | ||||
msg = "one or more exceptions from call to method: %s" % (method) | ||||
# This silliness is needed so the debugger has access to the exception | ||||
# instance (e in this case) | ||||
try: | ||||
raise CompositeError(msg, elist) | ||||
except CompositeError, e: | ||||
raise e | ||||