##// END OF EJS Templates
Deprecate io.{stdout,stderr} and shell.{write,write_err}...
Thomas Kluyver -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,637 +1,637 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 http://www.python.org/2.2.3/license.html"""
17 17
18 18 #*****************************************************************************
19 19 #
20 20 # This file is licensed under the PSF license.
21 21 #
22 22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 24 #
25 25 #
26 26 #*****************************************************************************
27 27 from __future__ import print_function
28 28
29 29 import bdb
30 30 import functools
31 31 import inspect
32 32 import sys
33 33
34 34 from IPython import get_ipython
35 35 from IPython.utils import PyColorize, ulinecache
36 from IPython.utils import coloransi, io, py3compat
36 from IPython.utils import coloransi, py3compat
37 37 from IPython.core.excolors import exception_colors
38 38 from IPython.testing.skipdoctest import skip_doctest
39 39
40 40 # See if we can use pydb.
41 41 has_pydb = False
42 42 prompt = 'ipdb> '
43 43 #We have to check this directly from sys.argv, config struct not yet available
44 44 if '--pydb' in sys.argv:
45 45 try:
46 46 import pydb
47 47 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
48 48 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
49 49 # better protect against it.
50 50 has_pydb = True
51 51 except ImportError:
52 52 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
53 53
54 54 if has_pydb:
55 55 from pydb import Pdb as OldPdb
56 56 prompt = 'ipydb> '
57 57 else:
58 58 from pdb import Pdb as OldPdb
59 59
60 60 # Allow the set_trace code to operate outside of an ipython instance, even if
61 61 # it does so with some limitations. The rest of this support is implemented in
62 62 # the Tracer constructor.
63 63
64 64 def make_arrow(pad):
65 65 """generate the leading arrow in front of traceback or debugger"""
66 66 if pad >= 2:
67 67 return '-'*(pad-2) + '> '
68 68 elif pad == 1:
69 69 return '>'
70 70 return ''
71 71
72 72
73 73 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
74 74 """Exception hook which handles `BdbQuit` exceptions.
75 75
76 76 All other exceptions are processed using the `excepthook`
77 77 parameter.
78 78 """
79 79 if et==bdb.BdbQuit:
80 80 print('Exiting Debugger.')
81 81 elif excepthook is not None:
82 82 excepthook(et, ev, tb)
83 83 else:
84 84 # Backwards compatibility. Raise deprecation warning?
85 85 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
86 86
87 87 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
88 88 print('Exiting Debugger.')
89 89
90 90
91 91 class Tracer(object):
92 92 """Class for local debugging, similar to pdb.set_trace.
93 93
94 94 Instances of this class, when called, behave like pdb.set_trace, but
95 95 providing IPython's enhanced capabilities.
96 96
97 97 This is implemented as a class which must be initialized in your own code
98 98 and not as a standalone function because we need to detect at runtime
99 99 whether IPython is already active or not. That detection is done in the
100 100 constructor, ensuring that this code plays nicely with a running IPython,
101 101 while functioning acceptably (though with limitations) if outside of it.
102 102 """
103 103
104 104 @skip_doctest
105 105 def __init__(self, colors=None):
106 106 """Create a local debugger instance.
107 107
108 108 Parameters
109 109 ----------
110 110
111 111 colors : str, optional
112 112 The name of the color scheme to use, it must be one of IPython's
113 113 valid color schemes. If not given, the function will default to
114 114 the current IPython scheme when running inside IPython, and to
115 115 'NoColor' otherwise.
116 116
117 117 Examples
118 118 --------
119 119 ::
120 120
121 121 from IPython.core.debugger import Tracer; debug_here = Tracer()
122 122
123 123 Later in your code::
124 124
125 125 debug_here() # -> will open up the debugger at that point.
126 126
127 127 Once the debugger activates, you can use all of its regular commands to
128 128 step through code, set breakpoints, etc. See the pdb documentation
129 129 from the Python standard library for usage details.
130 130 """
131 131
132 132 ip = get_ipython()
133 133 if ip is None:
134 134 # Outside of ipython, we set our own exception hook manually
135 135 sys.excepthook = functools.partial(BdbQuit_excepthook,
136 136 excepthook=sys.excepthook)
137 137 def_colors = 'NoColor'
138 138 try:
139 139 # Limited tab completion support
140 140 import readline
141 141 readline.parse_and_bind('tab: complete')
142 142 except ImportError:
143 143 pass
144 144 else:
145 145 # In ipython, we use its custom exception handler mechanism
146 146 def_colors = ip.colors
147 147 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
148 148
149 149 if colors is None:
150 150 colors = def_colors
151 151
152 152 # The stdlib debugger internally uses a modified repr from the `repr`
153 153 # module, that limits the length of printed strings to a hardcoded
154 154 # limit of 30 characters. That much trimming is too aggressive, let's
155 155 # at least raise that limit to 80 chars, which should be enough for
156 156 # most interactive uses.
157 157 try:
158 158 try:
159 159 from reprlib import aRepr # Py 3
160 160 except ImportError:
161 161 from repr import aRepr # Py 2
162 162 aRepr.maxstring = 80
163 163 except:
164 164 # This is only a user-facing convenience, so any error we encounter
165 165 # here can be warned about but can be otherwise ignored. These
166 166 # printouts will tell us about problems if this API changes
167 167 import traceback
168 168 traceback.print_exc()
169 169
170 170 self.debugger = Pdb(colors)
171 171
172 172 def __call__(self):
173 173 """Starts an interactive debugger at the point where called.
174 174
175 175 This is similar to the pdb.set_trace() function from the std lib, but
176 176 using IPython's enhanced debugger."""
177 177
178 178 self.debugger.set_trace(sys._getframe().f_back)
179 179
180 180
181 181 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
182 182 """Make new_fn have old_fn's doc string. This is particularly useful
183 183 for the ``do_...`` commands that hook into the help system.
184 184 Adapted from from a comp.lang.python posting
185 185 by Duncan Booth."""
186 186 def wrapper(*args, **kw):
187 187 return new_fn(*args, **kw)
188 188 if old_fn.__doc__:
189 189 wrapper.__doc__ = old_fn.__doc__ + additional_text
190 190 return wrapper
191 191
192 192
193 193 def _file_lines(fname):
194 194 """Return the contents of a named file as a list of lines.
195 195
196 196 This function never raises an IOError exception: if the file can't be
197 197 read, it simply returns an empty list."""
198 198
199 199 try:
200 200 outfile = open(fname)
201 201 except IOError:
202 202 return []
203 203 else:
204 204 out = outfile.readlines()
205 205 outfile.close()
206 206 return out
207 207
208 208
209 209 class Pdb(OldPdb):
210 210 """Modified Pdb class, does not load readline."""
211 211
212 212 def __init__(self,color_scheme='NoColor',completekey=None,
213 213 stdin=None, stdout=None, context=5):
214 214
215 215 # Parent constructor:
216 216 try:
217 217 self.context=int(context)
218 218 if self.context <= 0:
219 219 raise ValueError("Context must be a positive integer")
220 220 except (TypeError, ValueError):
221 221 raise ValueError("Context must be a positive integer")
222 222
223 223 if has_pydb and completekey is None:
224 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
224 OldPdb.__init__(self,stdin=stdin,stdout=sys.stdout)
225 225 else:
226 226 OldPdb.__init__(self,completekey,stdin,stdout)
227 227
228 228 # IPython changes...
229 229 self.is_pydb = has_pydb
230 230
231 231 self.shell = get_ipython()
232 232
233 233 if self.shell is None:
234 234 # No IPython instance running, we must create one
235 235 from IPython.terminal.interactiveshell import \
236 236 TerminalInteractiveShell
237 237 self.shell = TerminalInteractiveShell.instance()
238 238
239 239 if self.is_pydb:
240 240
241 241 # interactiveshell.py's ipalias seems to want pdb's checkline
242 242 # which located in pydb.fn
243 243 import pydb.fns
244 244 self.checkline = lambda filename, lineno: \
245 245 pydb.fns.checkline(self, filename, lineno)
246 246
247 247 self.curframe = None
248 248 self.do_restart = self.new_do_restart
249 249
250 250 self.old_all_completions = self.shell.Completer.all_completions
251 251 self.shell.Completer.all_completions=self.all_completions
252 252
253 253 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
254 254 OldPdb.do_list)
255 255 self.do_l = self.do_list
256 256 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
257 257 OldPdb.do_frame)
258 258
259 259 self.aliases = {}
260 260
261 261 # Create color table: we copy the default one from the traceback
262 262 # module and add a few attributes needed for debugging
263 263 self.color_scheme_table = exception_colors()
264 264
265 265 # shorthands
266 266 C = coloransi.TermColors
267 267 cst = self.color_scheme_table
268 268
269 269 cst['NoColor'].colors.prompt = C.NoColor
270 270 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
271 271 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
272 272
273 273 cst['Linux'].colors.prompt = C.Green
274 274 cst['Linux'].colors.breakpoint_enabled = C.LightRed
275 275 cst['Linux'].colors.breakpoint_disabled = C.Red
276 276
277 277 cst['LightBG'].colors.prompt = C.Blue
278 278 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
279 279 cst['LightBG'].colors.breakpoint_disabled = C.Red
280 280
281 281 self.set_colors(color_scheme)
282 282
283 283 # Add a python parser so we can syntax highlight source while
284 284 # debugging.
285 285 self.parser = PyColorize.Parser()
286 286
287 287 # Set the prompt - the default prompt is '(Pdb)'
288 288 Colors = cst.active_colors
289 289 if color_scheme == 'NoColor':
290 290 self.prompt = prompt
291 291 else:
292 292 # The colour markers are wrapped by bytes 01 and 02 so that readline
293 293 # can calculate the width.
294 294 self.prompt = u'\x01%s\x02%s\x01%s\x02' % (Colors.prompt, prompt, Colors.Normal)
295 295
296 296 def set_colors(self, scheme):
297 297 """Shorthand access to the color table scheme selector method."""
298 298 self.color_scheme_table.set_active_scheme(scheme)
299 299
300 300 def interaction(self, frame, traceback):
301 301 self.shell.set_completer_frame(frame)
302 302 while True:
303 303 try:
304 304 OldPdb.interaction(self, frame, traceback)
305 305 break
306 306 except KeyboardInterrupt:
307 307 self.shell.write('\n' + self.shell.get_exception_only())
308 308 break
309 309 finally:
310 310 # Pdb sets readline delimiters, so set them back to our own
311 311 if self.shell.readline is not None:
312 312 self.shell.readline.set_completer_delims(self.shell.readline_delims)
313 313
314 314 def new_do_up(self, arg):
315 315 OldPdb.do_up(self, arg)
316 316 self.shell.set_completer_frame(self.curframe)
317 317 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
318 318
319 319 def new_do_down(self, arg):
320 320 OldPdb.do_down(self, arg)
321 321 self.shell.set_completer_frame(self.curframe)
322 322
323 323 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
324 324
325 325 def new_do_frame(self, arg):
326 326 OldPdb.do_frame(self, arg)
327 327 self.shell.set_completer_frame(self.curframe)
328 328
329 329 def new_do_quit(self, arg):
330 330
331 331 if hasattr(self, 'old_all_completions'):
332 332 self.shell.Completer.all_completions=self.old_all_completions
333 333
334 334 return OldPdb.do_quit(self, arg)
335 335
336 336 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
337 337
338 338 def new_do_restart(self, arg):
339 339 """Restart command. In the context of ipython this is exactly the same
340 340 thing as 'quit'."""
341 341 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
342 342 return self.do_quit(arg)
343 343
344 344 def postloop(self):
345 345 self.shell.set_completer_frame(None)
346 346
347 347 def print_stack_trace(self, context=None):
348 348 if context is None:
349 349 context = self.context
350 350 try:
351 351 context=int(context)
352 352 if context <= 0:
353 353 raise ValueError("Context must be a positive integer")
354 354 except (TypeError, ValueError):
355 355 raise ValueError("Context must be a positive integer")
356 356 try:
357 357 for frame_lineno in self.stack:
358 358 self.print_stack_entry(frame_lineno, context=context)
359 359 except KeyboardInterrupt:
360 360 pass
361 361
362 362 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
363 363 context=None):
364 364 if context is None:
365 365 context = self.context
366 366 try:
367 367 context=int(context)
368 368 if context <= 0:
369 369 raise ValueError("Context must be a positive integer")
370 370 except (TypeError, ValueError):
371 371 raise ValueError("Context must be a positive integer")
372 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
372 print(self.format_stack_entry(frame_lineno, '', context))
373 373
374 374 # vds: >>
375 375 frame, lineno = frame_lineno
376 376 filename = frame.f_code.co_filename
377 377 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
378 378 # vds: <<
379 379
380 380 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
381 381 if context is None:
382 382 context = self.context
383 383 try:
384 384 context=int(context)
385 385 if context <= 0:
386 386 print("Context must be a positive integer")
387 387 except (TypeError, ValueError):
388 388 print("Context must be a positive integer")
389 389 try:
390 390 import reprlib # Py 3
391 391 except ImportError:
392 392 import repr as reprlib # Py 2
393 393
394 394 ret = []
395 395
396 396 Colors = self.color_scheme_table.active_colors
397 397 ColorsNormal = Colors.Normal
398 398 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
399 399 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
400 400 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
401 401 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
402 402 ColorsNormal)
403 403
404 404 frame, lineno = frame_lineno
405 405
406 406 return_value = ''
407 407 if '__return__' in frame.f_locals:
408 408 rv = frame.f_locals['__return__']
409 409 #return_value += '->'
410 410 return_value += reprlib.repr(rv) + '\n'
411 411 ret.append(return_value)
412 412
413 413 #s = filename + '(' + `lineno` + ')'
414 414 filename = self.canonic(frame.f_code.co_filename)
415 415 link = tpl_link % py3compat.cast_unicode(filename)
416 416
417 417 if frame.f_code.co_name:
418 418 func = frame.f_code.co_name
419 419 else:
420 420 func = "<lambda>"
421 421
422 422 call = ''
423 423 if func != '?':
424 424 if '__args__' in frame.f_locals:
425 425 args = reprlib.repr(frame.f_locals['__args__'])
426 426 else:
427 427 args = '()'
428 428 call = tpl_call % (func, args)
429 429
430 430 # The level info should be generated in the same format pdb uses, to
431 431 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
432 432 if frame is self.curframe:
433 433 ret.append('> ')
434 434 else:
435 435 ret.append(' ')
436 436 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
437 437
438 438 start = lineno - 1 - context//2
439 439 lines = ulinecache.getlines(filename)
440 440 start = min(start, len(lines) - context)
441 441 start = max(start, 0)
442 442 lines = lines[start : start + context]
443 443
444 444 for i,line in enumerate(lines):
445 445 show_arrow = (start + 1 + i == lineno)
446 446 linetpl = (frame is self.curframe or show_arrow) \
447 447 and tpl_line_em \
448 448 or tpl_line
449 449 ret.append(self.__format_line(linetpl, filename,
450 450 start + 1 + i, line,
451 451 arrow = show_arrow) )
452 452 return ''.join(ret)
453 453
454 454 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
455 455 bp_mark = ""
456 456 bp_mark_color = ""
457 457
458 458 scheme = self.color_scheme_table.active_scheme_name
459 459 new_line, err = self.parser.format2(line, 'str', scheme)
460 460 if not err: line = new_line
461 461
462 462 bp = None
463 463 if lineno in self.get_file_breaks(filename):
464 464 bps = self.get_breaks(filename, lineno)
465 465 bp = bps[-1]
466 466
467 467 if bp:
468 468 Colors = self.color_scheme_table.active_colors
469 469 bp_mark = str(bp.number)
470 470 bp_mark_color = Colors.breakpoint_enabled
471 471 if not bp.enabled:
472 472 bp_mark_color = Colors.breakpoint_disabled
473 473
474 474 numbers_width = 7
475 475 if arrow:
476 476 # This is the line with the error
477 477 pad = numbers_width - len(str(lineno)) - len(bp_mark)
478 478 num = '%s%s' % (make_arrow(pad), str(lineno))
479 479 else:
480 480 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
481 481
482 482 return tpl_line % (bp_mark_color + bp_mark, num, line)
483 483
484 484
485 485 def list_command_pydb(self, arg):
486 486 """List command to use if we have a newer pydb installed"""
487 487 filename, first, last = OldPdb.parse_list_cmd(self, arg)
488 488 if filename is not None:
489 489 self.print_list_lines(filename, first, last)
490 490
491 491 def print_list_lines(self, filename, first, last):
492 492 """The printing (as opposed to the parsing part of a 'list'
493 493 command."""
494 494 try:
495 495 Colors = self.color_scheme_table.active_colors
496 496 ColorsNormal = Colors.Normal
497 497 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
498 498 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
499 499 src = []
500 500 if filename == "<string>" and hasattr(self, "_exec_filename"):
501 501 filename = self._exec_filename
502 502
503 503 for lineno in range(first, last+1):
504 504 line = ulinecache.getline(filename, lineno)
505 505 if not line:
506 506 break
507 507
508 508 if lineno == self.curframe.f_lineno:
509 509 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
510 510 else:
511 511 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
512 512
513 513 src.append(line)
514 514 self.lineno = lineno
515 515
516 print(''.join(src), file=io.stdout)
516 print(''.join(src))
517 517
518 518 except KeyboardInterrupt:
519 519 pass
520 520
521 521 def do_list(self, arg):
522 522 self.lastcmd = 'list'
523 523 last = None
524 524 if arg:
525 525 try:
526 526 x = eval(arg, {}, {})
527 527 if type(x) == type(()):
528 528 first, last = x
529 529 first = int(first)
530 530 last = int(last)
531 531 if last < first:
532 532 # Assume it's a count
533 533 last = first + last
534 534 else:
535 535 first = max(1, int(x) - 5)
536 536 except:
537 537 print('*** Error in argument:', repr(arg))
538 538 return
539 539 elif self.lineno is None:
540 540 first = max(1, self.curframe.f_lineno - 5)
541 541 else:
542 542 first = self.lineno + 1
543 543 if last is None:
544 544 last = first + 10
545 545 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
546 546
547 547 # vds: >>
548 548 lineno = first
549 549 filename = self.curframe.f_code.co_filename
550 550 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
551 551 # vds: <<
552 552
553 553 do_l = do_list
554 554
555 555 def getsourcelines(self, obj):
556 556 lines, lineno = inspect.findsource(obj)
557 557 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
558 558 # must be a module frame: do not try to cut a block out of it
559 559 return lines, 1
560 560 elif inspect.ismodule(obj):
561 561 return lines, 1
562 562 return inspect.getblock(lines[lineno:]), lineno+1
563 563
564 564 def do_longlist(self, arg):
565 565 self.lastcmd = 'longlist'
566 566 try:
567 567 lines, lineno = self.getsourcelines(self.curframe)
568 568 except OSError as err:
569 569 self.error(err)
570 570 return
571 571 last = lineno + len(lines)
572 572 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
573 573 do_ll = do_longlist
574 574
575 575 def do_pdef(self, arg):
576 576 """Print the call signature for any callable object.
577 577
578 578 The debugger interface to %pdef"""
579 579 namespaces = [('Locals', self.curframe.f_locals),
580 580 ('Globals', self.curframe.f_globals)]
581 581 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
582 582
583 583 def do_pdoc(self, arg):
584 584 """Print the docstring for an object.
585 585
586 586 The debugger interface to %pdoc."""
587 587 namespaces = [('Locals', self.curframe.f_locals),
588 588 ('Globals', self.curframe.f_globals)]
589 589 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
590 590
591 591 def do_pfile(self, arg):
592 592 """Print (or run through pager) the file where an object is defined.
593 593
594 594 The debugger interface to %pfile.
595 595 """
596 596 namespaces = [('Locals', self.curframe.f_locals),
597 597 ('Globals', self.curframe.f_globals)]
598 598 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
599 599
600 600 def do_pinfo(self, arg):
601 601 """Provide detailed information about an object.
602 602
603 603 The debugger interface to %pinfo, i.e., obj?."""
604 604 namespaces = [('Locals', self.curframe.f_locals),
605 605 ('Globals', self.curframe.f_globals)]
606 606 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
607 607
608 608 def do_pinfo2(self, arg):
609 609 """Provide extra detailed information about an object.
610 610
611 611 The debugger interface to %pinfo2, i.e., obj??."""
612 612 namespaces = [('Locals', self.curframe.f_locals),
613 613 ('Globals', self.curframe.f_globals)]
614 614 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
615 615
616 616 def do_psource(self, arg):
617 617 """Print (or run through pager) the source code for an object."""
618 618 namespaces = [('Locals', self.curframe.f_locals),
619 619 ('Globals', self.curframe.f_globals)]
620 620 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
621 621
622 622 if sys.version_info > (3, ):
623 623 def do_where(self, arg):
624 624 """w(here)
625 625 Print a stack trace, with the most recent frame at the bottom.
626 626 An arrow indicates the "current frame", which determines the
627 627 context of most commands. 'bt' is an alias for this command.
628 628
629 629 Take a number as argument as an (optional) number of context line to
630 630 print"""
631 631 if arg:
632 632 context = int(arg)
633 633 self.print_stack_trace(context)
634 634 else:
635 635 self.print_stack_trace()
636 636
637 637 do_w = do_where
@@ -1,1004 +1,1004 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from __future__ import print_function
8 8
9 9 try:
10 10 from base64 import encodebytes as base64_encode
11 11 except ImportError:
12 12 from base64 import encodestring as base64_encode
13 13
14 14 import json
15 15 import mimetypes
16 16 import os
17 17 import struct
18 import sys
18 19 import warnings
19 20
20 21 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
21 22 unicode_type)
22 23 from IPython.testing.skipdoctest import skip_doctest
23 24
24 25 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 26 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 27 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 28 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
28 29 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 30 'publish_display_data']
30 31
31 32 #-----------------------------------------------------------------------------
32 33 # utility functions
33 34 #-----------------------------------------------------------------------------
34 35
35 36 def _safe_exists(path):
36 37 """Check path, but don't let exceptions raise"""
37 38 try:
38 39 return os.path.exists(path)
39 40 except Exception:
40 41 return False
41 42
42 43 def _merge(d1, d2):
43 44 """Like update, but merges sub-dicts instead of clobbering at the top level.
44 45
45 46 Updates d1 in-place
46 47 """
47 48
48 49 if not isinstance(d2, dict) or not isinstance(d1, dict):
49 50 return d2
50 51 for key, value in d2.items():
51 52 d1[key] = _merge(d1.get(key), value)
52 53 return d1
53 54
54 55 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
55 56 """internal implementation of all display_foo methods
56 57
57 58 Parameters
58 59 ----------
59 60 mimetype : str
60 61 The mimetype to be published (e.g. 'image/png')
61 62 objs : tuple of objects
62 63 The Python objects to display, or if raw=True raw text data to
63 64 display.
64 65 raw : bool
65 66 Are the data objects raw data or Python objects that need to be
66 67 formatted before display? [default: False]
67 68 metadata : dict (optional)
68 69 Metadata to be associated with the specific mimetype output.
69 70 """
70 71 if metadata:
71 72 metadata = {mimetype: metadata}
72 73 if raw:
73 74 # turn list of pngdata into list of { 'image/png': pngdata }
74 75 objs = [ {mimetype: obj} for obj in objs ]
75 76 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
76 77
77 78 #-----------------------------------------------------------------------------
78 79 # Main functions
79 80 #-----------------------------------------------------------------------------
80 81
81 82 def publish_display_data(data, metadata=None, source=None):
82 83 """Publish data and metadata to all frontends.
83 84
84 85 See the ``display_data`` message in the messaging documentation for
85 86 more details about this message type.
86 87
87 88 The following MIME types are currently implemented:
88 89
89 90 * text/plain
90 91 * text/html
91 92 * text/markdown
92 93 * text/latex
93 94 * application/json
94 95 * application/javascript
95 96 * image/png
96 97 * image/jpeg
97 98 * image/svg+xml
98 99
99 100 Parameters
100 101 ----------
101 102 data : dict
102 103 A dictionary having keys that are valid MIME types (like
103 104 'text/plain' or 'image/svg+xml') and values that are the data for
104 105 that MIME type. The data itself must be a JSON'able data
105 106 structure. Minimally all data should have the 'text/plain' data,
106 107 which can be displayed by all frontends. If more than the plain
107 108 text is given, it is up to the frontend to decide which
108 109 representation to use.
109 110 metadata : dict
110 111 A dictionary for metadata related to the data. This can contain
111 112 arbitrary key, value pairs that frontends can use to interpret
112 113 the data. mime-type keys matching those in data can be used
113 114 to specify metadata about particular representations.
114 115 source : str, deprecated
115 116 Unused.
116 117 """
117 118 from IPython.core.interactiveshell import InteractiveShell
118 119 InteractiveShell.instance().display_pub.publish(
119 120 data=data,
120 121 metadata=metadata,
121 122 )
122 123
123 124 def display(*objs, **kwargs):
124 125 """Display a Python object in all frontends.
125 126
126 127 By default all representations will be computed and sent to the frontends.
127 128 Frontends can decide which representation is used and how.
128 129
129 130 Parameters
130 131 ----------
131 132 objs : tuple of objects
132 133 The Python objects to display.
133 134 raw : bool, optional
134 135 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
135 136 or Python objects that need to be formatted before display? [default: False]
136 137 include : list or tuple, optional
137 138 A list of format type strings (MIME types) to include in the
138 139 format data dict. If this is set *only* the format types included
139 140 in this list will be computed.
140 141 exclude : list or tuple, optional
141 142 A list of format type strings (MIME types) to exclude in the format
142 143 data dict. If this is set all format types will be computed,
143 144 except for those included in this argument.
144 145 metadata : dict, optional
145 146 A dictionary of metadata to associate with the output.
146 147 mime-type keys in this dictionary will be associated with the individual
147 148 representation formats, if they exist.
148 149 """
149 150 raw = kwargs.get('raw', False)
150 151 include = kwargs.get('include')
151 152 exclude = kwargs.get('exclude')
152 153 metadata = kwargs.get('metadata')
153 154
154 155 from IPython.core.interactiveshell import InteractiveShell
155 156
156 157 if not raw:
157 158 format = InteractiveShell.instance().display_formatter.format
158 159
159 160 for obj in objs:
160 161 if raw:
161 162 publish_display_data(data=obj, metadata=metadata)
162 163 else:
163 164 format_dict, md_dict = format(obj, include=include, exclude=exclude)
164 165 if not format_dict:
165 166 # nothing to display (e.g. _ipython_display_ took over)
166 167 continue
167 168 if metadata:
168 169 # kwarg-specified metadata gets precedence
169 170 _merge(md_dict, metadata)
170 171 publish_display_data(data=format_dict, metadata=md_dict)
171 172
172 173
173 174 def display_pretty(*objs, **kwargs):
174 175 """Display the pretty (default) representation of an object.
175 176
176 177 Parameters
177 178 ----------
178 179 objs : tuple of objects
179 180 The Python objects to display, or if raw=True raw text data to
180 181 display.
181 182 raw : bool
182 183 Are the data objects raw data or Python objects that need to be
183 184 formatted before display? [default: False]
184 185 metadata : dict (optional)
185 186 Metadata to be associated with the specific mimetype output.
186 187 """
187 188 _display_mimetype('text/plain', objs, **kwargs)
188 189
189 190
190 191 def display_html(*objs, **kwargs):
191 192 """Display the HTML representation of an object.
192 193
193 194 Note: If raw=False and the object does not have a HTML
194 195 representation, no HTML will be shown.
195 196
196 197 Parameters
197 198 ----------
198 199 objs : tuple of objects
199 200 The Python objects to display, or if raw=True raw HTML data to
200 201 display.
201 202 raw : bool
202 203 Are the data objects raw data or Python objects that need to be
203 204 formatted before display? [default: False]
204 205 metadata : dict (optional)
205 206 Metadata to be associated with the specific mimetype output.
206 207 """
207 208 _display_mimetype('text/html', objs, **kwargs)
208 209
209 210
210 211 def display_markdown(*objs, **kwargs):
211 212 """Displays the Markdown representation of an object.
212 213
213 214 Parameters
214 215 ----------
215 216 objs : tuple of objects
216 217 The Python objects to display, or if raw=True raw markdown data to
217 218 display.
218 219 raw : bool
219 220 Are the data objects raw data or Python objects that need to be
220 221 formatted before display? [default: False]
221 222 metadata : dict (optional)
222 223 Metadata to be associated with the specific mimetype output.
223 224 """
224 225
225 226 _display_mimetype('text/markdown', objs, **kwargs)
226 227
227 228
228 229 def display_svg(*objs, **kwargs):
229 230 """Display the SVG representation of an object.
230 231
231 232 Parameters
232 233 ----------
233 234 objs : tuple of objects
234 235 The Python objects to display, or if raw=True raw svg data to
235 236 display.
236 237 raw : bool
237 238 Are the data objects raw data or Python objects that need to be
238 239 formatted before display? [default: False]
239 240 metadata : dict (optional)
240 241 Metadata to be associated with the specific mimetype output.
241 242 """
242 243 _display_mimetype('image/svg+xml', objs, **kwargs)
243 244
244 245
245 246 def display_png(*objs, **kwargs):
246 247 """Display the PNG representation of an object.
247 248
248 249 Parameters
249 250 ----------
250 251 objs : tuple of objects
251 252 The Python objects to display, or if raw=True raw png data to
252 253 display.
253 254 raw : bool
254 255 Are the data objects raw data or Python objects that need to be
255 256 formatted before display? [default: False]
256 257 metadata : dict (optional)
257 258 Metadata to be associated with the specific mimetype output.
258 259 """
259 260 _display_mimetype('image/png', objs, **kwargs)
260 261
261 262
262 263 def display_jpeg(*objs, **kwargs):
263 264 """Display the JPEG representation of an object.
264 265
265 266 Parameters
266 267 ----------
267 268 objs : tuple of objects
268 269 The Python objects to display, or if raw=True raw JPEG data to
269 270 display.
270 271 raw : bool
271 272 Are the data objects raw data or Python objects that need to be
272 273 formatted before display? [default: False]
273 274 metadata : dict (optional)
274 275 Metadata to be associated with the specific mimetype output.
275 276 """
276 277 _display_mimetype('image/jpeg', objs, **kwargs)
277 278
278 279
279 280 def display_latex(*objs, **kwargs):
280 281 """Display the LaTeX representation of an object.
281 282
282 283 Parameters
283 284 ----------
284 285 objs : tuple of objects
285 286 The Python objects to display, or if raw=True raw latex data to
286 287 display.
287 288 raw : bool
288 289 Are the data objects raw data or Python objects that need to be
289 290 formatted before display? [default: False]
290 291 metadata : dict (optional)
291 292 Metadata to be associated with the specific mimetype output.
292 293 """
293 294 _display_mimetype('text/latex', objs, **kwargs)
294 295
295 296
296 297 def display_json(*objs, **kwargs):
297 298 """Display the JSON representation of an object.
298 299
299 300 Note that not many frontends support displaying JSON.
300 301
301 302 Parameters
302 303 ----------
303 304 objs : tuple of objects
304 305 The Python objects to display, or if raw=True raw json data to
305 306 display.
306 307 raw : bool
307 308 Are the data objects raw data or Python objects that need to be
308 309 formatted before display? [default: False]
309 310 metadata : dict (optional)
310 311 Metadata to be associated with the specific mimetype output.
311 312 """
312 313 _display_mimetype('application/json', objs, **kwargs)
313 314
314 315
315 316 def display_javascript(*objs, **kwargs):
316 317 """Display the Javascript representation of an object.
317 318
318 319 Parameters
319 320 ----------
320 321 objs : tuple of objects
321 322 The Python objects to display, or if raw=True raw javascript data to
322 323 display.
323 324 raw : bool
324 325 Are the data objects raw data or Python objects that need to be
325 326 formatted before display? [default: False]
326 327 metadata : dict (optional)
327 328 Metadata to be associated with the specific mimetype output.
328 329 """
329 330 _display_mimetype('application/javascript', objs, **kwargs)
330 331
331 332
332 333 def display_pdf(*objs, **kwargs):
333 334 """Display the PDF representation of an object.
334 335
335 336 Parameters
336 337 ----------
337 338 objs : tuple of objects
338 339 The Python objects to display, or if raw=True raw javascript data to
339 340 display.
340 341 raw : bool
341 342 Are the data objects raw data or Python objects that need to be
342 343 formatted before display? [default: False]
343 344 metadata : dict (optional)
344 345 Metadata to be associated with the specific mimetype output.
345 346 """
346 347 _display_mimetype('application/pdf', objs, **kwargs)
347 348
348 349
349 350 #-----------------------------------------------------------------------------
350 351 # Smart classes
351 352 #-----------------------------------------------------------------------------
352 353
353 354
354 355 class DisplayObject(object):
355 356 """An object that wraps data to be displayed."""
356 357
357 358 _read_flags = 'r'
358 359 _show_mem_addr = False
359 360
360 361 def __init__(self, data=None, url=None, filename=None):
361 362 """Create a display object given raw data.
362 363
363 364 When this object is returned by an expression or passed to the
364 365 display function, it will result in the data being displayed
365 366 in the frontend. The MIME type of the data should match the
366 367 subclasses used, so the Png subclass should be used for 'image/png'
367 368 data. If the data is a URL, the data will first be downloaded
368 369 and then displayed. If
369 370
370 371 Parameters
371 372 ----------
372 373 data : unicode, str or bytes
373 374 The raw data or a URL or file to load the data from
374 375 url : unicode
375 376 A URL to download the data from.
376 377 filename : unicode
377 378 Path to a local file to load the data from.
378 379 """
379 380 if data is not None and isinstance(data, string_types):
380 381 if data.startswith('http') and url is None:
381 382 url = data
382 383 filename = None
383 384 data = None
384 385 elif _safe_exists(data) and filename is None:
385 386 url = None
386 387 filename = data
387 388 data = None
388 389
389 390 self.data = data
390 391 self.url = url
391 392 self.filename = None if filename is None else unicode_type(filename)
392 393
393 394 self.reload()
394 395 self._check_data()
395 396
396 397 def __repr__(self):
397 398 if not self._show_mem_addr:
398 399 cls = self.__class__
399 400 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
400 401 else:
401 402 r = super(DisplayObject, self).__repr__()
402 403 return r
403 404
404 405 def _check_data(self):
405 406 """Override in subclasses if there's something to check."""
406 407 pass
407 408
408 409 def reload(self):
409 410 """Reload the raw data from file or URL."""
410 411 if self.filename is not None:
411 412 with open(self.filename, self._read_flags) as f:
412 413 self.data = f.read()
413 414 elif self.url is not None:
414 415 try:
415 416 try:
416 417 from urllib.request import urlopen # Py3
417 418 except ImportError:
418 419 from urllib2 import urlopen
419 420 response = urlopen(self.url)
420 421 self.data = response.read()
421 422 # extract encoding from header, if there is one:
422 423 encoding = None
423 424 for sub in response.headers['content-type'].split(';'):
424 425 sub = sub.strip()
425 426 if sub.startswith('charset'):
426 427 encoding = sub.split('=')[-1].strip()
427 428 break
428 429 # decode data, if an encoding was specified
429 430 if encoding:
430 431 self.data = self.data.decode(encoding, 'replace')
431 432 except:
432 433 self.data = None
433 434
434 435 class TextDisplayObject(DisplayObject):
435 436 """Validate that display data is text"""
436 437 def _check_data(self):
437 438 if self.data is not None and not isinstance(self.data, string_types):
438 439 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
439 440
440 441 class Pretty(TextDisplayObject):
441 442
442 443 def _repr_pretty_(self):
443 444 return self.data
444 445
445 446
446 447 class HTML(TextDisplayObject):
447 448
448 449 def _repr_html_(self):
449 450 return self.data
450 451
451 452 def __html__(self):
452 453 """
453 454 This method exists to inform other HTML-using modules (e.g. Markupsafe,
454 455 htmltag, etc) that this object is HTML and does not need things like
455 456 special characters (<>&) escaped.
456 457 """
457 458 return self._repr_html_()
458 459
459 460
460 461 class Markdown(TextDisplayObject):
461 462
462 463 def _repr_markdown_(self):
463 464 return self.data
464 465
465 466
466 467 class Math(TextDisplayObject):
467 468
468 469 def _repr_latex_(self):
469 470 s = self.data.strip('$')
470 471 return "$$%s$$" % s
471 472
472 473
473 474 class Latex(TextDisplayObject):
474 475
475 476 def _repr_latex_(self):
476 477 return self.data
477 478
478 479
479 480 class SVG(DisplayObject):
480 481
481 482 # wrap data in a property, which extracts the <svg> tag, discarding
482 483 # document headers
483 484 _data = None
484 485
485 486 @property
486 487 def data(self):
487 488 return self._data
488 489
489 490 @data.setter
490 491 def data(self, svg):
491 492 if svg is None:
492 493 self._data = None
493 494 return
494 495 # parse into dom object
495 496 from xml.dom import minidom
496 497 svg = cast_bytes_py2(svg)
497 498 x = minidom.parseString(svg)
498 499 # get svg tag (should be 1)
499 500 found_svg = x.getElementsByTagName('svg')
500 501 if found_svg:
501 502 svg = found_svg[0].toxml()
502 503 else:
503 504 # fallback on the input, trust the user
504 505 # but this is probably an error.
505 506 pass
506 507 svg = cast_unicode(svg)
507 508 self._data = svg
508 509
509 510 def _repr_svg_(self):
510 511 return self.data
511 512
512 513
513 514 class JSON(DisplayObject):
514 515 """JSON expects a JSON-able dict or list
515 516
516 517 not an already-serialized JSON string.
517 518
518 519 Scalar types (None, number, string) are not allowed, only dict or list containers.
519 520 """
520 521 # wrap data in a property, which warns about passing already-serialized JSON
521 522 _data = None
522 523 def _check_data(self):
523 524 if self.data is not None and not isinstance(self.data, (dict, list)):
524 525 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
525 526
526 527 @property
527 528 def data(self):
528 529 return self._data
529 530
530 531 @data.setter
531 532 def data(self, data):
532 533 if isinstance(data, string_types):
533 534 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
534 535 data = json.loads(data)
535 536 self._data = data
536 537
537 538 def _repr_json_(self):
538 539 return self.data
539 540
540 541 css_t = """$("head").append($("<link/>").attr({
541 542 rel: "stylesheet",
542 543 type: "text/css",
543 544 href: "%s"
544 545 }));
545 546 """
546 547
547 548 lib_t1 = """$.getScript("%s", function () {
548 549 """
549 550 lib_t2 = """});
550 551 """
551 552
552 553 class Javascript(TextDisplayObject):
553 554
554 555 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
555 556 """Create a Javascript display object given raw data.
556 557
557 558 When this object is returned by an expression or passed to the
558 559 display function, it will result in the data being displayed
559 560 in the frontend. If the data is a URL, the data will first be
560 561 downloaded and then displayed.
561 562
562 563 In the Notebook, the containing element will be available as `element`,
563 564 and jQuery will be available. Content appended to `element` will be
564 565 visible in the output area.
565 566
566 567 Parameters
567 568 ----------
568 569 data : unicode, str or bytes
569 570 The Javascript source code or a URL to download it from.
570 571 url : unicode
571 572 A URL to download the data from.
572 573 filename : unicode
573 574 Path to a local file to load the data from.
574 575 lib : list or str
575 576 A sequence of Javascript library URLs to load asynchronously before
576 577 running the source code. The full URLs of the libraries should
577 578 be given. A single Javascript library URL can also be given as a
578 579 string.
579 580 css: : list or str
580 581 A sequence of css files to load before running the source code.
581 582 The full URLs of the css files should be given. A single css URL
582 583 can also be given as a string.
583 584 """
584 585 if isinstance(lib, string_types):
585 586 lib = [lib]
586 587 elif lib is None:
587 588 lib = []
588 589 if isinstance(css, string_types):
589 590 css = [css]
590 591 elif css is None:
591 592 css = []
592 593 if not isinstance(lib, (list,tuple)):
593 594 raise TypeError('expected sequence, got: %r' % lib)
594 595 if not isinstance(css, (list,tuple)):
595 596 raise TypeError('expected sequence, got: %r' % css)
596 597 self.lib = lib
597 598 self.css = css
598 599 super(Javascript, self).__init__(data=data, url=url, filename=filename)
599 600
600 601 def _repr_javascript_(self):
601 602 r = ''
602 603 for c in self.css:
603 604 r += css_t % c
604 605 for l in self.lib:
605 606 r += lib_t1 % l
606 607 r += self.data
607 608 r += lib_t2*len(self.lib)
608 609 return r
609 610
610 611 # constants for identifying png/jpeg data
611 612 _PNG = b'\x89PNG\r\n\x1a\n'
612 613 _JPEG = b'\xff\xd8'
613 614
614 615 def _pngxy(data):
615 616 """read the (width, height) from a PNG header"""
616 617 ihdr = data.index(b'IHDR')
617 618 # next 8 bytes are width/height
618 619 w4h4 = data[ihdr+4:ihdr+12]
619 620 return struct.unpack('>ii', w4h4)
620 621
621 622 def _jpegxy(data):
622 623 """read the (width, height) from a JPEG header"""
623 624 # adapted from http://www.64lines.com/jpeg-width-height
624 625
625 626 idx = 4
626 627 while True:
627 628 block_size = struct.unpack('>H', data[idx:idx+2])[0]
628 629 idx = idx + block_size
629 630 if data[idx:idx+2] == b'\xFF\xC0':
630 631 # found Start of Frame
631 632 iSOF = idx
632 633 break
633 634 else:
634 635 # read another block
635 636 idx += 2
636 637
637 638 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
638 639 return w, h
639 640
640 641 class Image(DisplayObject):
641 642
642 643 _read_flags = 'rb'
643 644 _FMT_JPEG = u'jpeg'
644 645 _FMT_PNG = u'png'
645 646 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
646 647
647 648 def __init__(self, data=None, url=None, filename=None, format=None,
648 649 embed=None, width=None, height=None, retina=False,
649 650 unconfined=False, metadata=None):
650 651 """Create a PNG/JPEG image object given raw data.
651 652
652 653 When this object is returned by an input cell or passed to the
653 654 display function, it will result in the image being displayed
654 655 in the frontend.
655 656
656 657 Parameters
657 658 ----------
658 659 data : unicode, str or bytes
659 660 The raw image data or a URL or filename to load the data from.
660 661 This always results in embedded image data.
661 662 url : unicode
662 663 A URL to download the data from. If you specify `url=`,
663 664 the image data will not be embedded unless you also specify `embed=True`.
664 665 filename : unicode
665 666 Path to a local file to load the data from.
666 667 Images from a file are always embedded.
667 668 format : unicode
668 669 The format of the image data (png/jpeg/jpg). If a filename or URL is given
669 670 for format will be inferred from the filename extension.
670 671 embed : bool
671 672 Should the image data be embedded using a data URI (True) or be
672 673 loaded using an <img> tag. Set this to True if you want the image
673 674 to be viewable later with no internet connection in the notebook.
674 675
675 676 Default is `True`, unless the keyword argument `url` is set, then
676 677 default value is `False`.
677 678
678 679 Note that QtConsole is not able to display images if `embed` is set to `False`
679 680 width : int
680 681 Width to which to constrain the image in html
681 682 height : int
682 683 Height to which to constrain the image in html
683 684 retina : bool
684 685 Automatically set the width and height to half of the measured
685 686 width and height.
686 687 This only works for embedded images because it reads the width/height
687 688 from image data.
688 689 For non-embedded images, you can just set the desired display width
689 690 and height directly.
690 691 unconfined: bool
691 692 Set unconfined=True to disable max-width confinement of the image.
692 693 metadata: dict
693 694 Specify extra metadata to attach to the image.
694 695
695 696 Examples
696 697 --------
697 698 # embedded image data, works in qtconsole and notebook
698 699 # when passed positionally, the first arg can be any of raw image data,
699 700 # a URL, or a filename from which to load image data.
700 701 # The result is always embedding image data for inline images.
701 702 Image('http://www.google.fr/images/srpr/logo3w.png')
702 703 Image('/path/to/image.jpg')
703 704 Image(b'RAW_PNG_DATA...')
704 705
705 706 # Specifying Image(url=...) does not embed the image data,
706 707 # it only generates `<img>` tag with a link to the source.
707 708 # This will not work in the qtconsole or offline.
708 709 Image(url='http://www.google.fr/images/srpr/logo3w.png')
709 710
710 711 """
711 712 if filename is not None:
712 713 ext = self._find_ext(filename)
713 714 elif url is not None:
714 715 ext = self._find_ext(url)
715 716 elif data is None:
716 717 raise ValueError("No image data found. Expecting filename, url, or data.")
717 718 elif isinstance(data, string_types) and (
718 719 data.startswith('http') or _safe_exists(data)
719 720 ):
720 721 ext = self._find_ext(data)
721 722 else:
722 723 ext = None
723 724
724 725 if format is None:
725 726 if ext is not None:
726 727 if ext == u'jpg' or ext == u'jpeg':
727 728 format = self._FMT_JPEG
728 729 if ext == u'png':
729 730 format = self._FMT_PNG
730 731 else:
731 732 format = ext.lower()
732 733 elif isinstance(data, bytes):
733 734 # infer image type from image data header,
734 735 # only if format has not been specified.
735 736 if data[:2] == _JPEG:
736 737 format = self._FMT_JPEG
737 738
738 739 # failed to detect format, default png
739 740 if format is None:
740 741 format = 'png'
741 742
742 743 if format.lower() == 'jpg':
743 744 # jpg->jpeg
744 745 format = self._FMT_JPEG
745 746
746 747 self.format = unicode_type(format).lower()
747 748 self.embed = embed if embed is not None else (url is None)
748 749
749 750 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
750 751 raise ValueError("Cannot embed the '%s' image format" % (self.format))
751 752 self.width = width
752 753 self.height = height
753 754 self.retina = retina
754 755 self.unconfined = unconfined
755 756 self.metadata = metadata
756 757 super(Image, self).__init__(data=data, url=url, filename=filename)
757 758
758 759 if retina:
759 760 self._retina_shape()
760 761
761 762 def _retina_shape(self):
762 763 """load pixel-doubled width and height from image data"""
763 764 if not self.embed:
764 765 return
765 766 if self.format == 'png':
766 767 w, h = _pngxy(self.data)
767 768 elif self.format == 'jpeg':
768 769 w, h = _jpegxy(self.data)
769 770 else:
770 771 # retina only supports png
771 772 return
772 773 self.width = w // 2
773 774 self.height = h // 2
774 775
775 776 def reload(self):
776 777 """Reload the raw data from file or URL."""
777 778 if self.embed:
778 779 super(Image,self).reload()
779 780 if self.retina:
780 781 self._retina_shape()
781 782
782 783 def _repr_html_(self):
783 784 if not self.embed:
784 785 width = height = klass = ''
785 786 if self.width:
786 787 width = ' width="%d"' % self.width
787 788 if self.height:
788 789 height = ' height="%d"' % self.height
789 790 if self.unconfined:
790 791 klass = ' class="unconfined"'
791 792 return u'<img src="{url}"{width}{height}{klass}/>'.format(
792 793 url=self.url,
793 794 width=width,
794 795 height=height,
795 796 klass=klass,
796 797 )
797 798
798 799 def _data_and_metadata(self):
799 800 """shortcut for returning metadata with shape information, if defined"""
800 801 md = {}
801 802 if self.width:
802 803 md['width'] = self.width
803 804 if self.height:
804 805 md['height'] = self.height
805 806 if self.unconfined:
806 807 md['unconfined'] = self.unconfined
807 808 if self.metadata:
808 809 md.update(self.metadata)
809 810 if md:
810 811 return self.data, md
811 812 else:
812 813 return self.data
813 814
814 815 def _repr_png_(self):
815 816 if self.embed and self.format == u'png':
816 817 return self._data_and_metadata()
817 818
818 819 def _repr_jpeg_(self):
819 820 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
820 821 return self._data_and_metadata()
821 822
822 823 def _find_ext(self, s):
823 824 return unicode_type(s.split('.')[-1].lower())
824 825
825 826 class Video(DisplayObject):
826 827
827 828 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
828 829 """Create a video object given raw data or an URL.
829 830
830 831 When this object is returned by an input cell or passed to the
831 832 display function, it will result in the video being displayed
832 833 in the frontend.
833 834
834 835 Parameters
835 836 ----------
836 837 data : unicode, str or bytes
837 838 The raw video data or a URL or filename to load the data from.
838 839 Raw data will require passing `embed=True`.
839 840 url : unicode
840 841 A URL for the video. If you specify `url=`,
841 842 the image data will not be embedded.
842 843 filename : unicode
843 844 Path to a local file containing the video.
844 845 Will be interpreted as a local URL unless `embed=True`.
845 846 embed : bool
846 847 Should the video be embedded using a data URI (True) or be
847 848 loaded using a <video> tag (False).
848 849
849 850 Since videos are large, embedding them should be avoided, if possible.
850 851 You must confirm embedding as your intention by passing `embed=True`.
851 852
852 853 Local files can be displayed with URLs without embedding the content, via::
853 854
854 855 Video('./video.mp4')
855 856
856 857 mimetype: unicode
857 858 Specify the mimetype for embedded videos.
858 859 Default will be guessed from file extension, if available.
859 860
860 861 Examples
861 862 --------
862 863
863 864 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
864 865 Video('path/to/video.mp4')
865 866 Video('path/to/video.mp4', embed=True)
866 867 Video(b'raw-videodata', embed=True)
867 868 """
868 869 if url is None and isinstance(data, string_types) and data.startswith(('http:', 'https:')):
869 870 url = data
870 871 data = None
871 872 elif os.path.exists(data):
872 873 filename = data
873 874 data = None
874 875
875 876 if data and not embed:
876 877 msg = ''.join([
877 878 "To embed videos, you must pass embed=True ",
878 879 "(this may make your notebook files huge)\n",
879 880 "Consider passing Video(url='...')",
880 881 ])
881 882 raise ValueError(msg)
882 883
883 884 self.mimetype = mimetype
884 885 self.embed = embed
885 886 super(Video, self).__init__(data=data, url=url, filename=filename)
886 887
887 888 def _repr_html_(self):
888 889 # External URLs and potentially local files are not embedded into the
889 890 # notebook output.
890 891 if not self.embed:
891 892 url = self.url if self.url is not None else self.filename
892 893 output = """<video src="{0}" controls>
893 894 Your browser does not support the <code>video</code> element.
894 895 </video>""".format(url)
895 896 return output
896 897
897 898 # Embedded videos are base64-encoded.
898 899 mimetype = self.mimetype
899 900 if self.filename is not None:
900 901 if not mimetype:
901 902 mimetype, _ = mimetypes.guess_type(self.filename)
902 903
903 904 with open(self.filename, 'rb') as f:
904 905 video = f.read()
905 906 else:
906 907 video = self.data
907 908 if isinstance(video, unicode_type):
908 909 # unicode input is already b64-encoded
909 910 b64_video = video
910 911 else:
911 912 b64_video = base64_encode(video).decode('ascii').rstrip()
912 913
913 914 output = """<video controls>
914 915 <source src="data:{0};base64,{1}" type="{0}">
915 916 Your browser does not support the video tag.
916 917 </video>""".format(mimetype, b64_video)
917 918 return output
918 919
919 920 def reload(self):
920 921 # TODO
921 922 pass
922 923
923 924 def _repr_png_(self):
924 925 # TODO
925 926 pass
926 927 def _repr_jpeg_(self):
927 928 # TODO
928 929 pass
929 930
930 931 def clear_output(wait=False):
931 932 """Clear the output of the current cell receiving output.
932 933
933 934 Parameters
934 935 ----------
935 936 wait : bool [default: false]
936 937 Wait to clear the output until new output is available to replace it."""
937 938 from IPython.core.interactiveshell import InteractiveShell
938 939 if InteractiveShell.initialized():
939 940 InteractiveShell.instance().display_pub.clear_output(wait)
940 941 else:
941 from IPython.utils import io
942 print('\033[2K\r', file=io.stdout, end='')
943 io.stdout.flush()
944 print('\033[2K\r', file=io.stderr, end='')
945 io.stderr.flush()
942 print('\033[2K\r', end='')
943 sys.stdout.flush()
944 print('\033[2K\r', end='')
945 sys.stderr.flush()
946 946
947 947
948 948 @skip_doctest
949 949 def set_matplotlib_formats(*formats, **kwargs):
950 950 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
951 951
952 952 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
953 953
954 954 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
955 955
956 956 To set this in your config files use the following::
957 957
958 958 c.InlineBackend.figure_formats = {'png', 'jpeg'}
959 959 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
960 960
961 961 Parameters
962 962 ----------
963 963 *formats : strs
964 964 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
965 965 **kwargs :
966 966 Keyword args will be relayed to ``figure.canvas.print_figure``.
967 967 """
968 968 from IPython.core.interactiveshell import InteractiveShell
969 969 from IPython.core.pylabtools import select_figure_formats
970 970 # build kwargs, starting with InlineBackend config
971 971 kw = {}
972 972 from ipykernel.pylab.config import InlineBackend
973 973 cfg = InlineBackend.instance()
974 974 kw.update(cfg.print_figure_kwargs)
975 975 kw.update(**kwargs)
976 976 shell = InteractiveShell.instance()
977 977 select_figure_formats(shell, formats, **kw)
978 978
979 979 @skip_doctest
980 980 def set_matplotlib_close(close=True):
981 981 """Set whether the inline backend closes all figures automatically or not.
982 982
983 983 By default, the inline backend used in the IPython Notebook will close all
984 984 matplotlib figures automatically after each cell is run. This means that
985 985 plots in different cells won't interfere. Sometimes, you may want to make
986 986 a plot in one cell and then refine it in later cells. This can be accomplished
987 987 by::
988 988
989 989 In [1]: set_matplotlib_close(False)
990 990
991 991 To set this in your config files use the following::
992 992
993 993 c.InlineBackend.close_figures = False
994 994
995 995 Parameters
996 996 ----------
997 997 close : bool
998 998 Should all matplotlib figures be automatically closed after each cell is
999 999 run?
1000 1000 """
1001 1001 from ipykernel.pylab.config import InlineBackend
1002 1002 cfg = InlineBackend.instance()
1003 1003 cfg.close_figures = close
1004 1004
@@ -1,294 +1,293 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Displayhook for IPython.
3 3
4 4 This defines a callable class that IPython uses for `sys.displayhook`.
5 5 """
6 6
7 7 # Copyright (c) IPython Development Team.
8 8 # Distributed under the terms of the Modified BSD License.
9 9
10 10 from __future__ import print_function
11 11
12 12 import sys
13 13 import io as _io
14 14 import tokenize
15 15
16 16 from traitlets.config.configurable import Configurable
17 from IPython.utils import io
18 17 from IPython.utils.py3compat import builtin_mod, cast_unicode_py2
19 18 from traitlets import Instance, Float
20 19 from warnings import warn
21 20
22 21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
23 22 # of these are also attributes of InteractiveShell. They should be on ONE object
24 23 # only and the other objects should ask that one object for their values.
25 24
26 25 class DisplayHook(Configurable):
27 26 """The custom IPython displayhook to replace sys.displayhook.
28 27
29 28 This class does many things, but the basic idea is that it is a callable
30 29 that gets called anytime user code returns a value.
31 30 """
32 31
33 32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
34 33 allow_none=True)
35 34 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
36 35 allow_none=True)
37 36 cull_fraction = Float(0.2)
38 37
39 38 def __init__(self, shell=None, cache_size=1000, **kwargs):
40 39 super(DisplayHook, self).__init__(shell=shell, **kwargs)
41 40 cache_size_min = 3
42 41 if cache_size <= 0:
43 42 self.do_full_cache = 0
44 43 cache_size = 0
45 44 elif cache_size < cache_size_min:
46 45 self.do_full_cache = 0
47 46 cache_size = 0
48 47 warn('caching was disabled (min value for cache size is %s).' %
49 48 cache_size_min,level=3)
50 49 else:
51 50 self.do_full_cache = 1
52 51
53 52 self.cache_size = cache_size
54 53
55 54 # we need a reference to the user-level namespace
56 55 self.shell = shell
57 56
58 57 self._,self.__,self.___ = '','',''
59 58
60 59 # these are deliberately global:
61 60 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
62 61 self.shell.user_ns.update(to_user_ns)
63 62
64 63 @property
65 64 def prompt_count(self):
66 65 return self.shell.execution_count
67 66
68 67 #-------------------------------------------------------------------------
69 68 # Methods used in __call__. Override these methods to modify the behavior
70 69 # of the displayhook.
71 70 #-------------------------------------------------------------------------
72 71
73 72 def check_for_underscore(self):
74 73 """Check if the user has set the '_' variable by hand."""
75 74 # If something injected a '_' variable in __builtin__, delete
76 75 # ipython's automatic one so we don't clobber that. gettext() in
77 76 # particular uses _, so we need to stay away from it.
78 77 if '_' in builtin_mod.__dict__:
79 78 try:
80 79 del self.shell.user_ns['_']
81 80 except KeyError:
82 81 pass
83 82
84 83 def quiet(self):
85 84 """Should we silence the display hook because of ';'?"""
86 85 # do not print output if input ends in ';'
87 86
88 87 try:
89 88 cell = cast_unicode_py2(self.shell.history_manager.input_hist_parsed[-1])
90 89 except IndexError:
91 90 # some uses of ipshellembed may fail here
92 91 return False
93 92
94 93 sio = _io.StringIO(cell)
95 94 tokens = list(tokenize.generate_tokens(sio.readline))
96 95
97 96 for token in reversed(tokens):
98 97 if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
99 98 continue
100 99 if (token[0] == tokenize.OP) and (token[1] == ';'):
101 100 return True
102 101 else:
103 102 return False
104 103
105 104 def start_displayhook(self):
106 105 """Start the displayhook, initializing resources."""
107 106 pass
108 107
109 108 def write_output_prompt(self):
110 109 """Write the output prompt.
111 110
112 111 The default implementation simply writes the prompt to
113 112 ``io.stdout``.
114 113 """
115 114 # Use write, not print which adds an extra space.
116 io.stdout.write(self.shell.separate_out)
115 sys.stdout.write(self.shell.separate_out)
117 116 outprompt = self.shell.prompt_manager.render('out')
118 117 if self.do_full_cache:
119 io.stdout.write(outprompt)
118 sys.stdout.write(outprompt)
120 119
121 120 def compute_format_data(self, result):
122 121 """Compute format data of the object to be displayed.
123 122
124 123 The format data is a generalization of the :func:`repr` of an object.
125 124 In the default implementation the format data is a :class:`dict` of
126 125 key value pair where the keys are valid MIME types and the values
127 126 are JSON'able data structure containing the raw data for that MIME
128 127 type. It is up to frontends to determine pick a MIME to to use and
129 128 display that data in an appropriate manner.
130 129
131 130 This method only computes the format data for the object and should
132 131 NOT actually print or write that to a stream.
133 132
134 133 Parameters
135 134 ----------
136 135 result : object
137 136 The Python object passed to the display hook, whose format will be
138 137 computed.
139 138
140 139 Returns
141 140 -------
142 141 (format_dict, md_dict) : dict
143 142 format_dict is a :class:`dict` whose keys are valid MIME types and values are
144 143 JSON'able raw data for that MIME type. It is recommended that
145 144 all return values of this should always include the "text/plain"
146 145 MIME type representation of the object.
147 146 md_dict is a :class:`dict` with the same MIME type keys
148 147 of metadata associated with each output.
149 148
150 149 """
151 150 return self.shell.display_formatter.format(result)
152 151
153 152 def write_format_data(self, format_dict, md_dict=None):
154 153 """Write the format data dict to the frontend.
155 154
156 155 This default version of this method simply writes the plain text
157 156 representation of the object to ``io.stdout``. Subclasses should
158 157 override this method to send the entire `format_dict` to the
159 158 frontends.
160 159
161 160 Parameters
162 161 ----------
163 162 format_dict : dict
164 163 The format dict for the object passed to `sys.displayhook`.
165 164 md_dict : dict (optional)
166 165 The metadata dict to be associated with the display data.
167 166 """
168 167 if 'text/plain' not in format_dict:
169 168 # nothing to do
170 169 return
171 170 # We want to print because we want to always make sure we have a
172 171 # newline, even if all the prompt separators are ''. This is the
173 172 # standard IPython behavior.
174 173 result_repr = format_dict['text/plain']
175 174 if '\n' in result_repr:
176 175 # So that multi-line strings line up with the left column of
177 176 # the screen, instead of having the output prompt mess up
178 177 # their first line.
179 178 # We use the prompt template instead of the expanded prompt
180 179 # because the expansion may add ANSI escapes that will interfere
181 180 # with our ability to determine whether or not we should add
182 181 # a newline.
183 182 prompt_template = self.shell.prompt_manager.out_template
184 183 if prompt_template and not prompt_template.endswith('\n'):
185 184 # But avoid extraneous empty lines.
186 185 result_repr = '\n' + result_repr
187 186
188 print(result_repr, file=io.stdout)
187 print(result_repr)
189 188
190 189 def update_user_ns(self, result):
191 190 """Update user_ns with various things like _, __, _1, etc."""
192 191
193 192 # Avoid recursive reference when displaying _oh/Out
194 193 if result is not self.shell.user_ns['_oh']:
195 194 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
196 195 self.cull_cache()
197 196 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
198 197 # we cause buggy behavior for things like gettext).
199 198
200 199 if '_' not in builtin_mod.__dict__:
201 200 self.___ = self.__
202 201 self.__ = self._
203 202 self._ = result
204 203 self.shell.push({'_':self._,
205 204 '__':self.__,
206 205 '___':self.___}, interactive=False)
207 206
208 207 # hackish access to top-level namespace to create _1,_2... dynamically
209 208 to_main = {}
210 209 if self.do_full_cache:
211 210 new_result = '_'+repr(self.prompt_count)
212 211 to_main[new_result] = result
213 212 self.shell.push(to_main, interactive=False)
214 213 self.shell.user_ns['_oh'][self.prompt_count] = result
215 214
216 215 def fill_exec_result(self, result):
217 216 if self.exec_result is not None:
218 217 self.exec_result.result = result
219 218
220 219 def log_output(self, format_dict):
221 220 """Log the output."""
222 221 if 'text/plain' not in format_dict:
223 222 # nothing to do
224 223 return
225 224 if self.shell.logger.log_output:
226 225 self.shell.logger.log_write(format_dict['text/plain'], 'output')
227 226 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
228 227 format_dict['text/plain']
229 228
230 229 def finish_displayhook(self):
231 230 """Finish up all displayhook activities."""
232 io.stdout.write(self.shell.separate_out2)
233 io.stdout.flush()
231 sys.stdout.write(self.shell.separate_out2)
232 sys.stdout.flush()
234 233
235 234 def __call__(self, result=None):
236 235 """Printing with history cache management.
237 236
238 237 This is invoked everytime the interpreter needs to print, and is
239 238 activated by setting the variable sys.displayhook to it.
240 239 """
241 240 self.check_for_underscore()
242 241 if result is not None and not self.quiet():
243 242 self.start_displayhook()
244 243 self.write_output_prompt()
245 244 format_dict, md_dict = self.compute_format_data(result)
246 245 self.update_user_ns(result)
247 246 self.fill_exec_result(result)
248 247 if format_dict:
249 248 self.write_format_data(format_dict, md_dict)
250 249 self.log_output(format_dict)
251 250 self.finish_displayhook()
252 251
253 252 def cull_cache(self):
254 253 """Output cache is full, cull the oldest entries"""
255 254 oh = self.shell.user_ns.get('_oh', {})
256 255 sz = len(oh)
257 256 cull_count = max(int(sz * self.cull_fraction), 2)
258 257 warn('Output cache limit (currently {sz} entries) hit.\n'
259 258 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
260 259
261 260 for i, n in enumerate(sorted(oh)):
262 261 if i >= cull_count:
263 262 break
264 263 self.shell.user_ns.pop('_%i' % n, None)
265 264 oh.pop(n, None)
266 265
267 266
268 267 def flush(self):
269 268 if not self.do_full_cache:
270 269 raise ValueError("You shouldn't have reached the cache flush "
271 270 "if full caching is not enabled!")
272 271 # delete auto-generated vars from global namespace
273 272
274 273 for n in range(1,self.prompt_count + 1):
275 274 key = '_'+repr(n)
276 275 try:
277 276 del self.shell.user_ns[key]
278 277 except: pass
279 278 # In some embedded circumstances, the user_ns doesn't have the
280 279 # '_oh' key set up.
281 280 oh = self.shell.user_ns.get('_oh', None)
282 281 if oh is not None:
283 282 oh.clear()
284 283
285 284 # Release our own references to objects:
286 285 self._, self.__, self.___ = '', '', ''
287 286
288 287 if '_' not in builtin_mod.__dict__:
289 288 self.shell.user_ns.update({'_':None,'__':None, '___':None})
290 289 import gc
291 290 # TODO: Is this really needed?
292 291 # IronPython blocks here forever
293 292 if sys.platform != "cli":
294 293 gc.collect()
@@ -1,116 +1,117 b''
1 1 """An interface for publishing rich data to frontends.
2 2
3 3 There are two components of the display system:
4 4
5 5 * Display formatters, which take a Python object and compute the
6 6 representation of the object in various formats (text, HTML, SVG, etc.).
7 7 * The display publisher that is used to send the representation data to the
8 8 various frontends.
9 9
10 10 This module defines the logic display publishing. The display publisher uses
11 11 the ``display_data`` message type that is defined in the IPython messaging
12 12 spec.
13 13 """
14 14
15 15 # Copyright (c) IPython Development Team.
16 16 # Distributed under the terms of the Modified BSD License.
17 17
18 18 from __future__ import print_function
19 19
20 import sys
21
20 22 from traitlets.config.configurable import Configurable
21 from IPython.utils import io
22 23 from traitlets import List
23 24
24 25 # This used to be defined here - it is imported for backwards compatibility
25 26 from .display import publish_display_data
26 27
27 28 #-----------------------------------------------------------------------------
28 29 # Main payload class
29 30 #-----------------------------------------------------------------------------
30 31
31 32 class DisplayPublisher(Configurable):
32 33 """A traited class that publishes display data to frontends.
33 34
34 35 Instances of this class are created by the main IPython object and should
35 36 be accessed there.
36 37 """
37 38
38 39 def _validate_data(self, data, metadata=None):
39 40 """Validate the display data.
40 41
41 42 Parameters
42 43 ----------
43 44 data : dict
44 45 The formata data dictionary.
45 46 metadata : dict
46 47 Any metadata for the data.
47 48 """
48 49
49 50 if not isinstance(data, dict):
50 51 raise TypeError('data must be a dict, got: %r' % data)
51 52 if metadata is not None:
52 53 if not isinstance(metadata, dict):
53 54 raise TypeError('metadata must be a dict, got: %r' % data)
54 55
55 56 def publish(self, data, metadata=None, source=None):
56 57 """Publish data and metadata to all frontends.
57 58
58 59 See the ``display_data`` message in the messaging documentation for
59 60 more details about this message type.
60 61
61 62 The following MIME types are currently implemented:
62 63
63 64 * text/plain
64 65 * text/html
65 66 * text/markdown
66 67 * text/latex
67 68 * application/json
68 69 * application/javascript
69 70 * image/png
70 71 * image/jpeg
71 72 * image/svg+xml
72 73
73 74 Parameters
74 75 ----------
75 76 data : dict
76 77 A dictionary having keys that are valid MIME types (like
77 78 'text/plain' or 'image/svg+xml') and values that are the data for
78 79 that MIME type. The data itself must be a JSON'able data
79 80 structure. Minimally all data should have the 'text/plain' data,
80 81 which can be displayed by all frontends. If more than the plain
81 82 text is given, it is up to the frontend to decide which
82 83 representation to use.
83 84 metadata : dict
84 85 A dictionary for metadata related to the data. This can contain
85 86 arbitrary key, value pairs that frontends can use to interpret
86 87 the data. Metadata specific to each mime-type can be specified
87 88 in the metadata dict with the same mime-type keys as
88 89 the data itself.
89 90 source : str, deprecated
90 91 Unused.
91 92 """
92 93
93 94 # The default is to simply write the plain text data using io.stdout.
94 95 if 'text/plain' in data:
95 print(data['text/plain'], file=io.stdout)
96 print(data['text/plain'])
96 97
97 98 def clear_output(self, wait=False):
98 99 """Clear the output of the cell receiving output."""
99 print('\033[2K\r', file=io.stdout, end='')
100 io.stdout.flush()
101 print('\033[2K\r', file=io.stderr, end='')
102 io.stderr.flush()
100 print('\033[2K\r', end='')
101 sys.stdout.flush()
102 print('\033[2K\r', end='')
103 sys.stderr.flush()
103 104
104 105
105 106 class CapturingDisplayPublisher(DisplayPublisher):
106 107 """A DisplayPublisher that stores"""
107 108 outputs = List()
108 109
109 110 def publish(self, data, metadata=None, source=None):
110 111 self.outputs.append((data, metadata))
111 112
112 113 def clear_output(self, wait=False):
113 114 super(CapturingDisplayPublisher, self).clear_output(wait)
114 115
115 116 # empty the list, *do not* reassign a new list
116 117 del self.outputs[:]
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,319 +1,320 b''
1 1 """Implementation of magic functions related to History.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012, IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib
17 17 import os
18 import sys
18 19 from io import open as io_open
19 20
20 21 # Our own packages
21 22 from IPython.core.error import StdinNotImplementedError
22 23 from IPython.core.magic import Magics, magics_class, line_magic
23 24 from IPython.core.magic_arguments import (argument, magic_arguments,
24 25 parse_argstring)
25 26 from IPython.testing.skipdoctest import skip_doctest
26 27 from IPython.utils import io
27 28 from IPython.utils.py3compat import cast_unicode_py2
28 29
29 30 #-----------------------------------------------------------------------------
30 31 # Magics class implementation
31 32 #-----------------------------------------------------------------------------
32 33
33 34
34 35 _unspecified = object()
35 36
36 37
37 38 @magics_class
38 39 class HistoryMagics(Magics):
39 40
40 41 @magic_arguments()
41 42 @argument(
42 43 '-n', dest='print_nums', action='store_true', default=False,
43 44 help="""
44 45 print line numbers for each input.
45 46 This feature is only available if numbered prompts are in use.
46 47 """)
47 48 @argument(
48 49 '-o', dest='get_output', action='store_true', default=False,
49 50 help="also print outputs for each input.")
50 51 @argument(
51 52 '-p', dest='pyprompts', action='store_true', default=False,
52 53 help="""
53 54 print classic '>>>' python prompts before each input.
54 55 This is useful for making documentation, and in conjunction
55 56 with -o, for producing doctest-ready output.
56 57 """)
57 58 @argument(
58 59 '-t', dest='raw', action='store_false', default=True,
59 60 help="""
60 61 print the 'translated' history, as IPython understands it.
61 62 IPython filters your input and converts it all into valid Python
62 63 source before executing it (things like magics or aliases are turned
63 64 into function calls, for example). With this option, you'll see the
64 65 native history instead of the user-entered version: '%%cd /' will be
65 66 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
66 67 """)
67 68 @argument(
68 69 '-f', dest='filename',
69 70 help="""
70 71 FILENAME: instead of printing the output to the screen, redirect
71 72 it to the given file. The file is always overwritten, though *when
72 73 it can*, IPython asks for confirmation first. In particular, running
73 74 the command 'history -f FILENAME' from the IPython Notebook
74 75 interface will replace FILENAME even if it already exists *without*
75 76 confirmation.
76 77 """)
77 78 @argument(
78 79 '-g', dest='pattern', nargs='*', default=None,
79 80 help="""
80 81 treat the arg as a glob pattern to search for in (full) history.
81 82 This includes the saved history (almost all commands ever written).
82 83 The pattern may contain '?' to match one unknown character and '*'
83 84 to match any number of unknown characters. Use '%%hist -g' to show
84 85 full saved history (may be very long).
85 86 """)
86 87 @argument(
87 88 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
88 89 help="""
89 90 get the last n lines from all sessions. Specify n as a single
90 91 arg, or the default is the last 10 lines.
91 92 """)
92 93 @argument(
93 94 '-u', dest='unique', action='store_true',
94 95 help="""
95 96 when searching history using `-g`, show only unique history.
96 97 """)
97 98 @argument('range', nargs='*')
98 99 @skip_doctest
99 100 @line_magic
100 101 def history(self, parameter_s = ''):
101 102 """Print input history (_i<n> variables), with most recent last.
102 103
103 104 By default, input history is printed without line numbers so it can be
104 105 directly pasted into an editor. Use -n to show them.
105 106
106 107 By default, all input history from the current session is displayed.
107 108 Ranges of history can be indicated using the syntax:
108 109
109 110 ``4``
110 111 Line 4, current session
111 112 ``4-6``
112 113 Lines 4-6, current session
113 114 ``243/1-5``
114 115 Lines 1-5, session 243
115 116 ``~2/7``
116 117 Line 7, session 2 before current
117 118 ``~8/1-~6/5``
118 119 From the first line of 8 sessions ago, to the fifth line of 6
119 120 sessions ago.
120 121
121 122 Multiple ranges can be entered, separated by spaces
122 123
123 124 The same syntax is used by %macro, %save, %edit, %rerun
124 125
125 126 Examples
126 127 --------
127 128 ::
128 129
129 130 In [6]: %history -n 4-6
130 131 4:a = 12
131 132 5:print a**2
132 133 6:%history -n 4-6
133 134
134 135 """
135 136
136 137 args = parse_argstring(self.history, parameter_s)
137 138
138 139 # For brevity
139 140 history_manager = self.shell.history_manager
140 141
141 142 def _format_lineno(session, line):
142 143 """Helper function to format line numbers properly."""
143 144 if session in (0, history_manager.session_number):
144 145 return str(line)
145 146 return "%s/%s" % (session, line)
146 147
147 148 # Check if output to specific file was requested.
148 149 outfname = args.filename
149 150 if not outfname:
150 outfile = io.stdout # default
151 outfile = sys.stdout # default
151 152 # We don't want to close stdout at the end!
152 153 close_at_end = False
153 154 else:
154 155 if os.path.exists(outfname):
155 156 try:
156 157 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
157 158 except StdinNotImplementedError:
158 159 ans = True
159 160 if not ans:
160 161 print('Aborting.')
161 162 return
162 163 print("Overwriting file.")
163 164 outfile = io_open(outfname, 'w', encoding='utf-8')
164 165 close_at_end = True
165 166
166 167 print_nums = args.print_nums
167 168 get_output = args.get_output
168 169 pyprompts = args.pyprompts
169 170 raw = args.raw
170 171
171 172 pattern = None
172 173 limit = None if args.limit is _unspecified else args.limit
173 174
174 175 if args.pattern is not None:
175 176 if args.pattern:
176 177 pattern = "*" + " ".join(args.pattern) + "*"
177 178 else:
178 179 pattern = "*"
179 180 hist = history_manager.search(pattern, raw=raw, output=get_output,
180 181 n=limit, unique=args.unique)
181 182 print_nums = True
182 183 elif args.limit is not _unspecified:
183 184 n = 10 if limit is None else limit
184 185 hist = history_manager.get_tail(n, raw=raw, output=get_output)
185 186 else:
186 187 if args.range: # Get history by ranges
187 188 hist = history_manager.get_range_by_str(" ".join(args.range),
188 189 raw, get_output)
189 190 else: # Just get history for the current session
190 191 hist = history_manager.get_range(raw=raw, output=get_output)
191 192
192 193 # We could be displaying the entire history, so let's not try to pull
193 194 # it into a list in memory. Anything that needs more space will just
194 195 # misalign.
195 196 width = 4
196 197
197 198 for session, lineno, inline in hist:
198 199 # Print user history with tabs expanded to 4 spaces. The GUI
199 200 # clients use hard tabs for easier usability in auto-indented code,
200 201 # but we want to produce PEP-8 compliant history for safe pasting
201 202 # into an editor.
202 203 if get_output:
203 204 inline, output = inline
204 205 inline = inline.expandtabs(4).rstrip()
205 206
206 207 multiline = "\n" in inline
207 208 line_sep = '\n' if multiline else ' '
208 209 if print_nums:
209 210 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
210 211 line_sep), file=outfile, end=u'')
211 212 if pyprompts:
212 213 print(u">>> ", end=u"", file=outfile)
213 214 if multiline:
214 215 inline = "\n... ".join(inline.splitlines()) + "\n..."
215 216 print(inline, file=outfile)
216 217 if get_output and output:
217 218 print(cast_unicode_py2(output), file=outfile)
218 219
219 220 if close_at_end:
220 221 outfile.close()
221 222
222 223 @line_magic
223 224 def recall(self, arg):
224 225 r"""Repeat a command, or get command to input line for editing.
225 226
226 227 %recall and %rep are equivalent.
227 228
228 229 - %recall (no arguments):
229 230
230 231 Place a string version of last computation result (stored in the
231 232 special '_' variable) to the next input prompt. Allows you to create
232 233 elaborate command lines without using copy-paste::
233 234
234 235 In[1]: l = ["hei", "vaan"]
235 236 In[2]: "".join(l)
236 237 Out[2]: heivaan
237 238 In[3]: %recall
238 239 In[4]: heivaan_ <== cursor blinking
239 240
240 241 %recall 45
241 242
242 243 Place history line 45 on the next input prompt. Use %hist to find
243 244 out the number.
244 245
245 246 %recall 1-4
246 247
247 248 Combine the specified lines into one cell, and place it on the next
248 249 input prompt. See %history for the slice syntax.
249 250
250 251 %recall foo+bar
251 252
252 253 If foo+bar can be evaluated in the user namespace, the result is
253 254 placed at the next input prompt. Otherwise, the history is searched
254 255 for lines which contain that substring, and the most recent one is
255 256 placed at the next input prompt.
256 257 """
257 258 if not arg: # Last output
258 259 self.shell.set_next_input(str(self.shell.user_ns["_"]))
259 260 return
260 261 # Get history range
261 262 histlines = self.shell.history_manager.get_range_by_str(arg)
262 263 cmd = "\n".join(x[2] for x in histlines)
263 264 if cmd:
264 265 self.shell.set_next_input(cmd.rstrip())
265 266 return
266 267
267 268 try: # Variable in user namespace
268 269 cmd = str(eval(arg, self.shell.user_ns))
269 270 except Exception: # Search for term in history
270 271 histlines = self.shell.history_manager.search("*"+arg+"*")
271 272 for h in reversed([x[2] for x in histlines]):
272 273 if 'recall' in h or 'rep' in h:
273 274 continue
274 275 self.shell.set_next_input(h.rstrip())
275 276 return
276 277 else:
277 278 self.shell.set_next_input(cmd.rstrip())
278 279 print("Couldn't evaluate or find in history:", arg)
279 280
280 281 @line_magic
281 282 def rerun(self, parameter_s=''):
282 283 """Re-run previous input
283 284
284 285 By default, you can specify ranges of input history to be repeated
285 286 (as with %history). With no arguments, it will repeat the last line.
286 287
287 288 Options:
288 289
289 290 -l <n> : Repeat the last n lines of input, not including the
290 291 current command.
291 292
292 293 -g foo : Repeat the most recent line which contains foo
293 294 """
294 295 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
295 296 if "l" in opts: # Last n lines
296 297 n = int(opts['l'])
297 298 hist = self.shell.history_manager.get_tail(n)
298 299 elif "g" in opts: # Search
299 300 p = "*"+opts['g']+"*"
300 301 hist = list(self.shell.history_manager.search(p))
301 302 for l in reversed(hist):
302 303 if "rerun" not in l[2]:
303 304 hist = [l] # The last match which isn't a %rerun
304 305 break
305 306 else:
306 307 hist = [] # No matches except %rerun
307 308 elif args: # Specify history ranges
308 309 hist = self.shell.history_manager.get_range_by_str(args)
309 310 else: # Last line
310 311 hist = self.shell.history_manager.get_tail(1)
311 312 hist = [x[2] for x in hist]
312 313 if not hist:
313 314 print("No lines in history match specification")
314 315 return
315 316 histlines = "\n".join(hist)
316 317 print("=== Executing: ===")
317 318 print(histlines)
318 319 print("=== Output: ===")
319 320 self.shell.run_cell("\n".join(hist), store_history=False)
@@ -1,929 +1,928 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for inspecting Python objects.
3 3
4 4 Uses syntax highlighting for presenting the various information elements.
5 5
6 6 Similar in spirit to the inspect module, but all calls take a name argument to
7 7 reference the name under which an object is being read.
8 8 """
9 9
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 from __future__ import print_function
14 14
15 15 __all__ = ['Inspector','InspectColors']
16 16
17 17 # stdlib modules
18 18 import inspect
19 19 import linecache
20 20 import os
21 21 from textwrap import dedent
22 22 import types
23 23 import io as stdlib_io
24 24
25 25 try:
26 26 from itertools import izip_longest
27 27 except ImportError:
28 28 from itertools import zip_longest as izip_longest
29 29
30 30 # IPython's own
31 31 from IPython.core import page
32 32 from IPython.lib.pretty import pretty
33 33 from IPython.testing.skipdoctest import skip_doctest_py3
34 34 from IPython.utils import PyColorize
35 from IPython.utils import io
36 35 from IPython.utils import openpy
37 36 from IPython.utils import py3compat
38 37 from IPython.utils.dir2 import safe_hasattr
39 38 from IPython.utils.path import compress_user
40 39 from IPython.utils.text import indent
41 40 from IPython.utils.wildcard import list_namespace
42 41 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
43 42 from IPython.utils.py3compat import cast_unicode, string_types, PY3
44 43 from IPython.utils.signatures import signature
45 44 from IPython.utils.colorable import Colorable
46 45
47 46 # builtin docstrings to ignore
48 47 _func_call_docstring = types.FunctionType.__call__.__doc__
49 48 _object_init_docstring = object.__init__.__doc__
50 49 _builtin_type_docstrings = {
51 50 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
52 51 types.FunctionType, property)
53 52 }
54 53
55 54 _builtin_func_type = type(all)
56 55 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
57 56 #****************************************************************************
58 57 # Builtin color schemes
59 58
60 59 Colors = TermColors # just a shorthand
61 60
62 61 InspectColors = PyColorize.ANSICodeColors
63 62
64 63 #****************************************************************************
65 64 # Auxiliary functions and objects
66 65
67 66 # See the messaging spec for the definition of all these fields. This list
68 67 # effectively defines the order of display
69 68 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
70 69 'length', 'file', 'definition', 'docstring', 'source',
71 70 'init_definition', 'class_docstring', 'init_docstring',
72 71 'call_def', 'call_docstring',
73 72 # These won't be printed but will be used to determine how to
74 73 # format the object
75 74 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
76 75 ]
77 76
78 77
79 78 def object_info(**kw):
80 79 """Make an object info dict with all fields present."""
81 80 infodict = dict(izip_longest(info_fields, [None]))
82 81 infodict.update(kw)
83 82 return infodict
84 83
85 84
86 85 def get_encoding(obj):
87 86 """Get encoding for python source file defining obj
88 87
89 88 Returns None if obj is not defined in a sourcefile.
90 89 """
91 90 ofile = find_file(obj)
92 91 # run contents of file through pager starting at line where the object
93 92 # is defined, as long as the file isn't binary and is actually on the
94 93 # filesystem.
95 94 if ofile is None:
96 95 return None
97 96 elif ofile.endswith(('.so', '.dll', '.pyd')):
98 97 return None
99 98 elif not os.path.isfile(ofile):
100 99 return None
101 100 else:
102 101 # Print only text files, not extension binaries. Note that
103 102 # getsourcelines returns lineno with 1-offset and page() uses
104 103 # 0-offset, so we must adjust.
105 104 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
106 105 encoding, lines = openpy.detect_encoding(buffer.readline)
107 106 return encoding
108 107
109 108 def getdoc(obj):
110 109 """Stable wrapper around inspect.getdoc.
111 110
112 111 This can't crash because of attribute problems.
113 112
114 113 It also attempts to call a getdoc() method on the given object. This
115 114 allows objects which provide their docstrings via non-standard mechanisms
116 115 (like Pyro proxies) to still be inspected by ipython's ? system."""
117 116 # Allow objects to offer customized documentation via a getdoc method:
118 117 try:
119 118 ds = obj.getdoc()
120 119 except Exception:
121 120 pass
122 121 else:
123 122 # if we get extra info, we add it to the normal docstring.
124 123 if isinstance(ds, string_types):
125 124 return inspect.cleandoc(ds)
126 125
127 126 try:
128 127 docstr = inspect.getdoc(obj)
129 128 encoding = get_encoding(obj)
130 129 return py3compat.cast_unicode(docstr, encoding=encoding)
131 130 except Exception:
132 131 # Harden against an inspect failure, which can occur with
133 132 # SWIG-wrapped extensions.
134 133 raise
135 134 return None
136 135
137 136
138 137 def getsource(obj, oname=''):
139 138 """Wrapper around inspect.getsource.
140 139
141 140 This can be modified by other projects to provide customized source
142 141 extraction.
143 142
144 143 Parameters
145 144 ----------
146 145 obj : object
147 146 an object whose source code we will attempt to extract
148 147 oname : str
149 148 (optional) a name under which the object is known
150 149
151 150 Returns
152 151 -------
153 152 src : unicode or None
154 153
155 154 """
156 155
157 156 if isinstance(obj, property):
158 157 sources = []
159 158 for attrname in ['fget', 'fset', 'fdel']:
160 159 fn = getattr(obj, attrname)
161 160 if fn is not None:
162 161 encoding = get_encoding(fn)
163 162 oname_prefix = ('%s.' % oname) if oname else ''
164 163 sources.append(cast_unicode(
165 164 ''.join(('# ', oname_prefix, attrname)),
166 165 encoding=encoding))
167 166 if inspect.isfunction(fn):
168 167 sources.append(dedent(getsource(fn)))
169 168 else:
170 169 # Default str/repr only prints function name,
171 170 # pretty.pretty prints module name too.
172 171 sources.append(cast_unicode(
173 172 '%s%s = %s\n' % (
174 173 oname_prefix, attrname, pretty(fn)),
175 174 encoding=encoding))
176 175 if sources:
177 176 return '\n'.join(sources)
178 177 else:
179 178 return None
180 179
181 180 else:
182 181 # Get source for non-property objects.
183 182
184 183 obj = _get_wrapped(obj)
185 184
186 185 try:
187 186 src = inspect.getsource(obj)
188 187 except TypeError:
189 188 # The object itself provided no meaningful source, try looking for
190 189 # its class definition instead.
191 190 if hasattr(obj, '__class__'):
192 191 try:
193 192 src = inspect.getsource(obj.__class__)
194 193 except TypeError:
195 194 return None
196 195
197 196 encoding = get_encoding(obj)
198 197 return cast_unicode(src, encoding=encoding)
199 198
200 199
201 200 def is_simple_callable(obj):
202 201 """True if obj is a function ()"""
203 202 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
204 203 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
205 204
206 205
207 206 def getargspec(obj):
208 207 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
209 208 :func:inspect.getargspec` on Python 2.
210 209
211 210 In addition to functions and methods, this can also handle objects with a
212 211 ``__call__`` attribute.
213 212 """
214 213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
215 214 obj = obj.__call__
216 215
217 216 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
218 217
219 218
220 219 def format_argspec(argspec):
221 220 """Format argspect, convenience wrapper around inspect's.
222 221
223 222 This takes a dict instead of ordered arguments and calls
224 223 inspect.format_argspec with the arguments in the necessary order.
225 224 """
226 225 return inspect.formatargspec(argspec['args'], argspec['varargs'],
227 226 argspec['varkw'], argspec['defaults'])
228 227
229 228
230 229 def call_tip(oinfo, format_call=True):
231 230 """Extract call tip data from an oinfo dict.
232 231
233 232 Parameters
234 233 ----------
235 234 oinfo : dict
236 235
237 236 format_call : bool, optional
238 237 If True, the call line is formatted and returned as a string. If not, a
239 238 tuple of (name, argspec) is returned.
240 239
241 240 Returns
242 241 -------
243 242 call_info : None, str or (str, dict) tuple.
244 243 When format_call is True, the whole call information is formattted as a
245 244 single string. Otherwise, the object's name and its argspec dict are
246 245 returned. If no call information is available, None is returned.
247 246
248 247 docstring : str or None
249 248 The most relevant docstring for calling purposes is returned, if
250 249 available. The priority is: call docstring for callable instances, then
251 250 constructor docstring for classes, then main object's docstring otherwise
252 251 (regular functions).
253 252 """
254 253 # Get call definition
255 254 argspec = oinfo.get('argspec')
256 255 if argspec is None:
257 256 call_line = None
258 257 else:
259 258 # Callable objects will have 'self' as their first argument, prune
260 259 # it out if it's there for clarity (since users do *not* pass an
261 260 # extra first argument explicitly).
262 261 try:
263 262 has_self = argspec['args'][0] == 'self'
264 263 except (KeyError, IndexError):
265 264 pass
266 265 else:
267 266 if has_self:
268 267 argspec['args'] = argspec['args'][1:]
269 268
270 269 call_line = oinfo['name']+format_argspec(argspec)
271 270
272 271 # Now get docstring.
273 272 # The priority is: call docstring, constructor docstring, main one.
274 273 doc = oinfo.get('call_docstring')
275 274 if doc is None:
276 275 doc = oinfo.get('init_docstring')
277 276 if doc is None:
278 277 doc = oinfo.get('docstring','')
279 278
280 279 return call_line, doc
281 280
282 281
283 282 def _get_wrapped(obj):
284 283 """Get the original object if wrapped in one or more @decorators
285 284
286 285 Some objects automatically construct similar objects on any unrecognised
287 286 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
288 287 this will arbitrarily cut off after 100 levels of obj.__wrapped__
289 288 attribute access. --TK, Jan 2016
290 289 """
291 290 orig_obj = obj
292 291 i = 0
293 292 while safe_hasattr(obj, '__wrapped__'):
294 293 obj = obj.__wrapped__
295 294 i += 1
296 295 if i > 100:
297 296 # __wrapped__ is probably a lie, so return the thing we started with
298 297 return orig_obj
299 298 return obj
300 299
301 300 def find_file(obj):
302 301 """Find the absolute path to the file where an object was defined.
303 302
304 303 This is essentially a robust wrapper around `inspect.getabsfile`.
305 304
306 305 Returns None if no file can be found.
307 306
308 307 Parameters
309 308 ----------
310 309 obj : any Python object
311 310
312 311 Returns
313 312 -------
314 313 fname : str
315 314 The absolute path to the file where the object was defined.
316 315 """
317 316 obj = _get_wrapped(obj)
318 317
319 318 fname = None
320 319 try:
321 320 fname = inspect.getabsfile(obj)
322 321 except TypeError:
323 322 # For an instance, the file that matters is where its class was
324 323 # declared.
325 324 if hasattr(obj, '__class__'):
326 325 try:
327 326 fname = inspect.getabsfile(obj.__class__)
328 327 except TypeError:
329 328 # Can happen for builtins
330 329 pass
331 330 except:
332 331 pass
333 332 return cast_unicode(fname)
334 333
335 334
336 335 def find_source_lines(obj):
337 336 """Find the line number in a file where an object was defined.
338 337
339 338 This is essentially a robust wrapper around `inspect.getsourcelines`.
340 339
341 340 Returns None if no file can be found.
342 341
343 342 Parameters
344 343 ----------
345 344 obj : any Python object
346 345
347 346 Returns
348 347 -------
349 348 lineno : int
350 349 The line number where the object definition starts.
351 350 """
352 351 obj = _get_wrapped(obj)
353 352
354 353 try:
355 354 try:
356 355 lineno = inspect.getsourcelines(obj)[1]
357 356 except TypeError:
358 357 # For instances, try the class object like getsource() does
359 358 if hasattr(obj, '__class__'):
360 359 lineno = inspect.getsourcelines(obj.__class__)[1]
361 360 else:
362 361 lineno = None
363 362 except:
364 363 return None
365 364
366 365 return lineno
367 366
368 367
369 368 class Inspector(Colorable):
370 369 def __init__(self, color_table=InspectColors,
371 370 code_color_table=PyColorize.ANSICodeColors,
372 371 scheme='NoColor',
373 372 str_detail_level=0,
374 373 parent=None, config=None):
375 374 super(Inspector, self).__init__(parent=parent, config=config)
376 375 self.color_table = color_table
377 376 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
378 377 self.format = self.parser.format
379 378 self.str_detail_level = str_detail_level
380 379 self.set_active_scheme(scheme)
381 380
382 381 def _getdef(self,obj,oname=''):
383 382 """Return the call signature for any callable object.
384 383
385 384 If any exception is generated, None is returned instead and the
386 385 exception is suppressed."""
387 386 try:
388 387 hdef = oname + str(signature(obj))
389 388 return cast_unicode(hdef)
390 389 except:
391 390 return None
392 391
393 392 def __head(self,h):
394 393 """Return a header string with proper colors."""
395 394 return '%s%s%s' % (self.color_table.active_colors.header,h,
396 395 self.color_table.active_colors.normal)
397 396
398 397 def set_active_scheme(self, scheme):
399 398 self.color_table.set_active_scheme(scheme)
400 399 self.parser.color_table.set_active_scheme(scheme)
401 400
402 401 def noinfo(self, msg, oname):
403 402 """Generic message when no information is found."""
404 403 print('No %s found' % msg, end=' ')
405 404 if oname:
406 405 print('for %s' % oname)
407 406 else:
408 407 print()
409 408
410 409 def pdef(self, obj, oname=''):
411 410 """Print the call signature for any callable object.
412 411
413 412 If the object is a class, print the constructor information."""
414 413
415 414 if not callable(obj):
416 415 print('Object is not callable.')
417 416 return
418 417
419 418 header = ''
420 419
421 420 if inspect.isclass(obj):
422 421 header = self.__head('Class constructor information:\n')
423 422 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
424 423 obj = obj.__call__
425 424
426 425 output = self._getdef(obj,oname)
427 426 if output is None:
428 427 self.noinfo('definition header',oname)
429 428 else:
430 print(header,self.format(output), end=' ', file=io.stdout)
429 print(header,self.format(output), end=' ')
431 430
432 431 # In Python 3, all classes are new-style, so they all have __init__.
433 432 @skip_doctest_py3
434 433 def pdoc(self,obj,oname='',formatter = None):
435 434 """Print the docstring for any object.
436 435
437 436 Optional:
438 437 -formatter: a function to run the docstring through for specially
439 438 formatted docstrings.
440 439
441 440 Examples
442 441 --------
443 442
444 443 In [1]: class NoInit:
445 444 ...: pass
446 445
447 446 In [2]: class NoDoc:
448 447 ...: def __init__(self):
449 448 ...: pass
450 449
451 450 In [3]: %pdoc NoDoc
452 451 No documentation found for NoDoc
453 452
454 453 In [4]: %pdoc NoInit
455 454 No documentation found for NoInit
456 455
457 456 In [5]: obj = NoInit()
458 457
459 458 In [6]: %pdoc obj
460 459 No documentation found for obj
461 460
462 461 In [5]: obj2 = NoDoc()
463 462
464 463 In [6]: %pdoc obj2
465 464 No documentation found for obj2
466 465 """
467 466
468 467 head = self.__head # For convenience
469 468 lines = []
470 469 ds = getdoc(obj)
471 470 if formatter:
472 471 ds = formatter(ds)
473 472 if ds:
474 473 lines.append(head("Class docstring:"))
475 474 lines.append(indent(ds))
476 475 if inspect.isclass(obj) and hasattr(obj, '__init__'):
477 476 init_ds = getdoc(obj.__init__)
478 477 if init_ds is not None:
479 478 lines.append(head("Init docstring:"))
480 479 lines.append(indent(init_ds))
481 480 elif hasattr(obj,'__call__'):
482 481 call_ds = getdoc(obj.__call__)
483 482 if call_ds:
484 483 lines.append(head("Call docstring:"))
485 484 lines.append(indent(call_ds))
486 485
487 486 if not lines:
488 487 self.noinfo('documentation',oname)
489 488 else:
490 489 page.page('\n'.join(lines))
491 490
492 491 def psource(self, obj, oname=''):
493 492 """Print the source code for an object."""
494 493
495 494 # Flush the source cache because inspect can return out-of-date source
496 495 linecache.checkcache()
497 496 try:
498 497 src = getsource(obj, oname=oname)
499 498 except Exception:
500 499 src = None
501 500
502 501 if src is None:
503 502 self.noinfo('source', oname)
504 503 else:
505 504 page.page(self.format(src))
506 505
507 506 def pfile(self, obj, oname=''):
508 507 """Show the whole file where an object was defined."""
509 508
510 509 lineno = find_source_lines(obj)
511 510 if lineno is None:
512 511 self.noinfo('file', oname)
513 512 return
514 513
515 514 ofile = find_file(obj)
516 515 # run contents of file through pager starting at line where the object
517 516 # is defined, as long as the file isn't binary and is actually on the
518 517 # filesystem.
519 518 if ofile.endswith(('.so', '.dll', '.pyd')):
520 519 print('File %r is binary, not printing.' % ofile)
521 520 elif not os.path.isfile(ofile):
522 521 print('File %r does not exist, not printing.' % ofile)
523 522 else:
524 523 # Print only text files, not extension binaries. Note that
525 524 # getsourcelines returns lineno with 1-offset and page() uses
526 525 # 0-offset, so we must adjust.
527 526 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
528 527
529 528 def _format_fields(self, fields, title_width=0):
530 529 """Formats a list of fields for display.
531 530
532 531 Parameters
533 532 ----------
534 533 fields : list
535 534 A list of 2-tuples: (field_title, field_content)
536 535 title_width : int
537 536 How many characters to pad titles to. Default to longest title.
538 537 """
539 538 out = []
540 539 header = self.__head
541 540 if title_width == 0:
542 541 title_width = max(len(title) + 2 for title, _ in fields)
543 542 for title, content in fields:
544 543 if len(content.splitlines()) > 1:
545 544 title = header(title + ":") + "\n"
546 545 else:
547 546 title = header((title+":").ljust(title_width))
548 547 out.append(cast_unicode(title) + cast_unicode(content))
549 548 return "\n".join(out)
550 549
551 550 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
552 551 """Format an info dict as text"""
553 552 info = self.info(obj, oname=oname, formatter=formatter,
554 553 info=info, detail_level=detail_level)
555 554 displayfields = []
556 555 def add_fields(fields):
557 556 for title, key in fields:
558 557 field = info[key]
559 558 if field is not None:
560 559 if key == "source":
561 560 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
562 561 else:
563 562 displayfields.append((title, field.rstrip()))
564 563
565 564 if info['isalias']:
566 565 add_fields([('Repr', "string_form")])
567 566
568 567 elif info['ismagic']:
569 568 if detail_level > 0 and info['source'] is not None:
570 569 add_fields([("Source", "source")])
571 570 else:
572 571 add_fields([("Docstring", "docstring")])
573 572
574 573 add_fields([("File", "file"),
575 574 ])
576 575
577 576 elif info['isclass'] or is_simple_callable(obj):
578 577 # Functions, methods, classes
579 578 add_fields([("Signature", "definition"),
580 579 ("Init signature", "init_definition"),
581 580 ])
582 581 if detail_level > 0 and info['source'] is not None:
583 582 add_fields([("Source", "source")])
584 583 else:
585 584 add_fields([("Docstring", "docstring"),
586 585 ("Init docstring", "init_docstring"),
587 586 ])
588 587
589 588 add_fields([('File', 'file'),
590 589 ('Type', 'type_name'),
591 590 ])
592 591
593 592 else:
594 593 # General Python objects
595 594 add_fields([("Type", "type_name")])
596 595
597 596 # Base class for old-style instances
598 597 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
599 598 displayfields.append(("Base Class", info['base_class'].rstrip()))
600 599
601 600 add_fields([("String form", "string_form")])
602 601
603 602 # Namespace
604 603 if info['namespace'] != 'Interactive':
605 604 displayfields.append(("Namespace", info['namespace'].rstrip()))
606 605
607 606 add_fields([("Length", "length"),
608 607 ("File", "file"),
609 608 ("Signature", "definition"),
610 609 ])
611 610
612 611 # Source or docstring, depending on detail level and whether
613 612 # source found.
614 613 if detail_level > 0 and info['source'] is not None:
615 614 displayfields.append(("Source",
616 615 self.format(cast_unicode(info['source']))))
617 616 elif info['docstring'] is not None:
618 617 displayfields.append(("Docstring", info["docstring"]))
619 618
620 619 add_fields([("Class docstring", "class_docstring"),
621 620 ("Init docstring", "init_docstring"),
622 621 ("Call signature", "call_def"),
623 622 ("Call docstring", "call_docstring")])
624 623
625 624 if displayfields:
626 625 return self._format_fields(displayfields)
627 626 else:
628 627 return u''
629 628
630 629 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
631 630 """Show detailed information about an object.
632 631
633 632 Optional arguments:
634 633
635 634 - oname: name of the variable pointing to the object.
636 635
637 636 - formatter: special formatter for docstrings (see pdoc)
638 637
639 638 - info: a structure with some information fields which may have been
640 639 precomputed already.
641 640
642 641 - detail_level: if set to 1, more information is given.
643 642 """
644 643 text = self._format_info(obj, oname, formatter, info, detail_level)
645 644 if text:
646 645 page.page(text)
647 646
648 647 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
649 648 """Compute a dict with detailed information about an object.
650 649
651 650 Optional arguments:
652 651
653 652 - oname: name of the variable pointing to the object.
654 653
655 654 - formatter: special formatter for docstrings (see pdoc)
656 655
657 656 - info: a structure with some information fields which may have been
658 657 precomputed already.
659 658
660 659 - detail_level: if set to 1, more information is given.
661 660 """
662 661
663 662 obj_type = type(obj)
664 663
665 664 if info is None:
666 665 ismagic = 0
667 666 isalias = 0
668 667 ospace = ''
669 668 else:
670 669 ismagic = info.ismagic
671 670 isalias = info.isalias
672 671 ospace = info.namespace
673 672
674 673 # Get docstring, special-casing aliases:
675 674 if isalias:
676 675 if not callable(obj):
677 676 try:
678 677 ds = "Alias to the system command:\n %s" % obj[1]
679 678 except:
680 679 ds = "Alias: " + str(obj)
681 680 else:
682 681 ds = "Alias to " + str(obj)
683 682 if obj.__doc__:
684 683 ds += "\nDocstring:\n" + obj.__doc__
685 684 else:
686 685 ds = getdoc(obj)
687 686 if ds is None:
688 687 ds = '<no docstring>'
689 688 if formatter is not None:
690 689 ds = formatter(ds)
691 690
692 691 # store output in a dict, we initialize it here and fill it as we go
693 692 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
694 693
695 694 string_max = 200 # max size of strings to show (snipped if longer)
696 695 shalf = int((string_max -5)/2)
697 696
698 697 if ismagic:
699 698 obj_type_name = 'Magic function'
700 699 elif isalias:
701 700 obj_type_name = 'System alias'
702 701 else:
703 702 obj_type_name = obj_type.__name__
704 703 out['type_name'] = obj_type_name
705 704
706 705 try:
707 706 bclass = obj.__class__
708 707 out['base_class'] = str(bclass)
709 708 except: pass
710 709
711 710 # String form, but snip if too long in ? form (full in ??)
712 711 if detail_level >= self.str_detail_level:
713 712 try:
714 713 ostr = str(obj)
715 714 str_head = 'string_form'
716 715 if not detail_level and len(ostr)>string_max:
717 716 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
718 717 ostr = ("\n" + " " * len(str_head.expandtabs())).\
719 718 join(q.strip() for q in ostr.split("\n"))
720 719 out[str_head] = ostr
721 720 except:
722 721 pass
723 722
724 723 if ospace:
725 724 out['namespace'] = ospace
726 725
727 726 # Length (for strings and lists)
728 727 try:
729 728 out['length'] = str(len(obj))
730 729 except: pass
731 730
732 731 # Filename where object was defined
733 732 binary_file = False
734 733 fname = find_file(obj)
735 734 if fname is None:
736 735 # if anything goes wrong, we don't want to show source, so it's as
737 736 # if the file was binary
738 737 binary_file = True
739 738 else:
740 739 if fname.endswith(('.so', '.dll', '.pyd')):
741 740 binary_file = True
742 741 elif fname.endswith('<string>'):
743 742 fname = 'Dynamically generated function. No source code available.'
744 743 out['file'] = compress_user(fname)
745 744
746 745 # Original source code for a callable, class or property.
747 746 if detail_level:
748 747 # Flush the source cache because inspect can return out-of-date
749 748 # source
750 749 linecache.checkcache()
751 750 try:
752 751 if isinstance(obj, property) or not binary_file:
753 752 src = getsource(obj, oname)
754 753 if src is not None:
755 754 src = src.rstrip()
756 755 out['source'] = src
757 756
758 757 except Exception:
759 758 pass
760 759
761 760 # Add docstring only if no source is to be shown (avoid repetitions).
762 761 if ds and out.get('source', None) is None:
763 762 out['docstring'] = ds
764 763
765 764 # Constructor docstring for classes
766 765 if inspect.isclass(obj):
767 766 out['isclass'] = True
768 767
769 768 # get the init signature:
770 769 try:
771 770 init_def = self._getdef(obj, oname)
772 771 except AttributeError:
773 772 init_def = None
774 773
775 774 if init_def:
776 775 out['init_definition'] = self.format(init_def)
777 776
778 777 # get the __init__ docstring
779 778 try:
780 779 obj_init = obj.__init__
781 780 except AttributeError:
782 781 init_ds = None
783 782 else:
784 783 init_ds = getdoc(obj_init)
785 784 # Skip Python's auto-generated docstrings
786 785 if init_ds == _object_init_docstring:
787 786 init_ds = None
788 787
789 788 if init_ds:
790 789 out['init_docstring'] = init_ds
791 790
792 791 # and class docstring for instances:
793 792 else:
794 793 # reconstruct the function definition and print it:
795 794 defln = self._getdef(obj, oname)
796 795 if defln:
797 796 out['definition'] = self.format(defln)
798 797
799 798 # First, check whether the instance docstring is identical to the
800 799 # class one, and print it separately if they don't coincide. In
801 800 # most cases they will, but it's nice to print all the info for
802 801 # objects which use instance-customized docstrings.
803 802 if ds:
804 803 try:
805 804 cls = getattr(obj,'__class__')
806 805 except:
807 806 class_ds = None
808 807 else:
809 808 class_ds = getdoc(cls)
810 809 # Skip Python's auto-generated docstrings
811 810 if class_ds in _builtin_type_docstrings:
812 811 class_ds = None
813 812 if class_ds and ds != class_ds:
814 813 out['class_docstring'] = class_ds
815 814
816 815 # Next, try to show constructor docstrings
817 816 try:
818 817 init_ds = getdoc(obj.__init__)
819 818 # Skip Python's auto-generated docstrings
820 819 if init_ds == _object_init_docstring:
821 820 init_ds = None
822 821 except AttributeError:
823 822 init_ds = None
824 823 if init_ds:
825 824 out['init_docstring'] = init_ds
826 825
827 826 # Call form docstring for callable instances
828 827 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
829 828 call_def = self._getdef(obj.__call__, oname)
830 829 if call_def:
831 830 call_def = self.format(call_def)
832 831 # it may never be the case that call def and definition differ,
833 832 # but don't include the same signature twice
834 833 if call_def != out.get('definition'):
835 834 out['call_def'] = call_def
836 835 call_ds = getdoc(obj.__call__)
837 836 # Skip Python's auto-generated docstrings
838 837 if call_ds == _func_call_docstring:
839 838 call_ds = None
840 839 if call_ds:
841 840 out['call_docstring'] = call_ds
842 841
843 842 # Compute the object's argspec as a callable. The key is to decide
844 843 # whether to pull it from the object itself, from its __init__ or
845 844 # from its __call__ method.
846 845
847 846 if inspect.isclass(obj):
848 847 # Old-style classes need not have an __init__
849 848 callable_obj = getattr(obj, "__init__", None)
850 849 elif callable(obj):
851 850 callable_obj = obj
852 851 else:
853 852 callable_obj = None
854 853
855 854 if callable_obj is not None:
856 855 try:
857 856 argspec = getargspec(callable_obj)
858 857 except (TypeError, AttributeError):
859 858 # For extensions/builtins we can't retrieve the argspec
860 859 pass
861 860 else:
862 861 # named tuples' _asdict() method returns an OrderedDict, but we
863 862 # we want a normal
864 863 out['argspec'] = argspec_dict = dict(argspec._asdict())
865 864 # We called this varkw before argspec became a named tuple.
866 865 # With getfullargspec it's also called varkw.
867 866 if 'varkw' not in argspec_dict:
868 867 argspec_dict['varkw'] = argspec_dict.pop('keywords')
869 868
870 869 return object_info(**out)
871 870
872 871 def psearch(self,pattern,ns_table,ns_search=[],
873 872 ignore_case=False,show_all=False):
874 873 """Search namespaces with wildcards for objects.
875 874
876 875 Arguments:
877 876
878 877 - pattern: string containing shell-like wildcards to use in namespace
879 878 searches and optionally a type specification to narrow the search to
880 879 objects of that type.
881 880
882 881 - ns_table: dict of name->namespaces for search.
883 882
884 883 Optional arguments:
885 884
886 885 - ns_search: list of namespace names to include in search.
887 886
888 887 - ignore_case(False): make the search case-insensitive.
889 888
890 889 - show_all(False): show all names, including those starting with
891 890 underscores.
892 891 """
893 892 #print 'ps pattern:<%r>' % pattern # dbg
894 893
895 894 # defaults
896 895 type_pattern = 'all'
897 896 filter = ''
898 897
899 898 cmds = pattern.split()
900 899 len_cmds = len(cmds)
901 900 if len_cmds == 1:
902 901 # Only filter pattern given
903 902 filter = cmds[0]
904 903 elif len_cmds == 2:
905 904 # Both filter and type specified
906 905 filter,type_pattern = cmds
907 906 else:
908 907 raise ValueError('invalid argument string for psearch: <%s>' %
909 908 pattern)
910 909
911 910 # filter search namespaces
912 911 for name in ns_search:
913 912 if name not in ns_table:
914 913 raise ValueError('invalid namespace <%s>. Valid names: %s' %
915 914 (name,ns_table.keys()))
916 915
917 916 #print 'type_pattern:',type_pattern # dbg
918 917 search_result, namespaces_seen = set(), set()
919 918 for ns_name in ns_search:
920 919 ns = ns_table[ns_name]
921 920 # Normally, locals and globals are the same, so we just check one.
922 921 if id(ns) in namespaces_seen:
923 922 continue
924 923 namespaces_seen.add(id(ns))
925 924 tmp_res = list_namespace(ns, type_pattern, filter,
926 925 ignore_case=ignore_case, show_all=show_all)
927 926 search_result.update(tmp_res)
928 927
929 928 page.page('\n'.join(sorted(search_result)))
@@ -1,385 +1,384 b''
1 1 # encoding: utf-8
2 2 """
3 3 Paging capabilities for IPython.core
4 4
5 5 Notes
6 6 -----
7 7
8 8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
9 9 rid of that dependency, we could move it there.
10 10 -----
11 11 """
12 12
13 13 # Copyright (c) IPython Development Team.
14 14 # Distributed under the terms of the Modified BSD License.
15 15
16 16 from __future__ import print_function
17 17
18 18 import os
19 19 import re
20 20 import sys
21 21 import tempfile
22 22
23 23 from io import UnsupportedOperation
24 24
25 25 from IPython import get_ipython
26 26 from IPython.core.display import display
27 27 from IPython.core.error import TryNext
28 28 from IPython.utils.data import chop
29 from IPython.utils import io
30 29 from IPython.utils.process import system
31 30 from IPython.utils.terminal import get_terminal_size
32 31 from IPython.utils import py3compat
33 32
34 33
35 34 def display_page(strng, start=0, screen_lines=25):
36 35 """Just display, no paging. screen_lines is ignored."""
37 36 if isinstance(strng, dict):
38 37 data = strng
39 38 else:
40 39 if start:
41 40 strng = u'\n'.join(strng.splitlines()[start:])
42 41 data = {'text/plain': strng}
43 42 display(data, raw=True)
44 43
45 44
46 45 def as_hook(page_func):
47 46 """Wrap a pager func to strip the `self` arg
48 47
49 48 so it can be called as a hook.
50 49 """
51 50 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
52 51
53 52
54 53 esc_re = re.compile(r"(\x1b[^m]+m)")
55 54
56 55 def page_dumb(strng, start=0, screen_lines=25):
57 56 """Very dumb 'pager' in Python, for when nothing else works.
58 57
59 58 Only moves forward, same interface as page(), except for pager_cmd and
60 59 mode."""
61 60
62 61 out_ln = strng.splitlines()[start:]
63 62 screens = chop(out_ln,screen_lines-1)
64 63 if len(screens) == 1:
65 print(os.linesep.join(screens[0]), file=io.stdout)
64 print(os.linesep.join(screens[0]))
66 65 else:
67 66 last_escape = ""
68 67 for scr in screens[0:-1]:
69 68 hunk = os.linesep.join(scr)
70 print(last_escape + hunk, file=io.stdout)
69 print(last_escape + hunk)
71 70 if not page_more():
72 71 return
73 72 esc_list = esc_re.findall(hunk)
74 73 if len(esc_list) > 0:
75 74 last_escape = esc_list[-1]
76 print(last_escape + os.linesep.join(screens[-1]), file=io.stdout)
75 print(last_escape + os.linesep.join(screens[-1]))
77 76
78 77 def _detect_screen_size(screen_lines_def):
79 78 """Attempt to work out the number of lines on the screen.
80 79
81 80 This is called by page(). It can raise an error (e.g. when run in the
82 81 test suite), so it's separated out so it can easily be called in a try block.
83 82 """
84 83 TERM = os.environ.get('TERM',None)
85 84 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
86 85 # curses causes problems on many terminals other than xterm, and
87 86 # some termios calls lock up on Sun OS5.
88 87 return screen_lines_def
89 88
90 89 try:
91 90 import termios
92 91 import curses
93 92 except ImportError:
94 93 return screen_lines_def
95 94
96 95 # There is a bug in curses, where *sometimes* it fails to properly
97 96 # initialize, and then after the endwin() call is made, the
98 97 # terminal is left in an unusable state. Rather than trying to
99 98 # check everytime for this (by requesting and comparing termios
100 99 # flags each time), we just save the initial terminal state and
101 100 # unconditionally reset it every time. It's cheaper than making
102 101 # the checks.
103 102 try:
104 103 term_flags = termios.tcgetattr(sys.stdout)
105 104 except termios.error as err:
106 105 # can fail on Linux 2.6, pager_page will catch the TypeError
107 106 raise TypeError('termios error: {0}'.format(err))
108 107
109 108 # Curses modifies the stdout buffer size by default, which messes
110 109 # up Python's normal stdout buffering. This would manifest itself
111 110 # to IPython users as delayed printing on stdout after having used
112 111 # the pager.
113 112 #
114 113 # We can prevent this by manually setting the NCURSES_NO_SETBUF
115 114 # environment variable. For more details, see:
116 115 # http://bugs.python.org/issue10144
117 116 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
118 117 os.environ['NCURSES_NO_SETBUF'] = ''
119 118
120 119 # Proceed with curses initialization
121 120 try:
122 121 scr = curses.initscr()
123 122 except AttributeError:
124 123 # Curses on Solaris may not be complete, so we can't use it there
125 124 return screen_lines_def
126 125
127 126 screen_lines_real,screen_cols = scr.getmaxyx()
128 127 curses.endwin()
129 128
130 129 # Restore environment
131 130 if NCURSES_NO_SETBUF is None:
132 131 del os.environ['NCURSES_NO_SETBUF']
133 132 else:
134 133 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
135 134
136 135 # Restore terminal state in case endwin() didn't.
137 136 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
138 137 # Now we have what we needed: the screen size in rows/columns
139 138 return screen_lines_real
140 139 #print '***Screen size:',screen_lines_real,'lines x',\
141 140 #screen_cols,'columns.' # dbg
142 141
143 142 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
144 143 """Display a string, piping through a pager after a certain length.
145 144
146 145 strng can be a mime-bundle dict, supplying multiple representations,
147 146 keyed by mime-type.
148 147
149 148 The screen_lines parameter specifies the number of *usable* lines of your
150 149 terminal screen (total lines minus lines you need to reserve to show other
151 150 information).
152 151
153 152 If you set screen_lines to a number <=0, page() will try to auto-determine
154 153 your screen size and will only use up to (screen_size+screen_lines) for
155 154 printing, paging after that. That is, if you want auto-detection but need
156 155 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
157 156 auto-detection without any lines reserved simply use screen_lines = 0.
158 157
159 158 If a string won't fit in the allowed lines, it is sent through the
160 159 specified pager command. If none given, look for PAGER in the environment,
161 160 and ultimately default to less.
162 161
163 162 If no system pager works, the string is sent through a 'dumb pager'
164 163 written in python, very simplistic.
165 164 """
166 165
167 166 # for compatibility with mime-bundle form:
168 167 if isinstance(strng, dict):
169 168 strng = strng['text/plain']
170 169
171 170 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
172 171 TERM = os.environ.get('TERM','dumb')
173 172 if TERM in ['dumb','emacs'] and os.name != 'nt':
174 173 print(strng)
175 174 return
176 175 # chop off the topmost part of the string we don't want to see
177 176 str_lines = strng.splitlines()[start:]
178 177 str_toprint = os.linesep.join(str_lines)
179 178 num_newlines = len(str_lines)
180 179 len_str = len(str_toprint)
181 180
182 181 # Dumb heuristics to guesstimate number of on-screen lines the string
183 182 # takes. Very basic, but good enough for docstrings in reasonable
184 183 # terminals. If someone later feels like refining it, it's not hard.
185 184 numlines = max(num_newlines,int(len_str/80)+1)
186 185
187 186 screen_lines_def = get_terminal_size()[1]
188 187
189 188 # auto-determine screen size
190 189 if screen_lines <= 0:
191 190 try:
192 191 screen_lines += _detect_screen_size(screen_lines_def)
193 192 except (TypeError, UnsupportedOperation):
194 print(str_toprint, file=io.stdout)
193 print(str_toprint)
195 194 return
196 195
197 196 #print 'numlines',numlines,'screenlines',screen_lines # dbg
198 197 if numlines <= screen_lines :
199 198 #print '*** normal print' # dbg
200 print(str_toprint, file=io.stdout)
199 print(str_toprint)
201 200 else:
202 201 # Try to open pager and default to internal one if that fails.
203 202 # All failure modes are tagged as 'retval=1', to match the return
204 203 # value of a failed system command. If any intermediate attempt
205 204 # sets retval to 1, at the end we resort to our own page_dumb() pager.
206 205 pager_cmd = get_pager_cmd(pager_cmd)
207 206 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
208 207 if os.name == 'nt':
209 208 if pager_cmd.startswith('type'):
210 209 # The default WinXP 'type' command is failing on complex strings.
211 210 retval = 1
212 211 else:
213 212 fd, tmpname = tempfile.mkstemp('.txt')
214 213 try:
215 214 os.close(fd)
216 215 with open(tmpname, 'wt') as tmpfile:
217 216 tmpfile.write(strng)
218 217 cmd = "%s < %s" % (pager_cmd, tmpname)
219 218 # tmpfile needs to be closed for windows
220 219 if os.system(cmd):
221 220 retval = 1
222 221 else:
223 222 retval = None
224 223 finally:
225 224 os.remove(tmpname)
226 225 else:
227 226 try:
228 227 retval = None
229 228 # if I use popen4, things hang. No idea why.
230 229 #pager,shell_out = os.popen4(pager_cmd)
231 230 pager = os.popen(pager_cmd, 'w')
232 231 try:
233 232 pager_encoding = pager.encoding or sys.stdout.encoding
234 233 pager.write(py3compat.cast_bytes_py2(
235 234 strng, encoding=pager_encoding))
236 235 finally:
237 236 retval = pager.close()
238 237 except IOError as msg: # broken pipe when user quits
239 238 if msg.args == (32, 'Broken pipe'):
240 239 retval = None
241 240 else:
242 241 retval = 1
243 242 except OSError:
244 243 # Other strange problems, sometimes seen in Win2k/cygwin
245 244 retval = 1
246 245 if retval is not None:
247 246 page_dumb(strng,screen_lines=screen_lines)
248 247
249 248
250 249 def page(data, start=0, screen_lines=0, pager_cmd=None):
251 250 """Display content in a pager, piping through a pager after a certain length.
252 251
253 252 data can be a mime-bundle dict, supplying multiple representations,
254 253 keyed by mime-type, or text.
255 254
256 255 Pager is dispatched via the `show_in_pager` IPython hook.
257 256 If no hook is registered, `pager_page` will be used.
258 257 """
259 258 # Some routines may auto-compute start offsets incorrectly and pass a
260 259 # negative value. Offset to 0 for robustness.
261 260 start = max(0, start)
262 261
263 262 # first, try the hook
264 263 ip = get_ipython()
265 264 if ip:
266 265 try:
267 266 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
268 267 return
269 268 except TryNext:
270 269 pass
271 270
272 271 # fallback on default pager
273 272 return pager_page(data, start, screen_lines, pager_cmd)
274 273
275 274
276 275 def page_file(fname, start=0, pager_cmd=None):
277 276 """Page a file, using an optional pager command and starting line.
278 277 """
279 278
280 279 pager_cmd = get_pager_cmd(pager_cmd)
281 280 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
282 281
283 282 try:
284 283 if os.environ['TERM'] in ['emacs','dumb']:
285 284 raise EnvironmentError
286 285 system(pager_cmd + ' ' + fname)
287 286 except:
288 287 try:
289 288 if start > 0:
290 289 start -= 1
291 290 page(open(fname).read(),start)
292 291 except:
293 292 print('Unable to show file',repr(fname))
294 293
295 294
296 295 def get_pager_cmd(pager_cmd=None):
297 296 """Return a pager command.
298 297
299 298 Makes some attempts at finding an OS-correct one.
300 299 """
301 300 if os.name == 'posix':
302 301 default_pager_cmd = 'less -r' # -r for color control sequences
303 302 elif os.name in ['nt','dos']:
304 303 default_pager_cmd = 'type'
305 304
306 305 if pager_cmd is None:
307 306 try:
308 307 pager_cmd = os.environ['PAGER']
309 308 except:
310 309 pager_cmd = default_pager_cmd
311 310
312 311 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''):
313 312 pager_cmd += ' -r'
314 313
315 314 return pager_cmd
316 315
317 316
318 317 def get_pager_start(pager, start):
319 318 """Return the string for paging files with an offset.
320 319
321 320 This is the '+N' argument which less and more (under Unix) accept.
322 321 """
323 322
324 323 if pager in ['less','more']:
325 324 if start:
326 325 start_string = '+' + str(start)
327 326 else:
328 327 start_string = ''
329 328 else:
330 329 start_string = ''
331 330 return start_string
332 331
333 332
334 333 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
335 334 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
336 335 import msvcrt
337 336 def page_more():
338 337 """ Smart pausing between pages
339 338
340 339 @return: True if need print more lines, False if quit
341 340 """
342 io.stdout.write('---Return to continue, q to quit--- ')
341 sys.stdout.write('---Return to continue, q to quit--- ')
343 342 ans = msvcrt.getwch()
344 343 if ans in ("q", "Q"):
345 344 result = False
346 345 else:
347 346 result = True
348 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
347 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
349 348 return result
350 349 else:
351 350 def page_more():
352 351 ans = py3compat.input('---Return to continue, q to quit--- ')
353 352 if ans.lower().startswith('q'):
354 353 return False
355 354 else:
356 355 return True
357 356
358 357
359 358 def snip_print(str,width = 75,print_full = 0,header = ''):
360 359 """Print a string snipping the midsection to fit in width.
361 360
362 361 print_full: mode control:
363 362
364 363 - 0: only snip long strings
365 364 - 1: send to page() directly.
366 365 - 2: snip long strings and ask for full length viewing with page()
367 366
368 367 Return 1 if snipping was necessary, 0 otherwise."""
369 368
370 369 if print_full == 1:
371 370 page(header+str)
372 371 return 0
373 372
374 373 print(header, end=' ')
375 374 if len(str) < width:
376 375 print(str)
377 376 snip = 0
378 377 else:
379 378 whalf = int((width -5)/2)
380 379 print(str[:whalf] + ' <...> ' + str[-whalf:])
381 380 snip = 1
382 381 if snip and print_full == 2:
383 382 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
384 383 page(str)
385 384 return snip
@@ -1,943 +1,929 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 import ast
13 13 import os
14 14 import signal
15 15 import shutil
16 16 import sys
17 17 import tempfile
18 18 import unittest
19 19 try:
20 20 from unittest import mock
21 21 except ImportError:
22 22 import mock
23 23 from os.path import join
24 24
25 25 import nose.tools as nt
26 26
27 27 from IPython.core.error import InputRejected
28 28 from IPython.core.inputtransformer import InputTransformer
29 29 from IPython.testing.decorators import (
30 30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 31 )
32 32 from IPython.testing import tools as tt
33 33 from IPython.utils.process import find_cmd
34 34 from IPython.utils import py3compat
35 35 from IPython.utils.py3compat import unicode_type, PY3
36 36
37 37 if PY3:
38 38 from io import StringIO
39 39 else:
40 40 from StringIO import StringIO
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Globals
44 44 #-----------------------------------------------------------------------------
45 45 # This is used by every single test, no point repeating it ad nauseam
46 46 ip = get_ipython()
47 47
48 48 #-----------------------------------------------------------------------------
49 49 # Tests
50 50 #-----------------------------------------------------------------------------
51 51
52 52 class DerivedInterrupt(KeyboardInterrupt):
53 53 pass
54 54
55 55 class InteractiveShellTestCase(unittest.TestCase):
56 56 def test_naked_string_cells(self):
57 57 """Test that cells with only naked strings are fully executed"""
58 58 # First, single-line inputs
59 59 ip.run_cell('"a"\n')
60 60 self.assertEqual(ip.user_ns['_'], 'a')
61 61 # And also multi-line cells
62 62 ip.run_cell('"""a\nb"""\n')
63 63 self.assertEqual(ip.user_ns['_'], 'a\nb')
64 64
65 65 def test_run_empty_cell(self):
66 66 """Just make sure we don't get a horrible error with a blank
67 67 cell of input. Yes, I did overlook that."""
68 68 old_xc = ip.execution_count
69 69 res = ip.run_cell('')
70 70 self.assertEqual(ip.execution_count, old_xc)
71 71 self.assertEqual(res.execution_count, None)
72 72
73 73 def test_run_cell_multiline(self):
74 74 """Multi-block, multi-line cells must execute correctly.
75 75 """
76 76 src = '\n'.join(["x=1",
77 77 "y=2",
78 78 "if 1:",
79 79 " x += 1",
80 80 " y += 1",])
81 81 res = ip.run_cell(src)
82 82 self.assertEqual(ip.user_ns['x'], 2)
83 83 self.assertEqual(ip.user_ns['y'], 3)
84 84 self.assertEqual(res.success, True)
85 85 self.assertEqual(res.result, None)
86 86
87 87 def test_multiline_string_cells(self):
88 88 "Code sprinkled with multiline strings should execute (GH-306)"
89 89 ip.run_cell('tmp=0')
90 90 self.assertEqual(ip.user_ns['tmp'], 0)
91 91 res = ip.run_cell('tmp=1;"""a\nb"""\n')
92 92 self.assertEqual(ip.user_ns['tmp'], 1)
93 93 self.assertEqual(res.success, True)
94 94 self.assertEqual(res.result, "a\nb")
95 95
96 96 def test_dont_cache_with_semicolon(self):
97 97 "Ending a line with semicolon should not cache the returned object (GH-307)"
98 98 oldlen = len(ip.user_ns['Out'])
99 99 for cell in ['1;', '1;1;']:
100 100 res = ip.run_cell(cell, store_history=True)
101 101 newlen = len(ip.user_ns['Out'])
102 102 self.assertEqual(oldlen, newlen)
103 103 self.assertIsNone(res.result)
104 104 i = 0
105 105 #also test the default caching behavior
106 106 for cell in ['1', '1;1']:
107 107 ip.run_cell(cell, store_history=True)
108 108 newlen = len(ip.user_ns['Out'])
109 109 i += 1
110 110 self.assertEqual(oldlen+i, newlen)
111 111
112 112 def test_syntax_error(self):
113 113 res = ip.run_cell("raise = 3")
114 114 self.assertIsInstance(res.error_before_exec, SyntaxError)
115 115
116 116 def test_In_variable(self):
117 117 "Verify that In variable grows with user input (GH-284)"
118 118 oldlen = len(ip.user_ns['In'])
119 119 ip.run_cell('1;', store_history=True)
120 120 newlen = len(ip.user_ns['In'])
121 121 self.assertEqual(oldlen+1, newlen)
122 122 self.assertEqual(ip.user_ns['In'][-1],'1;')
123 123
124 124 def test_magic_names_in_string(self):
125 125 ip.run_cell('a = """\n%exit\n"""')
126 126 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
127 127
128 128 def test_trailing_newline(self):
129 129 """test that running !(command) does not raise a SyntaxError"""
130 130 ip.run_cell('!(true)\n', False)
131 131 ip.run_cell('!(true)\n\n\n', False)
132 132
133 133 def test_gh_597(self):
134 134 """Pretty-printing lists of objects with non-ascii reprs may cause
135 135 problems."""
136 136 class Spam(object):
137 137 def __repr__(self):
138 138 return "\xe9"*50
139 139 import IPython.core.formatters
140 140 f = IPython.core.formatters.PlainTextFormatter()
141 141 f([Spam(),Spam()])
142 142
143 143
144 144 def test_future_flags(self):
145 145 """Check that future flags are used for parsing code (gh-777)"""
146 146 ip.run_cell('from __future__ import print_function')
147 147 try:
148 148 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
149 149 assert 'prfunc_return_val' in ip.user_ns
150 150 finally:
151 151 # Reset compiler flags so we don't mess up other tests.
152 152 ip.compile.reset_compiler_flags()
153 153
154 154 def test_future_unicode(self):
155 155 """Check that unicode_literals is imported from __future__ (gh #786)"""
156 156 try:
157 157 ip.run_cell(u'byte_str = "a"')
158 158 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
159 159 ip.run_cell('from __future__ import unicode_literals')
160 160 ip.run_cell(u'unicode_str = "a"')
161 161 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
162 162 finally:
163 163 # Reset compiler flags so we don't mess up other tests.
164 164 ip.compile.reset_compiler_flags()
165 165
166 166 def test_can_pickle(self):
167 167 "Can we pickle objects defined interactively (GH-29)"
168 168 ip = get_ipython()
169 169 ip.reset()
170 170 ip.run_cell(("class Mylist(list):\n"
171 171 " def __init__(self,x=[]):\n"
172 172 " list.__init__(self,x)"))
173 173 ip.run_cell("w=Mylist([1,2,3])")
174 174
175 175 from pickle import dumps
176 176
177 177 # We need to swap in our main module - this is only necessary
178 178 # inside the test framework, because IPython puts the interactive module
179 179 # in place (but the test framework undoes this).
180 180 _main = sys.modules['__main__']
181 181 sys.modules['__main__'] = ip.user_module
182 182 try:
183 183 res = dumps(ip.user_ns["w"])
184 184 finally:
185 185 sys.modules['__main__'] = _main
186 186 self.assertTrue(isinstance(res, bytes))
187 187
188 188 def test_global_ns(self):
189 189 "Code in functions must be able to access variables outside them."
190 190 ip = get_ipython()
191 191 ip.run_cell("a = 10")
192 192 ip.run_cell(("def f(x):\n"
193 193 " return x + a"))
194 194 ip.run_cell("b = f(12)")
195 195 self.assertEqual(ip.user_ns["b"], 22)
196 196
197 197 def test_bad_custom_tb(self):
198 198 """Check that InteractiveShell is protected from bad custom exception handlers"""
199 from IPython.utils import io
200 save_stderr = io.stderr
201 try:
202 # capture stderr
203 io.stderr = StringIO()
204 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
205 self.assertEqual(ip.custom_exceptions, (IOError,))
199 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
200 self.assertEqual(ip.custom_exceptions, (IOError,))
201 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
206 202 ip.run_cell(u'raise IOError("foo")')
207 self.assertEqual(ip.custom_exceptions, ())
208 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
209 finally:
210 io.stderr = save_stderr
203 self.assertEqual(ip.custom_exceptions, ())
211 204
212 205 def test_bad_custom_tb_return(self):
213 206 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
214 from IPython.utils import io
215 save_stderr = io.stderr
216 try:
217 # capture stderr
218 io.stderr = StringIO()
219 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
220 self.assertEqual(ip.custom_exceptions, (NameError,))
207 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
208 self.assertEqual(ip.custom_exceptions, (NameError,))
209 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
221 210 ip.run_cell(u'a=abracadabra')
222 self.assertEqual(ip.custom_exceptions, ())
223 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
224 finally:
225 io.stderr = save_stderr
211 self.assertEqual(ip.custom_exceptions, ())
226 212
227 213 def test_drop_by_id(self):
228 214 myvars = {"a":object(), "b":object(), "c": object()}
229 215 ip.push(myvars, interactive=False)
230 216 for name in myvars:
231 217 assert name in ip.user_ns, name
232 218 assert name in ip.user_ns_hidden, name
233 219 ip.user_ns['b'] = 12
234 220 ip.drop_by_id(myvars)
235 221 for name in ["a", "c"]:
236 222 assert name not in ip.user_ns, name
237 223 assert name not in ip.user_ns_hidden, name
238 224 assert ip.user_ns['b'] == 12
239 225 ip.reset()
240 226
241 227 def test_var_expand(self):
242 228 ip.user_ns['f'] = u'Ca\xf1o'
243 229 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
244 230 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
245 231 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
246 232 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
247 233
248 234 ip.user_ns['f'] = b'Ca\xc3\xb1o'
249 235 # This should not raise any exception:
250 236 ip.var_expand(u'echo $f')
251 237
252 238 def test_var_expand_local(self):
253 239 """Test local variable expansion in !system and %magic calls"""
254 240 # !system
255 241 ip.run_cell('def test():\n'
256 242 ' lvar = "ttt"\n'
257 243 ' ret = !echo {lvar}\n'
258 244 ' return ret[0]\n')
259 245 res = ip.user_ns['test']()
260 246 nt.assert_in('ttt', res)
261 247
262 248 # %magic
263 249 ip.run_cell('def makemacro():\n'
264 250 ' macroname = "macro_var_expand_locals"\n'
265 251 ' %macro {macroname} codestr\n')
266 252 ip.user_ns['codestr'] = "str(12)"
267 253 ip.run_cell('makemacro()')
268 254 nt.assert_in('macro_var_expand_locals', ip.user_ns)
269 255
270 256 def test_var_expand_self(self):
271 257 """Test variable expansion with the name 'self', which was failing.
272 258
273 259 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
274 260 """
275 261 ip.run_cell('class cTest:\n'
276 262 ' classvar="see me"\n'
277 263 ' def test(self):\n'
278 264 ' res = !echo Variable: {self.classvar}\n'
279 265 ' return res[0]\n')
280 266 nt.assert_in('see me', ip.user_ns['cTest']().test())
281 267
282 268 def test_bad_var_expand(self):
283 269 """var_expand on invalid formats shouldn't raise"""
284 270 # SyntaxError
285 271 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
286 272 # NameError
287 273 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
288 274 # ZeroDivisionError
289 275 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
290 276
291 277 def test_silent_postexec(self):
292 278 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
293 279 pre_explicit = mock.Mock()
294 280 pre_always = mock.Mock()
295 281 post_explicit = mock.Mock()
296 282 post_always = mock.Mock()
297 283
298 284 ip.events.register('pre_run_cell', pre_explicit)
299 285 ip.events.register('pre_execute', pre_always)
300 286 ip.events.register('post_run_cell', post_explicit)
301 287 ip.events.register('post_execute', post_always)
302 288
303 289 try:
304 290 ip.run_cell("1", silent=True)
305 291 assert pre_always.called
306 292 assert not pre_explicit.called
307 293 assert post_always.called
308 294 assert not post_explicit.called
309 295 # double-check that non-silent exec did what we expected
310 296 # silent to avoid
311 297 ip.run_cell("1")
312 298 assert pre_explicit.called
313 299 assert post_explicit.called
314 300 finally:
315 301 # remove post-exec
316 302 ip.events.unregister('pre_run_cell', pre_explicit)
317 303 ip.events.unregister('pre_execute', pre_always)
318 304 ip.events.unregister('post_run_cell', post_explicit)
319 305 ip.events.unregister('post_execute', post_always)
320 306
321 307 def test_silent_noadvance(self):
322 308 """run_cell(silent=True) doesn't advance execution_count"""
323 309 ec = ip.execution_count
324 310 # silent should force store_history=False
325 311 ip.run_cell("1", store_history=True, silent=True)
326 312
327 313 self.assertEqual(ec, ip.execution_count)
328 314 # double-check that non-silent exec did what we expected
329 315 # silent to avoid
330 316 ip.run_cell("1", store_history=True)
331 317 self.assertEqual(ec+1, ip.execution_count)
332 318
333 319 def test_silent_nodisplayhook(self):
334 320 """run_cell(silent=True) doesn't trigger displayhook"""
335 321 d = dict(called=False)
336 322
337 323 trap = ip.display_trap
338 324 save_hook = trap.hook
339 325
340 326 def failing_hook(*args, **kwargs):
341 327 d['called'] = True
342 328
343 329 try:
344 330 trap.hook = failing_hook
345 331 res = ip.run_cell("1", silent=True)
346 332 self.assertFalse(d['called'])
347 333 self.assertIsNone(res.result)
348 334 # double-check that non-silent exec did what we expected
349 335 # silent to avoid
350 336 ip.run_cell("1")
351 337 self.assertTrue(d['called'])
352 338 finally:
353 339 trap.hook = save_hook
354 340
355 341 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
356 342 def test_print_softspace(self):
357 343 """Verify that softspace is handled correctly when executing multiple
358 344 statements.
359 345
360 346 In [1]: print 1; print 2
361 347 1
362 348 2
363 349
364 350 In [2]: print 1,; print 2
365 351 1 2
366 352 """
367 353
368 354 def test_ofind_line_magic(self):
369 355 from IPython.core.magic import register_line_magic
370 356
371 357 @register_line_magic
372 358 def lmagic(line):
373 359 "A line magic"
374 360
375 361 # Get info on line magic
376 362 lfind = ip._ofind('lmagic')
377 363 info = dict(found=True, isalias=False, ismagic=True,
378 364 namespace = 'IPython internal', obj= lmagic.__wrapped__,
379 365 parent = None)
380 366 nt.assert_equal(lfind, info)
381 367
382 368 def test_ofind_cell_magic(self):
383 369 from IPython.core.magic import register_cell_magic
384 370
385 371 @register_cell_magic
386 372 def cmagic(line, cell):
387 373 "A cell magic"
388 374
389 375 # Get info on cell magic
390 376 find = ip._ofind('cmagic')
391 377 info = dict(found=True, isalias=False, ismagic=True,
392 378 namespace = 'IPython internal', obj= cmagic.__wrapped__,
393 379 parent = None)
394 380 nt.assert_equal(find, info)
395 381
396 382 def test_ofind_property_with_error(self):
397 383 class A(object):
398 384 @property
399 385 def foo(self):
400 386 raise NotImplementedError()
401 387 a = A()
402 388
403 389 found = ip._ofind('a.foo', [('locals', locals())])
404 390 info = dict(found=True, isalias=False, ismagic=False,
405 391 namespace='locals', obj=A.foo, parent=a)
406 392 nt.assert_equal(found, info)
407 393
408 394 def test_ofind_multiple_attribute_lookups(self):
409 395 class A(object):
410 396 @property
411 397 def foo(self):
412 398 raise NotImplementedError()
413 399
414 400 a = A()
415 401 a.a = A()
416 402 a.a.a = A()
417 403
418 404 found = ip._ofind('a.a.a.foo', [('locals', locals())])
419 405 info = dict(found=True, isalias=False, ismagic=False,
420 406 namespace='locals', obj=A.foo, parent=a.a.a)
421 407 nt.assert_equal(found, info)
422 408
423 409 def test_ofind_slotted_attributes(self):
424 410 class A(object):
425 411 __slots__ = ['foo']
426 412 def __init__(self):
427 413 self.foo = 'bar'
428 414
429 415 a = A()
430 416 found = ip._ofind('a.foo', [('locals', locals())])
431 417 info = dict(found=True, isalias=False, ismagic=False,
432 418 namespace='locals', obj=a.foo, parent=a)
433 419 nt.assert_equal(found, info)
434 420
435 421 found = ip._ofind('a.bar', [('locals', locals())])
436 422 info = dict(found=False, isalias=False, ismagic=False,
437 423 namespace=None, obj=None, parent=a)
438 424 nt.assert_equal(found, info)
439 425
440 426 def test_ofind_prefers_property_to_instance_level_attribute(self):
441 427 class A(object):
442 428 @property
443 429 def foo(self):
444 430 return 'bar'
445 431 a = A()
446 432 a.__dict__['foo'] = 'baz'
447 433 nt.assert_equal(a.foo, 'bar')
448 434 found = ip._ofind('a.foo', [('locals', locals())])
449 435 nt.assert_is(found['obj'], A.foo)
450 436
451 437 def test_custom_exception(self):
452 438 called = []
453 439 def my_handler(shell, etype, value, tb, tb_offset=None):
454 440 called.append(etype)
455 441 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
456 442
457 443 ip.set_custom_exc((ValueError,), my_handler)
458 444 try:
459 445 res = ip.run_cell("raise ValueError('test')")
460 446 # Check that this was called, and only once.
461 447 self.assertEqual(called, [ValueError])
462 448 # Check that the error is on the result object
463 449 self.assertIsInstance(res.error_in_exec, ValueError)
464 450 finally:
465 451 # Reset the custom exception hook
466 452 ip.set_custom_exc((), None)
467 453
468 454 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
469 455 def test_future_environment(self):
470 456 "Can we run code with & without the shell's __future__ imports?"
471 457 ip.run_cell("from __future__ import division")
472 458 ip.run_cell("a = 1/2", shell_futures=True)
473 459 self.assertEqual(ip.user_ns['a'], 0.5)
474 460 ip.run_cell("b = 1/2", shell_futures=False)
475 461 self.assertEqual(ip.user_ns['b'], 0)
476 462
477 463 ip.compile.reset_compiler_flags()
478 464 # This shouldn't leak to the shell's compiler
479 465 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
480 466 self.assertEqual(ip.user_ns['c'], 0.5)
481 467 ip.run_cell("d = 1/2", shell_futures=True)
482 468 self.assertEqual(ip.user_ns['d'], 0)
483 469
484 470 def test_mktempfile(self):
485 471 filename = ip.mktempfile()
486 472 # Check that we can open the file again on Windows
487 473 with open(filename, 'w') as f:
488 474 f.write('abc')
489 475
490 476 filename = ip.mktempfile(data='blah')
491 477 with open(filename, 'r') as f:
492 478 self.assertEqual(f.read(), 'blah')
493 479
494 480 def test_new_main_mod(self):
495 481 # Smoketest to check that this accepts a unicode module name
496 482 name = u'jiefmw'
497 483 mod = ip.new_main_mod(u'%s.py' % name, name)
498 484 self.assertEqual(mod.__name__, name)
499 485
500 486 def test_get_exception_only(self):
501 487 try:
502 488 raise KeyboardInterrupt
503 489 except KeyboardInterrupt:
504 490 msg = ip.get_exception_only()
505 491 self.assertEqual(msg, 'KeyboardInterrupt\n')
506 492
507 493 try:
508 494 raise DerivedInterrupt("foo")
509 495 except KeyboardInterrupt:
510 496 msg = ip.get_exception_only()
511 497 if sys.version_info[0] <= 2:
512 498 self.assertEqual(msg, 'DerivedInterrupt: foo\n')
513 499 else:
514 500 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
515 501
516 502 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
517 503
518 504 @onlyif_unicode_paths
519 505 def setUp(self):
520 506 self.BASETESTDIR = tempfile.mkdtemp()
521 507 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
522 508 os.mkdir(self.TESTDIR)
523 509 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
524 510 sfile.write("pass\n")
525 511 self.oldpath = py3compat.getcwd()
526 512 os.chdir(self.TESTDIR)
527 513 self.fname = u"Γ₯Àâtestscript.py"
528 514
529 515 def tearDown(self):
530 516 os.chdir(self.oldpath)
531 517 shutil.rmtree(self.BASETESTDIR)
532 518
533 519 @onlyif_unicode_paths
534 520 def test_1(self):
535 521 """Test safe_execfile with non-ascii path
536 522 """
537 523 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
538 524
539 525 class ExitCodeChecks(tt.TempFileMixin):
540 526 def test_exit_code_ok(self):
541 527 self.system('exit 0')
542 528 self.assertEqual(ip.user_ns['_exit_code'], 0)
543 529
544 530 def test_exit_code_error(self):
545 531 self.system('exit 1')
546 532 self.assertEqual(ip.user_ns['_exit_code'], 1)
547 533
548 534 @skipif(not hasattr(signal, 'SIGALRM'))
549 535 def test_exit_code_signal(self):
550 536 self.mktmp("import signal, time\n"
551 537 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
552 538 "time.sleep(1)\n")
553 539 self.system("%s %s" % (sys.executable, self.fname))
554 540 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
555 541
556 542 @onlyif_cmds_exist("csh")
557 543 def test_exit_code_signal_csh(self):
558 544 SHELL = os.environ.get('SHELL', None)
559 545 os.environ['SHELL'] = find_cmd("csh")
560 546 try:
561 547 self.test_exit_code_signal()
562 548 finally:
563 549 if SHELL is not None:
564 550 os.environ['SHELL'] = SHELL
565 551 else:
566 552 del os.environ['SHELL']
567 553
568 554 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
569 555 system = ip.system_raw
570 556
571 557 @onlyif_unicode_paths
572 558 def test_1(self):
573 559 """Test system_raw with non-ascii cmd
574 560 """
575 561 cmd = u'''python -c "'Γ₯Àâ'" '''
576 562 ip.system_raw(cmd)
577 563
578 564 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
579 565 @mock.patch('os.system', side_effect=KeyboardInterrupt)
580 566 def test_control_c(self, *mocks):
581 567 try:
582 568 self.system("sleep 1 # wont happen")
583 569 except KeyboardInterrupt:
584 570 self.fail("system call should intercept "
585 571 "keyboard interrupt from subprocess.call")
586 572 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
587 573
588 574 # TODO: Exit codes are currently ignored on Windows.
589 575 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
590 576 system = ip.system_piped
591 577
592 578 @skip_win32
593 579 def test_exit_code_ok(self):
594 580 ExitCodeChecks.test_exit_code_ok(self)
595 581
596 582 @skip_win32
597 583 def test_exit_code_error(self):
598 584 ExitCodeChecks.test_exit_code_error(self)
599 585
600 586 @skip_win32
601 587 def test_exit_code_signal(self):
602 588 ExitCodeChecks.test_exit_code_signal(self)
603 589
604 590 class TestModules(unittest.TestCase, tt.TempFileMixin):
605 591 def test_extraneous_loads(self):
606 592 """Test we're not loading modules on startup that we shouldn't.
607 593 """
608 594 self.mktmp("import sys\n"
609 595 "print('numpy' in sys.modules)\n"
610 596 "print('ipyparallel' in sys.modules)\n"
611 597 "print('ipykernel' in sys.modules)\n"
612 598 )
613 599 out = "False\nFalse\nFalse\n"
614 600 tt.ipexec_validate(self.fname, out)
615 601
616 602 class Negator(ast.NodeTransformer):
617 603 """Negates all number literals in an AST."""
618 604 def visit_Num(self, node):
619 605 node.n = -node.n
620 606 return node
621 607
622 608 class TestAstTransform(unittest.TestCase):
623 609 def setUp(self):
624 610 self.negator = Negator()
625 611 ip.ast_transformers.append(self.negator)
626 612
627 613 def tearDown(self):
628 614 ip.ast_transformers.remove(self.negator)
629 615
630 616 def test_run_cell(self):
631 617 with tt.AssertPrints('-34'):
632 618 ip.run_cell('print (12 + 22)')
633 619
634 620 # A named reference to a number shouldn't be transformed.
635 621 ip.user_ns['n'] = 55
636 622 with tt.AssertNotPrints('-55'):
637 623 ip.run_cell('print (n)')
638 624
639 625 def test_timeit(self):
640 626 called = set()
641 627 def f(x):
642 628 called.add(x)
643 629 ip.push({'f':f})
644 630
645 631 with tt.AssertPrints("best of "):
646 632 ip.run_line_magic("timeit", "-n1 f(1)")
647 633 self.assertEqual(called, {-1})
648 634 called.clear()
649 635
650 636 with tt.AssertPrints("best of "):
651 637 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
652 638 self.assertEqual(called, {-2, -3})
653 639
654 640 def test_time(self):
655 641 called = []
656 642 def f(x):
657 643 called.append(x)
658 644 ip.push({'f':f})
659 645
660 646 # Test with an expression
661 647 with tt.AssertPrints("Wall time: "):
662 648 ip.run_line_magic("time", "f(5+9)")
663 649 self.assertEqual(called, [-14])
664 650 called[:] = []
665 651
666 652 # Test with a statement (different code path)
667 653 with tt.AssertPrints("Wall time: "):
668 654 ip.run_line_magic("time", "a = f(-3 + -2)")
669 655 self.assertEqual(called, [5])
670 656
671 657 def test_macro(self):
672 658 ip.push({'a':10})
673 659 # The AST transformation makes this do a+=-1
674 660 ip.define_macro("amacro", "a+=1\nprint(a)")
675 661
676 662 with tt.AssertPrints("9"):
677 663 ip.run_cell("amacro")
678 664 with tt.AssertPrints("8"):
679 665 ip.run_cell("amacro")
680 666
681 667 class IntegerWrapper(ast.NodeTransformer):
682 668 """Wraps all integers in a call to Integer()"""
683 669 def visit_Num(self, node):
684 670 if isinstance(node.n, int):
685 671 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
686 672 args=[node], keywords=[])
687 673 return node
688 674
689 675 class TestAstTransform2(unittest.TestCase):
690 676 def setUp(self):
691 677 self.intwrapper = IntegerWrapper()
692 678 ip.ast_transformers.append(self.intwrapper)
693 679
694 680 self.calls = []
695 681 def Integer(*args):
696 682 self.calls.append(args)
697 683 return args
698 684 ip.push({"Integer": Integer})
699 685
700 686 def tearDown(self):
701 687 ip.ast_transformers.remove(self.intwrapper)
702 688 del ip.user_ns['Integer']
703 689
704 690 def test_run_cell(self):
705 691 ip.run_cell("n = 2")
706 692 self.assertEqual(self.calls, [(2,)])
707 693
708 694 # This shouldn't throw an error
709 695 ip.run_cell("o = 2.0")
710 696 self.assertEqual(ip.user_ns['o'], 2.0)
711 697
712 698 def test_timeit(self):
713 699 called = set()
714 700 def f(x):
715 701 called.add(x)
716 702 ip.push({'f':f})
717 703
718 704 with tt.AssertPrints("best of "):
719 705 ip.run_line_magic("timeit", "-n1 f(1)")
720 706 self.assertEqual(called, {(1,)})
721 707 called.clear()
722 708
723 709 with tt.AssertPrints("best of "):
724 710 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
725 711 self.assertEqual(called, {(2,), (3,)})
726 712
727 713 class ErrorTransformer(ast.NodeTransformer):
728 714 """Throws an error when it sees a number."""
729 715 def visit_Num(self, node):
730 716 raise ValueError("test")
731 717
732 718 class TestAstTransformError(unittest.TestCase):
733 719 def test_unregistering(self):
734 720 err_transformer = ErrorTransformer()
735 721 ip.ast_transformers.append(err_transformer)
736 722
737 723 with tt.AssertPrints("unregister", channel='stderr'):
738 724 ip.run_cell("1 + 2")
739 725
740 726 # This should have been removed.
741 727 nt.assert_not_in(err_transformer, ip.ast_transformers)
742 728
743 729
744 730 class StringRejector(ast.NodeTransformer):
745 731 """Throws an InputRejected when it sees a string literal.
746 732
747 733 Used to verify that NodeTransformers can signal that a piece of code should
748 734 not be executed by throwing an InputRejected.
749 735 """
750 736
751 737 def visit_Str(self, node):
752 738 raise InputRejected("test")
753 739
754 740
755 741 class TestAstTransformInputRejection(unittest.TestCase):
756 742
757 743 def setUp(self):
758 744 self.transformer = StringRejector()
759 745 ip.ast_transformers.append(self.transformer)
760 746
761 747 def tearDown(self):
762 748 ip.ast_transformers.remove(self.transformer)
763 749
764 750 def test_input_rejection(self):
765 751 """Check that NodeTransformers can reject input."""
766 752
767 753 expect_exception_tb = tt.AssertPrints("InputRejected: test")
768 754 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
769 755
770 756 # Run the same check twice to verify that the transformer is not
771 757 # disabled after raising.
772 758 with expect_exception_tb, expect_no_cell_output:
773 759 ip.run_cell("'unsafe'")
774 760
775 761 with expect_exception_tb, expect_no_cell_output:
776 762 res = ip.run_cell("'unsafe'")
777 763
778 764 self.assertIsInstance(res.error_before_exec, InputRejected)
779 765
780 766 def test__IPYTHON__():
781 767 # This shouldn't raise a NameError, that's all
782 768 __IPYTHON__
783 769
784 770
785 771 class DummyRepr(object):
786 772 def __repr__(self):
787 773 return "DummyRepr"
788 774
789 775 def _repr_html_(self):
790 776 return "<b>dummy</b>"
791 777
792 778 def _repr_javascript_(self):
793 779 return "console.log('hi');", {'key': 'value'}
794 780
795 781
796 782 def test_user_variables():
797 783 # enable all formatters
798 784 ip.display_formatter.active_types = ip.display_formatter.format_types
799 785
800 786 ip.user_ns['dummy'] = d = DummyRepr()
801 787 keys = {'dummy', 'doesnotexist'}
802 788 r = ip.user_expressions({ key:key for key in keys})
803 789
804 790 nt.assert_equal(keys, set(r.keys()))
805 791 dummy = r['dummy']
806 792 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
807 793 nt.assert_equal(dummy['status'], 'ok')
808 794 data = dummy['data']
809 795 metadata = dummy['metadata']
810 796 nt.assert_equal(data.get('text/html'), d._repr_html_())
811 797 js, jsmd = d._repr_javascript_()
812 798 nt.assert_equal(data.get('application/javascript'), js)
813 799 nt.assert_equal(metadata.get('application/javascript'), jsmd)
814 800
815 801 dne = r['doesnotexist']
816 802 nt.assert_equal(dne['status'], 'error')
817 803 nt.assert_equal(dne['ename'], 'NameError')
818 804
819 805 # back to text only
820 806 ip.display_formatter.active_types = ['text/plain']
821 807
822 808 def test_user_expression():
823 809 # enable all formatters
824 810 ip.display_formatter.active_types = ip.display_formatter.format_types
825 811 query = {
826 812 'a' : '1 + 2',
827 813 'b' : '1/0',
828 814 }
829 815 r = ip.user_expressions(query)
830 816 import pprint
831 817 pprint.pprint(r)
832 818 nt.assert_equal(set(r.keys()), set(query.keys()))
833 819 a = r['a']
834 820 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
835 821 nt.assert_equal(a['status'], 'ok')
836 822 data = a['data']
837 823 metadata = a['metadata']
838 824 nt.assert_equal(data.get('text/plain'), '3')
839 825
840 826 b = r['b']
841 827 nt.assert_equal(b['status'], 'error')
842 828 nt.assert_equal(b['ename'], 'ZeroDivisionError')
843 829
844 830 # back to text only
845 831 ip.display_formatter.active_types = ['text/plain']
846 832
847 833
848 834
849 835
850 836
851 837 class TestSyntaxErrorTransformer(unittest.TestCase):
852 838 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
853 839
854 840 class SyntaxErrorTransformer(InputTransformer):
855 841
856 842 def push(self, line):
857 843 pos = line.find('syntaxerror')
858 844 if pos >= 0:
859 845 e = SyntaxError('input contains "syntaxerror"')
860 846 e.text = line
861 847 e.offset = pos + 1
862 848 raise e
863 849 return line
864 850
865 851 def reset(self):
866 852 pass
867 853
868 854 def setUp(self):
869 855 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
870 856 ip.input_splitter.python_line_transforms.append(self.transformer)
871 857 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
872 858
873 859 def tearDown(self):
874 860 ip.input_splitter.python_line_transforms.remove(self.transformer)
875 861 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
876 862
877 863 def test_syntaxerror_input_transformer(self):
878 864 with tt.AssertPrints('1234'):
879 865 ip.run_cell('1234')
880 866 with tt.AssertPrints('SyntaxError: invalid syntax'):
881 867 ip.run_cell('1 2 3') # plain python syntax error
882 868 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
883 869 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
884 870 with tt.AssertPrints('3456'):
885 871 ip.run_cell('3456')
886 872
887 873
888 874
889 875 def test_warning_suppression():
890 876 ip.run_cell("import warnings")
891 877 try:
892 878 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
893 879 ip.run_cell("warnings.warn('asdf')")
894 880 # Here's the real test -- if we run that again, we should get the
895 881 # warning again. Traditionally, each warning was only issued once per
896 882 # IPython session (approximately), even if the user typed in new and
897 883 # different code that should have also triggered the warning, leading
898 884 # to much confusion.
899 885 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
900 886 ip.run_cell("warnings.warn('asdf')")
901 887 finally:
902 888 ip.run_cell("del warnings")
903 889
904 890
905 891 def test_deprecation_warning():
906 892 ip.run_cell("""
907 893 import warnings
908 894 def wrn():
909 895 warnings.warn(
910 896 "I AM A WARNING",
911 897 DeprecationWarning
912 898 )
913 899 """)
914 900 try:
915 901 with tt.AssertPrints("I AM A WARNING", channel="stderr"):
916 902 ip.run_cell("wrn()")
917 903 finally:
918 904 ip.run_cell("del warnings")
919 905 ip.run_cell("del wrn")
920 906
921 907
922 908 class TestImportNoDeprecate(tt.TempFileMixin):
923 909
924 910 def setup(self):
925 911 """Make a valid python temp file."""
926 912 self.mktmp("""
927 913 import warnings
928 914 def wrn():
929 915 warnings.warn(
930 916 "I AM A WARNING",
931 917 DeprecationWarning
932 918 )
933 919 """)
934 920
935 921 def test_no_dep(self):
936 922 """
937 923 No deprecation warning should be raised from imported functions
938 924 """
939 925 ip.run_cell("from {} import wrn".format(self.fname))
940 926
941 927 with tt.AssertNotPrints("I AM A WARNING"):
942 928 ip.run_cell("wrn()")
943 929 ip.run_cell("del wrn")
@@ -1,1485 +1,1484 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 You can implement other color schemes easily, the syntax is fairly
71 71 self-explanatory. Please send back new schemes you develop to the author for
72 72 possible inclusion in future releases.
73 73
74 74 Inheritance diagram:
75 75
76 76 .. inheritance-diagram:: IPython.core.ultratb
77 77 :parts: 3
78 78 """
79 79
80 80 #*****************************************************************************
81 81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
82 82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
83 83 #
84 84 # Distributed under the terms of the BSD License. The full license is in
85 85 # the file COPYING, distributed as part of this software.
86 86 #*****************************************************************************
87 87
88 88 from __future__ import absolute_import
89 89 from __future__ import unicode_literals
90 90 from __future__ import print_function
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 import types
104 104
105 105 try: # Python 2
106 106 generate_tokens = tokenize.generate_tokens
107 107 except AttributeError: # Python 3
108 108 generate_tokens = tokenize.tokenize
109 109
110 110 # For purposes of monkeypatching inspect to fix a bug in it.
111 111 from inspect import getsourcefile, getfile, getmodule, \
112 112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
113 113
114 114 # IPython's own modules
115 115 # Modified pdb which doesn't damage IPython's readline handling
116 116 from IPython import get_ipython
117 117 from IPython.core import debugger
118 118 from IPython.core.display_trap import DisplayTrap
119 119 from IPython.core.excolors import exception_colors
120 120 from IPython.utils import PyColorize
121 from IPython.utils import io
122 121 from IPython.utils import openpy
123 122 from IPython.utils import path as util_path
124 123 from IPython.utils import py3compat
125 124 from IPython.utils import ulinecache
126 125 from IPython.utils.data import uniq_stable
127 126 from IPython.utils.terminal import get_terminal_size
128 127 from logging import info, error
129 128
130 129 import IPython.utils.colorable as colorable
131 130
132 131 # Globals
133 132 # amount of space to put line numbers before verbose tracebacks
134 133 INDENT_SIZE = 8
135 134
136 135 # Default color scheme. This is used, for example, by the traceback
137 136 # formatter. When running in an actual IPython instance, the user's rc.colors
138 137 # value is used, but having a module global makes this functionality available
139 138 # to users of ultratb who are NOT running inside ipython.
140 139 DEFAULT_SCHEME = 'NoColor'
141 140
142 141 # ---------------------------------------------------------------------------
143 142 # Code begins
144 143
145 144 # Utility functions
146 145 def inspect_error():
147 146 """Print a message about internal inspect errors.
148 147
149 148 These are unfortunately quite common."""
150 149
151 150 error('Internal Python error in the inspect module.\n'
152 151 'Below is the traceback from this internal error.\n')
153 152
154 153
155 154 # This function is a monkeypatch we apply to the Python inspect module. We have
156 155 # now found when it's needed (see discussion on issue gh-1456), and we have a
157 156 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
158 157 # the monkeypatch is not applied. TK, Aug 2012.
159 158 def findsource(object):
160 159 """Return the entire source file and starting line number for an object.
161 160
162 161 The argument may be a module, class, method, function, traceback, frame,
163 162 or code object. The source code is returned as a list of all the lines
164 163 in the file and the line number indexes a line in that list. An IOError
165 164 is raised if the source code cannot be retrieved.
166 165
167 166 FIXED version with which we monkeypatch the stdlib to work around a bug."""
168 167
169 168 file = getsourcefile(object) or getfile(object)
170 169 # If the object is a frame, then trying to get the globals dict from its
171 170 # module won't work. Instead, the frame object itself has the globals
172 171 # dictionary.
173 172 globals_dict = None
174 173 if inspect.isframe(object):
175 174 # XXX: can this ever be false?
176 175 globals_dict = object.f_globals
177 176 else:
178 177 module = getmodule(object, file)
179 178 if module:
180 179 globals_dict = module.__dict__
181 180 lines = linecache.getlines(file, globals_dict)
182 181 if not lines:
183 182 raise IOError('could not get source code')
184 183
185 184 if ismodule(object):
186 185 return lines, 0
187 186
188 187 if isclass(object):
189 188 name = object.__name__
190 189 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
191 190 # make some effort to find the best matching class definition:
192 191 # use the one with the least indentation, which is the one
193 192 # that's most probably not inside a function definition.
194 193 candidates = []
195 194 for i in range(len(lines)):
196 195 match = pat.match(lines[i])
197 196 if match:
198 197 # if it's at toplevel, it's already the best one
199 198 if lines[i][0] == 'c':
200 199 return lines, i
201 200 # else add whitespace to candidate list
202 201 candidates.append((match.group(1), i))
203 202 if candidates:
204 203 # this will sort by whitespace, and by line number,
205 204 # less whitespace first
206 205 candidates.sort()
207 206 return lines, candidates[0][1]
208 207 else:
209 208 raise IOError('could not find class definition')
210 209
211 210 if ismethod(object):
212 211 object = object.__func__
213 212 if isfunction(object):
214 213 object = object.__code__
215 214 if istraceback(object):
216 215 object = object.tb_frame
217 216 if isframe(object):
218 217 object = object.f_code
219 218 if iscode(object):
220 219 if not hasattr(object, 'co_firstlineno'):
221 220 raise IOError('could not find function definition')
222 221 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
223 222 pmatch = pat.match
224 223 # fperez - fix: sometimes, co_firstlineno can give a number larger than
225 224 # the length of lines, which causes an error. Safeguard against that.
226 225 lnum = min(object.co_firstlineno, len(lines)) - 1
227 226 while lnum > 0:
228 227 if pmatch(lines[lnum]):
229 228 break
230 229 lnum -= 1
231 230
232 231 return lines, lnum
233 232 raise IOError('could not find code object')
234 233
235 234
236 235 # This is a patched version of inspect.getargs that applies the (unmerged)
237 236 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
238 237 # https://github.com/ipython/ipython/issues/8205 and
239 238 # https://github.com/ipython/ipython/issues/8293
240 239 def getargs(co):
241 240 """Get information about the arguments accepted by a code object.
242 241
243 242 Three things are returned: (args, varargs, varkw), where 'args' is
244 243 a list of argument names (possibly containing nested lists), and
245 244 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
246 245 if not iscode(co):
247 246 raise TypeError('{!r} is not a code object'.format(co))
248 247
249 248 nargs = co.co_argcount
250 249 names = co.co_varnames
251 250 args = list(names[:nargs])
252 251 step = 0
253 252
254 253 # The following acrobatics are for anonymous (tuple) arguments.
255 254 for i in range(nargs):
256 255 if args[i][:1] in ('', '.'):
257 256 stack, remain, count = [], [], []
258 257 while step < len(co.co_code):
259 258 op = ord(co.co_code[step])
260 259 step = step + 1
261 260 if op >= dis.HAVE_ARGUMENT:
262 261 opname = dis.opname[op]
263 262 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
264 263 step = step + 2
265 264 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
266 265 remain.append(value)
267 266 count.append(value)
268 267 elif opname in ('STORE_FAST', 'STORE_DEREF'):
269 268 if op in dis.haslocal:
270 269 stack.append(co.co_varnames[value])
271 270 elif op in dis.hasfree:
272 271 stack.append((co.co_cellvars + co.co_freevars)[value])
273 272 # Special case for sublists of length 1: def foo((bar))
274 273 # doesn't generate the UNPACK_TUPLE bytecode, so if
275 274 # `remain` is empty here, we have such a sublist.
276 275 if not remain:
277 276 stack[0] = [stack[0]]
278 277 break
279 278 else:
280 279 remain[-1] = remain[-1] - 1
281 280 while remain[-1] == 0:
282 281 remain.pop()
283 282 size = count.pop()
284 283 stack[-size:] = [stack[-size:]]
285 284 if not remain:
286 285 break
287 286 remain[-1] = remain[-1] - 1
288 287 if not remain:
289 288 break
290 289 args[i] = stack[0]
291 290
292 291 varargs = None
293 292 if co.co_flags & inspect.CO_VARARGS:
294 293 varargs = co.co_varnames[nargs]
295 294 nargs = nargs + 1
296 295 varkw = None
297 296 if co.co_flags & inspect.CO_VARKEYWORDS:
298 297 varkw = co.co_varnames[nargs]
299 298 return inspect.Arguments(args, varargs, varkw)
300 299
301 300
302 301 # Monkeypatch inspect to apply our bugfix.
303 302 def with_patch_inspect(f):
304 303 """decorator for monkeypatching inspect.findsource"""
305 304
306 305 def wrapped(*args, **kwargs):
307 306 save_findsource = inspect.findsource
308 307 save_getargs = inspect.getargs
309 308 inspect.findsource = findsource
310 309 inspect.getargs = getargs
311 310 try:
312 311 return f(*args, **kwargs)
313 312 finally:
314 313 inspect.findsource = save_findsource
315 314 inspect.getargs = save_getargs
316 315
317 316 return wrapped
318 317
319 318
320 319 if py3compat.PY3:
321 320 fixed_getargvalues = inspect.getargvalues
322 321 else:
323 322 # Fixes for https://github.com/ipython/ipython/issues/8293
324 323 # and https://github.com/ipython/ipython/issues/8205.
325 324 # The relevant bug is caused by failure to correctly handle anonymous tuple
326 325 # unpacking, which only exists in Python 2.
327 326 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
328 327
329 328
330 329 def fix_frame_records_filenames(records):
331 330 """Try to fix the filenames in each record from inspect.getinnerframes().
332 331
333 332 Particularly, modules loaded from within zip files have useless filenames
334 333 attached to their code object, and inspect.getinnerframes() just uses it.
335 334 """
336 335 fixed_records = []
337 336 for frame, filename, line_no, func_name, lines, index in records:
338 337 # Look inside the frame's globals dictionary for __file__,
339 338 # which should be better. However, keep Cython filenames since
340 339 # we prefer the source filenames over the compiled .so file.
341 340 filename = py3compat.cast_unicode_py2(filename, "utf-8")
342 341 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
343 342 better_fn = frame.f_globals.get('__file__', None)
344 343 if isinstance(better_fn, str):
345 344 # Check the type just in case someone did something weird with
346 345 # __file__. It might also be None if the error occurred during
347 346 # import.
348 347 filename = better_fn
349 348 fixed_records.append((frame, filename, line_no, func_name, lines, index))
350 349 return fixed_records
351 350
352 351
353 352 @with_patch_inspect
354 353 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
355 354 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
356 355
357 356 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
358 357 # If the error is at the console, don't build any context, since it would
359 358 # otherwise produce 5 blank lines printed out (there is no file at the
360 359 # console)
361 360 rec_check = records[tb_offset:]
362 361 try:
363 362 rname = rec_check[0][1]
364 363 if rname == '<ipython console>' or rname.endswith('<string>'):
365 364 return rec_check
366 365 except IndexError:
367 366 pass
368 367
369 368 aux = traceback.extract_tb(etb)
370 369 assert len(records) == len(aux)
371 370 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
372 371 maybeStart = lnum - 1 - context // 2
373 372 start = max(maybeStart, 0)
374 373 end = start + context
375 374 lines = ulinecache.getlines(file)[start:end]
376 375 buf = list(records[i])
377 376 buf[LNUM_POS] = lnum
378 377 buf[INDEX_POS] = lnum - 1 - start
379 378 buf[LINES_POS] = lines
380 379 records[i] = tuple(buf)
381 380 return records[tb_offset:]
382 381
383 382 # Helper function -- largely belongs to VerboseTB, but we need the same
384 383 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
385 384 # can be recognized properly by ipython.el's py-traceback-line-re
386 385 # (SyntaxErrors have to be treated specially because they have no traceback)
387 386
388 387 _parser = PyColorize.Parser()
389 388
390 389
391 390 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
392 391 numbers_width = INDENT_SIZE - 1
393 392 res = []
394 393 i = lnum - index
395 394
396 395 # This lets us get fully syntax-highlighted tracebacks.
397 396 if scheme is None:
398 397 ipinst = get_ipython()
399 398 if ipinst is not None:
400 399 scheme = ipinst.colors
401 400 else:
402 401 scheme = DEFAULT_SCHEME
403 402
404 403 _line_format = _parser.format2
405 404
406 405 for line in lines:
407 406 line = py3compat.cast_unicode(line)
408 407
409 408 new_line, err = _line_format(line, 'str', scheme)
410 409 if not err: line = new_line
411 410
412 411 if i == lnum:
413 412 # This is the line with the error
414 413 pad = numbers_width - len(str(i))
415 414 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
416 415 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
417 416 Colors.line, line, Colors.Normal)
418 417 else:
419 418 num = '%*s' % (numbers_width, i)
420 419 line = '%s%s%s %s' % (Colors.lineno, num,
421 420 Colors.Normal, line)
422 421
423 422 res.append(line)
424 423 if lvals and i == lnum:
425 424 res.append(lvals + '\n')
426 425 i = i + 1
427 426 return res
428 427
429 428 def is_recursion_error(etype, value, records):
430 429 try:
431 430 # RecursionError is new in Python 3.5
432 431 recursion_error_type = RecursionError
433 432 except NameError:
434 433 recursion_error_type = RuntimeError
435 434
436 435 # The default recursion limit is 1000, but some of that will be taken up
437 436 # by stack frames in IPython itself. >500 frames probably indicates
438 437 # a recursion error.
439 438 return (etype is recursion_error_type) \
440 439 and "recursion" in str(value).lower() \
441 440 and len(records) > 500
442 441
443 442 def find_recursion(etype, value, records):
444 443 """Identify the repeating stack frames from a RecursionError traceback
445 444
446 445 'records' is a list as returned by VerboseTB.get_records()
447 446
448 447 Returns (last_unique, repeat_length)
449 448 """
450 449 # This involves a bit of guesswork - we want to show enough of the traceback
451 450 # to indicate where the recursion is occurring. We guess that the innermost
452 451 # quarter of the traceback (250 frames by default) is repeats, and find the
453 452 # first frame (from in to out) that looks different.
454 453 if not is_recursion_error(etype, value, records):
455 454 return len(records), 0
456 455
457 456 # Select filename, lineno, func_name to track frames with
458 457 records = [r[1:4] for r in records]
459 458 inner_frames = records[-(len(records)//4):]
460 459 frames_repeated = set(inner_frames)
461 460
462 461 last_seen_at = {}
463 462 longest_repeat = 0
464 463 i = len(records)
465 464 for frame in reversed(records):
466 465 i -= 1
467 466 if frame not in frames_repeated:
468 467 last_unique = i
469 468 break
470 469
471 470 if frame in last_seen_at:
472 471 distance = last_seen_at[frame] - i
473 472 longest_repeat = max(longest_repeat, distance)
474 473
475 474 last_seen_at[frame] = i
476 475 else:
477 476 last_unique = 0 # The whole traceback was recursion
478 477
479 478 return last_unique, longest_repeat
480 479
481 480 #---------------------------------------------------------------------------
482 481 # Module classes
483 482 class TBTools(colorable.Colorable):
484 483 """Basic tools used by all traceback printer classes."""
485 484
486 485 # Number of frames to skip when reporting tracebacks
487 486 tb_offset = 0
488 487
489 488 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
490 489 # Whether to call the interactive pdb debugger after printing
491 490 # tracebacks or not
492 491 super(TBTools, self).__init__(parent=parent, config=config)
493 492 self.call_pdb = call_pdb
494 493
495 494 # Output stream to write to. Note that we store the original value in
496 495 # a private attribute and then make the public ostream a property, so
497 496 # that we can delay accessing io.stdout until runtime. The way
498 497 # things are written now, the io.stdout object is dynamically managed
499 498 # so a reference to it should NEVER be stored statically. This
500 499 # property approach confines this detail to a single location, and all
501 500 # subclasses can simply access self.ostream for writing.
502 501 self._ostream = ostream
503 502
504 503 # Create color table
505 504 self.color_scheme_table = exception_colors()
506 505
507 506 self.set_colors(color_scheme)
508 507 self.old_scheme = color_scheme # save initial value for toggles
509 508
510 509 if call_pdb:
511 510 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
512 511 else:
513 512 self.pdb = None
514 513
515 514 def _get_ostream(self):
516 515 """Output stream that exceptions are written to.
517 516
518 517 Valid values are:
519 518
520 519 - None: the default, which means that IPython will dynamically resolve
521 520 to io.stdout. This ensures compatibility with most tools, including
522 521 Windows (where plain stdout doesn't recognize ANSI escapes).
523 522
524 523 - Any object with 'write' and 'flush' attributes.
525 524 """
526 return io.stdout if self._ostream is None else self._ostream
525 return sys.stdout if self._ostream is None else self._ostream
527 526
528 527 def _set_ostream(self, val):
529 528 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
530 529 self._ostream = val
531 530
532 531 ostream = property(_get_ostream, _set_ostream)
533 532
534 533 def set_colors(self, *args, **kw):
535 534 """Shorthand access to the color table scheme selector method."""
536 535
537 536 # Set own color table
538 537 self.color_scheme_table.set_active_scheme(*args, **kw)
539 538 # for convenience, set Colors to the active scheme
540 539 self.Colors = self.color_scheme_table.active_colors
541 540 # Also set colors of debugger
542 541 if hasattr(self, 'pdb') and self.pdb is not None:
543 542 self.pdb.set_colors(*args, **kw)
544 543
545 544 def color_toggle(self):
546 545 """Toggle between the currently active color scheme and NoColor."""
547 546
548 547 if self.color_scheme_table.active_scheme_name == 'NoColor':
549 548 self.color_scheme_table.set_active_scheme(self.old_scheme)
550 549 self.Colors = self.color_scheme_table.active_colors
551 550 else:
552 551 self.old_scheme = self.color_scheme_table.active_scheme_name
553 552 self.color_scheme_table.set_active_scheme('NoColor')
554 553 self.Colors = self.color_scheme_table.active_colors
555 554
556 555 def stb2text(self, stb):
557 556 """Convert a structured traceback (a list) to a string."""
558 557 return '\n'.join(stb)
559 558
560 559 def text(self, etype, value, tb, tb_offset=None, context=5):
561 560 """Return formatted traceback.
562 561
563 562 Subclasses may override this if they add extra arguments.
564 563 """
565 564 tb_list = self.structured_traceback(etype, value, tb,
566 565 tb_offset, context)
567 566 return self.stb2text(tb_list)
568 567
569 568 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
570 569 context=5, mode=None):
571 570 """Return a list of traceback frames.
572 571
573 572 Must be implemented by each class.
574 573 """
575 574 raise NotImplementedError()
576 575
577 576
578 577 #---------------------------------------------------------------------------
579 578 class ListTB(TBTools):
580 579 """Print traceback information from a traceback list, with optional color.
581 580
582 581 Calling requires 3 arguments: (etype, evalue, elist)
583 582 as would be obtained by::
584 583
585 584 etype, evalue, tb = sys.exc_info()
586 585 if tb:
587 586 elist = traceback.extract_tb(tb)
588 587 else:
589 588 elist = None
590 589
591 590 It can thus be used by programs which need to process the traceback before
592 591 printing (such as console replacements based on the code module from the
593 592 standard library).
594 593
595 594 Because they are meant to be called without a full traceback (only a
596 595 list), instances of this class can't call the interactive pdb debugger."""
597 596
598 597 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
599 598 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
600 599 ostream=ostream, parent=parent)
601 600
602 601 def __call__(self, etype, value, elist):
603 602 self.ostream.flush()
604 603 self.ostream.write(self.text(etype, value, elist))
605 604 self.ostream.write('\n')
606 605
607 606 def structured_traceback(self, etype, value, elist, tb_offset=None,
608 607 context=5):
609 608 """Return a color formatted string with the traceback info.
610 609
611 610 Parameters
612 611 ----------
613 612 etype : exception type
614 613 Type of the exception raised.
615 614
616 615 value : object
617 616 Data stored in the exception
618 617
619 618 elist : list
620 619 List of frames, see class docstring for details.
621 620
622 621 tb_offset : int, optional
623 622 Number of frames in the traceback to skip. If not given, the
624 623 instance value is used (set in constructor).
625 624
626 625 context : int, optional
627 626 Number of lines of context information to print.
628 627
629 628 Returns
630 629 -------
631 630 String with formatted exception.
632 631 """
633 632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
634 633 Colors = self.Colors
635 634 out_list = []
636 635 if elist:
637 636
638 637 if tb_offset and len(elist) > tb_offset:
639 638 elist = elist[tb_offset:]
640 639
641 640 out_list.append('Traceback %s(most recent call last)%s:' %
642 641 (Colors.normalEm, Colors.Normal) + '\n')
643 642 out_list.extend(self._format_list(elist))
644 643 # The exception info should be a single entry in the list.
645 644 lines = ''.join(self._format_exception_only(etype, value))
646 645 out_list.append(lines)
647 646
648 647 # Note: this code originally read:
649 648
650 649 ## for line in lines[:-1]:
651 650 ## out_list.append(" "+line)
652 651 ## out_list.append(lines[-1])
653 652
654 653 # This means it was indenting everything but the last line by a little
655 654 # bit. I've disabled this for now, but if we see ugliness somewhere we
656 655 # can restore it.
657 656
658 657 return out_list
659 658
660 659 def _format_list(self, extracted_list):
661 660 """Format a list of traceback entry tuples for printing.
662 661
663 662 Given a list of tuples as returned by extract_tb() or
664 663 extract_stack(), return a list of strings ready for printing.
665 664 Each string in the resulting list corresponds to the item with the
666 665 same index in the argument list. Each string ends in a newline;
667 666 the strings may contain internal newlines as well, for those items
668 667 whose source text line is not None.
669 668
670 669 Lifted almost verbatim from traceback.py
671 670 """
672 671
673 672 Colors = self.Colors
674 673 list = []
675 674 for filename, lineno, name, line in extracted_list[:-1]:
676 675 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
677 676 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
678 677 Colors.lineno, lineno, Colors.Normal,
679 678 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
680 679 if line:
681 680 item += ' %s\n' % line.strip()
682 681 list.append(item)
683 682 # Emphasize the last entry
684 683 filename, lineno, name, line = extracted_list[-1]
685 684 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
686 685 (Colors.normalEm,
687 686 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
688 687 Colors.linenoEm, lineno, Colors.normalEm,
689 688 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
690 689 Colors.Normal)
691 690 if line:
692 691 item += '%s %s%s\n' % (Colors.line, line.strip(),
693 692 Colors.Normal)
694 693 list.append(item)
695 694 return list
696 695
697 696 def _format_exception_only(self, etype, value):
698 697 """Format the exception part of a traceback.
699 698
700 699 The arguments are the exception type and value such as given by
701 700 sys.exc_info()[:2]. The return value is a list of strings, each ending
702 701 in a newline. Normally, the list contains a single string; however,
703 702 for SyntaxError exceptions, it contains several lines that (when
704 703 printed) display detailed information about where the syntax error
705 704 occurred. The message indicating which exception occurred is the
706 705 always last string in the list.
707 706
708 707 Also lifted nearly verbatim from traceback.py
709 708 """
710 709 have_filedata = False
711 710 Colors = self.Colors
712 711 list = []
713 712 stype = Colors.excName + etype.__name__ + Colors.Normal
714 713 if value is None:
715 714 # Not sure if this can still happen in Python 2.6 and above
716 715 list.append(py3compat.cast_unicode(stype) + '\n')
717 716 else:
718 717 if issubclass(etype, SyntaxError):
719 718 have_filedata = True
720 719 if not value.filename: value.filename = "<string>"
721 720 if value.lineno:
722 721 lineno = value.lineno
723 722 textline = ulinecache.getline(value.filename, value.lineno)
724 723 else:
725 724 lineno = 'unknown'
726 725 textline = ''
727 726 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
728 727 (Colors.normalEm,
729 728 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
730 729 Colors.linenoEm, lineno, Colors.Normal ))
731 730 if textline == '':
732 731 textline = py3compat.cast_unicode(value.text, "utf-8")
733 732
734 733 if textline is not None:
735 734 i = 0
736 735 while i < len(textline) and textline[i].isspace():
737 736 i += 1
738 737 list.append('%s %s%s\n' % (Colors.line,
739 738 textline.strip(),
740 739 Colors.Normal))
741 740 if value.offset is not None:
742 741 s = ' '
743 742 for c in textline[i:value.offset - 1]:
744 743 if c.isspace():
745 744 s += c
746 745 else:
747 746 s += ' '
748 747 list.append('%s%s^%s\n' % (Colors.caret, s,
749 748 Colors.Normal))
750 749
751 750 try:
752 751 s = value.msg
753 752 except Exception:
754 753 s = self._some_str(value)
755 754 if s:
756 755 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
757 756 Colors.Normal, s))
758 757 else:
759 758 list.append('%s\n' % str(stype))
760 759
761 760 # sync with user hooks
762 761 if have_filedata:
763 762 ipinst = get_ipython()
764 763 if ipinst is not None:
765 764 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
766 765
767 766 return list
768 767
769 768 def get_exception_only(self, etype, value):
770 769 """Only print the exception type and message, without a traceback.
771 770
772 771 Parameters
773 772 ----------
774 773 etype : exception type
775 774 value : exception value
776 775 """
777 776 return ListTB.structured_traceback(self, etype, value, [])
778 777
779 778 def show_exception_only(self, etype, evalue):
780 779 """Only print the exception type and message, without a traceback.
781 780
782 781 Parameters
783 782 ----------
784 783 etype : exception type
785 784 value : exception value
786 785 """
787 786 # This method needs to use __call__ from *this* class, not the one from
788 787 # a subclass whose signature or behavior may be different
789 788 ostream = self.ostream
790 789 ostream.flush()
791 790 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
792 791 ostream.flush()
793 792
794 793 def _some_str(self, value):
795 794 # Lifted from traceback.py
796 795 try:
797 796 return str(value)
798 797 except:
799 798 return '<unprintable %s object>' % type(value).__name__
800 799
801 800
802 801 #----------------------------------------------------------------------------
803 802 class VerboseTB(TBTools):
804 803 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
805 804 of HTML. Requires inspect and pydoc. Crazy, man.
806 805
807 806 Modified version which optionally strips the topmost entries from the
808 807 traceback, to be used with alternate interpreters (because their own code
809 808 would appear in the traceback)."""
810 809
811 810 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
812 811 tb_offset=0, long_header=False, include_vars=True,
813 812 check_cache=None):
814 813 """Specify traceback offset, headers and color scheme.
815 814
816 815 Define how many frames to drop from the tracebacks. Calling it with
817 816 tb_offset=1 allows use of this handler in interpreters which will have
818 817 their own code at the top of the traceback (VerboseTB will first
819 818 remove that frame before printing the traceback info)."""
820 819 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
821 820 ostream=ostream)
822 821 self.tb_offset = tb_offset
823 822 self.long_header = long_header
824 823 self.include_vars = include_vars
825 824 # By default we use linecache.checkcache, but the user can provide a
826 825 # different check_cache implementation. This is used by the IPython
827 826 # kernel to provide tracebacks for interactive code that is cached,
828 827 # by a compiler instance that flushes the linecache but preserves its
829 828 # own code cache.
830 829 if check_cache is None:
831 830 check_cache = linecache.checkcache
832 831 self.check_cache = check_cache
833 832
834 833 def format_records(self, records, last_unique, recursion_repeat):
835 834 """Format the stack frames of the traceback"""
836 835 frames = []
837 836 for r in records[:last_unique+recursion_repeat+1]:
838 837 #print '*** record:',file,lnum,func,lines,index # dbg
839 838 frames.append(self.format_record(*r))
840 839
841 840 if recursion_repeat:
842 841 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
843 842 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
844 843
845 844 return frames
846 845
847 846 def format_record(self, frame, file, lnum, func, lines, index):
848 847 """Format a single stack frame"""
849 848 Colors = self.Colors # just a shorthand + quicker name lookup
850 849 ColorsNormal = Colors.Normal # used a lot
851 850 col_scheme = self.color_scheme_table.active_scheme_name
852 851 indent = ' ' * INDENT_SIZE
853 852 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
854 853 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
855 854 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
856 855 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
857 856 ColorsNormal)
858 857 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
859 858 (Colors.vName, Colors.valEm, ColorsNormal)
860 859 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
861 860 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
862 861 Colors.vName, ColorsNormal)
863 862 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
864 863
865 864 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
866 865 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
867 866 ColorsNormal)
868 867
869 868 abspath = os.path.abspath
870 869
871 870
872 871 if not file:
873 872 file = '?'
874 873 elif file.startswith(str("<")) and file.endswith(str(">")):
875 874 # Not a real filename, no problem...
876 875 pass
877 876 elif not os.path.isabs(file):
878 877 # Try to make the filename absolute by trying all
879 878 # sys.path entries (which is also what linecache does)
880 879 for dirname in sys.path:
881 880 try:
882 881 fullname = os.path.join(dirname, file)
883 882 if os.path.isfile(fullname):
884 883 file = os.path.abspath(fullname)
885 884 break
886 885 except Exception:
887 886 # Just in case that sys.path contains very
888 887 # strange entries...
889 888 pass
890 889
891 890 file = py3compat.cast_unicode(file, util_path.fs_encoding)
892 891 link = tpl_link % file
893 892 args, varargs, varkw, locals = fixed_getargvalues(frame)
894 893
895 894 if func == '?':
896 895 call = ''
897 896 else:
898 897 # Decide whether to include variable details or not
899 898 var_repr = self.include_vars and eqrepr or nullrepr
900 899 try:
901 900 call = tpl_call % (func, inspect.formatargvalues(args,
902 901 varargs, varkw,
903 902 locals, formatvalue=var_repr))
904 903 except KeyError:
905 904 # This happens in situations like errors inside generator
906 905 # expressions, where local variables are listed in the
907 906 # line, but can't be extracted from the frame. I'm not
908 907 # 100% sure this isn't actually a bug in inspect itself,
909 908 # but since there's no info for us to compute with, the
910 909 # best we can do is report the failure and move on. Here
911 910 # we must *not* call any traceback construction again,
912 911 # because that would mess up use of %debug later on. So we
913 912 # simply report the failure and move on. The only
914 913 # limitation will be that this frame won't have locals
915 914 # listed in the call signature. Quite subtle problem...
916 915 # I can't think of a good way to validate this in a unit
917 916 # test, but running a script consisting of:
918 917 # dict( (k,v.strip()) for (k,v) in range(10) )
919 918 # will illustrate the error, if this exception catch is
920 919 # disabled.
921 920 call = tpl_call_fail % func
922 921
923 922 # Don't attempt to tokenize binary files.
924 923 if file.endswith(('.so', '.pyd', '.dll')):
925 924 return '%s %s\n' % (link, call)
926 925
927 926 elif file.endswith(('.pyc', '.pyo')):
928 927 # Look up the corresponding source file.
929 928 file = openpy.source_from_cache(file)
930 929
931 930 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
932 931 line = getline(file, lnum[0])
933 932 lnum[0] += 1
934 933 return line
935 934
936 935 # Build the list of names on this line of code where the exception
937 936 # occurred.
938 937 try:
939 938 names = []
940 939 name_cont = False
941 940
942 941 for token_type, token, start, end, line in generate_tokens(linereader):
943 942 # build composite names
944 943 if token_type == tokenize.NAME and token not in keyword.kwlist:
945 944 if name_cont:
946 945 # Continuation of a dotted name
947 946 try:
948 947 names[-1].append(token)
949 948 except IndexError:
950 949 names.append([token])
951 950 name_cont = False
952 951 else:
953 952 # Regular new names. We append everything, the caller
954 953 # will be responsible for pruning the list later. It's
955 954 # very tricky to try to prune as we go, b/c composite
956 955 # names can fool us. The pruning at the end is easy
957 956 # to do (or the caller can print a list with repeated
958 957 # names if so desired.
959 958 names.append([token])
960 959 elif token == '.':
961 960 name_cont = True
962 961 elif token_type == tokenize.NEWLINE:
963 962 break
964 963
965 964 except (IndexError, UnicodeDecodeError, SyntaxError):
966 965 # signals exit of tokenizer
967 966 # SyntaxError can occur if the file is not actually Python
968 967 # - see gh-6300
969 968 pass
970 969 except tokenize.TokenError as msg:
971 970 _m = ("An unexpected error occurred while tokenizing input\n"
972 971 "The following traceback may be corrupted or invalid\n"
973 972 "The error message is: %s\n" % msg)
974 973 error(_m)
975 974
976 975 # Join composite names (e.g. "dict.fromkeys")
977 976 names = ['.'.join(n) for n in names]
978 977 # prune names list of duplicates, but keep the right order
979 978 unique_names = uniq_stable(names)
980 979
981 980 # Start loop over vars
982 981 lvals = []
983 982 if self.include_vars:
984 983 for name_full in unique_names:
985 984 name_base = name_full.split('.', 1)[0]
986 985 if name_base in frame.f_code.co_varnames:
987 986 if name_base in locals:
988 987 try:
989 988 value = repr(eval(name_full, locals))
990 989 except:
991 990 value = undefined
992 991 else:
993 992 value = undefined
994 993 name = tpl_local_var % name_full
995 994 else:
996 995 if name_base in frame.f_globals:
997 996 try:
998 997 value = repr(eval(name_full, frame.f_globals))
999 998 except:
1000 999 value = undefined
1001 1000 else:
1002 1001 value = undefined
1003 1002 name = tpl_global_var % name_full
1004 1003 lvals.append(tpl_name_val % (name, value))
1005 1004 if lvals:
1006 1005 lvals = '%s%s' % (indent, em_normal.join(lvals))
1007 1006 else:
1008 1007 lvals = ''
1009 1008
1010 1009 level = '%s %s\n' % (link, call)
1011 1010
1012 1011 if index is None:
1013 1012 return level
1014 1013 else:
1015 1014 return '%s%s' % (level, ''.join(
1016 1015 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1017 1016 col_scheme)))
1018 1017
1019 1018 def prepare_chained_exception_message(self, cause):
1020 1019 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1021 1020 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1022 1021
1023 1022 if cause:
1024 1023 message = [[direct_cause]]
1025 1024 else:
1026 1025 message = [[exception_during_handling]]
1027 1026 return message
1028 1027
1029 1028 def prepare_header(self, etype, long_version=False):
1030 1029 colors = self.Colors # just a shorthand + quicker name lookup
1031 1030 colorsnormal = colors.Normal # used a lot
1032 1031 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1033 1032 width = min(75, get_terminal_size()[0])
1034 1033 if long_version:
1035 1034 # Header with the exception type, python version, and date
1036 1035 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1037 1036 date = time.ctime(time.time())
1038 1037
1039 1038 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1040 1039 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1041 1040 pyver, date.rjust(width) )
1042 1041 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1043 1042 "\ncalls leading up to the error, with the most recent (innermost) call last."
1044 1043 else:
1045 1044 # Simplified header
1046 1045 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1047 1046 rjust(width - len(str(etype))) )
1048 1047
1049 1048 return head
1050 1049
1051 1050 def format_exception(self, etype, evalue):
1052 1051 colors = self.Colors # just a shorthand + quicker name lookup
1053 1052 colorsnormal = colors.Normal # used a lot
1054 1053 indent = ' ' * INDENT_SIZE
1055 1054 # Get (safely) a string form of the exception info
1056 1055 try:
1057 1056 etype_str, evalue_str = map(str, (etype, evalue))
1058 1057 except:
1059 1058 # User exception is improperly defined.
1060 1059 etype, evalue = str, sys.exc_info()[:2]
1061 1060 etype_str, evalue_str = map(str, (etype, evalue))
1062 1061 # ... and format it
1063 1062 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1064 1063 colorsnormal, py3compat.cast_unicode(evalue_str))]
1065 1064
1066 1065 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1067 1066 try:
1068 1067 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1069 1068 except:
1070 1069 # Every now and then, an object with funny internals blows up
1071 1070 # when dir() is called on it. We do the best we can to report
1072 1071 # the problem and continue
1073 1072 _m = '%sException reporting error (object with broken dir())%s:'
1074 1073 exception.append(_m % (colors.excName, colorsnormal))
1075 1074 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1076 1075 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1077 1076 colorsnormal, py3compat.cast_unicode(evalue_str)))
1078 1077 names = []
1079 1078 for name in names:
1080 1079 value = text_repr(getattr(evalue, name))
1081 1080 exception.append('\n%s%s = %s' % (indent, name, value))
1082 1081
1083 1082 return exception
1084 1083
1085 1084 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1086 1085 """Formats the header, traceback and exception message for a single exception.
1087 1086
1088 1087 This may be called multiple times by Python 3 exception chaining
1089 1088 (PEP 3134).
1090 1089 """
1091 1090 # some locals
1092 1091 orig_etype = etype
1093 1092 try:
1094 1093 etype = etype.__name__
1095 1094 except AttributeError:
1096 1095 pass
1097 1096
1098 1097 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1099 1098 head = self.prepare_header(etype, self.long_header)
1100 1099 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1101 1100
1102 1101 if records is None:
1103 1102 return ""
1104 1103
1105 1104 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1106 1105
1107 1106 frames = self.format_records(records, last_unique, recursion_repeat)
1108 1107
1109 1108 formatted_exception = self.format_exception(etype, evalue)
1110 1109 if records:
1111 1110 filepath, lnum = records[-1][1:3]
1112 1111 filepath = os.path.abspath(filepath)
1113 1112 ipinst = get_ipython()
1114 1113 if ipinst is not None:
1115 1114 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1116 1115
1117 1116 return [[head] + frames + [''.join(formatted_exception[0])]]
1118 1117
1119 1118 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1120 1119 try:
1121 1120 # Try the default getinnerframes and Alex's: Alex's fixes some
1122 1121 # problems, but it generates empty tracebacks for console errors
1123 1122 # (5 blanks lines) where none should be returned.
1124 1123 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1125 1124 except:
1126 1125 # FIXME: I've been getting many crash reports from python 2.3
1127 1126 # users, traceable to inspect.py. If I can find a small test-case
1128 1127 # to reproduce this, I should either write a better workaround or
1129 1128 # file a bug report against inspect (if that's the real problem).
1130 1129 # So far, I haven't been able to find an isolated example to
1131 1130 # reproduce the problem.
1132 1131 inspect_error()
1133 1132 traceback.print_exc(file=self.ostream)
1134 1133 info('\nUnfortunately, your original traceback can not be constructed.\n')
1135 1134 return None
1136 1135
1137 1136 def get_parts_of_chained_exception(self, evalue):
1138 1137 def get_chained_exception(exception_value):
1139 1138 cause = getattr(exception_value, '__cause__', None)
1140 1139 if cause:
1141 1140 return cause
1142 1141 if getattr(exception_value, '__suppress_context__', False):
1143 1142 return None
1144 1143 return getattr(exception_value, '__context__', None)
1145 1144
1146 1145 chained_evalue = get_chained_exception(evalue)
1147 1146
1148 1147 if chained_evalue:
1149 1148 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1150 1149
1151 1150 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1152 1151 number_of_lines_of_context=5):
1153 1152 """Return a nice text document describing the traceback."""
1154 1153
1155 1154 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1156 1155 tb_offset)
1157 1156
1158 1157 colors = self.Colors # just a shorthand + quicker name lookup
1159 1158 colorsnormal = colors.Normal # used a lot
1160 1159 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1161 1160 structured_traceback_parts = [head]
1162 1161 if py3compat.PY3:
1163 1162 chained_exceptions_tb_offset = 0
1164 1163 lines_of_context = 3
1165 1164 formatted_exceptions = formatted_exception
1166 1165 exception = self.get_parts_of_chained_exception(evalue)
1167 1166 if exception:
1168 1167 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1169 1168 etype, evalue, etb = exception
1170 1169 else:
1171 1170 evalue = None
1172 1171 chained_exc_ids = set()
1173 1172 while evalue:
1174 1173 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1175 1174 chained_exceptions_tb_offset)
1176 1175 exception = self.get_parts_of_chained_exception(evalue)
1177 1176
1178 1177 if exception and not id(exception[1]) in chained_exc_ids:
1179 1178 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1180 1179 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1181 1180 etype, evalue, etb = exception
1182 1181 else:
1183 1182 evalue = None
1184 1183
1185 1184 # we want to see exceptions in a reversed order:
1186 1185 # the first exception should be on top
1187 1186 for formatted_exception in reversed(formatted_exceptions):
1188 1187 structured_traceback_parts += formatted_exception
1189 1188 else:
1190 1189 structured_traceback_parts += formatted_exception[0]
1191 1190
1192 1191 return structured_traceback_parts
1193 1192
1194 1193 def debugger(self, force=False):
1195 1194 """Call up the pdb debugger if desired, always clean up the tb
1196 1195 reference.
1197 1196
1198 1197 Keywords:
1199 1198
1200 1199 - force(False): by default, this routine checks the instance call_pdb
1201 1200 flag and does not actually invoke the debugger if the flag is false.
1202 1201 The 'force' option forces the debugger to activate even if the flag
1203 1202 is false.
1204 1203
1205 1204 If the call_pdb flag is set, the pdb interactive debugger is
1206 1205 invoked. In all cases, the self.tb reference to the current traceback
1207 1206 is deleted to prevent lingering references which hamper memory
1208 1207 management.
1209 1208
1210 1209 Note that each call to pdb() does an 'import readline', so if your app
1211 1210 requires a special setup for the readline completers, you'll have to
1212 1211 fix that by hand after invoking the exception handler."""
1213 1212
1214 1213 if force or self.call_pdb:
1215 1214 if self.pdb is None:
1216 1215 self.pdb = debugger.Pdb(
1217 1216 self.color_scheme_table.active_scheme_name)
1218 1217 # the system displayhook may have changed, restore the original
1219 1218 # for pdb
1220 1219 display_trap = DisplayTrap(hook=sys.__displayhook__)
1221 1220 with display_trap:
1222 1221 self.pdb.reset()
1223 1222 # Find the right frame so we don't pop up inside ipython itself
1224 1223 if hasattr(self, 'tb') and self.tb is not None:
1225 1224 etb = self.tb
1226 1225 else:
1227 1226 etb = self.tb = sys.last_traceback
1228 1227 while self.tb is not None and self.tb.tb_next is not None:
1229 1228 self.tb = self.tb.tb_next
1230 1229 if etb and etb.tb_next:
1231 1230 etb = etb.tb_next
1232 1231 self.pdb.botframe = etb.tb_frame
1233 1232 self.pdb.interaction(self.tb.tb_frame, self.tb)
1234 1233
1235 1234 if hasattr(self, 'tb'):
1236 1235 del self.tb
1237 1236
1238 1237 def handler(self, info=None):
1239 1238 (etype, evalue, etb) = info or sys.exc_info()
1240 1239 self.tb = etb
1241 1240 ostream = self.ostream
1242 1241 ostream.flush()
1243 1242 ostream.write(self.text(etype, evalue, etb))
1244 1243 ostream.write('\n')
1245 1244 ostream.flush()
1246 1245
1247 1246 # Changed so an instance can just be called as VerboseTB_inst() and print
1248 1247 # out the right info on its own.
1249 1248 def __call__(self, etype=None, evalue=None, etb=None):
1250 1249 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1251 1250 if etb is None:
1252 1251 self.handler()
1253 1252 else:
1254 1253 self.handler((etype, evalue, etb))
1255 1254 try:
1256 1255 self.debugger()
1257 1256 except KeyboardInterrupt:
1258 1257 print("\nKeyboardInterrupt")
1259 1258
1260 1259
1261 1260 #----------------------------------------------------------------------------
1262 1261 class FormattedTB(VerboseTB, ListTB):
1263 1262 """Subclass ListTB but allow calling with a traceback.
1264 1263
1265 1264 It can thus be used as a sys.excepthook for Python > 2.1.
1266 1265
1267 1266 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1268 1267
1269 1268 Allows a tb_offset to be specified. This is useful for situations where
1270 1269 one needs to remove a number of topmost frames from the traceback (such as
1271 1270 occurs with python programs that themselves execute other python code,
1272 1271 like Python shells). """
1273 1272
1274 1273 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1275 1274 ostream=None,
1276 1275 tb_offset=0, long_header=False, include_vars=False,
1277 1276 check_cache=None):
1278 1277
1279 1278 # NEVER change the order of this list. Put new modes at the end:
1280 1279 self.valid_modes = ['Plain', 'Context', 'Verbose']
1281 1280 self.verbose_modes = self.valid_modes[1:3]
1282 1281
1283 1282 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1284 1283 ostream=ostream, tb_offset=tb_offset,
1285 1284 long_header=long_header, include_vars=include_vars,
1286 1285 check_cache=check_cache)
1287 1286
1288 1287 # Different types of tracebacks are joined with different separators to
1289 1288 # form a single string. They are taken from this dict
1290 1289 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1291 1290 # set_mode also sets the tb_join_char attribute
1292 1291 self.set_mode(mode)
1293 1292
1294 1293 def _extract_tb(self, tb):
1295 1294 if tb:
1296 1295 return traceback.extract_tb(tb)
1297 1296 else:
1298 1297 return None
1299 1298
1300 1299 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1301 1300 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1302 1301 mode = self.mode
1303 1302 if mode in self.verbose_modes:
1304 1303 # Verbose modes need a full traceback
1305 1304 return VerboseTB.structured_traceback(
1306 1305 self, etype, value, tb, tb_offset, number_of_lines_of_context
1307 1306 )
1308 1307 else:
1309 1308 # We must check the source cache because otherwise we can print
1310 1309 # out-of-date source code.
1311 1310 self.check_cache()
1312 1311 # Now we can extract and format the exception
1313 1312 elist = self._extract_tb(tb)
1314 1313 return ListTB.structured_traceback(
1315 1314 self, etype, value, elist, tb_offset, number_of_lines_of_context
1316 1315 )
1317 1316
1318 1317 def stb2text(self, stb):
1319 1318 """Convert a structured traceback (a list) to a string."""
1320 1319 return self.tb_join_char.join(stb)
1321 1320
1322 1321
1323 1322 def set_mode(self, mode=None):
1324 1323 """Switch to the desired mode.
1325 1324
1326 1325 If mode is not specified, cycles through the available modes."""
1327 1326
1328 1327 if not mode:
1329 1328 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1330 1329 len(self.valid_modes)
1331 1330 self.mode = self.valid_modes[new_idx]
1332 1331 elif mode not in self.valid_modes:
1333 1332 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1334 1333 'Valid modes: ' + str(self.valid_modes))
1335 1334 else:
1336 1335 self.mode = mode
1337 1336 # include variable details only in 'Verbose' mode
1338 1337 self.include_vars = (self.mode == self.valid_modes[2])
1339 1338 # Set the join character for generating text tracebacks
1340 1339 self.tb_join_char = self._join_chars[self.mode]
1341 1340
1342 1341 # some convenient shortcuts
1343 1342 def plain(self):
1344 1343 self.set_mode(self.valid_modes[0])
1345 1344
1346 1345 def context(self):
1347 1346 self.set_mode(self.valid_modes[1])
1348 1347
1349 1348 def verbose(self):
1350 1349 self.set_mode(self.valid_modes[2])
1351 1350
1352 1351
1353 1352 #----------------------------------------------------------------------------
1354 1353 class AutoFormattedTB(FormattedTB):
1355 1354 """A traceback printer which can be called on the fly.
1356 1355
1357 1356 It will find out about exceptions by itself.
1358 1357
1359 1358 A brief example::
1360 1359
1361 1360 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1362 1361 try:
1363 1362 ...
1364 1363 except:
1365 1364 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1366 1365 """
1367 1366
1368 1367 def __call__(self, etype=None, evalue=None, etb=None,
1369 1368 out=None, tb_offset=None):
1370 1369 """Print out a formatted exception traceback.
1371 1370
1372 1371 Optional arguments:
1373 1372 - out: an open file-like object to direct output to.
1374 1373
1375 1374 - tb_offset: the number of frames to skip over in the stack, on a
1376 1375 per-call basis (this overrides temporarily the instance's tb_offset
1377 1376 given at initialization time. """
1378 1377
1379 1378 if out is None:
1380 1379 out = self.ostream
1381 1380 out.flush()
1382 1381 out.write(self.text(etype, evalue, etb, tb_offset))
1383 1382 out.write('\n')
1384 1383 out.flush()
1385 1384 # FIXME: we should remove the auto pdb behavior from here and leave
1386 1385 # that to the clients.
1387 1386 try:
1388 1387 self.debugger()
1389 1388 except KeyboardInterrupt:
1390 1389 print("\nKeyboardInterrupt")
1391 1390
1392 1391 def structured_traceback(self, etype=None, value=None, tb=None,
1393 1392 tb_offset=None, number_of_lines_of_context=5):
1394 1393 if etype is None:
1395 1394 etype, value, tb = sys.exc_info()
1396 1395 self.tb = tb
1397 1396 return FormattedTB.structured_traceback(
1398 1397 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1399 1398
1400 1399
1401 1400 #---------------------------------------------------------------------------
1402 1401
1403 1402 # A simple class to preserve Nathan's original functionality.
1404 1403 class ColorTB(FormattedTB):
1405 1404 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1406 1405
1407 1406 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1408 1407 FormattedTB.__init__(self, color_scheme=color_scheme,
1409 1408 call_pdb=call_pdb, **kwargs)
1410 1409
1411 1410
1412 1411 class SyntaxTB(ListTB):
1413 1412 """Extension which holds some state: the last exception value"""
1414 1413
1415 1414 def __init__(self, color_scheme='NoColor'):
1416 1415 ListTB.__init__(self, color_scheme)
1417 1416 self.last_syntax_error = None
1418 1417
1419 1418 def __call__(self, etype, value, elist):
1420 1419 self.last_syntax_error = value
1421 1420
1422 1421 ListTB.__call__(self, etype, value, elist)
1423 1422
1424 1423 def structured_traceback(self, etype, value, elist, tb_offset=None,
1425 1424 context=5):
1426 1425 # If the source file has been edited, the line in the syntax error can
1427 1426 # be wrong (retrieved from an outdated cache). This replaces it with
1428 1427 # the current value.
1429 1428 if isinstance(value, SyntaxError) \
1430 1429 and isinstance(value.filename, py3compat.string_types) \
1431 1430 and isinstance(value.lineno, int):
1432 1431 linecache.checkcache(value.filename)
1433 1432 newtext = ulinecache.getline(value.filename, value.lineno)
1434 1433 if newtext:
1435 1434 value.text = newtext
1436 1435 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1437 1436 tb_offset=tb_offset, context=context)
1438 1437
1439 1438 def clear_err_state(self):
1440 1439 """Return the current error state and clear it"""
1441 1440 e = self.last_syntax_error
1442 1441 self.last_syntax_error = None
1443 1442 return e
1444 1443
1445 1444 def stb2text(self, stb):
1446 1445 """Convert a structured traceback (a list) to a string."""
1447 1446 return ''.join(stb)
1448 1447
1449 1448
1450 1449 # some internal-use functions
1451 1450 def text_repr(value):
1452 1451 """Hopefully pretty robust repr equivalent."""
1453 1452 # this is pretty horrible but should always return *something*
1454 1453 try:
1455 1454 return pydoc.text.repr(value)
1456 1455 except KeyboardInterrupt:
1457 1456 raise
1458 1457 except:
1459 1458 try:
1460 1459 return repr(value)
1461 1460 except KeyboardInterrupt:
1462 1461 raise
1463 1462 except:
1464 1463 try:
1465 1464 # all still in an except block so we catch
1466 1465 # getattr raising
1467 1466 name = getattr(value, '__name__', None)
1468 1467 if name:
1469 1468 # ick, recursion
1470 1469 return text_repr(name)
1471 1470 klass = getattr(value, '__class__', None)
1472 1471 if klass:
1473 1472 return '%s instance' % text_repr(klass)
1474 1473 except KeyboardInterrupt:
1475 1474 raise
1476 1475 except:
1477 1476 return 'UNRECOVERABLE REPR FAILURE'
1478 1477
1479 1478
1480 1479 def eqrepr(value, repr=text_repr):
1481 1480 return '=%s' % repr(value)
1482 1481
1483 1482
1484 1483 def nullrepr(value, repr=text_repr):
1485 1484 return ''
@@ -1,583 +1,583 b''
1 1 """Module for interactive demos using IPython.
2 2
3 3 This module implements a few classes for running Python scripts interactively
4 4 in IPython for demonstrations. With very simple markup (a few tags in
5 5 comments), you can control points where the script stops executing and returns
6 6 control to IPython.
7 7
8 8
9 9 Provided classes
10 10 ----------------
11 11
12 12 The classes are (see their docstrings for further details):
13 13
14 14 - Demo: pure python demos
15 15
16 16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 17 typed interactively (so magics work, as well as any other special syntax you
18 18 may have added via input prefilters).
19 19
20 20 - LineDemo: single-line version of the Demo class. These demos are executed
21 21 one line at a time, and require no markup.
22 22
23 23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 24 executed a line at a time, but processed via IPython).
25 25
26 26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 27 declares an empty marquee and a pre_cmd that clears the screen before each
28 28 block (see Subclassing below).
29 29
30 30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 31 classes.
32 32
33 33 Inheritance diagram:
34 34
35 35 .. inheritance-diagram:: IPython.lib.demo
36 36 :parts: 3
37 37
38 38 Subclassing
39 39 -----------
40 40
41 41 The classes here all include a few methods meant to make customization by
42 42 subclassing more convenient. Their docstrings below have some more details:
43 43
44 44 - marquee(): generates a marquee to provide visible on-screen markers at each
45 45 block start and end.
46 46
47 47 - pre_cmd(): run right before the execution of each block.
48 48
49 49 - post_cmd(): run right after the execution of each block. If the block
50 50 raises an exception, this is NOT called.
51 51
52 52
53 53 Operation
54 54 ---------
55 55
56 56 The file is run in its own empty namespace (though you can pass it a string of
57 57 arguments as if in a command line environment, and it will see those as
58 58 sys.argv). But at each stop, the global IPython namespace is updated with the
59 59 current internal demo namespace, so you can work interactively with the data
60 60 accumulated so far.
61 61
62 62 By default, each block of code is printed (with syntax highlighting) before
63 63 executing it and you have to confirm execution. This is intended to show the
64 64 code to an audience first so you can discuss it, and only proceed with
65 65 execution once you agree. There are a few tags which allow you to modify this
66 66 behavior.
67 67
68 68 The supported tags are:
69 69
70 70 # <demo> stop
71 71
72 72 Defines block boundaries, the points where IPython stops execution of the
73 73 file and returns to the interactive prompt.
74 74
75 75 You can optionally mark the stop tag with extra dashes before and after the
76 76 word 'stop', to help visually distinguish the blocks in a text editor:
77 77
78 78 # <demo> --- stop ---
79 79
80 80
81 81 # <demo> silent
82 82
83 83 Make a block execute silently (and hence automatically). Typically used in
84 84 cases where you have some boilerplate or initialization code which you need
85 85 executed but do not want to be seen in the demo.
86 86
87 87 # <demo> auto
88 88
89 89 Make a block execute automatically, but still being printed. Useful for
90 90 simple code which does not warrant discussion, since it avoids the extra
91 91 manual confirmation.
92 92
93 93 # <demo> auto_all
94 94
95 95 This tag can _only_ be in the first block, and if given it overrides the
96 96 individual auto tags to make the whole demo fully automatic (no block asks
97 97 for confirmation). It can also be given at creation time (or the attribute
98 98 set later) to override what's in the file.
99 99
100 100 While _any_ python file can be run as a Demo instance, if there are no stop
101 101 tags the whole file will run in a single block (no different that calling
102 102 first %pycat and then %run). The minimal markup to make this useful is to
103 103 place a set of stop tags; the other tags are only there to let you fine-tune
104 104 the execution.
105 105
106 106 This is probably best explained with the simple example file below. You can
107 107 copy this into a file named ex_demo.py, and try running it via::
108 108
109 109 from IPython.demo import Demo
110 110 d = Demo('ex_demo.py')
111 111 d()
112 112
113 113 Each time you call the demo object, it runs the next block. The demo object
114 114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
115 115 and back(). It can be reset for a new run via reset() or reloaded from disk
116 116 (in case you've edited the source) via reload(). See their docstrings below.
117 117
118 118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
119 119 been added to the "docs/examples/core" directory. Just cd to this directory in
120 120 an IPython session, and type::
121 121
122 122 %run demo-exercizer.py
123 123
124 124 and then follow the directions.
125 125
126 126 Example
127 127 -------
128 128
129 129 The following is a very simple example of a valid demo file.
130 130
131 131 ::
132 132
133 133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
135 135
136 136 print 'Hello, welcome to an interactive IPython demo.'
137 137
138 138 # The mark below defines a block boundary, which is a point where IPython will
139 139 # stop execution and return to the interactive prompt. The dashes are actually
140 140 # optional and used only as a visual aid to clearly separate blocks while
141 141 # editing the demo code.
142 142 # <demo> stop
143 143
144 144 x = 1
145 145 y = 2
146 146
147 147 # <demo> stop
148 148
149 149 # the mark below makes this block as silent
150 150 # <demo> silent
151 151
152 152 print 'This is a silent block, which gets executed but not printed.'
153 153
154 154 # <demo> stop
155 155 # <demo> auto
156 156 print 'This is an automatic block.'
157 157 print 'It is executed without asking for confirmation, but printed.'
158 158 z = x+y
159 159
160 160 print 'z=',x
161 161
162 162 # <demo> stop
163 163 # This is just another normal block.
164 164 print 'z is now:', z
165 165
166 166 print 'bye!'
167 167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
168 168 """
169 169
170 170 from __future__ import unicode_literals
171 171
172 172 #*****************************************************************************
173 173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
174 174 #
175 175 # Distributed under the terms of the BSD License. The full license is in
176 176 # the file COPYING, distributed as part of this software.
177 177 #
178 178 #*****************************************************************************
179 179 from __future__ import print_function
180 180
181 181 import os
182 182 import re
183 183 import shlex
184 184 import sys
185 185
186 186 from IPython.utils import io
187 187 from IPython.utils.text import marquee
188 188 from IPython.utils import openpy
189 189 from IPython.utils import py3compat
190 190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191 191
192 192 class DemoError(Exception): pass
193 193
194 194 def re_mark(mark):
195 195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196 196
197 197 class Demo(object):
198 198
199 199 re_stop = re_mark('-*\s?stop\s?-*')
200 200 re_silent = re_mark('silent')
201 201 re_auto = re_mark('auto')
202 202 re_auto_all = re_mark('auto_all')
203 203
204 204 def __init__(self,src,title='',arg_str='',auto_all=None):
205 205 """Make a new demo object. To run the demo, simply call the object.
206 206
207 207 See the module docstring for full details and an example (you can use
208 208 IPython.Demo? in IPython to see it).
209 209
210 210 Inputs:
211 211
212 212 - src is either a file, or file-like object, or a
213 213 string that can be resolved to a filename.
214 214
215 215 Optional inputs:
216 216
217 217 - title: a string to use as the demo name. Of most use when the demo
218 218 you are making comes from an object that has no filename, or if you
219 219 want an alternate denotation distinct from the filename.
220 220
221 221 - arg_str(''): a string of arguments, internally converted to a list
222 222 just like sys.argv, so the demo script can see a similar
223 223 environment.
224 224
225 225 - auto_all(None): global flag to run all blocks automatically without
226 226 confirmation. This attribute overrides the block-level tags and
227 227 applies to the whole demo. It is an attribute of the object, and
228 228 can be changed at runtime simply by reassigning it to a boolean
229 229 value.
230 230 """
231 231 if hasattr(src, "read"):
232 232 # It seems to be a file or a file-like object
233 233 self.fname = "from a file-like object"
234 234 if title == '':
235 235 self.title = "from a file-like object"
236 236 else:
237 237 self.title = title
238 238 else:
239 239 # Assume it's a string or something that can be converted to one
240 240 self.fname = src
241 241 if title == '':
242 242 (filepath, filename) = os.path.split(src)
243 243 self.title = filename
244 244 else:
245 245 self.title = title
246 246 self.sys_argv = [src] + shlex.split(arg_str)
247 247 self.auto_all = auto_all
248 248 self.src = src
249 249
250 250 # get a few things from ipython. While it's a bit ugly design-wise,
251 251 # it ensures that things like color scheme and the like are always in
252 252 # sync with the ipython mode being used. This class is only meant to
253 253 # be used inside ipython anyways, so it's OK.
254 254 ip = get_ipython() # this is in builtins whenever IPython is running
255 255 self.ip_ns = ip.user_ns
256 256 self.ip_colorize = ip.pycolorize
257 257 self.ip_showtb = ip.showtraceback
258 258 self.ip_run_cell = ip.run_cell
259 259 self.shell = ip
260 260
261 261 # load user data and initialize data structures
262 262 self.reload()
263 263
264 264 def fload(self):
265 265 """Load file object."""
266 266 # read data and parse into blocks
267 267 if hasattr(self, 'fobj') and self.fobj is not None:
268 268 self.fobj.close()
269 269 if hasattr(self.src, "read"):
270 270 # It seems to be a file or a file-like object
271 271 self.fobj = self.src
272 272 else:
273 273 # Assume it's a string or something that can be converted to one
274 274 self.fobj = openpy.open(self.fname)
275 275
276 276 def reload(self):
277 277 """Reload source from disk and initialize state."""
278 278 self.fload()
279 279
280 280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284 284
285 285 # if auto_all is not given (def. None), we read it from the file
286 286 if self.auto_all is None:
287 287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 288 else:
289 289 self.auto_all = bool(self.auto_all)
290 290
291 291 # Clean the sources from all markup so it doesn't get displayed when
292 292 # running the demo
293 293 src_blocks = []
294 294 auto_strip = lambda s: self.re_auto.sub('',s)
295 295 for i,b in enumerate(src_b):
296 296 if self._auto[i]:
297 297 src_blocks.append(auto_strip(b))
298 298 else:
299 299 src_blocks.append(b)
300 300 # remove the auto_all marker
301 301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302 302
303 303 self.nblocks = len(src_blocks)
304 304 self.src_blocks = src_blocks
305 305
306 306 # also build syntax-highlighted source
307 307 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
308 308
309 309 # ensure clean namespace and seek offset
310 310 self.reset()
311 311
312 312 def reset(self):
313 313 """Reset the namespace and seek pointer to restart the demo"""
314 314 self.user_ns = {}
315 315 self.finished = False
316 316 self.block_index = 0
317 317
318 318 def _validate_index(self,index):
319 319 if index<0 or index>=self.nblocks:
320 320 raise ValueError('invalid block index %s' % index)
321 321
322 322 def _get_index(self,index):
323 323 """Get the current block index, validating and checking status.
324 324
325 325 Returns None if the demo is finished"""
326 326
327 327 if index is None:
328 328 if self.finished:
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.')
330 330 return None
331 331 index = self.block_index
332 332 else:
333 333 self._validate_index(index)
334 334 return index
335 335
336 336 def seek(self,index):
337 337 """Move the current seek pointer to the given block.
338 338
339 339 You can use negative indices to seek from the end, with identical
340 340 semantics to those of Python lists."""
341 341 if index<0:
342 342 index = self.nblocks + index
343 343 self._validate_index(index)
344 344 self.block_index = index
345 345 self.finished = False
346 346
347 347 def back(self,num=1):
348 348 """Move the seek pointer back num blocks (default is 1)."""
349 349 self.seek(self.block_index-num)
350 350
351 351 def jump(self,num=1):
352 352 """Jump a given number of blocks relative to the current one.
353 353
354 354 The offset can be positive or negative, defaults to 1."""
355 355 self.seek(self.block_index+num)
356 356
357 357 def again(self):
358 358 """Move the seek pointer back one block and re-execute."""
359 359 self.back(1)
360 360 self()
361 361
362 362 def edit(self,index=None):
363 363 """Edit a block.
364 364
365 365 If no number is given, use the last block executed.
366 366
367 367 This edits the in-memory copy of the demo, it does NOT modify the
368 368 original source file. If you want to do that, simply open the file in
369 369 an editor and use reload() when you make changes to the file. This
370 370 method is meant to let you change a block during a demonstration for
371 371 explanatory purposes, without damaging your original script."""
372 372
373 373 index = self._get_index(index)
374 374 if index is None:
375 375 return
376 376 # decrease the index by one (unless we're at the very beginning), so
377 377 # that the default demo.edit() call opens up the sblock we've last run
378 378 if index>0:
379 379 index -= 1
380 380
381 381 filename = self.shell.mktempfile(self.src_blocks[index])
382 382 self.shell.hooks.editor(filename,1)
383 383 with open(filename, 'r') as f:
384 384 new_block = f.read()
385 385 # update the source and colored block
386 386 self.src_blocks[index] = new_block
387 387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
388 388 self.block_index = index
389 389 # call to run with the newly edited index
390 390 self()
391 391
392 392 def show(self,index=None):
393 393 """Show a single block on screen"""
394 394
395 395 index = self._get_index(index)
396 396 if index is None:
397 397 return
398 398
399 399 print(self.marquee('<%s> block # %s (%s remaining)' %
400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
401 print(self.src_blocks_colored[index], file=io.stdout)
400 (self.title,index,self.nblocks-index-1)))
401 print(self.src_blocks_colored[index])
402 402 sys.stdout.flush()
403 403
404 404 def show_all(self):
405 405 """Show entire demo on screen, block by block"""
406 406
407 407 fname = self.title
408 408 title = self.title
409 409 nblocks = self.nblocks
410 410 silent = self._silent
411 411 marquee = self.marquee
412 412 for index,block in enumerate(self.src_blocks_colored):
413 413 if silent[index]:
414 414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
415 (title,index,nblocks-index-1)), file=io.stdout)
415 (title,index,nblocks-index-1)))
416 416 else:
417 417 print(marquee('<%s> block # %s (%s remaining)' %
418 (title,index,nblocks-index-1)), file=io.stdout)
419 print(block, end=' ', file=io.stdout)
418 (title,index,nblocks-index-1)))
419 print(block, end=' ')
420 420 sys.stdout.flush()
421 421
422 422 def run_cell(self,source):
423 423 """Execute a string with one or more lines of code"""
424 424
425 425 exec(source, self.user_ns)
426 426
427 427 def __call__(self,index=None):
428 428 """run a block of the demo.
429 429
430 430 If index is given, it should be an integer >=1 and <= nblocks. This
431 431 means that the calling convention is one off from typical Python
432 432 lists. The reason for the inconsistency is that the demo always
433 433 prints 'Block n/N, and N is the total, so it would be very odd to use
434 434 zero-indexing here."""
435 435
436 436 index = self._get_index(index)
437 437 if index is None:
438 438 return
439 439 try:
440 440 marquee = self.marquee
441 441 next_block = self.src_blocks[index]
442 442 self.block_index += 1
443 443 if self._silent[index]:
444 444 print(marquee('Executing silent block # %s (%s remaining)' %
445 (index,self.nblocks-index-1)), file=io.stdout)
445 (index,self.nblocks-index-1)))
446 446 else:
447 447 self.pre_cmd()
448 448 self.show(index)
449 449 if self.auto_all or self._auto[index]:
450 print(marquee('output:'), file=io.stdout)
450 print(marquee('output:'))
451 451 else:
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ')
453 453 ans = py3compat.input().strip()
454 454 if ans:
455 print(marquee('Block NOT executed'), file=io.stdout)
455 print(marquee('Block NOT executed'))
456 456 return
457 457 try:
458 458 save_argv = sys.argv
459 459 sys.argv = self.sys_argv
460 460 self.run_cell(next_block)
461 461 self.post_cmd()
462 462 finally:
463 463 sys.argv = save_argv
464 464
465 465 except:
466 466 self.ip_showtb(filename=self.fname)
467 467 else:
468 468 self.ip_ns.update(self.user_ns)
469 469
470 470 if self.block_index == self.nblocks:
471 471 mq1 = self.marquee('END OF DEMO')
472 472 if mq1:
473 473 # avoid spurious print >>io.stdout,s if empty marquees are used
474 print(file=io.stdout)
475 print(mq1, file=io.stdout)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
474 print()
475 print(mq1)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'))
477 477 self.finished = True
478 478
479 479 # These methods are meant to be overridden by subclasses who may wish to
480 480 # customize the behavior of of their demos.
481 481 def marquee(self,txt='',width=78,mark='*'):
482 482 """Return the input string centered in a 'marquee'."""
483 483 return marquee(txt,width,mark)
484 484
485 485 def pre_cmd(self):
486 486 """Method called before executing each block."""
487 487 pass
488 488
489 489 def post_cmd(self):
490 490 """Method called after executing each block."""
491 491 pass
492 492
493 493
494 494 class IPythonDemo(Demo):
495 495 """Class for interactive demos with IPython's input processing applied.
496 496
497 497 This subclasses Demo, but instead of executing each block by the Python
498 498 interpreter (via exec), it actually calls IPython on it, so that any input
499 499 filters which may be in place are applied to the input block.
500 500
501 501 If you have an interactive environment which exposes special input
502 502 processing, you can use this class instead to write demo scripts which
503 503 operate exactly as if you had typed them interactively. The default Demo
504 504 class requires the input to be valid, pure Python code.
505 505 """
506 506
507 507 def run_cell(self,source):
508 508 """Execute a string with one or more lines of code"""
509 509
510 510 self.shell.run_cell(source)
511 511
512 512 class LineDemo(Demo):
513 513 """Demo where each line is executed as a separate block.
514 514
515 515 The input script should be valid Python code.
516 516
517 517 This class doesn't require any markup at all, and it's meant for simple
518 518 scripts (with no nesting or any kind of indentation) which consist of
519 519 multiple lines of input to be executed, one at a time, as if they had been
520 520 typed in the interactive prompt.
521 521
522 522 Note: the input can not have *any* indentation, which means that only
523 523 single-lines of input are accepted, not even function definitions are
524 524 valid."""
525 525
526 526 def reload(self):
527 527 """Reload source from disk and initialize state."""
528 528 # read data and parse into blocks
529 529 self.fload()
530 530 lines = self.fobj.readlines()
531 531 src_b = [l for l in lines if l.strip()]
532 532 nblocks = len(src_b)
533 533 self.src = ''.join(lines)
534 534 self._silent = [False]*nblocks
535 535 self._auto = [True]*nblocks
536 536 self.auto_all = True
537 537 self.nblocks = nblocks
538 538 self.src_blocks = src_b
539 539
540 540 # also build syntax-highlighted source
541 541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
542 542
543 543 # ensure clean namespace and seek offset
544 544 self.reset()
545 545
546 546
547 547 class IPythonLineDemo(IPythonDemo,LineDemo):
548 548 """Variant of the LineDemo class whose input is processed by IPython."""
549 549 pass
550 550
551 551
552 552 class ClearMixin(object):
553 553 """Use this mixin to make Demo classes with less visual clutter.
554 554
555 555 Demos using this mixin will clear the screen before every block and use
556 556 blank marquees.
557 557
558 558 Note that in order for the methods defined here to actually override those
559 559 of the classes it's mixed with, it must go /first/ in the inheritance
560 560 tree. For example:
561 561
562 562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
563 563
564 564 will provide an IPythonDemo class with the mixin's features.
565 565 """
566 566
567 567 def marquee(self,txt='',width=78,mark='*'):
568 568 """Blank marquee that returns '' no matter what the input."""
569 569 return ''
570 570
571 571 def pre_cmd(self):
572 572 """Method called before executing each block.
573 573
574 574 This one simply clears the screen."""
575 575 from IPython.utils.terminal import term_clear
576 576 term_clear()
577 577
578 578 class ClearDemo(ClearMixin,Demo):
579 579 pass
580 580
581 581
582 582 class ClearIPDemo(ClearMixin,IPythonDemo):
583 583 pass
@@ -1,227 +1,233 b''
1 1 # encoding: utf-8
2 2 """
3 3 IO related utilities.
4 4 """
5 5
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 from __future__ import print_function
10 10 from __future__ import absolute_import
11 11
12 12
13 13 import atexit
14 14 import os
15 15 import sys
16 16 import tempfile
17 17 from warnings import warn
18
19 from IPython.utils.decorators import undoc
18 20 from .capture import CapturedIO, capture_output
19 21 from .py3compat import string_types, input, PY3
20 22
21
23 @undoc
22 24 class IOStream:
23 25
24 26 def __init__(self,stream, fallback=None):
25 27 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
26 28 if fallback is not None:
27 29 stream = fallback
28 30 else:
29 31 raise ValueError("fallback required, but not specified")
30 32 self.stream = stream
31 33 self._swrite = stream.write
32 34
33 35 # clone all methods not overridden:
34 36 def clone(meth):
35 37 return not hasattr(self, meth) and not meth.startswith('_')
36 38 for meth in filter(clone, dir(stream)):
37 39 setattr(self, meth, getattr(stream, meth))
38 40
39 41 def __repr__(self):
40 42 cls = self.__class__
41 43 tpl = '{mod}.{cls}({args})'
42 44 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
43 45
44 46 def write(self,data):
47 warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead',
48 DeprecationWarning, stacklevel=2)
45 49 try:
46 50 self._swrite(data)
47 51 except:
48 52 try:
49 53 # print handles some unicode issues which may trip a plain
50 54 # write() call. Emulate write() by using an empty end
51 55 # argument.
52 56 print(data, end='', file=self.stream)
53 57 except:
54 58 # if we get here, something is seriously broken.
55 59 print('ERROR - failed to write data to stream:', self.stream,
56 60 file=sys.stderr)
57 61
58 62 def writelines(self, lines):
63 warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead',
64 DeprecationWarning, stacklevel=2)
59 65 if isinstance(lines, string_types):
60 66 lines = [lines]
61 67 for line in lines:
62 68 self.write(line)
63 69
64 70 # This class used to have a writeln method, but regular files and streams
65 71 # in Python don't have this method. We need to keep this completely
66 72 # compatible so we removed it.
67 73
68 74 @property
69 75 def closed(self):
70 76 return self.stream.closed
71 77
72 78 def close(self):
73 79 pass
74 80
75 81 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
76 82 devnull = open(os.devnull, 'w')
77 83 atexit.register(devnull.close)
78 84 stdin = IOStream(sys.stdin, fallback=devnull)
79 85 stdout = IOStream(sys.stdout, fallback=devnull)
80 86 stderr = IOStream(sys.stderr, fallback=devnull)
81 87
82 88 class Tee(object):
83 89 """A class to duplicate an output stream to stdout/err.
84 90
85 91 This works in a manner very similar to the Unix 'tee' command.
86 92
87 93 When the object is closed or deleted, it closes the original file given to
88 94 it for duplication.
89 95 """
90 96 # Inspired by:
91 97 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
92 98
93 99 def __init__(self, file_or_name, mode="w", channel='stdout'):
94 100 """Construct a new Tee object.
95 101
96 102 Parameters
97 103 ----------
98 104 file_or_name : filename or open filehandle (writable)
99 105 File that will be duplicated
100 106
101 107 mode : optional, valid mode for open().
102 108 If a filename was give, open with this mode.
103 109
104 110 channel : str, one of ['stdout', 'stderr']
105 111 """
106 112 if channel not in ['stdout', 'stderr']:
107 113 raise ValueError('Invalid channel spec %s' % channel)
108 114
109 115 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
110 116 self.file = file_or_name
111 117 else:
112 118 self.file = open(file_or_name, mode)
113 119 self.channel = channel
114 120 self.ostream = getattr(sys, channel)
115 121 setattr(sys, channel, self)
116 122 self._closed = False
117 123
118 124 def close(self):
119 125 """Close the file and restore the channel."""
120 126 self.flush()
121 127 setattr(sys, self.channel, self.ostream)
122 128 self.file.close()
123 129 self._closed = True
124 130
125 131 def write(self, data):
126 132 """Write data to both channels."""
127 133 self.file.write(data)
128 134 self.ostream.write(data)
129 135 self.ostream.flush()
130 136
131 137 def flush(self):
132 138 """Flush both channels."""
133 139 self.file.flush()
134 140 self.ostream.flush()
135 141
136 142 def __del__(self):
137 143 if not self._closed:
138 144 self.close()
139 145
140 146
141 147 def ask_yes_no(prompt, default=None, interrupt=None):
142 148 """Asks a question and returns a boolean (y/n) answer.
143 149
144 150 If default is given (one of 'y','n'), it is used if the user input is
145 151 empty. If interrupt is given (one of 'y','n'), it is used if the user
146 152 presses Ctrl-C. Otherwise the question is repeated until an answer is
147 153 given.
148 154
149 155 An EOF is treated as the default answer. If there is no default, an
150 156 exception is raised to prevent infinite loops.
151 157
152 158 Valid answers are: y/yes/n/no (match is not case sensitive)."""
153 159
154 160 answers = {'y':True,'n':False,'yes':True,'no':False}
155 161 ans = None
156 162 while ans not in answers.keys():
157 163 try:
158 164 ans = input(prompt+' ').lower()
159 165 if not ans: # response was an empty string
160 166 ans = default
161 167 except KeyboardInterrupt:
162 168 if interrupt:
163 169 ans = interrupt
164 170 except EOFError:
165 171 if default in answers.keys():
166 172 ans = default
167 173 print()
168 174 else:
169 175 raise
170 176
171 177 return answers[ans]
172 178
173 179
174 180 def temp_pyfile(src, ext='.py'):
175 181 """Make a temporary python file, return filename and filehandle.
176 182
177 183 Parameters
178 184 ----------
179 185 src : string or list of strings (no need for ending newlines if list)
180 186 Source code to be written to the file.
181 187
182 188 ext : optional, string
183 189 Extension for the generated file.
184 190
185 191 Returns
186 192 -------
187 193 (filename, open filehandle)
188 194 It is the caller's responsibility to close the open file and unlink it.
189 195 """
190 196 fname = tempfile.mkstemp(ext)[1]
191 197 f = open(fname,'w')
192 198 f.write(src)
193 199 f.flush()
194 200 return fname, f
195 201
196 202 def atomic_writing(*args, **kwargs):
197 203 """DEPRECATED: moved to notebook.services.contents.fileio"""
198 204 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
199 205 from notebook.services.contents.fileio import atomic_writing
200 206 return atomic_writing(*args, **kwargs)
201 207
202 208 def raw_print(*args, **kw):
203 209 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
204 210
205 211 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
206 212 file=sys.__stdout__)
207 213 sys.__stdout__.flush()
208 214
209 215
210 216 def raw_print_err(*args, **kw):
211 217 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
212 218
213 219 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
214 220 file=sys.__stderr__)
215 221 sys.__stderr__.flush()
216 222
217 223
218 224 # Short aliases for quick debugging, do NOT use these in production code.
219 225 rprint = raw_print
220 226 rprinte = raw_print_err
221 227
222 228
223 229 def unicode_std_stream(stream='stdout'):
224 230 """DEPRECATED, moved to nbconvert.utils.io"""
225 231 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
226 232 from nbconvert.utils.io import unicode_std_stream
227 233 return unicode_std_stream(stream)
@@ -1,60 +1,57 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for warnings. Shoudn't we just use the built in warnings module.
4 4 """
5 5
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 from __future__ import print_function
10 10
11 11 import sys
12
13 from IPython.utils import io
14
15 12 import warnings
16 13
17 14 warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning)
18 15
19 16 def warn(msg,level=2,exit_val=1):
20 17 """Standard warning printer. Gives formatting consistency.
21 18
22 19 Output is sent to io.stderr (sys.stderr by default).
23 20
24 21 Options:
25 22
26 23 -level(2): allows finer control:
27 24 0 -> Do nothing, dummy function.
28 25 1 -> Print message.
29 26 2 -> Print 'WARNING:' + message. (Default level).
30 27 3 -> Print 'ERROR:' + message.
31 28 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
32 29
33 30 -exit_val (1): exit value returned by sys.exit() for a level 4
34 31 warning. Ignored for all other levels."""
35 32
36 33 warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning)
37 34 if level>0:
38 35 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
39 print(header[level], msg, sep='', file=io.stderr)
36 print(header[level], msg, sep='', file=sys.stderr)
40 37 if level == 4:
41 print('Exiting.\n', file=io.stderr)
38 print('Exiting.\n', file=sys.stderr)
42 39 sys.exit(exit_val)
43 40
44 41
45 42 def info(msg):
46 43 """Equivalent to warn(msg,level=1)."""
47 44
48 45 warn(msg,level=1)
49 46
50 47
51 48 def error(msg):
52 49 """Equivalent to warn(msg,level=3)."""
53 50
54 51 warn(msg,level=3)
55 52
56 53
57 54 def fatal(msg,exit_val=1):
58 55 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
59 56
60 57 warn(msg,exit_val=exit_val,level=4)
General Comments 0
You need to be logged in to leave comments. Login now