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