##// END OF EJS Templates
Remove import indirection and deprecated private function....
Matthias Bussonnier -
Show More
@@ -1,1461 +1,1462 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 44 potentially leak sensitive information like access keys, or unencryted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 - Neutral: a neutral color scheme that should be readable on both light and
71 71 dark background
72 72
73 73 You can implement other color schemes easily, the syntax is fairly
74 74 self-explanatory. Please send back new schemes you develop to the author for
75 75 possible inclusion in future releases.
76 76
77 77 Inheritance diagram:
78 78
79 79 .. inheritance-diagram:: IPython.core.ultratb
80 80 :parts: 3
81 81 """
82 82
83 83 #*****************************************************************************
84 84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 86 #
87 87 # Distributed under the terms of the BSD License. The full license is in
88 88 # the file COPYING, distributed as part of this software.
89 89 #*****************************************************************************
90 90
91 91
92 92 import dis
93 93 import inspect
94 94 import keyword
95 95 import linecache
96 96 import os
97 97 import pydoc
98 98 import re
99 99 import sys
100 100 import time
101 101 import tokenize
102 102 import traceback
103 103
104 104 try: # Python 2
105 105 generate_tokens = tokenize.generate_tokens
106 106 except AttributeError: # Python 3
107 107 generate_tokens = tokenize.tokenize
108 108
109 109 # For purposes of monkeypatching inspect to fix a bug in it.
110 110 from inspect import getsourcefile, getfile, getmodule, \
111 111 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
112 112
113 113 # IPython's own modules
114 114 from IPython import get_ipython
115 115 from IPython.core import debugger
116 116 from IPython.core.display_trap import DisplayTrap
117 117 from IPython.core.excolors import exception_colors
118 118 from IPython.utils import PyColorize
119 from IPython.utils import openpy
120 119 from IPython.utils import path as util_path
121 120 from IPython.utils import py3compat
122 121 from IPython.utils.data import uniq_stable
123 122 from IPython.utils.terminal import get_terminal_size
124 123 from logging import info, error, debug
125 124
125 from importlib.util import source_from_cache
126
126 127 import IPython.utils.colorable as colorable
127 128
128 129 # Globals
129 130 # amount of space to put line numbers before verbose tracebacks
130 131 INDENT_SIZE = 8
131 132
132 133 # Default color scheme. This is used, for example, by the traceback
133 134 # formatter. When running in an actual IPython instance, the user's rc.colors
134 135 # value is used, but having a module global makes this functionality available
135 136 # to users of ultratb who are NOT running inside ipython.
136 137 DEFAULT_SCHEME = 'NoColor'
137 138
138 139 # ---------------------------------------------------------------------------
139 140 # Code begins
140 141
141 142 # Utility functions
142 143 def inspect_error():
143 144 """Print a message about internal inspect errors.
144 145
145 146 These are unfortunately quite common."""
146 147
147 148 error('Internal Python error in the inspect module.\n'
148 149 'Below is the traceback from this internal error.\n')
149 150
150 151
151 152 # This function is a monkeypatch we apply to the Python inspect module. We have
152 153 # now found when it's needed (see discussion on issue gh-1456), and we have a
153 154 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
154 155 # the monkeypatch is not applied. TK, Aug 2012.
155 156 def findsource(object):
156 157 """Return the entire source file and starting line number for an object.
157 158
158 159 The argument may be a module, class, method, function, traceback, frame,
159 160 or code object. The source code is returned as a list of all the lines
160 161 in the file and the line number indexes a line in that list. An IOError
161 162 is raised if the source code cannot be retrieved.
162 163
163 164 FIXED version with which we monkeypatch the stdlib to work around a bug."""
164 165
165 166 file = getsourcefile(object) or getfile(object)
166 167 # If the object is a frame, then trying to get the globals dict from its
167 168 # module won't work. Instead, the frame object itself has the globals
168 169 # dictionary.
169 170 globals_dict = None
170 171 if inspect.isframe(object):
171 172 # XXX: can this ever be false?
172 173 globals_dict = object.f_globals
173 174 else:
174 175 module = getmodule(object, file)
175 176 if module:
176 177 globals_dict = module.__dict__
177 178 lines = linecache.getlines(file, globals_dict)
178 179 if not lines:
179 180 raise IOError('could not get source code')
180 181
181 182 if ismodule(object):
182 183 return lines, 0
183 184
184 185 if isclass(object):
185 186 name = object.__name__
186 187 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
187 188 # make some effort to find the best matching class definition:
188 189 # use the one with the least indentation, which is the one
189 190 # that's most probably not inside a function definition.
190 191 candidates = []
191 192 for i, line in enumerate(lines):
192 193 match = pat.match(line)
193 194 if match:
194 195 # if it's at toplevel, it's already the best one
195 196 if line[0] == 'c':
196 197 return lines, i
197 198 # else add whitespace to candidate list
198 199 candidates.append((match.group(1), i))
199 200 if candidates:
200 201 # this will sort by whitespace, and by line number,
201 202 # less whitespace first
202 203 candidates.sort()
203 204 return lines, candidates[0][1]
204 205 else:
205 206 raise IOError('could not find class definition')
206 207
207 208 if ismethod(object):
208 209 object = object.__func__
209 210 if isfunction(object):
210 211 object = object.__code__
211 212 if istraceback(object):
212 213 object = object.tb_frame
213 214 if isframe(object):
214 215 object = object.f_code
215 216 if iscode(object):
216 217 if not hasattr(object, 'co_firstlineno'):
217 218 raise IOError('could not find function definition')
218 219 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
219 220 pmatch = pat.match
220 221 # fperez - fix: sometimes, co_firstlineno can give a number larger than
221 222 # the length of lines, which causes an error. Safeguard against that.
222 223 lnum = min(object.co_firstlineno, len(lines)) - 1
223 224 while lnum > 0:
224 225 if pmatch(lines[lnum]):
225 226 break
226 227 lnum -= 1
227 228
228 229 return lines, lnum
229 230 raise IOError('could not find code object')
230 231
231 232
232 233 # This is a patched version of inspect.getargs that applies the (unmerged)
233 234 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
234 235 # https://github.com/ipython/ipython/issues/8205 and
235 236 # https://github.com/ipython/ipython/issues/8293
236 237 def getargs(co):
237 238 """Get information about the arguments accepted by a code object.
238 239
239 240 Three things are returned: (args, varargs, varkw), where 'args' is
240 241 a list of argument names (possibly containing nested lists), and
241 242 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
242 243 if not iscode(co):
243 244 raise TypeError('{!r} is not a code object'.format(co))
244 245
245 246 nargs = co.co_argcount
246 247 names = co.co_varnames
247 248 args = list(names[:nargs])
248 249 step = 0
249 250
250 251 # The following acrobatics are for anonymous (tuple) arguments.
251 252 for i in range(nargs):
252 253 if args[i][:1] in ('', '.'):
253 254 stack, remain, count = [], [], []
254 255 while step < len(co.co_code):
255 256 op = ord(co.co_code[step])
256 257 step = step + 1
257 258 if op >= dis.HAVE_ARGUMENT:
258 259 opname = dis.opname[op]
259 260 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
260 261 step = step + 2
261 262 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
262 263 remain.append(value)
263 264 count.append(value)
264 265 elif opname in ('STORE_FAST', 'STORE_DEREF'):
265 266 if op in dis.haslocal:
266 267 stack.append(co.co_varnames[value])
267 268 elif op in dis.hasfree:
268 269 stack.append((co.co_cellvars + co.co_freevars)[value])
269 270 # Special case for sublists of length 1: def foo((bar))
270 271 # doesn't generate the UNPACK_TUPLE bytecode, so if
271 272 # `remain` is empty here, we have such a sublist.
272 273 if not remain:
273 274 stack[0] = [stack[0]]
274 275 break
275 276 else:
276 277 remain[-1] = remain[-1] - 1
277 278 while remain[-1] == 0:
278 279 remain.pop()
279 280 size = count.pop()
280 281 stack[-size:] = [stack[-size:]]
281 282 if not remain:
282 283 break
283 284 remain[-1] = remain[-1] - 1
284 285 if not remain:
285 286 break
286 287 args[i] = stack[0]
287 288
288 289 varargs = None
289 290 if co.co_flags & inspect.CO_VARARGS:
290 291 varargs = co.co_varnames[nargs]
291 292 nargs = nargs + 1
292 293 varkw = None
293 294 if co.co_flags & inspect.CO_VARKEYWORDS:
294 295 varkw = co.co_varnames[nargs]
295 296 return inspect.Arguments(args, varargs, varkw)
296 297
297 298
298 299 # Monkeypatch inspect to apply our bugfix.
299 300 def with_patch_inspect(f):
300 301 """
301 302 Deprecated since IPython 6.0
302 303 decorator for monkeypatching inspect.findsource
303 304 """
304 305
305 306 def wrapped(*args, **kwargs):
306 307 save_findsource = inspect.findsource
307 308 save_getargs = inspect.getargs
308 309 inspect.findsource = findsource
309 310 inspect.getargs = getargs
310 311 try:
311 312 return f(*args, **kwargs)
312 313 finally:
313 314 inspect.findsource = save_findsource
314 315 inspect.getargs = save_getargs
315 316
316 317 return wrapped
317 318
318 319
319 320 def fix_frame_records_filenames(records):
320 321 """Try to fix the filenames in each record from inspect.getinnerframes().
321 322
322 323 Particularly, modules loaded from within zip files have useless filenames
323 324 attached to their code object, and inspect.getinnerframes() just uses it.
324 325 """
325 326 fixed_records = []
326 327 for frame, filename, line_no, func_name, lines, index in records:
327 328 # Look inside the frame's globals dictionary for __file__,
328 329 # which should be better. However, keep Cython filenames since
329 330 # we prefer the source filenames over the compiled .so file.
330 331 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
331 332 better_fn = frame.f_globals.get('__file__', None)
332 333 if isinstance(better_fn, str):
333 334 # Check the type just in case someone did something weird with
334 335 # __file__. It might also be None if the error occurred during
335 336 # import.
336 337 filename = better_fn
337 338 fixed_records.append((frame, filename, line_no, func_name, lines, index))
338 339 return fixed_records
339 340
340 341
341 342 @with_patch_inspect
342 343 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
343 344 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
344 345
345 346 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
346 347 # If the error is at the console, don't build any context, since it would
347 348 # otherwise produce 5 blank lines printed out (there is no file at the
348 349 # console)
349 350 rec_check = records[tb_offset:]
350 351 try:
351 352 rname = rec_check[0][1]
352 353 if rname == '<ipython console>' or rname.endswith('<string>'):
353 354 return rec_check
354 355 except IndexError:
355 356 pass
356 357
357 358 aux = traceback.extract_tb(etb)
358 359 assert len(records) == len(aux)
359 360 for i, (file, lnum, _, _) in enumerate(aux):
360 361 maybeStart = lnum - 1 - context // 2
361 362 start = max(maybeStart, 0)
362 363 end = start + context
363 364 lines = linecache.getlines(file)[start:end]
364 365 buf = list(records[i])
365 366 buf[LNUM_POS] = lnum
366 367 buf[INDEX_POS] = lnum - 1 - start
367 368 buf[LINES_POS] = lines
368 369 records[i] = tuple(buf)
369 370 return records[tb_offset:]
370 371
371 372 # Helper function -- largely belongs to VerboseTB, but we need the same
372 373 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
373 374 # can be recognized properly by ipython.el's py-traceback-line-re
374 375 # (SyntaxErrors have to be treated specially because they have no traceback)
375 376
376 377
377 378 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, _line_format=(lambda x,_:x,None)):
378 379 numbers_width = INDENT_SIZE - 1
379 380 res = []
380 381 i = lnum - index
381 382
382 383 for line in lines:
383 384 line = py3compat.cast_unicode(line)
384 385
385 386 new_line, err = _line_format(line, 'str')
386 387 if not err: line = new_line
387 388
388 389 if i == lnum:
389 390 # This is the line with the error
390 391 pad = numbers_width - len(str(i))
391 392 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
392 393 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
393 394 Colors.line, line, Colors.Normal)
394 395 else:
395 396 num = '%*s' % (numbers_width, i)
396 397 line = '%s%s%s %s' % (Colors.lineno, num,
397 398 Colors.Normal, line)
398 399
399 400 res.append(line)
400 401 if lvals and i == lnum:
401 402 res.append(lvals + '\n')
402 403 i = i + 1
403 404 return res
404 405
405 406 def is_recursion_error(etype, value, records):
406 407 try:
407 408 # RecursionError is new in Python 3.5
408 409 recursion_error_type = RecursionError
409 410 except NameError:
410 411 recursion_error_type = RuntimeError
411 412
412 413 # The default recursion limit is 1000, but some of that will be taken up
413 414 # by stack frames in IPython itself. >500 frames probably indicates
414 415 # a recursion error.
415 416 return (etype is recursion_error_type) \
416 417 and "recursion" in str(value).lower() \
417 418 and len(records) > 500
418 419
419 420 def find_recursion(etype, value, records):
420 421 """Identify the repeating stack frames from a RecursionError traceback
421 422
422 423 'records' is a list as returned by VerboseTB.get_records()
423 424
424 425 Returns (last_unique, repeat_length)
425 426 """
426 427 # This involves a bit of guesswork - we want to show enough of the traceback
427 428 # to indicate where the recursion is occurring. We guess that the innermost
428 429 # quarter of the traceback (250 frames by default) is repeats, and find the
429 430 # first frame (from in to out) that looks different.
430 431 if not is_recursion_error(etype, value, records):
431 432 return len(records), 0
432 433
433 434 # Select filename, lineno, func_name to track frames with
434 435 records = [r[1:4] for r in records]
435 436 inner_frames = records[-(len(records)//4):]
436 437 frames_repeated = set(inner_frames)
437 438
438 439 last_seen_at = {}
439 440 longest_repeat = 0
440 441 i = len(records)
441 442 for frame in reversed(records):
442 443 i -= 1
443 444 if frame not in frames_repeated:
444 445 last_unique = i
445 446 break
446 447
447 448 if frame in last_seen_at:
448 449 distance = last_seen_at[frame] - i
449 450 longest_repeat = max(longest_repeat, distance)
450 451
451 452 last_seen_at[frame] = i
452 453 else:
453 454 last_unique = 0 # The whole traceback was recursion
454 455
455 456 return last_unique, longest_repeat
456 457
457 458 #---------------------------------------------------------------------------
458 459 # Module classes
459 460 class TBTools(colorable.Colorable):
460 461 """Basic tools used by all traceback printer classes."""
461 462
462 463 # Number of frames to skip when reporting tracebacks
463 464 tb_offset = 0
464 465
465 466 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
466 467 # Whether to call the interactive pdb debugger after printing
467 468 # tracebacks or not
468 469 super(TBTools, self).__init__(parent=parent, config=config)
469 470 self.call_pdb = call_pdb
470 471
471 472 # Output stream to write to. Note that we store the original value in
472 473 # a private attribute and then make the public ostream a property, so
473 474 # that we can delay accessing sys.stdout until runtime. The way
474 475 # things are written now, the sys.stdout object is dynamically managed
475 476 # so a reference to it should NEVER be stored statically. This
476 477 # property approach confines this detail to a single location, and all
477 478 # subclasses can simply access self.ostream for writing.
478 479 self._ostream = ostream
479 480
480 481 # Create color table
481 482 self.color_scheme_table = exception_colors()
482 483
483 484 self.set_colors(color_scheme)
484 485 self.old_scheme = color_scheme # save initial value for toggles
485 486
486 487 if call_pdb:
487 488 self.pdb = debugger.Pdb()
488 489 else:
489 490 self.pdb = None
490 491
491 492 def _get_ostream(self):
492 493 """Output stream that exceptions are written to.
493 494
494 495 Valid values are:
495 496
496 497 - None: the default, which means that IPython will dynamically resolve
497 498 to sys.stdout. This ensures compatibility with most tools, including
498 499 Windows (where plain stdout doesn't recognize ANSI escapes).
499 500
500 501 - Any object with 'write' and 'flush' attributes.
501 502 """
502 503 return sys.stdout if self._ostream is None else self._ostream
503 504
504 505 def _set_ostream(self, val):
505 506 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
506 507 self._ostream = val
507 508
508 509 ostream = property(_get_ostream, _set_ostream)
509 510
510 511 def set_colors(self, *args, **kw):
511 512 """Shorthand access to the color table scheme selector method."""
512 513
513 514 # Set own color table
514 515 self.color_scheme_table.set_active_scheme(*args, **kw)
515 516 # for convenience, set Colors to the active scheme
516 517 self.Colors = self.color_scheme_table.active_colors
517 518 # Also set colors of debugger
518 519 if hasattr(self, 'pdb') and self.pdb is not None:
519 520 self.pdb.set_colors(*args, **kw)
520 521
521 522 def color_toggle(self):
522 523 """Toggle between the currently active color scheme and NoColor."""
523 524
524 525 if self.color_scheme_table.active_scheme_name == 'NoColor':
525 526 self.color_scheme_table.set_active_scheme(self.old_scheme)
526 527 self.Colors = self.color_scheme_table.active_colors
527 528 else:
528 529 self.old_scheme = self.color_scheme_table.active_scheme_name
529 530 self.color_scheme_table.set_active_scheme('NoColor')
530 531 self.Colors = self.color_scheme_table.active_colors
531 532
532 533 def stb2text(self, stb):
533 534 """Convert a structured traceback (a list) to a string."""
534 535 return '\n'.join(stb)
535 536
536 537 def text(self, etype, value, tb, tb_offset=None, context=5):
537 538 """Return formatted traceback.
538 539
539 540 Subclasses may override this if they add extra arguments.
540 541 """
541 542 tb_list = self.structured_traceback(etype, value, tb,
542 543 tb_offset, context)
543 544 return self.stb2text(tb_list)
544 545
545 546 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
546 547 context=5, mode=None):
547 548 """Return a list of traceback frames.
548 549
549 550 Must be implemented by each class.
550 551 """
551 552 raise NotImplementedError()
552 553
553 554
554 555 #---------------------------------------------------------------------------
555 556 class ListTB(TBTools):
556 557 """Print traceback information from a traceback list, with optional color.
557 558
558 559 Calling requires 3 arguments: (etype, evalue, elist)
559 560 as would be obtained by::
560 561
561 562 etype, evalue, tb = sys.exc_info()
562 563 if tb:
563 564 elist = traceback.extract_tb(tb)
564 565 else:
565 566 elist = None
566 567
567 568 It can thus be used by programs which need to process the traceback before
568 569 printing (such as console replacements based on the code module from the
569 570 standard library).
570 571
571 572 Because they are meant to be called without a full traceback (only a
572 573 list), instances of this class can't call the interactive pdb debugger."""
573 574
574 575 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
575 576 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
576 577 ostream=ostream, parent=parent,config=config)
577 578
578 579 def __call__(self, etype, value, elist):
579 580 self.ostream.flush()
580 581 self.ostream.write(self.text(etype, value, elist))
581 582 self.ostream.write('\n')
582 583
583 584 def structured_traceback(self, etype, value, elist, tb_offset=None,
584 585 context=5):
585 586 """Return a color formatted string with the traceback info.
586 587
587 588 Parameters
588 589 ----------
589 590 etype : exception type
590 591 Type of the exception raised.
591 592
592 593 value : object
593 594 Data stored in the exception
594 595
595 596 elist : list
596 597 List of frames, see class docstring for details.
597 598
598 599 tb_offset : int, optional
599 600 Number of frames in the traceback to skip. If not given, the
600 601 instance value is used (set in constructor).
601 602
602 603 context : int, optional
603 604 Number of lines of context information to print.
604 605
605 606 Returns
606 607 -------
607 608 String with formatted exception.
608 609 """
609 610 tb_offset = self.tb_offset if tb_offset is None else tb_offset
610 611 Colors = self.Colors
611 612 out_list = []
612 613 if elist:
613 614
614 615 if tb_offset and len(elist) > tb_offset:
615 616 elist = elist[tb_offset:]
616 617
617 618 out_list.append('Traceback %s(most recent call last)%s:' %
618 619 (Colors.normalEm, Colors.Normal) + '\n')
619 620 out_list.extend(self._format_list(elist))
620 621 # The exception info should be a single entry in the list.
621 622 lines = ''.join(self._format_exception_only(etype, value))
622 623 out_list.append(lines)
623 624
624 625 # Note: this code originally read:
625 626
626 627 ## for line in lines[:-1]:
627 628 ## out_list.append(" "+line)
628 629 ## out_list.append(lines[-1])
629 630
630 631 # This means it was indenting everything but the last line by a little
631 632 # bit. I've disabled this for now, but if we see ugliness somewhere we
632 633 # can restore it.
633 634
634 635 return out_list
635 636
636 637 def _format_list(self, extracted_list):
637 638 """Format a list of traceback entry tuples for printing.
638 639
639 640 Given a list of tuples as returned by extract_tb() or
640 641 extract_stack(), return a list of strings ready for printing.
641 642 Each string in the resulting list corresponds to the item with the
642 643 same index in the argument list. Each string ends in a newline;
643 644 the strings may contain internal newlines as well, for those items
644 645 whose source text line is not None.
645 646
646 647 Lifted almost verbatim from traceback.py
647 648 """
648 649
649 650 Colors = self.Colors
650 651 list = []
651 652 for filename, lineno, name, line in extracted_list[:-1]:
652 653 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
653 654 (Colors.filename, filename, Colors.Normal,
654 655 Colors.lineno, lineno, Colors.Normal,
655 656 Colors.name, name, Colors.Normal)
656 657 if line:
657 658 item += ' %s\n' % line.strip()
658 659 list.append(item)
659 660 # Emphasize the last entry
660 661 filename, lineno, name, line = extracted_list[-1]
661 662 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
662 663 (Colors.normalEm,
663 664 Colors.filenameEm, filename, Colors.normalEm,
664 665 Colors.linenoEm, lineno, Colors.normalEm,
665 666 Colors.nameEm, name, Colors.normalEm,
666 667 Colors.Normal)
667 668 if line:
668 669 item += '%s %s%s\n' % (Colors.line, line.strip(),
669 670 Colors.Normal)
670 671 list.append(item)
671 672 return list
672 673
673 674 def _format_exception_only(self, etype, value):
674 675 """Format the exception part of a traceback.
675 676
676 677 The arguments are the exception type and value such as given by
677 678 sys.exc_info()[:2]. The return value is a list of strings, each ending
678 679 in a newline. Normally, the list contains a single string; however,
679 680 for SyntaxError exceptions, it contains several lines that (when
680 681 printed) display detailed information about where the syntax error
681 682 occurred. The message indicating which exception occurred is the
682 683 always last string in the list.
683 684
684 685 Also lifted nearly verbatim from traceback.py
685 686 """
686 687 have_filedata = False
687 688 Colors = self.Colors
688 689 list = []
689 690 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
690 691 if value is None:
691 692 # Not sure if this can still happen in Python 2.6 and above
692 693 list.append(stype + '\n')
693 694 else:
694 695 if issubclass(etype, SyntaxError):
695 696 have_filedata = True
696 697 if not value.filename: value.filename = "<string>"
697 698 if value.lineno:
698 699 lineno = value.lineno
699 700 textline = linecache.getline(value.filename, value.lineno)
700 701 else:
701 702 lineno = 'unknown'
702 703 textline = ''
703 704 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
704 705 (Colors.normalEm,
705 706 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
706 707 Colors.linenoEm, lineno, Colors.Normal ))
707 708 if textline == '':
708 709 textline = py3compat.cast_unicode(value.text, "utf-8")
709 710
710 711 if textline is not None:
711 712 i = 0
712 713 while i < len(textline) and textline[i].isspace():
713 714 i += 1
714 715 list.append('%s %s%s\n' % (Colors.line,
715 716 textline.strip(),
716 717 Colors.Normal))
717 718 if value.offset is not None:
718 719 s = ' '
719 720 for c in textline[i:value.offset - 1]:
720 721 if c.isspace():
721 722 s += c
722 723 else:
723 724 s += ' '
724 725 list.append('%s%s^%s\n' % (Colors.caret, s,
725 726 Colors.Normal))
726 727
727 728 try:
728 729 s = value.msg
729 730 except Exception:
730 731 s = self._some_str(value)
731 732 if s:
732 733 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
733 734 Colors.Normal, s))
734 735 else:
735 736 list.append('%s\n' % stype)
736 737
737 738 # sync with user hooks
738 739 if have_filedata:
739 740 ipinst = get_ipython()
740 741 if ipinst is not None:
741 742 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
742 743
743 744 return list
744 745
745 746 def get_exception_only(self, etype, value):
746 747 """Only print the exception type and message, without a traceback.
747 748
748 749 Parameters
749 750 ----------
750 751 etype : exception type
751 752 value : exception value
752 753 """
753 754 return ListTB.structured_traceback(self, etype, value, [])
754 755
755 756 def show_exception_only(self, etype, evalue):
756 757 """Only print the exception type and message, without a traceback.
757 758
758 759 Parameters
759 760 ----------
760 761 etype : exception type
761 762 value : exception value
762 763 """
763 764 # This method needs to use __call__ from *this* class, not the one from
764 765 # a subclass whose signature or behavior may be different
765 766 ostream = self.ostream
766 767 ostream.flush()
767 768 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
768 769 ostream.flush()
769 770
770 771 def _some_str(self, value):
771 772 # Lifted from traceback.py
772 773 try:
773 774 return py3compat.cast_unicode(str(value))
774 775 except:
775 776 return u'<unprintable %s object>' % type(value).__name__
776 777
777 778
778 779 #----------------------------------------------------------------------------
779 780 class VerboseTB(TBTools):
780 781 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
781 782 of HTML. Requires inspect and pydoc. Crazy, man.
782 783
783 784 Modified version which optionally strips the topmost entries from the
784 785 traceback, to be used with alternate interpreters (because their own code
785 786 would appear in the traceback)."""
786 787
787 788 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
788 789 tb_offset=0, long_header=False, include_vars=True,
789 790 check_cache=None, debugger_cls = None,
790 791 parent=None, config=None):
791 792 """Specify traceback offset, headers and color scheme.
792 793
793 794 Define how many frames to drop from the tracebacks. Calling it with
794 795 tb_offset=1 allows use of this handler in interpreters which will have
795 796 their own code at the top of the traceback (VerboseTB will first
796 797 remove that frame before printing the traceback info)."""
797 798 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
798 799 ostream=ostream, parent=parent, config=config)
799 800 self.tb_offset = tb_offset
800 801 self.long_header = long_header
801 802 self.include_vars = include_vars
802 803 # By default we use linecache.checkcache, but the user can provide a
803 804 # different check_cache implementation. This is used by the IPython
804 805 # kernel to provide tracebacks for interactive code that is cached,
805 806 # by a compiler instance that flushes the linecache but preserves its
806 807 # own code cache.
807 808 if check_cache is None:
808 809 check_cache = linecache.checkcache
809 810 self.check_cache = check_cache
810 811
811 812 self.debugger_cls = debugger_cls or debugger.Pdb
812 813
813 814 def format_records(self, records, last_unique, recursion_repeat):
814 815 """Format the stack frames of the traceback"""
815 816 frames = []
816 817 for r in records[:last_unique+recursion_repeat+1]:
817 818 #print '*** record:',file,lnum,func,lines,index # dbg
818 819 frames.append(self.format_record(*r))
819 820
820 821 if recursion_repeat:
821 822 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
822 823 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
823 824
824 825 return frames
825 826
826 827 def format_record(self, frame, file, lnum, func, lines, index):
827 828 """Format a single stack frame"""
828 829 Colors = self.Colors # just a shorthand + quicker name lookup
829 830 ColorsNormal = Colors.Normal # used a lot
830 831 col_scheme = self.color_scheme_table.active_scheme_name
831 832 indent = ' ' * INDENT_SIZE
832 833 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
833 834 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
834 835 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
835 836 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
836 837 ColorsNormal)
837 838 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
838 839 (Colors.vName, Colors.valEm, ColorsNormal)
839 840 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
840 841 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
841 842 Colors.vName, ColorsNormal)
842 843 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
843 844
844 845 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
845 846 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
846 847 ColorsNormal)
847 848
848 849 abspath = os.path.abspath
849 850
850 851
851 852 if not file:
852 853 file = '?'
853 854 elif file.startswith(str("<")) and file.endswith(str(">")):
854 855 # Not a real filename, no problem...
855 856 pass
856 857 elif not os.path.isabs(file):
857 858 # Try to make the filename absolute by trying all
858 859 # sys.path entries (which is also what linecache does)
859 860 for dirname in sys.path:
860 861 try:
861 862 fullname = os.path.join(dirname, file)
862 863 if os.path.isfile(fullname):
863 864 file = os.path.abspath(fullname)
864 865 break
865 866 except Exception:
866 867 # Just in case that sys.path contains very
867 868 # strange entries...
868 869 pass
869 870
870 871 file = py3compat.cast_unicode(file, util_path.fs_encoding)
871 872 link = tpl_link % util_path.compress_user(file)
872 873 args, varargs, varkw, locals = inspect.getargvalues(frame)
873 874
874 875 if func == '?':
875 876 call = ''
876 877 else:
877 878 # Decide whether to include variable details or not
878 879 var_repr = self.include_vars and eqrepr or nullrepr
879 880 try:
880 881 call = tpl_call % (func, inspect.formatargvalues(args,
881 882 varargs, varkw,
882 883 locals, formatvalue=var_repr))
883 884 except KeyError:
884 885 # This happens in situations like errors inside generator
885 886 # expressions, where local variables are listed in the
886 887 # line, but can't be extracted from the frame. I'm not
887 888 # 100% sure this isn't actually a bug in inspect itself,
888 889 # but since there's no info for us to compute with, the
889 890 # best we can do is report the failure and move on. Here
890 891 # we must *not* call any traceback construction again,
891 892 # because that would mess up use of %debug later on. So we
892 893 # simply report the failure and move on. The only
893 894 # limitation will be that this frame won't have locals
894 895 # listed in the call signature. Quite subtle problem...
895 896 # I can't think of a good way to validate this in a unit
896 897 # test, but running a script consisting of:
897 898 # dict( (k,v.strip()) for (k,v) in range(10) )
898 899 # will illustrate the error, if this exception catch is
899 900 # disabled.
900 901 call = tpl_call_fail % func
901 902
902 903 # Don't attempt to tokenize binary files.
903 904 if file.endswith(('.so', '.pyd', '.dll')):
904 905 return '%s %s\n' % (link, call)
905 906
906 907 elif file.endswith(('.pyc', '.pyo')):
907 908 # Look up the corresponding source file.
908 909 try:
909 file = openpy.source_from_cache(file)
910 file = source_from_cache(file)
910 911 except ValueError:
911 912 # Failed to get the source file for some reason
912 913 # E.g. https://github.com/ipython/ipython/issues/9486
913 914 return '%s %s\n' % (link, call)
914 915
915 916 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
916 917 line = getline(file, lnum[0])
917 918 lnum[0] += 1
918 919 return line
919 920
920 921 # Build the list of names on this line of code where the exception
921 922 # occurred.
922 923 try:
923 924 names = []
924 925 name_cont = False
925 926
926 927 for token_type, token, start, end, line in generate_tokens(linereader):
927 928 # build composite names
928 929 if token_type == tokenize.NAME and token not in keyword.kwlist:
929 930 if name_cont:
930 931 # Continuation of a dotted name
931 932 try:
932 933 names[-1].append(token)
933 934 except IndexError:
934 935 names.append([token])
935 936 name_cont = False
936 937 else:
937 938 # Regular new names. We append everything, the caller
938 939 # will be responsible for pruning the list later. It's
939 940 # very tricky to try to prune as we go, b/c composite
940 941 # names can fool us. The pruning at the end is easy
941 942 # to do (or the caller can print a list with repeated
942 943 # names if so desired.
943 944 names.append([token])
944 945 elif token == '.':
945 946 name_cont = True
946 947 elif token_type == tokenize.NEWLINE:
947 948 break
948 949
949 950 except (IndexError, UnicodeDecodeError, SyntaxError):
950 951 # signals exit of tokenizer
951 952 # SyntaxError can occur if the file is not actually Python
952 953 # - see gh-6300
953 954 pass
954 955 except tokenize.TokenError as msg:
955 956 # Tokenizing may fail for various reasons, many of which are
956 957 # harmless. (A good example is when the line in question is the
957 958 # close of a triple-quoted string, cf gh-6864). We don't want to
958 959 # show this to users, but want make it available for debugging
959 960 # purposes.
960 961 _m = ("An unexpected error occurred while tokenizing input\n"
961 962 "The following traceback may be corrupted or invalid\n"
962 963 "The error message is: %s\n" % msg)
963 964 debug(_m)
964 965
965 966 # Join composite names (e.g. "dict.fromkeys")
966 967 names = ['.'.join(n) for n in names]
967 968 # prune names list of duplicates, but keep the right order
968 969 unique_names = uniq_stable(names)
969 970
970 971 # Start loop over vars
971 972 lvals = []
972 973 if self.include_vars:
973 974 for name_full in unique_names:
974 975 name_base = name_full.split('.', 1)[0]
975 976 if name_base in frame.f_code.co_varnames:
976 977 if name_base in locals:
977 978 try:
978 979 value = repr(eval(name_full, locals))
979 980 except:
980 981 value = undefined
981 982 else:
982 983 value = undefined
983 984 name = tpl_local_var % name_full
984 985 else:
985 986 if name_base in frame.f_globals:
986 987 try:
987 988 value = repr(eval(name_full, frame.f_globals))
988 989 except:
989 990 value = undefined
990 991 else:
991 992 value = undefined
992 993 name = tpl_global_var % name_full
993 994 lvals.append(tpl_name_val % (name, value))
994 995 if lvals:
995 996 lvals = '%s%s' % (indent, em_normal.join(lvals))
996 997 else:
997 998 lvals = ''
998 999
999 1000 level = '%s %s\n' % (link, call)
1000 1001
1001 1002 if index is None:
1002 1003 return level
1003 1004 else:
1004 1005 _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2
1005 1006 return '%s%s' % (level, ''.join(
1006 1007 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1007 1008 _line_format)))
1008 1009
1009 1010 def prepare_chained_exception_message(self, cause):
1010 1011 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1011 1012 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1012 1013
1013 1014 if cause:
1014 1015 message = [[direct_cause]]
1015 1016 else:
1016 1017 message = [[exception_during_handling]]
1017 1018 return message
1018 1019
1019 1020 def prepare_header(self, etype, long_version=False):
1020 1021 colors = self.Colors # just a shorthand + quicker name lookup
1021 1022 colorsnormal = colors.Normal # used a lot
1022 1023 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1023 1024 width = min(75, get_terminal_size()[0])
1024 1025 if long_version:
1025 1026 # Header with the exception type, python version, and date
1026 1027 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1027 1028 date = time.ctime(time.time())
1028 1029
1029 1030 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1030 1031 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1031 1032 pyver, date.rjust(width) )
1032 1033 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1033 1034 "\ncalls leading up to the error, with the most recent (innermost) call last."
1034 1035 else:
1035 1036 # Simplified header
1036 1037 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1037 1038 rjust(width - len(str(etype))) )
1038 1039
1039 1040 return head
1040 1041
1041 1042 def format_exception(self, etype, evalue):
1042 1043 colors = self.Colors # just a shorthand + quicker name lookup
1043 1044 colorsnormal = colors.Normal # used a lot
1044 1045 indent = ' ' * INDENT_SIZE
1045 1046 # Get (safely) a string form of the exception info
1046 1047 try:
1047 1048 etype_str, evalue_str = map(str, (etype, evalue))
1048 1049 except:
1049 1050 # User exception is improperly defined.
1050 1051 etype, evalue = str, sys.exc_info()[:2]
1051 1052 etype_str, evalue_str = map(str, (etype, evalue))
1052 1053 # ... and format it
1053 1054 return ['%s%s%s: %s' % (colors.excName, etype_str,
1054 1055 colorsnormal, py3compat.cast_unicode(evalue_str))]
1055 1056
1056 1057 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1057 1058 """Formats the header, traceback and exception message for a single exception.
1058 1059
1059 1060 This may be called multiple times by Python 3 exception chaining
1060 1061 (PEP 3134).
1061 1062 """
1062 1063 # some locals
1063 1064 orig_etype = etype
1064 1065 try:
1065 1066 etype = etype.__name__
1066 1067 except AttributeError:
1067 1068 pass
1068 1069
1069 1070 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1070 1071 head = self.prepare_header(etype, self.long_header)
1071 1072 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1072 1073
1073 1074 if records is None:
1074 1075 return ""
1075 1076
1076 1077 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1077 1078
1078 1079 frames = self.format_records(records, last_unique, recursion_repeat)
1079 1080
1080 1081 formatted_exception = self.format_exception(etype, evalue)
1081 1082 if records:
1082 1083 filepath, lnum = records[-1][1:3]
1083 1084 filepath = os.path.abspath(filepath)
1084 1085 ipinst = get_ipython()
1085 1086 if ipinst is not None:
1086 1087 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1087 1088
1088 1089 return [[head] + frames + [''.join(formatted_exception[0])]]
1089 1090
1090 1091 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1091 1092 try:
1092 1093 # Try the default getinnerframes and Alex's: Alex's fixes some
1093 1094 # problems, but it generates empty tracebacks for console errors
1094 1095 # (5 blanks lines) where none should be returned.
1095 1096 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1096 1097 except UnicodeDecodeError:
1097 1098 # This can occur if a file's encoding magic comment is wrong.
1098 1099 # I can't see a way to recover without duplicating a bunch of code
1099 1100 # from the stdlib traceback module. --TK
1100 1101 error('\nUnicodeDecodeError while processing traceback.\n')
1101 1102 return None
1102 1103 except:
1103 1104 # FIXME: I've been getting many crash reports from python 2.3
1104 1105 # users, traceable to inspect.py. If I can find a small test-case
1105 1106 # to reproduce this, I should either write a better workaround or
1106 1107 # file a bug report against inspect (if that's the real problem).
1107 1108 # So far, I haven't been able to find an isolated example to
1108 1109 # reproduce the problem.
1109 1110 inspect_error()
1110 1111 traceback.print_exc(file=self.ostream)
1111 1112 info('\nUnfortunately, your original traceback can not be constructed.\n')
1112 1113 return None
1113 1114
1114 1115 def get_parts_of_chained_exception(self, evalue):
1115 1116 def get_chained_exception(exception_value):
1116 1117 cause = getattr(exception_value, '__cause__', None)
1117 1118 if cause:
1118 1119 return cause
1119 1120 if getattr(exception_value, '__suppress_context__', False):
1120 1121 return None
1121 1122 return getattr(exception_value, '__context__', None)
1122 1123
1123 1124 chained_evalue = get_chained_exception(evalue)
1124 1125
1125 1126 if chained_evalue:
1126 1127 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1127 1128
1128 1129 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1129 1130 number_of_lines_of_context=5):
1130 1131 """Return a nice text document describing the traceback."""
1131 1132
1132 1133 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1133 1134 tb_offset)
1134 1135
1135 1136 colors = self.Colors # just a shorthand + quicker name lookup
1136 1137 colorsnormal = colors.Normal # used a lot
1137 1138 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1138 1139 structured_traceback_parts = [head]
1139 1140 chained_exceptions_tb_offset = 0
1140 1141 lines_of_context = 3
1141 1142 formatted_exceptions = formatted_exception
1142 1143 exception = self.get_parts_of_chained_exception(evalue)
1143 1144 if exception:
1144 1145 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1145 1146 etype, evalue, etb = exception
1146 1147 else:
1147 1148 evalue = None
1148 1149 chained_exc_ids = set()
1149 1150 while evalue:
1150 1151 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1151 1152 chained_exceptions_tb_offset)
1152 1153 exception = self.get_parts_of_chained_exception(evalue)
1153 1154
1154 1155 if exception and not id(exception[1]) in chained_exc_ids:
1155 1156 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1156 1157 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1157 1158 etype, evalue, etb = exception
1158 1159 else:
1159 1160 evalue = None
1160 1161
1161 1162 # we want to see exceptions in a reversed order:
1162 1163 # the first exception should be on top
1163 1164 for formatted_exception in reversed(formatted_exceptions):
1164 1165 structured_traceback_parts += formatted_exception
1165 1166
1166 1167 return structured_traceback_parts
1167 1168
1168 1169 def debugger(self, force=False):
1169 1170 """Call up the pdb debugger if desired, always clean up the tb
1170 1171 reference.
1171 1172
1172 1173 Keywords:
1173 1174
1174 1175 - force(False): by default, this routine checks the instance call_pdb
1175 1176 flag and does not actually invoke the debugger if the flag is false.
1176 1177 The 'force' option forces the debugger to activate even if the flag
1177 1178 is false.
1178 1179
1179 1180 If the call_pdb flag is set, the pdb interactive debugger is
1180 1181 invoked. In all cases, the self.tb reference to the current traceback
1181 1182 is deleted to prevent lingering references which hamper memory
1182 1183 management.
1183 1184
1184 1185 Note that each call to pdb() does an 'import readline', so if your app
1185 1186 requires a special setup for the readline completers, you'll have to
1186 1187 fix that by hand after invoking the exception handler."""
1187 1188
1188 1189 if force or self.call_pdb:
1189 1190 if self.pdb is None:
1190 1191 self.pdb = self.debugger_cls()
1191 1192 # the system displayhook may have changed, restore the original
1192 1193 # for pdb
1193 1194 display_trap = DisplayTrap(hook=sys.__displayhook__)
1194 1195 with display_trap:
1195 1196 self.pdb.reset()
1196 1197 # Find the right frame so we don't pop up inside ipython itself
1197 1198 if hasattr(self, 'tb') and self.tb is not None:
1198 1199 etb = self.tb
1199 1200 else:
1200 1201 etb = self.tb = sys.last_traceback
1201 1202 while self.tb is not None and self.tb.tb_next is not None:
1202 1203 self.tb = self.tb.tb_next
1203 1204 if etb and etb.tb_next:
1204 1205 etb = etb.tb_next
1205 1206 self.pdb.botframe = etb.tb_frame
1206 1207 self.pdb.interaction(self.tb.tb_frame, self.tb)
1207 1208
1208 1209 if hasattr(self, 'tb'):
1209 1210 del self.tb
1210 1211
1211 1212 def handler(self, info=None):
1212 1213 (etype, evalue, etb) = info or sys.exc_info()
1213 1214 self.tb = etb
1214 1215 ostream = self.ostream
1215 1216 ostream.flush()
1216 1217 ostream.write(self.text(etype, evalue, etb))
1217 1218 ostream.write('\n')
1218 1219 ostream.flush()
1219 1220
1220 1221 # Changed so an instance can just be called as VerboseTB_inst() and print
1221 1222 # out the right info on its own.
1222 1223 def __call__(self, etype=None, evalue=None, etb=None):
1223 1224 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1224 1225 if etb is None:
1225 1226 self.handler()
1226 1227 else:
1227 1228 self.handler((etype, evalue, etb))
1228 1229 try:
1229 1230 self.debugger()
1230 1231 except KeyboardInterrupt:
1231 1232 print("\nKeyboardInterrupt")
1232 1233
1233 1234
1234 1235 #----------------------------------------------------------------------------
1235 1236 class FormattedTB(VerboseTB, ListTB):
1236 1237 """Subclass ListTB but allow calling with a traceback.
1237 1238
1238 1239 It can thus be used as a sys.excepthook for Python > 2.1.
1239 1240
1240 1241 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1241 1242
1242 1243 Allows a tb_offset to be specified. This is useful for situations where
1243 1244 one needs to remove a number of topmost frames from the traceback (such as
1244 1245 occurs with python programs that themselves execute other python code,
1245 1246 like Python shells). """
1246 1247
1247 1248 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1248 1249 ostream=None,
1249 1250 tb_offset=0, long_header=False, include_vars=False,
1250 1251 check_cache=None, debugger_cls=None,
1251 1252 parent=None, config=None):
1252 1253
1253 1254 # NEVER change the order of this list. Put new modes at the end:
1254 1255 self.valid_modes = ['Plain', 'Context', 'Verbose']
1255 1256 self.verbose_modes = self.valid_modes[1:3]
1256 1257
1257 1258 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1258 1259 ostream=ostream, tb_offset=tb_offset,
1259 1260 long_header=long_header, include_vars=include_vars,
1260 1261 check_cache=check_cache, debugger_cls=debugger_cls,
1261 1262 parent=parent, config=config)
1262 1263
1263 1264 # Different types of tracebacks are joined with different separators to
1264 1265 # form a single string. They are taken from this dict
1265 1266 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1266 1267 # set_mode also sets the tb_join_char attribute
1267 1268 self.set_mode(mode)
1268 1269
1269 1270 def _extract_tb(self, tb):
1270 1271 if tb:
1271 1272 return traceback.extract_tb(tb)
1272 1273 else:
1273 1274 return None
1274 1275
1275 1276 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1276 1277 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1277 1278 mode = self.mode
1278 1279 if mode in self.verbose_modes:
1279 1280 # Verbose modes need a full traceback
1280 1281 return VerboseTB.structured_traceback(
1281 1282 self, etype, value, tb, tb_offset, number_of_lines_of_context
1282 1283 )
1283 1284 else:
1284 1285 # We must check the source cache because otherwise we can print
1285 1286 # out-of-date source code.
1286 1287 self.check_cache()
1287 1288 # Now we can extract and format the exception
1288 1289 elist = self._extract_tb(tb)
1289 1290 return ListTB.structured_traceback(
1290 1291 self, etype, value, elist, tb_offset, number_of_lines_of_context
1291 1292 )
1292 1293
1293 1294 def stb2text(self, stb):
1294 1295 """Convert a structured traceback (a list) to a string."""
1295 1296 return self.tb_join_char.join(stb)
1296 1297
1297 1298
1298 1299 def set_mode(self, mode=None):
1299 1300 """Switch to the desired mode.
1300 1301
1301 1302 If mode is not specified, cycles through the available modes."""
1302 1303
1303 1304 if not mode:
1304 1305 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1305 1306 len(self.valid_modes)
1306 1307 self.mode = self.valid_modes[new_idx]
1307 1308 elif mode not in self.valid_modes:
1308 1309 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1309 1310 'Valid modes: ' + str(self.valid_modes))
1310 1311 else:
1311 1312 self.mode = mode
1312 1313 # include variable details only in 'Verbose' mode
1313 1314 self.include_vars = (self.mode == self.valid_modes[2])
1314 1315 # Set the join character for generating text tracebacks
1315 1316 self.tb_join_char = self._join_chars[self.mode]
1316 1317
1317 1318 # some convenient shortcuts
1318 1319 def plain(self):
1319 1320 self.set_mode(self.valid_modes[0])
1320 1321
1321 1322 def context(self):
1322 1323 self.set_mode(self.valid_modes[1])
1323 1324
1324 1325 def verbose(self):
1325 1326 self.set_mode(self.valid_modes[2])
1326 1327
1327 1328
1328 1329 #----------------------------------------------------------------------------
1329 1330 class AutoFormattedTB(FormattedTB):
1330 1331 """A traceback printer which can be called on the fly.
1331 1332
1332 1333 It will find out about exceptions by itself.
1333 1334
1334 1335 A brief example::
1335 1336
1336 1337 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1337 1338 try:
1338 1339 ...
1339 1340 except:
1340 1341 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1341 1342 """
1342 1343
1343 1344 def __call__(self, etype=None, evalue=None, etb=None,
1344 1345 out=None, tb_offset=None):
1345 1346 """Print out a formatted exception traceback.
1346 1347
1347 1348 Optional arguments:
1348 1349 - out: an open file-like object to direct output to.
1349 1350
1350 1351 - tb_offset: the number of frames to skip over in the stack, on a
1351 1352 per-call basis (this overrides temporarily the instance's tb_offset
1352 1353 given at initialization time. """
1353 1354
1354 1355 if out is None:
1355 1356 out = self.ostream
1356 1357 out.flush()
1357 1358 out.write(self.text(etype, evalue, etb, tb_offset))
1358 1359 out.write('\n')
1359 1360 out.flush()
1360 1361 # FIXME: we should remove the auto pdb behavior from here and leave
1361 1362 # that to the clients.
1362 1363 try:
1363 1364 self.debugger()
1364 1365 except KeyboardInterrupt:
1365 1366 print("\nKeyboardInterrupt")
1366 1367
1367 1368 def structured_traceback(self, etype=None, value=None, tb=None,
1368 1369 tb_offset=None, number_of_lines_of_context=5):
1369 1370 if etype is None:
1370 1371 etype, value, tb = sys.exc_info()
1371 1372 self.tb = tb
1372 1373 return FormattedTB.structured_traceback(
1373 1374 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1374 1375
1375 1376
1376 1377 #---------------------------------------------------------------------------
1377 1378
1378 1379 # A simple class to preserve Nathan's original functionality.
1379 1380 class ColorTB(FormattedTB):
1380 1381 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1381 1382
1382 1383 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1383 1384 FormattedTB.__init__(self, color_scheme=color_scheme,
1384 1385 call_pdb=call_pdb, **kwargs)
1385 1386
1386 1387
1387 1388 class SyntaxTB(ListTB):
1388 1389 """Extension which holds some state: the last exception value"""
1389 1390
1390 1391 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1391 1392 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1392 1393 self.last_syntax_error = None
1393 1394
1394 1395 def __call__(self, etype, value, elist):
1395 1396 self.last_syntax_error = value
1396 1397
1397 1398 ListTB.__call__(self, etype, value, elist)
1398 1399
1399 1400 def structured_traceback(self, etype, value, elist, tb_offset=None,
1400 1401 context=5):
1401 1402 # If the source file has been edited, the line in the syntax error can
1402 1403 # be wrong (retrieved from an outdated cache). This replaces it with
1403 1404 # the current value.
1404 1405 if isinstance(value, SyntaxError) \
1405 1406 and isinstance(value.filename, str) \
1406 1407 and isinstance(value.lineno, int):
1407 1408 linecache.checkcache(value.filename)
1408 1409 newtext = linecache.getline(value.filename, value.lineno)
1409 1410 if newtext:
1410 1411 value.text = newtext
1411 1412 self.last_syntax_error = value
1412 1413 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1413 1414 tb_offset=tb_offset, context=context)
1414 1415
1415 1416 def clear_err_state(self):
1416 1417 """Return the current error state and clear it"""
1417 1418 e = self.last_syntax_error
1418 1419 self.last_syntax_error = None
1419 1420 return e
1420 1421
1421 1422 def stb2text(self, stb):
1422 1423 """Convert a structured traceback (a list) to a string."""
1423 1424 return ''.join(stb)
1424 1425
1425 1426
1426 1427 # some internal-use functions
1427 1428 def text_repr(value):
1428 1429 """Hopefully pretty robust repr equivalent."""
1429 1430 # this is pretty horrible but should always return *something*
1430 1431 try:
1431 1432 return pydoc.text.repr(value)
1432 1433 except KeyboardInterrupt:
1433 1434 raise
1434 1435 except:
1435 1436 try:
1436 1437 return repr(value)
1437 1438 except KeyboardInterrupt:
1438 1439 raise
1439 1440 except:
1440 1441 try:
1441 1442 # all still in an except block so we catch
1442 1443 # getattr raising
1443 1444 name = getattr(value, '__name__', None)
1444 1445 if name:
1445 1446 # ick, recursion
1446 1447 return text_repr(name)
1447 1448 klass = getattr(value, '__class__', None)
1448 1449 if klass:
1449 1450 return '%s instance' % text_repr(klass)
1450 1451 except KeyboardInterrupt:
1451 1452 raise
1452 1453 except:
1453 1454 return 'UNRECOVERABLE REPR FAILURE'
1454 1455
1455 1456
1456 1457 def eqrepr(value, repr=text_repr):
1457 1458 return '=%s' % repr(value)
1458 1459
1459 1460
1460 1461 def nullrepr(value, repr=text_repr):
1461 1462 return ''
@@ -1,524 +1,523 b''
1 1 """IPython extension to reload modules before executing user code.
2 2
3 3 ``autoreload`` reloads modules automatically before entering the execution of
4 4 code typed at the IPython prompt.
5 5
6 6 This makes for example the following workflow possible:
7 7
8 8 .. sourcecode:: ipython
9 9
10 10 In [1]: %load_ext autoreload
11 11
12 12 In [2]: %autoreload 2
13 13
14 14 In [3]: from foo import some_function
15 15
16 16 In [4]: some_function()
17 17 Out[4]: 42
18 18
19 19 In [5]: # open foo.py in an editor and change some_function to return 43
20 20
21 21 In [6]: some_function()
22 22 Out[6]: 43
23 23
24 24 The module was reloaded without reloading it explicitly, and the object
25 25 imported with ``from foo import ...`` was also updated.
26 26
27 27 Usage
28 28 =====
29 29
30 30 The following magic commands are provided:
31 31
32 32 ``%autoreload``
33 33
34 34 Reload all modules (except those excluded by ``%aimport``)
35 35 automatically now.
36 36
37 37 ``%autoreload 0``
38 38
39 39 Disable automatic reloading.
40 40
41 41 ``%autoreload 1``
42 42
43 43 Reload all modules imported with ``%aimport`` every time before
44 44 executing the Python code typed.
45 45
46 46 ``%autoreload 2``
47 47
48 48 Reload all modules (except those excluded by ``%aimport``) every
49 49 time before executing the Python code typed.
50 50
51 51 ``%aimport``
52 52
53 53 List modules which are to be automatically imported or not to be imported.
54 54
55 55 ``%aimport foo``
56 56
57 57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
58 58
59 59 ``%aimport foo, bar``
60 60
61 61 Import modules 'foo', 'bar' and mark them to be autoreloaded for ``%autoreload 1``
62 62
63 63 ``%aimport -foo``
64 64
65 65 Mark module 'foo' to not be autoreloaded.
66 66
67 67 Caveats
68 68 =======
69 69
70 70 Reloading Python modules in a reliable way is in general difficult,
71 71 and unexpected things may occur. ``%autoreload`` tries to work around
72 72 common pitfalls by replacing function code objects and parts of
73 73 classes previously in the module with new versions. This makes the
74 74 following things to work:
75 75
76 76 - Functions and classes imported via 'from xxx import foo' are upgraded
77 77 to new versions when 'xxx' is reloaded.
78 78
79 79 - Methods and properties of classes are upgraded on reload, so that
80 80 calling 'c.foo()' on an object 'c' created before the reload causes
81 81 the new code for 'foo' to be executed.
82 82
83 83 Some of the known remaining caveats are:
84 84
85 85 - Replacing code objects does not always succeed: changing a @property
86 86 in a class to an ordinary method or a method to a member variable
87 87 can cause problems (but in old objects only).
88 88
89 89 - Functions that are removed (eg. via monkey-patching) from a module
90 90 before it is reloaded are not upgraded.
91 91
92 92 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
93 93 """
94 94
95 95 skip_doctest = True
96 96
97 97 #-----------------------------------------------------------------------------
98 98 # Copyright (C) 2000 Thomas Heller
99 99 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
100 100 # Copyright (C) 2012 The IPython Development Team
101 101 #
102 102 # Distributed under the terms of the BSD License. The full license is in
103 103 # the file COPYING, distributed as part of this software.
104 104 #-----------------------------------------------------------------------------
105 105 #
106 106 # This IPython module is written by Pauli Virtanen, based on the autoreload
107 107 # code by Thomas Heller.
108 108
109 109 #-----------------------------------------------------------------------------
110 110 # Imports
111 111 #-----------------------------------------------------------------------------
112 112
113 113 import os
114 114 import sys
115 115 import traceback
116 116 import types
117 117 import weakref
118 118 from importlib import import_module
119 from importlib.util import source_from_cache
119 120 from imp import reload
120 121
121 from IPython.utils import openpy
122
123 122 #------------------------------------------------------------------------------
124 123 # Autoreload functionality
125 124 #------------------------------------------------------------------------------
126 125
127 126 class ModuleReloader(object):
128 127 enabled = False
129 128 """Whether this reloader is enabled"""
130 129
131 130 check_all = True
132 131 """Autoreload all modules, not just those listed in 'modules'"""
133 132
134 133 def __init__(self):
135 134 # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
136 135 self.failed = {}
137 136 # Modules specially marked as autoreloadable.
138 137 self.modules = {}
139 138 # Modules specially marked as not autoreloadable.
140 139 self.skip_modules = {}
141 140 # (module-name, name) -> weakref, for replacing old code objects
142 141 self.old_objects = {}
143 142 # Module modification timestamps
144 143 self.modules_mtimes = {}
145 144
146 145 # Cache module modification times
147 146 self.check(check_all=True, do_reload=False)
148 147
149 148 def mark_module_skipped(self, module_name):
150 149 """Skip reloading the named module in the future"""
151 150 try:
152 151 del self.modules[module_name]
153 152 except KeyError:
154 153 pass
155 154 self.skip_modules[module_name] = True
156 155
157 156 def mark_module_reloadable(self, module_name):
158 157 """Reload the named module in the future (if it is imported)"""
159 158 try:
160 159 del self.skip_modules[module_name]
161 160 except KeyError:
162 161 pass
163 162 self.modules[module_name] = True
164 163
165 164 def aimport_module(self, module_name):
166 165 """Import a module, and mark it reloadable
167 166
168 167 Returns
169 168 -------
170 169 top_module : module
171 170 The imported module if it is top-level, or the top-level
172 171 top_name : module
173 172 Name of top_module
174 173
175 174 """
176 175 self.mark_module_reloadable(module_name)
177 176
178 177 import_module(module_name)
179 178 top_name = module_name.split('.')[0]
180 179 top_module = sys.modules[top_name]
181 180 return top_module, top_name
182 181
183 182 def filename_and_mtime(self, module):
184 183 if not hasattr(module, '__file__') or module.__file__ is None:
185 184 return None, None
186 185
187 186 if getattr(module, '__name__', None) in [None, '__mp_main__', '__main__']:
188 187 # we cannot reload(__main__) or reload(__mp_main__)
189 188 return None, None
190 189
191 190 filename = module.__file__
192 191 path, ext = os.path.splitext(filename)
193 192
194 193 if ext.lower() == '.py':
195 194 py_filename = filename
196 195 else:
197 196 try:
198 py_filename = openpy.source_from_cache(filename)
197 py_filename = source_from_cache(filename)
199 198 except ValueError:
200 199 return None, None
201 200
202 201 try:
203 202 pymtime = os.stat(py_filename).st_mtime
204 203 except OSError:
205 204 return None, None
206 205
207 206 return py_filename, pymtime
208 207
209 208 def check(self, check_all=False, do_reload=True):
210 209 """Check whether some modules need to be reloaded."""
211 210
212 211 if not self.enabled and not check_all:
213 212 return
214 213
215 214 if check_all or self.check_all:
216 215 modules = list(sys.modules.keys())
217 216 else:
218 217 modules = list(self.modules.keys())
219 218
220 219 for modname in modules:
221 220 m = sys.modules.get(modname, None)
222 221
223 222 if modname in self.skip_modules:
224 223 continue
225 224
226 225 py_filename, pymtime = self.filename_and_mtime(m)
227 226 if py_filename is None:
228 227 continue
229 228
230 229 try:
231 230 if pymtime <= self.modules_mtimes[modname]:
232 231 continue
233 232 except KeyError:
234 233 self.modules_mtimes[modname] = pymtime
235 234 continue
236 235 else:
237 236 if self.failed.get(py_filename, None) == pymtime:
238 237 continue
239 238
240 239 self.modules_mtimes[modname] = pymtime
241 240
242 241 # If we've reached this point, we should try to reload the module
243 242 if do_reload:
244 243 try:
245 244 superreload(m, reload, self.old_objects)
246 245 if py_filename in self.failed:
247 246 del self.failed[py_filename]
248 247 except:
249 248 print("[autoreload of %s failed: %s]" % (
250 249 modname, traceback.format_exc(10)), file=sys.stderr)
251 250 self.failed[py_filename] = pymtime
252 251
253 252 #------------------------------------------------------------------------------
254 253 # superreload
255 254 #------------------------------------------------------------------------------
256 255
257 256
258 257 func_attrs = ['__code__', '__defaults__', '__doc__',
259 258 '__closure__', '__globals__', '__dict__']
260 259
261 260
262 261 def update_function(old, new):
263 262 """Upgrade the code object of a function"""
264 263 for name in func_attrs:
265 264 try:
266 265 setattr(old, name, getattr(new, name))
267 266 except (AttributeError, TypeError):
268 267 pass
269 268
270 269
271 270 def update_class(old, new):
272 271 """Replace stuff in the __dict__ of a class, and upgrade
273 272 method code objects"""
274 273 for key in list(old.__dict__.keys()):
275 274 old_obj = getattr(old, key)
276 275 try:
277 276 new_obj = getattr(new, key)
278 277 if old_obj == new_obj:
279 278 continue
280 279 except AttributeError:
281 280 # obsolete attribute: remove it
282 281 try:
283 282 delattr(old, key)
284 283 except (AttributeError, TypeError):
285 284 pass
286 285 continue
287 286
288 287 if update_generic(old_obj, new_obj): continue
289 288
290 289 try:
291 290 setattr(old, key, getattr(new, key))
292 291 except (AttributeError, TypeError):
293 292 pass # skip non-writable attributes
294 293
295 294
296 295 def update_property(old, new):
297 296 """Replace get/set/del functions of a property"""
298 297 update_generic(old.fdel, new.fdel)
299 298 update_generic(old.fget, new.fget)
300 299 update_generic(old.fset, new.fset)
301 300
302 301
303 302 def isinstance2(a, b, typ):
304 303 return isinstance(a, typ) and isinstance(b, typ)
305 304
306 305
307 306 UPDATE_RULES = [
308 307 (lambda a, b: isinstance2(a, b, type),
309 308 update_class),
310 309 (lambda a, b: isinstance2(a, b, types.FunctionType),
311 310 update_function),
312 311 (lambda a, b: isinstance2(a, b, property),
313 312 update_property),
314 313 ]
315 314 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
316 315 lambda a, b: update_function(a.__func__, b.__func__)),
317 316 ])
318 317
319 318
320 319 def update_generic(a, b):
321 320 for type_check, update in UPDATE_RULES:
322 321 if type_check(a, b):
323 322 update(a, b)
324 323 return True
325 324 return False
326 325
327 326
328 327 class StrongRef(object):
329 328 def __init__(self, obj):
330 329 self.obj = obj
331 330 def __call__(self):
332 331 return self.obj
333 332
334 333
335 334 def superreload(module, reload=reload, old_objects={}):
336 335 """Enhanced version of the builtin reload function.
337 336
338 337 superreload remembers objects previously in the module, and
339 338
340 339 - upgrades the class dictionary of every old class in the module
341 340 - upgrades the code object of every old function and method
342 341 - clears the module's namespace before reloading
343 342
344 343 """
345 344
346 345 # collect old objects in the module
347 346 for name, obj in list(module.__dict__.items()):
348 347 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
349 348 continue
350 349 key = (module.__name__, name)
351 350 try:
352 351 old_objects.setdefault(key, []).append(weakref.ref(obj))
353 352 except TypeError:
354 353 pass
355 354
356 355 # reload module
357 356 try:
358 357 # clear namespace first from old cruft
359 358 old_dict = module.__dict__.copy()
360 359 old_name = module.__name__
361 360 module.__dict__.clear()
362 361 module.__dict__['__name__'] = old_name
363 362 module.__dict__['__loader__'] = old_dict['__loader__']
364 363 except (TypeError, AttributeError, KeyError):
365 364 pass
366 365
367 366 try:
368 367 module = reload(module)
369 368 except:
370 369 # restore module dictionary on failed reload
371 370 module.__dict__.update(old_dict)
372 371 raise
373 372
374 373 # iterate over all objects and update functions & classes
375 374 for name, new_obj in list(module.__dict__.items()):
376 375 key = (module.__name__, name)
377 376 if key not in old_objects: continue
378 377
379 378 new_refs = []
380 379 for old_ref in old_objects[key]:
381 380 old_obj = old_ref()
382 381 if old_obj is None: continue
383 382 new_refs.append(old_ref)
384 383 update_generic(old_obj, new_obj)
385 384
386 385 if new_refs:
387 386 old_objects[key] = new_refs
388 387 else:
389 388 del old_objects[key]
390 389
391 390 return module
392 391
393 392 #------------------------------------------------------------------------------
394 393 # IPython connectivity
395 394 #------------------------------------------------------------------------------
396 395
397 396 from IPython.core.magic import Magics, magics_class, line_magic
398 397
399 398 @magics_class
400 399 class AutoreloadMagics(Magics):
401 400 def __init__(self, *a, **kw):
402 401 super(AutoreloadMagics, self).__init__(*a, **kw)
403 402 self._reloader = ModuleReloader()
404 403 self._reloader.check_all = False
405 404 self.loaded_modules = set(sys.modules)
406 405
407 406 @line_magic
408 407 def autoreload(self, parameter_s=''):
409 408 r"""%autoreload => Reload modules automatically
410 409
411 410 %autoreload
412 411 Reload all modules (except those excluded by %aimport) automatically
413 412 now.
414 413
415 414 %autoreload 0
416 415 Disable automatic reloading.
417 416
418 417 %autoreload 1
419 418 Reload all modules imported with %aimport every time before executing
420 419 the Python code typed.
421 420
422 421 %autoreload 2
423 422 Reload all modules (except those excluded by %aimport) every time
424 423 before executing the Python code typed.
425 424
426 425 Reloading Python modules in a reliable way is in general
427 426 difficult, and unexpected things may occur. %autoreload tries to
428 427 work around common pitfalls by replacing function code objects and
429 428 parts of classes previously in the module with new versions. This
430 429 makes the following things to work:
431 430
432 431 - Functions and classes imported via 'from xxx import foo' are upgraded
433 432 to new versions when 'xxx' is reloaded.
434 433
435 434 - Methods and properties of classes are upgraded on reload, so that
436 435 calling 'c.foo()' on an object 'c' created before the reload causes
437 436 the new code for 'foo' to be executed.
438 437
439 438 Some of the known remaining caveats are:
440 439
441 440 - Replacing code objects does not always succeed: changing a @property
442 441 in a class to an ordinary method or a method to a member variable
443 442 can cause problems (but in old objects only).
444 443
445 444 - Functions that are removed (eg. via monkey-patching) from a module
446 445 before it is reloaded are not upgraded.
447 446
448 447 - C extension modules cannot be reloaded, and so cannot be
449 448 autoreloaded.
450 449
451 450 """
452 451 if parameter_s == '':
453 452 self._reloader.check(True)
454 453 elif parameter_s == '0':
455 454 self._reloader.enabled = False
456 455 elif parameter_s == '1':
457 456 self._reloader.check_all = False
458 457 self._reloader.enabled = True
459 458 elif parameter_s == '2':
460 459 self._reloader.check_all = True
461 460 self._reloader.enabled = True
462 461
463 462 @line_magic
464 463 def aimport(self, parameter_s='', stream=None):
465 464 """%aimport => Import modules for automatic reloading.
466 465
467 466 %aimport
468 467 List modules to automatically import and not to import.
469 468
470 469 %aimport foo
471 470 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
472 471
473 472 %aimport foo, bar
474 473 Import modules 'foo', 'bar' and mark them to be autoreloaded for %autoreload 1
475 474
476 475 %aimport -foo
477 476 Mark module 'foo' to not be autoreloaded for %autoreload 1
478 477 """
479 478 modname = parameter_s
480 479 if not modname:
481 480 to_reload = sorted(self._reloader.modules.keys())
482 481 to_skip = sorted(self._reloader.skip_modules.keys())
483 482 if stream is None:
484 483 stream = sys.stdout
485 484 if self._reloader.check_all:
486 485 stream.write("Modules to reload:\nall-except-skipped\n")
487 486 else:
488 487 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
489 488 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
490 489 elif modname.startswith('-'):
491 490 modname = modname[1:]
492 491 self._reloader.mark_module_skipped(modname)
493 492 else:
494 493 for _module in ([_.strip() for _ in modname.split(',')]):
495 494 top_module, top_name = self._reloader.aimport_module(_module)
496 495
497 496 # Inject module to user namespace
498 497 self.shell.push({top_name: top_module})
499 498
500 499 def pre_run_cell(self):
501 500 if self._reloader.enabled:
502 501 try:
503 502 self._reloader.check()
504 503 except:
505 504 pass
506 505
507 506 def post_execute_hook(self):
508 507 """Cache the modification times of any modules imported in this execution
509 508 """
510 509 newly_loaded_modules = set(sys.modules) - self.loaded_modules
511 510 for modname in newly_loaded_modules:
512 511 _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname])
513 512 if pymtime is not None:
514 513 self._reloader.modules_mtimes[modname] = pymtime
515 514
516 515 self.loaded_modules.update(newly_loaded_modules)
517 516
518 517
519 518 def load_ipython_extension(ip):
520 519 """Load the extension in IPython."""
521 520 auto_reload = AutoreloadMagics(ip)
522 521 ip.register_magics(auto_reload)
523 522 ip.events.register('pre_run_cell', auto_reload.pre_run_cell)
524 523 ip.events.register('post_execute', auto_reload.post_execute_hook)
@@ -1,117 +1,105 b''
1 1 """
2 2 Tools to open .py files as Unicode, using the encoding specified within the file,
3 3 as per PEP 263.
4 4
5 5 Much of the code is taken from the tokenize module in Python 3.2.
6 6 """
7 7
8 8 import io
9 9 from io import TextIOWrapper, BytesIO
10 10 import re
11 11 from tokenize import open, detect_encoding
12 12
13 13 cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)", re.UNICODE)
14 14 cookie_comment_re = re.compile(r"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
15 15
16 16 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
17 17 """Converts a bytes string with python source code to unicode.
18 18
19 19 Unicode strings are passed through unchanged. Byte strings are checked
20 20 for the python source file encoding cookie to determine encoding.
21 21 txt can be either a bytes buffer or a string containing the source
22 22 code.
23 23 """
24 24 if isinstance(txt, str):
25 25 return txt
26 26 if isinstance(txt, bytes):
27 27 buffer = BytesIO(txt)
28 28 else:
29 29 buffer = txt
30 30 try:
31 31 encoding, _ = detect_encoding(buffer.readline)
32 32 except SyntaxError:
33 33 encoding = "ascii"
34 34 buffer.seek(0)
35 35 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
36 36 text.mode = 'r'
37 37 if skip_encoding_cookie:
38 38 return u"".join(strip_encoding_cookie(text))
39 39 else:
40 40 return text.read()
41 41
42 42 def strip_encoding_cookie(filelike):
43 43 """Generator to pull lines from a text-mode file, skipping the encoding
44 44 cookie if it is found in the first two lines.
45 45 """
46 46 it = iter(filelike)
47 47 try:
48 48 first = next(it)
49 49 if not cookie_comment_re.match(first):
50 50 yield first
51 51 second = next(it)
52 52 if not cookie_comment_re.match(second):
53 53 yield second
54 54 except StopIteration:
55 55 return
56 56
57 57 for line in it:
58 58 yield line
59 59
60 60 def read_py_file(filename, skip_encoding_cookie=True):
61 61 """Read a Python file, using the encoding declared inside the file.
62 62
63 63 Parameters
64 64 ----------
65 65 filename : str
66 66 The path to the file to read.
67 67 skip_encoding_cookie : bool
68 68 If True (the default), and the encoding declaration is found in the first
69 69 two lines, that line will be excluded from the output - compiling a
70 70 unicode string with an encoding declaration is a SyntaxError in Python 2.
71 71
72 72 Returns
73 73 -------
74 74 A unicode string containing the contents of the file.
75 75 """
76 76 with open(filename) as f: # the open function defined in this module.
77 77 if skip_encoding_cookie:
78 78 return "".join(strip_encoding_cookie(f))
79 79 else:
80 80 return f.read()
81 81
82 82 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
83 83 """Read a Python file from a URL, using the encoding declared inside the file.
84 84
85 85 Parameters
86 86 ----------
87 87 url : str
88 88 The URL from which to fetch the file.
89 89 errors : str
90 90 How to handle decoding errors in the file. Options are the same as for
91 91 bytes.decode(), but here 'replace' is the default.
92 92 skip_encoding_cookie : bool
93 93 If True (the default), and the encoding declaration is found in the first
94 94 two lines, that line will be excluded from the output - compiling a
95 95 unicode string with an encoding declaration is a SyntaxError in Python 2.
96 96
97 97 Returns
98 98 -------
99 99 A unicode string containing the contents of the file.
100 100 """
101 101 # Deferred import for faster start
102 102 from urllib.request import urlopen
103 103 response = urlopen(url)
104 104 buffer = io.BytesIO(response.read())
105 105 return source_to_unicode(buffer, errors, skip_encoding_cookie)
106
107 def _list_readline(x):
108 """Given a list, returns a readline() function that returns the next element
109 with each call.
110 """
111 x = iter(x)
112 def readline():
113 return next(x)
114 return readline
115
116 # Code for going between .py files and cached .pyc files ----------------------
117 from importlib.util import source_from_cache, cache_from_source
@@ -1,39 +1,31 b''
1 1 import io
2 2 import os.path
3 3 import nose.tools as nt
4 4
5 5 from IPython.utils import openpy
6 6
7 7 mydir = os.path.dirname(__file__)
8 8 nonascii_path = os.path.join(mydir, '../../core/tests/nonascii.py')
9 9
10 10 def test_detect_encoding():
11 11 f = open(nonascii_path, 'rb')
12 12 enc, lines = openpy.detect_encoding(f.readline)
13 13 nt.assert_equal(enc, 'iso-8859-5')
14 14
15 15 def test_read_file():
16 16 read_specified_enc = io.open(nonascii_path, encoding='iso-8859-5').read()
17 17 read_detected_enc = openpy.read_py_file(nonascii_path, skip_encoding_cookie=False)
18 18 nt.assert_equal(read_detected_enc, read_specified_enc)
19 19 assert u'coding: iso-8859-5' in read_detected_enc
20 20
21 21 read_strip_enc_cookie = openpy.read_py_file(nonascii_path, skip_encoding_cookie=True)
22 22 assert u'coding: iso-8859-5' not in read_strip_enc_cookie
23 23
24 24 def test_source_to_unicode():
25 25 with io.open(nonascii_path, 'rb') as f:
26 26 source_bytes = f.read()
27 27 nt.assert_equal(openpy.source_to_unicode(source_bytes, skip_encoding_cookie=False).splitlines(),
28 28 source_bytes.decode('iso-8859-5').splitlines())
29 29
30 30 source_no_cookie = openpy.source_to_unicode(source_bytes, skip_encoding_cookie=True)
31 31 nt.assert_not_in(u'coding: iso-8859-5', source_no_cookie)
32
33 def test_list_readline():
34 l = ['a', 'b']
35 readline = openpy._list_readline(l)
36 nt.assert_equal(readline(), 'a')
37 nt.assert_equal(readline(), 'b')
38 with nt.assert_raises(StopIteration):
39 readline() No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now