##// END OF EJS Templates
docstring on _render_traceback_
MinRK -
Show More
@@ -1,336 +1,341 b''
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
198 def _render_traceback_(self):
197 def _render_traceback_(self):
198 """Special method for custom tracebacks within IPython.
199
200 This will be called by IPython instead of displaying the local traceback.
201
202 It should return a traceback rendered as a list of lines.
203 """
199 return self.render_traceback()
204 return self.render_traceback()
200
205
201 def print_traceback(self, excid=None):
206 def print_traceback(self, excid=None):
202 """print my traceback"""
207 """print my traceback"""
203 print('\n'.join(self.render_traceback()))
208 print('\n'.join(self.render_traceback()))
204
209
205
210
206
211
207
212
208 class TaskRejectError(KernelError):
213 class TaskRejectError(KernelError):
209 """Exception to raise when a task should be rejected by an engine.
214 """Exception to raise when a task should be rejected by an engine.
210
215
211 This exception can be used to allow a task running on an engine to test
216 This exception can be used to allow a task running on an engine to test
212 if the engine (or the user's namespace on the engine) has the needed
217 if the engine (or the user's namespace on the engine) has the needed
213 task dependencies. If not, the task should raise this exception. For
218 task dependencies. If not, the task should raise this exception. For
214 the task to be retried on another engine, the task should be created
219 the task to be retried on another engine, the task should be created
215 with the `retries` argument > 1.
220 with the `retries` argument > 1.
216
221
217 The advantage of this approach over our older properties system is that
222 The advantage of this approach over our older properties system is that
218 tasks have full access to the user's namespace on the engines and the
223 tasks have full access to the user's namespace on the engines and the
219 properties don't have to be managed or tested by the controller.
224 properties don't have to be managed or tested by the controller.
220 """
225 """
221
226
222
227
223 class CompositeError(RemoteError):
228 class CompositeError(RemoteError):
224 """Error for representing possibly multiple errors on engines"""
229 """Error for representing possibly multiple errors on engines"""
225 def __init__(self, message, elist):
230 def __init__(self, message, elist):
226 Exception.__init__(self, *(message, elist))
231 Exception.__init__(self, *(message, elist))
227 # Don't use pack_exception because it will conflict with the .message
232 # Don't use pack_exception because it will conflict with the .message
228 # attribute that is being deprecated in 2.6 and beyond.
233 # attribute that is being deprecated in 2.6 and beyond.
229 self.msg = message
234 self.msg = message
230 self.elist = elist
235 self.elist = elist
231 self.args = [ e[0] for e in elist ]
236 self.args = [ e[0] for e in elist ]
232
237
233 def _get_engine_str(self, ei):
238 def _get_engine_str(self, ei):
234 if not ei:
239 if not ei:
235 return '[Engine Exception]'
240 return '[Engine Exception]'
236 else:
241 else:
237 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
242 return '[%s:%s]: ' % (ei['engine_id'], ei['method'])
238
243
239 def _get_traceback(self, ev):
244 def _get_traceback(self, ev):
240 try:
245 try:
241 tb = ev._ipython_traceback_text
246 tb = ev._ipython_traceback_text
242 except AttributeError:
247 except AttributeError:
243 return 'No traceback available'
248 return 'No traceback available'
244 else:
249 else:
245 return tb
250 return tb
246
251
247 def __str__(self):
252 def __str__(self):
248 s = str(self.msg)
253 s = str(self.msg)
249 for en, ev, etb, ei in self.elist:
254 for en, ev, etb, ei in self.elist:
250 engine_str = self._get_engine_str(ei)
255 engine_str = self._get_engine_str(ei)
251 s = s + '\n' + engine_str + en + ': ' + str(ev)
256 s = s + '\n' + engine_str + en + ': ' + str(ev)
252 return s
257 return s
253
258
254 def __repr__(self):
259 def __repr__(self):
255 return "CompositeError(%i)"%len(self.elist)
260 return "CompositeError(%i)"%len(self.elist)
256
261
257 def render_traceback(self, excid=None):
262 def render_traceback(self, excid=None):
258 """render one or all of my tracebacks to a list of lines"""
263 """render one or all of my tracebacks to a list of lines"""
259 lines = []
264 lines = []
260 if excid is None:
265 if excid is None:
261 for (en,ev,etb,ei) in self.elist:
266 for (en,ev,etb,ei) in self.elist:
262 lines.append(self._get_engine_str(ei))
267 lines.append(self._get_engine_str(ei))
263 lines.extend((etb or 'No traceback available').splitlines())
268 lines.extend((etb or 'No traceback available').splitlines())
264 lines.append('')
269 lines.append('')
265 else:
270 else:
266 try:
271 try:
267 en,ev,etb,ei = self.elist[excid]
272 en,ev,etb,ei = self.elist[excid]
268 except:
273 except:
269 raise IndexError("an exception with index %i does not exist"%excid)
274 raise IndexError("an exception with index %i does not exist"%excid)
270 else:
275 else:
271 lines.append(self._get_engine_str(ei))
276 lines.append(self._get_engine_str(ei))
272 lines.extend((etb or 'No traceback available').splitlines())
277 lines.extend((etb or 'No traceback available').splitlines())
273
278
274 return lines
279 return lines
275
280
276 def print_traceback(self, excid=None):
281 def print_traceback(self, excid=None):
277 print('\n'.join(self.render_traceback(excid)))
282 print('\n'.join(self.render_traceback(excid)))
278
283
279 def raise_exception(self, excid=0):
284 def raise_exception(self, excid=0):
280 try:
285 try:
281 en,ev,etb,ei = self.elist[excid]
286 en,ev,etb,ei = self.elist[excid]
282 except:
287 except:
283 raise IndexError("an exception with index %i does not exist"%excid)
288 raise IndexError("an exception with index %i does not exist"%excid)
284 else:
289 else:
285 raise RemoteError(en, ev, etb, ei)
290 raise RemoteError(en, ev, etb, ei)
286
291
287
292
288 def collect_exceptions(rdict_or_list, method='unspecified'):
293 def collect_exceptions(rdict_or_list, method='unspecified'):
289 """check a result dict for errors, and raise CompositeError if any exist.
294 """check a result dict for errors, and raise CompositeError if any exist.
290 Passthrough otherwise."""
295 Passthrough otherwise."""
291 elist = []
296 elist = []
292 if isinstance(rdict_or_list, dict):
297 if isinstance(rdict_or_list, dict):
293 rlist = rdict_or_list.values()
298 rlist = rdict_or_list.values()
294 else:
299 else:
295 rlist = rdict_or_list
300 rlist = rdict_or_list
296 for r in rlist:
301 for r in rlist:
297 if isinstance(r, RemoteError):
302 if isinstance(r, RemoteError):
298 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
303 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
299 # Sometimes we could have CompositeError in our list. Just take
304 # Sometimes we could have CompositeError in our list. Just take
300 # the errors out of them and put them in our new list. This
305 # the errors out of them and put them in our new list. This
301 # has the effect of flattening lists of CompositeErrors into one
306 # has the effect of flattening lists of CompositeErrors into one
302 # CompositeError
307 # CompositeError
303 if en=='CompositeError':
308 if en=='CompositeError':
304 for e in ev.elist:
309 for e in ev.elist:
305 elist.append(e)
310 elist.append(e)
306 else:
311 else:
307 elist.append((en, ev, etb, ei))
312 elist.append((en, ev, etb, ei))
308 if len(elist)==0:
313 if len(elist)==0:
309 return rdict_or_list
314 return rdict_or_list
310 else:
315 else:
311 msg = "one or more exceptions from call to method: %s" % (method)
316 msg = "one or more exceptions from call to method: %s" % (method)
312 # This silliness is needed so the debugger has access to the exception
317 # This silliness is needed so the debugger has access to the exception
313 # instance (e in this case)
318 # instance (e in this case)
314 try:
319 try:
315 raise CompositeError(msg, elist)
320 raise CompositeError(msg, elist)
316 except CompositeError as e:
321 except CompositeError as e:
317 raise e
322 raise e
318
323
319 def wrap_exception(engine_info={}):
324 def wrap_exception(engine_info={}):
320 etype, evalue, tb = sys.exc_info()
325 etype, evalue, tb = sys.exc_info()
321 stb = traceback.format_exception(etype, evalue, tb)
326 stb = traceback.format_exception(etype, evalue, tb)
322 exc_content = {
327 exc_content = {
323 'status' : 'error',
328 'status' : 'error',
324 'traceback' : stb,
329 'traceback' : stb,
325 'ename' : unicode(etype.__name__),
330 'ename' : unicode(etype.__name__),
326 'evalue' : unicode(evalue),
331 'evalue' : unicode(evalue),
327 'engine_info' : engine_info
332 'engine_info' : engine_info
328 }
333 }
329 return exc_content
334 return exc_content
330
335
331 def unwrap_exception(content):
336 def unwrap_exception(content):
332 err = RemoteError(content['ename'], content['evalue'],
337 err = RemoteError(content['ename'], content['evalue'],
333 ''.join(content['traceback']),
338 ''.join(content['traceback']),
334 content.get('engine_info', {}))
339 content.get('engine_info', {}))
335 return err
340 return err
336
341
General Comments 0
You need to be logged in to leave comments. Login now