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