##// END OF EJS Templates
RemoteError._render_traceback_ calls self.render_traceback...
MinRK -
Show More
@@ -1,335 +1,336
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """Classes and functions for kernel related errors and exceptions.
3 """Classes and functions for kernel related errors and exceptions.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Min RK
8 * Min RK
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 import sys
12 import sys
13 import traceback
13 import traceback
14
14
15 __docformat__ = "restructuredtext en"
15 __docformat__ = "restructuredtext en"
16
16
17 # Tell nose to skip this module
17 # Tell nose to skip this module
18 __test__ = {}
18 __test__ = {}
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Copyright (C) 2008-2011 The IPython Development Team
21 # Copyright (C) 2008-2011 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-------------------------------------------------------------------------------
25 #-------------------------------------------------------------------------------
26
26
27 #-------------------------------------------------------------------------------
27 #-------------------------------------------------------------------------------
28 # Error classes
28 # Error classes
29 #-------------------------------------------------------------------------------
29 #-------------------------------------------------------------------------------
30 class IPythonError(Exception):
30 class IPythonError(Exception):
31 """Base exception that all of our exceptions inherit from.
31 """Base exception that all of our exceptions inherit from.
32
32
33 This can be raised by code that doesn't have any more specific
33 This can be raised by code that doesn't have any more specific
34 information."""
34 information."""
35
35
36 pass
36 pass
37
37
38 # Exceptions associated with the controller objects
38 # Exceptions associated with the controller objects
39 class ControllerError(IPythonError): pass
39 class ControllerError(IPythonError): pass
40
40
41 class ControllerCreationError(ControllerError): pass
41 class ControllerCreationError(ControllerError): pass
42
42
43
43
44 # Exceptions associated with the Engines
44 # Exceptions associated with the Engines
45 class EngineError(IPythonError): pass
45 class EngineError(IPythonError): pass
46
46
47 class EngineCreationError(EngineError): pass
47 class EngineCreationError(EngineError): pass
48
48
49 class KernelError(IPythonError):
49 class KernelError(IPythonError):
50 pass
50 pass
51
51
52 class NotDefined(KernelError):
52 class NotDefined(KernelError):
53 def __init__(self, name):
53 def __init__(self, name):
54 self.name = name
54 self.name = name
55 self.args = (name,)
55 self.args = (name,)
56
56
57 def __repr__(self):
57 def __repr__(self):
58 return '<NotDefined: %s>' % self.name
58 return '<NotDefined: %s>' % self.name
59
59
60 __str__ = __repr__
60 __str__ = __repr__
61
61
62
62
63 class QueueCleared(KernelError):
63 class QueueCleared(KernelError):
64 pass
64 pass
65
65
66
66
67 class IdInUse(KernelError):
67 class IdInUse(KernelError):
68 pass
68 pass
69
69
70
70
71 class ProtocolError(KernelError):
71 class ProtocolError(KernelError):
72 pass
72 pass
73
73
74
74
75 class ConnectionError(KernelError):
75 class ConnectionError(KernelError):
76 pass
76 pass
77
77
78
78
79 class InvalidEngineID(KernelError):
79 class InvalidEngineID(KernelError):
80 pass
80 pass
81
81
82
82
83 class NoEnginesRegistered(KernelError):
83 class NoEnginesRegistered(KernelError):
84 pass
84 pass
85
85
86
86
87 class InvalidClientID(KernelError):
87 class InvalidClientID(KernelError):
88 pass
88 pass
89
89
90
90
91 class InvalidDeferredID(KernelError):
91 class InvalidDeferredID(KernelError):
92 pass
92 pass
93
93
94
94
95 class SerializationError(KernelError):
95 class SerializationError(KernelError):
96 pass
96 pass
97
97
98
98
99 class MessageSizeError(KernelError):
99 class MessageSizeError(KernelError):
100 pass
100 pass
101
101
102
102
103 class PBMessageSizeError(MessageSizeError):
103 class PBMessageSizeError(MessageSizeError):
104 pass
104 pass
105
105
106
106
107 class ResultNotCompleted(KernelError):
107 class ResultNotCompleted(KernelError):
108 pass
108 pass
109
109
110
110
111 class ResultAlreadyRetrieved(KernelError):
111 class ResultAlreadyRetrieved(KernelError):
112 pass
112 pass
113
113
114 class ClientError(KernelError):
114 class ClientError(KernelError):
115 pass
115 pass
116
116
117
117
118 class TaskAborted(KernelError):
118 class TaskAborted(KernelError):
119 pass
119 pass
120
120
121
121
122 class TaskTimeout(KernelError):
122 class TaskTimeout(KernelError):
123 pass
123 pass
124
124
125
125
126 class NotAPendingResult(KernelError):
126 class NotAPendingResult(KernelError):
127 pass
127 pass
128
128
129
129
130 class UnpickleableException(KernelError):
130 class UnpickleableException(KernelError):
131 pass
131 pass
132
132
133
133
134 class AbortedPendingDeferredError(KernelError):
134 class AbortedPendingDeferredError(KernelError):
135 pass
135 pass
136
136
137
137
138 class InvalidProperty(KernelError):
138 class InvalidProperty(KernelError):
139 pass
139 pass
140
140
141
141
142 class MissingBlockArgument(KernelError):
142 class MissingBlockArgument(KernelError):
143 pass
143 pass
144
144
145
145
146 class StopLocalExecution(KernelError):
146 class StopLocalExecution(KernelError):
147 pass
147 pass
148
148
149
149
150 class SecurityError(KernelError):
150 class SecurityError(KernelError):
151 pass
151 pass
152
152
153
153
154 class FileTimeoutError(KernelError):
154 class FileTimeoutError(KernelError):
155 pass
155 pass
156
156
157 class TimeoutError(KernelError):
157 class TimeoutError(KernelError):
158 pass
158 pass
159
159
160 class UnmetDependency(KernelError):
160 class UnmetDependency(KernelError):
161 pass
161 pass
162
162
163 class ImpossibleDependency(UnmetDependency):
163 class ImpossibleDependency(UnmetDependency):
164 pass
164 pass
165
165
166 class DependencyTimeout(ImpossibleDependency):
166 class DependencyTimeout(ImpossibleDependency):
167 pass
167 pass
168
168
169 class InvalidDependency(ImpossibleDependency):
169 class InvalidDependency(ImpossibleDependency):
170 pass
170 pass
171
171
172 class RemoteError(KernelError):
172 class RemoteError(KernelError):
173 """Error raised elsewhere"""
173 """Error raised elsewhere"""
174 ename=None
174 ename=None
175 evalue=None
175 evalue=None
176 traceback=None
176 traceback=None
177 engine_info=None
177 engine_info=None
178
178
179 def __init__(self, ename, evalue, traceback, engine_info=None):
179 def __init__(self, ename, evalue, traceback, engine_info=None):
180 self.ename=ename
180 self.ename=ename
181 self.evalue=evalue
181 self.evalue=evalue
182 self.traceback=traceback
182 self.traceback=traceback
183 self.engine_info=engine_info or {}
183 self.engine_info=engine_info or {}
184 self.args=(ename, evalue)
184 self.args=(ename, evalue)
185
185
186 def __repr__(self):
186 def __repr__(self):
187 engineid = self.engine_info.get('engine_id', ' ')
187 engineid = self.engine_info.get('engine_id', ' ')
188 return "<Remote[%s]:%s(%s)>"%(engineid, self.ename, self.evalue)
188 return "<Remote[%s]:%s(%s)>"%(engineid, self.ename, self.evalue)
189
189
190 def __str__(self):
190 def __str__(self):
191 return "%s(%s)" % (self.ename, self.evalue)
191 return "%s(%s)" % (self.ename, self.evalue)
192
192
193 def render_traceback(self):
193 def render_traceback(self):
194 """render traceback to a list of lines"""
194 """render traceback to a list of lines"""
195 return (self.traceback or "No traceback available").splitlines()
195 return (self.traceback or "No traceback available").splitlines()
196
196
197 # Special method for custom tracebacks within IPython
197 # Special method for custom tracebacks within IPython
198 _render_traceback_ = render_traceback
198 def _render_traceback_(self):
199 return self.render_traceback()
199
200
200 def print_traceback(self, excid=None):
201 def print_traceback(self, excid=None):
201 """print my traceback"""
202 """print my traceback"""
202 print('\n'.join(self.render_traceback()))
203 print('\n'.join(self.render_traceback()))
203
204
204
205
205
206
206
207
207 class TaskRejectError(KernelError):
208 class TaskRejectError(KernelError):
208 """Exception to raise when a task should be rejected by an engine.
209 """Exception to raise when a task should be rejected by an engine.
209
210
210 This exception can be used to allow a task running on an engine to test
211 This exception can be used to allow a task running on an engine to test
211 if the engine (or the user's namespace on the engine) has the needed
212 if the engine (or the user's namespace on the engine) has the needed
212 task dependencies. If not, the task should raise this exception. For
213 task dependencies. If not, the task should raise this exception. For
213 the task to be retried on another engine, the task should be created
214 the task to be retried on another engine, the task should be created
214 with the `retries` argument > 1.
215 with the `retries` argument > 1.
215
216
216 The advantage of this approach over our older properties system is that
217 The advantage of this approach over our older properties system is that
217 tasks have full access to the user's namespace on the engines and the
218 tasks have full access to the user's namespace on the engines and the
218 properties don't have to be managed or tested by the controller.
219 properties don't have to be managed or tested by the controller.
219 """
220 """
220
221
221
222
222 class CompositeError(RemoteError):
223 class CompositeError(RemoteError):
223 """Error for representing possibly multiple errors on engines"""
224 """Error for representing possibly multiple errors on engines"""
224 def __init__(self, message, elist):
225 def __init__(self, message, elist):
225 Exception.__init__(self, *(message, elist))
226 Exception.__init__(self, *(message, elist))
226 # Don't use pack_exception because it will conflict with the .message
227 # Don't use pack_exception because it will conflict with the .message
227 # attribute that is being deprecated in 2.6 and beyond.
228 # attribute that is being deprecated in 2.6 and beyond.
228 self.msg = message
229 self.msg = message
229 self.elist = elist
230 self.elist = elist
230 self.args = [ e[0] for e in elist ]
231 self.args = [ e[0] for e in elist ]
231
232
232 def _get_engine_str(self, ei):
233 def _get_engine_str(self, ei):
233 if not ei:
234 if not ei:
234 return '[Engine Exception]'
235 return '[Engine Exception]'
235 else:
236 else:
236 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
237 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
237
238
238 def _get_traceback(self, ev):
239 def _get_traceback(self, ev):
239 try:
240 try:
240 tb = ev._ipython_traceback_text
241 tb = ev._ipython_traceback_text
241 except AttributeError:
242 except AttributeError:
242 return 'No traceback available'
243 return 'No traceback available'
243 else:
244 else:
244 return tb
245 return tb
245
246
246 def __str__(self):
247 def __str__(self):
247 s = str(self.msg)
248 s = str(self.msg)
248 for en, ev, etb, ei in self.elist:
249 for en, ev, etb, ei in self.elist:
249 engine_str = self._get_engine_str(ei)
250 engine_str = self._get_engine_str(ei)
250 s = s + '\n' + engine_str + en + ': ' + str(ev)
251 s = s + '\n' + engine_str + en + ': ' + str(ev)
251 return s
252 return s
252
253
253 def __repr__(self):
254 def __repr__(self):
254 return "CompositeError(%i)"%len(self.elist)
255 return "CompositeError(%i)"%len(self.elist)
255
256
256 def render_traceback(self, excid=None):
257 def render_traceback(self, excid=None):
257 """render one or all of my tracebacks to a list of lines"""
258 """render one or all of my tracebacks to a list of lines"""
258 lines = []
259 lines = []
259 if excid is None:
260 if excid is None:
260 for (en,ev,etb,ei) in self.elist:
261 for (en,ev,etb,ei) in self.elist:
261 lines.append(self._get_engine_str(ei))
262 lines.append(self._get_engine_str(ei))
262 lines.extend((etb or 'No traceback available').splitlines())
263 lines.extend((etb or 'No traceback available').splitlines())
263 lines.append('')
264 lines.append('')
264 else:
265 else:
265 try:
266 try:
266 en,ev,etb,ei = self.elist[excid]
267 en,ev,etb,ei = self.elist[excid]
267 except:
268 except:
268 raise IndexError("an exception with index %i does not exist"%excid)
269 raise IndexError("an exception with index %i does not exist"%excid)
269 else:
270 else:
270 lines.append(self._get_engine_str(ei))
271 lines.append(self._get_engine_str(ei))
271 lines.extend((etb or 'No traceback available').splitlines())
272 lines.extend((etb or 'No traceback available').splitlines())
272
273
273 return lines
274 return lines
274
275
275 def print_traceback(self, excid=None):
276 def print_traceback(self, excid=None):
276 print('\n'.join(self.render_traceback(excid)))
277 print('\n'.join(self.render_traceback(excid)))
277
278
278 def raise_exception(self, excid=0):
279 def raise_exception(self, excid=0):
279 try:
280 try:
280 en,ev,etb,ei = self.elist[excid]
281 en,ev,etb,ei = self.elist[excid]
281 except:
282 except:
282 raise IndexError("an exception with index %i does not exist"%excid)
283 raise IndexError("an exception with index %i does not exist"%excid)
283 else:
284 else:
284 raise RemoteError(en, ev, etb, ei)
285 raise RemoteError(en, ev, etb, ei)
285
286
286
287
287 def collect_exceptions(rdict_or_list, method='unspecified'):
288 def collect_exceptions(rdict_or_list, method='unspecified'):
288 """check a result dict for errors, and raise CompositeError if any exist.
289 """check a result dict for errors, and raise CompositeError if any exist.
289 Passthrough otherwise."""
290 Passthrough otherwise."""
290 elist = []
291 elist = []
291 if isinstance(rdict_or_list, dict):
292 if isinstance(rdict_or_list, dict):
292 rlist = rdict_or_list.values()
293 rlist = rdict_or_list.values()
293 else:
294 else:
294 rlist = rdict_or_list
295 rlist = rdict_or_list
295 for r in rlist:
296 for r in rlist:
296 if isinstance(r, RemoteError):
297 if isinstance(r, RemoteError):
297 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
298 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
298 # Sometimes we could have CompositeError in our list. Just take
299 # Sometimes we could have CompositeError in our list. Just take
299 # the errors out of them and put them in our new list. This
300 # the errors out of them and put them in our new list. This
300 # has the effect of flattening lists of CompositeErrors into one
301 # has the effect of flattening lists of CompositeErrors into one
301 # CompositeError
302 # CompositeError
302 if en=='CompositeError':
303 if en=='CompositeError':
303 for e in ev.elist:
304 for e in ev.elist:
304 elist.append(e)
305 elist.append(e)
305 else:
306 else:
306 elist.append((en, ev, etb, ei))
307 elist.append((en, ev, etb, ei))
307 if len(elist)==0:
308 if len(elist)==0:
308 return rdict_or_list
309 return rdict_or_list
309 else:
310 else:
310 msg = "one or more exceptions from call to method: %s" % (method)
311 msg = "one or more exceptions from call to method: %s" % (method)
311 # This silliness is needed so the debugger has access to the exception
312 # This silliness is needed so the debugger has access to the exception
312 # instance (e in this case)
313 # instance (e in this case)
313 try:
314 try:
314 raise CompositeError(msg, elist)
315 raise CompositeError(msg, elist)
315 except CompositeError as e:
316 except CompositeError as e:
316 raise e
317 raise e
317
318
318 def wrap_exception(engine_info={}):
319 def wrap_exception(engine_info={}):
319 etype, evalue, tb = sys.exc_info()
320 etype, evalue, tb = sys.exc_info()
320 stb = traceback.format_exception(etype, evalue, tb)
321 stb = traceback.format_exception(etype, evalue, tb)
321 exc_content = {
322 exc_content = {
322 'status' : 'error',
323 'status' : 'error',
323 'traceback' : stb,
324 'traceback' : stb,
324 'ename' : unicode(etype.__name__),
325 'ename' : unicode(etype.__name__),
325 'evalue' : unicode(evalue),
326 'evalue' : unicode(evalue),
326 'engine_info' : engine_info
327 'engine_info' : engine_info
327 }
328 }
328 return exc_content
329 return exc_content
329
330
330 def unwrap_exception(content):
331 def unwrap_exception(content):
331 err = RemoteError(content['ename'], content['evalue'],
332 err = RemoteError(content['ename'], content['evalue'],
332 ''.join(content['traceback']),
333 ''.join(content['traceback']),
333 content.get('engine_info', {}))
334 content.get('engine_info', {}))
334 return err
335 return err
335
336
General Comments 0
You need to be logged in to leave comments. Login now