##// 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 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 the command line completion of other programs which include this isn't
6 the command line completion of other programs which include this isn't
7 damaged.
7 damaged.
8
8
9 In the future, this class will be expanded with improvements over the standard
9 In the future, this class will be expanded with improvements over the standard
10 pdb.
10 pdb.
11
11
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 changes. Licensing should therefore be under the standard Python terms. For
13 changes. Licensing should therefore be under the standard Python terms. For
14 details on the PSF (Python Software Foundation) standard license, see:
14 details on the PSF (Python Software Foundation) standard license, see:
15
15
16 http://www.python.org/2.2.3/license.html"""
16 http://www.python.org/2.2.3/license.html"""
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 #
19 #
20 # This file is licensed under the PSF license.
20 # This file is licensed under the PSF license.
21 #
21 #
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 #
24 #
25 #
25 #
26 #*****************************************************************************
26 #*****************************************************************************
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 import bdb
29 import bdb
30 import functools
30 import functools
31 import inspect
31 import inspect
32 import sys
32 import sys
33
33
34 from IPython import get_ipython
34 from IPython import get_ipython
35 from IPython.utils import PyColorize, ulinecache
35 from IPython.utils import PyColorize, ulinecache
36 from IPython.utils import coloransi, io, py3compat
36 from IPython.utils import coloransi, py3compat
37 from IPython.core.excolors import exception_colors
37 from IPython.core.excolors import exception_colors
38 from IPython.testing.skipdoctest import skip_doctest
38 from IPython.testing.skipdoctest import skip_doctest
39
39
40 # See if we can use pydb.
40 # See if we can use pydb.
41 has_pydb = False
41 has_pydb = False
42 prompt = 'ipdb> '
42 prompt = 'ipdb> '
43 #We have to check this directly from sys.argv, config struct not yet available
43 #We have to check this directly from sys.argv, config struct not yet available
44 if '--pydb' in sys.argv:
44 if '--pydb' in sys.argv:
45 try:
45 try:
46 import pydb
46 import pydb
47 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
47 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
48 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
48 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
49 # better protect against it.
49 # better protect against it.
50 has_pydb = True
50 has_pydb = True
51 except ImportError:
51 except ImportError:
52 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
52 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
53
53
54 if has_pydb:
54 if has_pydb:
55 from pydb import Pdb as OldPdb
55 from pydb import Pdb as OldPdb
56 prompt = 'ipydb> '
56 prompt = 'ipydb> '
57 else:
57 else:
58 from pdb import Pdb as OldPdb
58 from pdb import Pdb as OldPdb
59
59
60 # Allow the set_trace code to operate outside of an ipython instance, even if
60 # Allow the set_trace code to operate outside of an ipython instance, even if
61 # it does so with some limitations. The rest of this support is implemented in
61 # it does so with some limitations. The rest of this support is implemented in
62 # the Tracer constructor.
62 # the Tracer constructor.
63
63
64 def make_arrow(pad):
64 def make_arrow(pad):
65 """generate the leading arrow in front of traceback or debugger"""
65 """generate the leading arrow in front of traceback or debugger"""
66 if pad >= 2:
66 if pad >= 2:
67 return '-'*(pad-2) + '> '
67 return '-'*(pad-2) + '> '
68 elif pad == 1:
68 elif pad == 1:
69 return '>'
69 return '>'
70 return ''
70 return ''
71
71
72
72
73 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
73 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
74 """Exception hook which handles `BdbQuit` exceptions.
74 """Exception hook which handles `BdbQuit` exceptions.
75
75
76 All other exceptions are processed using the `excepthook`
76 All other exceptions are processed using the `excepthook`
77 parameter.
77 parameter.
78 """
78 """
79 if et==bdb.BdbQuit:
79 if et==bdb.BdbQuit:
80 print('Exiting Debugger.')
80 print('Exiting Debugger.')
81 elif excepthook is not None:
81 elif excepthook is not None:
82 excepthook(et, ev, tb)
82 excepthook(et, ev, tb)
83 else:
83 else:
84 # Backwards compatibility. Raise deprecation warning?
84 # Backwards compatibility. Raise deprecation warning?
85 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
85 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
86
86
87 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
87 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
88 print('Exiting Debugger.')
88 print('Exiting Debugger.')
89
89
90
90
91 class Tracer(object):
91 class Tracer(object):
92 """Class for local debugging, similar to pdb.set_trace.
92 """Class for local debugging, similar to pdb.set_trace.
93
93
94 Instances of this class, when called, behave like pdb.set_trace, but
94 Instances of this class, when called, behave like pdb.set_trace, but
95 providing IPython's enhanced capabilities.
95 providing IPython's enhanced capabilities.
96
96
97 This is implemented as a class which must be initialized in your own code
97 This is implemented as a class which must be initialized in your own code
98 and not as a standalone function because we need to detect at runtime
98 and not as a standalone function because we need to detect at runtime
99 whether IPython is already active or not. That detection is done in the
99 whether IPython is already active or not. That detection is done in the
100 constructor, ensuring that this code plays nicely with a running IPython,
100 constructor, ensuring that this code plays nicely with a running IPython,
101 while functioning acceptably (though with limitations) if outside of it.
101 while functioning acceptably (though with limitations) if outside of it.
102 """
102 """
103
103
104 @skip_doctest
104 @skip_doctest
105 def __init__(self, colors=None):
105 def __init__(self, colors=None):
106 """Create a local debugger instance.
106 """Create a local debugger instance.
107
107
108 Parameters
108 Parameters
109 ----------
109 ----------
110
110
111 colors : str, optional
111 colors : str, optional
112 The name of the color scheme to use, it must be one of IPython's
112 The name of the color scheme to use, it must be one of IPython's
113 valid color schemes. If not given, the function will default to
113 valid color schemes. If not given, the function will default to
114 the current IPython scheme when running inside IPython, and to
114 the current IPython scheme when running inside IPython, and to
115 'NoColor' otherwise.
115 'NoColor' otherwise.
116
116
117 Examples
117 Examples
118 --------
118 --------
119 ::
119 ::
120
120
121 from IPython.core.debugger import Tracer; debug_here = Tracer()
121 from IPython.core.debugger import Tracer; debug_here = Tracer()
122
122
123 Later in your code::
123 Later in your code::
124
124
125 debug_here() # -> will open up the debugger at that point.
125 debug_here() # -> will open up the debugger at that point.
126
126
127 Once the debugger activates, you can use all of its regular commands to
127 Once the debugger activates, you can use all of its regular commands to
128 step through code, set breakpoints, etc. See the pdb documentation
128 step through code, set breakpoints, etc. See the pdb documentation
129 from the Python standard library for usage details.
129 from the Python standard library for usage details.
130 """
130 """
131
131
132 ip = get_ipython()
132 ip = get_ipython()
133 if ip is None:
133 if ip is None:
134 # Outside of ipython, we set our own exception hook manually
134 # Outside of ipython, we set our own exception hook manually
135 sys.excepthook = functools.partial(BdbQuit_excepthook,
135 sys.excepthook = functools.partial(BdbQuit_excepthook,
136 excepthook=sys.excepthook)
136 excepthook=sys.excepthook)
137 def_colors = 'NoColor'
137 def_colors = 'NoColor'
138 try:
138 try:
139 # Limited tab completion support
139 # Limited tab completion support
140 import readline
140 import readline
141 readline.parse_and_bind('tab: complete')
141 readline.parse_and_bind('tab: complete')
142 except ImportError:
142 except ImportError:
143 pass
143 pass
144 else:
144 else:
145 # In ipython, we use its custom exception handler mechanism
145 # In ipython, we use its custom exception handler mechanism
146 def_colors = ip.colors
146 def_colors = ip.colors
147 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
147 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
148
148
149 if colors is None:
149 if colors is None:
150 colors = def_colors
150 colors = def_colors
151
151
152 # The stdlib debugger internally uses a modified repr from the `repr`
152 # The stdlib debugger internally uses a modified repr from the `repr`
153 # module, that limits the length of printed strings to a hardcoded
153 # module, that limits the length of printed strings to a hardcoded
154 # limit of 30 characters. That much trimming is too aggressive, let's
154 # limit of 30 characters. That much trimming is too aggressive, let's
155 # at least raise that limit to 80 chars, which should be enough for
155 # at least raise that limit to 80 chars, which should be enough for
156 # most interactive uses.
156 # most interactive uses.
157 try:
157 try:
158 try:
158 try:
159 from reprlib import aRepr # Py 3
159 from reprlib import aRepr # Py 3
160 except ImportError:
160 except ImportError:
161 from repr import aRepr # Py 2
161 from repr import aRepr # Py 2
162 aRepr.maxstring = 80
162 aRepr.maxstring = 80
163 except:
163 except:
164 # This is only a user-facing convenience, so any error we encounter
164 # This is only a user-facing convenience, so any error we encounter
165 # here can be warned about but can be otherwise ignored. These
165 # here can be warned about but can be otherwise ignored. These
166 # printouts will tell us about problems if this API changes
166 # printouts will tell us about problems if this API changes
167 import traceback
167 import traceback
168 traceback.print_exc()
168 traceback.print_exc()
169
169
170 self.debugger = Pdb(colors)
170 self.debugger = Pdb(colors)
171
171
172 def __call__(self):
172 def __call__(self):
173 """Starts an interactive debugger at the point where called.
173 """Starts an interactive debugger at the point where called.
174
174
175 This is similar to the pdb.set_trace() function from the std lib, but
175 This is similar to the pdb.set_trace() function from the std lib, but
176 using IPython's enhanced debugger."""
176 using IPython's enhanced debugger."""
177
177
178 self.debugger.set_trace(sys._getframe().f_back)
178 self.debugger.set_trace(sys._getframe().f_back)
179
179
180
180
181 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
181 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
182 """Make new_fn have old_fn's doc string. This is particularly useful
182 """Make new_fn have old_fn's doc string. This is particularly useful
183 for the ``do_...`` commands that hook into the help system.
183 for the ``do_...`` commands that hook into the help system.
184 Adapted from from a comp.lang.python posting
184 Adapted from from a comp.lang.python posting
185 by Duncan Booth."""
185 by Duncan Booth."""
186 def wrapper(*args, **kw):
186 def wrapper(*args, **kw):
187 return new_fn(*args, **kw)
187 return new_fn(*args, **kw)
188 if old_fn.__doc__:
188 if old_fn.__doc__:
189 wrapper.__doc__ = old_fn.__doc__ + additional_text
189 wrapper.__doc__ = old_fn.__doc__ + additional_text
190 return wrapper
190 return wrapper
191
191
192
192
193 def _file_lines(fname):
193 def _file_lines(fname):
194 """Return the contents of a named file as a list of lines.
194 """Return the contents of a named file as a list of lines.
195
195
196 This function never raises an IOError exception: if the file can't be
196 This function never raises an IOError exception: if the file can't be
197 read, it simply returns an empty list."""
197 read, it simply returns an empty list."""
198
198
199 try:
199 try:
200 outfile = open(fname)
200 outfile = open(fname)
201 except IOError:
201 except IOError:
202 return []
202 return []
203 else:
203 else:
204 out = outfile.readlines()
204 out = outfile.readlines()
205 outfile.close()
205 outfile.close()
206 return out
206 return out
207
207
208
208
209 class Pdb(OldPdb):
209 class Pdb(OldPdb):
210 """Modified Pdb class, does not load readline."""
210 """Modified Pdb class, does not load readline."""
211
211
212 def __init__(self,color_scheme='NoColor',completekey=None,
212 def __init__(self,color_scheme='NoColor',completekey=None,
213 stdin=None, stdout=None, context=5):
213 stdin=None, stdout=None, context=5):
214
214
215 # Parent constructor:
215 # Parent constructor:
216 try:
216 try:
217 self.context=int(context)
217 self.context=int(context)
218 if self.context <= 0:
218 if self.context <= 0:
219 raise ValueError("Context must be a positive integer")
219 raise ValueError("Context must be a positive integer")
220 except (TypeError, ValueError):
220 except (TypeError, ValueError):
221 raise ValueError("Context must be a positive integer")
221 raise ValueError("Context must be a positive integer")
222
222
223 if has_pydb and completekey is None:
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 else:
225 else:
226 OldPdb.__init__(self,completekey,stdin,stdout)
226 OldPdb.__init__(self,completekey,stdin,stdout)
227
227
228 # IPython changes...
228 # IPython changes...
229 self.is_pydb = has_pydb
229 self.is_pydb = has_pydb
230
230
231 self.shell = get_ipython()
231 self.shell = get_ipython()
232
232
233 if self.shell is None:
233 if self.shell is None:
234 # No IPython instance running, we must create one
234 # No IPython instance running, we must create one
235 from IPython.terminal.interactiveshell import \
235 from IPython.terminal.interactiveshell import \
236 TerminalInteractiveShell
236 TerminalInteractiveShell
237 self.shell = TerminalInteractiveShell.instance()
237 self.shell = TerminalInteractiveShell.instance()
238
238
239 if self.is_pydb:
239 if self.is_pydb:
240
240
241 # interactiveshell.py's ipalias seems to want pdb's checkline
241 # interactiveshell.py's ipalias seems to want pdb's checkline
242 # which located in pydb.fn
242 # which located in pydb.fn
243 import pydb.fns
243 import pydb.fns
244 self.checkline = lambda filename, lineno: \
244 self.checkline = lambda filename, lineno: \
245 pydb.fns.checkline(self, filename, lineno)
245 pydb.fns.checkline(self, filename, lineno)
246
246
247 self.curframe = None
247 self.curframe = None
248 self.do_restart = self.new_do_restart
248 self.do_restart = self.new_do_restart
249
249
250 self.old_all_completions = self.shell.Completer.all_completions
250 self.old_all_completions = self.shell.Completer.all_completions
251 self.shell.Completer.all_completions=self.all_completions
251 self.shell.Completer.all_completions=self.all_completions
252
252
253 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
253 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
254 OldPdb.do_list)
254 OldPdb.do_list)
255 self.do_l = self.do_list
255 self.do_l = self.do_list
256 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
256 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
257 OldPdb.do_frame)
257 OldPdb.do_frame)
258
258
259 self.aliases = {}
259 self.aliases = {}
260
260
261 # Create color table: we copy the default one from the traceback
261 # Create color table: we copy the default one from the traceback
262 # module and add a few attributes needed for debugging
262 # module and add a few attributes needed for debugging
263 self.color_scheme_table = exception_colors()
263 self.color_scheme_table = exception_colors()
264
264
265 # shorthands
265 # shorthands
266 C = coloransi.TermColors
266 C = coloransi.TermColors
267 cst = self.color_scheme_table
267 cst = self.color_scheme_table
268
268
269 cst['NoColor'].colors.prompt = C.NoColor
269 cst['NoColor'].colors.prompt = C.NoColor
270 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
270 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
271 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
271 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
272
272
273 cst['Linux'].colors.prompt = C.Green
273 cst['Linux'].colors.prompt = C.Green
274 cst['Linux'].colors.breakpoint_enabled = C.LightRed
274 cst['Linux'].colors.breakpoint_enabled = C.LightRed
275 cst['Linux'].colors.breakpoint_disabled = C.Red
275 cst['Linux'].colors.breakpoint_disabled = C.Red
276
276
277 cst['LightBG'].colors.prompt = C.Blue
277 cst['LightBG'].colors.prompt = C.Blue
278 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
278 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
279 cst['LightBG'].colors.breakpoint_disabled = C.Red
279 cst['LightBG'].colors.breakpoint_disabled = C.Red
280
280
281 self.set_colors(color_scheme)
281 self.set_colors(color_scheme)
282
282
283 # Add a python parser so we can syntax highlight source while
283 # Add a python parser so we can syntax highlight source while
284 # debugging.
284 # debugging.
285 self.parser = PyColorize.Parser()
285 self.parser = PyColorize.Parser()
286
286
287 # Set the prompt - the default prompt is '(Pdb)'
287 # Set the prompt - the default prompt is '(Pdb)'
288 Colors = cst.active_colors
288 Colors = cst.active_colors
289 if color_scheme == 'NoColor':
289 if color_scheme == 'NoColor':
290 self.prompt = prompt
290 self.prompt = prompt
291 else:
291 else:
292 # The colour markers are wrapped by bytes 01 and 02 so that readline
292 # The colour markers are wrapped by bytes 01 and 02 so that readline
293 # can calculate the width.
293 # can calculate the width.
294 self.prompt = u'\x01%s\x02%s\x01%s\x02' % (Colors.prompt, prompt, Colors.Normal)
294 self.prompt = u'\x01%s\x02%s\x01%s\x02' % (Colors.prompt, prompt, Colors.Normal)
295
295
296 def set_colors(self, scheme):
296 def set_colors(self, scheme):
297 """Shorthand access to the color table scheme selector method."""
297 """Shorthand access to the color table scheme selector method."""
298 self.color_scheme_table.set_active_scheme(scheme)
298 self.color_scheme_table.set_active_scheme(scheme)
299
299
300 def interaction(self, frame, traceback):
300 def interaction(self, frame, traceback):
301 self.shell.set_completer_frame(frame)
301 self.shell.set_completer_frame(frame)
302 while True:
302 while True:
303 try:
303 try:
304 OldPdb.interaction(self, frame, traceback)
304 OldPdb.interaction(self, frame, traceback)
305 break
305 break
306 except KeyboardInterrupt:
306 except KeyboardInterrupt:
307 self.shell.write('\n' + self.shell.get_exception_only())
307 self.shell.write('\n' + self.shell.get_exception_only())
308 break
308 break
309 finally:
309 finally:
310 # Pdb sets readline delimiters, so set them back to our own
310 # Pdb sets readline delimiters, so set them back to our own
311 if self.shell.readline is not None:
311 if self.shell.readline is not None:
312 self.shell.readline.set_completer_delims(self.shell.readline_delims)
312 self.shell.readline.set_completer_delims(self.shell.readline_delims)
313
313
314 def new_do_up(self, arg):
314 def new_do_up(self, arg):
315 OldPdb.do_up(self, arg)
315 OldPdb.do_up(self, arg)
316 self.shell.set_completer_frame(self.curframe)
316 self.shell.set_completer_frame(self.curframe)
317 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
317 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
318
318
319 def new_do_down(self, arg):
319 def new_do_down(self, arg):
320 OldPdb.do_down(self, arg)
320 OldPdb.do_down(self, arg)
321 self.shell.set_completer_frame(self.curframe)
321 self.shell.set_completer_frame(self.curframe)
322
322
323 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
323 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
324
324
325 def new_do_frame(self, arg):
325 def new_do_frame(self, arg):
326 OldPdb.do_frame(self, arg)
326 OldPdb.do_frame(self, arg)
327 self.shell.set_completer_frame(self.curframe)
327 self.shell.set_completer_frame(self.curframe)
328
328
329 def new_do_quit(self, arg):
329 def new_do_quit(self, arg):
330
330
331 if hasattr(self, 'old_all_completions'):
331 if hasattr(self, 'old_all_completions'):
332 self.shell.Completer.all_completions=self.old_all_completions
332 self.shell.Completer.all_completions=self.old_all_completions
333
333
334 return OldPdb.do_quit(self, arg)
334 return OldPdb.do_quit(self, arg)
335
335
336 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
336 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
337
337
338 def new_do_restart(self, arg):
338 def new_do_restart(self, arg):
339 """Restart command. In the context of ipython this is exactly the same
339 """Restart command. In the context of ipython this is exactly the same
340 thing as 'quit'."""
340 thing as 'quit'."""
341 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
341 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
342 return self.do_quit(arg)
342 return self.do_quit(arg)
343
343
344 def postloop(self):
344 def postloop(self):
345 self.shell.set_completer_frame(None)
345 self.shell.set_completer_frame(None)
346
346
347 def print_stack_trace(self, context=None):
347 def print_stack_trace(self, context=None):
348 if context is None:
348 if context is None:
349 context = self.context
349 context = self.context
350 try:
350 try:
351 context=int(context)
351 context=int(context)
352 if context <= 0:
352 if context <= 0:
353 raise ValueError("Context must be a positive integer")
353 raise ValueError("Context must be a positive integer")
354 except (TypeError, ValueError):
354 except (TypeError, ValueError):
355 raise ValueError("Context must be a positive integer")
355 raise ValueError("Context must be a positive integer")
356 try:
356 try:
357 for frame_lineno in self.stack:
357 for frame_lineno in self.stack:
358 self.print_stack_entry(frame_lineno, context=context)
358 self.print_stack_entry(frame_lineno, context=context)
359 except KeyboardInterrupt:
359 except KeyboardInterrupt:
360 pass
360 pass
361
361
362 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
362 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
363 context=None):
363 context=None):
364 if context is None:
364 if context is None:
365 context = self.context
365 context = self.context
366 try:
366 try:
367 context=int(context)
367 context=int(context)
368 if context <= 0:
368 if context <= 0:
369 raise ValueError("Context must be a positive integer")
369 raise ValueError("Context must be a positive integer")
370 except (TypeError, ValueError):
370 except (TypeError, ValueError):
371 raise ValueError("Context must be a positive integer")
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 # vds: >>
374 # vds: >>
375 frame, lineno = frame_lineno
375 frame, lineno = frame_lineno
376 filename = frame.f_code.co_filename
376 filename = frame.f_code.co_filename
377 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
377 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
378 # vds: <<
378 # vds: <<
379
379
380 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
380 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
381 if context is None:
381 if context is None:
382 context = self.context
382 context = self.context
383 try:
383 try:
384 context=int(context)
384 context=int(context)
385 if context <= 0:
385 if context <= 0:
386 print("Context must be a positive integer")
386 print("Context must be a positive integer")
387 except (TypeError, ValueError):
387 except (TypeError, ValueError):
388 print("Context must be a positive integer")
388 print("Context must be a positive integer")
389 try:
389 try:
390 import reprlib # Py 3
390 import reprlib # Py 3
391 except ImportError:
391 except ImportError:
392 import repr as reprlib # Py 2
392 import repr as reprlib # Py 2
393
393
394 ret = []
394 ret = []
395
395
396 Colors = self.color_scheme_table.active_colors
396 Colors = self.color_scheme_table.active_colors
397 ColorsNormal = Colors.Normal
397 ColorsNormal = Colors.Normal
398 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
398 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
399 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
399 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
400 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
400 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
401 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
401 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
402 ColorsNormal)
402 ColorsNormal)
403
403
404 frame, lineno = frame_lineno
404 frame, lineno = frame_lineno
405
405
406 return_value = ''
406 return_value = ''
407 if '__return__' in frame.f_locals:
407 if '__return__' in frame.f_locals:
408 rv = frame.f_locals['__return__']
408 rv = frame.f_locals['__return__']
409 #return_value += '->'
409 #return_value += '->'
410 return_value += reprlib.repr(rv) + '\n'
410 return_value += reprlib.repr(rv) + '\n'
411 ret.append(return_value)
411 ret.append(return_value)
412
412
413 #s = filename + '(' + `lineno` + ')'
413 #s = filename + '(' + `lineno` + ')'
414 filename = self.canonic(frame.f_code.co_filename)
414 filename = self.canonic(frame.f_code.co_filename)
415 link = tpl_link % py3compat.cast_unicode(filename)
415 link = tpl_link % py3compat.cast_unicode(filename)
416
416
417 if frame.f_code.co_name:
417 if frame.f_code.co_name:
418 func = frame.f_code.co_name
418 func = frame.f_code.co_name
419 else:
419 else:
420 func = "<lambda>"
420 func = "<lambda>"
421
421
422 call = ''
422 call = ''
423 if func != '?':
423 if func != '?':
424 if '__args__' in frame.f_locals:
424 if '__args__' in frame.f_locals:
425 args = reprlib.repr(frame.f_locals['__args__'])
425 args = reprlib.repr(frame.f_locals['__args__'])
426 else:
426 else:
427 args = '()'
427 args = '()'
428 call = tpl_call % (func, args)
428 call = tpl_call % (func, args)
429
429
430 # The level info should be generated in the same format pdb uses, to
430 # The level info should be generated in the same format pdb uses, to
431 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
431 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
432 if frame is self.curframe:
432 if frame is self.curframe:
433 ret.append('> ')
433 ret.append('> ')
434 else:
434 else:
435 ret.append(' ')
435 ret.append(' ')
436 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
436 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
437
437
438 start = lineno - 1 - context//2
438 start = lineno - 1 - context//2
439 lines = ulinecache.getlines(filename)
439 lines = ulinecache.getlines(filename)
440 start = min(start, len(lines) - context)
440 start = min(start, len(lines) - context)
441 start = max(start, 0)
441 start = max(start, 0)
442 lines = lines[start : start + context]
442 lines = lines[start : start + context]
443
443
444 for i,line in enumerate(lines):
444 for i,line in enumerate(lines):
445 show_arrow = (start + 1 + i == lineno)
445 show_arrow = (start + 1 + i == lineno)
446 linetpl = (frame is self.curframe or show_arrow) \
446 linetpl = (frame is self.curframe or show_arrow) \
447 and tpl_line_em \
447 and tpl_line_em \
448 or tpl_line
448 or tpl_line
449 ret.append(self.__format_line(linetpl, filename,
449 ret.append(self.__format_line(linetpl, filename,
450 start + 1 + i, line,
450 start + 1 + i, line,
451 arrow = show_arrow) )
451 arrow = show_arrow) )
452 return ''.join(ret)
452 return ''.join(ret)
453
453
454 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
454 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
455 bp_mark = ""
455 bp_mark = ""
456 bp_mark_color = ""
456 bp_mark_color = ""
457
457
458 scheme = self.color_scheme_table.active_scheme_name
458 scheme = self.color_scheme_table.active_scheme_name
459 new_line, err = self.parser.format2(line, 'str', scheme)
459 new_line, err = self.parser.format2(line, 'str', scheme)
460 if not err: line = new_line
460 if not err: line = new_line
461
461
462 bp = None
462 bp = None
463 if lineno in self.get_file_breaks(filename):
463 if lineno in self.get_file_breaks(filename):
464 bps = self.get_breaks(filename, lineno)
464 bps = self.get_breaks(filename, lineno)
465 bp = bps[-1]
465 bp = bps[-1]
466
466
467 if bp:
467 if bp:
468 Colors = self.color_scheme_table.active_colors
468 Colors = self.color_scheme_table.active_colors
469 bp_mark = str(bp.number)
469 bp_mark = str(bp.number)
470 bp_mark_color = Colors.breakpoint_enabled
470 bp_mark_color = Colors.breakpoint_enabled
471 if not bp.enabled:
471 if not bp.enabled:
472 bp_mark_color = Colors.breakpoint_disabled
472 bp_mark_color = Colors.breakpoint_disabled
473
473
474 numbers_width = 7
474 numbers_width = 7
475 if arrow:
475 if arrow:
476 # This is the line with the error
476 # This is the line with the error
477 pad = numbers_width - len(str(lineno)) - len(bp_mark)
477 pad = numbers_width - len(str(lineno)) - len(bp_mark)
478 num = '%s%s' % (make_arrow(pad), str(lineno))
478 num = '%s%s' % (make_arrow(pad), str(lineno))
479 else:
479 else:
480 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
480 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
481
481
482 return tpl_line % (bp_mark_color + bp_mark, num, line)
482 return tpl_line % (bp_mark_color + bp_mark, num, line)
483
483
484
484
485 def list_command_pydb(self, arg):
485 def list_command_pydb(self, arg):
486 """List command to use if we have a newer pydb installed"""
486 """List command to use if we have a newer pydb installed"""
487 filename, first, last = OldPdb.parse_list_cmd(self, arg)
487 filename, first, last = OldPdb.parse_list_cmd(self, arg)
488 if filename is not None:
488 if filename is not None:
489 self.print_list_lines(filename, first, last)
489 self.print_list_lines(filename, first, last)
490
490
491 def print_list_lines(self, filename, first, last):
491 def print_list_lines(self, filename, first, last):
492 """The printing (as opposed to the parsing part of a 'list'
492 """The printing (as opposed to the parsing part of a 'list'
493 command."""
493 command."""
494 try:
494 try:
495 Colors = self.color_scheme_table.active_colors
495 Colors = self.color_scheme_table.active_colors
496 ColorsNormal = Colors.Normal
496 ColorsNormal = Colors.Normal
497 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
497 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
498 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
498 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
499 src = []
499 src = []
500 if filename == "<string>" and hasattr(self, "_exec_filename"):
500 if filename == "<string>" and hasattr(self, "_exec_filename"):
501 filename = self._exec_filename
501 filename = self._exec_filename
502
502
503 for lineno in range(first, last+1):
503 for lineno in range(first, last+1):
504 line = ulinecache.getline(filename, lineno)
504 line = ulinecache.getline(filename, lineno)
505 if not line:
505 if not line:
506 break
506 break
507
507
508 if lineno == self.curframe.f_lineno:
508 if lineno == self.curframe.f_lineno:
509 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
509 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
510 else:
510 else:
511 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
511 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
512
512
513 src.append(line)
513 src.append(line)
514 self.lineno = lineno
514 self.lineno = lineno
515
515
516 print(''.join(src), file=io.stdout)
516 print(''.join(src))
517
517
518 except KeyboardInterrupt:
518 except KeyboardInterrupt:
519 pass
519 pass
520
520
521 def do_list(self, arg):
521 def do_list(self, arg):
522 self.lastcmd = 'list'
522 self.lastcmd = 'list'
523 last = None
523 last = None
524 if arg:
524 if arg:
525 try:
525 try:
526 x = eval(arg, {}, {})
526 x = eval(arg, {}, {})
527 if type(x) == type(()):
527 if type(x) == type(()):
528 first, last = x
528 first, last = x
529 first = int(first)
529 first = int(first)
530 last = int(last)
530 last = int(last)
531 if last < first:
531 if last < first:
532 # Assume it's a count
532 # Assume it's a count
533 last = first + last
533 last = first + last
534 else:
534 else:
535 first = max(1, int(x) - 5)
535 first = max(1, int(x) - 5)
536 except:
536 except:
537 print('*** Error in argument:', repr(arg))
537 print('*** Error in argument:', repr(arg))
538 return
538 return
539 elif self.lineno is None:
539 elif self.lineno is None:
540 first = max(1, self.curframe.f_lineno - 5)
540 first = max(1, self.curframe.f_lineno - 5)
541 else:
541 else:
542 first = self.lineno + 1
542 first = self.lineno + 1
543 if last is None:
543 if last is None:
544 last = first + 10
544 last = first + 10
545 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
545 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
546
546
547 # vds: >>
547 # vds: >>
548 lineno = first
548 lineno = first
549 filename = self.curframe.f_code.co_filename
549 filename = self.curframe.f_code.co_filename
550 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
550 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
551 # vds: <<
551 # vds: <<
552
552
553 do_l = do_list
553 do_l = do_list
554
554
555 def getsourcelines(self, obj):
555 def getsourcelines(self, obj):
556 lines, lineno = inspect.findsource(obj)
556 lines, lineno = inspect.findsource(obj)
557 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
557 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
558 # must be a module frame: do not try to cut a block out of it
558 # must be a module frame: do not try to cut a block out of it
559 return lines, 1
559 return lines, 1
560 elif inspect.ismodule(obj):
560 elif inspect.ismodule(obj):
561 return lines, 1
561 return lines, 1
562 return inspect.getblock(lines[lineno:]), lineno+1
562 return inspect.getblock(lines[lineno:]), lineno+1
563
563
564 def do_longlist(self, arg):
564 def do_longlist(self, arg):
565 self.lastcmd = 'longlist'
565 self.lastcmd = 'longlist'
566 try:
566 try:
567 lines, lineno = self.getsourcelines(self.curframe)
567 lines, lineno = self.getsourcelines(self.curframe)
568 except OSError as err:
568 except OSError as err:
569 self.error(err)
569 self.error(err)
570 return
570 return
571 last = lineno + len(lines)
571 last = lineno + len(lines)
572 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
572 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
573 do_ll = do_longlist
573 do_ll = do_longlist
574
574
575 def do_pdef(self, arg):
575 def do_pdef(self, arg):
576 """Print the call signature for any callable object.
576 """Print the call signature for any callable object.
577
577
578 The debugger interface to %pdef"""
578 The debugger interface to %pdef"""
579 namespaces = [('Locals', self.curframe.f_locals),
579 namespaces = [('Locals', self.curframe.f_locals),
580 ('Globals', self.curframe.f_globals)]
580 ('Globals', self.curframe.f_globals)]
581 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
581 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
582
582
583 def do_pdoc(self, arg):
583 def do_pdoc(self, arg):
584 """Print the docstring for an object.
584 """Print the docstring for an object.
585
585
586 The debugger interface to %pdoc."""
586 The debugger interface to %pdoc."""
587 namespaces = [('Locals', self.curframe.f_locals),
587 namespaces = [('Locals', self.curframe.f_locals),
588 ('Globals', self.curframe.f_globals)]
588 ('Globals', self.curframe.f_globals)]
589 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
589 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
590
590
591 def do_pfile(self, arg):
591 def do_pfile(self, arg):
592 """Print (or run through pager) the file where an object is defined.
592 """Print (or run through pager) the file where an object is defined.
593
593
594 The debugger interface to %pfile.
594 The debugger interface to %pfile.
595 """
595 """
596 namespaces = [('Locals', self.curframe.f_locals),
596 namespaces = [('Locals', self.curframe.f_locals),
597 ('Globals', self.curframe.f_globals)]
597 ('Globals', self.curframe.f_globals)]
598 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
598 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
599
599
600 def do_pinfo(self, arg):
600 def do_pinfo(self, arg):
601 """Provide detailed information about an object.
601 """Provide detailed information about an object.
602
602
603 The debugger interface to %pinfo, i.e., obj?."""
603 The debugger interface to %pinfo, i.e., obj?."""
604 namespaces = [('Locals', self.curframe.f_locals),
604 namespaces = [('Locals', self.curframe.f_locals),
605 ('Globals', self.curframe.f_globals)]
605 ('Globals', self.curframe.f_globals)]
606 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
606 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
607
607
608 def do_pinfo2(self, arg):
608 def do_pinfo2(self, arg):
609 """Provide extra detailed information about an object.
609 """Provide extra detailed information about an object.
610
610
611 The debugger interface to %pinfo2, i.e., obj??."""
611 The debugger interface to %pinfo2, i.e., obj??."""
612 namespaces = [('Locals', self.curframe.f_locals),
612 namespaces = [('Locals', self.curframe.f_locals),
613 ('Globals', self.curframe.f_globals)]
613 ('Globals', self.curframe.f_globals)]
614 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
614 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
615
615
616 def do_psource(self, arg):
616 def do_psource(self, arg):
617 """Print (or run through pager) the source code for an object."""
617 """Print (or run through pager) the source code for an object."""
618 namespaces = [('Locals', self.curframe.f_locals),
618 namespaces = [('Locals', self.curframe.f_locals),
619 ('Globals', self.curframe.f_globals)]
619 ('Globals', self.curframe.f_globals)]
620 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
620 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
621
621
622 if sys.version_info > (3, ):
622 if sys.version_info > (3, ):
623 def do_where(self, arg):
623 def do_where(self, arg):
624 """w(here)
624 """w(here)
625 Print a stack trace, with the most recent frame at the bottom.
625 Print a stack trace, with the most recent frame at the bottom.
626 An arrow indicates the "current frame", which determines the
626 An arrow indicates the "current frame", which determines the
627 context of most commands. 'bt' is an alias for this command.
627 context of most commands. 'bt' is an alias for this command.
628
628
629 Take a number as argument as an (optional) number of context line to
629 Take a number as argument as an (optional) number of context line to
630 print"""
630 print"""
631 if arg:
631 if arg:
632 context = int(arg)
632 context = int(arg)
633 self.print_stack_trace(context)
633 self.print_stack_trace(context)
634 else:
634 else:
635 self.print_stack_trace()
635 self.print_stack_trace()
636
636
637 do_w = do_where
637 do_w = do_where
@@ -1,1004 +1,1004 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 try:
9 try:
10 from base64 import encodebytes as base64_encode
10 from base64 import encodebytes as base64_encode
11 except ImportError:
11 except ImportError:
12 from base64 import encodestring as base64_encode
12 from base64 import encodestring as base64_encode
13
13
14 import json
14 import json
15 import mimetypes
15 import mimetypes
16 import os
16 import os
17 import struct
17 import struct
18 import sys
18 import warnings
19 import warnings
19
20
20 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
21 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
21 unicode_type)
22 unicode_type)
22 from IPython.testing.skipdoctest import skip_doctest
23 from IPython.testing.skipdoctest import skip_doctest
23
24
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
28 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 'publish_display_data']
30 'publish_display_data']
30
31
31 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
32 # utility functions
33 # utility functions
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34
35
35 def _safe_exists(path):
36 def _safe_exists(path):
36 """Check path, but don't let exceptions raise"""
37 """Check path, but don't let exceptions raise"""
37 try:
38 try:
38 return os.path.exists(path)
39 return os.path.exists(path)
39 except Exception:
40 except Exception:
40 return False
41 return False
41
42
42 def _merge(d1, d2):
43 def _merge(d1, d2):
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
44 """Like update, but merges sub-dicts instead of clobbering at the top level.
44
45
45 Updates d1 in-place
46 Updates d1 in-place
46 """
47 """
47
48
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
49 if not isinstance(d2, dict) or not isinstance(d1, dict):
49 return d2
50 return d2
50 for key, value in d2.items():
51 for key, value in d2.items():
51 d1[key] = _merge(d1.get(key), value)
52 d1[key] = _merge(d1.get(key), value)
52 return d1
53 return d1
53
54
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
55 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
55 """internal implementation of all display_foo methods
56 """internal implementation of all display_foo methods
56
57
57 Parameters
58 Parameters
58 ----------
59 ----------
59 mimetype : str
60 mimetype : str
60 The mimetype to be published (e.g. 'image/png')
61 The mimetype to be published (e.g. 'image/png')
61 objs : tuple of objects
62 objs : tuple of objects
62 The Python objects to display, or if raw=True raw text data to
63 The Python objects to display, or if raw=True raw text data to
63 display.
64 display.
64 raw : bool
65 raw : bool
65 Are the data objects raw data or Python objects that need to be
66 Are the data objects raw data or Python objects that need to be
66 formatted before display? [default: False]
67 formatted before display? [default: False]
67 metadata : dict (optional)
68 metadata : dict (optional)
68 Metadata to be associated with the specific mimetype output.
69 Metadata to be associated with the specific mimetype output.
69 """
70 """
70 if metadata:
71 if metadata:
71 metadata = {mimetype: metadata}
72 metadata = {mimetype: metadata}
72 if raw:
73 if raw:
73 # turn list of pngdata into list of { 'image/png': pngdata }
74 # turn list of pngdata into list of { 'image/png': pngdata }
74 objs = [ {mimetype: obj} for obj in objs ]
75 objs = [ {mimetype: obj} for obj in objs ]
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
76 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
76
77
77 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
78 # Main functions
79 # Main functions
79 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
80
81
81 def publish_display_data(data, metadata=None, source=None):
82 def publish_display_data(data, metadata=None, source=None):
82 """Publish data and metadata to all frontends.
83 """Publish data and metadata to all frontends.
83
84
84 See the ``display_data`` message in the messaging documentation for
85 See the ``display_data`` message in the messaging documentation for
85 more details about this message type.
86 more details about this message type.
86
87
87 The following MIME types are currently implemented:
88 The following MIME types are currently implemented:
88
89
89 * text/plain
90 * text/plain
90 * text/html
91 * text/html
91 * text/markdown
92 * text/markdown
92 * text/latex
93 * text/latex
93 * application/json
94 * application/json
94 * application/javascript
95 * application/javascript
95 * image/png
96 * image/png
96 * image/jpeg
97 * image/jpeg
97 * image/svg+xml
98 * image/svg+xml
98
99
99 Parameters
100 Parameters
100 ----------
101 ----------
101 data : dict
102 data : dict
102 A dictionary having keys that are valid MIME types (like
103 A dictionary having keys that are valid MIME types (like
103 'text/plain' or 'image/svg+xml') and values that are the data for
104 'text/plain' or 'image/svg+xml') and values that are the data for
104 that MIME type. The data itself must be a JSON'able data
105 that MIME type. The data itself must be a JSON'able data
105 structure. Minimally all data should have the 'text/plain' data,
106 structure. Minimally all data should have the 'text/plain' data,
106 which can be displayed by all frontends. If more than the plain
107 which can be displayed by all frontends. If more than the plain
107 text is given, it is up to the frontend to decide which
108 text is given, it is up to the frontend to decide which
108 representation to use.
109 representation to use.
109 metadata : dict
110 metadata : dict
110 A dictionary for metadata related to the data. This can contain
111 A dictionary for metadata related to the data. This can contain
111 arbitrary key, value pairs that frontends can use to interpret
112 arbitrary key, value pairs that frontends can use to interpret
112 the data. mime-type keys matching those in data can be used
113 the data. mime-type keys matching those in data can be used
113 to specify metadata about particular representations.
114 to specify metadata about particular representations.
114 source : str, deprecated
115 source : str, deprecated
115 Unused.
116 Unused.
116 """
117 """
117 from IPython.core.interactiveshell import InteractiveShell
118 from IPython.core.interactiveshell import InteractiveShell
118 InteractiveShell.instance().display_pub.publish(
119 InteractiveShell.instance().display_pub.publish(
119 data=data,
120 data=data,
120 metadata=metadata,
121 metadata=metadata,
121 )
122 )
122
123
123 def display(*objs, **kwargs):
124 def display(*objs, **kwargs):
124 """Display a Python object in all frontends.
125 """Display a Python object in all frontends.
125
126
126 By default all representations will be computed and sent to the frontends.
127 By default all representations will be computed and sent to the frontends.
127 Frontends can decide which representation is used and how.
128 Frontends can decide which representation is used and how.
128
129
129 Parameters
130 Parameters
130 ----------
131 ----------
131 objs : tuple of objects
132 objs : tuple of objects
132 The Python objects to display.
133 The Python objects to display.
133 raw : bool, optional
134 raw : bool, optional
134 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
135 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
135 or Python objects that need to be formatted before display? [default: False]
136 or Python objects that need to be formatted before display? [default: False]
136 include : list or tuple, optional
137 include : list or tuple, optional
137 A list of format type strings (MIME types) to include in the
138 A list of format type strings (MIME types) to include in the
138 format data dict. If this is set *only* the format types included
139 format data dict. If this is set *only* the format types included
139 in this list will be computed.
140 in this list will be computed.
140 exclude : list or tuple, optional
141 exclude : list or tuple, optional
141 A list of format type strings (MIME types) to exclude in the format
142 A list of format type strings (MIME types) to exclude in the format
142 data dict. If this is set all format types will be computed,
143 data dict. If this is set all format types will be computed,
143 except for those included in this argument.
144 except for those included in this argument.
144 metadata : dict, optional
145 metadata : dict, optional
145 A dictionary of metadata to associate with the output.
146 A dictionary of metadata to associate with the output.
146 mime-type keys in this dictionary will be associated with the individual
147 mime-type keys in this dictionary will be associated with the individual
147 representation formats, if they exist.
148 representation formats, if they exist.
148 """
149 """
149 raw = kwargs.get('raw', False)
150 raw = kwargs.get('raw', False)
150 include = kwargs.get('include')
151 include = kwargs.get('include')
151 exclude = kwargs.get('exclude')
152 exclude = kwargs.get('exclude')
152 metadata = kwargs.get('metadata')
153 metadata = kwargs.get('metadata')
153
154
154 from IPython.core.interactiveshell import InteractiveShell
155 from IPython.core.interactiveshell import InteractiveShell
155
156
156 if not raw:
157 if not raw:
157 format = InteractiveShell.instance().display_formatter.format
158 format = InteractiveShell.instance().display_formatter.format
158
159
159 for obj in objs:
160 for obj in objs:
160 if raw:
161 if raw:
161 publish_display_data(data=obj, metadata=metadata)
162 publish_display_data(data=obj, metadata=metadata)
162 else:
163 else:
163 format_dict, md_dict = format(obj, include=include, exclude=exclude)
164 format_dict, md_dict = format(obj, include=include, exclude=exclude)
164 if not format_dict:
165 if not format_dict:
165 # nothing to display (e.g. _ipython_display_ took over)
166 # nothing to display (e.g. _ipython_display_ took over)
166 continue
167 continue
167 if metadata:
168 if metadata:
168 # kwarg-specified metadata gets precedence
169 # kwarg-specified metadata gets precedence
169 _merge(md_dict, metadata)
170 _merge(md_dict, metadata)
170 publish_display_data(data=format_dict, metadata=md_dict)
171 publish_display_data(data=format_dict, metadata=md_dict)
171
172
172
173
173 def display_pretty(*objs, **kwargs):
174 def display_pretty(*objs, **kwargs):
174 """Display the pretty (default) representation of an object.
175 """Display the pretty (default) representation of an object.
175
176
176 Parameters
177 Parameters
177 ----------
178 ----------
178 objs : tuple of objects
179 objs : tuple of objects
179 The Python objects to display, or if raw=True raw text data to
180 The Python objects to display, or if raw=True raw text data to
180 display.
181 display.
181 raw : bool
182 raw : bool
182 Are the data objects raw data or Python objects that need to be
183 Are the data objects raw data or Python objects that need to be
183 formatted before display? [default: False]
184 formatted before display? [default: False]
184 metadata : dict (optional)
185 metadata : dict (optional)
185 Metadata to be associated with the specific mimetype output.
186 Metadata to be associated with the specific mimetype output.
186 """
187 """
187 _display_mimetype('text/plain', objs, **kwargs)
188 _display_mimetype('text/plain', objs, **kwargs)
188
189
189
190
190 def display_html(*objs, **kwargs):
191 def display_html(*objs, **kwargs):
191 """Display the HTML representation of an object.
192 """Display the HTML representation of an object.
192
193
193 Note: If raw=False and the object does not have a HTML
194 Note: If raw=False and the object does not have a HTML
194 representation, no HTML will be shown.
195 representation, no HTML will be shown.
195
196
196 Parameters
197 Parameters
197 ----------
198 ----------
198 objs : tuple of objects
199 objs : tuple of objects
199 The Python objects to display, or if raw=True raw HTML data to
200 The Python objects to display, or if raw=True raw HTML data to
200 display.
201 display.
201 raw : bool
202 raw : bool
202 Are the data objects raw data or Python objects that need to be
203 Are the data objects raw data or Python objects that need to be
203 formatted before display? [default: False]
204 formatted before display? [default: False]
204 metadata : dict (optional)
205 metadata : dict (optional)
205 Metadata to be associated with the specific mimetype output.
206 Metadata to be associated with the specific mimetype output.
206 """
207 """
207 _display_mimetype('text/html', objs, **kwargs)
208 _display_mimetype('text/html', objs, **kwargs)
208
209
209
210
210 def display_markdown(*objs, **kwargs):
211 def display_markdown(*objs, **kwargs):
211 """Displays the Markdown representation of an object.
212 """Displays the Markdown representation of an object.
212
213
213 Parameters
214 Parameters
214 ----------
215 ----------
215 objs : tuple of objects
216 objs : tuple of objects
216 The Python objects to display, or if raw=True raw markdown data to
217 The Python objects to display, or if raw=True raw markdown data to
217 display.
218 display.
218 raw : bool
219 raw : bool
219 Are the data objects raw data or Python objects that need to be
220 Are the data objects raw data or Python objects that need to be
220 formatted before display? [default: False]
221 formatted before display? [default: False]
221 metadata : dict (optional)
222 metadata : dict (optional)
222 Metadata to be associated with the specific mimetype output.
223 Metadata to be associated with the specific mimetype output.
223 """
224 """
224
225
225 _display_mimetype('text/markdown', objs, **kwargs)
226 _display_mimetype('text/markdown', objs, **kwargs)
226
227
227
228
228 def display_svg(*objs, **kwargs):
229 def display_svg(*objs, **kwargs):
229 """Display the SVG representation of an object.
230 """Display the SVG representation of an object.
230
231
231 Parameters
232 Parameters
232 ----------
233 ----------
233 objs : tuple of objects
234 objs : tuple of objects
234 The Python objects to display, or if raw=True raw svg data to
235 The Python objects to display, or if raw=True raw svg data to
235 display.
236 display.
236 raw : bool
237 raw : bool
237 Are the data objects raw data or Python objects that need to be
238 Are the data objects raw data or Python objects that need to be
238 formatted before display? [default: False]
239 formatted before display? [default: False]
239 metadata : dict (optional)
240 metadata : dict (optional)
240 Metadata to be associated with the specific mimetype output.
241 Metadata to be associated with the specific mimetype output.
241 """
242 """
242 _display_mimetype('image/svg+xml', objs, **kwargs)
243 _display_mimetype('image/svg+xml', objs, **kwargs)
243
244
244
245
245 def display_png(*objs, **kwargs):
246 def display_png(*objs, **kwargs):
246 """Display the PNG representation of an object.
247 """Display the PNG representation of an object.
247
248
248 Parameters
249 Parameters
249 ----------
250 ----------
250 objs : tuple of objects
251 objs : tuple of objects
251 The Python objects to display, or if raw=True raw png data to
252 The Python objects to display, or if raw=True raw png data to
252 display.
253 display.
253 raw : bool
254 raw : bool
254 Are the data objects raw data or Python objects that need to be
255 Are the data objects raw data or Python objects that need to be
255 formatted before display? [default: False]
256 formatted before display? [default: False]
256 metadata : dict (optional)
257 metadata : dict (optional)
257 Metadata to be associated with the specific mimetype output.
258 Metadata to be associated with the specific mimetype output.
258 """
259 """
259 _display_mimetype('image/png', objs, **kwargs)
260 _display_mimetype('image/png', objs, **kwargs)
260
261
261
262
262 def display_jpeg(*objs, **kwargs):
263 def display_jpeg(*objs, **kwargs):
263 """Display the JPEG representation of an object.
264 """Display the JPEG representation of an object.
264
265
265 Parameters
266 Parameters
266 ----------
267 ----------
267 objs : tuple of objects
268 objs : tuple of objects
268 The Python objects to display, or if raw=True raw JPEG data to
269 The Python objects to display, or if raw=True raw JPEG data to
269 display.
270 display.
270 raw : bool
271 raw : bool
271 Are the data objects raw data or Python objects that need to be
272 Are the data objects raw data or Python objects that need to be
272 formatted before display? [default: False]
273 formatted before display? [default: False]
273 metadata : dict (optional)
274 metadata : dict (optional)
274 Metadata to be associated with the specific mimetype output.
275 Metadata to be associated with the specific mimetype output.
275 """
276 """
276 _display_mimetype('image/jpeg', objs, **kwargs)
277 _display_mimetype('image/jpeg', objs, **kwargs)
277
278
278
279
279 def display_latex(*objs, **kwargs):
280 def display_latex(*objs, **kwargs):
280 """Display the LaTeX representation of an object.
281 """Display the LaTeX representation of an object.
281
282
282 Parameters
283 Parameters
283 ----------
284 ----------
284 objs : tuple of objects
285 objs : tuple of objects
285 The Python objects to display, or if raw=True raw latex data to
286 The Python objects to display, or if raw=True raw latex data to
286 display.
287 display.
287 raw : bool
288 raw : bool
288 Are the data objects raw data or Python objects that need to be
289 Are the data objects raw data or Python objects that need to be
289 formatted before display? [default: False]
290 formatted before display? [default: False]
290 metadata : dict (optional)
291 metadata : dict (optional)
291 Metadata to be associated with the specific mimetype output.
292 Metadata to be associated with the specific mimetype output.
292 """
293 """
293 _display_mimetype('text/latex', objs, **kwargs)
294 _display_mimetype('text/latex', objs, **kwargs)
294
295
295
296
296 def display_json(*objs, **kwargs):
297 def display_json(*objs, **kwargs):
297 """Display the JSON representation of an object.
298 """Display the JSON representation of an object.
298
299
299 Note that not many frontends support displaying JSON.
300 Note that not many frontends support displaying JSON.
300
301
301 Parameters
302 Parameters
302 ----------
303 ----------
303 objs : tuple of objects
304 objs : tuple of objects
304 The Python objects to display, or if raw=True raw json data to
305 The Python objects to display, or if raw=True raw json data to
305 display.
306 display.
306 raw : bool
307 raw : bool
307 Are the data objects raw data or Python objects that need to be
308 Are the data objects raw data or Python objects that need to be
308 formatted before display? [default: False]
309 formatted before display? [default: False]
309 metadata : dict (optional)
310 metadata : dict (optional)
310 Metadata to be associated with the specific mimetype output.
311 Metadata to be associated with the specific mimetype output.
311 """
312 """
312 _display_mimetype('application/json', objs, **kwargs)
313 _display_mimetype('application/json', objs, **kwargs)
313
314
314
315
315 def display_javascript(*objs, **kwargs):
316 def display_javascript(*objs, **kwargs):
316 """Display the Javascript representation of an object.
317 """Display the Javascript representation of an object.
317
318
318 Parameters
319 Parameters
319 ----------
320 ----------
320 objs : tuple of objects
321 objs : tuple of objects
321 The Python objects to display, or if raw=True raw javascript data to
322 The Python objects to display, or if raw=True raw javascript data to
322 display.
323 display.
323 raw : bool
324 raw : bool
324 Are the data objects raw data or Python objects that need to be
325 Are the data objects raw data or Python objects that need to be
325 formatted before display? [default: False]
326 formatted before display? [default: False]
326 metadata : dict (optional)
327 metadata : dict (optional)
327 Metadata to be associated with the specific mimetype output.
328 Metadata to be associated with the specific mimetype output.
328 """
329 """
329 _display_mimetype('application/javascript', objs, **kwargs)
330 _display_mimetype('application/javascript', objs, **kwargs)
330
331
331
332
332 def display_pdf(*objs, **kwargs):
333 def display_pdf(*objs, **kwargs):
333 """Display the PDF representation of an object.
334 """Display the PDF representation of an object.
334
335
335 Parameters
336 Parameters
336 ----------
337 ----------
337 objs : tuple of objects
338 objs : tuple of objects
338 The Python objects to display, or if raw=True raw javascript data to
339 The Python objects to display, or if raw=True raw javascript data to
339 display.
340 display.
340 raw : bool
341 raw : bool
341 Are the data objects raw data or Python objects that need to be
342 Are the data objects raw data or Python objects that need to be
342 formatted before display? [default: False]
343 formatted before display? [default: False]
343 metadata : dict (optional)
344 metadata : dict (optional)
344 Metadata to be associated with the specific mimetype output.
345 Metadata to be associated with the specific mimetype output.
345 """
346 """
346 _display_mimetype('application/pdf', objs, **kwargs)
347 _display_mimetype('application/pdf', objs, **kwargs)
347
348
348
349
349 #-----------------------------------------------------------------------------
350 #-----------------------------------------------------------------------------
350 # Smart classes
351 # Smart classes
351 #-----------------------------------------------------------------------------
352 #-----------------------------------------------------------------------------
352
353
353
354
354 class DisplayObject(object):
355 class DisplayObject(object):
355 """An object that wraps data to be displayed."""
356 """An object that wraps data to be displayed."""
356
357
357 _read_flags = 'r'
358 _read_flags = 'r'
358 _show_mem_addr = False
359 _show_mem_addr = False
359
360
360 def __init__(self, data=None, url=None, filename=None):
361 def __init__(self, data=None, url=None, filename=None):
361 """Create a display object given raw data.
362 """Create a display object given raw data.
362
363
363 When this object is returned by an expression or passed to the
364 When this object is returned by an expression or passed to the
364 display function, it will result in the data being displayed
365 display function, it will result in the data being displayed
365 in the frontend. The MIME type of the data should match the
366 in the frontend. The MIME type of the data should match the
366 subclasses used, so the Png subclass should be used for 'image/png'
367 subclasses used, so the Png subclass should be used for 'image/png'
367 data. If the data is a URL, the data will first be downloaded
368 data. If the data is a URL, the data will first be downloaded
368 and then displayed. If
369 and then displayed. If
369
370
370 Parameters
371 Parameters
371 ----------
372 ----------
372 data : unicode, str or bytes
373 data : unicode, str or bytes
373 The raw data or a URL or file to load the data from
374 The raw data or a URL or file to load the data from
374 url : unicode
375 url : unicode
375 A URL to download the data from.
376 A URL to download the data from.
376 filename : unicode
377 filename : unicode
377 Path to a local file to load the data from.
378 Path to a local file to load the data from.
378 """
379 """
379 if data is not None and isinstance(data, string_types):
380 if data is not None and isinstance(data, string_types):
380 if data.startswith('http') and url is None:
381 if data.startswith('http') and url is None:
381 url = data
382 url = data
382 filename = None
383 filename = None
383 data = None
384 data = None
384 elif _safe_exists(data) and filename is None:
385 elif _safe_exists(data) and filename is None:
385 url = None
386 url = None
386 filename = data
387 filename = data
387 data = None
388 data = None
388
389
389 self.data = data
390 self.data = data
390 self.url = url
391 self.url = url
391 self.filename = None if filename is None else unicode_type(filename)
392 self.filename = None if filename is None else unicode_type(filename)
392
393
393 self.reload()
394 self.reload()
394 self._check_data()
395 self._check_data()
395
396
396 def __repr__(self):
397 def __repr__(self):
397 if not self._show_mem_addr:
398 if not self._show_mem_addr:
398 cls = self.__class__
399 cls = self.__class__
399 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
400 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
400 else:
401 else:
401 r = super(DisplayObject, self).__repr__()
402 r = super(DisplayObject, self).__repr__()
402 return r
403 return r
403
404
404 def _check_data(self):
405 def _check_data(self):
405 """Override in subclasses if there's something to check."""
406 """Override in subclasses if there's something to check."""
406 pass
407 pass
407
408
408 def reload(self):
409 def reload(self):
409 """Reload the raw data from file or URL."""
410 """Reload the raw data from file or URL."""
410 if self.filename is not None:
411 if self.filename is not None:
411 with open(self.filename, self._read_flags) as f:
412 with open(self.filename, self._read_flags) as f:
412 self.data = f.read()
413 self.data = f.read()
413 elif self.url is not None:
414 elif self.url is not None:
414 try:
415 try:
415 try:
416 try:
416 from urllib.request import urlopen # Py3
417 from urllib.request import urlopen # Py3
417 except ImportError:
418 except ImportError:
418 from urllib2 import urlopen
419 from urllib2 import urlopen
419 response = urlopen(self.url)
420 response = urlopen(self.url)
420 self.data = response.read()
421 self.data = response.read()
421 # extract encoding from header, if there is one:
422 # extract encoding from header, if there is one:
422 encoding = None
423 encoding = None
423 for sub in response.headers['content-type'].split(';'):
424 for sub in response.headers['content-type'].split(';'):
424 sub = sub.strip()
425 sub = sub.strip()
425 if sub.startswith('charset'):
426 if sub.startswith('charset'):
426 encoding = sub.split('=')[-1].strip()
427 encoding = sub.split('=')[-1].strip()
427 break
428 break
428 # decode data, if an encoding was specified
429 # decode data, if an encoding was specified
429 if encoding:
430 if encoding:
430 self.data = self.data.decode(encoding, 'replace')
431 self.data = self.data.decode(encoding, 'replace')
431 except:
432 except:
432 self.data = None
433 self.data = None
433
434
434 class TextDisplayObject(DisplayObject):
435 class TextDisplayObject(DisplayObject):
435 """Validate that display data is text"""
436 """Validate that display data is text"""
436 def _check_data(self):
437 def _check_data(self):
437 if self.data is not None and not isinstance(self.data, string_types):
438 if self.data is not None and not isinstance(self.data, string_types):
438 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
439 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
439
440
440 class Pretty(TextDisplayObject):
441 class Pretty(TextDisplayObject):
441
442
442 def _repr_pretty_(self):
443 def _repr_pretty_(self):
443 return self.data
444 return self.data
444
445
445
446
446 class HTML(TextDisplayObject):
447 class HTML(TextDisplayObject):
447
448
448 def _repr_html_(self):
449 def _repr_html_(self):
449 return self.data
450 return self.data
450
451
451 def __html__(self):
452 def __html__(self):
452 """
453 """
453 This method exists to inform other HTML-using modules (e.g. Markupsafe,
454 This method exists to inform other HTML-using modules (e.g. Markupsafe,
454 htmltag, etc) that this object is HTML and does not need things like
455 htmltag, etc) that this object is HTML and does not need things like
455 special characters (<>&) escaped.
456 special characters (<>&) escaped.
456 """
457 """
457 return self._repr_html_()
458 return self._repr_html_()
458
459
459
460
460 class Markdown(TextDisplayObject):
461 class Markdown(TextDisplayObject):
461
462
462 def _repr_markdown_(self):
463 def _repr_markdown_(self):
463 return self.data
464 return self.data
464
465
465
466
466 class Math(TextDisplayObject):
467 class Math(TextDisplayObject):
467
468
468 def _repr_latex_(self):
469 def _repr_latex_(self):
469 s = self.data.strip('$')
470 s = self.data.strip('$')
470 return "$$%s$$" % s
471 return "$$%s$$" % s
471
472
472
473
473 class Latex(TextDisplayObject):
474 class Latex(TextDisplayObject):
474
475
475 def _repr_latex_(self):
476 def _repr_latex_(self):
476 return self.data
477 return self.data
477
478
478
479
479 class SVG(DisplayObject):
480 class SVG(DisplayObject):
480
481
481 # wrap data in a property, which extracts the <svg> tag, discarding
482 # wrap data in a property, which extracts the <svg> tag, discarding
482 # document headers
483 # document headers
483 _data = None
484 _data = None
484
485
485 @property
486 @property
486 def data(self):
487 def data(self):
487 return self._data
488 return self._data
488
489
489 @data.setter
490 @data.setter
490 def data(self, svg):
491 def data(self, svg):
491 if svg is None:
492 if svg is None:
492 self._data = None
493 self._data = None
493 return
494 return
494 # parse into dom object
495 # parse into dom object
495 from xml.dom import minidom
496 from xml.dom import minidom
496 svg = cast_bytes_py2(svg)
497 svg = cast_bytes_py2(svg)
497 x = minidom.parseString(svg)
498 x = minidom.parseString(svg)
498 # get svg tag (should be 1)
499 # get svg tag (should be 1)
499 found_svg = x.getElementsByTagName('svg')
500 found_svg = x.getElementsByTagName('svg')
500 if found_svg:
501 if found_svg:
501 svg = found_svg[0].toxml()
502 svg = found_svg[0].toxml()
502 else:
503 else:
503 # fallback on the input, trust the user
504 # fallback on the input, trust the user
504 # but this is probably an error.
505 # but this is probably an error.
505 pass
506 pass
506 svg = cast_unicode(svg)
507 svg = cast_unicode(svg)
507 self._data = svg
508 self._data = svg
508
509
509 def _repr_svg_(self):
510 def _repr_svg_(self):
510 return self.data
511 return self.data
511
512
512
513
513 class JSON(DisplayObject):
514 class JSON(DisplayObject):
514 """JSON expects a JSON-able dict or list
515 """JSON expects a JSON-able dict or list
515
516
516 not an already-serialized JSON string.
517 not an already-serialized JSON string.
517
518
518 Scalar types (None, number, string) are not allowed, only dict or list containers.
519 Scalar types (None, number, string) are not allowed, only dict or list containers.
519 """
520 """
520 # wrap data in a property, which warns about passing already-serialized JSON
521 # wrap data in a property, which warns about passing already-serialized JSON
521 _data = None
522 _data = None
522 def _check_data(self):
523 def _check_data(self):
523 if self.data is not None and not isinstance(self.data, (dict, list)):
524 if self.data is not None and not isinstance(self.data, (dict, list)):
524 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
525 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
525
526
526 @property
527 @property
527 def data(self):
528 def data(self):
528 return self._data
529 return self._data
529
530
530 @data.setter
531 @data.setter
531 def data(self, data):
532 def data(self, data):
532 if isinstance(data, string_types):
533 if isinstance(data, string_types):
533 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
534 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
534 data = json.loads(data)
535 data = json.loads(data)
535 self._data = data
536 self._data = data
536
537
537 def _repr_json_(self):
538 def _repr_json_(self):
538 return self.data
539 return self.data
539
540
540 css_t = """$("head").append($("<link/>").attr({
541 css_t = """$("head").append($("<link/>").attr({
541 rel: "stylesheet",
542 rel: "stylesheet",
542 type: "text/css",
543 type: "text/css",
543 href: "%s"
544 href: "%s"
544 }));
545 }));
545 """
546 """
546
547
547 lib_t1 = """$.getScript("%s", function () {
548 lib_t1 = """$.getScript("%s", function () {
548 """
549 """
549 lib_t2 = """});
550 lib_t2 = """});
550 """
551 """
551
552
552 class Javascript(TextDisplayObject):
553 class Javascript(TextDisplayObject):
553
554
554 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
555 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
555 """Create a Javascript display object given raw data.
556 """Create a Javascript display object given raw data.
556
557
557 When this object is returned by an expression or passed to the
558 When this object is returned by an expression or passed to the
558 display function, it will result in the data being displayed
559 display function, it will result in the data being displayed
559 in the frontend. If the data is a URL, the data will first be
560 in the frontend. If the data is a URL, the data will first be
560 downloaded and then displayed.
561 downloaded and then displayed.
561
562
562 In the Notebook, the containing element will be available as `element`,
563 In the Notebook, the containing element will be available as `element`,
563 and jQuery will be available. Content appended to `element` will be
564 and jQuery will be available. Content appended to `element` will be
564 visible in the output area.
565 visible in the output area.
565
566
566 Parameters
567 Parameters
567 ----------
568 ----------
568 data : unicode, str or bytes
569 data : unicode, str or bytes
569 The Javascript source code or a URL to download it from.
570 The Javascript source code or a URL to download it from.
570 url : unicode
571 url : unicode
571 A URL to download the data from.
572 A URL to download the data from.
572 filename : unicode
573 filename : unicode
573 Path to a local file to load the data from.
574 Path to a local file to load the data from.
574 lib : list or str
575 lib : list or str
575 A sequence of Javascript library URLs to load asynchronously before
576 A sequence of Javascript library URLs to load asynchronously before
576 running the source code. The full URLs of the libraries should
577 running the source code. The full URLs of the libraries should
577 be given. A single Javascript library URL can also be given as a
578 be given. A single Javascript library URL can also be given as a
578 string.
579 string.
579 css: : list or str
580 css: : list or str
580 A sequence of css files to load before running the source code.
581 A sequence of css files to load before running the source code.
581 The full URLs of the css files should be given. A single css URL
582 The full URLs of the css files should be given. A single css URL
582 can also be given as a string.
583 can also be given as a string.
583 """
584 """
584 if isinstance(lib, string_types):
585 if isinstance(lib, string_types):
585 lib = [lib]
586 lib = [lib]
586 elif lib is None:
587 elif lib is None:
587 lib = []
588 lib = []
588 if isinstance(css, string_types):
589 if isinstance(css, string_types):
589 css = [css]
590 css = [css]
590 elif css is None:
591 elif css is None:
591 css = []
592 css = []
592 if not isinstance(lib, (list,tuple)):
593 if not isinstance(lib, (list,tuple)):
593 raise TypeError('expected sequence, got: %r' % lib)
594 raise TypeError('expected sequence, got: %r' % lib)
594 if not isinstance(css, (list,tuple)):
595 if not isinstance(css, (list,tuple)):
595 raise TypeError('expected sequence, got: %r' % css)
596 raise TypeError('expected sequence, got: %r' % css)
596 self.lib = lib
597 self.lib = lib
597 self.css = css
598 self.css = css
598 super(Javascript, self).__init__(data=data, url=url, filename=filename)
599 super(Javascript, self).__init__(data=data, url=url, filename=filename)
599
600
600 def _repr_javascript_(self):
601 def _repr_javascript_(self):
601 r = ''
602 r = ''
602 for c in self.css:
603 for c in self.css:
603 r += css_t % c
604 r += css_t % c
604 for l in self.lib:
605 for l in self.lib:
605 r += lib_t1 % l
606 r += lib_t1 % l
606 r += self.data
607 r += self.data
607 r += lib_t2*len(self.lib)
608 r += lib_t2*len(self.lib)
608 return r
609 return r
609
610
610 # constants for identifying png/jpeg data
611 # constants for identifying png/jpeg data
611 _PNG = b'\x89PNG\r\n\x1a\n'
612 _PNG = b'\x89PNG\r\n\x1a\n'
612 _JPEG = b'\xff\xd8'
613 _JPEG = b'\xff\xd8'
613
614
614 def _pngxy(data):
615 def _pngxy(data):
615 """read the (width, height) from a PNG header"""
616 """read the (width, height) from a PNG header"""
616 ihdr = data.index(b'IHDR')
617 ihdr = data.index(b'IHDR')
617 # next 8 bytes are width/height
618 # next 8 bytes are width/height
618 w4h4 = data[ihdr+4:ihdr+12]
619 w4h4 = data[ihdr+4:ihdr+12]
619 return struct.unpack('>ii', w4h4)
620 return struct.unpack('>ii', w4h4)
620
621
621 def _jpegxy(data):
622 def _jpegxy(data):
622 """read the (width, height) from a JPEG header"""
623 """read the (width, height) from a JPEG header"""
623 # adapted from http://www.64lines.com/jpeg-width-height
624 # adapted from http://www.64lines.com/jpeg-width-height
624
625
625 idx = 4
626 idx = 4
626 while True:
627 while True:
627 block_size = struct.unpack('>H', data[idx:idx+2])[0]
628 block_size = struct.unpack('>H', data[idx:idx+2])[0]
628 idx = idx + block_size
629 idx = idx + block_size
629 if data[idx:idx+2] == b'\xFF\xC0':
630 if data[idx:idx+2] == b'\xFF\xC0':
630 # found Start of Frame
631 # found Start of Frame
631 iSOF = idx
632 iSOF = idx
632 break
633 break
633 else:
634 else:
634 # read another block
635 # read another block
635 idx += 2
636 idx += 2
636
637
637 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
638 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
638 return w, h
639 return w, h
639
640
640 class Image(DisplayObject):
641 class Image(DisplayObject):
641
642
642 _read_flags = 'rb'
643 _read_flags = 'rb'
643 _FMT_JPEG = u'jpeg'
644 _FMT_JPEG = u'jpeg'
644 _FMT_PNG = u'png'
645 _FMT_PNG = u'png'
645 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
646 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
646
647
647 def __init__(self, data=None, url=None, filename=None, format=None,
648 def __init__(self, data=None, url=None, filename=None, format=None,
648 embed=None, width=None, height=None, retina=False,
649 embed=None, width=None, height=None, retina=False,
649 unconfined=False, metadata=None):
650 unconfined=False, metadata=None):
650 """Create a PNG/JPEG image object given raw data.
651 """Create a PNG/JPEG image object given raw data.
651
652
652 When this object is returned by an input cell or passed to the
653 When this object is returned by an input cell or passed to the
653 display function, it will result in the image being displayed
654 display function, it will result in the image being displayed
654 in the frontend.
655 in the frontend.
655
656
656 Parameters
657 Parameters
657 ----------
658 ----------
658 data : unicode, str or bytes
659 data : unicode, str or bytes
659 The raw image data or a URL or filename to load the data from.
660 The raw image data or a URL or filename to load the data from.
660 This always results in embedded image data.
661 This always results in embedded image data.
661 url : unicode
662 url : unicode
662 A URL to download the data from. If you specify `url=`,
663 A URL to download the data from. If you specify `url=`,
663 the image data will not be embedded unless you also specify `embed=True`.
664 the image data will not be embedded unless you also specify `embed=True`.
664 filename : unicode
665 filename : unicode
665 Path to a local file to load the data from.
666 Path to a local file to load the data from.
666 Images from a file are always embedded.
667 Images from a file are always embedded.
667 format : unicode
668 format : unicode
668 The format of the image data (png/jpeg/jpg). If a filename or URL is given
669 The format of the image data (png/jpeg/jpg). If a filename or URL is given
669 for format will be inferred from the filename extension.
670 for format will be inferred from the filename extension.
670 embed : bool
671 embed : bool
671 Should the image data be embedded using a data URI (True) or be
672 Should the image data be embedded using a data URI (True) or be
672 loaded using an <img> tag. Set this to True if you want the image
673 loaded using an <img> tag. Set this to True if you want the image
673 to be viewable later with no internet connection in the notebook.
674 to be viewable later with no internet connection in the notebook.
674
675
675 Default is `True`, unless the keyword argument `url` is set, then
676 Default is `True`, unless the keyword argument `url` is set, then
676 default value is `False`.
677 default value is `False`.
677
678
678 Note that QtConsole is not able to display images if `embed` is set to `False`
679 Note that QtConsole is not able to display images if `embed` is set to `False`
679 width : int
680 width : int
680 Width to which to constrain the image in html
681 Width to which to constrain the image in html
681 height : int
682 height : int
682 Height to which to constrain the image in html
683 Height to which to constrain the image in html
683 retina : bool
684 retina : bool
684 Automatically set the width and height to half of the measured
685 Automatically set the width and height to half of the measured
685 width and height.
686 width and height.
686 This only works for embedded images because it reads the width/height
687 This only works for embedded images because it reads the width/height
687 from image data.
688 from image data.
688 For non-embedded images, you can just set the desired display width
689 For non-embedded images, you can just set the desired display width
689 and height directly.
690 and height directly.
690 unconfined: bool
691 unconfined: bool
691 Set unconfined=True to disable max-width confinement of the image.
692 Set unconfined=True to disable max-width confinement of the image.
692 metadata: dict
693 metadata: dict
693 Specify extra metadata to attach to the image.
694 Specify extra metadata to attach to the image.
694
695
695 Examples
696 Examples
696 --------
697 --------
697 # embedded image data, works in qtconsole and notebook
698 # embedded image data, works in qtconsole and notebook
698 # when passed positionally, the first arg can be any of raw image data,
699 # when passed positionally, the first arg can be any of raw image data,
699 # a URL, or a filename from which to load image data.
700 # a URL, or a filename from which to load image data.
700 # The result is always embedding image data for inline images.
701 # The result is always embedding image data for inline images.
701 Image('http://www.google.fr/images/srpr/logo3w.png')
702 Image('http://www.google.fr/images/srpr/logo3w.png')
702 Image('/path/to/image.jpg')
703 Image('/path/to/image.jpg')
703 Image(b'RAW_PNG_DATA...')
704 Image(b'RAW_PNG_DATA...')
704
705
705 # Specifying Image(url=...) does not embed the image data,
706 # Specifying Image(url=...) does not embed the image data,
706 # it only generates `<img>` tag with a link to the source.
707 # it only generates `<img>` tag with a link to the source.
707 # This will not work in the qtconsole or offline.
708 # This will not work in the qtconsole or offline.
708 Image(url='http://www.google.fr/images/srpr/logo3w.png')
709 Image(url='http://www.google.fr/images/srpr/logo3w.png')
709
710
710 """
711 """
711 if filename is not None:
712 if filename is not None:
712 ext = self._find_ext(filename)
713 ext = self._find_ext(filename)
713 elif url is not None:
714 elif url is not None:
714 ext = self._find_ext(url)
715 ext = self._find_ext(url)
715 elif data is None:
716 elif data is None:
716 raise ValueError("No image data found. Expecting filename, url, or data.")
717 raise ValueError("No image data found. Expecting filename, url, or data.")
717 elif isinstance(data, string_types) and (
718 elif isinstance(data, string_types) and (
718 data.startswith('http') or _safe_exists(data)
719 data.startswith('http') or _safe_exists(data)
719 ):
720 ):
720 ext = self._find_ext(data)
721 ext = self._find_ext(data)
721 else:
722 else:
722 ext = None
723 ext = None
723
724
724 if format is None:
725 if format is None:
725 if ext is not None:
726 if ext is not None:
726 if ext == u'jpg' or ext == u'jpeg':
727 if ext == u'jpg' or ext == u'jpeg':
727 format = self._FMT_JPEG
728 format = self._FMT_JPEG
728 if ext == u'png':
729 if ext == u'png':
729 format = self._FMT_PNG
730 format = self._FMT_PNG
730 else:
731 else:
731 format = ext.lower()
732 format = ext.lower()
732 elif isinstance(data, bytes):
733 elif isinstance(data, bytes):
733 # infer image type from image data header,
734 # infer image type from image data header,
734 # only if format has not been specified.
735 # only if format has not been specified.
735 if data[:2] == _JPEG:
736 if data[:2] == _JPEG:
736 format = self._FMT_JPEG
737 format = self._FMT_JPEG
737
738
738 # failed to detect format, default png
739 # failed to detect format, default png
739 if format is None:
740 if format is None:
740 format = 'png'
741 format = 'png'
741
742
742 if format.lower() == 'jpg':
743 if format.lower() == 'jpg':
743 # jpg->jpeg
744 # jpg->jpeg
744 format = self._FMT_JPEG
745 format = self._FMT_JPEG
745
746
746 self.format = unicode_type(format).lower()
747 self.format = unicode_type(format).lower()
747 self.embed = embed if embed is not None else (url is None)
748 self.embed = embed if embed is not None else (url is None)
748
749
749 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
750 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
750 raise ValueError("Cannot embed the '%s' image format" % (self.format))
751 raise ValueError("Cannot embed the '%s' image format" % (self.format))
751 self.width = width
752 self.width = width
752 self.height = height
753 self.height = height
753 self.retina = retina
754 self.retina = retina
754 self.unconfined = unconfined
755 self.unconfined = unconfined
755 self.metadata = metadata
756 self.metadata = metadata
756 super(Image, self).__init__(data=data, url=url, filename=filename)
757 super(Image, self).__init__(data=data, url=url, filename=filename)
757
758
758 if retina:
759 if retina:
759 self._retina_shape()
760 self._retina_shape()
760
761
761 def _retina_shape(self):
762 def _retina_shape(self):
762 """load pixel-doubled width and height from image data"""
763 """load pixel-doubled width and height from image data"""
763 if not self.embed:
764 if not self.embed:
764 return
765 return
765 if self.format == 'png':
766 if self.format == 'png':
766 w, h = _pngxy(self.data)
767 w, h = _pngxy(self.data)
767 elif self.format == 'jpeg':
768 elif self.format == 'jpeg':
768 w, h = _jpegxy(self.data)
769 w, h = _jpegxy(self.data)
769 else:
770 else:
770 # retina only supports png
771 # retina only supports png
771 return
772 return
772 self.width = w // 2
773 self.width = w // 2
773 self.height = h // 2
774 self.height = h // 2
774
775
775 def reload(self):
776 def reload(self):
776 """Reload the raw data from file or URL."""
777 """Reload the raw data from file or URL."""
777 if self.embed:
778 if self.embed:
778 super(Image,self).reload()
779 super(Image,self).reload()
779 if self.retina:
780 if self.retina:
780 self._retina_shape()
781 self._retina_shape()
781
782
782 def _repr_html_(self):
783 def _repr_html_(self):
783 if not self.embed:
784 if not self.embed:
784 width = height = klass = ''
785 width = height = klass = ''
785 if self.width:
786 if self.width:
786 width = ' width="%d"' % self.width
787 width = ' width="%d"' % self.width
787 if self.height:
788 if self.height:
788 height = ' height="%d"' % self.height
789 height = ' height="%d"' % self.height
789 if self.unconfined:
790 if self.unconfined:
790 klass = ' class="unconfined"'
791 klass = ' class="unconfined"'
791 return u'<img src="{url}"{width}{height}{klass}/>'.format(
792 return u'<img src="{url}"{width}{height}{klass}/>'.format(
792 url=self.url,
793 url=self.url,
793 width=width,
794 width=width,
794 height=height,
795 height=height,
795 klass=klass,
796 klass=klass,
796 )
797 )
797
798
798 def _data_and_metadata(self):
799 def _data_and_metadata(self):
799 """shortcut for returning metadata with shape information, if defined"""
800 """shortcut for returning metadata with shape information, if defined"""
800 md = {}
801 md = {}
801 if self.width:
802 if self.width:
802 md['width'] = self.width
803 md['width'] = self.width
803 if self.height:
804 if self.height:
804 md['height'] = self.height
805 md['height'] = self.height
805 if self.unconfined:
806 if self.unconfined:
806 md['unconfined'] = self.unconfined
807 md['unconfined'] = self.unconfined
807 if self.metadata:
808 if self.metadata:
808 md.update(self.metadata)
809 md.update(self.metadata)
809 if md:
810 if md:
810 return self.data, md
811 return self.data, md
811 else:
812 else:
812 return self.data
813 return self.data
813
814
814 def _repr_png_(self):
815 def _repr_png_(self):
815 if self.embed and self.format == u'png':
816 if self.embed and self.format == u'png':
816 return self._data_and_metadata()
817 return self._data_and_metadata()
817
818
818 def _repr_jpeg_(self):
819 def _repr_jpeg_(self):
819 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
820 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
820 return self._data_and_metadata()
821 return self._data_and_metadata()
821
822
822 def _find_ext(self, s):
823 def _find_ext(self, s):
823 return unicode_type(s.split('.')[-1].lower())
824 return unicode_type(s.split('.')[-1].lower())
824
825
825 class Video(DisplayObject):
826 class Video(DisplayObject):
826
827
827 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
828 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
828 """Create a video object given raw data or an URL.
829 """Create a video object given raw data or an URL.
829
830
830 When this object is returned by an input cell or passed to the
831 When this object is returned by an input cell or passed to the
831 display function, it will result in the video being displayed
832 display function, it will result in the video being displayed
832 in the frontend.
833 in the frontend.
833
834
834 Parameters
835 Parameters
835 ----------
836 ----------
836 data : unicode, str or bytes
837 data : unicode, str or bytes
837 The raw video data or a URL or filename to load the data from.
838 The raw video data or a URL or filename to load the data from.
838 Raw data will require passing `embed=True`.
839 Raw data will require passing `embed=True`.
839 url : unicode
840 url : unicode
840 A URL for the video. If you specify `url=`,
841 A URL for the video. If you specify `url=`,
841 the image data will not be embedded.
842 the image data will not be embedded.
842 filename : unicode
843 filename : unicode
843 Path to a local file containing the video.
844 Path to a local file containing the video.
844 Will be interpreted as a local URL unless `embed=True`.
845 Will be interpreted as a local URL unless `embed=True`.
845 embed : bool
846 embed : bool
846 Should the video be embedded using a data URI (True) or be
847 Should the video be embedded using a data URI (True) or be
847 loaded using a <video> tag (False).
848 loaded using a <video> tag (False).
848
849
849 Since videos are large, embedding them should be avoided, if possible.
850 Since videos are large, embedding them should be avoided, if possible.
850 You must confirm embedding as your intention by passing `embed=True`.
851 You must confirm embedding as your intention by passing `embed=True`.
851
852
852 Local files can be displayed with URLs without embedding the content, via::
853 Local files can be displayed with URLs without embedding the content, via::
853
854
854 Video('./video.mp4')
855 Video('./video.mp4')
855
856
856 mimetype: unicode
857 mimetype: unicode
857 Specify the mimetype for embedded videos.
858 Specify the mimetype for embedded videos.
858 Default will be guessed from file extension, if available.
859 Default will be guessed from file extension, if available.
859
860
860 Examples
861 Examples
861 --------
862 --------
862
863
863 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
864 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
864 Video('path/to/video.mp4')
865 Video('path/to/video.mp4')
865 Video('path/to/video.mp4', embed=True)
866 Video('path/to/video.mp4', embed=True)
866 Video(b'raw-videodata', embed=True)
867 Video(b'raw-videodata', embed=True)
867 """
868 """
868 if url is None and isinstance(data, string_types) and data.startswith(('http:', 'https:')):
869 if url is None and isinstance(data, string_types) and data.startswith(('http:', 'https:')):
869 url = data
870 url = data
870 data = None
871 data = None
871 elif os.path.exists(data):
872 elif os.path.exists(data):
872 filename = data
873 filename = data
873 data = None
874 data = None
874
875
875 if data and not embed:
876 if data and not embed:
876 msg = ''.join([
877 msg = ''.join([
877 "To embed videos, you must pass embed=True ",
878 "To embed videos, you must pass embed=True ",
878 "(this may make your notebook files huge)\n",
879 "(this may make your notebook files huge)\n",
879 "Consider passing Video(url='...')",
880 "Consider passing Video(url='...')",
880 ])
881 ])
881 raise ValueError(msg)
882 raise ValueError(msg)
882
883
883 self.mimetype = mimetype
884 self.mimetype = mimetype
884 self.embed = embed
885 self.embed = embed
885 super(Video, self).__init__(data=data, url=url, filename=filename)
886 super(Video, self).__init__(data=data, url=url, filename=filename)
886
887
887 def _repr_html_(self):
888 def _repr_html_(self):
888 # External URLs and potentially local files are not embedded into the
889 # External URLs and potentially local files are not embedded into the
889 # notebook output.
890 # notebook output.
890 if not self.embed:
891 if not self.embed:
891 url = self.url if self.url is not None else self.filename
892 url = self.url if self.url is not None else self.filename
892 output = """<video src="{0}" controls>
893 output = """<video src="{0}" controls>
893 Your browser does not support the <code>video</code> element.
894 Your browser does not support the <code>video</code> element.
894 </video>""".format(url)
895 </video>""".format(url)
895 return output
896 return output
896
897
897 # Embedded videos are base64-encoded.
898 # Embedded videos are base64-encoded.
898 mimetype = self.mimetype
899 mimetype = self.mimetype
899 if self.filename is not None:
900 if self.filename is not None:
900 if not mimetype:
901 if not mimetype:
901 mimetype, _ = mimetypes.guess_type(self.filename)
902 mimetype, _ = mimetypes.guess_type(self.filename)
902
903
903 with open(self.filename, 'rb') as f:
904 with open(self.filename, 'rb') as f:
904 video = f.read()
905 video = f.read()
905 else:
906 else:
906 video = self.data
907 video = self.data
907 if isinstance(video, unicode_type):
908 if isinstance(video, unicode_type):
908 # unicode input is already b64-encoded
909 # unicode input is already b64-encoded
909 b64_video = video
910 b64_video = video
910 else:
911 else:
911 b64_video = base64_encode(video).decode('ascii').rstrip()
912 b64_video = base64_encode(video).decode('ascii').rstrip()
912
913
913 output = """<video controls>
914 output = """<video controls>
914 <source src="data:{0};base64,{1}" type="{0}">
915 <source src="data:{0};base64,{1}" type="{0}">
915 Your browser does not support the video tag.
916 Your browser does not support the video tag.
916 </video>""".format(mimetype, b64_video)
917 </video>""".format(mimetype, b64_video)
917 return output
918 return output
918
919
919 def reload(self):
920 def reload(self):
920 # TODO
921 # TODO
921 pass
922 pass
922
923
923 def _repr_png_(self):
924 def _repr_png_(self):
924 # TODO
925 # TODO
925 pass
926 pass
926 def _repr_jpeg_(self):
927 def _repr_jpeg_(self):
927 # TODO
928 # TODO
928 pass
929 pass
929
930
930 def clear_output(wait=False):
931 def clear_output(wait=False):
931 """Clear the output of the current cell receiving output.
932 """Clear the output of the current cell receiving output.
932
933
933 Parameters
934 Parameters
934 ----------
935 ----------
935 wait : bool [default: false]
936 wait : bool [default: false]
936 Wait to clear the output until new output is available to replace it."""
937 Wait to clear the output until new output is available to replace it."""
937 from IPython.core.interactiveshell import InteractiveShell
938 from IPython.core.interactiveshell import InteractiveShell
938 if InteractiveShell.initialized():
939 if InteractiveShell.initialized():
939 InteractiveShell.instance().display_pub.clear_output(wait)
940 InteractiveShell.instance().display_pub.clear_output(wait)
940 else:
941 else:
941 from IPython.utils import io
942 print('\033[2K\r', end='')
942 print('\033[2K\r', file=io.stdout, end='')
943 sys.stdout.flush()
943 io.stdout.flush()
944 print('\033[2K\r', end='')
944 print('\033[2K\r', file=io.stderr, end='')
945 sys.stderr.flush()
945 io.stderr.flush()
946
946
947
947
948 @skip_doctest
948 @skip_doctest
949 def set_matplotlib_formats(*formats, **kwargs):
949 def set_matplotlib_formats(*formats, **kwargs):
950 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
950 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
951
951
952 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
952 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
953
953
954 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
954 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
955
955
956 To set this in your config files use the following::
956 To set this in your config files use the following::
957
957
958 c.InlineBackend.figure_formats = {'png', 'jpeg'}
958 c.InlineBackend.figure_formats = {'png', 'jpeg'}
959 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
959 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
960
960
961 Parameters
961 Parameters
962 ----------
962 ----------
963 *formats : strs
963 *formats : strs
964 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
964 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
965 **kwargs :
965 **kwargs :
966 Keyword args will be relayed to ``figure.canvas.print_figure``.
966 Keyword args will be relayed to ``figure.canvas.print_figure``.
967 """
967 """
968 from IPython.core.interactiveshell import InteractiveShell
968 from IPython.core.interactiveshell import InteractiveShell
969 from IPython.core.pylabtools import select_figure_formats
969 from IPython.core.pylabtools import select_figure_formats
970 # build kwargs, starting with InlineBackend config
970 # build kwargs, starting with InlineBackend config
971 kw = {}
971 kw = {}
972 from ipykernel.pylab.config import InlineBackend
972 from ipykernel.pylab.config import InlineBackend
973 cfg = InlineBackend.instance()
973 cfg = InlineBackend.instance()
974 kw.update(cfg.print_figure_kwargs)
974 kw.update(cfg.print_figure_kwargs)
975 kw.update(**kwargs)
975 kw.update(**kwargs)
976 shell = InteractiveShell.instance()
976 shell = InteractiveShell.instance()
977 select_figure_formats(shell, formats, **kw)
977 select_figure_formats(shell, formats, **kw)
978
978
979 @skip_doctest
979 @skip_doctest
980 def set_matplotlib_close(close=True):
980 def set_matplotlib_close(close=True):
981 """Set whether the inline backend closes all figures automatically or not.
981 """Set whether the inline backend closes all figures automatically or not.
982
982
983 By default, the inline backend used in the IPython Notebook will close all
983 By default, the inline backend used in the IPython Notebook will close all
984 matplotlib figures automatically after each cell is run. This means that
984 matplotlib figures automatically after each cell is run. This means that
985 plots in different cells won't interfere. Sometimes, you may want to make
985 plots in different cells won't interfere. Sometimes, you may want to make
986 a plot in one cell and then refine it in later cells. This can be accomplished
986 a plot in one cell and then refine it in later cells. This can be accomplished
987 by::
987 by::
988
988
989 In [1]: set_matplotlib_close(False)
989 In [1]: set_matplotlib_close(False)
990
990
991 To set this in your config files use the following::
991 To set this in your config files use the following::
992
992
993 c.InlineBackend.close_figures = False
993 c.InlineBackend.close_figures = False
994
994
995 Parameters
995 Parameters
996 ----------
996 ----------
997 close : bool
997 close : bool
998 Should all matplotlib figures be automatically closed after each cell is
998 Should all matplotlib figures be automatically closed after each cell is
999 run?
999 run?
1000 """
1000 """
1001 from ipykernel.pylab.config import InlineBackend
1001 from ipykernel.pylab.config import InlineBackend
1002 cfg = InlineBackend.instance()
1002 cfg = InlineBackend.instance()
1003 cfg.close_figures = close
1003 cfg.close_figures = close
1004
1004
@@ -1,294 +1,293 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Displayhook for IPython.
2 """Displayhook for IPython.
3
3
4 This defines a callable class that IPython uses for `sys.displayhook`.
4 This defines a callable class that IPython uses for `sys.displayhook`.
5 """
5 """
6
6
7 # Copyright (c) IPython Development Team.
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9
9
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 import sys
12 import sys
13 import io as _io
13 import io as _io
14 import tokenize
14 import tokenize
15
15
16 from traitlets.config.configurable import Configurable
16 from traitlets.config.configurable import Configurable
17 from IPython.utils import io
18 from IPython.utils.py3compat import builtin_mod, cast_unicode_py2
17 from IPython.utils.py3compat import builtin_mod, cast_unicode_py2
19 from traitlets import Instance, Float
18 from traitlets import Instance, Float
20 from warnings import warn
19 from warnings import warn
21
20
22 # TODO: Move the various attributes (cache_size, [others now moved]). Some
21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
23 # of these are also attributes of InteractiveShell. They should be on ONE object
22 # of these are also attributes of InteractiveShell. They should be on ONE object
24 # only and the other objects should ask that one object for their values.
23 # only and the other objects should ask that one object for their values.
25
24
26 class DisplayHook(Configurable):
25 class DisplayHook(Configurable):
27 """The custom IPython displayhook to replace sys.displayhook.
26 """The custom IPython displayhook to replace sys.displayhook.
28
27
29 This class does many things, but the basic idea is that it is a callable
28 This class does many things, but the basic idea is that it is a callable
30 that gets called anytime user code returns a value.
29 that gets called anytime user code returns a value.
31 """
30 """
32
31
33 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
34 allow_none=True)
33 allow_none=True)
35 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
34 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
36 allow_none=True)
35 allow_none=True)
37 cull_fraction = Float(0.2)
36 cull_fraction = Float(0.2)
38
37
39 def __init__(self, shell=None, cache_size=1000, **kwargs):
38 def __init__(self, shell=None, cache_size=1000, **kwargs):
40 super(DisplayHook, self).__init__(shell=shell, **kwargs)
39 super(DisplayHook, self).__init__(shell=shell, **kwargs)
41 cache_size_min = 3
40 cache_size_min = 3
42 if cache_size <= 0:
41 if cache_size <= 0:
43 self.do_full_cache = 0
42 self.do_full_cache = 0
44 cache_size = 0
43 cache_size = 0
45 elif cache_size < cache_size_min:
44 elif cache_size < cache_size_min:
46 self.do_full_cache = 0
45 self.do_full_cache = 0
47 cache_size = 0
46 cache_size = 0
48 warn('caching was disabled (min value for cache size is %s).' %
47 warn('caching was disabled (min value for cache size is %s).' %
49 cache_size_min,level=3)
48 cache_size_min,level=3)
50 else:
49 else:
51 self.do_full_cache = 1
50 self.do_full_cache = 1
52
51
53 self.cache_size = cache_size
52 self.cache_size = cache_size
54
53
55 # we need a reference to the user-level namespace
54 # we need a reference to the user-level namespace
56 self.shell = shell
55 self.shell = shell
57
56
58 self._,self.__,self.___ = '','',''
57 self._,self.__,self.___ = '','',''
59
58
60 # these are deliberately global:
59 # these are deliberately global:
61 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
60 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
62 self.shell.user_ns.update(to_user_ns)
61 self.shell.user_ns.update(to_user_ns)
63
62
64 @property
63 @property
65 def prompt_count(self):
64 def prompt_count(self):
66 return self.shell.execution_count
65 return self.shell.execution_count
67
66
68 #-------------------------------------------------------------------------
67 #-------------------------------------------------------------------------
69 # Methods used in __call__. Override these methods to modify the behavior
68 # Methods used in __call__. Override these methods to modify the behavior
70 # of the displayhook.
69 # of the displayhook.
71 #-------------------------------------------------------------------------
70 #-------------------------------------------------------------------------
72
71
73 def check_for_underscore(self):
72 def check_for_underscore(self):
74 """Check if the user has set the '_' variable by hand."""
73 """Check if the user has set the '_' variable by hand."""
75 # If something injected a '_' variable in __builtin__, delete
74 # If something injected a '_' variable in __builtin__, delete
76 # ipython's automatic one so we don't clobber that. gettext() in
75 # ipython's automatic one so we don't clobber that. gettext() in
77 # particular uses _, so we need to stay away from it.
76 # particular uses _, so we need to stay away from it.
78 if '_' in builtin_mod.__dict__:
77 if '_' in builtin_mod.__dict__:
79 try:
78 try:
80 del self.shell.user_ns['_']
79 del self.shell.user_ns['_']
81 except KeyError:
80 except KeyError:
82 pass
81 pass
83
82
84 def quiet(self):
83 def quiet(self):
85 """Should we silence the display hook because of ';'?"""
84 """Should we silence the display hook because of ';'?"""
86 # do not print output if input ends in ';'
85 # do not print output if input ends in ';'
87
86
88 try:
87 try:
89 cell = cast_unicode_py2(self.shell.history_manager.input_hist_parsed[-1])
88 cell = cast_unicode_py2(self.shell.history_manager.input_hist_parsed[-1])
90 except IndexError:
89 except IndexError:
91 # some uses of ipshellembed may fail here
90 # some uses of ipshellembed may fail here
92 return False
91 return False
93
92
94 sio = _io.StringIO(cell)
93 sio = _io.StringIO(cell)
95 tokens = list(tokenize.generate_tokens(sio.readline))
94 tokens = list(tokenize.generate_tokens(sio.readline))
96
95
97 for token in reversed(tokens):
96 for token in reversed(tokens):
98 if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
97 if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
99 continue
98 continue
100 if (token[0] == tokenize.OP) and (token[1] == ';'):
99 if (token[0] == tokenize.OP) and (token[1] == ';'):
101 return True
100 return True
102 else:
101 else:
103 return False
102 return False
104
103
105 def start_displayhook(self):
104 def start_displayhook(self):
106 """Start the displayhook, initializing resources."""
105 """Start the displayhook, initializing resources."""
107 pass
106 pass
108
107
109 def write_output_prompt(self):
108 def write_output_prompt(self):
110 """Write the output prompt.
109 """Write the output prompt.
111
110
112 The default implementation simply writes the prompt to
111 The default implementation simply writes the prompt to
113 ``io.stdout``.
112 ``io.stdout``.
114 """
113 """
115 # Use write, not print which adds an extra space.
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 outprompt = self.shell.prompt_manager.render('out')
116 outprompt = self.shell.prompt_manager.render('out')
118 if self.do_full_cache:
117 if self.do_full_cache:
119 io.stdout.write(outprompt)
118 sys.stdout.write(outprompt)
120
119
121 def compute_format_data(self, result):
120 def compute_format_data(self, result):
122 """Compute format data of the object to be displayed.
121 """Compute format data of the object to be displayed.
123
122
124 The format data is a generalization of the :func:`repr` of an object.
123 The format data is a generalization of the :func:`repr` of an object.
125 In the default implementation the format data is a :class:`dict` of
124 In the default implementation the format data is a :class:`dict` of
126 key value pair where the keys are valid MIME types and the values
125 key value pair where the keys are valid MIME types and the values
127 are JSON'able data structure containing the raw data for that MIME
126 are JSON'able data structure containing the raw data for that MIME
128 type. It is up to frontends to determine pick a MIME to to use and
127 type. It is up to frontends to determine pick a MIME to to use and
129 display that data in an appropriate manner.
128 display that data in an appropriate manner.
130
129
131 This method only computes the format data for the object and should
130 This method only computes the format data for the object and should
132 NOT actually print or write that to a stream.
131 NOT actually print or write that to a stream.
133
132
134 Parameters
133 Parameters
135 ----------
134 ----------
136 result : object
135 result : object
137 The Python object passed to the display hook, whose format will be
136 The Python object passed to the display hook, whose format will be
138 computed.
137 computed.
139
138
140 Returns
139 Returns
141 -------
140 -------
142 (format_dict, md_dict) : dict
141 (format_dict, md_dict) : dict
143 format_dict is a :class:`dict` whose keys are valid MIME types and values are
142 format_dict is a :class:`dict` whose keys are valid MIME types and values are
144 JSON'able raw data for that MIME type. It is recommended that
143 JSON'able raw data for that MIME type. It is recommended that
145 all return values of this should always include the "text/plain"
144 all return values of this should always include the "text/plain"
146 MIME type representation of the object.
145 MIME type representation of the object.
147 md_dict is a :class:`dict` with the same MIME type keys
146 md_dict is a :class:`dict` with the same MIME type keys
148 of metadata associated with each output.
147 of metadata associated with each output.
149
148
150 """
149 """
151 return self.shell.display_formatter.format(result)
150 return self.shell.display_formatter.format(result)
152
151
153 def write_format_data(self, format_dict, md_dict=None):
152 def write_format_data(self, format_dict, md_dict=None):
154 """Write the format data dict to the frontend.
153 """Write the format data dict to the frontend.
155
154
156 This default version of this method simply writes the plain text
155 This default version of this method simply writes the plain text
157 representation of the object to ``io.stdout``. Subclasses should
156 representation of the object to ``io.stdout``. Subclasses should
158 override this method to send the entire `format_dict` to the
157 override this method to send the entire `format_dict` to the
159 frontends.
158 frontends.
160
159
161 Parameters
160 Parameters
162 ----------
161 ----------
163 format_dict : dict
162 format_dict : dict
164 The format dict for the object passed to `sys.displayhook`.
163 The format dict for the object passed to `sys.displayhook`.
165 md_dict : dict (optional)
164 md_dict : dict (optional)
166 The metadata dict to be associated with the display data.
165 The metadata dict to be associated with the display data.
167 """
166 """
168 if 'text/plain' not in format_dict:
167 if 'text/plain' not in format_dict:
169 # nothing to do
168 # nothing to do
170 return
169 return
171 # We want to print because we want to always make sure we have a
170 # We want to print because we want to always make sure we have a
172 # newline, even if all the prompt separators are ''. This is the
171 # newline, even if all the prompt separators are ''. This is the
173 # standard IPython behavior.
172 # standard IPython behavior.
174 result_repr = format_dict['text/plain']
173 result_repr = format_dict['text/plain']
175 if '\n' in result_repr:
174 if '\n' in result_repr:
176 # So that multi-line strings line up with the left column of
175 # So that multi-line strings line up with the left column of
177 # the screen, instead of having the output prompt mess up
176 # the screen, instead of having the output prompt mess up
178 # their first line.
177 # their first line.
179 # We use the prompt template instead of the expanded prompt
178 # We use the prompt template instead of the expanded prompt
180 # because the expansion may add ANSI escapes that will interfere
179 # because the expansion may add ANSI escapes that will interfere
181 # with our ability to determine whether or not we should add
180 # with our ability to determine whether or not we should add
182 # a newline.
181 # a newline.
183 prompt_template = self.shell.prompt_manager.out_template
182 prompt_template = self.shell.prompt_manager.out_template
184 if prompt_template and not prompt_template.endswith('\n'):
183 if prompt_template and not prompt_template.endswith('\n'):
185 # But avoid extraneous empty lines.
184 # But avoid extraneous empty lines.
186 result_repr = '\n' + result_repr
185 result_repr = '\n' + result_repr
187
186
188 print(result_repr, file=io.stdout)
187 print(result_repr)
189
188
190 def update_user_ns(self, result):
189 def update_user_ns(self, result):
191 """Update user_ns with various things like _, __, _1, etc."""
190 """Update user_ns with various things like _, __, _1, etc."""
192
191
193 # Avoid recursive reference when displaying _oh/Out
192 # Avoid recursive reference when displaying _oh/Out
194 if result is not self.shell.user_ns['_oh']:
193 if result is not self.shell.user_ns['_oh']:
195 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
194 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
196 self.cull_cache()
195 self.cull_cache()
197 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
196 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
198 # we cause buggy behavior for things like gettext).
197 # we cause buggy behavior for things like gettext).
199
198
200 if '_' not in builtin_mod.__dict__:
199 if '_' not in builtin_mod.__dict__:
201 self.___ = self.__
200 self.___ = self.__
202 self.__ = self._
201 self.__ = self._
203 self._ = result
202 self._ = result
204 self.shell.push({'_':self._,
203 self.shell.push({'_':self._,
205 '__':self.__,
204 '__':self.__,
206 '___':self.___}, interactive=False)
205 '___':self.___}, interactive=False)
207
206
208 # hackish access to top-level namespace to create _1,_2... dynamically
207 # hackish access to top-level namespace to create _1,_2... dynamically
209 to_main = {}
208 to_main = {}
210 if self.do_full_cache:
209 if self.do_full_cache:
211 new_result = '_'+repr(self.prompt_count)
210 new_result = '_'+repr(self.prompt_count)
212 to_main[new_result] = result
211 to_main[new_result] = result
213 self.shell.push(to_main, interactive=False)
212 self.shell.push(to_main, interactive=False)
214 self.shell.user_ns['_oh'][self.prompt_count] = result
213 self.shell.user_ns['_oh'][self.prompt_count] = result
215
214
216 def fill_exec_result(self, result):
215 def fill_exec_result(self, result):
217 if self.exec_result is not None:
216 if self.exec_result is not None:
218 self.exec_result.result = result
217 self.exec_result.result = result
219
218
220 def log_output(self, format_dict):
219 def log_output(self, format_dict):
221 """Log the output."""
220 """Log the output."""
222 if 'text/plain' not in format_dict:
221 if 'text/plain' not in format_dict:
223 # nothing to do
222 # nothing to do
224 return
223 return
225 if self.shell.logger.log_output:
224 if self.shell.logger.log_output:
226 self.shell.logger.log_write(format_dict['text/plain'], 'output')
225 self.shell.logger.log_write(format_dict['text/plain'], 'output')
227 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
226 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
228 format_dict['text/plain']
227 format_dict['text/plain']
229
228
230 def finish_displayhook(self):
229 def finish_displayhook(self):
231 """Finish up all displayhook activities."""
230 """Finish up all displayhook activities."""
232 io.stdout.write(self.shell.separate_out2)
231 sys.stdout.write(self.shell.separate_out2)
233 io.stdout.flush()
232 sys.stdout.flush()
234
233
235 def __call__(self, result=None):
234 def __call__(self, result=None):
236 """Printing with history cache management.
235 """Printing with history cache management.
237
236
238 This is invoked everytime the interpreter needs to print, and is
237 This is invoked everytime the interpreter needs to print, and is
239 activated by setting the variable sys.displayhook to it.
238 activated by setting the variable sys.displayhook to it.
240 """
239 """
241 self.check_for_underscore()
240 self.check_for_underscore()
242 if result is not None and not self.quiet():
241 if result is not None and not self.quiet():
243 self.start_displayhook()
242 self.start_displayhook()
244 self.write_output_prompt()
243 self.write_output_prompt()
245 format_dict, md_dict = self.compute_format_data(result)
244 format_dict, md_dict = self.compute_format_data(result)
246 self.update_user_ns(result)
245 self.update_user_ns(result)
247 self.fill_exec_result(result)
246 self.fill_exec_result(result)
248 if format_dict:
247 if format_dict:
249 self.write_format_data(format_dict, md_dict)
248 self.write_format_data(format_dict, md_dict)
250 self.log_output(format_dict)
249 self.log_output(format_dict)
251 self.finish_displayhook()
250 self.finish_displayhook()
252
251
253 def cull_cache(self):
252 def cull_cache(self):
254 """Output cache is full, cull the oldest entries"""
253 """Output cache is full, cull the oldest entries"""
255 oh = self.shell.user_ns.get('_oh', {})
254 oh = self.shell.user_ns.get('_oh', {})
256 sz = len(oh)
255 sz = len(oh)
257 cull_count = max(int(sz * self.cull_fraction), 2)
256 cull_count = max(int(sz * self.cull_fraction), 2)
258 warn('Output cache limit (currently {sz} entries) hit.\n'
257 warn('Output cache limit (currently {sz} entries) hit.\n'
259 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
258 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
260
259
261 for i, n in enumerate(sorted(oh)):
260 for i, n in enumerate(sorted(oh)):
262 if i >= cull_count:
261 if i >= cull_count:
263 break
262 break
264 self.shell.user_ns.pop('_%i' % n, None)
263 self.shell.user_ns.pop('_%i' % n, None)
265 oh.pop(n, None)
264 oh.pop(n, None)
266
265
267
266
268 def flush(self):
267 def flush(self):
269 if not self.do_full_cache:
268 if not self.do_full_cache:
270 raise ValueError("You shouldn't have reached the cache flush "
269 raise ValueError("You shouldn't have reached the cache flush "
271 "if full caching is not enabled!")
270 "if full caching is not enabled!")
272 # delete auto-generated vars from global namespace
271 # delete auto-generated vars from global namespace
273
272
274 for n in range(1,self.prompt_count + 1):
273 for n in range(1,self.prompt_count + 1):
275 key = '_'+repr(n)
274 key = '_'+repr(n)
276 try:
275 try:
277 del self.shell.user_ns[key]
276 del self.shell.user_ns[key]
278 except: pass
277 except: pass
279 # In some embedded circumstances, the user_ns doesn't have the
278 # In some embedded circumstances, the user_ns doesn't have the
280 # '_oh' key set up.
279 # '_oh' key set up.
281 oh = self.shell.user_ns.get('_oh', None)
280 oh = self.shell.user_ns.get('_oh', None)
282 if oh is not None:
281 if oh is not None:
283 oh.clear()
282 oh.clear()
284
283
285 # Release our own references to objects:
284 # Release our own references to objects:
286 self._, self.__, self.___ = '', '', ''
285 self._, self.__, self.___ = '', '', ''
287
286
288 if '_' not in builtin_mod.__dict__:
287 if '_' not in builtin_mod.__dict__:
289 self.shell.user_ns.update({'_':None,'__':None, '___':None})
288 self.shell.user_ns.update({'_':None,'__':None, '___':None})
290 import gc
289 import gc
291 # TODO: Is this really needed?
290 # TODO: Is this really needed?
292 # IronPython blocks here forever
291 # IronPython blocks here forever
293 if sys.platform != "cli":
292 if sys.platform != "cli":
294 gc.collect()
293 gc.collect()
@@ -1,116 +1,117 b''
1 """An interface for publishing rich data to frontends.
1 """An interface for publishing rich data to frontends.
2
2
3 There are two components of the display system:
3 There are two components of the display system:
4
4
5 * Display formatters, which take a Python object and compute the
5 * Display formatters, which take a Python object and compute the
6 representation of the object in various formats (text, HTML, SVG, etc.).
6 representation of the object in various formats (text, HTML, SVG, etc.).
7 * The display publisher that is used to send the representation data to the
7 * The display publisher that is used to send the representation data to the
8 various frontends.
8 various frontends.
9
9
10 This module defines the logic display publishing. The display publisher uses
10 This module defines the logic display publishing. The display publisher uses
11 the ``display_data`` message type that is defined in the IPython messaging
11 the ``display_data`` message type that is defined in the IPython messaging
12 spec.
12 spec.
13 """
13 """
14
14
15 # Copyright (c) IPython Development Team.
15 # Copyright (c) IPython Development Team.
16 # Distributed under the terms of the Modified BSD License.
16 # Distributed under the terms of the Modified BSD License.
17
17
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import sys
21
20 from traitlets.config.configurable import Configurable
22 from traitlets.config.configurable import Configurable
21 from IPython.utils import io
22 from traitlets import List
23 from traitlets import List
23
24
24 # This used to be defined here - it is imported for backwards compatibility
25 # This used to be defined here - it is imported for backwards compatibility
25 from .display import publish_display_data
26 from .display import publish_display_data
26
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Main payload class
29 # Main payload class
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30
31
31 class DisplayPublisher(Configurable):
32 class DisplayPublisher(Configurable):
32 """A traited class that publishes display data to frontends.
33 """A traited class that publishes display data to frontends.
33
34
34 Instances of this class are created by the main IPython object and should
35 Instances of this class are created by the main IPython object and should
35 be accessed there.
36 be accessed there.
36 """
37 """
37
38
38 def _validate_data(self, data, metadata=None):
39 def _validate_data(self, data, metadata=None):
39 """Validate the display data.
40 """Validate the display data.
40
41
41 Parameters
42 Parameters
42 ----------
43 ----------
43 data : dict
44 data : dict
44 The formata data dictionary.
45 The formata data dictionary.
45 metadata : dict
46 metadata : dict
46 Any metadata for the data.
47 Any metadata for the data.
47 """
48 """
48
49
49 if not isinstance(data, dict):
50 if not isinstance(data, dict):
50 raise TypeError('data must be a dict, got: %r' % data)
51 raise TypeError('data must be a dict, got: %r' % data)
51 if metadata is not None:
52 if metadata is not None:
52 if not isinstance(metadata, dict):
53 if not isinstance(metadata, dict):
53 raise TypeError('metadata must be a dict, got: %r' % data)
54 raise TypeError('metadata must be a dict, got: %r' % data)
54
55
55 def publish(self, data, metadata=None, source=None):
56 def publish(self, data, metadata=None, source=None):
56 """Publish data and metadata to all frontends.
57 """Publish data and metadata to all frontends.
57
58
58 See the ``display_data`` message in the messaging documentation for
59 See the ``display_data`` message in the messaging documentation for
59 more details about this message type.
60 more details about this message type.
60
61
61 The following MIME types are currently implemented:
62 The following MIME types are currently implemented:
62
63
63 * text/plain
64 * text/plain
64 * text/html
65 * text/html
65 * text/markdown
66 * text/markdown
66 * text/latex
67 * text/latex
67 * application/json
68 * application/json
68 * application/javascript
69 * application/javascript
69 * image/png
70 * image/png
70 * image/jpeg
71 * image/jpeg
71 * image/svg+xml
72 * image/svg+xml
72
73
73 Parameters
74 Parameters
74 ----------
75 ----------
75 data : dict
76 data : dict
76 A dictionary having keys that are valid MIME types (like
77 A dictionary having keys that are valid MIME types (like
77 'text/plain' or 'image/svg+xml') and values that are the data for
78 'text/plain' or 'image/svg+xml') and values that are the data for
78 that MIME type. The data itself must be a JSON'able data
79 that MIME type. The data itself must be a JSON'able data
79 structure. Minimally all data should have the 'text/plain' data,
80 structure. Minimally all data should have the 'text/plain' data,
80 which can be displayed by all frontends. If more than the plain
81 which can be displayed by all frontends. If more than the plain
81 text is given, it is up to the frontend to decide which
82 text is given, it is up to the frontend to decide which
82 representation to use.
83 representation to use.
83 metadata : dict
84 metadata : dict
84 A dictionary for metadata related to the data. This can contain
85 A dictionary for metadata related to the data. This can contain
85 arbitrary key, value pairs that frontends can use to interpret
86 arbitrary key, value pairs that frontends can use to interpret
86 the data. Metadata specific to each mime-type can be specified
87 the data. Metadata specific to each mime-type can be specified
87 in the metadata dict with the same mime-type keys as
88 in the metadata dict with the same mime-type keys as
88 the data itself.
89 the data itself.
89 source : str, deprecated
90 source : str, deprecated
90 Unused.
91 Unused.
91 """
92 """
92
93
93 # The default is to simply write the plain text data using io.stdout.
94 # The default is to simply write the plain text data using io.stdout.
94 if 'text/plain' in data:
95 if 'text/plain' in data:
95 print(data['text/plain'], file=io.stdout)
96 print(data['text/plain'])
96
97
97 def clear_output(self, wait=False):
98 def clear_output(self, wait=False):
98 """Clear the output of the cell receiving output."""
99 """Clear the output of the cell receiving output."""
99 print('\033[2K\r', file=io.stdout, end='')
100 print('\033[2K\r', end='')
100 io.stdout.flush()
101 sys.stdout.flush()
101 print('\033[2K\r', file=io.stderr, end='')
102 print('\033[2K\r', end='')
102 io.stderr.flush()
103 sys.stderr.flush()
103
104
104
105
105 class CapturingDisplayPublisher(DisplayPublisher):
106 class CapturingDisplayPublisher(DisplayPublisher):
106 """A DisplayPublisher that stores"""
107 """A DisplayPublisher that stores"""
107 outputs = List()
108 outputs = List()
108
109
109 def publish(self, data, metadata=None, source=None):
110 def publish(self, data, metadata=None, source=None):
110 self.outputs.append((data, metadata))
111 self.outputs.append((data, metadata))
111
112
112 def clear_output(self, wait=False):
113 def clear_output(self, wait=False):
113 super(CapturingDisplayPublisher, self).clear_output(wait)
114 super(CapturingDisplayPublisher, self).clear_output(wait)
114
115
115 # empty the list, *do not* reassign a new list
116 # empty the list, *do not* reassign a new list
116 del self.outputs[:]
117 del self.outputs[:]
1 NO CONTENT: modified file
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 """Implementation of magic functions related to History.
1 """Implementation of magic functions related to History.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012, IPython Development Team.
4 # Copyright (c) 2012, IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib
16 # Stdlib
17 import os
17 import os
18 import sys
18 from io import open as io_open
19 from io import open as io_open
19
20
20 # Our own packages
21 # Our own packages
21 from IPython.core.error import StdinNotImplementedError
22 from IPython.core.error import StdinNotImplementedError
22 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic_arguments import (argument, magic_arguments,
24 from IPython.core.magic_arguments import (argument, magic_arguments,
24 parse_argstring)
25 parse_argstring)
25 from IPython.testing.skipdoctest import skip_doctest
26 from IPython.testing.skipdoctest import skip_doctest
26 from IPython.utils import io
27 from IPython.utils import io
27 from IPython.utils.py3compat import cast_unicode_py2
28 from IPython.utils.py3compat import cast_unicode_py2
28
29
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30 # Magics class implementation
31 # Magics class implementation
31 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
32
33
33
34
34 _unspecified = object()
35 _unspecified = object()
35
36
36
37
37 @magics_class
38 @magics_class
38 class HistoryMagics(Magics):
39 class HistoryMagics(Magics):
39
40
40 @magic_arguments()
41 @magic_arguments()
41 @argument(
42 @argument(
42 '-n', dest='print_nums', action='store_true', default=False,
43 '-n', dest='print_nums', action='store_true', default=False,
43 help="""
44 help="""
44 print line numbers for each input.
45 print line numbers for each input.
45 This feature is only available if numbered prompts are in use.
46 This feature is only available if numbered prompts are in use.
46 """)
47 """)
47 @argument(
48 @argument(
48 '-o', dest='get_output', action='store_true', default=False,
49 '-o', dest='get_output', action='store_true', default=False,
49 help="also print outputs for each input.")
50 help="also print outputs for each input.")
50 @argument(
51 @argument(
51 '-p', dest='pyprompts', action='store_true', default=False,
52 '-p', dest='pyprompts', action='store_true', default=False,
52 help="""
53 help="""
53 print classic '>>>' python prompts before each input.
54 print classic '>>>' python prompts before each input.
54 This is useful for making documentation, and in conjunction
55 This is useful for making documentation, and in conjunction
55 with -o, for producing doctest-ready output.
56 with -o, for producing doctest-ready output.
56 """)
57 """)
57 @argument(
58 @argument(
58 '-t', dest='raw', action='store_false', default=True,
59 '-t', dest='raw', action='store_false', default=True,
59 help="""
60 help="""
60 print the 'translated' history, as IPython understands it.
61 print the 'translated' history, as IPython understands it.
61 IPython filters your input and converts it all into valid Python
62 IPython filters your input and converts it all into valid Python
62 source before executing it (things like magics or aliases are turned
63 source before executing it (things like magics or aliases are turned
63 into function calls, for example). With this option, you'll see the
64 into function calls, for example). With this option, you'll see the
64 native history instead of the user-entered version: '%%cd /' will be
65 native history instead of the user-entered version: '%%cd /' will be
65 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
66 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
66 """)
67 """)
67 @argument(
68 @argument(
68 '-f', dest='filename',
69 '-f', dest='filename',
69 help="""
70 help="""
70 FILENAME: instead of printing the output to the screen, redirect
71 FILENAME: instead of printing the output to the screen, redirect
71 it to the given file. The file is always overwritten, though *when
72 it to the given file. The file is always overwritten, though *when
72 it can*, IPython asks for confirmation first. In particular, running
73 it can*, IPython asks for confirmation first. In particular, running
73 the command 'history -f FILENAME' from the IPython Notebook
74 the command 'history -f FILENAME' from the IPython Notebook
74 interface will replace FILENAME even if it already exists *without*
75 interface will replace FILENAME even if it already exists *without*
75 confirmation.
76 confirmation.
76 """)
77 """)
77 @argument(
78 @argument(
78 '-g', dest='pattern', nargs='*', default=None,
79 '-g', dest='pattern', nargs='*', default=None,
79 help="""
80 help="""
80 treat the arg as a glob pattern to search for in (full) history.
81 treat the arg as a glob pattern to search for in (full) history.
81 This includes the saved history (almost all commands ever written).
82 This includes the saved history (almost all commands ever written).
82 The pattern may contain '?' to match one unknown character and '*'
83 The pattern may contain '?' to match one unknown character and '*'
83 to match any number of unknown characters. Use '%%hist -g' to show
84 to match any number of unknown characters. Use '%%hist -g' to show
84 full saved history (may be very long).
85 full saved history (may be very long).
85 """)
86 """)
86 @argument(
87 @argument(
87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
88 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
88 help="""
89 help="""
89 get the last n lines from all sessions. Specify n as a single
90 get the last n lines from all sessions. Specify n as a single
90 arg, or the default is the last 10 lines.
91 arg, or the default is the last 10 lines.
91 """)
92 """)
92 @argument(
93 @argument(
93 '-u', dest='unique', action='store_true',
94 '-u', dest='unique', action='store_true',
94 help="""
95 help="""
95 when searching history using `-g`, show only unique history.
96 when searching history using `-g`, show only unique history.
96 """)
97 """)
97 @argument('range', nargs='*')
98 @argument('range', nargs='*')
98 @skip_doctest
99 @skip_doctest
99 @line_magic
100 @line_magic
100 def history(self, parameter_s = ''):
101 def history(self, parameter_s = ''):
101 """Print input history (_i<n> variables), with most recent last.
102 """Print input history (_i<n> variables), with most recent last.
102
103
103 By default, input history is printed without line numbers so it can be
104 By default, input history is printed without line numbers so it can be
104 directly pasted into an editor. Use -n to show them.
105 directly pasted into an editor. Use -n to show them.
105
106
106 By default, all input history from the current session is displayed.
107 By default, all input history from the current session is displayed.
107 Ranges of history can be indicated using the syntax:
108 Ranges of history can be indicated using the syntax:
108
109
109 ``4``
110 ``4``
110 Line 4, current session
111 Line 4, current session
111 ``4-6``
112 ``4-6``
112 Lines 4-6, current session
113 Lines 4-6, current session
113 ``243/1-5``
114 ``243/1-5``
114 Lines 1-5, session 243
115 Lines 1-5, session 243
115 ``~2/7``
116 ``~2/7``
116 Line 7, session 2 before current
117 Line 7, session 2 before current
117 ``~8/1-~6/5``
118 ``~8/1-~6/5``
118 From the first line of 8 sessions ago, to the fifth line of 6
119 From the first line of 8 sessions ago, to the fifth line of 6
119 sessions ago.
120 sessions ago.
120
121
121 Multiple ranges can be entered, separated by spaces
122 Multiple ranges can be entered, separated by spaces
122
123
123 The same syntax is used by %macro, %save, %edit, %rerun
124 The same syntax is used by %macro, %save, %edit, %rerun
124
125
125 Examples
126 Examples
126 --------
127 --------
127 ::
128 ::
128
129
129 In [6]: %history -n 4-6
130 In [6]: %history -n 4-6
130 4:a = 12
131 4:a = 12
131 5:print a**2
132 5:print a**2
132 6:%history -n 4-6
133 6:%history -n 4-6
133
134
134 """
135 """
135
136
136 args = parse_argstring(self.history, parameter_s)
137 args = parse_argstring(self.history, parameter_s)
137
138
138 # For brevity
139 # For brevity
139 history_manager = self.shell.history_manager
140 history_manager = self.shell.history_manager
140
141
141 def _format_lineno(session, line):
142 def _format_lineno(session, line):
142 """Helper function to format line numbers properly."""
143 """Helper function to format line numbers properly."""
143 if session in (0, history_manager.session_number):
144 if session in (0, history_manager.session_number):
144 return str(line)
145 return str(line)
145 return "%s/%s" % (session, line)
146 return "%s/%s" % (session, line)
146
147
147 # Check if output to specific file was requested.
148 # Check if output to specific file was requested.
148 outfname = args.filename
149 outfname = args.filename
149 if not outfname:
150 if not outfname:
150 outfile = io.stdout # default
151 outfile = sys.stdout # default
151 # We don't want to close stdout at the end!
152 # We don't want to close stdout at the end!
152 close_at_end = False
153 close_at_end = False
153 else:
154 else:
154 if os.path.exists(outfname):
155 if os.path.exists(outfname):
155 try:
156 try:
156 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
157 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
157 except StdinNotImplementedError:
158 except StdinNotImplementedError:
158 ans = True
159 ans = True
159 if not ans:
160 if not ans:
160 print('Aborting.')
161 print('Aborting.')
161 return
162 return
162 print("Overwriting file.")
163 print("Overwriting file.")
163 outfile = io_open(outfname, 'w', encoding='utf-8')
164 outfile = io_open(outfname, 'w', encoding='utf-8')
164 close_at_end = True
165 close_at_end = True
165
166
166 print_nums = args.print_nums
167 print_nums = args.print_nums
167 get_output = args.get_output
168 get_output = args.get_output
168 pyprompts = args.pyprompts
169 pyprompts = args.pyprompts
169 raw = args.raw
170 raw = args.raw
170
171
171 pattern = None
172 pattern = None
172 limit = None if args.limit is _unspecified else args.limit
173 limit = None if args.limit is _unspecified else args.limit
173
174
174 if args.pattern is not None:
175 if args.pattern is not None:
175 if args.pattern:
176 if args.pattern:
176 pattern = "*" + " ".join(args.pattern) + "*"
177 pattern = "*" + " ".join(args.pattern) + "*"
177 else:
178 else:
178 pattern = "*"
179 pattern = "*"
179 hist = history_manager.search(pattern, raw=raw, output=get_output,
180 hist = history_manager.search(pattern, raw=raw, output=get_output,
180 n=limit, unique=args.unique)
181 n=limit, unique=args.unique)
181 print_nums = True
182 print_nums = True
182 elif args.limit is not _unspecified:
183 elif args.limit is not _unspecified:
183 n = 10 if limit is None else limit
184 n = 10 if limit is None else limit
184 hist = history_manager.get_tail(n, raw=raw, output=get_output)
185 hist = history_manager.get_tail(n, raw=raw, output=get_output)
185 else:
186 else:
186 if args.range: # Get history by ranges
187 if args.range: # Get history by ranges
187 hist = history_manager.get_range_by_str(" ".join(args.range),
188 hist = history_manager.get_range_by_str(" ".join(args.range),
188 raw, get_output)
189 raw, get_output)
189 else: # Just get history for the current session
190 else: # Just get history for the current session
190 hist = history_manager.get_range(raw=raw, output=get_output)
191 hist = history_manager.get_range(raw=raw, output=get_output)
191
192
192 # We could be displaying the entire history, so let's not try to pull
193 # We could be displaying the entire history, so let's not try to pull
193 # it into a list in memory. Anything that needs more space will just
194 # it into a list in memory. Anything that needs more space will just
194 # misalign.
195 # misalign.
195 width = 4
196 width = 4
196
197
197 for session, lineno, inline in hist:
198 for session, lineno, inline in hist:
198 # Print user history with tabs expanded to 4 spaces. The GUI
199 # Print user history with tabs expanded to 4 spaces. The GUI
199 # clients use hard tabs for easier usability in auto-indented code,
200 # clients use hard tabs for easier usability in auto-indented code,
200 # but we want to produce PEP-8 compliant history for safe pasting
201 # but we want to produce PEP-8 compliant history for safe pasting
201 # into an editor.
202 # into an editor.
202 if get_output:
203 if get_output:
203 inline, output = inline
204 inline, output = inline
204 inline = inline.expandtabs(4).rstrip()
205 inline = inline.expandtabs(4).rstrip()
205
206
206 multiline = "\n" in inline
207 multiline = "\n" in inline
207 line_sep = '\n' if multiline else ' '
208 line_sep = '\n' if multiline else ' '
208 if print_nums:
209 if print_nums:
209 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
210 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
210 line_sep), file=outfile, end=u'')
211 line_sep), file=outfile, end=u'')
211 if pyprompts:
212 if pyprompts:
212 print(u">>> ", end=u"", file=outfile)
213 print(u">>> ", end=u"", file=outfile)
213 if multiline:
214 if multiline:
214 inline = "\n... ".join(inline.splitlines()) + "\n..."
215 inline = "\n... ".join(inline.splitlines()) + "\n..."
215 print(inline, file=outfile)
216 print(inline, file=outfile)
216 if get_output and output:
217 if get_output and output:
217 print(cast_unicode_py2(output), file=outfile)
218 print(cast_unicode_py2(output), file=outfile)
218
219
219 if close_at_end:
220 if close_at_end:
220 outfile.close()
221 outfile.close()
221
222
222 @line_magic
223 @line_magic
223 def recall(self, arg):
224 def recall(self, arg):
224 r"""Repeat a command, or get command to input line for editing.
225 r"""Repeat a command, or get command to input line for editing.
225
226
226 %recall and %rep are equivalent.
227 %recall and %rep are equivalent.
227
228
228 - %recall (no arguments):
229 - %recall (no arguments):
229
230
230 Place a string version of last computation result (stored in the
231 Place a string version of last computation result (stored in the
231 special '_' variable) to the next input prompt. Allows you to create
232 special '_' variable) to the next input prompt. Allows you to create
232 elaborate command lines without using copy-paste::
233 elaborate command lines without using copy-paste::
233
234
234 In[1]: l = ["hei", "vaan"]
235 In[1]: l = ["hei", "vaan"]
235 In[2]: "".join(l)
236 In[2]: "".join(l)
236 Out[2]: heivaan
237 Out[2]: heivaan
237 In[3]: %recall
238 In[3]: %recall
238 In[4]: heivaan_ <== cursor blinking
239 In[4]: heivaan_ <== cursor blinking
239
240
240 %recall 45
241 %recall 45
241
242
242 Place history line 45 on the next input prompt. Use %hist to find
243 Place history line 45 on the next input prompt. Use %hist to find
243 out the number.
244 out the number.
244
245
245 %recall 1-4
246 %recall 1-4
246
247
247 Combine the specified lines into one cell, and place it on the next
248 Combine the specified lines into one cell, and place it on the next
248 input prompt. See %history for the slice syntax.
249 input prompt. See %history for the slice syntax.
249
250
250 %recall foo+bar
251 %recall foo+bar
251
252
252 If foo+bar can be evaluated in the user namespace, the result is
253 If foo+bar can be evaluated in the user namespace, the result is
253 placed at the next input prompt. Otherwise, the history is searched
254 placed at the next input prompt. Otherwise, the history is searched
254 for lines which contain that substring, and the most recent one is
255 for lines which contain that substring, and the most recent one is
255 placed at the next input prompt.
256 placed at the next input prompt.
256 """
257 """
257 if not arg: # Last output
258 if not arg: # Last output
258 self.shell.set_next_input(str(self.shell.user_ns["_"]))
259 self.shell.set_next_input(str(self.shell.user_ns["_"]))
259 return
260 return
260 # Get history range
261 # Get history range
261 histlines = self.shell.history_manager.get_range_by_str(arg)
262 histlines = self.shell.history_manager.get_range_by_str(arg)
262 cmd = "\n".join(x[2] for x in histlines)
263 cmd = "\n".join(x[2] for x in histlines)
263 if cmd:
264 if cmd:
264 self.shell.set_next_input(cmd.rstrip())
265 self.shell.set_next_input(cmd.rstrip())
265 return
266 return
266
267
267 try: # Variable in user namespace
268 try: # Variable in user namespace
268 cmd = str(eval(arg, self.shell.user_ns))
269 cmd = str(eval(arg, self.shell.user_ns))
269 except Exception: # Search for term in history
270 except Exception: # Search for term in history
270 histlines = self.shell.history_manager.search("*"+arg+"*")
271 histlines = self.shell.history_manager.search("*"+arg+"*")
271 for h in reversed([x[2] for x in histlines]):
272 for h in reversed([x[2] for x in histlines]):
272 if 'recall' in h or 'rep' in h:
273 if 'recall' in h or 'rep' in h:
273 continue
274 continue
274 self.shell.set_next_input(h.rstrip())
275 self.shell.set_next_input(h.rstrip())
275 return
276 return
276 else:
277 else:
277 self.shell.set_next_input(cmd.rstrip())
278 self.shell.set_next_input(cmd.rstrip())
278 print("Couldn't evaluate or find in history:", arg)
279 print("Couldn't evaluate or find in history:", arg)
279
280
280 @line_magic
281 @line_magic
281 def rerun(self, parameter_s=''):
282 def rerun(self, parameter_s=''):
282 """Re-run previous input
283 """Re-run previous input
283
284
284 By default, you can specify ranges of input history to be repeated
285 By default, you can specify ranges of input history to be repeated
285 (as with %history). With no arguments, it will repeat the last line.
286 (as with %history). With no arguments, it will repeat the last line.
286
287
287 Options:
288 Options:
288
289
289 -l <n> : Repeat the last n lines of input, not including the
290 -l <n> : Repeat the last n lines of input, not including the
290 current command.
291 current command.
291
292
292 -g foo : Repeat the most recent line which contains foo
293 -g foo : Repeat the most recent line which contains foo
293 """
294 """
294 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
295 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
295 if "l" in opts: # Last n lines
296 if "l" in opts: # Last n lines
296 n = int(opts['l'])
297 n = int(opts['l'])
297 hist = self.shell.history_manager.get_tail(n)
298 hist = self.shell.history_manager.get_tail(n)
298 elif "g" in opts: # Search
299 elif "g" in opts: # Search
299 p = "*"+opts['g']+"*"
300 p = "*"+opts['g']+"*"
300 hist = list(self.shell.history_manager.search(p))
301 hist = list(self.shell.history_manager.search(p))
301 for l in reversed(hist):
302 for l in reversed(hist):
302 if "rerun" not in l[2]:
303 if "rerun" not in l[2]:
303 hist = [l] # The last match which isn't a %rerun
304 hist = [l] # The last match which isn't a %rerun
304 break
305 break
305 else:
306 else:
306 hist = [] # No matches except %rerun
307 hist = [] # No matches except %rerun
307 elif args: # Specify history ranges
308 elif args: # Specify history ranges
308 hist = self.shell.history_manager.get_range_by_str(args)
309 hist = self.shell.history_manager.get_range_by_str(args)
309 else: # Last line
310 else: # Last line
310 hist = self.shell.history_manager.get_tail(1)
311 hist = self.shell.history_manager.get_tail(1)
311 hist = [x[2] for x in hist]
312 hist = [x[2] for x in hist]
312 if not hist:
313 if not hist:
313 print("No lines in history match specification")
314 print("No lines in history match specification")
314 return
315 return
315 histlines = "\n".join(hist)
316 histlines = "\n".join(hist)
316 print("=== Executing: ===")
317 print("=== Executing: ===")
317 print(histlines)
318 print(histlines)
318 print("=== Output: ===")
319 print("=== Output: ===")
319 self.shell.run_cell("\n".join(hist), store_history=False)
320 self.shell.run_cell("\n".join(hist), store_history=False)
@@ -1,929 +1,928 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for inspecting Python objects.
2 """Tools for inspecting Python objects.
3
3
4 Uses syntax highlighting for presenting the various information elements.
4 Uses syntax highlighting for presenting the various information elements.
5
5
6 Similar in spirit to the inspect module, but all calls take a name argument to
6 Similar in spirit to the inspect module, but all calls take a name argument to
7 reference the name under which an object is being read.
7 reference the name under which an object is being read.
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 __all__ = ['Inspector','InspectColors']
15 __all__ = ['Inspector','InspectColors']
16
16
17 # stdlib modules
17 # stdlib modules
18 import inspect
18 import inspect
19 import linecache
19 import linecache
20 import os
20 import os
21 from textwrap import dedent
21 from textwrap import dedent
22 import types
22 import types
23 import io as stdlib_io
23 import io as stdlib_io
24
24
25 try:
25 try:
26 from itertools import izip_longest
26 from itertools import izip_longest
27 except ImportError:
27 except ImportError:
28 from itertools import zip_longest as izip_longest
28 from itertools import zip_longest as izip_longest
29
29
30 # IPython's own
30 # IPython's own
31 from IPython.core import page
31 from IPython.core import page
32 from IPython.lib.pretty import pretty
32 from IPython.lib.pretty import pretty
33 from IPython.testing.skipdoctest import skip_doctest_py3
33 from IPython.testing.skipdoctest import skip_doctest_py3
34 from IPython.utils import PyColorize
34 from IPython.utils import PyColorize
35 from IPython.utils import io
36 from IPython.utils import openpy
35 from IPython.utils import openpy
37 from IPython.utils import py3compat
36 from IPython.utils import py3compat
38 from IPython.utils.dir2 import safe_hasattr
37 from IPython.utils.dir2 import safe_hasattr
39 from IPython.utils.path import compress_user
38 from IPython.utils.path import compress_user
40 from IPython.utils.text import indent
39 from IPython.utils.text import indent
41 from IPython.utils.wildcard import list_namespace
40 from IPython.utils.wildcard import list_namespace
42 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
41 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
43 from IPython.utils.py3compat import cast_unicode, string_types, PY3
42 from IPython.utils.py3compat import cast_unicode, string_types, PY3
44 from IPython.utils.signatures import signature
43 from IPython.utils.signatures import signature
45 from IPython.utils.colorable import Colorable
44 from IPython.utils.colorable import Colorable
46
45
47 # builtin docstrings to ignore
46 # builtin docstrings to ignore
48 _func_call_docstring = types.FunctionType.__call__.__doc__
47 _func_call_docstring = types.FunctionType.__call__.__doc__
49 _object_init_docstring = object.__init__.__doc__
48 _object_init_docstring = object.__init__.__doc__
50 _builtin_type_docstrings = {
49 _builtin_type_docstrings = {
51 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
50 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
52 types.FunctionType, property)
51 types.FunctionType, property)
53 }
52 }
54
53
55 _builtin_func_type = type(all)
54 _builtin_func_type = type(all)
56 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
55 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
57 #****************************************************************************
56 #****************************************************************************
58 # Builtin color schemes
57 # Builtin color schemes
59
58
60 Colors = TermColors # just a shorthand
59 Colors = TermColors # just a shorthand
61
60
62 InspectColors = PyColorize.ANSICodeColors
61 InspectColors = PyColorize.ANSICodeColors
63
62
64 #****************************************************************************
63 #****************************************************************************
65 # Auxiliary functions and objects
64 # Auxiliary functions and objects
66
65
67 # See the messaging spec for the definition of all these fields. This list
66 # See the messaging spec for the definition of all these fields. This list
68 # effectively defines the order of display
67 # effectively defines the order of display
69 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
68 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
70 'length', 'file', 'definition', 'docstring', 'source',
69 'length', 'file', 'definition', 'docstring', 'source',
71 'init_definition', 'class_docstring', 'init_docstring',
70 'init_definition', 'class_docstring', 'init_docstring',
72 'call_def', 'call_docstring',
71 'call_def', 'call_docstring',
73 # These won't be printed but will be used to determine how to
72 # These won't be printed but will be used to determine how to
74 # format the object
73 # format the object
75 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
74 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
76 ]
75 ]
77
76
78
77
79 def object_info(**kw):
78 def object_info(**kw):
80 """Make an object info dict with all fields present."""
79 """Make an object info dict with all fields present."""
81 infodict = dict(izip_longest(info_fields, [None]))
80 infodict = dict(izip_longest(info_fields, [None]))
82 infodict.update(kw)
81 infodict.update(kw)
83 return infodict
82 return infodict
84
83
85
84
86 def get_encoding(obj):
85 def get_encoding(obj):
87 """Get encoding for python source file defining obj
86 """Get encoding for python source file defining obj
88
87
89 Returns None if obj is not defined in a sourcefile.
88 Returns None if obj is not defined in a sourcefile.
90 """
89 """
91 ofile = find_file(obj)
90 ofile = find_file(obj)
92 # run contents of file through pager starting at line where the object
91 # run contents of file through pager starting at line where the object
93 # is defined, as long as the file isn't binary and is actually on the
92 # is defined, as long as the file isn't binary and is actually on the
94 # filesystem.
93 # filesystem.
95 if ofile is None:
94 if ofile is None:
96 return None
95 return None
97 elif ofile.endswith(('.so', '.dll', '.pyd')):
96 elif ofile.endswith(('.so', '.dll', '.pyd')):
98 return None
97 return None
99 elif not os.path.isfile(ofile):
98 elif not os.path.isfile(ofile):
100 return None
99 return None
101 else:
100 else:
102 # Print only text files, not extension binaries. Note that
101 # Print only text files, not extension binaries. Note that
103 # getsourcelines returns lineno with 1-offset and page() uses
102 # getsourcelines returns lineno with 1-offset and page() uses
104 # 0-offset, so we must adjust.
103 # 0-offset, so we must adjust.
105 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
104 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
106 encoding, lines = openpy.detect_encoding(buffer.readline)
105 encoding, lines = openpy.detect_encoding(buffer.readline)
107 return encoding
106 return encoding
108
107
109 def getdoc(obj):
108 def getdoc(obj):
110 """Stable wrapper around inspect.getdoc.
109 """Stable wrapper around inspect.getdoc.
111
110
112 This can't crash because of attribute problems.
111 This can't crash because of attribute problems.
113
112
114 It also attempts to call a getdoc() method on the given object. This
113 It also attempts to call a getdoc() method on the given object. This
115 allows objects which provide their docstrings via non-standard mechanisms
114 allows objects which provide their docstrings via non-standard mechanisms
116 (like Pyro proxies) to still be inspected by ipython's ? system."""
115 (like Pyro proxies) to still be inspected by ipython's ? system."""
117 # Allow objects to offer customized documentation via a getdoc method:
116 # Allow objects to offer customized documentation via a getdoc method:
118 try:
117 try:
119 ds = obj.getdoc()
118 ds = obj.getdoc()
120 except Exception:
119 except Exception:
121 pass
120 pass
122 else:
121 else:
123 # if we get extra info, we add it to the normal docstring.
122 # if we get extra info, we add it to the normal docstring.
124 if isinstance(ds, string_types):
123 if isinstance(ds, string_types):
125 return inspect.cleandoc(ds)
124 return inspect.cleandoc(ds)
126
125
127 try:
126 try:
128 docstr = inspect.getdoc(obj)
127 docstr = inspect.getdoc(obj)
129 encoding = get_encoding(obj)
128 encoding = get_encoding(obj)
130 return py3compat.cast_unicode(docstr, encoding=encoding)
129 return py3compat.cast_unicode(docstr, encoding=encoding)
131 except Exception:
130 except Exception:
132 # Harden against an inspect failure, which can occur with
131 # Harden against an inspect failure, which can occur with
133 # SWIG-wrapped extensions.
132 # SWIG-wrapped extensions.
134 raise
133 raise
135 return None
134 return None
136
135
137
136
138 def getsource(obj, oname=''):
137 def getsource(obj, oname=''):
139 """Wrapper around inspect.getsource.
138 """Wrapper around inspect.getsource.
140
139
141 This can be modified by other projects to provide customized source
140 This can be modified by other projects to provide customized source
142 extraction.
141 extraction.
143
142
144 Parameters
143 Parameters
145 ----------
144 ----------
146 obj : object
145 obj : object
147 an object whose source code we will attempt to extract
146 an object whose source code we will attempt to extract
148 oname : str
147 oname : str
149 (optional) a name under which the object is known
148 (optional) a name under which the object is known
150
149
151 Returns
150 Returns
152 -------
151 -------
153 src : unicode or None
152 src : unicode or None
154
153
155 """
154 """
156
155
157 if isinstance(obj, property):
156 if isinstance(obj, property):
158 sources = []
157 sources = []
159 for attrname in ['fget', 'fset', 'fdel']:
158 for attrname in ['fget', 'fset', 'fdel']:
160 fn = getattr(obj, attrname)
159 fn = getattr(obj, attrname)
161 if fn is not None:
160 if fn is not None:
162 encoding = get_encoding(fn)
161 encoding = get_encoding(fn)
163 oname_prefix = ('%s.' % oname) if oname else ''
162 oname_prefix = ('%s.' % oname) if oname else ''
164 sources.append(cast_unicode(
163 sources.append(cast_unicode(
165 ''.join(('# ', oname_prefix, attrname)),
164 ''.join(('# ', oname_prefix, attrname)),
166 encoding=encoding))
165 encoding=encoding))
167 if inspect.isfunction(fn):
166 if inspect.isfunction(fn):
168 sources.append(dedent(getsource(fn)))
167 sources.append(dedent(getsource(fn)))
169 else:
168 else:
170 # Default str/repr only prints function name,
169 # Default str/repr only prints function name,
171 # pretty.pretty prints module name too.
170 # pretty.pretty prints module name too.
172 sources.append(cast_unicode(
171 sources.append(cast_unicode(
173 '%s%s = %s\n' % (
172 '%s%s = %s\n' % (
174 oname_prefix, attrname, pretty(fn)),
173 oname_prefix, attrname, pretty(fn)),
175 encoding=encoding))
174 encoding=encoding))
176 if sources:
175 if sources:
177 return '\n'.join(sources)
176 return '\n'.join(sources)
178 else:
177 else:
179 return None
178 return None
180
179
181 else:
180 else:
182 # Get source for non-property objects.
181 # Get source for non-property objects.
183
182
184 obj = _get_wrapped(obj)
183 obj = _get_wrapped(obj)
185
184
186 try:
185 try:
187 src = inspect.getsource(obj)
186 src = inspect.getsource(obj)
188 except TypeError:
187 except TypeError:
189 # The object itself provided no meaningful source, try looking for
188 # The object itself provided no meaningful source, try looking for
190 # its class definition instead.
189 # its class definition instead.
191 if hasattr(obj, '__class__'):
190 if hasattr(obj, '__class__'):
192 try:
191 try:
193 src = inspect.getsource(obj.__class__)
192 src = inspect.getsource(obj.__class__)
194 except TypeError:
193 except TypeError:
195 return None
194 return None
196
195
197 encoding = get_encoding(obj)
196 encoding = get_encoding(obj)
198 return cast_unicode(src, encoding=encoding)
197 return cast_unicode(src, encoding=encoding)
199
198
200
199
201 def is_simple_callable(obj):
200 def is_simple_callable(obj):
202 """True if obj is a function ()"""
201 """True if obj is a function ()"""
203 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
202 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
204 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
203 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
205
204
206
205
207 def getargspec(obj):
206 def getargspec(obj):
208 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
207 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
209 :func:inspect.getargspec` on Python 2.
208 :func:inspect.getargspec` on Python 2.
210
209
211 In addition to functions and methods, this can also handle objects with a
210 In addition to functions and methods, this can also handle objects with a
212 ``__call__`` attribute.
211 ``__call__`` attribute.
213 """
212 """
214 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
215 obj = obj.__call__
214 obj = obj.__call__
216
215
217 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
216 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
218
217
219
218
220 def format_argspec(argspec):
219 def format_argspec(argspec):
221 """Format argspect, convenience wrapper around inspect's.
220 """Format argspect, convenience wrapper around inspect's.
222
221
223 This takes a dict instead of ordered arguments and calls
222 This takes a dict instead of ordered arguments and calls
224 inspect.format_argspec with the arguments in the necessary order.
223 inspect.format_argspec with the arguments in the necessary order.
225 """
224 """
226 return inspect.formatargspec(argspec['args'], argspec['varargs'],
225 return inspect.formatargspec(argspec['args'], argspec['varargs'],
227 argspec['varkw'], argspec['defaults'])
226 argspec['varkw'], argspec['defaults'])
228
227
229
228
230 def call_tip(oinfo, format_call=True):
229 def call_tip(oinfo, format_call=True):
231 """Extract call tip data from an oinfo dict.
230 """Extract call tip data from an oinfo dict.
232
231
233 Parameters
232 Parameters
234 ----------
233 ----------
235 oinfo : dict
234 oinfo : dict
236
235
237 format_call : bool, optional
236 format_call : bool, optional
238 If True, the call line is formatted and returned as a string. If not, a
237 If True, the call line is formatted and returned as a string. If not, a
239 tuple of (name, argspec) is returned.
238 tuple of (name, argspec) is returned.
240
239
241 Returns
240 Returns
242 -------
241 -------
243 call_info : None, str or (str, dict) tuple.
242 call_info : None, str or (str, dict) tuple.
244 When format_call is True, the whole call information is formattted as a
243 When format_call is True, the whole call information is formattted as a
245 single string. Otherwise, the object's name and its argspec dict are
244 single string. Otherwise, the object's name and its argspec dict are
246 returned. If no call information is available, None is returned.
245 returned. If no call information is available, None is returned.
247
246
248 docstring : str or None
247 docstring : str or None
249 The most relevant docstring for calling purposes is returned, if
248 The most relevant docstring for calling purposes is returned, if
250 available. The priority is: call docstring for callable instances, then
249 available. The priority is: call docstring for callable instances, then
251 constructor docstring for classes, then main object's docstring otherwise
250 constructor docstring for classes, then main object's docstring otherwise
252 (regular functions).
251 (regular functions).
253 """
252 """
254 # Get call definition
253 # Get call definition
255 argspec = oinfo.get('argspec')
254 argspec = oinfo.get('argspec')
256 if argspec is None:
255 if argspec is None:
257 call_line = None
256 call_line = None
258 else:
257 else:
259 # Callable objects will have 'self' as their first argument, prune
258 # Callable objects will have 'self' as their first argument, prune
260 # it out if it's there for clarity (since users do *not* pass an
259 # it out if it's there for clarity (since users do *not* pass an
261 # extra first argument explicitly).
260 # extra first argument explicitly).
262 try:
261 try:
263 has_self = argspec['args'][0] == 'self'
262 has_self = argspec['args'][0] == 'self'
264 except (KeyError, IndexError):
263 except (KeyError, IndexError):
265 pass
264 pass
266 else:
265 else:
267 if has_self:
266 if has_self:
268 argspec['args'] = argspec['args'][1:]
267 argspec['args'] = argspec['args'][1:]
269
268
270 call_line = oinfo['name']+format_argspec(argspec)
269 call_line = oinfo['name']+format_argspec(argspec)
271
270
272 # Now get docstring.
271 # Now get docstring.
273 # The priority is: call docstring, constructor docstring, main one.
272 # The priority is: call docstring, constructor docstring, main one.
274 doc = oinfo.get('call_docstring')
273 doc = oinfo.get('call_docstring')
275 if doc is None:
274 if doc is None:
276 doc = oinfo.get('init_docstring')
275 doc = oinfo.get('init_docstring')
277 if doc is None:
276 if doc is None:
278 doc = oinfo.get('docstring','')
277 doc = oinfo.get('docstring','')
279
278
280 return call_line, doc
279 return call_line, doc
281
280
282
281
283 def _get_wrapped(obj):
282 def _get_wrapped(obj):
284 """Get the original object if wrapped in one or more @decorators
283 """Get the original object if wrapped in one or more @decorators
285
284
286 Some objects automatically construct similar objects on any unrecognised
285 Some objects automatically construct similar objects on any unrecognised
287 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
286 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
288 this will arbitrarily cut off after 100 levels of obj.__wrapped__
287 this will arbitrarily cut off after 100 levels of obj.__wrapped__
289 attribute access. --TK, Jan 2016
288 attribute access. --TK, Jan 2016
290 """
289 """
291 orig_obj = obj
290 orig_obj = obj
292 i = 0
291 i = 0
293 while safe_hasattr(obj, '__wrapped__'):
292 while safe_hasattr(obj, '__wrapped__'):
294 obj = obj.__wrapped__
293 obj = obj.__wrapped__
295 i += 1
294 i += 1
296 if i > 100:
295 if i > 100:
297 # __wrapped__ is probably a lie, so return the thing we started with
296 # __wrapped__ is probably a lie, so return the thing we started with
298 return orig_obj
297 return orig_obj
299 return obj
298 return obj
300
299
301 def find_file(obj):
300 def find_file(obj):
302 """Find the absolute path to the file where an object was defined.
301 """Find the absolute path to the file where an object was defined.
303
302
304 This is essentially a robust wrapper around `inspect.getabsfile`.
303 This is essentially a robust wrapper around `inspect.getabsfile`.
305
304
306 Returns None if no file can be found.
305 Returns None if no file can be found.
307
306
308 Parameters
307 Parameters
309 ----------
308 ----------
310 obj : any Python object
309 obj : any Python object
311
310
312 Returns
311 Returns
313 -------
312 -------
314 fname : str
313 fname : str
315 The absolute path to the file where the object was defined.
314 The absolute path to the file where the object was defined.
316 """
315 """
317 obj = _get_wrapped(obj)
316 obj = _get_wrapped(obj)
318
317
319 fname = None
318 fname = None
320 try:
319 try:
321 fname = inspect.getabsfile(obj)
320 fname = inspect.getabsfile(obj)
322 except TypeError:
321 except TypeError:
323 # For an instance, the file that matters is where its class was
322 # For an instance, the file that matters is where its class was
324 # declared.
323 # declared.
325 if hasattr(obj, '__class__'):
324 if hasattr(obj, '__class__'):
326 try:
325 try:
327 fname = inspect.getabsfile(obj.__class__)
326 fname = inspect.getabsfile(obj.__class__)
328 except TypeError:
327 except TypeError:
329 # Can happen for builtins
328 # Can happen for builtins
330 pass
329 pass
331 except:
330 except:
332 pass
331 pass
333 return cast_unicode(fname)
332 return cast_unicode(fname)
334
333
335
334
336 def find_source_lines(obj):
335 def find_source_lines(obj):
337 """Find the line number in a file where an object was defined.
336 """Find the line number in a file where an object was defined.
338
337
339 This is essentially a robust wrapper around `inspect.getsourcelines`.
338 This is essentially a robust wrapper around `inspect.getsourcelines`.
340
339
341 Returns None if no file can be found.
340 Returns None if no file can be found.
342
341
343 Parameters
342 Parameters
344 ----------
343 ----------
345 obj : any Python object
344 obj : any Python object
346
345
347 Returns
346 Returns
348 -------
347 -------
349 lineno : int
348 lineno : int
350 The line number where the object definition starts.
349 The line number where the object definition starts.
351 """
350 """
352 obj = _get_wrapped(obj)
351 obj = _get_wrapped(obj)
353
352
354 try:
353 try:
355 try:
354 try:
356 lineno = inspect.getsourcelines(obj)[1]
355 lineno = inspect.getsourcelines(obj)[1]
357 except TypeError:
356 except TypeError:
358 # For instances, try the class object like getsource() does
357 # For instances, try the class object like getsource() does
359 if hasattr(obj, '__class__'):
358 if hasattr(obj, '__class__'):
360 lineno = inspect.getsourcelines(obj.__class__)[1]
359 lineno = inspect.getsourcelines(obj.__class__)[1]
361 else:
360 else:
362 lineno = None
361 lineno = None
363 except:
362 except:
364 return None
363 return None
365
364
366 return lineno
365 return lineno
367
366
368
367
369 class Inspector(Colorable):
368 class Inspector(Colorable):
370 def __init__(self, color_table=InspectColors,
369 def __init__(self, color_table=InspectColors,
371 code_color_table=PyColorize.ANSICodeColors,
370 code_color_table=PyColorize.ANSICodeColors,
372 scheme='NoColor',
371 scheme='NoColor',
373 str_detail_level=0,
372 str_detail_level=0,
374 parent=None, config=None):
373 parent=None, config=None):
375 super(Inspector, self).__init__(parent=parent, config=config)
374 super(Inspector, self).__init__(parent=parent, config=config)
376 self.color_table = color_table
375 self.color_table = color_table
377 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
376 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
378 self.format = self.parser.format
377 self.format = self.parser.format
379 self.str_detail_level = str_detail_level
378 self.str_detail_level = str_detail_level
380 self.set_active_scheme(scheme)
379 self.set_active_scheme(scheme)
381
380
382 def _getdef(self,obj,oname=''):
381 def _getdef(self,obj,oname=''):
383 """Return the call signature for any callable object.
382 """Return the call signature for any callable object.
384
383
385 If any exception is generated, None is returned instead and the
384 If any exception is generated, None is returned instead and the
386 exception is suppressed."""
385 exception is suppressed."""
387 try:
386 try:
388 hdef = oname + str(signature(obj))
387 hdef = oname + str(signature(obj))
389 return cast_unicode(hdef)
388 return cast_unicode(hdef)
390 except:
389 except:
391 return None
390 return None
392
391
393 def __head(self,h):
392 def __head(self,h):
394 """Return a header string with proper colors."""
393 """Return a header string with proper colors."""
395 return '%s%s%s' % (self.color_table.active_colors.header,h,
394 return '%s%s%s' % (self.color_table.active_colors.header,h,
396 self.color_table.active_colors.normal)
395 self.color_table.active_colors.normal)
397
396
398 def set_active_scheme(self, scheme):
397 def set_active_scheme(self, scheme):
399 self.color_table.set_active_scheme(scheme)
398 self.color_table.set_active_scheme(scheme)
400 self.parser.color_table.set_active_scheme(scheme)
399 self.parser.color_table.set_active_scheme(scheme)
401
400
402 def noinfo(self, msg, oname):
401 def noinfo(self, msg, oname):
403 """Generic message when no information is found."""
402 """Generic message when no information is found."""
404 print('No %s found' % msg, end=' ')
403 print('No %s found' % msg, end=' ')
405 if oname:
404 if oname:
406 print('for %s' % oname)
405 print('for %s' % oname)
407 else:
406 else:
408 print()
407 print()
409
408
410 def pdef(self, obj, oname=''):
409 def pdef(self, obj, oname=''):
411 """Print the call signature for any callable object.
410 """Print the call signature for any callable object.
412
411
413 If the object is a class, print the constructor information."""
412 If the object is a class, print the constructor information."""
414
413
415 if not callable(obj):
414 if not callable(obj):
416 print('Object is not callable.')
415 print('Object is not callable.')
417 return
416 return
418
417
419 header = ''
418 header = ''
420
419
421 if inspect.isclass(obj):
420 if inspect.isclass(obj):
422 header = self.__head('Class constructor information:\n')
421 header = self.__head('Class constructor information:\n')
423 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
422 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
424 obj = obj.__call__
423 obj = obj.__call__
425
424
426 output = self._getdef(obj,oname)
425 output = self._getdef(obj,oname)
427 if output is None:
426 if output is None:
428 self.noinfo('definition header',oname)
427 self.noinfo('definition header',oname)
429 else:
428 else:
430 print(header,self.format(output), end=' ', file=io.stdout)
429 print(header,self.format(output), end=' ')
431
430
432 # In Python 3, all classes are new-style, so they all have __init__.
431 # In Python 3, all classes are new-style, so they all have __init__.
433 @skip_doctest_py3
432 @skip_doctest_py3
434 def pdoc(self,obj,oname='',formatter = None):
433 def pdoc(self,obj,oname='',formatter = None):
435 """Print the docstring for any object.
434 """Print the docstring for any object.
436
435
437 Optional:
436 Optional:
438 -formatter: a function to run the docstring through for specially
437 -formatter: a function to run the docstring through for specially
439 formatted docstrings.
438 formatted docstrings.
440
439
441 Examples
440 Examples
442 --------
441 --------
443
442
444 In [1]: class NoInit:
443 In [1]: class NoInit:
445 ...: pass
444 ...: pass
446
445
447 In [2]: class NoDoc:
446 In [2]: class NoDoc:
448 ...: def __init__(self):
447 ...: def __init__(self):
449 ...: pass
448 ...: pass
450
449
451 In [3]: %pdoc NoDoc
450 In [3]: %pdoc NoDoc
452 No documentation found for NoDoc
451 No documentation found for NoDoc
453
452
454 In [4]: %pdoc NoInit
453 In [4]: %pdoc NoInit
455 No documentation found for NoInit
454 No documentation found for NoInit
456
455
457 In [5]: obj = NoInit()
456 In [5]: obj = NoInit()
458
457
459 In [6]: %pdoc obj
458 In [6]: %pdoc obj
460 No documentation found for obj
459 No documentation found for obj
461
460
462 In [5]: obj2 = NoDoc()
461 In [5]: obj2 = NoDoc()
463
462
464 In [6]: %pdoc obj2
463 In [6]: %pdoc obj2
465 No documentation found for obj2
464 No documentation found for obj2
466 """
465 """
467
466
468 head = self.__head # For convenience
467 head = self.__head # For convenience
469 lines = []
468 lines = []
470 ds = getdoc(obj)
469 ds = getdoc(obj)
471 if formatter:
470 if formatter:
472 ds = formatter(ds)
471 ds = formatter(ds)
473 if ds:
472 if ds:
474 lines.append(head("Class docstring:"))
473 lines.append(head("Class docstring:"))
475 lines.append(indent(ds))
474 lines.append(indent(ds))
476 if inspect.isclass(obj) and hasattr(obj, '__init__'):
475 if inspect.isclass(obj) and hasattr(obj, '__init__'):
477 init_ds = getdoc(obj.__init__)
476 init_ds = getdoc(obj.__init__)
478 if init_ds is not None:
477 if init_ds is not None:
479 lines.append(head("Init docstring:"))
478 lines.append(head("Init docstring:"))
480 lines.append(indent(init_ds))
479 lines.append(indent(init_ds))
481 elif hasattr(obj,'__call__'):
480 elif hasattr(obj,'__call__'):
482 call_ds = getdoc(obj.__call__)
481 call_ds = getdoc(obj.__call__)
483 if call_ds:
482 if call_ds:
484 lines.append(head("Call docstring:"))
483 lines.append(head("Call docstring:"))
485 lines.append(indent(call_ds))
484 lines.append(indent(call_ds))
486
485
487 if not lines:
486 if not lines:
488 self.noinfo('documentation',oname)
487 self.noinfo('documentation',oname)
489 else:
488 else:
490 page.page('\n'.join(lines))
489 page.page('\n'.join(lines))
491
490
492 def psource(self, obj, oname=''):
491 def psource(self, obj, oname=''):
493 """Print the source code for an object."""
492 """Print the source code for an object."""
494
493
495 # Flush the source cache because inspect can return out-of-date source
494 # Flush the source cache because inspect can return out-of-date source
496 linecache.checkcache()
495 linecache.checkcache()
497 try:
496 try:
498 src = getsource(obj, oname=oname)
497 src = getsource(obj, oname=oname)
499 except Exception:
498 except Exception:
500 src = None
499 src = None
501
500
502 if src is None:
501 if src is None:
503 self.noinfo('source', oname)
502 self.noinfo('source', oname)
504 else:
503 else:
505 page.page(self.format(src))
504 page.page(self.format(src))
506
505
507 def pfile(self, obj, oname=''):
506 def pfile(self, obj, oname=''):
508 """Show the whole file where an object was defined."""
507 """Show the whole file where an object was defined."""
509
508
510 lineno = find_source_lines(obj)
509 lineno = find_source_lines(obj)
511 if lineno is None:
510 if lineno is None:
512 self.noinfo('file', oname)
511 self.noinfo('file', oname)
513 return
512 return
514
513
515 ofile = find_file(obj)
514 ofile = find_file(obj)
516 # run contents of file through pager starting at line where the object
515 # run contents of file through pager starting at line where the object
517 # is defined, as long as the file isn't binary and is actually on the
516 # is defined, as long as the file isn't binary and is actually on the
518 # filesystem.
517 # filesystem.
519 if ofile.endswith(('.so', '.dll', '.pyd')):
518 if ofile.endswith(('.so', '.dll', '.pyd')):
520 print('File %r is binary, not printing.' % ofile)
519 print('File %r is binary, not printing.' % ofile)
521 elif not os.path.isfile(ofile):
520 elif not os.path.isfile(ofile):
522 print('File %r does not exist, not printing.' % ofile)
521 print('File %r does not exist, not printing.' % ofile)
523 else:
522 else:
524 # Print only text files, not extension binaries. Note that
523 # Print only text files, not extension binaries. Note that
525 # getsourcelines returns lineno with 1-offset and page() uses
524 # getsourcelines returns lineno with 1-offset and page() uses
526 # 0-offset, so we must adjust.
525 # 0-offset, so we must adjust.
527 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
526 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
528
527
529 def _format_fields(self, fields, title_width=0):
528 def _format_fields(self, fields, title_width=0):
530 """Formats a list of fields for display.
529 """Formats a list of fields for display.
531
530
532 Parameters
531 Parameters
533 ----------
532 ----------
534 fields : list
533 fields : list
535 A list of 2-tuples: (field_title, field_content)
534 A list of 2-tuples: (field_title, field_content)
536 title_width : int
535 title_width : int
537 How many characters to pad titles to. Default to longest title.
536 How many characters to pad titles to. Default to longest title.
538 """
537 """
539 out = []
538 out = []
540 header = self.__head
539 header = self.__head
541 if title_width == 0:
540 if title_width == 0:
542 title_width = max(len(title) + 2 for title, _ in fields)
541 title_width = max(len(title) + 2 for title, _ in fields)
543 for title, content in fields:
542 for title, content in fields:
544 if len(content.splitlines()) > 1:
543 if len(content.splitlines()) > 1:
545 title = header(title + ":") + "\n"
544 title = header(title + ":") + "\n"
546 else:
545 else:
547 title = header((title+":").ljust(title_width))
546 title = header((title+":").ljust(title_width))
548 out.append(cast_unicode(title) + cast_unicode(content))
547 out.append(cast_unicode(title) + cast_unicode(content))
549 return "\n".join(out)
548 return "\n".join(out)
550
549
551 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
550 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
552 """Format an info dict as text"""
551 """Format an info dict as text"""
553 info = self.info(obj, oname=oname, formatter=formatter,
552 info = self.info(obj, oname=oname, formatter=formatter,
554 info=info, detail_level=detail_level)
553 info=info, detail_level=detail_level)
555 displayfields = []
554 displayfields = []
556 def add_fields(fields):
555 def add_fields(fields):
557 for title, key in fields:
556 for title, key in fields:
558 field = info[key]
557 field = info[key]
559 if field is not None:
558 if field is not None:
560 if key == "source":
559 if key == "source":
561 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
560 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
562 else:
561 else:
563 displayfields.append((title, field.rstrip()))
562 displayfields.append((title, field.rstrip()))
564
563
565 if info['isalias']:
564 if info['isalias']:
566 add_fields([('Repr', "string_form")])
565 add_fields([('Repr', "string_form")])
567
566
568 elif info['ismagic']:
567 elif info['ismagic']:
569 if detail_level > 0 and info['source'] is not None:
568 if detail_level > 0 and info['source'] is not None:
570 add_fields([("Source", "source")])
569 add_fields([("Source", "source")])
571 else:
570 else:
572 add_fields([("Docstring", "docstring")])
571 add_fields([("Docstring", "docstring")])
573
572
574 add_fields([("File", "file"),
573 add_fields([("File", "file"),
575 ])
574 ])
576
575
577 elif info['isclass'] or is_simple_callable(obj):
576 elif info['isclass'] or is_simple_callable(obj):
578 # Functions, methods, classes
577 # Functions, methods, classes
579 add_fields([("Signature", "definition"),
578 add_fields([("Signature", "definition"),
580 ("Init signature", "init_definition"),
579 ("Init signature", "init_definition"),
581 ])
580 ])
582 if detail_level > 0 and info['source'] is not None:
581 if detail_level > 0 and info['source'] is not None:
583 add_fields([("Source", "source")])
582 add_fields([("Source", "source")])
584 else:
583 else:
585 add_fields([("Docstring", "docstring"),
584 add_fields([("Docstring", "docstring"),
586 ("Init docstring", "init_docstring"),
585 ("Init docstring", "init_docstring"),
587 ])
586 ])
588
587
589 add_fields([('File', 'file'),
588 add_fields([('File', 'file'),
590 ('Type', 'type_name'),
589 ('Type', 'type_name'),
591 ])
590 ])
592
591
593 else:
592 else:
594 # General Python objects
593 # General Python objects
595 add_fields([("Type", "type_name")])
594 add_fields([("Type", "type_name")])
596
595
597 # Base class for old-style instances
596 # Base class for old-style instances
598 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
597 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
599 displayfields.append(("Base Class", info['base_class'].rstrip()))
598 displayfields.append(("Base Class", info['base_class'].rstrip()))
600
599
601 add_fields([("String form", "string_form")])
600 add_fields([("String form", "string_form")])
602
601
603 # Namespace
602 # Namespace
604 if info['namespace'] != 'Interactive':
603 if info['namespace'] != 'Interactive':
605 displayfields.append(("Namespace", info['namespace'].rstrip()))
604 displayfields.append(("Namespace", info['namespace'].rstrip()))
606
605
607 add_fields([("Length", "length"),
606 add_fields([("Length", "length"),
608 ("File", "file"),
607 ("File", "file"),
609 ("Signature", "definition"),
608 ("Signature", "definition"),
610 ])
609 ])
611
610
612 # Source or docstring, depending on detail level and whether
611 # Source or docstring, depending on detail level and whether
613 # source found.
612 # source found.
614 if detail_level > 0 and info['source'] is not None:
613 if detail_level > 0 and info['source'] is not None:
615 displayfields.append(("Source",
614 displayfields.append(("Source",
616 self.format(cast_unicode(info['source']))))
615 self.format(cast_unicode(info['source']))))
617 elif info['docstring'] is not None:
616 elif info['docstring'] is not None:
618 displayfields.append(("Docstring", info["docstring"]))
617 displayfields.append(("Docstring", info["docstring"]))
619
618
620 add_fields([("Class docstring", "class_docstring"),
619 add_fields([("Class docstring", "class_docstring"),
621 ("Init docstring", "init_docstring"),
620 ("Init docstring", "init_docstring"),
622 ("Call signature", "call_def"),
621 ("Call signature", "call_def"),
623 ("Call docstring", "call_docstring")])
622 ("Call docstring", "call_docstring")])
624
623
625 if displayfields:
624 if displayfields:
626 return self._format_fields(displayfields)
625 return self._format_fields(displayfields)
627 else:
626 else:
628 return u''
627 return u''
629
628
630 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
629 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
631 """Show detailed information about an object.
630 """Show detailed information about an object.
632
631
633 Optional arguments:
632 Optional arguments:
634
633
635 - oname: name of the variable pointing to the object.
634 - oname: name of the variable pointing to the object.
636
635
637 - formatter: special formatter for docstrings (see pdoc)
636 - formatter: special formatter for docstrings (see pdoc)
638
637
639 - info: a structure with some information fields which may have been
638 - info: a structure with some information fields which may have been
640 precomputed already.
639 precomputed already.
641
640
642 - detail_level: if set to 1, more information is given.
641 - detail_level: if set to 1, more information is given.
643 """
642 """
644 text = self._format_info(obj, oname, formatter, info, detail_level)
643 text = self._format_info(obj, oname, formatter, info, detail_level)
645 if text:
644 if text:
646 page.page(text)
645 page.page(text)
647
646
648 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
647 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
649 """Compute a dict with detailed information about an object.
648 """Compute a dict with detailed information about an object.
650
649
651 Optional arguments:
650 Optional arguments:
652
651
653 - oname: name of the variable pointing to the object.
652 - oname: name of the variable pointing to the object.
654
653
655 - formatter: special formatter for docstrings (see pdoc)
654 - formatter: special formatter for docstrings (see pdoc)
656
655
657 - info: a structure with some information fields which may have been
656 - info: a structure with some information fields which may have been
658 precomputed already.
657 precomputed already.
659
658
660 - detail_level: if set to 1, more information is given.
659 - detail_level: if set to 1, more information is given.
661 """
660 """
662
661
663 obj_type = type(obj)
662 obj_type = type(obj)
664
663
665 if info is None:
664 if info is None:
666 ismagic = 0
665 ismagic = 0
667 isalias = 0
666 isalias = 0
668 ospace = ''
667 ospace = ''
669 else:
668 else:
670 ismagic = info.ismagic
669 ismagic = info.ismagic
671 isalias = info.isalias
670 isalias = info.isalias
672 ospace = info.namespace
671 ospace = info.namespace
673
672
674 # Get docstring, special-casing aliases:
673 # Get docstring, special-casing aliases:
675 if isalias:
674 if isalias:
676 if not callable(obj):
675 if not callable(obj):
677 try:
676 try:
678 ds = "Alias to the system command:\n %s" % obj[1]
677 ds = "Alias to the system command:\n %s" % obj[1]
679 except:
678 except:
680 ds = "Alias: " + str(obj)
679 ds = "Alias: " + str(obj)
681 else:
680 else:
682 ds = "Alias to " + str(obj)
681 ds = "Alias to " + str(obj)
683 if obj.__doc__:
682 if obj.__doc__:
684 ds += "\nDocstring:\n" + obj.__doc__
683 ds += "\nDocstring:\n" + obj.__doc__
685 else:
684 else:
686 ds = getdoc(obj)
685 ds = getdoc(obj)
687 if ds is None:
686 if ds is None:
688 ds = '<no docstring>'
687 ds = '<no docstring>'
689 if formatter is not None:
688 if formatter is not None:
690 ds = formatter(ds)
689 ds = formatter(ds)
691
690
692 # store output in a dict, we initialize it here and fill it as we go
691 # store output in a dict, we initialize it here and fill it as we go
693 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
692 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
694
693
695 string_max = 200 # max size of strings to show (snipped if longer)
694 string_max = 200 # max size of strings to show (snipped if longer)
696 shalf = int((string_max -5)/2)
695 shalf = int((string_max -5)/2)
697
696
698 if ismagic:
697 if ismagic:
699 obj_type_name = 'Magic function'
698 obj_type_name = 'Magic function'
700 elif isalias:
699 elif isalias:
701 obj_type_name = 'System alias'
700 obj_type_name = 'System alias'
702 else:
701 else:
703 obj_type_name = obj_type.__name__
702 obj_type_name = obj_type.__name__
704 out['type_name'] = obj_type_name
703 out['type_name'] = obj_type_name
705
704
706 try:
705 try:
707 bclass = obj.__class__
706 bclass = obj.__class__
708 out['base_class'] = str(bclass)
707 out['base_class'] = str(bclass)
709 except: pass
708 except: pass
710
709
711 # String form, but snip if too long in ? form (full in ??)
710 # String form, but snip if too long in ? form (full in ??)
712 if detail_level >= self.str_detail_level:
711 if detail_level >= self.str_detail_level:
713 try:
712 try:
714 ostr = str(obj)
713 ostr = str(obj)
715 str_head = 'string_form'
714 str_head = 'string_form'
716 if not detail_level and len(ostr)>string_max:
715 if not detail_level and len(ostr)>string_max:
717 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
716 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
718 ostr = ("\n" + " " * len(str_head.expandtabs())).\
717 ostr = ("\n" + " " * len(str_head.expandtabs())).\
719 join(q.strip() for q in ostr.split("\n"))
718 join(q.strip() for q in ostr.split("\n"))
720 out[str_head] = ostr
719 out[str_head] = ostr
721 except:
720 except:
722 pass
721 pass
723
722
724 if ospace:
723 if ospace:
725 out['namespace'] = ospace
724 out['namespace'] = ospace
726
725
727 # Length (for strings and lists)
726 # Length (for strings and lists)
728 try:
727 try:
729 out['length'] = str(len(obj))
728 out['length'] = str(len(obj))
730 except: pass
729 except: pass
731
730
732 # Filename where object was defined
731 # Filename where object was defined
733 binary_file = False
732 binary_file = False
734 fname = find_file(obj)
733 fname = find_file(obj)
735 if fname is None:
734 if fname is None:
736 # if anything goes wrong, we don't want to show source, so it's as
735 # if anything goes wrong, we don't want to show source, so it's as
737 # if the file was binary
736 # if the file was binary
738 binary_file = True
737 binary_file = True
739 else:
738 else:
740 if fname.endswith(('.so', '.dll', '.pyd')):
739 if fname.endswith(('.so', '.dll', '.pyd')):
741 binary_file = True
740 binary_file = True
742 elif fname.endswith('<string>'):
741 elif fname.endswith('<string>'):
743 fname = 'Dynamically generated function. No source code available.'
742 fname = 'Dynamically generated function. No source code available.'
744 out['file'] = compress_user(fname)
743 out['file'] = compress_user(fname)
745
744
746 # Original source code for a callable, class or property.
745 # Original source code for a callable, class or property.
747 if detail_level:
746 if detail_level:
748 # Flush the source cache because inspect can return out-of-date
747 # Flush the source cache because inspect can return out-of-date
749 # source
748 # source
750 linecache.checkcache()
749 linecache.checkcache()
751 try:
750 try:
752 if isinstance(obj, property) or not binary_file:
751 if isinstance(obj, property) or not binary_file:
753 src = getsource(obj, oname)
752 src = getsource(obj, oname)
754 if src is not None:
753 if src is not None:
755 src = src.rstrip()
754 src = src.rstrip()
756 out['source'] = src
755 out['source'] = src
757
756
758 except Exception:
757 except Exception:
759 pass
758 pass
760
759
761 # Add docstring only if no source is to be shown (avoid repetitions).
760 # Add docstring only if no source is to be shown (avoid repetitions).
762 if ds and out.get('source', None) is None:
761 if ds and out.get('source', None) is None:
763 out['docstring'] = ds
762 out['docstring'] = ds
764
763
765 # Constructor docstring for classes
764 # Constructor docstring for classes
766 if inspect.isclass(obj):
765 if inspect.isclass(obj):
767 out['isclass'] = True
766 out['isclass'] = True
768
767
769 # get the init signature:
768 # get the init signature:
770 try:
769 try:
771 init_def = self._getdef(obj, oname)
770 init_def = self._getdef(obj, oname)
772 except AttributeError:
771 except AttributeError:
773 init_def = None
772 init_def = None
774
773
775 if init_def:
774 if init_def:
776 out['init_definition'] = self.format(init_def)
775 out['init_definition'] = self.format(init_def)
777
776
778 # get the __init__ docstring
777 # get the __init__ docstring
779 try:
778 try:
780 obj_init = obj.__init__
779 obj_init = obj.__init__
781 except AttributeError:
780 except AttributeError:
782 init_ds = None
781 init_ds = None
783 else:
782 else:
784 init_ds = getdoc(obj_init)
783 init_ds = getdoc(obj_init)
785 # Skip Python's auto-generated docstrings
784 # Skip Python's auto-generated docstrings
786 if init_ds == _object_init_docstring:
785 if init_ds == _object_init_docstring:
787 init_ds = None
786 init_ds = None
788
787
789 if init_ds:
788 if init_ds:
790 out['init_docstring'] = init_ds
789 out['init_docstring'] = init_ds
791
790
792 # and class docstring for instances:
791 # and class docstring for instances:
793 else:
792 else:
794 # reconstruct the function definition and print it:
793 # reconstruct the function definition and print it:
795 defln = self._getdef(obj, oname)
794 defln = self._getdef(obj, oname)
796 if defln:
795 if defln:
797 out['definition'] = self.format(defln)
796 out['definition'] = self.format(defln)
798
797
799 # First, check whether the instance docstring is identical to the
798 # First, check whether the instance docstring is identical to the
800 # class one, and print it separately if they don't coincide. In
799 # class one, and print it separately if they don't coincide. In
801 # most cases they will, but it's nice to print all the info for
800 # most cases they will, but it's nice to print all the info for
802 # objects which use instance-customized docstrings.
801 # objects which use instance-customized docstrings.
803 if ds:
802 if ds:
804 try:
803 try:
805 cls = getattr(obj,'__class__')
804 cls = getattr(obj,'__class__')
806 except:
805 except:
807 class_ds = None
806 class_ds = None
808 else:
807 else:
809 class_ds = getdoc(cls)
808 class_ds = getdoc(cls)
810 # Skip Python's auto-generated docstrings
809 # Skip Python's auto-generated docstrings
811 if class_ds in _builtin_type_docstrings:
810 if class_ds in _builtin_type_docstrings:
812 class_ds = None
811 class_ds = None
813 if class_ds and ds != class_ds:
812 if class_ds and ds != class_ds:
814 out['class_docstring'] = class_ds
813 out['class_docstring'] = class_ds
815
814
816 # Next, try to show constructor docstrings
815 # Next, try to show constructor docstrings
817 try:
816 try:
818 init_ds = getdoc(obj.__init__)
817 init_ds = getdoc(obj.__init__)
819 # Skip Python's auto-generated docstrings
818 # Skip Python's auto-generated docstrings
820 if init_ds == _object_init_docstring:
819 if init_ds == _object_init_docstring:
821 init_ds = None
820 init_ds = None
822 except AttributeError:
821 except AttributeError:
823 init_ds = None
822 init_ds = None
824 if init_ds:
823 if init_ds:
825 out['init_docstring'] = init_ds
824 out['init_docstring'] = init_ds
826
825
827 # Call form docstring for callable instances
826 # Call form docstring for callable instances
828 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
827 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
829 call_def = self._getdef(obj.__call__, oname)
828 call_def = self._getdef(obj.__call__, oname)
830 if call_def:
829 if call_def:
831 call_def = self.format(call_def)
830 call_def = self.format(call_def)
832 # it may never be the case that call def and definition differ,
831 # it may never be the case that call def and definition differ,
833 # but don't include the same signature twice
832 # but don't include the same signature twice
834 if call_def != out.get('definition'):
833 if call_def != out.get('definition'):
835 out['call_def'] = call_def
834 out['call_def'] = call_def
836 call_ds = getdoc(obj.__call__)
835 call_ds = getdoc(obj.__call__)
837 # Skip Python's auto-generated docstrings
836 # Skip Python's auto-generated docstrings
838 if call_ds == _func_call_docstring:
837 if call_ds == _func_call_docstring:
839 call_ds = None
838 call_ds = None
840 if call_ds:
839 if call_ds:
841 out['call_docstring'] = call_ds
840 out['call_docstring'] = call_ds
842
841
843 # Compute the object's argspec as a callable. The key is to decide
842 # Compute the object's argspec as a callable. The key is to decide
844 # whether to pull it from the object itself, from its __init__ or
843 # whether to pull it from the object itself, from its __init__ or
845 # from its __call__ method.
844 # from its __call__ method.
846
845
847 if inspect.isclass(obj):
846 if inspect.isclass(obj):
848 # Old-style classes need not have an __init__
847 # Old-style classes need not have an __init__
849 callable_obj = getattr(obj, "__init__", None)
848 callable_obj = getattr(obj, "__init__", None)
850 elif callable(obj):
849 elif callable(obj):
851 callable_obj = obj
850 callable_obj = obj
852 else:
851 else:
853 callable_obj = None
852 callable_obj = None
854
853
855 if callable_obj is not None:
854 if callable_obj is not None:
856 try:
855 try:
857 argspec = getargspec(callable_obj)
856 argspec = getargspec(callable_obj)
858 except (TypeError, AttributeError):
857 except (TypeError, AttributeError):
859 # For extensions/builtins we can't retrieve the argspec
858 # For extensions/builtins we can't retrieve the argspec
860 pass
859 pass
861 else:
860 else:
862 # named tuples' _asdict() method returns an OrderedDict, but we
861 # named tuples' _asdict() method returns an OrderedDict, but we
863 # we want a normal
862 # we want a normal
864 out['argspec'] = argspec_dict = dict(argspec._asdict())
863 out['argspec'] = argspec_dict = dict(argspec._asdict())
865 # We called this varkw before argspec became a named tuple.
864 # We called this varkw before argspec became a named tuple.
866 # With getfullargspec it's also called varkw.
865 # With getfullargspec it's also called varkw.
867 if 'varkw' not in argspec_dict:
866 if 'varkw' not in argspec_dict:
868 argspec_dict['varkw'] = argspec_dict.pop('keywords')
867 argspec_dict['varkw'] = argspec_dict.pop('keywords')
869
868
870 return object_info(**out)
869 return object_info(**out)
871
870
872 def psearch(self,pattern,ns_table,ns_search=[],
871 def psearch(self,pattern,ns_table,ns_search=[],
873 ignore_case=False,show_all=False):
872 ignore_case=False,show_all=False):
874 """Search namespaces with wildcards for objects.
873 """Search namespaces with wildcards for objects.
875
874
876 Arguments:
875 Arguments:
877
876
878 - pattern: string containing shell-like wildcards to use in namespace
877 - pattern: string containing shell-like wildcards to use in namespace
879 searches and optionally a type specification to narrow the search to
878 searches and optionally a type specification to narrow the search to
880 objects of that type.
879 objects of that type.
881
880
882 - ns_table: dict of name->namespaces for search.
881 - ns_table: dict of name->namespaces for search.
883
882
884 Optional arguments:
883 Optional arguments:
885
884
886 - ns_search: list of namespace names to include in search.
885 - ns_search: list of namespace names to include in search.
887
886
888 - ignore_case(False): make the search case-insensitive.
887 - ignore_case(False): make the search case-insensitive.
889
888
890 - show_all(False): show all names, including those starting with
889 - show_all(False): show all names, including those starting with
891 underscores.
890 underscores.
892 """
891 """
893 #print 'ps pattern:<%r>' % pattern # dbg
892 #print 'ps pattern:<%r>' % pattern # dbg
894
893
895 # defaults
894 # defaults
896 type_pattern = 'all'
895 type_pattern = 'all'
897 filter = ''
896 filter = ''
898
897
899 cmds = pattern.split()
898 cmds = pattern.split()
900 len_cmds = len(cmds)
899 len_cmds = len(cmds)
901 if len_cmds == 1:
900 if len_cmds == 1:
902 # Only filter pattern given
901 # Only filter pattern given
903 filter = cmds[0]
902 filter = cmds[0]
904 elif len_cmds == 2:
903 elif len_cmds == 2:
905 # Both filter and type specified
904 # Both filter and type specified
906 filter,type_pattern = cmds
905 filter,type_pattern = cmds
907 else:
906 else:
908 raise ValueError('invalid argument string for psearch: <%s>' %
907 raise ValueError('invalid argument string for psearch: <%s>' %
909 pattern)
908 pattern)
910
909
911 # filter search namespaces
910 # filter search namespaces
912 for name in ns_search:
911 for name in ns_search:
913 if name not in ns_table:
912 if name not in ns_table:
914 raise ValueError('invalid namespace <%s>. Valid names: %s' %
913 raise ValueError('invalid namespace <%s>. Valid names: %s' %
915 (name,ns_table.keys()))
914 (name,ns_table.keys()))
916
915
917 #print 'type_pattern:',type_pattern # dbg
916 #print 'type_pattern:',type_pattern # dbg
918 search_result, namespaces_seen = set(), set()
917 search_result, namespaces_seen = set(), set()
919 for ns_name in ns_search:
918 for ns_name in ns_search:
920 ns = ns_table[ns_name]
919 ns = ns_table[ns_name]
921 # Normally, locals and globals are the same, so we just check one.
920 # Normally, locals and globals are the same, so we just check one.
922 if id(ns) in namespaces_seen:
921 if id(ns) in namespaces_seen:
923 continue
922 continue
924 namespaces_seen.add(id(ns))
923 namespaces_seen.add(id(ns))
925 tmp_res = list_namespace(ns, type_pattern, filter,
924 tmp_res = list_namespace(ns, type_pattern, filter,
926 ignore_case=ignore_case, show_all=show_all)
925 ignore_case=ignore_case, show_all=show_all)
927 search_result.update(tmp_res)
926 search_result.update(tmp_res)
928
927
929 page.page('\n'.join(sorted(search_result)))
928 page.page('\n'.join(sorted(search_result)))
@@ -1,385 +1,384 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Notes
5 Notes
6 -----
6 -----
7
7
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
9 rid of that dependency, we could move it there.
9 rid of that dependency, we could move it there.
10 -----
10 -----
11 """
11 """
12
12
13 # Copyright (c) IPython Development Team.
13 # Copyright (c) IPython Development Team.
14 # Distributed under the terms of the Modified BSD License.
14 # Distributed under the terms of the Modified BSD License.
15
15
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22
22
23 from io import UnsupportedOperation
23 from io import UnsupportedOperation
24
24
25 from IPython import get_ipython
25 from IPython import get_ipython
26 from IPython.core.display import display
26 from IPython.core.display import display
27 from IPython.core.error import TryNext
27 from IPython.core.error import TryNext
28 from IPython.utils.data import chop
28 from IPython.utils.data import chop
29 from IPython.utils import io
30 from IPython.utils.process import system
29 from IPython.utils.process import system
31 from IPython.utils.terminal import get_terminal_size
30 from IPython.utils.terminal import get_terminal_size
32 from IPython.utils import py3compat
31 from IPython.utils import py3compat
33
32
34
33
35 def display_page(strng, start=0, screen_lines=25):
34 def display_page(strng, start=0, screen_lines=25):
36 """Just display, no paging. screen_lines is ignored."""
35 """Just display, no paging. screen_lines is ignored."""
37 if isinstance(strng, dict):
36 if isinstance(strng, dict):
38 data = strng
37 data = strng
39 else:
38 else:
40 if start:
39 if start:
41 strng = u'\n'.join(strng.splitlines()[start:])
40 strng = u'\n'.join(strng.splitlines()[start:])
42 data = {'text/plain': strng}
41 data = {'text/plain': strng}
43 display(data, raw=True)
42 display(data, raw=True)
44
43
45
44
46 def as_hook(page_func):
45 def as_hook(page_func):
47 """Wrap a pager func to strip the `self` arg
46 """Wrap a pager func to strip the `self` arg
48
47
49 so it can be called as a hook.
48 so it can be called as a hook.
50 """
49 """
51 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
50 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
52
51
53
52
54 esc_re = re.compile(r"(\x1b[^m]+m)")
53 esc_re = re.compile(r"(\x1b[^m]+m)")
55
54
56 def page_dumb(strng, start=0, screen_lines=25):
55 def page_dumb(strng, start=0, screen_lines=25):
57 """Very dumb 'pager' in Python, for when nothing else works.
56 """Very dumb 'pager' in Python, for when nothing else works.
58
57
59 Only moves forward, same interface as page(), except for pager_cmd and
58 Only moves forward, same interface as page(), except for pager_cmd and
60 mode."""
59 mode."""
61
60
62 out_ln = strng.splitlines()[start:]
61 out_ln = strng.splitlines()[start:]
63 screens = chop(out_ln,screen_lines-1)
62 screens = chop(out_ln,screen_lines-1)
64 if len(screens) == 1:
63 if len(screens) == 1:
65 print(os.linesep.join(screens[0]), file=io.stdout)
64 print(os.linesep.join(screens[0]))
66 else:
65 else:
67 last_escape = ""
66 last_escape = ""
68 for scr in screens[0:-1]:
67 for scr in screens[0:-1]:
69 hunk = os.linesep.join(scr)
68 hunk = os.linesep.join(scr)
70 print(last_escape + hunk, file=io.stdout)
69 print(last_escape + hunk)
71 if not page_more():
70 if not page_more():
72 return
71 return
73 esc_list = esc_re.findall(hunk)
72 esc_list = esc_re.findall(hunk)
74 if len(esc_list) > 0:
73 if len(esc_list) > 0:
75 last_escape = esc_list[-1]
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 def _detect_screen_size(screen_lines_def):
77 def _detect_screen_size(screen_lines_def):
79 """Attempt to work out the number of lines on the screen.
78 """Attempt to work out the number of lines on the screen.
80
79
81 This is called by page(). It can raise an error (e.g. when run in the
80 This is called by page(). It can raise an error (e.g. when run in the
82 test suite), so it's separated out so it can easily be called in a try block.
81 test suite), so it's separated out so it can easily be called in a try block.
83 """
82 """
84 TERM = os.environ.get('TERM',None)
83 TERM = os.environ.get('TERM',None)
85 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
84 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
86 # curses causes problems on many terminals other than xterm, and
85 # curses causes problems on many terminals other than xterm, and
87 # some termios calls lock up on Sun OS5.
86 # some termios calls lock up on Sun OS5.
88 return screen_lines_def
87 return screen_lines_def
89
88
90 try:
89 try:
91 import termios
90 import termios
92 import curses
91 import curses
93 except ImportError:
92 except ImportError:
94 return screen_lines_def
93 return screen_lines_def
95
94
96 # There is a bug in curses, where *sometimes* it fails to properly
95 # There is a bug in curses, where *sometimes* it fails to properly
97 # initialize, and then after the endwin() call is made, the
96 # initialize, and then after the endwin() call is made, the
98 # terminal is left in an unusable state. Rather than trying to
97 # terminal is left in an unusable state. Rather than trying to
99 # check everytime for this (by requesting and comparing termios
98 # check everytime for this (by requesting and comparing termios
100 # flags each time), we just save the initial terminal state and
99 # flags each time), we just save the initial terminal state and
101 # unconditionally reset it every time. It's cheaper than making
100 # unconditionally reset it every time. It's cheaper than making
102 # the checks.
101 # the checks.
103 try:
102 try:
104 term_flags = termios.tcgetattr(sys.stdout)
103 term_flags = termios.tcgetattr(sys.stdout)
105 except termios.error as err:
104 except termios.error as err:
106 # can fail on Linux 2.6, pager_page will catch the TypeError
105 # can fail on Linux 2.6, pager_page will catch the TypeError
107 raise TypeError('termios error: {0}'.format(err))
106 raise TypeError('termios error: {0}'.format(err))
108
107
109 # Curses modifies the stdout buffer size by default, which messes
108 # Curses modifies the stdout buffer size by default, which messes
110 # up Python's normal stdout buffering. This would manifest itself
109 # up Python's normal stdout buffering. This would manifest itself
111 # to IPython users as delayed printing on stdout after having used
110 # to IPython users as delayed printing on stdout after having used
112 # the pager.
111 # the pager.
113 #
112 #
114 # We can prevent this by manually setting the NCURSES_NO_SETBUF
113 # We can prevent this by manually setting the NCURSES_NO_SETBUF
115 # environment variable. For more details, see:
114 # environment variable. For more details, see:
116 # http://bugs.python.org/issue10144
115 # http://bugs.python.org/issue10144
117 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
116 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
118 os.environ['NCURSES_NO_SETBUF'] = ''
117 os.environ['NCURSES_NO_SETBUF'] = ''
119
118
120 # Proceed with curses initialization
119 # Proceed with curses initialization
121 try:
120 try:
122 scr = curses.initscr()
121 scr = curses.initscr()
123 except AttributeError:
122 except AttributeError:
124 # Curses on Solaris may not be complete, so we can't use it there
123 # Curses on Solaris may not be complete, so we can't use it there
125 return screen_lines_def
124 return screen_lines_def
126
125
127 screen_lines_real,screen_cols = scr.getmaxyx()
126 screen_lines_real,screen_cols = scr.getmaxyx()
128 curses.endwin()
127 curses.endwin()
129
128
130 # Restore environment
129 # Restore environment
131 if NCURSES_NO_SETBUF is None:
130 if NCURSES_NO_SETBUF is None:
132 del os.environ['NCURSES_NO_SETBUF']
131 del os.environ['NCURSES_NO_SETBUF']
133 else:
132 else:
134 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
133 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
135
134
136 # Restore terminal state in case endwin() didn't.
135 # Restore terminal state in case endwin() didn't.
137 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
136 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
138 # Now we have what we needed: the screen size in rows/columns
137 # Now we have what we needed: the screen size in rows/columns
139 return screen_lines_real
138 return screen_lines_real
140 #print '***Screen size:',screen_lines_real,'lines x',\
139 #print '***Screen size:',screen_lines_real,'lines x',\
141 #screen_cols,'columns.' # dbg
140 #screen_cols,'columns.' # dbg
142
141
143 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
142 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
144 """Display a string, piping through a pager after a certain length.
143 """Display a string, piping through a pager after a certain length.
145
144
146 strng can be a mime-bundle dict, supplying multiple representations,
145 strng can be a mime-bundle dict, supplying multiple representations,
147 keyed by mime-type.
146 keyed by mime-type.
148
147
149 The screen_lines parameter specifies the number of *usable* lines of your
148 The screen_lines parameter specifies the number of *usable* lines of your
150 terminal screen (total lines minus lines you need to reserve to show other
149 terminal screen (total lines minus lines you need to reserve to show other
151 information).
150 information).
152
151
153 If you set screen_lines to a number <=0, page() will try to auto-determine
152 If you set screen_lines to a number <=0, page() will try to auto-determine
154 your screen size and will only use up to (screen_size+screen_lines) for
153 your screen size and will only use up to (screen_size+screen_lines) for
155 printing, paging after that. That is, if you want auto-detection but need
154 printing, paging after that. That is, if you want auto-detection but need
156 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
155 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
157 auto-detection without any lines reserved simply use screen_lines = 0.
156 auto-detection without any lines reserved simply use screen_lines = 0.
158
157
159 If a string won't fit in the allowed lines, it is sent through the
158 If a string won't fit in the allowed lines, it is sent through the
160 specified pager command. If none given, look for PAGER in the environment,
159 specified pager command. If none given, look for PAGER in the environment,
161 and ultimately default to less.
160 and ultimately default to less.
162
161
163 If no system pager works, the string is sent through a 'dumb pager'
162 If no system pager works, the string is sent through a 'dumb pager'
164 written in python, very simplistic.
163 written in python, very simplistic.
165 """
164 """
166
165
167 # for compatibility with mime-bundle form:
166 # for compatibility with mime-bundle form:
168 if isinstance(strng, dict):
167 if isinstance(strng, dict):
169 strng = strng['text/plain']
168 strng = strng['text/plain']
170
169
171 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
170 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
172 TERM = os.environ.get('TERM','dumb')
171 TERM = os.environ.get('TERM','dumb')
173 if TERM in ['dumb','emacs'] and os.name != 'nt':
172 if TERM in ['dumb','emacs'] and os.name != 'nt':
174 print(strng)
173 print(strng)
175 return
174 return
176 # chop off the topmost part of the string we don't want to see
175 # chop off the topmost part of the string we don't want to see
177 str_lines = strng.splitlines()[start:]
176 str_lines = strng.splitlines()[start:]
178 str_toprint = os.linesep.join(str_lines)
177 str_toprint = os.linesep.join(str_lines)
179 num_newlines = len(str_lines)
178 num_newlines = len(str_lines)
180 len_str = len(str_toprint)
179 len_str = len(str_toprint)
181
180
182 # Dumb heuristics to guesstimate number of on-screen lines the string
181 # Dumb heuristics to guesstimate number of on-screen lines the string
183 # takes. Very basic, but good enough for docstrings in reasonable
182 # takes. Very basic, but good enough for docstrings in reasonable
184 # terminals. If someone later feels like refining it, it's not hard.
183 # terminals. If someone later feels like refining it, it's not hard.
185 numlines = max(num_newlines,int(len_str/80)+1)
184 numlines = max(num_newlines,int(len_str/80)+1)
186
185
187 screen_lines_def = get_terminal_size()[1]
186 screen_lines_def = get_terminal_size()[1]
188
187
189 # auto-determine screen size
188 # auto-determine screen size
190 if screen_lines <= 0:
189 if screen_lines <= 0:
191 try:
190 try:
192 screen_lines += _detect_screen_size(screen_lines_def)
191 screen_lines += _detect_screen_size(screen_lines_def)
193 except (TypeError, UnsupportedOperation):
192 except (TypeError, UnsupportedOperation):
194 print(str_toprint, file=io.stdout)
193 print(str_toprint)
195 return
194 return
196
195
197 #print 'numlines',numlines,'screenlines',screen_lines # dbg
196 #print 'numlines',numlines,'screenlines',screen_lines # dbg
198 if numlines <= screen_lines :
197 if numlines <= screen_lines :
199 #print '*** normal print' # dbg
198 #print '*** normal print' # dbg
200 print(str_toprint, file=io.stdout)
199 print(str_toprint)
201 else:
200 else:
202 # Try to open pager and default to internal one if that fails.
201 # Try to open pager and default to internal one if that fails.
203 # All failure modes are tagged as 'retval=1', to match the return
202 # All failure modes are tagged as 'retval=1', to match the return
204 # value of a failed system command. If any intermediate attempt
203 # value of a failed system command. If any intermediate attempt
205 # sets retval to 1, at the end we resort to our own page_dumb() pager.
204 # sets retval to 1, at the end we resort to our own page_dumb() pager.
206 pager_cmd = get_pager_cmd(pager_cmd)
205 pager_cmd = get_pager_cmd(pager_cmd)
207 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
206 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
208 if os.name == 'nt':
207 if os.name == 'nt':
209 if pager_cmd.startswith('type'):
208 if pager_cmd.startswith('type'):
210 # The default WinXP 'type' command is failing on complex strings.
209 # The default WinXP 'type' command is failing on complex strings.
211 retval = 1
210 retval = 1
212 else:
211 else:
213 fd, tmpname = tempfile.mkstemp('.txt')
212 fd, tmpname = tempfile.mkstemp('.txt')
214 try:
213 try:
215 os.close(fd)
214 os.close(fd)
216 with open(tmpname, 'wt') as tmpfile:
215 with open(tmpname, 'wt') as tmpfile:
217 tmpfile.write(strng)
216 tmpfile.write(strng)
218 cmd = "%s < %s" % (pager_cmd, tmpname)
217 cmd = "%s < %s" % (pager_cmd, tmpname)
219 # tmpfile needs to be closed for windows
218 # tmpfile needs to be closed for windows
220 if os.system(cmd):
219 if os.system(cmd):
221 retval = 1
220 retval = 1
222 else:
221 else:
223 retval = None
222 retval = None
224 finally:
223 finally:
225 os.remove(tmpname)
224 os.remove(tmpname)
226 else:
225 else:
227 try:
226 try:
228 retval = None
227 retval = None
229 # if I use popen4, things hang. No idea why.
228 # if I use popen4, things hang. No idea why.
230 #pager,shell_out = os.popen4(pager_cmd)
229 #pager,shell_out = os.popen4(pager_cmd)
231 pager = os.popen(pager_cmd, 'w')
230 pager = os.popen(pager_cmd, 'w')
232 try:
231 try:
233 pager_encoding = pager.encoding or sys.stdout.encoding
232 pager_encoding = pager.encoding or sys.stdout.encoding
234 pager.write(py3compat.cast_bytes_py2(
233 pager.write(py3compat.cast_bytes_py2(
235 strng, encoding=pager_encoding))
234 strng, encoding=pager_encoding))
236 finally:
235 finally:
237 retval = pager.close()
236 retval = pager.close()
238 except IOError as msg: # broken pipe when user quits
237 except IOError as msg: # broken pipe when user quits
239 if msg.args == (32, 'Broken pipe'):
238 if msg.args == (32, 'Broken pipe'):
240 retval = None
239 retval = None
241 else:
240 else:
242 retval = 1
241 retval = 1
243 except OSError:
242 except OSError:
244 # Other strange problems, sometimes seen in Win2k/cygwin
243 # Other strange problems, sometimes seen in Win2k/cygwin
245 retval = 1
244 retval = 1
246 if retval is not None:
245 if retval is not None:
247 page_dumb(strng,screen_lines=screen_lines)
246 page_dumb(strng,screen_lines=screen_lines)
248
247
249
248
250 def page(data, start=0, screen_lines=0, pager_cmd=None):
249 def page(data, start=0, screen_lines=0, pager_cmd=None):
251 """Display content in a pager, piping through a pager after a certain length.
250 """Display content in a pager, piping through a pager after a certain length.
252
251
253 data can be a mime-bundle dict, supplying multiple representations,
252 data can be a mime-bundle dict, supplying multiple representations,
254 keyed by mime-type, or text.
253 keyed by mime-type, or text.
255
254
256 Pager is dispatched via the `show_in_pager` IPython hook.
255 Pager is dispatched via the `show_in_pager` IPython hook.
257 If no hook is registered, `pager_page` will be used.
256 If no hook is registered, `pager_page` will be used.
258 """
257 """
259 # Some routines may auto-compute start offsets incorrectly and pass a
258 # Some routines may auto-compute start offsets incorrectly and pass a
260 # negative value. Offset to 0 for robustness.
259 # negative value. Offset to 0 for robustness.
261 start = max(0, start)
260 start = max(0, start)
262
261
263 # first, try the hook
262 # first, try the hook
264 ip = get_ipython()
263 ip = get_ipython()
265 if ip:
264 if ip:
266 try:
265 try:
267 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
266 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
268 return
267 return
269 except TryNext:
268 except TryNext:
270 pass
269 pass
271
270
272 # fallback on default pager
271 # fallback on default pager
273 return pager_page(data, start, screen_lines, pager_cmd)
272 return pager_page(data, start, screen_lines, pager_cmd)
274
273
275
274
276 def page_file(fname, start=0, pager_cmd=None):
275 def page_file(fname, start=0, pager_cmd=None):
277 """Page a file, using an optional pager command and starting line.
276 """Page a file, using an optional pager command and starting line.
278 """
277 """
279
278
280 pager_cmd = get_pager_cmd(pager_cmd)
279 pager_cmd = get_pager_cmd(pager_cmd)
281 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
280 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
282
281
283 try:
282 try:
284 if os.environ['TERM'] in ['emacs','dumb']:
283 if os.environ['TERM'] in ['emacs','dumb']:
285 raise EnvironmentError
284 raise EnvironmentError
286 system(pager_cmd + ' ' + fname)
285 system(pager_cmd + ' ' + fname)
287 except:
286 except:
288 try:
287 try:
289 if start > 0:
288 if start > 0:
290 start -= 1
289 start -= 1
291 page(open(fname).read(),start)
290 page(open(fname).read(),start)
292 except:
291 except:
293 print('Unable to show file',repr(fname))
292 print('Unable to show file',repr(fname))
294
293
295
294
296 def get_pager_cmd(pager_cmd=None):
295 def get_pager_cmd(pager_cmd=None):
297 """Return a pager command.
296 """Return a pager command.
298
297
299 Makes some attempts at finding an OS-correct one.
298 Makes some attempts at finding an OS-correct one.
300 """
299 """
301 if os.name == 'posix':
300 if os.name == 'posix':
302 default_pager_cmd = 'less -r' # -r for color control sequences
301 default_pager_cmd = 'less -r' # -r for color control sequences
303 elif os.name in ['nt','dos']:
302 elif os.name in ['nt','dos']:
304 default_pager_cmd = 'type'
303 default_pager_cmd = 'type'
305
304
306 if pager_cmd is None:
305 if pager_cmd is None:
307 try:
306 try:
308 pager_cmd = os.environ['PAGER']
307 pager_cmd = os.environ['PAGER']
309 except:
308 except:
310 pager_cmd = default_pager_cmd
309 pager_cmd = default_pager_cmd
311
310
312 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''):
311 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''):
313 pager_cmd += ' -r'
312 pager_cmd += ' -r'
314
313
315 return pager_cmd
314 return pager_cmd
316
315
317
316
318 def get_pager_start(pager, start):
317 def get_pager_start(pager, start):
319 """Return the string for paging files with an offset.
318 """Return the string for paging files with an offset.
320
319
321 This is the '+N' argument which less and more (under Unix) accept.
320 This is the '+N' argument which less and more (under Unix) accept.
322 """
321 """
323
322
324 if pager in ['less','more']:
323 if pager in ['less','more']:
325 if start:
324 if start:
326 start_string = '+' + str(start)
325 start_string = '+' + str(start)
327 else:
326 else:
328 start_string = ''
327 start_string = ''
329 else:
328 else:
330 start_string = ''
329 start_string = ''
331 return start_string
330 return start_string
332
331
333
332
334 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
333 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
335 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
334 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
336 import msvcrt
335 import msvcrt
337 def page_more():
336 def page_more():
338 """ Smart pausing between pages
337 """ Smart pausing between pages
339
338
340 @return: True if need print more lines, False if quit
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 ans = msvcrt.getwch()
342 ans = msvcrt.getwch()
344 if ans in ("q", "Q"):
343 if ans in ("q", "Q"):
345 result = False
344 result = False
346 else:
345 else:
347 result = True
346 result = True
348 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
347 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
349 return result
348 return result
350 else:
349 else:
351 def page_more():
350 def page_more():
352 ans = py3compat.input('---Return to continue, q to quit--- ')
351 ans = py3compat.input('---Return to continue, q to quit--- ')
353 if ans.lower().startswith('q'):
352 if ans.lower().startswith('q'):
354 return False
353 return False
355 else:
354 else:
356 return True
355 return True
357
356
358
357
359 def snip_print(str,width = 75,print_full = 0,header = ''):
358 def snip_print(str,width = 75,print_full = 0,header = ''):
360 """Print a string snipping the midsection to fit in width.
359 """Print a string snipping the midsection to fit in width.
361
360
362 print_full: mode control:
361 print_full: mode control:
363
362
364 - 0: only snip long strings
363 - 0: only snip long strings
365 - 1: send to page() directly.
364 - 1: send to page() directly.
366 - 2: snip long strings and ask for full length viewing with page()
365 - 2: snip long strings and ask for full length viewing with page()
367
366
368 Return 1 if snipping was necessary, 0 otherwise."""
367 Return 1 if snipping was necessary, 0 otherwise."""
369
368
370 if print_full == 1:
369 if print_full == 1:
371 page(header+str)
370 page(header+str)
372 return 0
371 return 0
373
372
374 print(header, end=' ')
373 print(header, end=' ')
375 if len(str) < width:
374 if len(str) < width:
376 print(str)
375 print(str)
377 snip = 0
376 snip = 0
378 else:
377 else:
379 whalf = int((width -5)/2)
378 whalf = int((width -5)/2)
380 print(str[:whalf] + ' <...> ' + str[-whalf:])
379 print(str[:whalf] + ' <...> ' + str[-whalf:])
381 snip = 1
380 snip = 1
382 if snip and print_full == 2:
381 if snip and print_full == 2:
383 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
382 if py3compat.input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
384 page(str)
383 page(str)
385 return snip
384 return snip
@@ -1,943 +1,929 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import ast
12 import ast
13 import os
13 import os
14 import signal
14 import signal
15 import shutil
15 import shutil
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import unittest
18 import unittest
19 try:
19 try:
20 from unittest import mock
20 from unittest import mock
21 except ImportError:
21 except ImportError:
22 import mock
22 import mock
23 from os.path import join
23 from os.path import join
24
24
25 import nose.tools as nt
25 import nose.tools as nt
26
26
27 from IPython.core.error import InputRejected
27 from IPython.core.error import InputRejected
28 from IPython.core.inputtransformer import InputTransformer
28 from IPython.core.inputtransformer import InputTransformer
29 from IPython.testing.decorators import (
29 from IPython.testing.decorators import (
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 )
31 )
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.process import find_cmd
33 from IPython.utils.process import find_cmd
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35 from IPython.utils.py3compat import unicode_type, PY3
35 from IPython.utils.py3compat import unicode_type, PY3
36
36
37 if PY3:
37 if PY3:
38 from io import StringIO
38 from io import StringIO
39 else:
39 else:
40 from StringIO import StringIO
40 from StringIO import StringIO
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals
43 # Globals
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # This is used by every single test, no point repeating it ad nauseam
45 # This is used by every single test, no point repeating it ad nauseam
46 ip = get_ipython()
46 ip = get_ipython()
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # Tests
49 # Tests
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52 class DerivedInterrupt(KeyboardInterrupt):
52 class DerivedInterrupt(KeyboardInterrupt):
53 pass
53 pass
54
54
55 class InteractiveShellTestCase(unittest.TestCase):
55 class InteractiveShellTestCase(unittest.TestCase):
56 def test_naked_string_cells(self):
56 def test_naked_string_cells(self):
57 """Test that cells with only naked strings are fully executed"""
57 """Test that cells with only naked strings are fully executed"""
58 # First, single-line inputs
58 # First, single-line inputs
59 ip.run_cell('"a"\n')
59 ip.run_cell('"a"\n')
60 self.assertEqual(ip.user_ns['_'], 'a')
60 self.assertEqual(ip.user_ns['_'], 'a')
61 # And also multi-line cells
61 # And also multi-line cells
62 ip.run_cell('"""a\nb"""\n')
62 ip.run_cell('"""a\nb"""\n')
63 self.assertEqual(ip.user_ns['_'], 'a\nb')
63 self.assertEqual(ip.user_ns['_'], 'a\nb')
64
64
65 def test_run_empty_cell(self):
65 def test_run_empty_cell(self):
66 """Just make sure we don't get a horrible error with a blank
66 """Just make sure we don't get a horrible error with a blank
67 cell of input. Yes, I did overlook that."""
67 cell of input. Yes, I did overlook that."""
68 old_xc = ip.execution_count
68 old_xc = ip.execution_count
69 res = ip.run_cell('')
69 res = ip.run_cell('')
70 self.assertEqual(ip.execution_count, old_xc)
70 self.assertEqual(ip.execution_count, old_xc)
71 self.assertEqual(res.execution_count, None)
71 self.assertEqual(res.execution_count, None)
72
72
73 def test_run_cell_multiline(self):
73 def test_run_cell_multiline(self):
74 """Multi-block, multi-line cells must execute correctly.
74 """Multi-block, multi-line cells must execute correctly.
75 """
75 """
76 src = '\n'.join(["x=1",
76 src = '\n'.join(["x=1",
77 "y=2",
77 "y=2",
78 "if 1:",
78 "if 1:",
79 " x += 1",
79 " x += 1",
80 " y += 1",])
80 " y += 1",])
81 res = ip.run_cell(src)
81 res = ip.run_cell(src)
82 self.assertEqual(ip.user_ns['x'], 2)
82 self.assertEqual(ip.user_ns['x'], 2)
83 self.assertEqual(ip.user_ns['y'], 3)
83 self.assertEqual(ip.user_ns['y'], 3)
84 self.assertEqual(res.success, True)
84 self.assertEqual(res.success, True)
85 self.assertEqual(res.result, None)
85 self.assertEqual(res.result, None)
86
86
87 def test_multiline_string_cells(self):
87 def test_multiline_string_cells(self):
88 "Code sprinkled with multiline strings should execute (GH-306)"
88 "Code sprinkled with multiline strings should execute (GH-306)"
89 ip.run_cell('tmp=0')
89 ip.run_cell('tmp=0')
90 self.assertEqual(ip.user_ns['tmp'], 0)
90 self.assertEqual(ip.user_ns['tmp'], 0)
91 res = ip.run_cell('tmp=1;"""a\nb"""\n')
91 res = ip.run_cell('tmp=1;"""a\nb"""\n')
92 self.assertEqual(ip.user_ns['tmp'], 1)
92 self.assertEqual(ip.user_ns['tmp'], 1)
93 self.assertEqual(res.success, True)
93 self.assertEqual(res.success, True)
94 self.assertEqual(res.result, "a\nb")
94 self.assertEqual(res.result, "a\nb")
95
95
96 def test_dont_cache_with_semicolon(self):
96 def test_dont_cache_with_semicolon(self):
97 "Ending a line with semicolon should not cache the returned object (GH-307)"
97 "Ending a line with semicolon should not cache the returned object (GH-307)"
98 oldlen = len(ip.user_ns['Out'])
98 oldlen = len(ip.user_ns['Out'])
99 for cell in ['1;', '1;1;']:
99 for cell in ['1;', '1;1;']:
100 res = ip.run_cell(cell, store_history=True)
100 res = ip.run_cell(cell, store_history=True)
101 newlen = len(ip.user_ns['Out'])
101 newlen = len(ip.user_ns['Out'])
102 self.assertEqual(oldlen, newlen)
102 self.assertEqual(oldlen, newlen)
103 self.assertIsNone(res.result)
103 self.assertIsNone(res.result)
104 i = 0
104 i = 0
105 #also test the default caching behavior
105 #also test the default caching behavior
106 for cell in ['1', '1;1']:
106 for cell in ['1', '1;1']:
107 ip.run_cell(cell, store_history=True)
107 ip.run_cell(cell, store_history=True)
108 newlen = len(ip.user_ns['Out'])
108 newlen = len(ip.user_ns['Out'])
109 i += 1
109 i += 1
110 self.assertEqual(oldlen+i, newlen)
110 self.assertEqual(oldlen+i, newlen)
111
111
112 def test_syntax_error(self):
112 def test_syntax_error(self):
113 res = ip.run_cell("raise = 3")
113 res = ip.run_cell("raise = 3")
114 self.assertIsInstance(res.error_before_exec, SyntaxError)
114 self.assertIsInstance(res.error_before_exec, SyntaxError)
115
115
116 def test_In_variable(self):
116 def test_In_variable(self):
117 "Verify that In variable grows with user input (GH-284)"
117 "Verify that In variable grows with user input (GH-284)"
118 oldlen = len(ip.user_ns['In'])
118 oldlen = len(ip.user_ns['In'])
119 ip.run_cell('1;', store_history=True)
119 ip.run_cell('1;', store_history=True)
120 newlen = len(ip.user_ns['In'])
120 newlen = len(ip.user_ns['In'])
121 self.assertEqual(oldlen+1, newlen)
121 self.assertEqual(oldlen+1, newlen)
122 self.assertEqual(ip.user_ns['In'][-1],'1;')
122 self.assertEqual(ip.user_ns['In'][-1],'1;')
123
123
124 def test_magic_names_in_string(self):
124 def test_magic_names_in_string(self):
125 ip.run_cell('a = """\n%exit\n"""')
125 ip.run_cell('a = """\n%exit\n"""')
126 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
126 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
127
127
128 def test_trailing_newline(self):
128 def test_trailing_newline(self):
129 """test that running !(command) does not raise a SyntaxError"""
129 """test that running !(command) does not raise a SyntaxError"""
130 ip.run_cell('!(true)\n', False)
130 ip.run_cell('!(true)\n', False)
131 ip.run_cell('!(true)\n\n\n', False)
131 ip.run_cell('!(true)\n\n\n', False)
132
132
133 def test_gh_597(self):
133 def test_gh_597(self):
134 """Pretty-printing lists of objects with non-ascii reprs may cause
134 """Pretty-printing lists of objects with non-ascii reprs may cause
135 problems."""
135 problems."""
136 class Spam(object):
136 class Spam(object):
137 def __repr__(self):
137 def __repr__(self):
138 return "\xe9"*50
138 return "\xe9"*50
139 import IPython.core.formatters
139 import IPython.core.formatters
140 f = IPython.core.formatters.PlainTextFormatter()
140 f = IPython.core.formatters.PlainTextFormatter()
141 f([Spam(),Spam()])
141 f([Spam(),Spam()])
142
142
143
143
144 def test_future_flags(self):
144 def test_future_flags(self):
145 """Check that future flags are used for parsing code (gh-777)"""
145 """Check that future flags are used for parsing code (gh-777)"""
146 ip.run_cell('from __future__ import print_function')
146 ip.run_cell('from __future__ import print_function')
147 try:
147 try:
148 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
148 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
149 assert 'prfunc_return_val' in ip.user_ns
149 assert 'prfunc_return_val' in ip.user_ns
150 finally:
150 finally:
151 # Reset compiler flags so we don't mess up other tests.
151 # Reset compiler flags so we don't mess up other tests.
152 ip.compile.reset_compiler_flags()
152 ip.compile.reset_compiler_flags()
153
153
154 def test_future_unicode(self):
154 def test_future_unicode(self):
155 """Check that unicode_literals is imported from __future__ (gh #786)"""
155 """Check that unicode_literals is imported from __future__ (gh #786)"""
156 try:
156 try:
157 ip.run_cell(u'byte_str = "a"')
157 ip.run_cell(u'byte_str = "a"')
158 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
158 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
159 ip.run_cell('from __future__ import unicode_literals')
159 ip.run_cell('from __future__ import unicode_literals')
160 ip.run_cell(u'unicode_str = "a"')
160 ip.run_cell(u'unicode_str = "a"')
161 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
161 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
162 finally:
162 finally:
163 # Reset compiler flags so we don't mess up other tests.
163 # Reset compiler flags so we don't mess up other tests.
164 ip.compile.reset_compiler_flags()
164 ip.compile.reset_compiler_flags()
165
165
166 def test_can_pickle(self):
166 def test_can_pickle(self):
167 "Can we pickle objects defined interactively (GH-29)"
167 "Can we pickle objects defined interactively (GH-29)"
168 ip = get_ipython()
168 ip = get_ipython()
169 ip.reset()
169 ip.reset()
170 ip.run_cell(("class Mylist(list):\n"
170 ip.run_cell(("class Mylist(list):\n"
171 " def __init__(self,x=[]):\n"
171 " def __init__(self,x=[]):\n"
172 " list.__init__(self,x)"))
172 " list.__init__(self,x)"))
173 ip.run_cell("w=Mylist([1,2,3])")
173 ip.run_cell("w=Mylist([1,2,3])")
174
174
175 from pickle import dumps
175 from pickle import dumps
176
176
177 # We need to swap in our main module - this is only necessary
177 # We need to swap in our main module - this is only necessary
178 # inside the test framework, because IPython puts the interactive module
178 # inside the test framework, because IPython puts the interactive module
179 # in place (but the test framework undoes this).
179 # in place (but the test framework undoes this).
180 _main = sys.modules['__main__']
180 _main = sys.modules['__main__']
181 sys.modules['__main__'] = ip.user_module
181 sys.modules['__main__'] = ip.user_module
182 try:
182 try:
183 res = dumps(ip.user_ns["w"])
183 res = dumps(ip.user_ns["w"])
184 finally:
184 finally:
185 sys.modules['__main__'] = _main
185 sys.modules['__main__'] = _main
186 self.assertTrue(isinstance(res, bytes))
186 self.assertTrue(isinstance(res, bytes))
187
187
188 def test_global_ns(self):
188 def test_global_ns(self):
189 "Code in functions must be able to access variables outside them."
189 "Code in functions must be able to access variables outside them."
190 ip = get_ipython()
190 ip = get_ipython()
191 ip.run_cell("a = 10")
191 ip.run_cell("a = 10")
192 ip.run_cell(("def f(x):\n"
192 ip.run_cell(("def f(x):\n"
193 " return x + a"))
193 " return x + a"))
194 ip.run_cell("b = f(12)")
194 ip.run_cell("b = f(12)")
195 self.assertEqual(ip.user_ns["b"], 22)
195 self.assertEqual(ip.user_ns["b"], 22)
196
196
197 def test_bad_custom_tb(self):
197 def test_bad_custom_tb(self):
198 """Check that InteractiveShell is protected from bad custom exception handlers"""
198 """Check that InteractiveShell is protected from bad custom exception handlers"""
199 from IPython.utils import io
199 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
200 save_stderr = io.stderr
200 self.assertEqual(ip.custom_exceptions, (IOError,))
201 try:
201 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
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,))
206 ip.run_cell(u'raise IOError("foo")')
202 ip.run_cell(u'raise IOError("foo")')
207 self.assertEqual(ip.custom_exceptions, ())
203 self.assertEqual(ip.custom_exceptions, ())
208 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
209 finally:
210 io.stderr = save_stderr
211
204
212 def test_bad_custom_tb_return(self):
205 def test_bad_custom_tb_return(self):
213 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
206 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
214 from IPython.utils import io
207 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
215 save_stderr = io.stderr
208 self.assertEqual(ip.custom_exceptions, (NameError,))
216 try:
209 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
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,))
221 ip.run_cell(u'a=abracadabra')
210 ip.run_cell(u'a=abracadabra')
222 self.assertEqual(ip.custom_exceptions, ())
211 self.assertEqual(ip.custom_exceptions, ())
223 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
224 finally:
225 io.stderr = save_stderr
226
212
227 def test_drop_by_id(self):
213 def test_drop_by_id(self):
228 myvars = {"a":object(), "b":object(), "c": object()}
214 myvars = {"a":object(), "b":object(), "c": object()}
229 ip.push(myvars, interactive=False)
215 ip.push(myvars, interactive=False)
230 for name in myvars:
216 for name in myvars:
231 assert name in ip.user_ns, name
217 assert name in ip.user_ns, name
232 assert name in ip.user_ns_hidden, name
218 assert name in ip.user_ns_hidden, name
233 ip.user_ns['b'] = 12
219 ip.user_ns['b'] = 12
234 ip.drop_by_id(myvars)
220 ip.drop_by_id(myvars)
235 for name in ["a", "c"]:
221 for name in ["a", "c"]:
236 assert name not in ip.user_ns, name
222 assert name not in ip.user_ns, name
237 assert name not in ip.user_ns_hidden, name
223 assert name not in ip.user_ns_hidden, name
238 assert ip.user_ns['b'] == 12
224 assert ip.user_ns['b'] == 12
239 ip.reset()
225 ip.reset()
240
226
241 def test_var_expand(self):
227 def test_var_expand(self):
242 ip.user_ns['f'] = u'Ca\xf1o'
228 ip.user_ns['f'] = u'Ca\xf1o'
243 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
229 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
244 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
230 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
245 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
231 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
246 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
232 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
247
233
248 ip.user_ns['f'] = b'Ca\xc3\xb1o'
234 ip.user_ns['f'] = b'Ca\xc3\xb1o'
249 # This should not raise any exception:
235 # This should not raise any exception:
250 ip.var_expand(u'echo $f')
236 ip.var_expand(u'echo $f')
251
237
252 def test_var_expand_local(self):
238 def test_var_expand_local(self):
253 """Test local variable expansion in !system and %magic calls"""
239 """Test local variable expansion in !system and %magic calls"""
254 # !system
240 # !system
255 ip.run_cell('def test():\n'
241 ip.run_cell('def test():\n'
256 ' lvar = "ttt"\n'
242 ' lvar = "ttt"\n'
257 ' ret = !echo {lvar}\n'
243 ' ret = !echo {lvar}\n'
258 ' return ret[0]\n')
244 ' return ret[0]\n')
259 res = ip.user_ns['test']()
245 res = ip.user_ns['test']()
260 nt.assert_in('ttt', res)
246 nt.assert_in('ttt', res)
261
247
262 # %magic
248 # %magic
263 ip.run_cell('def makemacro():\n'
249 ip.run_cell('def makemacro():\n'
264 ' macroname = "macro_var_expand_locals"\n'
250 ' macroname = "macro_var_expand_locals"\n'
265 ' %macro {macroname} codestr\n')
251 ' %macro {macroname} codestr\n')
266 ip.user_ns['codestr'] = "str(12)"
252 ip.user_ns['codestr'] = "str(12)"
267 ip.run_cell('makemacro()')
253 ip.run_cell('makemacro()')
268 nt.assert_in('macro_var_expand_locals', ip.user_ns)
254 nt.assert_in('macro_var_expand_locals', ip.user_ns)
269
255
270 def test_var_expand_self(self):
256 def test_var_expand_self(self):
271 """Test variable expansion with the name 'self', which was failing.
257 """Test variable expansion with the name 'self', which was failing.
272
258
273 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
259 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
274 """
260 """
275 ip.run_cell('class cTest:\n'
261 ip.run_cell('class cTest:\n'
276 ' classvar="see me"\n'
262 ' classvar="see me"\n'
277 ' def test(self):\n'
263 ' def test(self):\n'
278 ' res = !echo Variable: {self.classvar}\n'
264 ' res = !echo Variable: {self.classvar}\n'
279 ' return res[0]\n')
265 ' return res[0]\n')
280 nt.assert_in('see me', ip.user_ns['cTest']().test())
266 nt.assert_in('see me', ip.user_ns['cTest']().test())
281
267
282 def test_bad_var_expand(self):
268 def test_bad_var_expand(self):
283 """var_expand on invalid formats shouldn't raise"""
269 """var_expand on invalid formats shouldn't raise"""
284 # SyntaxError
270 # SyntaxError
285 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
271 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
286 # NameError
272 # NameError
287 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
273 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
288 # ZeroDivisionError
274 # ZeroDivisionError
289 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
275 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
290
276
291 def test_silent_postexec(self):
277 def test_silent_postexec(self):
292 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
278 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
293 pre_explicit = mock.Mock()
279 pre_explicit = mock.Mock()
294 pre_always = mock.Mock()
280 pre_always = mock.Mock()
295 post_explicit = mock.Mock()
281 post_explicit = mock.Mock()
296 post_always = mock.Mock()
282 post_always = mock.Mock()
297
283
298 ip.events.register('pre_run_cell', pre_explicit)
284 ip.events.register('pre_run_cell', pre_explicit)
299 ip.events.register('pre_execute', pre_always)
285 ip.events.register('pre_execute', pre_always)
300 ip.events.register('post_run_cell', post_explicit)
286 ip.events.register('post_run_cell', post_explicit)
301 ip.events.register('post_execute', post_always)
287 ip.events.register('post_execute', post_always)
302
288
303 try:
289 try:
304 ip.run_cell("1", silent=True)
290 ip.run_cell("1", silent=True)
305 assert pre_always.called
291 assert pre_always.called
306 assert not pre_explicit.called
292 assert not pre_explicit.called
307 assert post_always.called
293 assert post_always.called
308 assert not post_explicit.called
294 assert not post_explicit.called
309 # double-check that non-silent exec did what we expected
295 # double-check that non-silent exec did what we expected
310 # silent to avoid
296 # silent to avoid
311 ip.run_cell("1")
297 ip.run_cell("1")
312 assert pre_explicit.called
298 assert pre_explicit.called
313 assert post_explicit.called
299 assert post_explicit.called
314 finally:
300 finally:
315 # remove post-exec
301 # remove post-exec
316 ip.events.unregister('pre_run_cell', pre_explicit)
302 ip.events.unregister('pre_run_cell', pre_explicit)
317 ip.events.unregister('pre_execute', pre_always)
303 ip.events.unregister('pre_execute', pre_always)
318 ip.events.unregister('post_run_cell', post_explicit)
304 ip.events.unregister('post_run_cell', post_explicit)
319 ip.events.unregister('post_execute', post_always)
305 ip.events.unregister('post_execute', post_always)
320
306
321 def test_silent_noadvance(self):
307 def test_silent_noadvance(self):
322 """run_cell(silent=True) doesn't advance execution_count"""
308 """run_cell(silent=True) doesn't advance execution_count"""
323 ec = ip.execution_count
309 ec = ip.execution_count
324 # silent should force store_history=False
310 # silent should force store_history=False
325 ip.run_cell("1", store_history=True, silent=True)
311 ip.run_cell("1", store_history=True, silent=True)
326
312
327 self.assertEqual(ec, ip.execution_count)
313 self.assertEqual(ec, ip.execution_count)
328 # double-check that non-silent exec did what we expected
314 # double-check that non-silent exec did what we expected
329 # silent to avoid
315 # silent to avoid
330 ip.run_cell("1", store_history=True)
316 ip.run_cell("1", store_history=True)
331 self.assertEqual(ec+1, ip.execution_count)
317 self.assertEqual(ec+1, ip.execution_count)
332
318
333 def test_silent_nodisplayhook(self):
319 def test_silent_nodisplayhook(self):
334 """run_cell(silent=True) doesn't trigger displayhook"""
320 """run_cell(silent=True) doesn't trigger displayhook"""
335 d = dict(called=False)
321 d = dict(called=False)
336
322
337 trap = ip.display_trap
323 trap = ip.display_trap
338 save_hook = trap.hook
324 save_hook = trap.hook
339
325
340 def failing_hook(*args, **kwargs):
326 def failing_hook(*args, **kwargs):
341 d['called'] = True
327 d['called'] = True
342
328
343 try:
329 try:
344 trap.hook = failing_hook
330 trap.hook = failing_hook
345 res = ip.run_cell("1", silent=True)
331 res = ip.run_cell("1", silent=True)
346 self.assertFalse(d['called'])
332 self.assertFalse(d['called'])
347 self.assertIsNone(res.result)
333 self.assertIsNone(res.result)
348 # double-check that non-silent exec did what we expected
334 # double-check that non-silent exec did what we expected
349 # silent to avoid
335 # silent to avoid
350 ip.run_cell("1")
336 ip.run_cell("1")
351 self.assertTrue(d['called'])
337 self.assertTrue(d['called'])
352 finally:
338 finally:
353 trap.hook = save_hook
339 trap.hook = save_hook
354
340
355 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
341 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
356 def test_print_softspace(self):
342 def test_print_softspace(self):
357 """Verify that softspace is handled correctly when executing multiple
343 """Verify that softspace is handled correctly when executing multiple
358 statements.
344 statements.
359
345
360 In [1]: print 1; print 2
346 In [1]: print 1; print 2
361 1
347 1
362 2
348 2
363
349
364 In [2]: print 1,; print 2
350 In [2]: print 1,; print 2
365 1 2
351 1 2
366 """
352 """
367
353
368 def test_ofind_line_magic(self):
354 def test_ofind_line_magic(self):
369 from IPython.core.magic import register_line_magic
355 from IPython.core.magic import register_line_magic
370
356
371 @register_line_magic
357 @register_line_magic
372 def lmagic(line):
358 def lmagic(line):
373 "A line magic"
359 "A line magic"
374
360
375 # Get info on line magic
361 # Get info on line magic
376 lfind = ip._ofind('lmagic')
362 lfind = ip._ofind('lmagic')
377 info = dict(found=True, isalias=False, ismagic=True,
363 info = dict(found=True, isalias=False, ismagic=True,
378 namespace = 'IPython internal', obj= lmagic.__wrapped__,
364 namespace = 'IPython internal', obj= lmagic.__wrapped__,
379 parent = None)
365 parent = None)
380 nt.assert_equal(lfind, info)
366 nt.assert_equal(lfind, info)
381
367
382 def test_ofind_cell_magic(self):
368 def test_ofind_cell_magic(self):
383 from IPython.core.magic import register_cell_magic
369 from IPython.core.magic import register_cell_magic
384
370
385 @register_cell_magic
371 @register_cell_magic
386 def cmagic(line, cell):
372 def cmagic(line, cell):
387 "A cell magic"
373 "A cell magic"
388
374
389 # Get info on cell magic
375 # Get info on cell magic
390 find = ip._ofind('cmagic')
376 find = ip._ofind('cmagic')
391 info = dict(found=True, isalias=False, ismagic=True,
377 info = dict(found=True, isalias=False, ismagic=True,
392 namespace = 'IPython internal', obj= cmagic.__wrapped__,
378 namespace = 'IPython internal', obj= cmagic.__wrapped__,
393 parent = None)
379 parent = None)
394 nt.assert_equal(find, info)
380 nt.assert_equal(find, info)
395
381
396 def test_ofind_property_with_error(self):
382 def test_ofind_property_with_error(self):
397 class A(object):
383 class A(object):
398 @property
384 @property
399 def foo(self):
385 def foo(self):
400 raise NotImplementedError()
386 raise NotImplementedError()
401 a = A()
387 a = A()
402
388
403 found = ip._ofind('a.foo', [('locals', locals())])
389 found = ip._ofind('a.foo', [('locals', locals())])
404 info = dict(found=True, isalias=False, ismagic=False,
390 info = dict(found=True, isalias=False, ismagic=False,
405 namespace='locals', obj=A.foo, parent=a)
391 namespace='locals', obj=A.foo, parent=a)
406 nt.assert_equal(found, info)
392 nt.assert_equal(found, info)
407
393
408 def test_ofind_multiple_attribute_lookups(self):
394 def test_ofind_multiple_attribute_lookups(self):
409 class A(object):
395 class A(object):
410 @property
396 @property
411 def foo(self):
397 def foo(self):
412 raise NotImplementedError()
398 raise NotImplementedError()
413
399
414 a = A()
400 a = A()
415 a.a = A()
401 a.a = A()
416 a.a.a = A()
402 a.a.a = A()
417
403
418 found = ip._ofind('a.a.a.foo', [('locals', locals())])
404 found = ip._ofind('a.a.a.foo', [('locals', locals())])
419 info = dict(found=True, isalias=False, ismagic=False,
405 info = dict(found=True, isalias=False, ismagic=False,
420 namespace='locals', obj=A.foo, parent=a.a.a)
406 namespace='locals', obj=A.foo, parent=a.a.a)
421 nt.assert_equal(found, info)
407 nt.assert_equal(found, info)
422
408
423 def test_ofind_slotted_attributes(self):
409 def test_ofind_slotted_attributes(self):
424 class A(object):
410 class A(object):
425 __slots__ = ['foo']
411 __slots__ = ['foo']
426 def __init__(self):
412 def __init__(self):
427 self.foo = 'bar'
413 self.foo = 'bar'
428
414
429 a = A()
415 a = A()
430 found = ip._ofind('a.foo', [('locals', locals())])
416 found = ip._ofind('a.foo', [('locals', locals())])
431 info = dict(found=True, isalias=False, ismagic=False,
417 info = dict(found=True, isalias=False, ismagic=False,
432 namespace='locals', obj=a.foo, parent=a)
418 namespace='locals', obj=a.foo, parent=a)
433 nt.assert_equal(found, info)
419 nt.assert_equal(found, info)
434
420
435 found = ip._ofind('a.bar', [('locals', locals())])
421 found = ip._ofind('a.bar', [('locals', locals())])
436 info = dict(found=False, isalias=False, ismagic=False,
422 info = dict(found=False, isalias=False, ismagic=False,
437 namespace=None, obj=None, parent=a)
423 namespace=None, obj=None, parent=a)
438 nt.assert_equal(found, info)
424 nt.assert_equal(found, info)
439
425
440 def test_ofind_prefers_property_to_instance_level_attribute(self):
426 def test_ofind_prefers_property_to_instance_level_attribute(self):
441 class A(object):
427 class A(object):
442 @property
428 @property
443 def foo(self):
429 def foo(self):
444 return 'bar'
430 return 'bar'
445 a = A()
431 a = A()
446 a.__dict__['foo'] = 'baz'
432 a.__dict__['foo'] = 'baz'
447 nt.assert_equal(a.foo, 'bar')
433 nt.assert_equal(a.foo, 'bar')
448 found = ip._ofind('a.foo', [('locals', locals())])
434 found = ip._ofind('a.foo', [('locals', locals())])
449 nt.assert_is(found['obj'], A.foo)
435 nt.assert_is(found['obj'], A.foo)
450
436
451 def test_custom_exception(self):
437 def test_custom_exception(self):
452 called = []
438 called = []
453 def my_handler(shell, etype, value, tb, tb_offset=None):
439 def my_handler(shell, etype, value, tb, tb_offset=None):
454 called.append(etype)
440 called.append(etype)
455 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
441 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
456
442
457 ip.set_custom_exc((ValueError,), my_handler)
443 ip.set_custom_exc((ValueError,), my_handler)
458 try:
444 try:
459 res = ip.run_cell("raise ValueError('test')")
445 res = ip.run_cell("raise ValueError('test')")
460 # Check that this was called, and only once.
446 # Check that this was called, and only once.
461 self.assertEqual(called, [ValueError])
447 self.assertEqual(called, [ValueError])
462 # Check that the error is on the result object
448 # Check that the error is on the result object
463 self.assertIsInstance(res.error_in_exec, ValueError)
449 self.assertIsInstance(res.error_in_exec, ValueError)
464 finally:
450 finally:
465 # Reset the custom exception hook
451 # Reset the custom exception hook
466 ip.set_custom_exc((), None)
452 ip.set_custom_exc((), None)
467
453
468 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
454 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
469 def test_future_environment(self):
455 def test_future_environment(self):
470 "Can we run code with & without the shell's __future__ imports?"
456 "Can we run code with & without the shell's __future__ imports?"
471 ip.run_cell("from __future__ import division")
457 ip.run_cell("from __future__ import division")
472 ip.run_cell("a = 1/2", shell_futures=True)
458 ip.run_cell("a = 1/2", shell_futures=True)
473 self.assertEqual(ip.user_ns['a'], 0.5)
459 self.assertEqual(ip.user_ns['a'], 0.5)
474 ip.run_cell("b = 1/2", shell_futures=False)
460 ip.run_cell("b = 1/2", shell_futures=False)
475 self.assertEqual(ip.user_ns['b'], 0)
461 self.assertEqual(ip.user_ns['b'], 0)
476
462
477 ip.compile.reset_compiler_flags()
463 ip.compile.reset_compiler_flags()
478 # This shouldn't leak to the shell's compiler
464 # This shouldn't leak to the shell's compiler
479 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
465 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
480 self.assertEqual(ip.user_ns['c'], 0.5)
466 self.assertEqual(ip.user_ns['c'], 0.5)
481 ip.run_cell("d = 1/2", shell_futures=True)
467 ip.run_cell("d = 1/2", shell_futures=True)
482 self.assertEqual(ip.user_ns['d'], 0)
468 self.assertEqual(ip.user_ns['d'], 0)
483
469
484 def test_mktempfile(self):
470 def test_mktempfile(self):
485 filename = ip.mktempfile()
471 filename = ip.mktempfile()
486 # Check that we can open the file again on Windows
472 # Check that we can open the file again on Windows
487 with open(filename, 'w') as f:
473 with open(filename, 'w') as f:
488 f.write('abc')
474 f.write('abc')
489
475
490 filename = ip.mktempfile(data='blah')
476 filename = ip.mktempfile(data='blah')
491 with open(filename, 'r') as f:
477 with open(filename, 'r') as f:
492 self.assertEqual(f.read(), 'blah')
478 self.assertEqual(f.read(), 'blah')
493
479
494 def test_new_main_mod(self):
480 def test_new_main_mod(self):
495 # Smoketest to check that this accepts a unicode module name
481 # Smoketest to check that this accepts a unicode module name
496 name = u'jiefmw'
482 name = u'jiefmw'
497 mod = ip.new_main_mod(u'%s.py' % name, name)
483 mod = ip.new_main_mod(u'%s.py' % name, name)
498 self.assertEqual(mod.__name__, name)
484 self.assertEqual(mod.__name__, name)
499
485
500 def test_get_exception_only(self):
486 def test_get_exception_only(self):
501 try:
487 try:
502 raise KeyboardInterrupt
488 raise KeyboardInterrupt
503 except KeyboardInterrupt:
489 except KeyboardInterrupt:
504 msg = ip.get_exception_only()
490 msg = ip.get_exception_only()
505 self.assertEqual(msg, 'KeyboardInterrupt\n')
491 self.assertEqual(msg, 'KeyboardInterrupt\n')
506
492
507 try:
493 try:
508 raise DerivedInterrupt("foo")
494 raise DerivedInterrupt("foo")
509 except KeyboardInterrupt:
495 except KeyboardInterrupt:
510 msg = ip.get_exception_only()
496 msg = ip.get_exception_only()
511 if sys.version_info[0] <= 2:
497 if sys.version_info[0] <= 2:
512 self.assertEqual(msg, 'DerivedInterrupt: foo\n')
498 self.assertEqual(msg, 'DerivedInterrupt: foo\n')
513 else:
499 else:
514 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
500 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
515
501
516 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
502 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
517
503
518 @onlyif_unicode_paths
504 @onlyif_unicode_paths
519 def setUp(self):
505 def setUp(self):
520 self.BASETESTDIR = tempfile.mkdtemp()
506 self.BASETESTDIR = tempfile.mkdtemp()
521 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
507 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
522 os.mkdir(self.TESTDIR)
508 os.mkdir(self.TESTDIR)
523 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
509 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
524 sfile.write("pass\n")
510 sfile.write("pass\n")
525 self.oldpath = py3compat.getcwd()
511 self.oldpath = py3compat.getcwd()
526 os.chdir(self.TESTDIR)
512 os.chdir(self.TESTDIR)
527 self.fname = u"Γ₯Àâtestscript.py"
513 self.fname = u"Γ₯Àâtestscript.py"
528
514
529 def tearDown(self):
515 def tearDown(self):
530 os.chdir(self.oldpath)
516 os.chdir(self.oldpath)
531 shutil.rmtree(self.BASETESTDIR)
517 shutil.rmtree(self.BASETESTDIR)
532
518
533 @onlyif_unicode_paths
519 @onlyif_unicode_paths
534 def test_1(self):
520 def test_1(self):
535 """Test safe_execfile with non-ascii path
521 """Test safe_execfile with non-ascii path
536 """
522 """
537 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
523 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
538
524
539 class ExitCodeChecks(tt.TempFileMixin):
525 class ExitCodeChecks(tt.TempFileMixin):
540 def test_exit_code_ok(self):
526 def test_exit_code_ok(self):
541 self.system('exit 0')
527 self.system('exit 0')
542 self.assertEqual(ip.user_ns['_exit_code'], 0)
528 self.assertEqual(ip.user_ns['_exit_code'], 0)
543
529
544 def test_exit_code_error(self):
530 def test_exit_code_error(self):
545 self.system('exit 1')
531 self.system('exit 1')
546 self.assertEqual(ip.user_ns['_exit_code'], 1)
532 self.assertEqual(ip.user_ns['_exit_code'], 1)
547
533
548 @skipif(not hasattr(signal, 'SIGALRM'))
534 @skipif(not hasattr(signal, 'SIGALRM'))
549 def test_exit_code_signal(self):
535 def test_exit_code_signal(self):
550 self.mktmp("import signal, time\n"
536 self.mktmp("import signal, time\n"
551 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
537 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
552 "time.sleep(1)\n")
538 "time.sleep(1)\n")
553 self.system("%s %s" % (sys.executable, self.fname))
539 self.system("%s %s" % (sys.executable, self.fname))
554 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
540 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
555
541
556 @onlyif_cmds_exist("csh")
542 @onlyif_cmds_exist("csh")
557 def test_exit_code_signal_csh(self):
543 def test_exit_code_signal_csh(self):
558 SHELL = os.environ.get('SHELL', None)
544 SHELL = os.environ.get('SHELL', None)
559 os.environ['SHELL'] = find_cmd("csh")
545 os.environ['SHELL'] = find_cmd("csh")
560 try:
546 try:
561 self.test_exit_code_signal()
547 self.test_exit_code_signal()
562 finally:
548 finally:
563 if SHELL is not None:
549 if SHELL is not None:
564 os.environ['SHELL'] = SHELL
550 os.environ['SHELL'] = SHELL
565 else:
551 else:
566 del os.environ['SHELL']
552 del os.environ['SHELL']
567
553
568 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
554 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
569 system = ip.system_raw
555 system = ip.system_raw
570
556
571 @onlyif_unicode_paths
557 @onlyif_unicode_paths
572 def test_1(self):
558 def test_1(self):
573 """Test system_raw with non-ascii cmd
559 """Test system_raw with non-ascii cmd
574 """
560 """
575 cmd = u'''python -c "'Γ₯Àâ'" '''
561 cmd = u'''python -c "'Γ₯Àâ'" '''
576 ip.system_raw(cmd)
562 ip.system_raw(cmd)
577
563
578 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
564 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
579 @mock.patch('os.system', side_effect=KeyboardInterrupt)
565 @mock.patch('os.system', side_effect=KeyboardInterrupt)
580 def test_control_c(self, *mocks):
566 def test_control_c(self, *mocks):
581 try:
567 try:
582 self.system("sleep 1 # wont happen")
568 self.system("sleep 1 # wont happen")
583 except KeyboardInterrupt:
569 except KeyboardInterrupt:
584 self.fail("system call should intercept "
570 self.fail("system call should intercept "
585 "keyboard interrupt from subprocess.call")
571 "keyboard interrupt from subprocess.call")
586 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
572 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
587
573
588 # TODO: Exit codes are currently ignored on Windows.
574 # TODO: Exit codes are currently ignored on Windows.
589 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
575 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
590 system = ip.system_piped
576 system = ip.system_piped
591
577
592 @skip_win32
578 @skip_win32
593 def test_exit_code_ok(self):
579 def test_exit_code_ok(self):
594 ExitCodeChecks.test_exit_code_ok(self)
580 ExitCodeChecks.test_exit_code_ok(self)
595
581
596 @skip_win32
582 @skip_win32
597 def test_exit_code_error(self):
583 def test_exit_code_error(self):
598 ExitCodeChecks.test_exit_code_error(self)
584 ExitCodeChecks.test_exit_code_error(self)
599
585
600 @skip_win32
586 @skip_win32
601 def test_exit_code_signal(self):
587 def test_exit_code_signal(self):
602 ExitCodeChecks.test_exit_code_signal(self)
588 ExitCodeChecks.test_exit_code_signal(self)
603
589
604 class TestModules(unittest.TestCase, tt.TempFileMixin):
590 class TestModules(unittest.TestCase, tt.TempFileMixin):
605 def test_extraneous_loads(self):
591 def test_extraneous_loads(self):
606 """Test we're not loading modules on startup that we shouldn't.
592 """Test we're not loading modules on startup that we shouldn't.
607 """
593 """
608 self.mktmp("import sys\n"
594 self.mktmp("import sys\n"
609 "print('numpy' in sys.modules)\n"
595 "print('numpy' in sys.modules)\n"
610 "print('ipyparallel' in sys.modules)\n"
596 "print('ipyparallel' in sys.modules)\n"
611 "print('ipykernel' in sys.modules)\n"
597 "print('ipykernel' in sys.modules)\n"
612 )
598 )
613 out = "False\nFalse\nFalse\n"
599 out = "False\nFalse\nFalse\n"
614 tt.ipexec_validate(self.fname, out)
600 tt.ipexec_validate(self.fname, out)
615
601
616 class Negator(ast.NodeTransformer):
602 class Negator(ast.NodeTransformer):
617 """Negates all number literals in an AST."""
603 """Negates all number literals in an AST."""
618 def visit_Num(self, node):
604 def visit_Num(self, node):
619 node.n = -node.n
605 node.n = -node.n
620 return node
606 return node
621
607
622 class TestAstTransform(unittest.TestCase):
608 class TestAstTransform(unittest.TestCase):
623 def setUp(self):
609 def setUp(self):
624 self.negator = Negator()
610 self.negator = Negator()
625 ip.ast_transformers.append(self.negator)
611 ip.ast_transformers.append(self.negator)
626
612
627 def tearDown(self):
613 def tearDown(self):
628 ip.ast_transformers.remove(self.negator)
614 ip.ast_transformers.remove(self.negator)
629
615
630 def test_run_cell(self):
616 def test_run_cell(self):
631 with tt.AssertPrints('-34'):
617 with tt.AssertPrints('-34'):
632 ip.run_cell('print (12 + 22)')
618 ip.run_cell('print (12 + 22)')
633
619
634 # A named reference to a number shouldn't be transformed.
620 # A named reference to a number shouldn't be transformed.
635 ip.user_ns['n'] = 55
621 ip.user_ns['n'] = 55
636 with tt.AssertNotPrints('-55'):
622 with tt.AssertNotPrints('-55'):
637 ip.run_cell('print (n)')
623 ip.run_cell('print (n)')
638
624
639 def test_timeit(self):
625 def test_timeit(self):
640 called = set()
626 called = set()
641 def f(x):
627 def f(x):
642 called.add(x)
628 called.add(x)
643 ip.push({'f':f})
629 ip.push({'f':f})
644
630
645 with tt.AssertPrints("best of "):
631 with tt.AssertPrints("best of "):
646 ip.run_line_magic("timeit", "-n1 f(1)")
632 ip.run_line_magic("timeit", "-n1 f(1)")
647 self.assertEqual(called, {-1})
633 self.assertEqual(called, {-1})
648 called.clear()
634 called.clear()
649
635
650 with tt.AssertPrints("best of "):
636 with tt.AssertPrints("best of "):
651 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
637 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
652 self.assertEqual(called, {-2, -3})
638 self.assertEqual(called, {-2, -3})
653
639
654 def test_time(self):
640 def test_time(self):
655 called = []
641 called = []
656 def f(x):
642 def f(x):
657 called.append(x)
643 called.append(x)
658 ip.push({'f':f})
644 ip.push({'f':f})
659
645
660 # Test with an expression
646 # Test with an expression
661 with tt.AssertPrints("Wall time: "):
647 with tt.AssertPrints("Wall time: "):
662 ip.run_line_magic("time", "f(5+9)")
648 ip.run_line_magic("time", "f(5+9)")
663 self.assertEqual(called, [-14])
649 self.assertEqual(called, [-14])
664 called[:] = []
650 called[:] = []
665
651
666 # Test with a statement (different code path)
652 # Test with a statement (different code path)
667 with tt.AssertPrints("Wall time: "):
653 with tt.AssertPrints("Wall time: "):
668 ip.run_line_magic("time", "a = f(-3 + -2)")
654 ip.run_line_magic("time", "a = f(-3 + -2)")
669 self.assertEqual(called, [5])
655 self.assertEqual(called, [5])
670
656
671 def test_macro(self):
657 def test_macro(self):
672 ip.push({'a':10})
658 ip.push({'a':10})
673 # The AST transformation makes this do a+=-1
659 # The AST transformation makes this do a+=-1
674 ip.define_macro("amacro", "a+=1\nprint(a)")
660 ip.define_macro("amacro", "a+=1\nprint(a)")
675
661
676 with tt.AssertPrints("9"):
662 with tt.AssertPrints("9"):
677 ip.run_cell("amacro")
663 ip.run_cell("amacro")
678 with tt.AssertPrints("8"):
664 with tt.AssertPrints("8"):
679 ip.run_cell("amacro")
665 ip.run_cell("amacro")
680
666
681 class IntegerWrapper(ast.NodeTransformer):
667 class IntegerWrapper(ast.NodeTransformer):
682 """Wraps all integers in a call to Integer()"""
668 """Wraps all integers in a call to Integer()"""
683 def visit_Num(self, node):
669 def visit_Num(self, node):
684 if isinstance(node.n, int):
670 if isinstance(node.n, int):
685 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
671 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
686 args=[node], keywords=[])
672 args=[node], keywords=[])
687 return node
673 return node
688
674
689 class TestAstTransform2(unittest.TestCase):
675 class TestAstTransform2(unittest.TestCase):
690 def setUp(self):
676 def setUp(self):
691 self.intwrapper = IntegerWrapper()
677 self.intwrapper = IntegerWrapper()
692 ip.ast_transformers.append(self.intwrapper)
678 ip.ast_transformers.append(self.intwrapper)
693
679
694 self.calls = []
680 self.calls = []
695 def Integer(*args):
681 def Integer(*args):
696 self.calls.append(args)
682 self.calls.append(args)
697 return args
683 return args
698 ip.push({"Integer": Integer})
684 ip.push({"Integer": Integer})
699
685
700 def tearDown(self):
686 def tearDown(self):
701 ip.ast_transformers.remove(self.intwrapper)
687 ip.ast_transformers.remove(self.intwrapper)
702 del ip.user_ns['Integer']
688 del ip.user_ns['Integer']
703
689
704 def test_run_cell(self):
690 def test_run_cell(self):
705 ip.run_cell("n = 2")
691 ip.run_cell("n = 2")
706 self.assertEqual(self.calls, [(2,)])
692 self.assertEqual(self.calls, [(2,)])
707
693
708 # This shouldn't throw an error
694 # This shouldn't throw an error
709 ip.run_cell("o = 2.0")
695 ip.run_cell("o = 2.0")
710 self.assertEqual(ip.user_ns['o'], 2.0)
696 self.assertEqual(ip.user_ns['o'], 2.0)
711
697
712 def test_timeit(self):
698 def test_timeit(self):
713 called = set()
699 called = set()
714 def f(x):
700 def f(x):
715 called.add(x)
701 called.add(x)
716 ip.push({'f':f})
702 ip.push({'f':f})
717
703
718 with tt.AssertPrints("best of "):
704 with tt.AssertPrints("best of "):
719 ip.run_line_magic("timeit", "-n1 f(1)")
705 ip.run_line_magic("timeit", "-n1 f(1)")
720 self.assertEqual(called, {(1,)})
706 self.assertEqual(called, {(1,)})
721 called.clear()
707 called.clear()
722
708
723 with tt.AssertPrints("best of "):
709 with tt.AssertPrints("best of "):
724 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
710 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
725 self.assertEqual(called, {(2,), (3,)})
711 self.assertEqual(called, {(2,), (3,)})
726
712
727 class ErrorTransformer(ast.NodeTransformer):
713 class ErrorTransformer(ast.NodeTransformer):
728 """Throws an error when it sees a number."""
714 """Throws an error when it sees a number."""
729 def visit_Num(self, node):
715 def visit_Num(self, node):
730 raise ValueError("test")
716 raise ValueError("test")
731
717
732 class TestAstTransformError(unittest.TestCase):
718 class TestAstTransformError(unittest.TestCase):
733 def test_unregistering(self):
719 def test_unregistering(self):
734 err_transformer = ErrorTransformer()
720 err_transformer = ErrorTransformer()
735 ip.ast_transformers.append(err_transformer)
721 ip.ast_transformers.append(err_transformer)
736
722
737 with tt.AssertPrints("unregister", channel='stderr'):
723 with tt.AssertPrints("unregister", channel='stderr'):
738 ip.run_cell("1 + 2")
724 ip.run_cell("1 + 2")
739
725
740 # This should have been removed.
726 # This should have been removed.
741 nt.assert_not_in(err_transformer, ip.ast_transformers)
727 nt.assert_not_in(err_transformer, ip.ast_transformers)
742
728
743
729
744 class StringRejector(ast.NodeTransformer):
730 class StringRejector(ast.NodeTransformer):
745 """Throws an InputRejected when it sees a string literal.
731 """Throws an InputRejected when it sees a string literal.
746
732
747 Used to verify that NodeTransformers can signal that a piece of code should
733 Used to verify that NodeTransformers can signal that a piece of code should
748 not be executed by throwing an InputRejected.
734 not be executed by throwing an InputRejected.
749 """
735 """
750
736
751 def visit_Str(self, node):
737 def visit_Str(self, node):
752 raise InputRejected("test")
738 raise InputRejected("test")
753
739
754
740
755 class TestAstTransformInputRejection(unittest.TestCase):
741 class TestAstTransformInputRejection(unittest.TestCase):
756
742
757 def setUp(self):
743 def setUp(self):
758 self.transformer = StringRejector()
744 self.transformer = StringRejector()
759 ip.ast_transformers.append(self.transformer)
745 ip.ast_transformers.append(self.transformer)
760
746
761 def tearDown(self):
747 def tearDown(self):
762 ip.ast_transformers.remove(self.transformer)
748 ip.ast_transformers.remove(self.transformer)
763
749
764 def test_input_rejection(self):
750 def test_input_rejection(self):
765 """Check that NodeTransformers can reject input."""
751 """Check that NodeTransformers can reject input."""
766
752
767 expect_exception_tb = tt.AssertPrints("InputRejected: test")
753 expect_exception_tb = tt.AssertPrints("InputRejected: test")
768 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
754 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
769
755
770 # Run the same check twice to verify that the transformer is not
756 # Run the same check twice to verify that the transformer is not
771 # disabled after raising.
757 # disabled after raising.
772 with expect_exception_tb, expect_no_cell_output:
758 with expect_exception_tb, expect_no_cell_output:
773 ip.run_cell("'unsafe'")
759 ip.run_cell("'unsafe'")
774
760
775 with expect_exception_tb, expect_no_cell_output:
761 with expect_exception_tb, expect_no_cell_output:
776 res = ip.run_cell("'unsafe'")
762 res = ip.run_cell("'unsafe'")
777
763
778 self.assertIsInstance(res.error_before_exec, InputRejected)
764 self.assertIsInstance(res.error_before_exec, InputRejected)
779
765
780 def test__IPYTHON__():
766 def test__IPYTHON__():
781 # This shouldn't raise a NameError, that's all
767 # This shouldn't raise a NameError, that's all
782 __IPYTHON__
768 __IPYTHON__
783
769
784
770
785 class DummyRepr(object):
771 class DummyRepr(object):
786 def __repr__(self):
772 def __repr__(self):
787 return "DummyRepr"
773 return "DummyRepr"
788
774
789 def _repr_html_(self):
775 def _repr_html_(self):
790 return "<b>dummy</b>"
776 return "<b>dummy</b>"
791
777
792 def _repr_javascript_(self):
778 def _repr_javascript_(self):
793 return "console.log('hi');", {'key': 'value'}
779 return "console.log('hi');", {'key': 'value'}
794
780
795
781
796 def test_user_variables():
782 def test_user_variables():
797 # enable all formatters
783 # enable all formatters
798 ip.display_formatter.active_types = ip.display_formatter.format_types
784 ip.display_formatter.active_types = ip.display_formatter.format_types
799
785
800 ip.user_ns['dummy'] = d = DummyRepr()
786 ip.user_ns['dummy'] = d = DummyRepr()
801 keys = {'dummy', 'doesnotexist'}
787 keys = {'dummy', 'doesnotexist'}
802 r = ip.user_expressions({ key:key for key in keys})
788 r = ip.user_expressions({ key:key for key in keys})
803
789
804 nt.assert_equal(keys, set(r.keys()))
790 nt.assert_equal(keys, set(r.keys()))
805 dummy = r['dummy']
791 dummy = r['dummy']
806 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
792 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
807 nt.assert_equal(dummy['status'], 'ok')
793 nt.assert_equal(dummy['status'], 'ok')
808 data = dummy['data']
794 data = dummy['data']
809 metadata = dummy['metadata']
795 metadata = dummy['metadata']
810 nt.assert_equal(data.get('text/html'), d._repr_html_())
796 nt.assert_equal(data.get('text/html'), d._repr_html_())
811 js, jsmd = d._repr_javascript_()
797 js, jsmd = d._repr_javascript_()
812 nt.assert_equal(data.get('application/javascript'), js)
798 nt.assert_equal(data.get('application/javascript'), js)
813 nt.assert_equal(metadata.get('application/javascript'), jsmd)
799 nt.assert_equal(metadata.get('application/javascript'), jsmd)
814
800
815 dne = r['doesnotexist']
801 dne = r['doesnotexist']
816 nt.assert_equal(dne['status'], 'error')
802 nt.assert_equal(dne['status'], 'error')
817 nt.assert_equal(dne['ename'], 'NameError')
803 nt.assert_equal(dne['ename'], 'NameError')
818
804
819 # back to text only
805 # back to text only
820 ip.display_formatter.active_types = ['text/plain']
806 ip.display_formatter.active_types = ['text/plain']
821
807
822 def test_user_expression():
808 def test_user_expression():
823 # enable all formatters
809 # enable all formatters
824 ip.display_formatter.active_types = ip.display_formatter.format_types
810 ip.display_formatter.active_types = ip.display_formatter.format_types
825 query = {
811 query = {
826 'a' : '1 + 2',
812 'a' : '1 + 2',
827 'b' : '1/0',
813 'b' : '1/0',
828 }
814 }
829 r = ip.user_expressions(query)
815 r = ip.user_expressions(query)
830 import pprint
816 import pprint
831 pprint.pprint(r)
817 pprint.pprint(r)
832 nt.assert_equal(set(r.keys()), set(query.keys()))
818 nt.assert_equal(set(r.keys()), set(query.keys()))
833 a = r['a']
819 a = r['a']
834 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
820 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
835 nt.assert_equal(a['status'], 'ok')
821 nt.assert_equal(a['status'], 'ok')
836 data = a['data']
822 data = a['data']
837 metadata = a['metadata']
823 metadata = a['metadata']
838 nt.assert_equal(data.get('text/plain'), '3')
824 nt.assert_equal(data.get('text/plain'), '3')
839
825
840 b = r['b']
826 b = r['b']
841 nt.assert_equal(b['status'], 'error')
827 nt.assert_equal(b['status'], 'error')
842 nt.assert_equal(b['ename'], 'ZeroDivisionError')
828 nt.assert_equal(b['ename'], 'ZeroDivisionError')
843
829
844 # back to text only
830 # back to text only
845 ip.display_formatter.active_types = ['text/plain']
831 ip.display_formatter.active_types = ['text/plain']
846
832
847
833
848
834
849
835
850
836
851 class TestSyntaxErrorTransformer(unittest.TestCase):
837 class TestSyntaxErrorTransformer(unittest.TestCase):
852 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
838 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
853
839
854 class SyntaxErrorTransformer(InputTransformer):
840 class SyntaxErrorTransformer(InputTransformer):
855
841
856 def push(self, line):
842 def push(self, line):
857 pos = line.find('syntaxerror')
843 pos = line.find('syntaxerror')
858 if pos >= 0:
844 if pos >= 0:
859 e = SyntaxError('input contains "syntaxerror"')
845 e = SyntaxError('input contains "syntaxerror"')
860 e.text = line
846 e.text = line
861 e.offset = pos + 1
847 e.offset = pos + 1
862 raise e
848 raise e
863 return line
849 return line
864
850
865 def reset(self):
851 def reset(self):
866 pass
852 pass
867
853
868 def setUp(self):
854 def setUp(self):
869 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
855 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
870 ip.input_splitter.python_line_transforms.append(self.transformer)
856 ip.input_splitter.python_line_transforms.append(self.transformer)
871 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
857 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
872
858
873 def tearDown(self):
859 def tearDown(self):
874 ip.input_splitter.python_line_transforms.remove(self.transformer)
860 ip.input_splitter.python_line_transforms.remove(self.transformer)
875 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
861 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
876
862
877 def test_syntaxerror_input_transformer(self):
863 def test_syntaxerror_input_transformer(self):
878 with tt.AssertPrints('1234'):
864 with tt.AssertPrints('1234'):
879 ip.run_cell('1234')
865 ip.run_cell('1234')
880 with tt.AssertPrints('SyntaxError: invalid syntax'):
866 with tt.AssertPrints('SyntaxError: invalid syntax'):
881 ip.run_cell('1 2 3') # plain python syntax error
867 ip.run_cell('1 2 3') # plain python syntax error
882 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
868 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
883 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
869 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
884 with tt.AssertPrints('3456'):
870 with tt.AssertPrints('3456'):
885 ip.run_cell('3456')
871 ip.run_cell('3456')
886
872
887
873
888
874
889 def test_warning_suppression():
875 def test_warning_suppression():
890 ip.run_cell("import warnings")
876 ip.run_cell("import warnings")
891 try:
877 try:
892 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
878 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
893 ip.run_cell("warnings.warn('asdf')")
879 ip.run_cell("warnings.warn('asdf')")
894 # Here's the real test -- if we run that again, we should get the
880 # Here's the real test -- if we run that again, we should get the
895 # warning again. Traditionally, each warning was only issued once per
881 # warning again. Traditionally, each warning was only issued once per
896 # IPython session (approximately), even if the user typed in new and
882 # IPython session (approximately), even if the user typed in new and
897 # different code that should have also triggered the warning, leading
883 # different code that should have also triggered the warning, leading
898 # to much confusion.
884 # to much confusion.
899 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
885 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
900 ip.run_cell("warnings.warn('asdf')")
886 ip.run_cell("warnings.warn('asdf')")
901 finally:
887 finally:
902 ip.run_cell("del warnings")
888 ip.run_cell("del warnings")
903
889
904
890
905 def test_deprecation_warning():
891 def test_deprecation_warning():
906 ip.run_cell("""
892 ip.run_cell("""
907 import warnings
893 import warnings
908 def wrn():
894 def wrn():
909 warnings.warn(
895 warnings.warn(
910 "I AM A WARNING",
896 "I AM A WARNING",
911 DeprecationWarning
897 DeprecationWarning
912 )
898 )
913 """)
899 """)
914 try:
900 try:
915 with tt.AssertPrints("I AM A WARNING", channel="stderr"):
901 with tt.AssertPrints("I AM A WARNING", channel="stderr"):
916 ip.run_cell("wrn()")
902 ip.run_cell("wrn()")
917 finally:
903 finally:
918 ip.run_cell("del warnings")
904 ip.run_cell("del warnings")
919 ip.run_cell("del wrn")
905 ip.run_cell("del wrn")
920
906
921
907
922 class TestImportNoDeprecate(tt.TempFileMixin):
908 class TestImportNoDeprecate(tt.TempFileMixin):
923
909
924 def setup(self):
910 def setup(self):
925 """Make a valid python temp file."""
911 """Make a valid python temp file."""
926 self.mktmp("""
912 self.mktmp("""
927 import warnings
913 import warnings
928 def wrn():
914 def wrn():
929 warnings.warn(
915 warnings.warn(
930 "I AM A WARNING",
916 "I AM A WARNING",
931 DeprecationWarning
917 DeprecationWarning
932 )
918 )
933 """)
919 """)
934
920
935 def test_no_dep(self):
921 def test_no_dep(self):
936 """
922 """
937 No deprecation warning should be raised from imported functions
923 No deprecation warning should be raised from imported functions
938 """
924 """
939 ip.run_cell("from {} import wrn".format(self.fname))
925 ip.run_cell("from {} import wrn".format(self.fname))
940
926
941 with tt.AssertNotPrints("I AM A WARNING"):
927 with tt.AssertNotPrints("I AM A WARNING"):
942 ip.run_cell("wrn()")
928 ip.run_cell("wrn()")
943 ip.run_cell("del wrn")
929 ip.run_cell("del wrn")
@@ -1,1485 +1,1484 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencryted
44 potentially leak sensitive information like access keys, or unencryted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 You can implement other color schemes easily, the syntax is fairly
70 You can implement other color schemes easily, the syntax is fairly
71 self-explanatory. Please send back new schemes you develop to the author for
71 self-explanatory. Please send back new schemes you develop to the author for
72 possible inclusion in future releases.
72 possible inclusion in future releases.
73
73
74 Inheritance diagram:
74 Inheritance diagram:
75
75
76 .. inheritance-diagram:: IPython.core.ultratb
76 .. inheritance-diagram:: IPython.core.ultratb
77 :parts: 3
77 :parts: 3
78 """
78 """
79
79
80 #*****************************************************************************
80 #*****************************************************************************
81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
83 #
83 #
84 # Distributed under the terms of the BSD License. The full license is in
84 # Distributed under the terms of the BSD License. The full license is in
85 # the file COPYING, distributed as part of this software.
85 # the file COPYING, distributed as part of this software.
86 #*****************************************************************************
86 #*****************************************************************************
87
87
88 from __future__ import absolute_import
88 from __future__ import absolute_import
89 from __future__ import unicode_literals
89 from __future__ import unicode_literals
90 from __future__ import print_function
90 from __future__ import print_function
91
91
92 import dis
92 import dis
93 import inspect
93 import inspect
94 import keyword
94 import keyword
95 import linecache
95 import linecache
96 import os
96 import os
97 import pydoc
97 import pydoc
98 import re
98 import re
99 import sys
99 import sys
100 import time
100 import time
101 import tokenize
101 import tokenize
102 import traceback
102 import traceback
103 import types
103 import types
104
104
105 try: # Python 2
105 try: # Python 2
106 generate_tokens = tokenize.generate_tokens
106 generate_tokens = tokenize.generate_tokens
107 except AttributeError: # Python 3
107 except AttributeError: # Python 3
108 generate_tokens = tokenize.tokenize
108 generate_tokens = tokenize.tokenize
109
109
110 # For purposes of monkeypatching inspect to fix a bug in it.
110 # For purposes of monkeypatching inspect to fix a bug in it.
111 from inspect import getsourcefile, getfile, getmodule, \
111 from inspect import getsourcefile, getfile, getmodule, \
112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
113
113
114 # IPython's own modules
114 # IPython's own modules
115 # Modified pdb which doesn't damage IPython's readline handling
115 # Modified pdb which doesn't damage IPython's readline handling
116 from IPython import get_ipython
116 from IPython import get_ipython
117 from IPython.core import debugger
117 from IPython.core import debugger
118 from IPython.core.display_trap import DisplayTrap
118 from IPython.core.display_trap import DisplayTrap
119 from IPython.core.excolors import exception_colors
119 from IPython.core.excolors import exception_colors
120 from IPython.utils import PyColorize
120 from IPython.utils import PyColorize
121 from IPython.utils import io
122 from IPython.utils import openpy
121 from IPython.utils import openpy
123 from IPython.utils import path as util_path
122 from IPython.utils import path as util_path
124 from IPython.utils import py3compat
123 from IPython.utils import py3compat
125 from IPython.utils import ulinecache
124 from IPython.utils import ulinecache
126 from IPython.utils.data import uniq_stable
125 from IPython.utils.data import uniq_stable
127 from IPython.utils.terminal import get_terminal_size
126 from IPython.utils.terminal import get_terminal_size
128 from logging import info, error
127 from logging import info, error
129
128
130 import IPython.utils.colorable as colorable
129 import IPython.utils.colorable as colorable
131
130
132 # Globals
131 # Globals
133 # amount of space to put line numbers before verbose tracebacks
132 # amount of space to put line numbers before verbose tracebacks
134 INDENT_SIZE = 8
133 INDENT_SIZE = 8
135
134
136 # Default color scheme. This is used, for example, by the traceback
135 # Default color scheme. This is used, for example, by the traceback
137 # formatter. When running in an actual IPython instance, the user's rc.colors
136 # formatter. When running in an actual IPython instance, the user's rc.colors
138 # value is used, but having a module global makes this functionality available
137 # value is used, but having a module global makes this functionality available
139 # to users of ultratb who are NOT running inside ipython.
138 # to users of ultratb who are NOT running inside ipython.
140 DEFAULT_SCHEME = 'NoColor'
139 DEFAULT_SCHEME = 'NoColor'
141
140
142 # ---------------------------------------------------------------------------
141 # ---------------------------------------------------------------------------
143 # Code begins
142 # Code begins
144
143
145 # Utility functions
144 # Utility functions
146 def inspect_error():
145 def inspect_error():
147 """Print a message about internal inspect errors.
146 """Print a message about internal inspect errors.
148
147
149 These are unfortunately quite common."""
148 These are unfortunately quite common."""
150
149
151 error('Internal Python error in the inspect module.\n'
150 error('Internal Python error in the inspect module.\n'
152 'Below is the traceback from this internal error.\n')
151 'Below is the traceback from this internal error.\n')
153
152
154
153
155 # This function is a monkeypatch we apply to the Python inspect module. We have
154 # This function is a monkeypatch we apply to the Python inspect module. We have
156 # now found when it's needed (see discussion on issue gh-1456), and we have a
155 # now found when it's needed (see discussion on issue gh-1456), and we have a
157 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
156 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
158 # the monkeypatch is not applied. TK, Aug 2012.
157 # the monkeypatch is not applied. TK, Aug 2012.
159 def findsource(object):
158 def findsource(object):
160 """Return the entire source file and starting line number for an object.
159 """Return the entire source file and starting line number for an object.
161
160
162 The argument may be a module, class, method, function, traceback, frame,
161 The argument may be a module, class, method, function, traceback, frame,
163 or code object. The source code is returned as a list of all the lines
162 or code object. The source code is returned as a list of all the lines
164 in the file and the line number indexes a line in that list. An IOError
163 in the file and the line number indexes a line in that list. An IOError
165 is raised if the source code cannot be retrieved.
164 is raised if the source code cannot be retrieved.
166
165
167 FIXED version with which we monkeypatch the stdlib to work around a bug."""
166 FIXED version with which we monkeypatch the stdlib to work around a bug."""
168
167
169 file = getsourcefile(object) or getfile(object)
168 file = getsourcefile(object) or getfile(object)
170 # If the object is a frame, then trying to get the globals dict from its
169 # If the object is a frame, then trying to get the globals dict from its
171 # module won't work. Instead, the frame object itself has the globals
170 # module won't work. Instead, the frame object itself has the globals
172 # dictionary.
171 # dictionary.
173 globals_dict = None
172 globals_dict = None
174 if inspect.isframe(object):
173 if inspect.isframe(object):
175 # XXX: can this ever be false?
174 # XXX: can this ever be false?
176 globals_dict = object.f_globals
175 globals_dict = object.f_globals
177 else:
176 else:
178 module = getmodule(object, file)
177 module = getmodule(object, file)
179 if module:
178 if module:
180 globals_dict = module.__dict__
179 globals_dict = module.__dict__
181 lines = linecache.getlines(file, globals_dict)
180 lines = linecache.getlines(file, globals_dict)
182 if not lines:
181 if not lines:
183 raise IOError('could not get source code')
182 raise IOError('could not get source code')
184
183
185 if ismodule(object):
184 if ismodule(object):
186 return lines, 0
185 return lines, 0
187
186
188 if isclass(object):
187 if isclass(object):
189 name = object.__name__
188 name = object.__name__
190 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
189 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
191 # make some effort to find the best matching class definition:
190 # make some effort to find the best matching class definition:
192 # use the one with the least indentation, which is the one
191 # use the one with the least indentation, which is the one
193 # that's most probably not inside a function definition.
192 # that's most probably not inside a function definition.
194 candidates = []
193 candidates = []
195 for i in range(len(lines)):
194 for i in range(len(lines)):
196 match = pat.match(lines[i])
195 match = pat.match(lines[i])
197 if match:
196 if match:
198 # if it's at toplevel, it's already the best one
197 # if it's at toplevel, it's already the best one
199 if lines[i][0] == 'c':
198 if lines[i][0] == 'c':
200 return lines, i
199 return lines, i
201 # else add whitespace to candidate list
200 # else add whitespace to candidate list
202 candidates.append((match.group(1), i))
201 candidates.append((match.group(1), i))
203 if candidates:
202 if candidates:
204 # this will sort by whitespace, and by line number,
203 # this will sort by whitespace, and by line number,
205 # less whitespace first
204 # less whitespace first
206 candidates.sort()
205 candidates.sort()
207 return lines, candidates[0][1]
206 return lines, candidates[0][1]
208 else:
207 else:
209 raise IOError('could not find class definition')
208 raise IOError('could not find class definition')
210
209
211 if ismethod(object):
210 if ismethod(object):
212 object = object.__func__
211 object = object.__func__
213 if isfunction(object):
212 if isfunction(object):
214 object = object.__code__
213 object = object.__code__
215 if istraceback(object):
214 if istraceback(object):
216 object = object.tb_frame
215 object = object.tb_frame
217 if isframe(object):
216 if isframe(object):
218 object = object.f_code
217 object = object.f_code
219 if iscode(object):
218 if iscode(object):
220 if not hasattr(object, 'co_firstlineno'):
219 if not hasattr(object, 'co_firstlineno'):
221 raise IOError('could not find function definition')
220 raise IOError('could not find function definition')
222 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
221 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
223 pmatch = pat.match
222 pmatch = pat.match
224 # fperez - fix: sometimes, co_firstlineno can give a number larger than
223 # fperez - fix: sometimes, co_firstlineno can give a number larger than
225 # the length of lines, which causes an error. Safeguard against that.
224 # the length of lines, which causes an error. Safeguard against that.
226 lnum = min(object.co_firstlineno, len(lines)) - 1
225 lnum = min(object.co_firstlineno, len(lines)) - 1
227 while lnum > 0:
226 while lnum > 0:
228 if pmatch(lines[lnum]):
227 if pmatch(lines[lnum]):
229 break
228 break
230 lnum -= 1
229 lnum -= 1
231
230
232 return lines, lnum
231 return lines, lnum
233 raise IOError('could not find code object')
232 raise IOError('could not find code object')
234
233
235
234
236 # This is a patched version of inspect.getargs that applies the (unmerged)
235 # This is a patched version of inspect.getargs that applies the (unmerged)
237 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
236 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
238 # https://github.com/ipython/ipython/issues/8205 and
237 # https://github.com/ipython/ipython/issues/8205 and
239 # https://github.com/ipython/ipython/issues/8293
238 # https://github.com/ipython/ipython/issues/8293
240 def getargs(co):
239 def getargs(co):
241 """Get information about the arguments accepted by a code object.
240 """Get information about the arguments accepted by a code object.
242
241
243 Three things are returned: (args, varargs, varkw), where 'args' is
242 Three things are returned: (args, varargs, varkw), where 'args' is
244 a list of argument names (possibly containing nested lists), and
243 a list of argument names (possibly containing nested lists), and
245 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
244 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
246 if not iscode(co):
245 if not iscode(co):
247 raise TypeError('{!r} is not a code object'.format(co))
246 raise TypeError('{!r} is not a code object'.format(co))
248
247
249 nargs = co.co_argcount
248 nargs = co.co_argcount
250 names = co.co_varnames
249 names = co.co_varnames
251 args = list(names[:nargs])
250 args = list(names[:nargs])
252 step = 0
251 step = 0
253
252
254 # The following acrobatics are for anonymous (tuple) arguments.
253 # The following acrobatics are for anonymous (tuple) arguments.
255 for i in range(nargs):
254 for i in range(nargs):
256 if args[i][:1] in ('', '.'):
255 if args[i][:1] in ('', '.'):
257 stack, remain, count = [], [], []
256 stack, remain, count = [], [], []
258 while step < len(co.co_code):
257 while step < len(co.co_code):
259 op = ord(co.co_code[step])
258 op = ord(co.co_code[step])
260 step = step + 1
259 step = step + 1
261 if op >= dis.HAVE_ARGUMENT:
260 if op >= dis.HAVE_ARGUMENT:
262 opname = dis.opname[op]
261 opname = dis.opname[op]
263 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
262 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
264 step = step + 2
263 step = step + 2
265 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
264 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
266 remain.append(value)
265 remain.append(value)
267 count.append(value)
266 count.append(value)
268 elif opname in ('STORE_FAST', 'STORE_DEREF'):
267 elif opname in ('STORE_FAST', 'STORE_DEREF'):
269 if op in dis.haslocal:
268 if op in dis.haslocal:
270 stack.append(co.co_varnames[value])
269 stack.append(co.co_varnames[value])
271 elif op in dis.hasfree:
270 elif op in dis.hasfree:
272 stack.append((co.co_cellvars + co.co_freevars)[value])
271 stack.append((co.co_cellvars + co.co_freevars)[value])
273 # Special case for sublists of length 1: def foo((bar))
272 # Special case for sublists of length 1: def foo((bar))
274 # doesn't generate the UNPACK_TUPLE bytecode, so if
273 # doesn't generate the UNPACK_TUPLE bytecode, so if
275 # `remain` is empty here, we have such a sublist.
274 # `remain` is empty here, we have such a sublist.
276 if not remain:
275 if not remain:
277 stack[0] = [stack[0]]
276 stack[0] = [stack[0]]
278 break
277 break
279 else:
278 else:
280 remain[-1] = remain[-1] - 1
279 remain[-1] = remain[-1] - 1
281 while remain[-1] == 0:
280 while remain[-1] == 0:
282 remain.pop()
281 remain.pop()
283 size = count.pop()
282 size = count.pop()
284 stack[-size:] = [stack[-size:]]
283 stack[-size:] = [stack[-size:]]
285 if not remain:
284 if not remain:
286 break
285 break
287 remain[-1] = remain[-1] - 1
286 remain[-1] = remain[-1] - 1
288 if not remain:
287 if not remain:
289 break
288 break
290 args[i] = stack[0]
289 args[i] = stack[0]
291
290
292 varargs = None
291 varargs = None
293 if co.co_flags & inspect.CO_VARARGS:
292 if co.co_flags & inspect.CO_VARARGS:
294 varargs = co.co_varnames[nargs]
293 varargs = co.co_varnames[nargs]
295 nargs = nargs + 1
294 nargs = nargs + 1
296 varkw = None
295 varkw = None
297 if co.co_flags & inspect.CO_VARKEYWORDS:
296 if co.co_flags & inspect.CO_VARKEYWORDS:
298 varkw = co.co_varnames[nargs]
297 varkw = co.co_varnames[nargs]
299 return inspect.Arguments(args, varargs, varkw)
298 return inspect.Arguments(args, varargs, varkw)
300
299
301
300
302 # Monkeypatch inspect to apply our bugfix.
301 # Monkeypatch inspect to apply our bugfix.
303 def with_patch_inspect(f):
302 def with_patch_inspect(f):
304 """decorator for monkeypatching inspect.findsource"""
303 """decorator for monkeypatching inspect.findsource"""
305
304
306 def wrapped(*args, **kwargs):
305 def wrapped(*args, **kwargs):
307 save_findsource = inspect.findsource
306 save_findsource = inspect.findsource
308 save_getargs = inspect.getargs
307 save_getargs = inspect.getargs
309 inspect.findsource = findsource
308 inspect.findsource = findsource
310 inspect.getargs = getargs
309 inspect.getargs = getargs
311 try:
310 try:
312 return f(*args, **kwargs)
311 return f(*args, **kwargs)
313 finally:
312 finally:
314 inspect.findsource = save_findsource
313 inspect.findsource = save_findsource
315 inspect.getargs = save_getargs
314 inspect.getargs = save_getargs
316
315
317 return wrapped
316 return wrapped
318
317
319
318
320 if py3compat.PY3:
319 if py3compat.PY3:
321 fixed_getargvalues = inspect.getargvalues
320 fixed_getargvalues = inspect.getargvalues
322 else:
321 else:
323 # Fixes for https://github.com/ipython/ipython/issues/8293
322 # Fixes for https://github.com/ipython/ipython/issues/8293
324 # and https://github.com/ipython/ipython/issues/8205.
323 # and https://github.com/ipython/ipython/issues/8205.
325 # The relevant bug is caused by failure to correctly handle anonymous tuple
324 # The relevant bug is caused by failure to correctly handle anonymous tuple
326 # unpacking, which only exists in Python 2.
325 # unpacking, which only exists in Python 2.
327 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
326 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
328
327
329
328
330 def fix_frame_records_filenames(records):
329 def fix_frame_records_filenames(records):
331 """Try to fix the filenames in each record from inspect.getinnerframes().
330 """Try to fix the filenames in each record from inspect.getinnerframes().
332
331
333 Particularly, modules loaded from within zip files have useless filenames
332 Particularly, modules loaded from within zip files have useless filenames
334 attached to their code object, and inspect.getinnerframes() just uses it.
333 attached to their code object, and inspect.getinnerframes() just uses it.
335 """
334 """
336 fixed_records = []
335 fixed_records = []
337 for frame, filename, line_no, func_name, lines, index in records:
336 for frame, filename, line_no, func_name, lines, index in records:
338 # Look inside the frame's globals dictionary for __file__,
337 # Look inside the frame's globals dictionary for __file__,
339 # which should be better. However, keep Cython filenames since
338 # which should be better. However, keep Cython filenames since
340 # we prefer the source filenames over the compiled .so file.
339 # we prefer the source filenames over the compiled .so file.
341 filename = py3compat.cast_unicode_py2(filename, "utf-8")
340 filename = py3compat.cast_unicode_py2(filename, "utf-8")
342 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
341 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
343 better_fn = frame.f_globals.get('__file__', None)
342 better_fn = frame.f_globals.get('__file__', None)
344 if isinstance(better_fn, str):
343 if isinstance(better_fn, str):
345 # Check the type just in case someone did something weird with
344 # Check the type just in case someone did something weird with
346 # __file__. It might also be None if the error occurred during
345 # __file__. It might also be None if the error occurred during
347 # import.
346 # import.
348 filename = better_fn
347 filename = better_fn
349 fixed_records.append((frame, filename, line_no, func_name, lines, index))
348 fixed_records.append((frame, filename, line_no, func_name, lines, index))
350 return fixed_records
349 return fixed_records
351
350
352
351
353 @with_patch_inspect
352 @with_patch_inspect
354 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
353 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
355 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
354 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
356
355
357 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
356 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
358 # If the error is at the console, don't build any context, since it would
357 # If the error is at the console, don't build any context, since it would
359 # otherwise produce 5 blank lines printed out (there is no file at the
358 # otherwise produce 5 blank lines printed out (there is no file at the
360 # console)
359 # console)
361 rec_check = records[tb_offset:]
360 rec_check = records[tb_offset:]
362 try:
361 try:
363 rname = rec_check[0][1]
362 rname = rec_check[0][1]
364 if rname == '<ipython console>' or rname.endswith('<string>'):
363 if rname == '<ipython console>' or rname.endswith('<string>'):
365 return rec_check
364 return rec_check
366 except IndexError:
365 except IndexError:
367 pass
366 pass
368
367
369 aux = traceback.extract_tb(etb)
368 aux = traceback.extract_tb(etb)
370 assert len(records) == len(aux)
369 assert len(records) == len(aux)
371 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
370 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
372 maybeStart = lnum - 1 - context // 2
371 maybeStart = lnum - 1 - context // 2
373 start = max(maybeStart, 0)
372 start = max(maybeStart, 0)
374 end = start + context
373 end = start + context
375 lines = ulinecache.getlines(file)[start:end]
374 lines = ulinecache.getlines(file)[start:end]
376 buf = list(records[i])
375 buf = list(records[i])
377 buf[LNUM_POS] = lnum
376 buf[LNUM_POS] = lnum
378 buf[INDEX_POS] = lnum - 1 - start
377 buf[INDEX_POS] = lnum - 1 - start
379 buf[LINES_POS] = lines
378 buf[LINES_POS] = lines
380 records[i] = tuple(buf)
379 records[i] = tuple(buf)
381 return records[tb_offset:]
380 return records[tb_offset:]
382
381
383 # Helper function -- largely belongs to VerboseTB, but we need the same
382 # Helper function -- largely belongs to VerboseTB, but we need the same
384 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
383 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
385 # can be recognized properly by ipython.el's py-traceback-line-re
384 # can be recognized properly by ipython.el's py-traceback-line-re
386 # (SyntaxErrors have to be treated specially because they have no traceback)
385 # (SyntaxErrors have to be treated specially because they have no traceback)
387
386
388 _parser = PyColorize.Parser()
387 _parser = PyColorize.Parser()
389
388
390
389
391 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
390 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
392 numbers_width = INDENT_SIZE - 1
391 numbers_width = INDENT_SIZE - 1
393 res = []
392 res = []
394 i = lnum - index
393 i = lnum - index
395
394
396 # This lets us get fully syntax-highlighted tracebacks.
395 # This lets us get fully syntax-highlighted tracebacks.
397 if scheme is None:
396 if scheme is None:
398 ipinst = get_ipython()
397 ipinst = get_ipython()
399 if ipinst is not None:
398 if ipinst is not None:
400 scheme = ipinst.colors
399 scheme = ipinst.colors
401 else:
400 else:
402 scheme = DEFAULT_SCHEME
401 scheme = DEFAULT_SCHEME
403
402
404 _line_format = _parser.format2
403 _line_format = _parser.format2
405
404
406 for line in lines:
405 for line in lines:
407 line = py3compat.cast_unicode(line)
406 line = py3compat.cast_unicode(line)
408
407
409 new_line, err = _line_format(line, 'str', scheme)
408 new_line, err = _line_format(line, 'str', scheme)
410 if not err: line = new_line
409 if not err: line = new_line
411
410
412 if i == lnum:
411 if i == lnum:
413 # This is the line with the error
412 # This is the line with the error
414 pad = numbers_width - len(str(i))
413 pad = numbers_width - len(str(i))
415 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
414 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
416 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
415 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
417 Colors.line, line, Colors.Normal)
416 Colors.line, line, Colors.Normal)
418 else:
417 else:
419 num = '%*s' % (numbers_width, i)
418 num = '%*s' % (numbers_width, i)
420 line = '%s%s%s %s' % (Colors.lineno, num,
419 line = '%s%s%s %s' % (Colors.lineno, num,
421 Colors.Normal, line)
420 Colors.Normal, line)
422
421
423 res.append(line)
422 res.append(line)
424 if lvals and i == lnum:
423 if lvals and i == lnum:
425 res.append(lvals + '\n')
424 res.append(lvals + '\n')
426 i = i + 1
425 i = i + 1
427 return res
426 return res
428
427
429 def is_recursion_error(etype, value, records):
428 def is_recursion_error(etype, value, records):
430 try:
429 try:
431 # RecursionError is new in Python 3.5
430 # RecursionError is new in Python 3.5
432 recursion_error_type = RecursionError
431 recursion_error_type = RecursionError
433 except NameError:
432 except NameError:
434 recursion_error_type = RuntimeError
433 recursion_error_type = RuntimeError
435
434
436 # The default recursion limit is 1000, but some of that will be taken up
435 # The default recursion limit is 1000, but some of that will be taken up
437 # by stack frames in IPython itself. >500 frames probably indicates
436 # by stack frames in IPython itself. >500 frames probably indicates
438 # a recursion error.
437 # a recursion error.
439 return (etype is recursion_error_type) \
438 return (etype is recursion_error_type) \
440 and "recursion" in str(value).lower() \
439 and "recursion" in str(value).lower() \
441 and len(records) > 500
440 and len(records) > 500
442
441
443 def find_recursion(etype, value, records):
442 def find_recursion(etype, value, records):
444 """Identify the repeating stack frames from a RecursionError traceback
443 """Identify the repeating stack frames from a RecursionError traceback
445
444
446 'records' is a list as returned by VerboseTB.get_records()
445 'records' is a list as returned by VerboseTB.get_records()
447
446
448 Returns (last_unique, repeat_length)
447 Returns (last_unique, repeat_length)
449 """
448 """
450 # This involves a bit of guesswork - we want to show enough of the traceback
449 # This involves a bit of guesswork - we want to show enough of the traceback
451 # to indicate where the recursion is occurring. We guess that the innermost
450 # to indicate where the recursion is occurring. We guess that the innermost
452 # quarter of the traceback (250 frames by default) is repeats, and find the
451 # quarter of the traceback (250 frames by default) is repeats, and find the
453 # first frame (from in to out) that looks different.
452 # first frame (from in to out) that looks different.
454 if not is_recursion_error(etype, value, records):
453 if not is_recursion_error(etype, value, records):
455 return len(records), 0
454 return len(records), 0
456
455
457 # Select filename, lineno, func_name to track frames with
456 # Select filename, lineno, func_name to track frames with
458 records = [r[1:4] for r in records]
457 records = [r[1:4] for r in records]
459 inner_frames = records[-(len(records)//4):]
458 inner_frames = records[-(len(records)//4):]
460 frames_repeated = set(inner_frames)
459 frames_repeated = set(inner_frames)
461
460
462 last_seen_at = {}
461 last_seen_at = {}
463 longest_repeat = 0
462 longest_repeat = 0
464 i = len(records)
463 i = len(records)
465 for frame in reversed(records):
464 for frame in reversed(records):
466 i -= 1
465 i -= 1
467 if frame not in frames_repeated:
466 if frame not in frames_repeated:
468 last_unique = i
467 last_unique = i
469 break
468 break
470
469
471 if frame in last_seen_at:
470 if frame in last_seen_at:
472 distance = last_seen_at[frame] - i
471 distance = last_seen_at[frame] - i
473 longest_repeat = max(longest_repeat, distance)
472 longest_repeat = max(longest_repeat, distance)
474
473
475 last_seen_at[frame] = i
474 last_seen_at[frame] = i
476 else:
475 else:
477 last_unique = 0 # The whole traceback was recursion
476 last_unique = 0 # The whole traceback was recursion
478
477
479 return last_unique, longest_repeat
478 return last_unique, longest_repeat
480
479
481 #---------------------------------------------------------------------------
480 #---------------------------------------------------------------------------
482 # Module classes
481 # Module classes
483 class TBTools(colorable.Colorable):
482 class TBTools(colorable.Colorable):
484 """Basic tools used by all traceback printer classes."""
483 """Basic tools used by all traceback printer classes."""
485
484
486 # Number of frames to skip when reporting tracebacks
485 # Number of frames to skip when reporting tracebacks
487 tb_offset = 0
486 tb_offset = 0
488
487
489 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
488 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
490 # Whether to call the interactive pdb debugger after printing
489 # Whether to call the interactive pdb debugger after printing
491 # tracebacks or not
490 # tracebacks or not
492 super(TBTools, self).__init__(parent=parent, config=config)
491 super(TBTools, self).__init__(parent=parent, config=config)
493 self.call_pdb = call_pdb
492 self.call_pdb = call_pdb
494
493
495 # Output stream to write to. Note that we store the original value in
494 # Output stream to write to. Note that we store the original value in
496 # a private attribute and then make the public ostream a property, so
495 # a private attribute and then make the public ostream a property, so
497 # that we can delay accessing io.stdout until runtime. The way
496 # that we can delay accessing io.stdout until runtime. The way
498 # things are written now, the io.stdout object is dynamically managed
497 # things are written now, the io.stdout object is dynamically managed
499 # so a reference to it should NEVER be stored statically. This
498 # so a reference to it should NEVER be stored statically. This
500 # property approach confines this detail to a single location, and all
499 # property approach confines this detail to a single location, and all
501 # subclasses can simply access self.ostream for writing.
500 # subclasses can simply access self.ostream for writing.
502 self._ostream = ostream
501 self._ostream = ostream
503
502
504 # Create color table
503 # Create color table
505 self.color_scheme_table = exception_colors()
504 self.color_scheme_table = exception_colors()
506
505
507 self.set_colors(color_scheme)
506 self.set_colors(color_scheme)
508 self.old_scheme = color_scheme # save initial value for toggles
507 self.old_scheme = color_scheme # save initial value for toggles
509
508
510 if call_pdb:
509 if call_pdb:
511 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
510 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
512 else:
511 else:
513 self.pdb = None
512 self.pdb = None
514
513
515 def _get_ostream(self):
514 def _get_ostream(self):
516 """Output stream that exceptions are written to.
515 """Output stream that exceptions are written to.
517
516
518 Valid values are:
517 Valid values are:
519
518
520 - None: the default, which means that IPython will dynamically resolve
519 - None: the default, which means that IPython will dynamically resolve
521 to io.stdout. This ensures compatibility with most tools, including
520 to io.stdout. This ensures compatibility with most tools, including
522 Windows (where plain stdout doesn't recognize ANSI escapes).
521 Windows (where plain stdout doesn't recognize ANSI escapes).
523
522
524 - Any object with 'write' and 'flush' attributes.
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 def _set_ostream(self, val):
527 def _set_ostream(self, val):
529 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
528 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
530 self._ostream = val
529 self._ostream = val
531
530
532 ostream = property(_get_ostream, _set_ostream)
531 ostream = property(_get_ostream, _set_ostream)
533
532
534 def set_colors(self, *args, **kw):
533 def set_colors(self, *args, **kw):
535 """Shorthand access to the color table scheme selector method."""
534 """Shorthand access to the color table scheme selector method."""
536
535
537 # Set own color table
536 # Set own color table
538 self.color_scheme_table.set_active_scheme(*args, **kw)
537 self.color_scheme_table.set_active_scheme(*args, **kw)
539 # for convenience, set Colors to the active scheme
538 # for convenience, set Colors to the active scheme
540 self.Colors = self.color_scheme_table.active_colors
539 self.Colors = self.color_scheme_table.active_colors
541 # Also set colors of debugger
540 # Also set colors of debugger
542 if hasattr(self, 'pdb') and self.pdb is not None:
541 if hasattr(self, 'pdb') and self.pdb is not None:
543 self.pdb.set_colors(*args, **kw)
542 self.pdb.set_colors(*args, **kw)
544
543
545 def color_toggle(self):
544 def color_toggle(self):
546 """Toggle between the currently active color scheme and NoColor."""
545 """Toggle between the currently active color scheme and NoColor."""
547
546
548 if self.color_scheme_table.active_scheme_name == 'NoColor':
547 if self.color_scheme_table.active_scheme_name == 'NoColor':
549 self.color_scheme_table.set_active_scheme(self.old_scheme)
548 self.color_scheme_table.set_active_scheme(self.old_scheme)
550 self.Colors = self.color_scheme_table.active_colors
549 self.Colors = self.color_scheme_table.active_colors
551 else:
550 else:
552 self.old_scheme = self.color_scheme_table.active_scheme_name
551 self.old_scheme = self.color_scheme_table.active_scheme_name
553 self.color_scheme_table.set_active_scheme('NoColor')
552 self.color_scheme_table.set_active_scheme('NoColor')
554 self.Colors = self.color_scheme_table.active_colors
553 self.Colors = self.color_scheme_table.active_colors
555
554
556 def stb2text(self, stb):
555 def stb2text(self, stb):
557 """Convert a structured traceback (a list) to a string."""
556 """Convert a structured traceback (a list) to a string."""
558 return '\n'.join(stb)
557 return '\n'.join(stb)
559
558
560 def text(self, etype, value, tb, tb_offset=None, context=5):
559 def text(self, etype, value, tb, tb_offset=None, context=5):
561 """Return formatted traceback.
560 """Return formatted traceback.
562
561
563 Subclasses may override this if they add extra arguments.
562 Subclasses may override this if they add extra arguments.
564 """
563 """
565 tb_list = self.structured_traceback(etype, value, tb,
564 tb_list = self.structured_traceback(etype, value, tb,
566 tb_offset, context)
565 tb_offset, context)
567 return self.stb2text(tb_list)
566 return self.stb2text(tb_list)
568
567
569 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
568 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
570 context=5, mode=None):
569 context=5, mode=None):
571 """Return a list of traceback frames.
570 """Return a list of traceback frames.
572
571
573 Must be implemented by each class.
572 Must be implemented by each class.
574 """
573 """
575 raise NotImplementedError()
574 raise NotImplementedError()
576
575
577
576
578 #---------------------------------------------------------------------------
577 #---------------------------------------------------------------------------
579 class ListTB(TBTools):
578 class ListTB(TBTools):
580 """Print traceback information from a traceback list, with optional color.
579 """Print traceback information from a traceback list, with optional color.
581
580
582 Calling requires 3 arguments: (etype, evalue, elist)
581 Calling requires 3 arguments: (etype, evalue, elist)
583 as would be obtained by::
582 as would be obtained by::
584
583
585 etype, evalue, tb = sys.exc_info()
584 etype, evalue, tb = sys.exc_info()
586 if tb:
585 if tb:
587 elist = traceback.extract_tb(tb)
586 elist = traceback.extract_tb(tb)
588 else:
587 else:
589 elist = None
588 elist = None
590
589
591 It can thus be used by programs which need to process the traceback before
590 It can thus be used by programs which need to process the traceback before
592 printing (such as console replacements based on the code module from the
591 printing (such as console replacements based on the code module from the
593 standard library).
592 standard library).
594
593
595 Because they are meant to be called without a full traceback (only a
594 Because they are meant to be called without a full traceback (only a
596 list), instances of this class can't call the interactive pdb debugger."""
595 list), instances of this class can't call the interactive pdb debugger."""
597
596
598 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
597 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
599 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
598 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
600 ostream=ostream, parent=parent)
599 ostream=ostream, parent=parent)
601
600
602 def __call__(self, etype, value, elist):
601 def __call__(self, etype, value, elist):
603 self.ostream.flush()
602 self.ostream.flush()
604 self.ostream.write(self.text(etype, value, elist))
603 self.ostream.write(self.text(etype, value, elist))
605 self.ostream.write('\n')
604 self.ostream.write('\n')
606
605
607 def structured_traceback(self, etype, value, elist, tb_offset=None,
606 def structured_traceback(self, etype, value, elist, tb_offset=None,
608 context=5):
607 context=5):
609 """Return a color formatted string with the traceback info.
608 """Return a color formatted string with the traceback info.
610
609
611 Parameters
610 Parameters
612 ----------
611 ----------
613 etype : exception type
612 etype : exception type
614 Type of the exception raised.
613 Type of the exception raised.
615
614
616 value : object
615 value : object
617 Data stored in the exception
616 Data stored in the exception
618
617
619 elist : list
618 elist : list
620 List of frames, see class docstring for details.
619 List of frames, see class docstring for details.
621
620
622 tb_offset : int, optional
621 tb_offset : int, optional
623 Number of frames in the traceback to skip. If not given, the
622 Number of frames in the traceback to skip. If not given, the
624 instance value is used (set in constructor).
623 instance value is used (set in constructor).
625
624
626 context : int, optional
625 context : int, optional
627 Number of lines of context information to print.
626 Number of lines of context information to print.
628
627
629 Returns
628 Returns
630 -------
629 -------
631 String with formatted exception.
630 String with formatted exception.
632 """
631 """
633 tb_offset = self.tb_offset if tb_offset is None else tb_offset
632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
634 Colors = self.Colors
633 Colors = self.Colors
635 out_list = []
634 out_list = []
636 if elist:
635 if elist:
637
636
638 if tb_offset and len(elist) > tb_offset:
637 if tb_offset and len(elist) > tb_offset:
639 elist = elist[tb_offset:]
638 elist = elist[tb_offset:]
640
639
641 out_list.append('Traceback %s(most recent call last)%s:' %
640 out_list.append('Traceback %s(most recent call last)%s:' %
642 (Colors.normalEm, Colors.Normal) + '\n')
641 (Colors.normalEm, Colors.Normal) + '\n')
643 out_list.extend(self._format_list(elist))
642 out_list.extend(self._format_list(elist))
644 # The exception info should be a single entry in the list.
643 # The exception info should be a single entry in the list.
645 lines = ''.join(self._format_exception_only(etype, value))
644 lines = ''.join(self._format_exception_only(etype, value))
646 out_list.append(lines)
645 out_list.append(lines)
647
646
648 # Note: this code originally read:
647 # Note: this code originally read:
649
648
650 ## for line in lines[:-1]:
649 ## for line in lines[:-1]:
651 ## out_list.append(" "+line)
650 ## out_list.append(" "+line)
652 ## out_list.append(lines[-1])
651 ## out_list.append(lines[-1])
653
652
654 # This means it was indenting everything but the last line by a little
653 # This means it was indenting everything but the last line by a little
655 # bit. I've disabled this for now, but if we see ugliness somewhere we
654 # bit. I've disabled this for now, but if we see ugliness somewhere we
656 # can restore it.
655 # can restore it.
657
656
658 return out_list
657 return out_list
659
658
660 def _format_list(self, extracted_list):
659 def _format_list(self, extracted_list):
661 """Format a list of traceback entry tuples for printing.
660 """Format a list of traceback entry tuples for printing.
662
661
663 Given a list of tuples as returned by extract_tb() or
662 Given a list of tuples as returned by extract_tb() or
664 extract_stack(), return a list of strings ready for printing.
663 extract_stack(), return a list of strings ready for printing.
665 Each string in the resulting list corresponds to the item with the
664 Each string in the resulting list corresponds to the item with the
666 same index in the argument list. Each string ends in a newline;
665 same index in the argument list. Each string ends in a newline;
667 the strings may contain internal newlines as well, for those items
666 the strings may contain internal newlines as well, for those items
668 whose source text line is not None.
667 whose source text line is not None.
669
668
670 Lifted almost verbatim from traceback.py
669 Lifted almost verbatim from traceback.py
671 """
670 """
672
671
673 Colors = self.Colors
672 Colors = self.Colors
674 list = []
673 list = []
675 for filename, lineno, name, line in extracted_list[:-1]:
674 for filename, lineno, name, line in extracted_list[:-1]:
676 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
675 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
677 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
676 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
678 Colors.lineno, lineno, Colors.Normal,
677 Colors.lineno, lineno, Colors.Normal,
679 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
678 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
680 if line:
679 if line:
681 item += ' %s\n' % line.strip()
680 item += ' %s\n' % line.strip()
682 list.append(item)
681 list.append(item)
683 # Emphasize the last entry
682 # Emphasize the last entry
684 filename, lineno, name, line = extracted_list[-1]
683 filename, lineno, name, line = extracted_list[-1]
685 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
684 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
686 (Colors.normalEm,
685 (Colors.normalEm,
687 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
686 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
688 Colors.linenoEm, lineno, Colors.normalEm,
687 Colors.linenoEm, lineno, Colors.normalEm,
689 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
688 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
690 Colors.Normal)
689 Colors.Normal)
691 if line:
690 if line:
692 item += '%s %s%s\n' % (Colors.line, line.strip(),
691 item += '%s %s%s\n' % (Colors.line, line.strip(),
693 Colors.Normal)
692 Colors.Normal)
694 list.append(item)
693 list.append(item)
695 return list
694 return list
696
695
697 def _format_exception_only(self, etype, value):
696 def _format_exception_only(self, etype, value):
698 """Format the exception part of a traceback.
697 """Format the exception part of a traceback.
699
698
700 The arguments are the exception type and value such as given by
699 The arguments are the exception type and value such as given by
701 sys.exc_info()[:2]. The return value is a list of strings, each ending
700 sys.exc_info()[:2]. The return value is a list of strings, each ending
702 in a newline. Normally, the list contains a single string; however,
701 in a newline. Normally, the list contains a single string; however,
703 for SyntaxError exceptions, it contains several lines that (when
702 for SyntaxError exceptions, it contains several lines that (when
704 printed) display detailed information about where the syntax error
703 printed) display detailed information about where the syntax error
705 occurred. The message indicating which exception occurred is the
704 occurred. The message indicating which exception occurred is the
706 always last string in the list.
705 always last string in the list.
707
706
708 Also lifted nearly verbatim from traceback.py
707 Also lifted nearly verbatim from traceback.py
709 """
708 """
710 have_filedata = False
709 have_filedata = False
711 Colors = self.Colors
710 Colors = self.Colors
712 list = []
711 list = []
713 stype = Colors.excName + etype.__name__ + Colors.Normal
712 stype = Colors.excName + etype.__name__ + Colors.Normal
714 if value is None:
713 if value is None:
715 # Not sure if this can still happen in Python 2.6 and above
714 # Not sure if this can still happen in Python 2.6 and above
716 list.append(py3compat.cast_unicode(stype) + '\n')
715 list.append(py3compat.cast_unicode(stype) + '\n')
717 else:
716 else:
718 if issubclass(etype, SyntaxError):
717 if issubclass(etype, SyntaxError):
719 have_filedata = True
718 have_filedata = True
720 if not value.filename: value.filename = "<string>"
719 if not value.filename: value.filename = "<string>"
721 if value.lineno:
720 if value.lineno:
722 lineno = value.lineno
721 lineno = value.lineno
723 textline = ulinecache.getline(value.filename, value.lineno)
722 textline = ulinecache.getline(value.filename, value.lineno)
724 else:
723 else:
725 lineno = 'unknown'
724 lineno = 'unknown'
726 textline = ''
725 textline = ''
727 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
726 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
728 (Colors.normalEm,
727 (Colors.normalEm,
729 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
728 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
730 Colors.linenoEm, lineno, Colors.Normal ))
729 Colors.linenoEm, lineno, Colors.Normal ))
731 if textline == '':
730 if textline == '':
732 textline = py3compat.cast_unicode(value.text, "utf-8")
731 textline = py3compat.cast_unicode(value.text, "utf-8")
733
732
734 if textline is not None:
733 if textline is not None:
735 i = 0
734 i = 0
736 while i < len(textline) and textline[i].isspace():
735 while i < len(textline) and textline[i].isspace():
737 i += 1
736 i += 1
738 list.append('%s %s%s\n' % (Colors.line,
737 list.append('%s %s%s\n' % (Colors.line,
739 textline.strip(),
738 textline.strip(),
740 Colors.Normal))
739 Colors.Normal))
741 if value.offset is not None:
740 if value.offset is not None:
742 s = ' '
741 s = ' '
743 for c in textline[i:value.offset - 1]:
742 for c in textline[i:value.offset - 1]:
744 if c.isspace():
743 if c.isspace():
745 s += c
744 s += c
746 else:
745 else:
747 s += ' '
746 s += ' '
748 list.append('%s%s^%s\n' % (Colors.caret, s,
747 list.append('%s%s^%s\n' % (Colors.caret, s,
749 Colors.Normal))
748 Colors.Normal))
750
749
751 try:
750 try:
752 s = value.msg
751 s = value.msg
753 except Exception:
752 except Exception:
754 s = self._some_str(value)
753 s = self._some_str(value)
755 if s:
754 if s:
756 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
755 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
757 Colors.Normal, s))
756 Colors.Normal, s))
758 else:
757 else:
759 list.append('%s\n' % str(stype))
758 list.append('%s\n' % str(stype))
760
759
761 # sync with user hooks
760 # sync with user hooks
762 if have_filedata:
761 if have_filedata:
763 ipinst = get_ipython()
762 ipinst = get_ipython()
764 if ipinst is not None:
763 if ipinst is not None:
765 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
764 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
766
765
767 return list
766 return list
768
767
769 def get_exception_only(self, etype, value):
768 def get_exception_only(self, etype, value):
770 """Only print the exception type and message, without a traceback.
769 """Only print the exception type and message, without a traceback.
771
770
772 Parameters
771 Parameters
773 ----------
772 ----------
774 etype : exception type
773 etype : exception type
775 value : exception value
774 value : exception value
776 """
775 """
777 return ListTB.structured_traceback(self, etype, value, [])
776 return ListTB.structured_traceback(self, etype, value, [])
778
777
779 def show_exception_only(self, etype, evalue):
778 def show_exception_only(self, etype, evalue):
780 """Only print the exception type and message, without a traceback.
779 """Only print the exception type and message, without a traceback.
781
780
782 Parameters
781 Parameters
783 ----------
782 ----------
784 etype : exception type
783 etype : exception type
785 value : exception value
784 value : exception value
786 """
785 """
787 # This method needs to use __call__ from *this* class, not the one from
786 # This method needs to use __call__ from *this* class, not the one from
788 # a subclass whose signature or behavior may be different
787 # a subclass whose signature or behavior may be different
789 ostream = self.ostream
788 ostream = self.ostream
790 ostream.flush()
789 ostream.flush()
791 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
790 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
792 ostream.flush()
791 ostream.flush()
793
792
794 def _some_str(self, value):
793 def _some_str(self, value):
795 # Lifted from traceback.py
794 # Lifted from traceback.py
796 try:
795 try:
797 return str(value)
796 return str(value)
798 except:
797 except:
799 return '<unprintable %s object>' % type(value).__name__
798 return '<unprintable %s object>' % type(value).__name__
800
799
801
800
802 #----------------------------------------------------------------------------
801 #----------------------------------------------------------------------------
803 class VerboseTB(TBTools):
802 class VerboseTB(TBTools):
804 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
803 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
805 of HTML. Requires inspect and pydoc. Crazy, man.
804 of HTML. Requires inspect and pydoc. Crazy, man.
806
805
807 Modified version which optionally strips the topmost entries from the
806 Modified version which optionally strips the topmost entries from the
808 traceback, to be used with alternate interpreters (because their own code
807 traceback, to be used with alternate interpreters (because their own code
809 would appear in the traceback)."""
808 would appear in the traceback)."""
810
809
811 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
810 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
812 tb_offset=0, long_header=False, include_vars=True,
811 tb_offset=0, long_header=False, include_vars=True,
813 check_cache=None):
812 check_cache=None):
814 """Specify traceback offset, headers and color scheme.
813 """Specify traceback offset, headers and color scheme.
815
814
816 Define how many frames to drop from the tracebacks. Calling it with
815 Define how many frames to drop from the tracebacks. Calling it with
817 tb_offset=1 allows use of this handler in interpreters which will have
816 tb_offset=1 allows use of this handler in interpreters which will have
818 their own code at the top of the traceback (VerboseTB will first
817 their own code at the top of the traceback (VerboseTB will first
819 remove that frame before printing the traceback info)."""
818 remove that frame before printing the traceback info)."""
820 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
819 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
821 ostream=ostream)
820 ostream=ostream)
822 self.tb_offset = tb_offset
821 self.tb_offset = tb_offset
823 self.long_header = long_header
822 self.long_header = long_header
824 self.include_vars = include_vars
823 self.include_vars = include_vars
825 # By default we use linecache.checkcache, but the user can provide a
824 # By default we use linecache.checkcache, but the user can provide a
826 # different check_cache implementation. This is used by the IPython
825 # different check_cache implementation. This is used by the IPython
827 # kernel to provide tracebacks for interactive code that is cached,
826 # kernel to provide tracebacks for interactive code that is cached,
828 # by a compiler instance that flushes the linecache but preserves its
827 # by a compiler instance that flushes the linecache but preserves its
829 # own code cache.
828 # own code cache.
830 if check_cache is None:
829 if check_cache is None:
831 check_cache = linecache.checkcache
830 check_cache = linecache.checkcache
832 self.check_cache = check_cache
831 self.check_cache = check_cache
833
832
834 def format_records(self, records, last_unique, recursion_repeat):
833 def format_records(self, records, last_unique, recursion_repeat):
835 """Format the stack frames of the traceback"""
834 """Format the stack frames of the traceback"""
836 frames = []
835 frames = []
837 for r in records[:last_unique+recursion_repeat+1]:
836 for r in records[:last_unique+recursion_repeat+1]:
838 #print '*** record:',file,lnum,func,lines,index # dbg
837 #print '*** record:',file,lnum,func,lines,index # dbg
839 frames.append(self.format_record(*r))
838 frames.append(self.format_record(*r))
840
839
841 if recursion_repeat:
840 if recursion_repeat:
842 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
841 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
843 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
842 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
844
843
845 return frames
844 return frames
846
845
847 def format_record(self, frame, file, lnum, func, lines, index):
846 def format_record(self, frame, file, lnum, func, lines, index):
848 """Format a single stack frame"""
847 """Format a single stack frame"""
849 Colors = self.Colors # just a shorthand + quicker name lookup
848 Colors = self.Colors # just a shorthand + quicker name lookup
850 ColorsNormal = Colors.Normal # used a lot
849 ColorsNormal = Colors.Normal # used a lot
851 col_scheme = self.color_scheme_table.active_scheme_name
850 col_scheme = self.color_scheme_table.active_scheme_name
852 indent = ' ' * INDENT_SIZE
851 indent = ' ' * INDENT_SIZE
853 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
852 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
854 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
853 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
855 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
854 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
856 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
855 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
857 ColorsNormal)
856 ColorsNormal)
858 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
857 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
859 (Colors.vName, Colors.valEm, ColorsNormal)
858 (Colors.vName, Colors.valEm, ColorsNormal)
860 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
859 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
861 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
860 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
862 Colors.vName, ColorsNormal)
861 Colors.vName, ColorsNormal)
863 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
862 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
864
863
865 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
864 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
866 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
865 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
867 ColorsNormal)
866 ColorsNormal)
868
867
869 abspath = os.path.abspath
868 abspath = os.path.abspath
870
869
871
870
872 if not file:
871 if not file:
873 file = '?'
872 file = '?'
874 elif file.startswith(str("<")) and file.endswith(str(">")):
873 elif file.startswith(str("<")) and file.endswith(str(">")):
875 # Not a real filename, no problem...
874 # Not a real filename, no problem...
876 pass
875 pass
877 elif not os.path.isabs(file):
876 elif not os.path.isabs(file):
878 # Try to make the filename absolute by trying all
877 # Try to make the filename absolute by trying all
879 # sys.path entries (which is also what linecache does)
878 # sys.path entries (which is also what linecache does)
880 for dirname in sys.path:
879 for dirname in sys.path:
881 try:
880 try:
882 fullname = os.path.join(dirname, file)
881 fullname = os.path.join(dirname, file)
883 if os.path.isfile(fullname):
882 if os.path.isfile(fullname):
884 file = os.path.abspath(fullname)
883 file = os.path.abspath(fullname)
885 break
884 break
886 except Exception:
885 except Exception:
887 # Just in case that sys.path contains very
886 # Just in case that sys.path contains very
888 # strange entries...
887 # strange entries...
889 pass
888 pass
890
889
891 file = py3compat.cast_unicode(file, util_path.fs_encoding)
890 file = py3compat.cast_unicode(file, util_path.fs_encoding)
892 link = tpl_link % file
891 link = tpl_link % file
893 args, varargs, varkw, locals = fixed_getargvalues(frame)
892 args, varargs, varkw, locals = fixed_getargvalues(frame)
894
893
895 if func == '?':
894 if func == '?':
896 call = ''
895 call = ''
897 else:
896 else:
898 # Decide whether to include variable details or not
897 # Decide whether to include variable details or not
899 var_repr = self.include_vars and eqrepr or nullrepr
898 var_repr = self.include_vars and eqrepr or nullrepr
900 try:
899 try:
901 call = tpl_call % (func, inspect.formatargvalues(args,
900 call = tpl_call % (func, inspect.formatargvalues(args,
902 varargs, varkw,
901 varargs, varkw,
903 locals, formatvalue=var_repr))
902 locals, formatvalue=var_repr))
904 except KeyError:
903 except KeyError:
905 # This happens in situations like errors inside generator
904 # This happens in situations like errors inside generator
906 # expressions, where local variables are listed in the
905 # expressions, where local variables are listed in the
907 # line, but can't be extracted from the frame. I'm not
906 # line, but can't be extracted from the frame. I'm not
908 # 100% sure this isn't actually a bug in inspect itself,
907 # 100% sure this isn't actually a bug in inspect itself,
909 # but since there's no info for us to compute with, the
908 # but since there's no info for us to compute with, the
910 # best we can do is report the failure and move on. Here
909 # best we can do is report the failure and move on. Here
911 # we must *not* call any traceback construction again,
910 # we must *not* call any traceback construction again,
912 # because that would mess up use of %debug later on. So we
911 # because that would mess up use of %debug later on. So we
913 # simply report the failure and move on. The only
912 # simply report the failure and move on. The only
914 # limitation will be that this frame won't have locals
913 # limitation will be that this frame won't have locals
915 # listed in the call signature. Quite subtle problem...
914 # listed in the call signature. Quite subtle problem...
916 # I can't think of a good way to validate this in a unit
915 # I can't think of a good way to validate this in a unit
917 # test, but running a script consisting of:
916 # test, but running a script consisting of:
918 # dict( (k,v.strip()) for (k,v) in range(10) )
917 # dict( (k,v.strip()) for (k,v) in range(10) )
919 # will illustrate the error, if this exception catch is
918 # will illustrate the error, if this exception catch is
920 # disabled.
919 # disabled.
921 call = tpl_call_fail % func
920 call = tpl_call_fail % func
922
921
923 # Don't attempt to tokenize binary files.
922 # Don't attempt to tokenize binary files.
924 if file.endswith(('.so', '.pyd', '.dll')):
923 if file.endswith(('.so', '.pyd', '.dll')):
925 return '%s %s\n' % (link, call)
924 return '%s %s\n' % (link, call)
926
925
927 elif file.endswith(('.pyc', '.pyo')):
926 elif file.endswith(('.pyc', '.pyo')):
928 # Look up the corresponding source file.
927 # Look up the corresponding source file.
929 file = openpy.source_from_cache(file)
928 file = openpy.source_from_cache(file)
930
929
931 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
930 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
932 line = getline(file, lnum[0])
931 line = getline(file, lnum[0])
933 lnum[0] += 1
932 lnum[0] += 1
934 return line
933 return line
935
934
936 # Build the list of names on this line of code where the exception
935 # Build the list of names on this line of code where the exception
937 # occurred.
936 # occurred.
938 try:
937 try:
939 names = []
938 names = []
940 name_cont = False
939 name_cont = False
941
940
942 for token_type, token, start, end, line in generate_tokens(linereader):
941 for token_type, token, start, end, line in generate_tokens(linereader):
943 # build composite names
942 # build composite names
944 if token_type == tokenize.NAME and token not in keyword.kwlist:
943 if token_type == tokenize.NAME and token not in keyword.kwlist:
945 if name_cont:
944 if name_cont:
946 # Continuation of a dotted name
945 # Continuation of a dotted name
947 try:
946 try:
948 names[-1].append(token)
947 names[-1].append(token)
949 except IndexError:
948 except IndexError:
950 names.append([token])
949 names.append([token])
951 name_cont = False
950 name_cont = False
952 else:
951 else:
953 # Regular new names. We append everything, the caller
952 # Regular new names. We append everything, the caller
954 # will be responsible for pruning the list later. It's
953 # will be responsible for pruning the list later. It's
955 # very tricky to try to prune as we go, b/c composite
954 # very tricky to try to prune as we go, b/c composite
956 # names can fool us. The pruning at the end is easy
955 # names can fool us. The pruning at the end is easy
957 # to do (or the caller can print a list with repeated
956 # to do (or the caller can print a list with repeated
958 # names if so desired.
957 # names if so desired.
959 names.append([token])
958 names.append([token])
960 elif token == '.':
959 elif token == '.':
961 name_cont = True
960 name_cont = True
962 elif token_type == tokenize.NEWLINE:
961 elif token_type == tokenize.NEWLINE:
963 break
962 break
964
963
965 except (IndexError, UnicodeDecodeError, SyntaxError):
964 except (IndexError, UnicodeDecodeError, SyntaxError):
966 # signals exit of tokenizer
965 # signals exit of tokenizer
967 # SyntaxError can occur if the file is not actually Python
966 # SyntaxError can occur if the file is not actually Python
968 # - see gh-6300
967 # - see gh-6300
969 pass
968 pass
970 except tokenize.TokenError as msg:
969 except tokenize.TokenError as msg:
971 _m = ("An unexpected error occurred while tokenizing input\n"
970 _m = ("An unexpected error occurred while tokenizing input\n"
972 "The following traceback may be corrupted or invalid\n"
971 "The following traceback may be corrupted or invalid\n"
973 "The error message is: %s\n" % msg)
972 "The error message is: %s\n" % msg)
974 error(_m)
973 error(_m)
975
974
976 # Join composite names (e.g. "dict.fromkeys")
975 # Join composite names (e.g. "dict.fromkeys")
977 names = ['.'.join(n) for n in names]
976 names = ['.'.join(n) for n in names]
978 # prune names list of duplicates, but keep the right order
977 # prune names list of duplicates, but keep the right order
979 unique_names = uniq_stable(names)
978 unique_names = uniq_stable(names)
980
979
981 # Start loop over vars
980 # Start loop over vars
982 lvals = []
981 lvals = []
983 if self.include_vars:
982 if self.include_vars:
984 for name_full in unique_names:
983 for name_full in unique_names:
985 name_base = name_full.split('.', 1)[0]
984 name_base = name_full.split('.', 1)[0]
986 if name_base in frame.f_code.co_varnames:
985 if name_base in frame.f_code.co_varnames:
987 if name_base in locals:
986 if name_base in locals:
988 try:
987 try:
989 value = repr(eval(name_full, locals))
988 value = repr(eval(name_full, locals))
990 except:
989 except:
991 value = undefined
990 value = undefined
992 else:
991 else:
993 value = undefined
992 value = undefined
994 name = tpl_local_var % name_full
993 name = tpl_local_var % name_full
995 else:
994 else:
996 if name_base in frame.f_globals:
995 if name_base in frame.f_globals:
997 try:
996 try:
998 value = repr(eval(name_full, frame.f_globals))
997 value = repr(eval(name_full, frame.f_globals))
999 except:
998 except:
1000 value = undefined
999 value = undefined
1001 else:
1000 else:
1002 value = undefined
1001 value = undefined
1003 name = tpl_global_var % name_full
1002 name = tpl_global_var % name_full
1004 lvals.append(tpl_name_val % (name, value))
1003 lvals.append(tpl_name_val % (name, value))
1005 if lvals:
1004 if lvals:
1006 lvals = '%s%s' % (indent, em_normal.join(lvals))
1005 lvals = '%s%s' % (indent, em_normal.join(lvals))
1007 else:
1006 else:
1008 lvals = ''
1007 lvals = ''
1009
1008
1010 level = '%s %s\n' % (link, call)
1009 level = '%s %s\n' % (link, call)
1011
1010
1012 if index is None:
1011 if index is None:
1013 return level
1012 return level
1014 else:
1013 else:
1015 return '%s%s' % (level, ''.join(
1014 return '%s%s' % (level, ''.join(
1016 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1015 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1017 col_scheme)))
1016 col_scheme)))
1018
1017
1019 def prepare_chained_exception_message(self, cause):
1018 def prepare_chained_exception_message(self, cause):
1020 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1019 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1021 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1020 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1022
1021
1023 if cause:
1022 if cause:
1024 message = [[direct_cause]]
1023 message = [[direct_cause]]
1025 else:
1024 else:
1026 message = [[exception_during_handling]]
1025 message = [[exception_during_handling]]
1027 return message
1026 return message
1028
1027
1029 def prepare_header(self, etype, long_version=False):
1028 def prepare_header(self, etype, long_version=False):
1030 colors = self.Colors # just a shorthand + quicker name lookup
1029 colors = self.Colors # just a shorthand + quicker name lookup
1031 colorsnormal = colors.Normal # used a lot
1030 colorsnormal = colors.Normal # used a lot
1032 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1031 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1033 width = min(75, get_terminal_size()[0])
1032 width = min(75, get_terminal_size()[0])
1034 if long_version:
1033 if long_version:
1035 # Header with the exception type, python version, and date
1034 # Header with the exception type, python version, and date
1036 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1035 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1037 date = time.ctime(time.time())
1036 date = time.ctime(time.time())
1038
1037
1039 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1038 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1040 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1039 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1041 pyver, date.rjust(width) )
1040 pyver, date.rjust(width) )
1042 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1041 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1043 "\ncalls leading up to the error, with the most recent (innermost) call last."
1042 "\ncalls leading up to the error, with the most recent (innermost) call last."
1044 else:
1043 else:
1045 # Simplified header
1044 # Simplified header
1046 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1045 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1047 rjust(width - len(str(etype))) )
1046 rjust(width - len(str(etype))) )
1048
1047
1049 return head
1048 return head
1050
1049
1051 def format_exception(self, etype, evalue):
1050 def format_exception(self, etype, evalue):
1052 colors = self.Colors # just a shorthand + quicker name lookup
1051 colors = self.Colors # just a shorthand + quicker name lookup
1053 colorsnormal = colors.Normal # used a lot
1052 colorsnormal = colors.Normal # used a lot
1054 indent = ' ' * INDENT_SIZE
1053 indent = ' ' * INDENT_SIZE
1055 # Get (safely) a string form of the exception info
1054 # Get (safely) a string form of the exception info
1056 try:
1055 try:
1057 etype_str, evalue_str = map(str, (etype, evalue))
1056 etype_str, evalue_str = map(str, (etype, evalue))
1058 except:
1057 except:
1059 # User exception is improperly defined.
1058 # User exception is improperly defined.
1060 etype, evalue = str, sys.exc_info()[:2]
1059 etype, evalue = str, sys.exc_info()[:2]
1061 etype_str, evalue_str = map(str, (etype, evalue))
1060 etype_str, evalue_str = map(str, (etype, evalue))
1062 # ... and format it
1061 # ... and format it
1063 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1062 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1064 colorsnormal, py3compat.cast_unicode(evalue_str))]
1063 colorsnormal, py3compat.cast_unicode(evalue_str))]
1065
1064
1066 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1065 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1067 try:
1066 try:
1068 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1067 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1069 except:
1068 except:
1070 # Every now and then, an object with funny internals blows up
1069 # Every now and then, an object with funny internals blows up
1071 # when dir() is called on it. We do the best we can to report
1070 # when dir() is called on it. We do the best we can to report
1072 # the problem and continue
1071 # the problem and continue
1073 _m = '%sException reporting error (object with broken dir())%s:'
1072 _m = '%sException reporting error (object with broken dir())%s:'
1074 exception.append(_m % (colors.excName, colorsnormal))
1073 exception.append(_m % (colors.excName, colorsnormal))
1075 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1074 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1076 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1075 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1077 colorsnormal, py3compat.cast_unicode(evalue_str)))
1076 colorsnormal, py3compat.cast_unicode(evalue_str)))
1078 names = []
1077 names = []
1079 for name in names:
1078 for name in names:
1080 value = text_repr(getattr(evalue, name))
1079 value = text_repr(getattr(evalue, name))
1081 exception.append('\n%s%s = %s' % (indent, name, value))
1080 exception.append('\n%s%s = %s' % (indent, name, value))
1082
1081
1083 return exception
1082 return exception
1084
1083
1085 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1084 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1086 """Formats the header, traceback and exception message for a single exception.
1085 """Formats the header, traceback and exception message for a single exception.
1087
1086
1088 This may be called multiple times by Python 3 exception chaining
1087 This may be called multiple times by Python 3 exception chaining
1089 (PEP 3134).
1088 (PEP 3134).
1090 """
1089 """
1091 # some locals
1090 # some locals
1092 orig_etype = etype
1091 orig_etype = etype
1093 try:
1092 try:
1094 etype = etype.__name__
1093 etype = etype.__name__
1095 except AttributeError:
1094 except AttributeError:
1096 pass
1095 pass
1097
1096
1098 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1097 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1099 head = self.prepare_header(etype, self.long_header)
1098 head = self.prepare_header(etype, self.long_header)
1100 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1099 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1101
1100
1102 if records is None:
1101 if records is None:
1103 return ""
1102 return ""
1104
1103
1105 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1104 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1106
1105
1107 frames = self.format_records(records, last_unique, recursion_repeat)
1106 frames = self.format_records(records, last_unique, recursion_repeat)
1108
1107
1109 formatted_exception = self.format_exception(etype, evalue)
1108 formatted_exception = self.format_exception(etype, evalue)
1110 if records:
1109 if records:
1111 filepath, lnum = records[-1][1:3]
1110 filepath, lnum = records[-1][1:3]
1112 filepath = os.path.abspath(filepath)
1111 filepath = os.path.abspath(filepath)
1113 ipinst = get_ipython()
1112 ipinst = get_ipython()
1114 if ipinst is not None:
1113 if ipinst is not None:
1115 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1114 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1116
1115
1117 return [[head] + frames + [''.join(formatted_exception[0])]]
1116 return [[head] + frames + [''.join(formatted_exception[0])]]
1118
1117
1119 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1118 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1120 try:
1119 try:
1121 # Try the default getinnerframes and Alex's: Alex's fixes some
1120 # Try the default getinnerframes and Alex's: Alex's fixes some
1122 # problems, but it generates empty tracebacks for console errors
1121 # problems, but it generates empty tracebacks for console errors
1123 # (5 blanks lines) where none should be returned.
1122 # (5 blanks lines) where none should be returned.
1124 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1123 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1125 except:
1124 except:
1126 # FIXME: I've been getting many crash reports from python 2.3
1125 # FIXME: I've been getting many crash reports from python 2.3
1127 # users, traceable to inspect.py. If I can find a small test-case
1126 # users, traceable to inspect.py. If I can find a small test-case
1128 # to reproduce this, I should either write a better workaround or
1127 # to reproduce this, I should either write a better workaround or
1129 # file a bug report against inspect (if that's the real problem).
1128 # file a bug report against inspect (if that's the real problem).
1130 # So far, I haven't been able to find an isolated example to
1129 # So far, I haven't been able to find an isolated example to
1131 # reproduce the problem.
1130 # reproduce the problem.
1132 inspect_error()
1131 inspect_error()
1133 traceback.print_exc(file=self.ostream)
1132 traceback.print_exc(file=self.ostream)
1134 info('\nUnfortunately, your original traceback can not be constructed.\n')
1133 info('\nUnfortunately, your original traceback can not be constructed.\n')
1135 return None
1134 return None
1136
1135
1137 def get_parts_of_chained_exception(self, evalue):
1136 def get_parts_of_chained_exception(self, evalue):
1138 def get_chained_exception(exception_value):
1137 def get_chained_exception(exception_value):
1139 cause = getattr(exception_value, '__cause__', None)
1138 cause = getattr(exception_value, '__cause__', None)
1140 if cause:
1139 if cause:
1141 return cause
1140 return cause
1142 if getattr(exception_value, '__suppress_context__', False):
1141 if getattr(exception_value, '__suppress_context__', False):
1143 return None
1142 return None
1144 return getattr(exception_value, '__context__', None)
1143 return getattr(exception_value, '__context__', None)
1145
1144
1146 chained_evalue = get_chained_exception(evalue)
1145 chained_evalue = get_chained_exception(evalue)
1147
1146
1148 if chained_evalue:
1147 if chained_evalue:
1149 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1148 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1150
1149
1151 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1150 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1152 number_of_lines_of_context=5):
1151 number_of_lines_of_context=5):
1153 """Return a nice text document describing the traceback."""
1152 """Return a nice text document describing the traceback."""
1154
1153
1155 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1154 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1156 tb_offset)
1155 tb_offset)
1157
1156
1158 colors = self.Colors # just a shorthand + quicker name lookup
1157 colors = self.Colors # just a shorthand + quicker name lookup
1159 colorsnormal = colors.Normal # used a lot
1158 colorsnormal = colors.Normal # used a lot
1160 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1159 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1161 structured_traceback_parts = [head]
1160 structured_traceback_parts = [head]
1162 if py3compat.PY3:
1161 if py3compat.PY3:
1163 chained_exceptions_tb_offset = 0
1162 chained_exceptions_tb_offset = 0
1164 lines_of_context = 3
1163 lines_of_context = 3
1165 formatted_exceptions = formatted_exception
1164 formatted_exceptions = formatted_exception
1166 exception = self.get_parts_of_chained_exception(evalue)
1165 exception = self.get_parts_of_chained_exception(evalue)
1167 if exception:
1166 if exception:
1168 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1167 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1169 etype, evalue, etb = exception
1168 etype, evalue, etb = exception
1170 else:
1169 else:
1171 evalue = None
1170 evalue = None
1172 chained_exc_ids = set()
1171 chained_exc_ids = set()
1173 while evalue:
1172 while evalue:
1174 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1173 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1175 chained_exceptions_tb_offset)
1174 chained_exceptions_tb_offset)
1176 exception = self.get_parts_of_chained_exception(evalue)
1175 exception = self.get_parts_of_chained_exception(evalue)
1177
1176
1178 if exception and not id(exception[1]) in chained_exc_ids:
1177 if exception and not id(exception[1]) in chained_exc_ids:
1179 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1178 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1180 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1179 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1181 etype, evalue, etb = exception
1180 etype, evalue, etb = exception
1182 else:
1181 else:
1183 evalue = None
1182 evalue = None
1184
1183
1185 # we want to see exceptions in a reversed order:
1184 # we want to see exceptions in a reversed order:
1186 # the first exception should be on top
1185 # the first exception should be on top
1187 for formatted_exception in reversed(formatted_exceptions):
1186 for formatted_exception in reversed(formatted_exceptions):
1188 structured_traceback_parts += formatted_exception
1187 structured_traceback_parts += formatted_exception
1189 else:
1188 else:
1190 structured_traceback_parts += formatted_exception[0]
1189 structured_traceback_parts += formatted_exception[0]
1191
1190
1192 return structured_traceback_parts
1191 return structured_traceback_parts
1193
1192
1194 def debugger(self, force=False):
1193 def debugger(self, force=False):
1195 """Call up the pdb debugger if desired, always clean up the tb
1194 """Call up the pdb debugger if desired, always clean up the tb
1196 reference.
1195 reference.
1197
1196
1198 Keywords:
1197 Keywords:
1199
1198
1200 - force(False): by default, this routine checks the instance call_pdb
1199 - force(False): by default, this routine checks the instance call_pdb
1201 flag and does not actually invoke the debugger if the flag is false.
1200 flag and does not actually invoke the debugger if the flag is false.
1202 The 'force' option forces the debugger to activate even if the flag
1201 The 'force' option forces the debugger to activate even if the flag
1203 is false.
1202 is false.
1204
1203
1205 If the call_pdb flag is set, the pdb interactive debugger is
1204 If the call_pdb flag is set, the pdb interactive debugger is
1206 invoked. In all cases, the self.tb reference to the current traceback
1205 invoked. In all cases, the self.tb reference to the current traceback
1207 is deleted to prevent lingering references which hamper memory
1206 is deleted to prevent lingering references which hamper memory
1208 management.
1207 management.
1209
1208
1210 Note that each call to pdb() does an 'import readline', so if your app
1209 Note that each call to pdb() does an 'import readline', so if your app
1211 requires a special setup for the readline completers, you'll have to
1210 requires a special setup for the readline completers, you'll have to
1212 fix that by hand after invoking the exception handler."""
1211 fix that by hand after invoking the exception handler."""
1213
1212
1214 if force or self.call_pdb:
1213 if force or self.call_pdb:
1215 if self.pdb is None:
1214 if self.pdb is None:
1216 self.pdb = debugger.Pdb(
1215 self.pdb = debugger.Pdb(
1217 self.color_scheme_table.active_scheme_name)
1216 self.color_scheme_table.active_scheme_name)
1218 # the system displayhook may have changed, restore the original
1217 # the system displayhook may have changed, restore the original
1219 # for pdb
1218 # for pdb
1220 display_trap = DisplayTrap(hook=sys.__displayhook__)
1219 display_trap = DisplayTrap(hook=sys.__displayhook__)
1221 with display_trap:
1220 with display_trap:
1222 self.pdb.reset()
1221 self.pdb.reset()
1223 # Find the right frame so we don't pop up inside ipython itself
1222 # Find the right frame so we don't pop up inside ipython itself
1224 if hasattr(self, 'tb') and self.tb is not None:
1223 if hasattr(self, 'tb') and self.tb is not None:
1225 etb = self.tb
1224 etb = self.tb
1226 else:
1225 else:
1227 etb = self.tb = sys.last_traceback
1226 etb = self.tb = sys.last_traceback
1228 while self.tb is not None and self.tb.tb_next is not None:
1227 while self.tb is not None and self.tb.tb_next is not None:
1229 self.tb = self.tb.tb_next
1228 self.tb = self.tb.tb_next
1230 if etb and etb.tb_next:
1229 if etb and etb.tb_next:
1231 etb = etb.tb_next
1230 etb = etb.tb_next
1232 self.pdb.botframe = etb.tb_frame
1231 self.pdb.botframe = etb.tb_frame
1233 self.pdb.interaction(self.tb.tb_frame, self.tb)
1232 self.pdb.interaction(self.tb.tb_frame, self.tb)
1234
1233
1235 if hasattr(self, 'tb'):
1234 if hasattr(self, 'tb'):
1236 del self.tb
1235 del self.tb
1237
1236
1238 def handler(self, info=None):
1237 def handler(self, info=None):
1239 (etype, evalue, etb) = info or sys.exc_info()
1238 (etype, evalue, etb) = info or sys.exc_info()
1240 self.tb = etb
1239 self.tb = etb
1241 ostream = self.ostream
1240 ostream = self.ostream
1242 ostream.flush()
1241 ostream.flush()
1243 ostream.write(self.text(etype, evalue, etb))
1242 ostream.write(self.text(etype, evalue, etb))
1244 ostream.write('\n')
1243 ostream.write('\n')
1245 ostream.flush()
1244 ostream.flush()
1246
1245
1247 # Changed so an instance can just be called as VerboseTB_inst() and print
1246 # Changed so an instance can just be called as VerboseTB_inst() and print
1248 # out the right info on its own.
1247 # out the right info on its own.
1249 def __call__(self, etype=None, evalue=None, etb=None):
1248 def __call__(self, etype=None, evalue=None, etb=None):
1250 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1249 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1251 if etb is None:
1250 if etb is None:
1252 self.handler()
1251 self.handler()
1253 else:
1252 else:
1254 self.handler((etype, evalue, etb))
1253 self.handler((etype, evalue, etb))
1255 try:
1254 try:
1256 self.debugger()
1255 self.debugger()
1257 except KeyboardInterrupt:
1256 except KeyboardInterrupt:
1258 print("\nKeyboardInterrupt")
1257 print("\nKeyboardInterrupt")
1259
1258
1260
1259
1261 #----------------------------------------------------------------------------
1260 #----------------------------------------------------------------------------
1262 class FormattedTB(VerboseTB, ListTB):
1261 class FormattedTB(VerboseTB, ListTB):
1263 """Subclass ListTB but allow calling with a traceback.
1262 """Subclass ListTB but allow calling with a traceback.
1264
1263
1265 It can thus be used as a sys.excepthook for Python > 2.1.
1264 It can thus be used as a sys.excepthook for Python > 2.1.
1266
1265
1267 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1266 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1268
1267
1269 Allows a tb_offset to be specified. This is useful for situations where
1268 Allows a tb_offset to be specified. This is useful for situations where
1270 one needs to remove a number of topmost frames from the traceback (such as
1269 one needs to remove a number of topmost frames from the traceback (such as
1271 occurs with python programs that themselves execute other python code,
1270 occurs with python programs that themselves execute other python code,
1272 like Python shells). """
1271 like Python shells). """
1273
1272
1274 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1273 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1275 ostream=None,
1274 ostream=None,
1276 tb_offset=0, long_header=False, include_vars=False,
1275 tb_offset=0, long_header=False, include_vars=False,
1277 check_cache=None):
1276 check_cache=None):
1278
1277
1279 # NEVER change the order of this list. Put new modes at the end:
1278 # NEVER change the order of this list. Put new modes at the end:
1280 self.valid_modes = ['Plain', 'Context', 'Verbose']
1279 self.valid_modes = ['Plain', 'Context', 'Verbose']
1281 self.verbose_modes = self.valid_modes[1:3]
1280 self.verbose_modes = self.valid_modes[1:3]
1282
1281
1283 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1282 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1284 ostream=ostream, tb_offset=tb_offset,
1283 ostream=ostream, tb_offset=tb_offset,
1285 long_header=long_header, include_vars=include_vars,
1284 long_header=long_header, include_vars=include_vars,
1286 check_cache=check_cache)
1285 check_cache=check_cache)
1287
1286
1288 # Different types of tracebacks are joined with different separators to
1287 # Different types of tracebacks are joined with different separators to
1289 # form a single string. They are taken from this dict
1288 # form a single string. They are taken from this dict
1290 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1289 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1291 # set_mode also sets the tb_join_char attribute
1290 # set_mode also sets the tb_join_char attribute
1292 self.set_mode(mode)
1291 self.set_mode(mode)
1293
1292
1294 def _extract_tb(self, tb):
1293 def _extract_tb(self, tb):
1295 if tb:
1294 if tb:
1296 return traceback.extract_tb(tb)
1295 return traceback.extract_tb(tb)
1297 else:
1296 else:
1298 return None
1297 return None
1299
1298
1300 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1299 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1301 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1300 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1302 mode = self.mode
1301 mode = self.mode
1303 if mode in self.verbose_modes:
1302 if mode in self.verbose_modes:
1304 # Verbose modes need a full traceback
1303 # Verbose modes need a full traceback
1305 return VerboseTB.structured_traceback(
1304 return VerboseTB.structured_traceback(
1306 self, etype, value, tb, tb_offset, number_of_lines_of_context
1305 self, etype, value, tb, tb_offset, number_of_lines_of_context
1307 )
1306 )
1308 else:
1307 else:
1309 # We must check the source cache because otherwise we can print
1308 # We must check the source cache because otherwise we can print
1310 # out-of-date source code.
1309 # out-of-date source code.
1311 self.check_cache()
1310 self.check_cache()
1312 # Now we can extract and format the exception
1311 # Now we can extract and format the exception
1313 elist = self._extract_tb(tb)
1312 elist = self._extract_tb(tb)
1314 return ListTB.structured_traceback(
1313 return ListTB.structured_traceback(
1315 self, etype, value, elist, tb_offset, number_of_lines_of_context
1314 self, etype, value, elist, tb_offset, number_of_lines_of_context
1316 )
1315 )
1317
1316
1318 def stb2text(self, stb):
1317 def stb2text(self, stb):
1319 """Convert a structured traceback (a list) to a string."""
1318 """Convert a structured traceback (a list) to a string."""
1320 return self.tb_join_char.join(stb)
1319 return self.tb_join_char.join(stb)
1321
1320
1322
1321
1323 def set_mode(self, mode=None):
1322 def set_mode(self, mode=None):
1324 """Switch to the desired mode.
1323 """Switch to the desired mode.
1325
1324
1326 If mode is not specified, cycles through the available modes."""
1325 If mode is not specified, cycles through the available modes."""
1327
1326
1328 if not mode:
1327 if not mode:
1329 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1328 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1330 len(self.valid_modes)
1329 len(self.valid_modes)
1331 self.mode = self.valid_modes[new_idx]
1330 self.mode = self.valid_modes[new_idx]
1332 elif mode not in self.valid_modes:
1331 elif mode not in self.valid_modes:
1333 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1332 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1334 'Valid modes: ' + str(self.valid_modes))
1333 'Valid modes: ' + str(self.valid_modes))
1335 else:
1334 else:
1336 self.mode = mode
1335 self.mode = mode
1337 # include variable details only in 'Verbose' mode
1336 # include variable details only in 'Verbose' mode
1338 self.include_vars = (self.mode == self.valid_modes[2])
1337 self.include_vars = (self.mode == self.valid_modes[2])
1339 # Set the join character for generating text tracebacks
1338 # Set the join character for generating text tracebacks
1340 self.tb_join_char = self._join_chars[self.mode]
1339 self.tb_join_char = self._join_chars[self.mode]
1341
1340
1342 # some convenient shortcuts
1341 # some convenient shortcuts
1343 def plain(self):
1342 def plain(self):
1344 self.set_mode(self.valid_modes[0])
1343 self.set_mode(self.valid_modes[0])
1345
1344
1346 def context(self):
1345 def context(self):
1347 self.set_mode(self.valid_modes[1])
1346 self.set_mode(self.valid_modes[1])
1348
1347
1349 def verbose(self):
1348 def verbose(self):
1350 self.set_mode(self.valid_modes[2])
1349 self.set_mode(self.valid_modes[2])
1351
1350
1352
1351
1353 #----------------------------------------------------------------------------
1352 #----------------------------------------------------------------------------
1354 class AutoFormattedTB(FormattedTB):
1353 class AutoFormattedTB(FormattedTB):
1355 """A traceback printer which can be called on the fly.
1354 """A traceback printer which can be called on the fly.
1356
1355
1357 It will find out about exceptions by itself.
1356 It will find out about exceptions by itself.
1358
1357
1359 A brief example::
1358 A brief example::
1360
1359
1361 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1360 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1362 try:
1361 try:
1363 ...
1362 ...
1364 except:
1363 except:
1365 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1364 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1366 """
1365 """
1367
1366
1368 def __call__(self, etype=None, evalue=None, etb=None,
1367 def __call__(self, etype=None, evalue=None, etb=None,
1369 out=None, tb_offset=None):
1368 out=None, tb_offset=None):
1370 """Print out a formatted exception traceback.
1369 """Print out a formatted exception traceback.
1371
1370
1372 Optional arguments:
1371 Optional arguments:
1373 - out: an open file-like object to direct output to.
1372 - out: an open file-like object to direct output to.
1374
1373
1375 - tb_offset: the number of frames to skip over in the stack, on a
1374 - tb_offset: the number of frames to skip over in the stack, on a
1376 per-call basis (this overrides temporarily the instance's tb_offset
1375 per-call basis (this overrides temporarily the instance's tb_offset
1377 given at initialization time. """
1376 given at initialization time. """
1378
1377
1379 if out is None:
1378 if out is None:
1380 out = self.ostream
1379 out = self.ostream
1381 out.flush()
1380 out.flush()
1382 out.write(self.text(etype, evalue, etb, tb_offset))
1381 out.write(self.text(etype, evalue, etb, tb_offset))
1383 out.write('\n')
1382 out.write('\n')
1384 out.flush()
1383 out.flush()
1385 # FIXME: we should remove the auto pdb behavior from here and leave
1384 # FIXME: we should remove the auto pdb behavior from here and leave
1386 # that to the clients.
1385 # that to the clients.
1387 try:
1386 try:
1388 self.debugger()
1387 self.debugger()
1389 except KeyboardInterrupt:
1388 except KeyboardInterrupt:
1390 print("\nKeyboardInterrupt")
1389 print("\nKeyboardInterrupt")
1391
1390
1392 def structured_traceback(self, etype=None, value=None, tb=None,
1391 def structured_traceback(self, etype=None, value=None, tb=None,
1393 tb_offset=None, number_of_lines_of_context=5):
1392 tb_offset=None, number_of_lines_of_context=5):
1394 if etype is None:
1393 if etype is None:
1395 etype, value, tb = sys.exc_info()
1394 etype, value, tb = sys.exc_info()
1396 self.tb = tb
1395 self.tb = tb
1397 return FormattedTB.structured_traceback(
1396 return FormattedTB.structured_traceback(
1398 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1397 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1399
1398
1400
1399
1401 #---------------------------------------------------------------------------
1400 #---------------------------------------------------------------------------
1402
1401
1403 # A simple class to preserve Nathan's original functionality.
1402 # A simple class to preserve Nathan's original functionality.
1404 class ColorTB(FormattedTB):
1403 class ColorTB(FormattedTB):
1405 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1404 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1406
1405
1407 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1406 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1408 FormattedTB.__init__(self, color_scheme=color_scheme,
1407 FormattedTB.__init__(self, color_scheme=color_scheme,
1409 call_pdb=call_pdb, **kwargs)
1408 call_pdb=call_pdb, **kwargs)
1410
1409
1411
1410
1412 class SyntaxTB(ListTB):
1411 class SyntaxTB(ListTB):
1413 """Extension which holds some state: the last exception value"""
1412 """Extension which holds some state: the last exception value"""
1414
1413
1415 def __init__(self, color_scheme='NoColor'):
1414 def __init__(self, color_scheme='NoColor'):
1416 ListTB.__init__(self, color_scheme)
1415 ListTB.__init__(self, color_scheme)
1417 self.last_syntax_error = None
1416 self.last_syntax_error = None
1418
1417
1419 def __call__(self, etype, value, elist):
1418 def __call__(self, etype, value, elist):
1420 self.last_syntax_error = value
1419 self.last_syntax_error = value
1421
1420
1422 ListTB.__call__(self, etype, value, elist)
1421 ListTB.__call__(self, etype, value, elist)
1423
1422
1424 def structured_traceback(self, etype, value, elist, tb_offset=None,
1423 def structured_traceback(self, etype, value, elist, tb_offset=None,
1425 context=5):
1424 context=5):
1426 # If the source file has been edited, the line in the syntax error can
1425 # If the source file has been edited, the line in the syntax error can
1427 # be wrong (retrieved from an outdated cache). This replaces it with
1426 # be wrong (retrieved from an outdated cache). This replaces it with
1428 # the current value.
1427 # the current value.
1429 if isinstance(value, SyntaxError) \
1428 if isinstance(value, SyntaxError) \
1430 and isinstance(value.filename, py3compat.string_types) \
1429 and isinstance(value.filename, py3compat.string_types) \
1431 and isinstance(value.lineno, int):
1430 and isinstance(value.lineno, int):
1432 linecache.checkcache(value.filename)
1431 linecache.checkcache(value.filename)
1433 newtext = ulinecache.getline(value.filename, value.lineno)
1432 newtext = ulinecache.getline(value.filename, value.lineno)
1434 if newtext:
1433 if newtext:
1435 value.text = newtext
1434 value.text = newtext
1436 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1435 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1437 tb_offset=tb_offset, context=context)
1436 tb_offset=tb_offset, context=context)
1438
1437
1439 def clear_err_state(self):
1438 def clear_err_state(self):
1440 """Return the current error state and clear it"""
1439 """Return the current error state and clear it"""
1441 e = self.last_syntax_error
1440 e = self.last_syntax_error
1442 self.last_syntax_error = None
1441 self.last_syntax_error = None
1443 return e
1442 return e
1444
1443
1445 def stb2text(self, stb):
1444 def stb2text(self, stb):
1446 """Convert a structured traceback (a list) to a string."""
1445 """Convert a structured traceback (a list) to a string."""
1447 return ''.join(stb)
1446 return ''.join(stb)
1448
1447
1449
1448
1450 # some internal-use functions
1449 # some internal-use functions
1451 def text_repr(value):
1450 def text_repr(value):
1452 """Hopefully pretty robust repr equivalent."""
1451 """Hopefully pretty robust repr equivalent."""
1453 # this is pretty horrible but should always return *something*
1452 # this is pretty horrible but should always return *something*
1454 try:
1453 try:
1455 return pydoc.text.repr(value)
1454 return pydoc.text.repr(value)
1456 except KeyboardInterrupt:
1455 except KeyboardInterrupt:
1457 raise
1456 raise
1458 except:
1457 except:
1459 try:
1458 try:
1460 return repr(value)
1459 return repr(value)
1461 except KeyboardInterrupt:
1460 except KeyboardInterrupt:
1462 raise
1461 raise
1463 except:
1462 except:
1464 try:
1463 try:
1465 # all still in an except block so we catch
1464 # all still in an except block so we catch
1466 # getattr raising
1465 # getattr raising
1467 name = getattr(value, '__name__', None)
1466 name = getattr(value, '__name__', None)
1468 if name:
1467 if name:
1469 # ick, recursion
1468 # ick, recursion
1470 return text_repr(name)
1469 return text_repr(name)
1471 klass = getattr(value, '__class__', None)
1470 klass = getattr(value, '__class__', None)
1472 if klass:
1471 if klass:
1473 return '%s instance' % text_repr(klass)
1472 return '%s instance' % text_repr(klass)
1474 except KeyboardInterrupt:
1473 except KeyboardInterrupt:
1475 raise
1474 raise
1476 except:
1475 except:
1477 return 'UNRECOVERABLE REPR FAILURE'
1476 return 'UNRECOVERABLE REPR FAILURE'
1478
1477
1479
1478
1480 def eqrepr(value, repr=text_repr):
1479 def eqrepr(value, repr=text_repr):
1481 return '=%s' % repr(value)
1480 return '=%s' % repr(value)
1482
1481
1483
1482
1484 def nullrepr(value, repr=text_repr):
1483 def nullrepr(value, repr=text_repr):
1485 return ''
1484 return ''
@@ -1,583 +1,583 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ----------------
10 ----------------
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33 Inheritance diagram:
33 Inheritance diagram:
34
34
35 .. inheritance-diagram:: IPython.lib.demo
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36 :parts: 3
37
37
38 Subclassing
38 Subclassing
39 -----------
39 -----------
40
40
41 The classes here all include a few methods meant to make customization by
41 The classes here all include a few methods meant to make customization by
42 subclassing more convenient. Their docstrings below have some more details:
42 subclassing more convenient. Their docstrings below have some more details:
43
43
44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 - marquee(): generates a marquee to provide visible on-screen markers at each
45 block start and end.
45 block start and end.
46
46
47 - pre_cmd(): run right before the execution of each block.
47 - pre_cmd(): run right before the execution of each block.
48
48
49 - post_cmd(): run right after the execution of each block. If the block
49 - post_cmd(): run right after the execution of each block. If the block
50 raises an exception, this is NOT called.
50 raises an exception, this is NOT called.
51
51
52
52
53 Operation
53 Operation
54 ---------
54 ---------
55
55
56 The file is run in its own empty namespace (though you can pass it a string of
56 The file is run in its own empty namespace (though you can pass it a string of
57 arguments as if in a command line environment, and it will see those as
57 arguments as if in a command line environment, and it will see those as
58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 sys.argv). But at each stop, the global IPython namespace is updated with the
59 current internal demo namespace, so you can work interactively with the data
59 current internal demo namespace, so you can work interactively with the data
60 accumulated so far.
60 accumulated so far.
61
61
62 By default, each block of code is printed (with syntax highlighting) before
62 By default, each block of code is printed (with syntax highlighting) before
63 executing it and you have to confirm execution. This is intended to show the
63 executing it and you have to confirm execution. This is intended to show the
64 code to an audience first so you can discuss it, and only proceed with
64 code to an audience first so you can discuss it, and only proceed with
65 execution once you agree. There are a few tags which allow you to modify this
65 execution once you agree. There are a few tags which allow you to modify this
66 behavior.
66 behavior.
67
67
68 The supported tags are:
68 The supported tags are:
69
69
70 # <demo> stop
70 # <demo> stop
71
71
72 Defines block boundaries, the points where IPython stops execution of the
72 Defines block boundaries, the points where IPython stops execution of the
73 file and returns to the interactive prompt.
73 file and returns to the interactive prompt.
74
74
75 You can optionally mark the stop tag with extra dashes before and after the
75 You can optionally mark the stop tag with extra dashes before and after the
76 word 'stop', to help visually distinguish the blocks in a text editor:
76 word 'stop', to help visually distinguish the blocks in a text editor:
77
77
78 # <demo> --- stop ---
78 # <demo> --- stop ---
79
79
80
80
81 # <demo> silent
81 # <demo> silent
82
82
83 Make a block execute silently (and hence automatically). Typically used in
83 Make a block execute silently (and hence automatically). Typically used in
84 cases where you have some boilerplate or initialization code which you need
84 cases where you have some boilerplate or initialization code which you need
85 executed but do not want to be seen in the demo.
85 executed but do not want to be seen in the demo.
86
86
87 # <demo> auto
87 # <demo> auto
88
88
89 Make a block execute automatically, but still being printed. Useful for
89 Make a block execute automatically, but still being printed. Useful for
90 simple code which does not warrant discussion, since it avoids the extra
90 simple code which does not warrant discussion, since it avoids the extra
91 manual confirmation.
91 manual confirmation.
92
92
93 # <demo> auto_all
93 # <demo> auto_all
94
94
95 This tag can _only_ be in the first block, and if given it overrides the
95 This tag can _only_ be in the first block, and if given it overrides the
96 individual auto tags to make the whole demo fully automatic (no block asks
96 individual auto tags to make the whole demo fully automatic (no block asks
97 for confirmation). It can also be given at creation time (or the attribute
97 for confirmation). It can also be given at creation time (or the attribute
98 set later) to override what's in the file.
98 set later) to override what's in the file.
99
99
100 While _any_ python file can be run as a Demo instance, if there are no stop
100 While _any_ python file can be run as a Demo instance, if there are no stop
101 tags the whole file will run in a single block (no different that calling
101 tags the whole file will run in a single block (no different that calling
102 first %pycat and then %run). The minimal markup to make this useful is to
102 first %pycat and then %run). The minimal markup to make this useful is to
103 place a set of stop tags; the other tags are only there to let you fine-tune
103 place a set of stop tags; the other tags are only there to let you fine-tune
104 the execution.
104 the execution.
105
105
106 This is probably best explained with the simple example file below. You can
106 This is probably best explained with the simple example file below. You can
107 copy this into a file named ex_demo.py, and try running it via::
107 copy this into a file named ex_demo.py, and try running it via::
108
108
109 from IPython.demo import Demo
109 from IPython.demo import Demo
110 d = Demo('ex_demo.py')
110 d = Demo('ex_demo.py')
111 d()
111 d()
112
112
113 Each time you call the demo object, it runs the next block. The demo object
113 Each time you call the demo object, it runs the next block. The demo object
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 and back(). It can be reset for a new run via reset() or reloaded from disk
116 (in case you've edited the source) via reload(). See their docstrings below.
116 (in case you've edited the source) via reload(). See their docstrings below.
117
117
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 been added to the "docs/examples/core" directory. Just cd to this directory in
120 an IPython session, and type::
120 an IPython session, and type::
121
121
122 %run demo-exercizer.py
122 %run demo-exercizer.py
123
123
124 and then follow the directions.
124 and then follow the directions.
125
125
126 Example
126 Example
127 -------
127 -------
128
128
129 The following is a very simple example of a valid demo file.
129 The following is a very simple example of a valid demo file.
130
130
131 ::
131 ::
132
132
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
135
135
136 print 'Hello, welcome to an interactive IPython demo.'
136 print 'Hello, welcome to an interactive IPython demo.'
137
137
138 # The mark below defines a block boundary, which is a point where IPython will
138 # The mark below defines a block boundary, which is a point where IPython will
139 # stop execution and return to the interactive prompt. The dashes are actually
139 # stop execution and return to the interactive prompt. The dashes are actually
140 # optional and used only as a visual aid to clearly separate blocks while
140 # optional and used only as a visual aid to clearly separate blocks while
141 # editing the demo code.
141 # editing the demo code.
142 # <demo> stop
142 # <demo> stop
143
143
144 x = 1
144 x = 1
145 y = 2
145 y = 2
146
146
147 # <demo> stop
147 # <demo> stop
148
148
149 # the mark below makes this block as silent
149 # the mark below makes this block as silent
150 # <demo> silent
150 # <demo> silent
151
151
152 print 'This is a silent block, which gets executed but not printed.'
152 print 'This is a silent block, which gets executed but not printed.'
153
153
154 # <demo> stop
154 # <demo> stop
155 # <demo> auto
155 # <demo> auto
156 print 'This is an automatic block.'
156 print 'This is an automatic block.'
157 print 'It is executed without asking for confirmation, but printed.'
157 print 'It is executed without asking for confirmation, but printed.'
158 z = x+y
158 z = x+y
159
159
160 print 'z=',x
160 print 'z=',x
161
161
162 # <demo> stop
162 # <demo> stop
163 # This is just another normal block.
163 # This is just another normal block.
164 print 'z is now:', z
164 print 'z is now:', z
165
165
166 print 'bye!'
166 print 'bye!'
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
168 """
168 """
169
169
170 from __future__ import unicode_literals
170 from __future__ import unicode_literals
171
171
172 #*****************************************************************************
172 #*****************************************************************************
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
174 #
174 #
175 # Distributed under the terms of the BSD License. The full license is in
175 # Distributed under the terms of the BSD License. The full license is in
176 # the file COPYING, distributed as part of this software.
176 # the file COPYING, distributed as part of this software.
177 #
177 #
178 #*****************************************************************************
178 #*****************************************************************************
179 from __future__ import print_function
179 from __future__ import print_function
180
180
181 import os
181 import os
182 import re
182 import re
183 import shlex
183 import shlex
184 import sys
184 import sys
185
185
186 from IPython.utils import io
186 from IPython.utils import io
187 from IPython.utils.text import marquee
187 from IPython.utils.text import marquee
188 from IPython.utils import openpy
188 from IPython.utils import openpy
189 from IPython.utils import py3compat
189 from IPython.utils import py3compat
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191
191
192 class DemoError(Exception): pass
192 class DemoError(Exception): pass
193
193
194 def re_mark(mark):
194 def re_mark(mark):
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196
196
197 class Demo(object):
197 class Demo(object):
198
198
199 re_stop = re_mark('-*\s?stop\s?-*')
199 re_stop = re_mark('-*\s?stop\s?-*')
200 re_silent = re_mark('silent')
200 re_silent = re_mark('silent')
201 re_auto = re_mark('auto')
201 re_auto = re_mark('auto')
202 re_auto_all = re_mark('auto_all')
202 re_auto_all = re_mark('auto_all')
203
203
204 def __init__(self,src,title='',arg_str='',auto_all=None):
204 def __init__(self,src,title='',arg_str='',auto_all=None):
205 """Make a new demo object. To run the demo, simply call the object.
205 """Make a new demo object. To run the demo, simply call the object.
206
206
207 See the module docstring for full details and an example (you can use
207 See the module docstring for full details and an example (you can use
208 IPython.Demo? in IPython to see it).
208 IPython.Demo? in IPython to see it).
209
209
210 Inputs:
210 Inputs:
211
211
212 - src is either a file, or file-like object, or a
212 - src is either a file, or file-like object, or a
213 string that can be resolved to a filename.
213 string that can be resolved to a filename.
214
214
215 Optional inputs:
215 Optional inputs:
216
216
217 - title: a string to use as the demo name. Of most use when the demo
217 - title: a string to use as the demo name. Of most use when the demo
218 you are making comes from an object that has no filename, or if you
218 you are making comes from an object that has no filename, or if you
219 want an alternate denotation distinct from the filename.
219 want an alternate denotation distinct from the filename.
220
220
221 - arg_str(''): a string of arguments, internally converted to a list
221 - arg_str(''): a string of arguments, internally converted to a list
222 just like sys.argv, so the demo script can see a similar
222 just like sys.argv, so the demo script can see a similar
223 environment.
223 environment.
224
224
225 - auto_all(None): global flag to run all blocks automatically without
225 - auto_all(None): global flag to run all blocks automatically without
226 confirmation. This attribute overrides the block-level tags and
226 confirmation. This attribute overrides the block-level tags and
227 applies to the whole demo. It is an attribute of the object, and
227 applies to the whole demo. It is an attribute of the object, and
228 can be changed at runtime simply by reassigning it to a boolean
228 can be changed at runtime simply by reassigning it to a boolean
229 value.
229 value.
230 """
230 """
231 if hasattr(src, "read"):
231 if hasattr(src, "read"):
232 # It seems to be a file or a file-like object
232 # It seems to be a file or a file-like object
233 self.fname = "from a file-like object"
233 self.fname = "from a file-like object"
234 if title == '':
234 if title == '':
235 self.title = "from a file-like object"
235 self.title = "from a file-like object"
236 else:
236 else:
237 self.title = title
237 self.title = title
238 else:
238 else:
239 # Assume it's a string or something that can be converted to one
239 # Assume it's a string or something that can be converted to one
240 self.fname = src
240 self.fname = src
241 if title == '':
241 if title == '':
242 (filepath, filename) = os.path.split(src)
242 (filepath, filename) = os.path.split(src)
243 self.title = filename
243 self.title = filename
244 else:
244 else:
245 self.title = title
245 self.title = title
246 self.sys_argv = [src] + shlex.split(arg_str)
246 self.sys_argv = [src] + shlex.split(arg_str)
247 self.auto_all = auto_all
247 self.auto_all = auto_all
248 self.src = src
248 self.src = src
249
249
250 # get a few things from ipython. While it's a bit ugly design-wise,
250 # get a few things from ipython. While it's a bit ugly design-wise,
251 # it ensures that things like color scheme and the like are always in
251 # it ensures that things like color scheme and the like are always in
252 # sync with the ipython mode being used. This class is only meant to
252 # sync with the ipython mode being used. This class is only meant to
253 # be used inside ipython anyways, so it's OK.
253 # be used inside ipython anyways, so it's OK.
254 ip = get_ipython() # this is in builtins whenever IPython is running
254 ip = get_ipython() # this is in builtins whenever IPython is running
255 self.ip_ns = ip.user_ns
255 self.ip_ns = ip.user_ns
256 self.ip_colorize = ip.pycolorize
256 self.ip_colorize = ip.pycolorize
257 self.ip_showtb = ip.showtraceback
257 self.ip_showtb = ip.showtraceback
258 self.ip_run_cell = ip.run_cell
258 self.ip_run_cell = ip.run_cell
259 self.shell = ip
259 self.shell = ip
260
260
261 # load user data and initialize data structures
261 # load user data and initialize data structures
262 self.reload()
262 self.reload()
263
263
264 def fload(self):
264 def fload(self):
265 """Load file object."""
265 """Load file object."""
266 # read data and parse into blocks
266 # read data and parse into blocks
267 if hasattr(self, 'fobj') and self.fobj is not None:
267 if hasattr(self, 'fobj') and self.fobj is not None:
268 self.fobj.close()
268 self.fobj.close()
269 if hasattr(self.src, "read"):
269 if hasattr(self.src, "read"):
270 # It seems to be a file or a file-like object
270 # It seems to be a file or a file-like object
271 self.fobj = self.src
271 self.fobj = self.src
272 else:
272 else:
273 # Assume it's a string or something that can be converted to one
273 # Assume it's a string or something that can be converted to one
274 self.fobj = openpy.open(self.fname)
274 self.fobj = openpy.open(self.fname)
275
275
276 def reload(self):
276 def reload(self):
277 """Reload source from disk and initialize state."""
277 """Reload source from disk and initialize state."""
278 self.fload()
278 self.fload()
279
279
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284
284
285 # if auto_all is not given (def. None), we read it from the file
285 # if auto_all is not given (def. None), we read it from the file
286 if self.auto_all is None:
286 if self.auto_all is None:
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 else:
288 else:
289 self.auto_all = bool(self.auto_all)
289 self.auto_all = bool(self.auto_all)
290
290
291 # Clean the sources from all markup so it doesn't get displayed when
291 # Clean the sources from all markup so it doesn't get displayed when
292 # running the demo
292 # running the demo
293 src_blocks = []
293 src_blocks = []
294 auto_strip = lambda s: self.re_auto.sub('',s)
294 auto_strip = lambda s: self.re_auto.sub('',s)
295 for i,b in enumerate(src_b):
295 for i,b in enumerate(src_b):
296 if self._auto[i]:
296 if self._auto[i]:
297 src_blocks.append(auto_strip(b))
297 src_blocks.append(auto_strip(b))
298 else:
298 else:
299 src_blocks.append(b)
299 src_blocks.append(b)
300 # remove the auto_all marker
300 # remove the auto_all marker
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302
302
303 self.nblocks = len(src_blocks)
303 self.nblocks = len(src_blocks)
304 self.src_blocks = src_blocks
304 self.src_blocks = src_blocks
305
305
306 # also build syntax-highlighted source
306 # also build syntax-highlighted source
307 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
307 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
308
308
309 # ensure clean namespace and seek offset
309 # ensure clean namespace and seek offset
310 self.reset()
310 self.reset()
311
311
312 def reset(self):
312 def reset(self):
313 """Reset the namespace and seek pointer to restart the demo"""
313 """Reset the namespace and seek pointer to restart the demo"""
314 self.user_ns = {}
314 self.user_ns = {}
315 self.finished = False
315 self.finished = False
316 self.block_index = 0
316 self.block_index = 0
317
317
318 def _validate_index(self,index):
318 def _validate_index(self,index):
319 if index<0 or index>=self.nblocks:
319 if index<0 or index>=self.nblocks:
320 raise ValueError('invalid block index %s' % index)
320 raise ValueError('invalid block index %s' % index)
321
321
322 def _get_index(self,index):
322 def _get_index(self,index):
323 """Get the current block index, validating and checking status.
323 """Get the current block index, validating and checking status.
324
324
325 Returns None if the demo is finished"""
325 Returns None if the demo is finished"""
326
326
327 if index is None:
327 if index is None:
328 if self.finished:
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 return None
330 return None
331 index = self.block_index
331 index = self.block_index
332 else:
332 else:
333 self._validate_index(index)
333 self._validate_index(index)
334 return index
334 return index
335
335
336 def seek(self,index):
336 def seek(self,index):
337 """Move the current seek pointer to the given block.
337 """Move the current seek pointer to the given block.
338
338
339 You can use negative indices to seek from the end, with identical
339 You can use negative indices to seek from the end, with identical
340 semantics to those of Python lists."""
340 semantics to those of Python lists."""
341 if index<0:
341 if index<0:
342 index = self.nblocks + index
342 index = self.nblocks + index
343 self._validate_index(index)
343 self._validate_index(index)
344 self.block_index = index
344 self.block_index = index
345 self.finished = False
345 self.finished = False
346
346
347 def back(self,num=1):
347 def back(self,num=1):
348 """Move the seek pointer back num blocks (default is 1)."""
348 """Move the seek pointer back num blocks (default is 1)."""
349 self.seek(self.block_index-num)
349 self.seek(self.block_index-num)
350
350
351 def jump(self,num=1):
351 def jump(self,num=1):
352 """Jump a given number of blocks relative to the current one.
352 """Jump a given number of blocks relative to the current one.
353
353
354 The offset can be positive or negative, defaults to 1."""
354 The offset can be positive or negative, defaults to 1."""
355 self.seek(self.block_index+num)
355 self.seek(self.block_index+num)
356
356
357 def again(self):
357 def again(self):
358 """Move the seek pointer back one block and re-execute."""
358 """Move the seek pointer back one block and re-execute."""
359 self.back(1)
359 self.back(1)
360 self()
360 self()
361
361
362 def edit(self,index=None):
362 def edit(self,index=None):
363 """Edit a block.
363 """Edit a block.
364
364
365 If no number is given, use the last block executed.
365 If no number is given, use the last block executed.
366
366
367 This edits the in-memory copy of the demo, it does NOT modify the
367 This edits the in-memory copy of the demo, it does NOT modify the
368 original source file. If you want to do that, simply open the file in
368 original source file. If you want to do that, simply open the file in
369 an editor and use reload() when you make changes to the file. This
369 an editor and use reload() when you make changes to the file. This
370 method is meant to let you change a block during a demonstration for
370 method is meant to let you change a block during a demonstration for
371 explanatory purposes, without damaging your original script."""
371 explanatory purposes, without damaging your original script."""
372
372
373 index = self._get_index(index)
373 index = self._get_index(index)
374 if index is None:
374 if index is None:
375 return
375 return
376 # decrease the index by one (unless we're at the very beginning), so
376 # decrease the index by one (unless we're at the very beginning), so
377 # that the default demo.edit() call opens up the sblock we've last run
377 # that the default demo.edit() call opens up the sblock we've last run
378 if index>0:
378 if index>0:
379 index -= 1
379 index -= 1
380
380
381 filename = self.shell.mktempfile(self.src_blocks[index])
381 filename = self.shell.mktempfile(self.src_blocks[index])
382 self.shell.hooks.editor(filename,1)
382 self.shell.hooks.editor(filename,1)
383 with open(filename, 'r') as f:
383 with open(filename, 'r') as f:
384 new_block = f.read()
384 new_block = f.read()
385 # update the source and colored block
385 # update the source and colored block
386 self.src_blocks[index] = new_block
386 self.src_blocks[index] = new_block
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
388 self.block_index = index
388 self.block_index = index
389 # call to run with the newly edited index
389 # call to run with the newly edited index
390 self()
390 self()
391
391
392 def show(self,index=None):
392 def show(self,index=None):
393 """Show a single block on screen"""
393 """Show a single block on screen"""
394
394
395 index = self._get_index(index)
395 index = self._get_index(index)
396 if index is None:
396 if index is None:
397 return
397 return
398
398
399 print(self.marquee('<%s> block # %s (%s remaining)' %
399 print(self.marquee('<%s> block # %s (%s remaining)' %
400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
400 (self.title,index,self.nblocks-index-1)))
401 print(self.src_blocks_colored[index], file=io.stdout)
401 print(self.src_blocks_colored[index])
402 sys.stdout.flush()
402 sys.stdout.flush()
403
403
404 def show_all(self):
404 def show_all(self):
405 """Show entire demo on screen, block by block"""
405 """Show entire demo on screen, block by block"""
406
406
407 fname = self.title
407 fname = self.title
408 title = self.title
408 title = self.title
409 nblocks = self.nblocks
409 nblocks = self.nblocks
410 silent = self._silent
410 silent = self._silent
411 marquee = self.marquee
411 marquee = self.marquee
412 for index,block in enumerate(self.src_blocks_colored):
412 for index,block in enumerate(self.src_blocks_colored):
413 if silent[index]:
413 if silent[index]:
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
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 else:
416 else:
417 print(marquee('<%s> block # %s (%s remaining)' %
417 print(marquee('<%s> block # %s (%s remaining)' %
418 (title,index,nblocks-index-1)), file=io.stdout)
418 (title,index,nblocks-index-1)))
419 print(block, end=' ', file=io.stdout)
419 print(block, end=' ')
420 sys.stdout.flush()
420 sys.stdout.flush()
421
421
422 def run_cell(self,source):
422 def run_cell(self,source):
423 """Execute a string with one or more lines of code"""
423 """Execute a string with one or more lines of code"""
424
424
425 exec(source, self.user_ns)
425 exec(source, self.user_ns)
426
426
427 def __call__(self,index=None):
427 def __call__(self,index=None):
428 """run a block of the demo.
428 """run a block of the demo.
429
429
430 If index is given, it should be an integer >=1 and <= nblocks. This
430 If index is given, it should be an integer >=1 and <= nblocks. This
431 means that the calling convention is one off from typical Python
431 means that the calling convention is one off from typical Python
432 lists. The reason for the inconsistency is that the demo always
432 lists. The reason for the inconsistency is that the demo always
433 prints 'Block n/N, and N is the total, so it would be very odd to use
433 prints 'Block n/N, and N is the total, so it would be very odd to use
434 zero-indexing here."""
434 zero-indexing here."""
435
435
436 index = self._get_index(index)
436 index = self._get_index(index)
437 if index is None:
437 if index is None:
438 return
438 return
439 try:
439 try:
440 marquee = self.marquee
440 marquee = self.marquee
441 next_block = self.src_blocks[index]
441 next_block = self.src_blocks[index]
442 self.block_index += 1
442 self.block_index += 1
443 if self._silent[index]:
443 if self._silent[index]:
444 print(marquee('Executing silent block # %s (%s remaining)' %
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 else:
446 else:
447 self.pre_cmd()
447 self.pre_cmd()
448 self.show(index)
448 self.show(index)
449 if self.auto_all or self._auto[index]:
449 if self.auto_all or self._auto[index]:
450 print(marquee('output:'), file=io.stdout)
450 print(marquee('output:'))
451 else:
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 ans = py3compat.input().strip()
453 ans = py3compat.input().strip()
454 if ans:
454 if ans:
455 print(marquee('Block NOT executed'), file=io.stdout)
455 print(marquee('Block NOT executed'))
456 return
456 return
457 try:
457 try:
458 save_argv = sys.argv
458 save_argv = sys.argv
459 sys.argv = self.sys_argv
459 sys.argv = self.sys_argv
460 self.run_cell(next_block)
460 self.run_cell(next_block)
461 self.post_cmd()
461 self.post_cmd()
462 finally:
462 finally:
463 sys.argv = save_argv
463 sys.argv = save_argv
464
464
465 except:
465 except:
466 self.ip_showtb(filename=self.fname)
466 self.ip_showtb(filename=self.fname)
467 else:
467 else:
468 self.ip_ns.update(self.user_ns)
468 self.ip_ns.update(self.user_ns)
469
469
470 if self.block_index == self.nblocks:
470 if self.block_index == self.nblocks:
471 mq1 = self.marquee('END OF DEMO')
471 mq1 = self.marquee('END OF DEMO')
472 if mq1:
472 if mq1:
473 # avoid spurious print >>io.stdout,s if empty marquees are used
473 # avoid spurious print >>io.stdout,s if empty marquees are used
474 print(file=io.stdout)
474 print()
475 print(mq1, file=io.stdout)
475 print(mq1)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'))
477 self.finished = True
477 self.finished = True
478
478
479 # These methods are meant to be overridden by subclasses who may wish to
479 # These methods are meant to be overridden by subclasses who may wish to
480 # customize the behavior of of their demos.
480 # customize the behavior of of their demos.
481 def marquee(self,txt='',width=78,mark='*'):
481 def marquee(self,txt='',width=78,mark='*'):
482 """Return the input string centered in a 'marquee'."""
482 """Return the input string centered in a 'marquee'."""
483 return marquee(txt,width,mark)
483 return marquee(txt,width,mark)
484
484
485 def pre_cmd(self):
485 def pre_cmd(self):
486 """Method called before executing each block."""
486 """Method called before executing each block."""
487 pass
487 pass
488
488
489 def post_cmd(self):
489 def post_cmd(self):
490 """Method called after executing each block."""
490 """Method called after executing each block."""
491 pass
491 pass
492
492
493
493
494 class IPythonDemo(Demo):
494 class IPythonDemo(Demo):
495 """Class for interactive demos with IPython's input processing applied.
495 """Class for interactive demos with IPython's input processing applied.
496
496
497 This subclasses Demo, but instead of executing each block by the Python
497 This subclasses Demo, but instead of executing each block by the Python
498 interpreter (via exec), it actually calls IPython on it, so that any input
498 interpreter (via exec), it actually calls IPython on it, so that any input
499 filters which may be in place are applied to the input block.
499 filters which may be in place are applied to the input block.
500
500
501 If you have an interactive environment which exposes special input
501 If you have an interactive environment which exposes special input
502 processing, you can use this class instead to write demo scripts which
502 processing, you can use this class instead to write demo scripts which
503 operate exactly as if you had typed them interactively. The default Demo
503 operate exactly as if you had typed them interactively. The default Demo
504 class requires the input to be valid, pure Python code.
504 class requires the input to be valid, pure Python code.
505 """
505 """
506
506
507 def run_cell(self,source):
507 def run_cell(self,source):
508 """Execute a string with one or more lines of code"""
508 """Execute a string with one or more lines of code"""
509
509
510 self.shell.run_cell(source)
510 self.shell.run_cell(source)
511
511
512 class LineDemo(Demo):
512 class LineDemo(Demo):
513 """Demo where each line is executed as a separate block.
513 """Demo where each line is executed as a separate block.
514
514
515 The input script should be valid Python code.
515 The input script should be valid Python code.
516
516
517 This class doesn't require any markup at all, and it's meant for simple
517 This class doesn't require any markup at all, and it's meant for simple
518 scripts (with no nesting or any kind of indentation) which consist of
518 scripts (with no nesting or any kind of indentation) which consist of
519 multiple lines of input to be executed, one at a time, as if they had been
519 multiple lines of input to be executed, one at a time, as if they had been
520 typed in the interactive prompt.
520 typed in the interactive prompt.
521
521
522 Note: the input can not have *any* indentation, which means that only
522 Note: the input can not have *any* indentation, which means that only
523 single-lines of input are accepted, not even function definitions are
523 single-lines of input are accepted, not even function definitions are
524 valid."""
524 valid."""
525
525
526 def reload(self):
526 def reload(self):
527 """Reload source from disk and initialize state."""
527 """Reload source from disk and initialize state."""
528 # read data and parse into blocks
528 # read data and parse into blocks
529 self.fload()
529 self.fload()
530 lines = self.fobj.readlines()
530 lines = self.fobj.readlines()
531 src_b = [l for l in lines if l.strip()]
531 src_b = [l for l in lines if l.strip()]
532 nblocks = len(src_b)
532 nblocks = len(src_b)
533 self.src = ''.join(lines)
533 self.src = ''.join(lines)
534 self._silent = [False]*nblocks
534 self._silent = [False]*nblocks
535 self._auto = [True]*nblocks
535 self._auto = [True]*nblocks
536 self.auto_all = True
536 self.auto_all = True
537 self.nblocks = nblocks
537 self.nblocks = nblocks
538 self.src_blocks = src_b
538 self.src_blocks = src_b
539
539
540 # also build syntax-highlighted source
540 # also build syntax-highlighted source
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
542
542
543 # ensure clean namespace and seek offset
543 # ensure clean namespace and seek offset
544 self.reset()
544 self.reset()
545
545
546
546
547 class IPythonLineDemo(IPythonDemo,LineDemo):
547 class IPythonLineDemo(IPythonDemo,LineDemo):
548 """Variant of the LineDemo class whose input is processed by IPython."""
548 """Variant of the LineDemo class whose input is processed by IPython."""
549 pass
549 pass
550
550
551
551
552 class ClearMixin(object):
552 class ClearMixin(object):
553 """Use this mixin to make Demo classes with less visual clutter.
553 """Use this mixin to make Demo classes with less visual clutter.
554
554
555 Demos using this mixin will clear the screen before every block and use
555 Demos using this mixin will clear the screen before every block and use
556 blank marquees.
556 blank marquees.
557
557
558 Note that in order for the methods defined here to actually override those
558 Note that in order for the methods defined here to actually override those
559 of the classes it's mixed with, it must go /first/ in the inheritance
559 of the classes it's mixed with, it must go /first/ in the inheritance
560 tree. For example:
560 tree. For example:
561
561
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
563
563
564 will provide an IPythonDemo class with the mixin's features.
564 will provide an IPythonDemo class with the mixin's features.
565 """
565 """
566
566
567 def marquee(self,txt='',width=78,mark='*'):
567 def marquee(self,txt='',width=78,mark='*'):
568 """Blank marquee that returns '' no matter what the input."""
568 """Blank marquee that returns '' no matter what the input."""
569 return ''
569 return ''
570
570
571 def pre_cmd(self):
571 def pre_cmd(self):
572 """Method called before executing each block.
572 """Method called before executing each block.
573
573
574 This one simply clears the screen."""
574 This one simply clears the screen."""
575 from IPython.utils.terminal import term_clear
575 from IPython.utils.terminal import term_clear
576 term_clear()
576 term_clear()
577
577
578 class ClearDemo(ClearMixin,Demo):
578 class ClearDemo(ClearMixin,Demo):
579 pass
579 pass
580
580
581
581
582 class ClearIPDemo(ClearMixin,IPythonDemo):
582 class ClearIPDemo(ClearMixin,IPythonDemo):
583 pass
583 pass
@@ -1,227 +1,233 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 from __future__ import print_function
9 from __future__ import print_function
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12
12
13 import atexit
13 import atexit
14 import os
14 import os
15 import sys
15 import sys
16 import tempfile
16 import tempfile
17 from warnings import warn
17 from warnings import warn
18
19 from IPython.utils.decorators import undoc
18 from .capture import CapturedIO, capture_output
20 from .capture import CapturedIO, capture_output
19 from .py3compat import string_types, input, PY3
21 from .py3compat import string_types, input, PY3
20
22
21
23 @undoc
22 class IOStream:
24 class IOStream:
23
25
24 def __init__(self,stream, fallback=None):
26 def __init__(self,stream, fallback=None):
25 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
27 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
26 if fallback is not None:
28 if fallback is not None:
27 stream = fallback
29 stream = fallback
28 else:
30 else:
29 raise ValueError("fallback required, but not specified")
31 raise ValueError("fallback required, but not specified")
30 self.stream = stream
32 self.stream = stream
31 self._swrite = stream.write
33 self._swrite = stream.write
32
34
33 # clone all methods not overridden:
35 # clone all methods not overridden:
34 def clone(meth):
36 def clone(meth):
35 return not hasattr(self, meth) and not meth.startswith('_')
37 return not hasattr(self, meth) and not meth.startswith('_')
36 for meth in filter(clone, dir(stream)):
38 for meth in filter(clone, dir(stream)):
37 setattr(self, meth, getattr(stream, meth))
39 setattr(self, meth, getattr(stream, meth))
38
40
39 def __repr__(self):
41 def __repr__(self):
40 cls = self.__class__
42 cls = self.__class__
41 tpl = '{mod}.{cls}({args})'
43 tpl = '{mod}.{cls}({args})'
42 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
44 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
43
45
44 def write(self,data):
46 def write(self,data):
47 warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead',
48 DeprecationWarning, stacklevel=2)
45 try:
49 try:
46 self._swrite(data)
50 self._swrite(data)
47 except:
51 except:
48 try:
52 try:
49 # print handles some unicode issues which may trip a plain
53 # print handles some unicode issues which may trip a plain
50 # write() call. Emulate write() by using an empty end
54 # write() call. Emulate write() by using an empty end
51 # argument.
55 # argument.
52 print(data, end='', file=self.stream)
56 print(data, end='', file=self.stream)
53 except:
57 except:
54 # if we get here, something is seriously broken.
58 # if we get here, something is seriously broken.
55 print('ERROR - failed to write data to stream:', self.stream,
59 print('ERROR - failed to write data to stream:', self.stream,
56 file=sys.stderr)
60 file=sys.stderr)
57
61
58 def writelines(self, lines):
62 def writelines(self, lines):
63 warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead',
64 DeprecationWarning, stacklevel=2)
59 if isinstance(lines, string_types):
65 if isinstance(lines, string_types):
60 lines = [lines]
66 lines = [lines]
61 for line in lines:
67 for line in lines:
62 self.write(line)
68 self.write(line)
63
69
64 # This class used to have a writeln method, but regular files and streams
70 # This class used to have a writeln method, but regular files and streams
65 # in Python don't have this method. We need to keep this completely
71 # in Python don't have this method. We need to keep this completely
66 # compatible so we removed it.
72 # compatible so we removed it.
67
73
68 @property
74 @property
69 def closed(self):
75 def closed(self):
70 return self.stream.closed
76 return self.stream.closed
71
77
72 def close(self):
78 def close(self):
73 pass
79 pass
74
80
75 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
81 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
76 devnull = open(os.devnull, 'w')
82 devnull = open(os.devnull, 'w')
77 atexit.register(devnull.close)
83 atexit.register(devnull.close)
78 stdin = IOStream(sys.stdin, fallback=devnull)
84 stdin = IOStream(sys.stdin, fallback=devnull)
79 stdout = IOStream(sys.stdout, fallback=devnull)
85 stdout = IOStream(sys.stdout, fallback=devnull)
80 stderr = IOStream(sys.stderr, fallback=devnull)
86 stderr = IOStream(sys.stderr, fallback=devnull)
81
87
82 class Tee(object):
88 class Tee(object):
83 """A class to duplicate an output stream to stdout/err.
89 """A class to duplicate an output stream to stdout/err.
84
90
85 This works in a manner very similar to the Unix 'tee' command.
91 This works in a manner very similar to the Unix 'tee' command.
86
92
87 When the object is closed or deleted, it closes the original file given to
93 When the object is closed or deleted, it closes the original file given to
88 it for duplication.
94 it for duplication.
89 """
95 """
90 # Inspired by:
96 # Inspired by:
91 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
97 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
92
98
93 def __init__(self, file_or_name, mode="w", channel='stdout'):
99 def __init__(self, file_or_name, mode="w", channel='stdout'):
94 """Construct a new Tee object.
100 """Construct a new Tee object.
95
101
96 Parameters
102 Parameters
97 ----------
103 ----------
98 file_or_name : filename or open filehandle (writable)
104 file_or_name : filename or open filehandle (writable)
99 File that will be duplicated
105 File that will be duplicated
100
106
101 mode : optional, valid mode for open().
107 mode : optional, valid mode for open().
102 If a filename was give, open with this mode.
108 If a filename was give, open with this mode.
103
109
104 channel : str, one of ['stdout', 'stderr']
110 channel : str, one of ['stdout', 'stderr']
105 """
111 """
106 if channel not in ['stdout', 'stderr']:
112 if channel not in ['stdout', 'stderr']:
107 raise ValueError('Invalid channel spec %s' % channel)
113 raise ValueError('Invalid channel spec %s' % channel)
108
114
109 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
115 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
110 self.file = file_or_name
116 self.file = file_or_name
111 else:
117 else:
112 self.file = open(file_or_name, mode)
118 self.file = open(file_or_name, mode)
113 self.channel = channel
119 self.channel = channel
114 self.ostream = getattr(sys, channel)
120 self.ostream = getattr(sys, channel)
115 setattr(sys, channel, self)
121 setattr(sys, channel, self)
116 self._closed = False
122 self._closed = False
117
123
118 def close(self):
124 def close(self):
119 """Close the file and restore the channel."""
125 """Close the file and restore the channel."""
120 self.flush()
126 self.flush()
121 setattr(sys, self.channel, self.ostream)
127 setattr(sys, self.channel, self.ostream)
122 self.file.close()
128 self.file.close()
123 self._closed = True
129 self._closed = True
124
130
125 def write(self, data):
131 def write(self, data):
126 """Write data to both channels."""
132 """Write data to both channels."""
127 self.file.write(data)
133 self.file.write(data)
128 self.ostream.write(data)
134 self.ostream.write(data)
129 self.ostream.flush()
135 self.ostream.flush()
130
136
131 def flush(self):
137 def flush(self):
132 """Flush both channels."""
138 """Flush both channels."""
133 self.file.flush()
139 self.file.flush()
134 self.ostream.flush()
140 self.ostream.flush()
135
141
136 def __del__(self):
142 def __del__(self):
137 if not self._closed:
143 if not self._closed:
138 self.close()
144 self.close()
139
145
140
146
141 def ask_yes_no(prompt, default=None, interrupt=None):
147 def ask_yes_no(prompt, default=None, interrupt=None):
142 """Asks a question and returns a boolean (y/n) answer.
148 """Asks a question and returns a boolean (y/n) answer.
143
149
144 If default is given (one of 'y','n'), it is used if the user input is
150 If default is given (one of 'y','n'), it is used if the user input is
145 empty. If interrupt is given (one of 'y','n'), it is used if the user
151 empty. If interrupt is given (one of 'y','n'), it is used if the user
146 presses Ctrl-C. Otherwise the question is repeated until an answer is
152 presses Ctrl-C. Otherwise the question is repeated until an answer is
147 given.
153 given.
148
154
149 An EOF is treated as the default answer. If there is no default, an
155 An EOF is treated as the default answer. If there is no default, an
150 exception is raised to prevent infinite loops.
156 exception is raised to prevent infinite loops.
151
157
152 Valid answers are: y/yes/n/no (match is not case sensitive)."""
158 Valid answers are: y/yes/n/no (match is not case sensitive)."""
153
159
154 answers = {'y':True,'n':False,'yes':True,'no':False}
160 answers = {'y':True,'n':False,'yes':True,'no':False}
155 ans = None
161 ans = None
156 while ans not in answers.keys():
162 while ans not in answers.keys():
157 try:
163 try:
158 ans = input(prompt+' ').lower()
164 ans = input(prompt+' ').lower()
159 if not ans: # response was an empty string
165 if not ans: # response was an empty string
160 ans = default
166 ans = default
161 except KeyboardInterrupt:
167 except KeyboardInterrupt:
162 if interrupt:
168 if interrupt:
163 ans = interrupt
169 ans = interrupt
164 except EOFError:
170 except EOFError:
165 if default in answers.keys():
171 if default in answers.keys():
166 ans = default
172 ans = default
167 print()
173 print()
168 else:
174 else:
169 raise
175 raise
170
176
171 return answers[ans]
177 return answers[ans]
172
178
173
179
174 def temp_pyfile(src, ext='.py'):
180 def temp_pyfile(src, ext='.py'):
175 """Make a temporary python file, return filename and filehandle.
181 """Make a temporary python file, return filename and filehandle.
176
182
177 Parameters
183 Parameters
178 ----------
184 ----------
179 src : string or list of strings (no need for ending newlines if list)
185 src : string or list of strings (no need for ending newlines if list)
180 Source code to be written to the file.
186 Source code to be written to the file.
181
187
182 ext : optional, string
188 ext : optional, string
183 Extension for the generated file.
189 Extension for the generated file.
184
190
185 Returns
191 Returns
186 -------
192 -------
187 (filename, open filehandle)
193 (filename, open filehandle)
188 It is the caller's responsibility to close the open file and unlink it.
194 It is the caller's responsibility to close the open file and unlink it.
189 """
195 """
190 fname = tempfile.mkstemp(ext)[1]
196 fname = tempfile.mkstemp(ext)[1]
191 f = open(fname,'w')
197 f = open(fname,'w')
192 f.write(src)
198 f.write(src)
193 f.flush()
199 f.flush()
194 return fname, f
200 return fname, f
195
201
196 def atomic_writing(*args, **kwargs):
202 def atomic_writing(*args, **kwargs):
197 """DEPRECATED: moved to notebook.services.contents.fileio"""
203 """DEPRECATED: moved to notebook.services.contents.fileio"""
198 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
204 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
199 from notebook.services.contents.fileio import atomic_writing
205 from notebook.services.contents.fileio import atomic_writing
200 return atomic_writing(*args, **kwargs)
206 return atomic_writing(*args, **kwargs)
201
207
202 def raw_print(*args, **kw):
208 def raw_print(*args, **kw):
203 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
209 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
204
210
205 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
211 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
206 file=sys.__stdout__)
212 file=sys.__stdout__)
207 sys.__stdout__.flush()
213 sys.__stdout__.flush()
208
214
209
215
210 def raw_print_err(*args, **kw):
216 def raw_print_err(*args, **kw):
211 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
217 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
212
218
213 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
219 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
214 file=sys.__stderr__)
220 file=sys.__stderr__)
215 sys.__stderr__.flush()
221 sys.__stderr__.flush()
216
222
217
223
218 # Short aliases for quick debugging, do NOT use these in production code.
224 # Short aliases for quick debugging, do NOT use these in production code.
219 rprint = raw_print
225 rprint = raw_print
220 rprinte = raw_print_err
226 rprinte = raw_print_err
221
227
222
228
223 def unicode_std_stream(stream='stdout'):
229 def unicode_std_stream(stream='stdout'):
224 """DEPRECATED, moved to nbconvert.utils.io"""
230 """DEPRECATED, moved to nbconvert.utils.io"""
225 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
231 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
226 from nbconvert.utils.io import unicode_std_stream
232 from nbconvert.utils.io import unicode_std_stream
227 return unicode_std_stream(stream)
233 return unicode_std_stream(stream)
@@ -1,60 +1,57 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for warnings. Shoudn't we just use the built in warnings module.
3 Utilities for warnings. Shoudn't we just use the built in warnings module.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 from __future__ import print_function
9 from __future__ import print_function
10
10
11 import sys
11 import sys
12
13 from IPython.utils import io
14
15 import warnings
12 import warnings
16
13
17 warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning)
14 warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning)
18
15
19 def warn(msg,level=2,exit_val=1):
16 def warn(msg,level=2,exit_val=1):
20 """Standard warning printer. Gives formatting consistency.
17 """Standard warning printer. Gives formatting consistency.
21
18
22 Output is sent to io.stderr (sys.stderr by default).
19 Output is sent to io.stderr (sys.stderr by default).
23
20
24 Options:
21 Options:
25
22
26 -level(2): allows finer control:
23 -level(2): allows finer control:
27 0 -> Do nothing, dummy function.
24 0 -> Do nothing, dummy function.
28 1 -> Print message.
25 1 -> Print message.
29 2 -> Print 'WARNING:' + message. (Default level).
26 2 -> Print 'WARNING:' + message. (Default level).
30 3 -> Print 'ERROR:' + message.
27 3 -> Print 'ERROR:' + message.
31 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
28 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
32
29
33 -exit_val (1): exit value returned by sys.exit() for a level 4
30 -exit_val (1): exit value returned by sys.exit() for a level 4
34 warning. Ignored for all other levels."""
31 warning. Ignored for all other levels."""
35
32
36 warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning)
33 warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning)
37 if level>0:
34 if level>0:
38 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
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 if level == 4:
37 if level == 4:
41 print('Exiting.\n', file=io.stderr)
38 print('Exiting.\n', file=sys.stderr)
42 sys.exit(exit_val)
39 sys.exit(exit_val)
43
40
44
41
45 def info(msg):
42 def info(msg):
46 """Equivalent to warn(msg,level=1)."""
43 """Equivalent to warn(msg,level=1)."""
47
44
48 warn(msg,level=1)
45 warn(msg,level=1)
49
46
50
47
51 def error(msg):
48 def error(msg):
52 """Equivalent to warn(msg,level=3)."""
49 """Equivalent to warn(msg,level=3)."""
53
50
54 warn(msg,level=3)
51 warn(msg,level=3)
55
52
56
53
57 def fatal(msg,exit_val=1):
54 def fatal(msg,exit_val=1):
58 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
55 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
59
56
60 warn(msg,exit_val=exit_val,level=4)
57 warn(msg,exit_val=exit_val,level=4)
General Comments 0
You need to be logged in to leave comments. Login now