##// END OF EJS Templates
Fixed bug in ultratb.py and io.py....
Brian Granger -
Show More
@@ -1,1102 +1,1104
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ultratb.py -- Spice up your tracebacks!
4 4
5 5 * ColorTB
6 6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 7 ColorTB class is a solution to that problem. It colors the different parts of a
8 8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 9 text editor.
10 10
11 11 Installation instructions for ColorTB:
12 12 import sys,ultratb
13 13 sys.excepthook = ultratb.ColorTB()
14 14
15 15 * VerboseTB
16 16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 18 and intended it for CGI programmers, but why should they have all the fun? I
19 19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 20 but kind of neat, and maybe useful for long-running programs that you believe
21 21 are bug-free. If a crash *does* occur in that type of program you want details.
22 22 Give it a shot--you'll love it or you'll hate it.
23 23
24 24 Note:
25 25
26 26 The Verbose mode prints the variables currently visible where the exception
27 27 happened (shortening their strings if too long). This can potentially be
28 28 very slow, if you happen to have a huge data structure whose string
29 29 representation is complex to compute. Your computer may appear to freeze for
30 30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 31 with Ctrl-C (maybe hitting it more than once).
32 32
33 33 If you encounter this kind of situation often, you may want to use the
34 34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 35 variables (but otherwise includes the information and context given by
36 36 Verbose).
37 37
38 38
39 39 Installation instructions for ColorTB:
40 40 import sys,ultratb
41 41 sys.excepthook = ultratb.VerboseTB()
42 42
43 43 Note: Much of the code in this module was lifted verbatim from the standard
44 44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45 45
46 46 * Color schemes
47 47 The colors are defined in the class TBTools through the use of the
48 48 ColorSchemeTable class. Currently the following exist:
49 49
50 50 - NoColor: allows all of this module to be used in any terminal (the color
51 51 escapes are just dummy blank strings).
52 52
53 53 - Linux: is meant to look good in a terminal like the Linux console (black
54 54 or very dark background).
55 55
56 56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 57 in light background terminals.
58 58
59 59 You can implement other color schemes easily, the syntax is fairly
60 60 self-explanatory. Please send back new schemes you develop to the author for
61 61 possible inclusion in future releases.
62 62 """
63 63
64 64 #*****************************************************************************
65 65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 67 #
68 68 # Distributed under the terms of the BSD License. The full license is in
69 69 # the file COPYING, distributed as part of this software.
70 70 #*****************************************************************************
71 71
72 72 from __future__ import with_statement
73 73
74 74 import inspect
75 75 import keyword
76 76 import linecache
77 77 import os
78 78 import pydoc
79 79 import re
80 80 import string
81 81 import sys
82 82 import time
83 83 import tokenize
84 84 import traceback
85 85 import types
86 86
87 87 # For purposes of monkeypatching inspect to fix a bug in it.
88 88 from inspect import getsourcefile, getfile, getmodule,\
89 89 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
90 90
91 91 # IPython's own modules
92 92 # Modified pdb which doesn't damage IPython's readline handling
93 93 from IPython.utils import PyColorize
94 94 from IPython.core import debugger, ipapi
95 95 from IPython.core.display_trap import DisplayTrap
96 96 from IPython.core.excolors import exception_colors
97 97 from IPython.utils.data import uniq_stable
98 98 from IPython.utils.io import Term
99 99 from IPython.utils.warn import info, error
100 100
101 101 # Globals
102 102 # amount of space to put line numbers before verbose tracebacks
103 103 INDENT_SIZE = 8
104 104
105 105 # Default color scheme. This is used, for example, by the traceback
106 106 # formatter. When running in an actual IPython instance, the user's rc.colors
107 107 # value is used, but havinga module global makes this functionality available
108 108 # to users of ultratb who are NOT running inside ipython.
109 109 DEFAULT_SCHEME = 'NoColor'
110 110
111 111 #---------------------------------------------------------------------------
112 112 # Code begins
113 113
114 114 # Utility functions
115 115 def inspect_error():
116 116 """Print a message about internal inspect errors.
117 117
118 118 These are unfortunately quite common."""
119 119
120 120 error('Internal Python error in the inspect module.\n'
121 121 'Below is the traceback from this internal error.\n')
122 122
123 123
124 124 def findsource(object):
125 125 """Return the entire source file and starting line number for an object.
126 126
127 127 The argument may be a module, class, method, function, traceback, frame,
128 128 or code object. The source code is returned as a list of all the lines
129 129 in the file and the line number indexes a line in that list. An IOError
130 130 is raised if the source code cannot be retrieved.
131 131
132 132 FIXED version with which we monkeypatch the stdlib to work around a bug."""
133 133
134 134 file = getsourcefile(object) or getfile(object)
135 135 # If the object is a frame, then trying to get the globals dict from its
136 136 # module won't work. Instead, the frame object itself has the globals
137 137 # dictionary.
138 138 globals_dict = None
139 139 if inspect.isframe(object):
140 140 # XXX: can this ever be false?
141 141 globals_dict = object.f_globals
142 142 else:
143 143 module = getmodule(object, file)
144 144 if module:
145 145 globals_dict = module.__dict__
146 146 lines = linecache.getlines(file, globals_dict)
147 147 if not lines:
148 148 raise IOError('could not get source code')
149 149
150 150 if ismodule(object):
151 151 return lines, 0
152 152
153 153 if isclass(object):
154 154 name = object.__name__
155 155 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
156 156 # make some effort to find the best matching class definition:
157 157 # use the one with the least indentation, which is the one
158 158 # that's most probably not inside a function definition.
159 159 candidates = []
160 160 for i in range(len(lines)):
161 161 match = pat.match(lines[i])
162 162 if match:
163 163 # if it's at toplevel, it's already the best one
164 164 if lines[i][0] == 'c':
165 165 return lines, i
166 166 # else add whitespace to candidate list
167 167 candidates.append((match.group(1), i))
168 168 if candidates:
169 169 # this will sort by whitespace, and by line number,
170 170 # less whitespace first
171 171 candidates.sort()
172 172 return lines, candidates[0][1]
173 173 else:
174 174 raise IOError('could not find class definition')
175 175
176 176 if ismethod(object):
177 177 object = object.im_func
178 178 if isfunction(object):
179 179 object = object.func_code
180 180 if istraceback(object):
181 181 object = object.tb_frame
182 182 if isframe(object):
183 183 object = object.f_code
184 184 if iscode(object):
185 185 if not hasattr(object, 'co_firstlineno'):
186 186 raise IOError('could not find function definition')
187 187 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
188 188 pmatch = pat.match
189 189 # fperez - fix: sometimes, co_firstlineno can give a number larger than
190 190 # the length of lines, which causes an error. Safeguard against that.
191 191 lnum = min(object.co_firstlineno,len(lines))-1
192 192 while lnum > 0:
193 193 if pmatch(lines[lnum]): break
194 194 lnum -= 1
195 195
196 196 return lines, lnum
197 197 raise IOError('could not find code object')
198 198
199 199 # Monkeypatch inspect to apply our bugfix. This code only works with py25
200 200 if sys.version_info[:2] >= (2,5):
201 201 inspect.findsource = findsource
202 202
203 203 def fix_frame_records_filenames(records):
204 204 """Try to fix the filenames in each record from inspect.getinnerframes().
205 205
206 206 Particularly, modules loaded from within zip files have useless filenames
207 207 attached to their code object, and inspect.getinnerframes() just uses it.
208 208 """
209 209 fixed_records = []
210 210 for frame, filename, line_no, func_name, lines, index in records:
211 211 # Look inside the frame's globals dictionary for __file__, which should
212 212 # be better.
213 213 better_fn = frame.f_globals.get('__file__', None)
214 214 if isinstance(better_fn, str):
215 215 # Check the type just in case someone did something weird with
216 216 # __file__. It might also be None if the error occurred during
217 217 # import.
218 218 filename = better_fn
219 219 fixed_records.append((frame, filename, line_no, func_name, lines, index))
220 220 return fixed_records
221 221
222 222
223 223 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
224 224 import linecache
225 225 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
226 226
227 227 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
228 228
229 229 # If the error is at the console, don't build any context, since it would
230 230 # otherwise produce 5 blank lines printed out (there is no file at the
231 231 # console)
232 232 rec_check = records[tb_offset:]
233 233 try:
234 234 rname = rec_check[0][1]
235 235 if rname == '<ipython console>' or rname.endswith('<string>'):
236 236 return rec_check
237 237 except IndexError:
238 238 pass
239 239
240 240 aux = traceback.extract_tb(etb)
241 241 assert len(records) == len(aux)
242 242 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
243 243 maybeStart = lnum-1 - context//2
244 244 start = max(maybeStart, 0)
245 245 end = start + context
246 246 lines = linecache.getlines(file)[start:end]
247 247 # pad with empty lines if necessary
248 248 if maybeStart < 0:
249 249 lines = (['\n'] * -maybeStart) + lines
250 250 if len(lines) < context:
251 251 lines += ['\n'] * (context - len(lines))
252 252 buf = list(records[i])
253 253 buf[LNUM_POS] = lnum
254 254 buf[INDEX_POS] = lnum - 1 - start
255 255 buf[LINES_POS] = lines
256 256 records[i] = tuple(buf)
257 257 return records[tb_offset:]
258 258
259 259 # Helper function -- largely belongs to VerboseTB, but we need the same
260 260 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
261 261 # can be recognized properly by ipython.el's py-traceback-line-re
262 262 # (SyntaxErrors have to be treated specially because they have no traceback)
263 263
264 264 _parser = PyColorize.Parser()
265 265
266 266 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
267 267 numbers_width = INDENT_SIZE - 1
268 268 res = []
269 269 i = lnum - index
270 270
271 271 # This lets us get fully syntax-highlighted tracebacks.
272 272 if scheme is None:
273 273 ipinst = ipapi.get()
274 274 if ipinst is not None:
275 275 scheme = ipinst.colors
276 276 else:
277 277 scheme = DEFAULT_SCHEME
278 278
279 279 _line_format = _parser.format2
280 280
281 281 for line in lines:
282 282 new_line, err = _line_format(line,'str',scheme)
283 283 if not err: line = new_line
284 284
285 285 if i == lnum:
286 286 # This is the line with the error
287 287 pad = numbers_width - len(str(i))
288 288 if pad >= 3:
289 289 marker = '-'*(pad-3) + '-> '
290 290 elif pad == 2:
291 291 marker = '> '
292 292 elif pad == 1:
293 293 marker = '>'
294 294 else:
295 295 marker = ''
296 296 num = marker + str(i)
297 297 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 298 Colors.line, line, Colors.Normal)
299 299 else:
300 300 num = '%*s' % (numbers_width,i)
301 301 line = '%s%s%s %s' %(Colors.lineno, num,
302 302 Colors.Normal, line)
303 303
304 304 res.append(line)
305 305 if lvals and i == lnum:
306 306 res.append(lvals + '\n')
307 307 i = i + 1
308 308 return res
309 309
310 310
311 311 #---------------------------------------------------------------------------
312 312 # Module classes
313 313 class TBTools:
314 314 """Basic tools used by all traceback printer classes."""
315 315
316 316 #: Default output stream, can be overridden at call time. A special value
317 317 #: of 'stdout' *as a string* can be given to force extraction of sys.stdout
318 318 #: at runtime. This allows testing exception printing with doctests, that
319 319 #: swap sys.stdout just at execution time.
320 320 #: Warning: be VERY careful to set this to one of the Term streams, NEVER
321 321 #: directly to sys.stdout/err, because under win32 the Term streams come from
322 322 #: pyreadline and know how to handle color correctly, whie stdout/err don't.
323 323 out_stream = Term.cerr
324 324
325 325 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
326 326 # Whether to call the interactive pdb debugger after printing
327 327 # tracebacks or not
328 328 self.call_pdb = call_pdb
329 329
330 330 # Create color table
331 331 self.color_scheme_table = exception_colors()
332 332
333 333 self.set_colors(color_scheme)
334 334 self.old_scheme = color_scheme # save initial value for toggles
335 335
336 336 if call_pdb:
337 337 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
338 338 else:
339 339 self.pdb = None
340 340
341 341 def set_colors(self,*args,**kw):
342 342 """Shorthand access to the color table scheme selector method."""
343 343
344 344 # Set own color table
345 345 self.color_scheme_table.set_active_scheme(*args,**kw)
346 346 # for convenience, set Colors to the active scheme
347 347 self.Colors = self.color_scheme_table.active_colors
348 348 # Also set colors of debugger
349 349 if hasattr(self,'pdb') and self.pdb is not None:
350 350 self.pdb.set_colors(*args,**kw)
351 351
352 352 def color_toggle(self):
353 353 """Toggle between the currently active color scheme and NoColor."""
354 354
355 355 if self.color_scheme_table.active_scheme_name == 'NoColor':
356 356 self.color_scheme_table.set_active_scheme(self.old_scheme)
357 357 self.Colors = self.color_scheme_table.active_colors
358 358 else:
359 359 self.old_scheme = self.color_scheme_table.active_scheme_name
360 360 self.color_scheme_table.set_active_scheme('NoColor')
361 361 self.Colors = self.color_scheme_table.active_colors
362 362
363 363 #---------------------------------------------------------------------------
364 364 class ListTB(TBTools):
365 365 """Print traceback information from a traceback list, with optional color.
366 366
367 367 Calling: requires 3 arguments:
368 368 (etype, evalue, elist)
369 369 as would be obtained by:
370 370 etype, evalue, tb = sys.exc_info()
371 371 if tb:
372 372 elist = traceback.extract_tb(tb)
373 373 else:
374 374 elist = None
375 375
376 376 It can thus be used by programs which need to process the traceback before
377 377 printing (such as console replacements based on the code module from the
378 378 standard library).
379 379
380 380 Because they are meant to be called without a full traceback (only a
381 381 list), instances of this class can't call the interactive pdb debugger."""
382 382
383 383 def __init__(self,color_scheme = 'NoColor'):
384 384 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
385 385
386 386 def __call__(self, etype, value, elist):
387 387 Term.cout.flush()
388 Term.cerr.writeln(self.text(etype,value,elist))
388 Term.cerr.write(self.text(etype,value,elist))
389 Term.cerr.write('\n')
389 390
390 391 def text(self, etype, value, elist, context=5):
391 392 """Return a color formatted string with the traceback info.
392 393
393 394 Parameters
394 395 ----------
395 396 etype : exception type
396 397 Type of the exception raised.
397 398
398 399 value : object
399 400 Data stored in the exception
400 401
401 402 elist : list
402 403 List of frames, see class docstring for details.
403 404
404 405 Returns
405 406 -------
406 407 String with formatted exception.
407 408 """
408 409
409 410 Colors = self.Colors
410 411 out_string = []
411 412 if elist:
412 413 out_string.append('Traceback %s(most recent call last)%s:' %
413 414 (Colors.normalEm, Colors.Normal) + '\n')
414 415 out_string.extend(self._format_list(elist))
415 416 lines = self._format_exception_only(etype, value)
416 417 for line in lines[:-1]:
417 418 out_string.append(" "+line)
418 419 out_string.append(lines[-1])
419 420 return ''.join(out_string)
420 421
421 422 def _format_list(self, extracted_list):
422 423 """Format a list of traceback entry tuples for printing.
423 424
424 425 Given a list of tuples as returned by extract_tb() or
425 426 extract_stack(), return a list of strings ready for printing.
426 427 Each string in the resulting list corresponds to the item with the
427 428 same index in the argument list. Each string ends in a newline;
428 429 the strings may contain internal newlines as well, for those items
429 430 whose source text line is not None.
430 431
431 432 Lifted almost verbatim from traceback.py
432 433 """
433 434
434 435 Colors = self.Colors
435 436 list = []
436 437 for filename, lineno, name, line in extracted_list[:-1]:
437 438 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
438 439 (Colors.filename, filename, Colors.Normal,
439 440 Colors.lineno, lineno, Colors.Normal,
440 441 Colors.name, name, Colors.Normal)
441 442 if line:
442 443 item = item + ' %s\n' % line.strip()
443 444 list.append(item)
444 445 # Emphasize the last entry
445 446 filename, lineno, name, line = extracted_list[-1]
446 447 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
447 448 (Colors.normalEm,
448 449 Colors.filenameEm, filename, Colors.normalEm,
449 450 Colors.linenoEm, lineno, Colors.normalEm,
450 451 Colors.nameEm, name, Colors.normalEm,
451 452 Colors.Normal)
452 453 if line:
453 454 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
454 455 Colors.Normal)
455 456 list.append(item)
456 457 return list
457 458
458 459 def _format_exception_only(self, etype, value):
459 460 """Format the exception part of a traceback.
460 461
461 462 The arguments are the exception type and value such as given by
462 463 sys.exc_info()[:2]. The return value is a list of strings, each ending
463 464 in a newline. Normally, the list contains a single string; however,
464 465 for SyntaxError exceptions, it contains several lines that (when
465 466 printed) display detailed information about where the syntax error
466 467 occurred. The message indicating which exception occurred is the
467 468 always last string in the list.
468 469
469 470 Also lifted nearly verbatim from traceback.py
470 471 """
471 472
472 473 have_filedata = False
473 474 Colors = self.Colors
474 475 list = []
475 476 try:
476 477 stype = Colors.excName + etype.__name__ + Colors.Normal
477 478 except AttributeError:
478 479 stype = etype # String exceptions don't get special coloring
479 480 if value is None:
480 481 list.append( str(stype) + '\n')
481 482 else:
482 483 if etype is SyntaxError:
483 484 try:
484 485 msg, (filename, lineno, offset, line) = value
485 486 except:
486 487 have_filedata = False
487 488 else:
488 489 have_filedata = True
489 490 #print 'filename is',filename # dbg
490 491 if not filename: filename = "<string>"
491 492 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
492 493 (Colors.normalEm,
493 494 Colors.filenameEm, filename, Colors.normalEm,
494 495 Colors.linenoEm, lineno, Colors.Normal ))
495 496 if line is not None:
496 497 i = 0
497 498 while i < len(line) and line[i].isspace():
498 499 i = i+1
499 500 list.append('%s %s%s\n' % (Colors.line,
500 501 line.strip(),
501 502 Colors.Normal))
502 503 if offset is not None:
503 504 s = ' '
504 505 for c in line[i:offset-1]:
505 506 if c.isspace():
506 507 s = s + c
507 508 else:
508 509 s = s + ' '
509 510 list.append('%s%s^%s\n' % (Colors.caret, s,
510 511 Colors.Normal) )
511 512 value = msg
512 513 s = self._some_str(value)
513 514 if s:
514 515 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
515 516 Colors.Normal, s))
516 517 else:
517 518 list.append('%s\n' % str(stype))
518 519
519 520 # sync with user hooks
520 521 if have_filedata:
521 522 ipinst = ipapi.get()
522 523 if ipinst is not None:
523 524 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
524 525
525 526 return list
526 527
527 528 def show_exception_only(self, etype, value):
528 529 """Only print the exception type and message, without a traceback.
529 530
530 531 Parameters
531 532 ----------
532 533 etype : exception type
533 534 value : exception value
534 535 """
535 536 # This method needs to use __call__ from *this* class, not the one from
536 537 # a subclass whose signature or behavior may be different
537 538 Term.cout.flush()
538 539 ostream = sys.stdout if self.out_stream == 'stdout' else Term.cerr
539 540 ostream.write(ListTB.text(self, etype, value, []))
540 541 ostream.flush()
541 542
542 543 def _some_str(self, value):
543 544 # Lifted from traceback.py
544 545 try:
545 546 return str(value)
546 547 except:
547 548 return '<unprintable %s object>' % type(value).__name__
548 549
549 550 #----------------------------------------------------------------------------
550 551 class VerboseTB(TBTools):
551 552 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
552 553 of HTML. Requires inspect and pydoc. Crazy, man.
553 554
554 555 Modified version which optionally strips the topmost entries from the
555 556 traceback, to be used with alternate interpreters (because their own code
556 557 would appear in the traceback)."""
557 558
558 559 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
559 560 call_pdb = 0, include_vars=1):
560 561 """Specify traceback offset, headers and color scheme.
561 562
562 563 Define how many frames to drop from the tracebacks. Calling it with
563 564 tb_offset=1 allows use of this handler in interpreters which will have
564 565 their own code at the top of the traceback (VerboseTB will first
565 566 remove that frame before printing the traceback info)."""
566 567 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
567 568 self.tb_offset = tb_offset
568 569 self.long_header = long_header
569 570 self.include_vars = include_vars
570 571
571 572 def text(self, etype, evalue, etb, context=5):
572 573 """Return a nice text document describing the traceback."""
573 574
574 575 # some locals
575 576 try:
576 577 etype = etype.__name__
577 578 except AttributeError:
578 579 pass
579 580 Colors = self.Colors # just a shorthand + quicker name lookup
580 581 ColorsNormal = Colors.Normal # used a lot
581 582 col_scheme = self.color_scheme_table.active_scheme_name
582 583 indent = ' '*INDENT_SIZE
583 584 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
584 585 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
585 586 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
586 587
587 588 # some internal-use functions
588 589 def text_repr(value):
589 590 """Hopefully pretty robust repr equivalent."""
590 591 # this is pretty horrible but should always return *something*
591 592 try:
592 593 return pydoc.text.repr(value)
593 594 except KeyboardInterrupt:
594 595 raise
595 596 except:
596 597 try:
597 598 return repr(value)
598 599 except KeyboardInterrupt:
599 600 raise
600 601 except:
601 602 try:
602 603 # all still in an except block so we catch
603 604 # getattr raising
604 605 name = getattr(value, '__name__', None)
605 606 if name:
606 607 # ick, recursion
607 608 return text_repr(name)
608 609 klass = getattr(value, '__class__', None)
609 610 if klass:
610 611 return '%s instance' % text_repr(klass)
611 612 except KeyboardInterrupt:
612 613 raise
613 614 except:
614 615 return 'UNRECOVERABLE REPR FAILURE'
615 616 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
616 617 def nullrepr(value, repr=text_repr): return ''
617 618
618 619 # meat of the code begins
619 620 try:
620 621 etype = etype.__name__
621 622 except AttributeError:
622 623 pass
623 624
624 625 if self.long_header:
625 626 # Header with the exception type, python version, and date
626 627 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
627 628 date = time.ctime(time.time())
628 629
629 630 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
630 631 exc, ' '*(75-len(str(etype))-len(pyver)),
631 632 pyver, string.rjust(date, 75) )
632 633 head += "\nA problem occured executing Python code. Here is the sequence of function"\
633 634 "\ncalls leading up to the error, with the most recent (innermost) call last."
634 635 else:
635 636 # Simplified header
636 637 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
637 638 string.rjust('Traceback (most recent call last)',
638 639 75 - len(str(etype)) ) )
639 640 frames = []
640 641 # Flush cache before calling inspect. This helps alleviate some of the
641 642 # problems with python 2.3's inspect.py.
642 643 linecache.checkcache()
643 644 # Drop topmost frames if requested
644 645 try:
645 646 # Try the default getinnerframes and Alex's: Alex's fixes some
646 647 # problems, but it generates empty tracebacks for console errors
647 648 # (5 blanks lines) where none should be returned.
648 649 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
649 650 #print 'python records:', records # dbg
650 651 records = _fixed_getinnerframes(etb, context,self.tb_offset)
651 652 #print 'alex records:', records # dbg
652 653 except:
653 654
654 655 # FIXME: I've been getting many crash reports from python 2.3
655 656 # users, traceable to inspect.py. If I can find a small test-case
656 657 # to reproduce this, I should either write a better workaround or
657 658 # file a bug report against inspect (if that's the real problem).
658 659 # So far, I haven't been able to find an isolated example to
659 660 # reproduce the problem.
660 661 inspect_error()
661 662 traceback.print_exc(file=Term.cerr)
662 663 info('\nUnfortunately, your original traceback can not be constructed.\n')
663 664 return ''
664 665
665 666 # build some color string templates outside these nested loops
666 667 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
667 668 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
668 669 ColorsNormal)
669 670 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
670 671 (Colors.vName, Colors.valEm, ColorsNormal)
671 672 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
672 673 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
673 674 Colors.vName, ColorsNormal)
674 675 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
675 676 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
676 677 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
677 678 ColorsNormal)
678 679
679 680 # now, loop over all records printing context and info
680 681 abspath = os.path.abspath
681 682 for frame, file, lnum, func, lines, index in records:
682 683 #print '*** record:',file,lnum,func,lines,index # dbg
683 684 try:
684 685 file = file and abspath(file) or '?'
685 686 except OSError:
686 687 # if file is '<console>' or something not in the filesystem,
687 688 # the abspath call will throw an OSError. Just ignore it and
688 689 # keep the original file string.
689 690 pass
690 691 link = tpl_link % file
691 692 try:
692 693 args, varargs, varkw, locals = inspect.getargvalues(frame)
693 694 except:
694 695 # This can happen due to a bug in python2.3. We should be
695 696 # able to remove this try/except when 2.4 becomes a
696 697 # requirement. Bug details at http://python.org/sf/1005466
697 698 inspect_error()
698 699 traceback.print_exc(file=Term.cerr)
699 700 info("\nIPython's exception reporting continues...\n")
700 701
701 702 if func == '?':
702 703 call = ''
703 704 else:
704 705 # Decide whether to include variable details or not
705 706 var_repr = self.include_vars and eqrepr or nullrepr
706 707 try:
707 708 call = tpl_call % (func,inspect.formatargvalues(args,
708 709 varargs, varkw,
709 710 locals,formatvalue=var_repr))
710 711 except KeyError:
711 712 # Very odd crash from inspect.formatargvalues(). The
712 713 # scenario under which it appeared was a call to
713 714 # view(array,scale) in NumTut.view.view(), where scale had
714 715 # been defined as a scalar (it should be a tuple). Somehow
715 716 # inspect messes up resolving the argument list of view()
716 717 # and barfs out. At some point I should dig into this one
717 718 # and file a bug report about it.
718 719 inspect_error()
719 720 traceback.print_exc(file=Term.cerr)
720 721 info("\nIPython's exception reporting continues...\n")
721 722 call = tpl_call_fail % func
722 723
723 724 # Initialize a list of names on the current line, which the
724 725 # tokenizer below will populate.
725 726 names = []
726 727
727 728 def tokeneater(token_type, token, start, end, line):
728 729 """Stateful tokeneater which builds dotted names.
729 730
730 731 The list of names it appends to (from the enclosing scope) can
731 732 contain repeated composite names. This is unavoidable, since
732 733 there is no way to disambguate partial dotted structures until
733 734 the full list is known. The caller is responsible for pruning
734 735 the final list of duplicates before using it."""
735 736
736 737 # build composite names
737 738 if token == '.':
738 739 try:
739 740 names[-1] += '.'
740 741 # store state so the next token is added for x.y.z names
741 742 tokeneater.name_cont = True
742 743 return
743 744 except IndexError:
744 745 pass
745 746 if token_type == tokenize.NAME and token not in keyword.kwlist:
746 747 if tokeneater.name_cont:
747 748 # Dotted names
748 749 names[-1] += token
749 750 tokeneater.name_cont = False
750 751 else:
751 752 # Regular new names. We append everything, the caller
752 753 # will be responsible for pruning the list later. It's
753 754 # very tricky to try to prune as we go, b/c composite
754 755 # names can fool us. The pruning at the end is easy
755 756 # to do (or the caller can print a list with repeated
756 757 # names if so desired.
757 758 names.append(token)
758 759 elif token_type == tokenize.NEWLINE:
759 760 raise IndexError
760 761 # we need to store a bit of state in the tokenizer to build
761 762 # dotted names
762 763 tokeneater.name_cont = False
763 764
764 765 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
765 766 line = getline(file, lnum[0])
766 767 lnum[0] += 1
767 768 return line
768 769
769 770 # Build the list of names on this line of code where the exception
770 771 # occurred.
771 772 try:
772 773 # This builds the names list in-place by capturing it from the
773 774 # enclosing scope.
774 775 tokenize.tokenize(linereader, tokeneater)
775 776 except IndexError:
776 777 # signals exit of tokenizer
777 778 pass
778 779 except tokenize.TokenError,msg:
779 780 _m = ("An unexpected error occurred while tokenizing input\n"
780 781 "The following traceback may be corrupted or invalid\n"
781 782 "The error message is: %s\n" % msg)
782 783 error(_m)
783 784
784 785 # prune names list of duplicates, but keep the right order
785 786 unique_names = uniq_stable(names)
786 787
787 788 # Start loop over vars
788 789 lvals = []
789 790 if self.include_vars:
790 791 for name_full in unique_names:
791 792 name_base = name_full.split('.',1)[0]
792 793 if name_base in frame.f_code.co_varnames:
793 794 if locals.has_key(name_base):
794 795 try:
795 796 value = repr(eval(name_full,locals))
796 797 except:
797 798 value = undefined
798 799 else:
799 800 value = undefined
800 801 name = tpl_local_var % name_full
801 802 else:
802 803 if frame.f_globals.has_key(name_base):
803 804 try:
804 805 value = repr(eval(name_full,frame.f_globals))
805 806 except:
806 807 value = undefined
807 808 else:
808 809 value = undefined
809 810 name = tpl_global_var % name_full
810 811 lvals.append(tpl_name_val % (name,value))
811 812 if lvals:
812 813 lvals = '%s%s' % (indent,em_normal.join(lvals))
813 814 else:
814 815 lvals = ''
815 816
816 817 level = '%s %s\n' % (link,call)
817 818
818 819 if index is None:
819 820 frames.append(level)
820 821 else:
821 822 frames.append('%s%s' % (level,''.join(
822 823 _format_traceback_lines(lnum,index,lines,Colors,lvals,
823 824 col_scheme))))
824 825
825 826 # Get (safely) a string form of the exception info
826 827 try:
827 828 etype_str,evalue_str = map(str,(etype,evalue))
828 829 except:
829 830 # User exception is improperly defined.
830 831 etype,evalue = str,sys.exc_info()[:2]
831 832 etype_str,evalue_str = map(str,(etype,evalue))
832 833 # ... and format it
833 834 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
834 835 ColorsNormal, evalue_str)]
835 836 if type(evalue) is types.InstanceType:
836 837 try:
837 838 names = [w for w in dir(evalue) if isinstance(w, basestring)]
838 839 except:
839 840 # Every now and then, an object with funny inernals blows up
840 841 # when dir() is called on it. We do the best we can to report
841 842 # the problem and continue
842 843 _m = '%sException reporting error (object with broken dir())%s:'
843 844 exception.append(_m % (Colors.excName,ColorsNormal))
844 845 etype_str,evalue_str = map(str,sys.exc_info()[:2])
845 846 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
846 847 ColorsNormal, evalue_str))
847 848 names = []
848 849 for name in names:
849 850 value = text_repr(getattr(evalue, name))
850 851 exception.append('\n%s%s = %s' % (indent, name, value))
851 852
852 853 # vds: >>
853 854 if records:
854 855 filepath, lnum = records[-1][1:3]
855 856 #print "file:", str(file), "linenb", str(lnum) # dbg
856 857 filepath = os.path.abspath(filepath)
857 858 ipinst = ipapi.get()
858 859 if ipinst is not None:
859 860 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
860 861 # vds: <<
861 862
862 863 # return all our info assembled as a single string
863 864 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
864 865
865 866 def debugger(self,force=False):
866 867 """Call up the pdb debugger if desired, always clean up the tb
867 868 reference.
868 869
869 870 Keywords:
870 871
871 872 - force(False): by default, this routine checks the instance call_pdb
872 873 flag and does not actually invoke the debugger if the flag is false.
873 874 The 'force' option forces the debugger to activate even if the flag
874 875 is false.
875 876
876 877 If the call_pdb flag is set, the pdb interactive debugger is
877 878 invoked. In all cases, the self.tb reference to the current traceback
878 879 is deleted to prevent lingering references which hamper memory
879 880 management.
880 881
881 882 Note that each call to pdb() does an 'import readline', so if your app
882 883 requires a special setup for the readline completers, you'll have to
883 884 fix that by hand after invoking the exception handler."""
884 885
885 886 if force or self.call_pdb:
886 887 if self.pdb is None:
887 888 self.pdb = debugger.Pdb(
888 889 self.color_scheme_table.active_scheme_name)
889 890 # the system displayhook may have changed, restore the original
890 891 # for pdb
891 892 display_trap = DisplayTrap(None, sys.__displayhook__)
892 893 with display_trap:
893 894 self.pdb.reset()
894 895 # Find the right frame so we don't pop up inside ipython itself
895 896 if hasattr(self,'tb') and self.tb is not None:
896 897 etb = self.tb
897 898 else:
898 899 etb = self.tb = sys.last_traceback
899 900 while self.tb is not None and self.tb.tb_next is not None:
900 901 self.tb = self.tb.tb_next
901 902 if etb and etb.tb_next:
902 903 etb = etb.tb_next
903 904 self.pdb.botframe = etb.tb_frame
904 905 self.pdb.interaction(self.tb.tb_frame, self.tb)
905 906
906 907 if hasattr(self,'tb'):
907 908 del self.tb
908 909
909 910 def handler(self, info=None):
910 911 (etype, evalue, etb) = info or sys.exc_info()
911 912 self.tb = etb
912 913 Term.cout.flush()
913 Term.cerr.writeln(self.text(etype, evalue, etb))
914 Term.cerr.write(self.text(etype, evalue, etb))
915 Term.cerr.write('\n')
914 916
915 917 # Changed so an instance can just be called as VerboseTB_inst() and print
916 918 # out the right info on its own.
917 919 def __call__(self, etype=None, evalue=None, etb=None):
918 920 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
919 921 if etb is None:
920 922 self.handler()
921 923 else:
922 924 self.handler((etype, evalue, etb))
923 925 try:
924 926 self.debugger()
925 927 except KeyboardInterrupt:
926 928 print "\nKeyboardInterrupt"
927 929
928 930 #----------------------------------------------------------------------------
929 931 class FormattedTB(VerboseTB,ListTB):
930 932 """Subclass ListTB but allow calling with a traceback.
931 933
932 934 It can thus be used as a sys.excepthook for Python > 2.1.
933 935
934 936 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
935 937
936 938 Allows a tb_offset to be specified. This is useful for situations where
937 939 one needs to remove a number of topmost frames from the traceback (such as
938 940 occurs with python programs that themselves execute other python code,
939 941 like Python shells). """
940 942
941 943 def __init__(self, mode = 'Plain', color_scheme='Linux',
942 944 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
943 945
944 946 # NEVER change the order of this list. Put new modes at the end:
945 947 self.valid_modes = ['Plain','Context','Verbose']
946 948 self.verbose_modes = self.valid_modes[1:3]
947 949
948 950 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
949 951 call_pdb=call_pdb,include_vars=include_vars)
950 952 self.set_mode(mode)
951 953
952 954 def _extract_tb(self,tb):
953 955 if tb:
954 956 return traceback.extract_tb(tb)
955 957 else:
956 958 return None
957 959
958 960 def text(self, etype, value, tb,context=5,mode=None):
959 961 """Return formatted traceback.
960 962
961 963 If the optional mode parameter is given, it overrides the current
962 964 mode."""
963 965
964 966 if mode is None:
965 967 mode = self.mode
966 968 if mode in self.verbose_modes:
967 969 # verbose modes need a full traceback
968 970 return VerboseTB.text(self,etype, value, tb,context=5)
969 971 else:
970 972 # We must check the source cache because otherwise we can print
971 973 # out-of-date source code.
972 974 linecache.checkcache()
973 975 # Now we can extract and format the exception
974 976 elist = self._extract_tb(tb)
975 977 if len(elist) > self.tb_offset:
976 978 del elist[:self.tb_offset]
977 979 return ListTB.text(self,etype,value,elist)
978 980
979 981 def set_mode(self,mode=None):
980 982 """Switch to the desired mode.
981 983
982 984 If mode is not specified, cycles through the available modes."""
983 985
984 986 if not mode:
985 987 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
986 988 len(self.valid_modes)
987 989 self.mode = self.valid_modes[new_idx]
988 990 elif mode not in self.valid_modes:
989 991 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
990 992 'Valid modes: '+str(self.valid_modes)
991 993 else:
992 994 self.mode = mode
993 995 # include variable details only in 'Verbose' mode
994 996 self.include_vars = (self.mode == self.valid_modes[2])
995 997
996 998 # some convenient shorcuts
997 999 def plain(self):
998 1000 self.set_mode(self.valid_modes[0])
999 1001
1000 1002 def context(self):
1001 1003 self.set_mode(self.valid_modes[1])
1002 1004
1003 1005 def verbose(self):
1004 1006 self.set_mode(self.valid_modes[2])
1005 1007
1006 1008 #----------------------------------------------------------------------------
1007 1009 class AutoFormattedTB(FormattedTB):
1008 1010 """A traceback printer which can be called on the fly.
1009 1011
1010 1012 It will find out about exceptions by itself.
1011 1013
1012 1014 A brief example:
1013 1015
1014 1016 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1015 1017 try:
1016 1018 ...
1017 1019 except:
1018 1020 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1019 1021 """
1020 1022
1021 1023 def __call__(self,etype=None,evalue=None,etb=None,
1022 1024 out=None,tb_offset=None):
1023 1025 """Print out a formatted exception traceback.
1024 1026
1025 1027 Optional arguments:
1026 1028 - out: an open file-like object to direct output to.
1027 1029
1028 1030 - tb_offset: the number of frames to skip over in the stack, on a
1029 1031 per-call basis (this overrides temporarily the instance's tb_offset
1030 1032 given at initialization time. """
1031 1033
1032 1034 if out is None:
1033 1035 out = sys.stdout if self.out_stream=='stdout' else self.out_stream
1034 1036 Term.cout.flush()
1035 1037 if tb_offset is not None:
1036 1038 tb_offset, self.tb_offset = self.tb_offset, tb_offset
1037 1039 out.write(self.text(etype, evalue, etb))
1038 1040 out.write('\n')
1039 1041 self.tb_offset = tb_offset
1040 1042 else:
1041 1043 out.write(self.text(etype, evalue, etb))
1042 1044 out.write('\n')
1043 1045 out.flush()
1044 1046 try:
1045 1047 self.debugger()
1046 1048 except KeyboardInterrupt:
1047 1049 print "\nKeyboardInterrupt"
1048 1050
1049 1051 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1050 1052 if etype is None:
1051 1053 etype,value,tb = sys.exc_info()
1052 1054 self.tb = tb
1053 1055 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1054 1056
1055 1057 #---------------------------------------------------------------------------
1056 1058 # A simple class to preserve Nathan's original functionality.
1057 1059 class ColorTB(FormattedTB):
1058 1060 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1059 1061 def __init__(self,color_scheme='Linux',call_pdb=0):
1060 1062 FormattedTB.__init__(self,color_scheme=color_scheme,
1061 1063 call_pdb=call_pdb)
1062 1064
1063 1065 #----------------------------------------------------------------------------
1064 1066 # module testing (minimal)
1065 1067 if __name__ == "__main__":
1066 1068 def spam(c, (d, e)):
1067 1069 x = c + d
1068 1070 y = c * d
1069 1071 foo(x, y)
1070 1072
1071 1073 def foo(a, b, bar=1):
1072 1074 eggs(a, b + bar)
1073 1075
1074 1076 def eggs(f, g, z=globals()):
1075 1077 h = f + g
1076 1078 i = f - g
1077 1079 return h / i
1078 1080
1079 1081 print ''
1080 1082 print '*** Before ***'
1081 1083 try:
1082 1084 print spam(1, (2, 3))
1083 1085 except:
1084 1086 traceback.print_exc()
1085 1087 print ''
1086 1088
1087 1089 handler = ColorTB()
1088 1090 print '*** ColorTB ***'
1089 1091 try:
1090 1092 print spam(1, (2, 3))
1091 1093 except:
1092 1094 apply(handler, sys.exc_info() )
1093 1095 print ''
1094 1096
1095 1097 handler = VerboseTB()
1096 1098 print '*** VerboseTB ***'
1097 1099 try:
1098 1100 print spam(1, (2, 3))
1099 1101 except:
1100 1102 apply(handler, sys.exc_info() )
1101 1103 print ''
1102 1104
@@ -1,292 +1,292
1 1 # encoding: utf-8
2 2 """
3 3 IO related utilities.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2009 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18 import tempfile
19 19
20 20 from IPython.external.Itpl import itpl, printpl
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Code
24 24 #-----------------------------------------------------------------------------
25 25
26 26
27 27 class IOStream:
28 28
29 29 def __init__(self,stream,fallback):
30 30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 31 stream = fallback
32 32 self.stream = stream
33 33 self._swrite = stream.write
34 34 self.flush = stream.flush
35 35
36 36 def write(self,data):
37 37 try:
38 38 self._swrite(data)
39 39 except:
40 40 try:
41 41 # print handles some unicode issues which may trip a plain
42 42 # write() call. Attempt to emulate write() by using a
43 43 # trailing comma
44 44 print >> self.stream, data,
45 45 except:
46 46 # if we get here, something is seriously broken.
47 47 print >> sys.stderr, \
48 48 'ERROR - failed to write data to stream:', self.stream
49 49
50 def writeln(self, data):
51 self.write(data)
52 self.write('\n')
50 # This class used to have a writeln method, but regular files and streams
51 # in Python don't have this method. We need to keep this completely
52 # compatible so we removed it.
53 53
54 54 def close(self):
55 55 pass
56 56
57 57
58 58 class IOTerm:
59 59 """ Term holds the file or file-like objects for handling I/O operations.
60 60
61 61 These are normally just sys.stdin, sys.stdout and sys.stderr but for
62 62 Windows they can can replaced to allow editing the strings before they are
63 63 displayed."""
64 64
65 65 # In the future, having IPython channel all its I/O operations through
66 66 # this class will make it easier to embed it into other environments which
67 67 # are not a normal terminal (such as a GUI-based shell)
68 68 def __init__(self,cin=None,cout=None,cerr=None):
69 69 self.cin = IOStream(cin,sys.stdin)
70 70 self.cout = IOStream(cout,sys.stdout)
71 71 self.cerr = IOStream(cerr,sys.stderr)
72 72
73 73
74 74 # Global variable to be used for all I/O
75 75 Term = IOTerm()
76 76
77 77
78 78 import IPython.utils.rlineimpl as readline
79 79 # Remake Term to use the readline i/o facilities
80 80 if sys.platform == 'win32' and readline.have_readline:
81 81
82 82 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
83 83
84 84
85 85 class Tee(object):
86 86 """A class to duplicate an output stream to stdout/err.
87 87
88 88 This works in a manner very similar to the Unix 'tee' command.
89 89
90 90 When the object is closed or deleted, it closes the original file given to
91 91 it for duplication.
92 92 """
93 93 # Inspired by:
94 94 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
95 95
96 96 def __init__(self, file_or_name, mode=None, channel='stdout'):
97 97 """Construct a new Tee object.
98 98
99 99 Parameters
100 100 ----------
101 101 file_or_name : filename or open filehandle (writable)
102 102 File that will be duplicated
103 103
104 104 mode : optional, valid mode for open().
105 105 If a filename was give, open with this mode.
106 106
107 107 channel : str, one of ['stdout', 'stderr']
108 108 """
109 109 if channel not in ['stdout', 'stderr']:
110 110 raise ValueError('Invalid channel spec %s' % channel)
111 111
112 112 if hasattr(file, 'write') and hasattr(file, 'seek'):
113 113 self.file = file_or_name
114 114 else:
115 115 self.file = open(file_or_name, mode)
116 116 self.channel = channel
117 117 self.ostream = getattr(sys, channel)
118 118 setattr(sys, channel, self)
119 119 self._closed = False
120 120
121 121 def close(self):
122 122 """Close the file and restore the channel."""
123 123 self.flush()
124 124 setattr(sys, self.channel, self.ostream)
125 125 self.file.close()
126 126 self._closed = True
127 127
128 128 def write(self, data):
129 129 """Write data to both channels."""
130 130 self.file.write(data)
131 131 self.ostream.write(data)
132 132 self.ostream.flush()
133 133
134 134 def flush(self):
135 135 """Flush both channels."""
136 136 self.file.flush()
137 137 self.ostream.flush()
138 138
139 139 def __del__(self):
140 140 if not self._closed:
141 141 self.close()
142 142
143 143
144 144 def file_read(filename):
145 145 """Read a file and close it. Returns the file source."""
146 146 fobj = open(filename,'r');
147 147 source = fobj.read();
148 148 fobj.close()
149 149 return source
150 150
151 151
152 152 def file_readlines(filename):
153 153 """Read a file and close it. Returns the file source using readlines()."""
154 154 fobj = open(filename,'r');
155 155 lines = fobj.readlines();
156 156 fobj.close()
157 157 return lines
158 158
159 159
160 160 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
161 161 """Take multiple lines of input.
162 162
163 163 A list with each line of input as a separate element is returned when a
164 164 termination string is entered (defaults to a single '.'). Input can also
165 165 terminate via EOF (^D in Unix, ^Z-RET in Windows).
166 166
167 167 Lines of input which end in \\ are joined into single entries (and a
168 168 secondary continuation prompt is issued as long as the user terminates
169 169 lines with \\). This allows entering very long strings which are still
170 170 meant to be treated as single entities.
171 171 """
172 172
173 173 try:
174 174 if header:
175 175 header += '\n'
176 176 lines = [raw_input(header + ps1)]
177 177 except EOFError:
178 178 return []
179 179 terminate = [terminate_str]
180 180 try:
181 181 while lines[-1:] != terminate:
182 182 new_line = raw_input(ps1)
183 183 while new_line.endswith('\\'):
184 184 new_line = new_line[:-1] + raw_input(ps2)
185 185 lines.append(new_line)
186 186
187 187 return lines[:-1] # don't return the termination command
188 188 except EOFError:
189 189 print
190 190 return lines
191 191
192 192
193 193 def raw_input_ext(prompt='', ps2='... '):
194 194 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
195 195
196 196 line = raw_input(prompt)
197 197 while line.endswith('\\'):
198 198 line = line[:-1] + raw_input(ps2)
199 199 return line
200 200
201 201
202 202 def ask_yes_no(prompt,default=None):
203 203 """Asks a question and returns a boolean (y/n) answer.
204 204
205 205 If default is given (one of 'y','n'), it is used if the user input is
206 206 empty. Otherwise the question is repeated until an answer is given.
207 207
208 208 An EOF is treated as the default answer. If there is no default, an
209 209 exception is raised to prevent infinite loops.
210 210
211 211 Valid answers are: y/yes/n/no (match is not case sensitive)."""
212 212
213 213 answers = {'y':True,'n':False,'yes':True,'no':False}
214 214 ans = None
215 215 while ans not in answers.keys():
216 216 try:
217 217 ans = raw_input(prompt+' ').lower()
218 218 if not ans: # response was an empty string
219 219 ans = default
220 220 except KeyboardInterrupt:
221 221 pass
222 222 except EOFError:
223 223 if default in answers.keys():
224 224 ans = default
225 225 print
226 226 else:
227 227 raise
228 228
229 229 return answers[ans]
230 230
231 231
232 232 class NLprinter:
233 233 """Print an arbitrarily nested list, indicating index numbers.
234 234
235 235 An instance of this class called nlprint is available and callable as a
236 236 function.
237 237
238 238 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
239 239 and using 'sep' to separate the index from the value. """
240 240
241 241 def __init__(self):
242 242 self.depth = 0
243 243
244 244 def __call__(self,lst,pos='',**kw):
245 245 """Prints the nested list numbering levels."""
246 246 kw.setdefault('indent',' ')
247 247 kw.setdefault('sep',': ')
248 248 kw.setdefault('start',0)
249 249 kw.setdefault('stop',len(lst))
250 250 # we need to remove start and stop from kw so they don't propagate
251 251 # into a recursive call for a nested list.
252 252 start = kw['start']; del kw['start']
253 253 stop = kw['stop']; del kw['stop']
254 254 if self.depth == 0 and 'header' in kw.keys():
255 255 print kw['header']
256 256
257 257 for idx in range(start,stop):
258 258 elem = lst[idx]
259 259 if type(elem)==type([]):
260 260 self.depth += 1
261 261 self.__call__(elem,itpl('$pos$idx,'),**kw)
262 262 self.depth -= 1
263 263 else:
264 264 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
265 265
266 266 nlprint = NLprinter()
267 267
268 268
269 269 def temp_pyfile(src, ext='.py'):
270 270 """Make a temporary python file, return filename and filehandle.
271 271
272 272 Parameters
273 273 ----------
274 274 src : string or list of strings (no need for ending newlines if list)
275 275 Source code to be written to the file.
276 276
277 277 ext : optional, string
278 278 Extension for the generated file.
279 279
280 280 Returns
281 281 -------
282 282 (filename, open filehandle)
283 283 It is the caller's responsibility to close the open file and unlink it.
284 284 """
285 285 fname = tempfile.mkstemp(ext)[1]
286 286 f = open(fname,'w')
287 287 f.write(src)
288 288 f.flush()
289 289 return fname, f
290 290
291 291
292 292
General Comments 0
You need to be logged in to leave comments. Login now