##// END OF EJS Templates
Fix method special attributes...
Thomas Kluyver -
Show More
@@ -1,647 +1,647 b''
1 """Implementation of basic magic functions.
1 """Implementation of basic magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The 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 io
17 import io
18 import json
18 import json
19 import sys
19 import sys
20 from pprint import pformat
20 from pprint import pformat
21
21
22 # Our own packages
22 # Our own packages
23 from IPython.core import magic_arguments, page
23 from IPython.core import magic_arguments, page
24 from IPython.core.error import UsageError
24 from IPython.core.error import UsageError
25 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
25 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
26 from IPython.utils.text import format_screen, dedent, indent
26 from IPython.utils.text import format_screen, dedent, indent
27 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.utils.ipstruct import Struct
28 from IPython.utils.ipstruct import Struct
29 from IPython.utils.path import unquote_filename
29 from IPython.utils.path import unquote_filename
30 from IPython.utils.py3compat import unicode_type
30 from IPython.utils.py3compat import unicode_type
31 from IPython.utils.warn import warn, error
31 from IPython.utils.warn import warn, error
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Magics class implementation
34 # Magics class implementation
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 class MagicsDisplay(object):
37 class MagicsDisplay(object):
38 def __init__(self, magics_manager):
38 def __init__(self, magics_manager):
39 self.magics_manager = magics_manager
39 self.magics_manager = magics_manager
40
40
41 def _lsmagic(self):
41 def _lsmagic(self):
42 """The main implementation of the %lsmagic"""
42 """The main implementation of the %lsmagic"""
43 mesc = magic_escapes['line']
43 mesc = magic_escapes['line']
44 cesc = magic_escapes['cell']
44 cesc = magic_escapes['cell']
45 mman = self.magics_manager
45 mman = self.magics_manager
46 magics = mman.lsmagic()
46 magics = mman.lsmagic()
47 out = ['Available line magics:',
47 out = ['Available line magics:',
48 mesc + (' '+mesc).join(sorted(magics['line'])),
48 mesc + (' '+mesc).join(sorted(magics['line'])),
49 '',
49 '',
50 'Available cell magics:',
50 'Available cell magics:',
51 cesc + (' '+cesc).join(sorted(magics['cell'])),
51 cesc + (' '+cesc).join(sorted(magics['cell'])),
52 '',
52 '',
53 mman.auto_status()]
53 mman.auto_status()]
54 return '\n'.join(out)
54 return '\n'.join(out)
55
55
56 def _repr_pretty_(self, p, cycle):
56 def _repr_pretty_(self, p, cycle):
57 p.text(self._lsmagic())
57 p.text(self._lsmagic())
58
58
59 def __str__(self):
59 def __str__(self):
60 return self._lsmagic()
60 return self._lsmagic()
61
61
62 def _jsonable(self):
62 def _jsonable(self):
63 """turn magics dict into jsonable dict of the same structure
63 """turn magics dict into jsonable dict of the same structure
64
64
65 replaces object instances with their class names as strings
65 replaces object instances with their class names as strings
66 """
66 """
67 magic_dict = {}
67 magic_dict = {}
68 mman = self.magics_manager
68 mman = self.magics_manager
69 magics = mman.lsmagic()
69 magics = mman.lsmagic()
70 for key, subdict in magics.items():
70 for key, subdict in magics.items():
71 d = {}
71 d = {}
72 magic_dict[key] = d
72 magic_dict[key] = d
73 for name, obj in subdict.items():
73 for name, obj in subdict.items():
74 try:
74 try:
75 classname = obj.im_class.__name__
75 classname = obj.__self__.__class__.__name__
76 except AttributeError:
76 except AttributeError:
77 classname = 'Other'
77 classname = 'Other'
78
78
79 d[name] = classname
79 d[name] = classname
80 return magic_dict
80 return magic_dict
81
81
82 def _repr_json_(self):
82 def _repr_json_(self):
83 return json.dumps(self._jsonable())
83 return json.dumps(self._jsonable())
84
84
85
85
86 @magics_class
86 @magics_class
87 class BasicMagics(Magics):
87 class BasicMagics(Magics):
88 """Magics that provide central IPython functionality.
88 """Magics that provide central IPython functionality.
89
89
90 These are various magics that don't fit into specific categories but that
90 These are various magics that don't fit into specific categories but that
91 are all part of the base 'IPython experience'."""
91 are all part of the base 'IPython experience'."""
92
92
93 @magic_arguments.magic_arguments()
93 @magic_arguments.magic_arguments()
94 @magic_arguments.argument(
94 @magic_arguments.argument(
95 '-l', '--line', action='store_true',
95 '-l', '--line', action='store_true',
96 help="""Create a line magic alias."""
96 help="""Create a line magic alias."""
97 )
97 )
98 @magic_arguments.argument(
98 @magic_arguments.argument(
99 '-c', '--cell', action='store_true',
99 '-c', '--cell', action='store_true',
100 help="""Create a cell magic alias."""
100 help="""Create a cell magic alias."""
101 )
101 )
102 @magic_arguments.argument(
102 @magic_arguments.argument(
103 'name',
103 'name',
104 help="""Name of the magic to be created."""
104 help="""Name of the magic to be created."""
105 )
105 )
106 @magic_arguments.argument(
106 @magic_arguments.argument(
107 'target',
107 'target',
108 help="""Name of the existing line or cell magic."""
108 help="""Name of the existing line or cell magic."""
109 )
109 )
110 @line_magic
110 @line_magic
111 def alias_magic(self, line=''):
111 def alias_magic(self, line=''):
112 """Create an alias for an existing line or cell magic.
112 """Create an alias for an existing line or cell magic.
113
113
114 Examples
114 Examples
115 --------
115 --------
116 ::
116 ::
117 In [1]: %alias_magic t timeit
117 In [1]: %alias_magic t timeit
118 Created `%t` as an alias for `%timeit`.
118 Created `%t` as an alias for `%timeit`.
119 Created `%%t` as an alias for `%%timeit`.
119 Created `%%t` as an alias for `%%timeit`.
120
120
121 In [2]: %t -n1 pass
121 In [2]: %t -n1 pass
122 1 loops, best of 3: 954 ns per loop
122 1 loops, best of 3: 954 ns per loop
123
123
124 In [3]: %%t -n1
124 In [3]: %%t -n1
125 ...: pass
125 ...: pass
126 ...:
126 ...:
127 1 loops, best of 3: 954 ns per loop
127 1 loops, best of 3: 954 ns per loop
128
128
129 In [4]: %alias_magic --cell whereami pwd
129 In [4]: %alias_magic --cell whereami pwd
130 UsageError: Cell magic function `%%pwd` not found.
130 UsageError: Cell magic function `%%pwd` not found.
131 In [5]: %alias_magic --line whereami pwd
131 In [5]: %alias_magic --line whereami pwd
132 Created `%whereami` as an alias for `%pwd`.
132 Created `%whereami` as an alias for `%pwd`.
133
133
134 In [6]: %whereami
134 In [6]: %whereami
135 Out[6]: u'/home/testuser'
135 Out[6]: u'/home/testuser'
136 """
136 """
137 args = magic_arguments.parse_argstring(self.alias_magic, line)
137 args = magic_arguments.parse_argstring(self.alias_magic, line)
138 shell = self.shell
138 shell = self.shell
139 mman = self.shell.magics_manager
139 mman = self.shell.magics_manager
140 escs = ''.join(magic_escapes.values())
140 escs = ''.join(magic_escapes.values())
141
141
142 target = args.target.lstrip(escs)
142 target = args.target.lstrip(escs)
143 name = args.name.lstrip(escs)
143 name = args.name.lstrip(escs)
144
144
145 # Find the requested magics.
145 # Find the requested magics.
146 m_line = shell.find_magic(target, 'line')
146 m_line = shell.find_magic(target, 'line')
147 m_cell = shell.find_magic(target, 'cell')
147 m_cell = shell.find_magic(target, 'cell')
148 if args.line and m_line is None:
148 if args.line and m_line is None:
149 raise UsageError('Line magic function `%s%s` not found.' %
149 raise UsageError('Line magic function `%s%s` not found.' %
150 (magic_escapes['line'], target))
150 (magic_escapes['line'], target))
151 if args.cell and m_cell is None:
151 if args.cell and m_cell is None:
152 raise UsageError('Cell magic function `%s%s` not found.' %
152 raise UsageError('Cell magic function `%s%s` not found.' %
153 (magic_escapes['cell'], target))
153 (magic_escapes['cell'], target))
154
154
155 # If --line and --cell are not specified, default to the ones
155 # If --line and --cell are not specified, default to the ones
156 # that are available.
156 # that are available.
157 if not args.line and not args.cell:
157 if not args.line and not args.cell:
158 if not m_line and not m_cell:
158 if not m_line and not m_cell:
159 raise UsageError(
159 raise UsageError(
160 'No line or cell magic with name `%s` found.' % target
160 'No line or cell magic with name `%s` found.' % target
161 )
161 )
162 args.line = bool(m_line)
162 args.line = bool(m_line)
163 args.cell = bool(m_cell)
163 args.cell = bool(m_cell)
164
164
165 if args.line:
165 if args.line:
166 mman.register_alias(name, target, 'line')
166 mman.register_alias(name, target, 'line')
167 print('Created `%s%s` as an alias for `%s%s`.' % (
167 print('Created `%s%s` as an alias for `%s%s`.' % (
168 magic_escapes['line'], name,
168 magic_escapes['line'], name,
169 magic_escapes['line'], target))
169 magic_escapes['line'], target))
170
170
171 if args.cell:
171 if args.cell:
172 mman.register_alias(name, target, 'cell')
172 mman.register_alias(name, target, 'cell')
173 print('Created `%s%s` as an alias for `%s%s`.' % (
173 print('Created `%s%s` as an alias for `%s%s`.' % (
174 magic_escapes['cell'], name,
174 magic_escapes['cell'], name,
175 magic_escapes['cell'], target))
175 magic_escapes['cell'], target))
176
176
177 @line_magic
177 @line_magic
178 def lsmagic(self, parameter_s=''):
178 def lsmagic(self, parameter_s=''):
179 """List currently available magic functions."""
179 """List currently available magic functions."""
180 return MagicsDisplay(self.shell.magics_manager)
180 return MagicsDisplay(self.shell.magics_manager)
181
181
182 def _magic_docs(self, brief=False, rest=False):
182 def _magic_docs(self, brief=False, rest=False):
183 """Return docstrings from magic functions."""
183 """Return docstrings from magic functions."""
184 mman = self.shell.magics_manager
184 mman = self.shell.magics_manager
185 docs = mman.lsmagic_docs(brief, missing='No documentation')
185 docs = mman.lsmagic_docs(brief, missing='No documentation')
186
186
187 if rest:
187 if rest:
188 format_string = '**%s%s**::\n\n%s\n\n'
188 format_string = '**%s%s**::\n\n%s\n\n'
189 else:
189 else:
190 format_string = '%s%s:\n%s\n'
190 format_string = '%s%s:\n%s\n'
191
191
192 return ''.join(
192 return ''.join(
193 [format_string % (magic_escapes['line'], fname,
193 [format_string % (magic_escapes['line'], fname,
194 indent(dedent(fndoc)))
194 indent(dedent(fndoc)))
195 for fname, fndoc in sorted(docs['line'].items())]
195 for fname, fndoc in sorted(docs['line'].items())]
196 +
196 +
197 [format_string % (magic_escapes['cell'], fname,
197 [format_string % (magic_escapes['cell'], fname,
198 indent(dedent(fndoc)))
198 indent(dedent(fndoc)))
199 for fname, fndoc in sorted(docs['cell'].items())]
199 for fname, fndoc in sorted(docs['cell'].items())]
200 )
200 )
201
201
202 @line_magic
202 @line_magic
203 def magic(self, parameter_s=''):
203 def magic(self, parameter_s=''):
204 """Print information about the magic function system.
204 """Print information about the magic function system.
205
205
206 Supported formats: -latex, -brief, -rest
206 Supported formats: -latex, -brief, -rest
207 """
207 """
208
208
209 mode = ''
209 mode = ''
210 try:
210 try:
211 mode = parameter_s.split()[0][1:]
211 mode = parameter_s.split()[0][1:]
212 if mode == 'rest':
212 if mode == 'rest':
213 rest_docs = []
213 rest_docs = []
214 except IndexError:
214 except IndexError:
215 pass
215 pass
216
216
217 brief = (mode == 'brief')
217 brief = (mode == 'brief')
218 rest = (mode == 'rest')
218 rest = (mode == 'rest')
219 magic_docs = self._magic_docs(brief, rest)
219 magic_docs = self._magic_docs(brief, rest)
220
220
221 if mode == 'latex':
221 if mode == 'latex':
222 print(self.format_latex(magic_docs))
222 print(self.format_latex(magic_docs))
223 return
223 return
224 else:
224 else:
225 magic_docs = format_screen(magic_docs)
225 magic_docs = format_screen(magic_docs)
226
226
227 out = ["""
227 out = ["""
228 IPython's 'magic' functions
228 IPython's 'magic' functions
229 ===========================
229 ===========================
230
230
231 The magic function system provides a series of functions which allow you to
231 The magic function system provides a series of functions which allow you to
232 control the behavior of IPython itself, plus a lot of system-type
232 control the behavior of IPython itself, plus a lot of system-type
233 features. There are two kinds of magics, line-oriented and cell-oriented.
233 features. There are two kinds of magics, line-oriented and cell-oriented.
234
234
235 Line magics are prefixed with the % character and work much like OS
235 Line magics are prefixed with the % character and work much like OS
236 command-line calls: they get as an argument the rest of the line, where
236 command-line calls: they get as an argument the rest of the line, where
237 arguments are passed without parentheses or quotes. For example, this will
237 arguments are passed without parentheses or quotes. For example, this will
238 time the given statement::
238 time the given statement::
239
239
240 %timeit range(1000)
240 %timeit range(1000)
241
241
242 Cell magics are prefixed with a double %%, and they are functions that get as
242 Cell magics are prefixed with a double %%, and they are functions that get as
243 an argument not only the rest of the line, but also the lines below it in a
243 an argument not only the rest of the line, but also the lines below it in a
244 separate argument. These magics are called with two arguments: the rest of the
244 separate argument. These magics are called with two arguments: the rest of the
245 call line and the body of the cell, consisting of the lines below the first.
245 call line and the body of the cell, consisting of the lines below the first.
246 For example::
246 For example::
247
247
248 %%timeit x = numpy.random.randn((100, 100))
248 %%timeit x = numpy.random.randn((100, 100))
249 numpy.linalg.svd(x)
249 numpy.linalg.svd(x)
250
250
251 will time the execution of the numpy svd routine, running the assignment of x
251 will time the execution of the numpy svd routine, running the assignment of x
252 as part of the setup phase, which is not timed.
252 as part of the setup phase, which is not timed.
253
253
254 In a line-oriented client (the terminal or Qt console IPython), starting a new
254 In a line-oriented client (the terminal or Qt console IPython), starting a new
255 input with %% will automatically enter cell mode, and IPython will continue
255 input with %% will automatically enter cell mode, and IPython will continue
256 reading input until a blank line is given. In the notebook, simply type the
256 reading input until a blank line is given. In the notebook, simply type the
257 whole cell as one entity, but keep in mind that the %% escape can only be at
257 whole cell as one entity, but keep in mind that the %% escape can only be at
258 the very start of the cell.
258 the very start of the cell.
259
259
260 NOTE: If you have 'automagic' enabled (via the command line option or with the
260 NOTE: If you have 'automagic' enabled (via the command line option or with the
261 %automagic function), you don't need to type in the % explicitly for line
261 %automagic function), you don't need to type in the % explicitly for line
262 magics; cell magics always require an explicit '%%' escape. By default,
262 magics; cell magics always require an explicit '%%' escape. By default,
263 IPython ships with automagic on, so you should only rarely need the % escape.
263 IPython ships with automagic on, so you should only rarely need the % escape.
264
264
265 Example: typing '%cd mydir' (without the quotes) changes you working directory
265 Example: typing '%cd mydir' (without the quotes) changes you working directory
266 to 'mydir', if it exists.
266 to 'mydir', if it exists.
267
267
268 For a list of the available magic functions, use %lsmagic. For a description
268 For a list of the available magic functions, use %lsmagic. For a description
269 of any of them, type %magic_name?, e.g. '%cd?'.
269 of any of them, type %magic_name?, e.g. '%cd?'.
270
270
271 Currently the magic system has the following functions:""",
271 Currently the magic system has the following functions:""",
272 magic_docs,
272 magic_docs,
273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
274 str(self.lsmagic()),
274 str(self.lsmagic()),
275 ]
275 ]
276 page.page('\n'.join(out))
276 page.page('\n'.join(out))
277
277
278
278
279 @line_magic
279 @line_magic
280 def page(self, parameter_s=''):
280 def page(self, parameter_s=''):
281 """Pretty print the object and display it through a pager.
281 """Pretty print the object and display it through a pager.
282
282
283 %page [options] OBJECT
283 %page [options] OBJECT
284
284
285 If no object is given, use _ (last output).
285 If no object is given, use _ (last output).
286
286
287 Options:
287 Options:
288
288
289 -r: page str(object), don't pretty-print it."""
289 -r: page str(object), don't pretty-print it."""
290
290
291 # After a function contributed by Olivier Aubert, slightly modified.
291 # After a function contributed by Olivier Aubert, slightly modified.
292
292
293 # Process options/args
293 # Process options/args
294 opts, args = self.parse_options(parameter_s, 'r')
294 opts, args = self.parse_options(parameter_s, 'r')
295 raw = 'r' in opts
295 raw = 'r' in opts
296
296
297 oname = args and args or '_'
297 oname = args and args or '_'
298 info = self.shell._ofind(oname)
298 info = self.shell._ofind(oname)
299 if info['found']:
299 if info['found']:
300 txt = (raw and str or pformat)( info['obj'] )
300 txt = (raw and str or pformat)( info['obj'] )
301 page.page(txt)
301 page.page(txt)
302 else:
302 else:
303 print('Object `%s` not found' % oname)
303 print('Object `%s` not found' % oname)
304
304
305 @line_magic
305 @line_magic
306 def profile(self, parameter_s=''):
306 def profile(self, parameter_s=''):
307 """Print your currently active IPython profile."""
307 """Print your currently active IPython profile."""
308 from IPython.core.application import BaseIPythonApplication
308 from IPython.core.application import BaseIPythonApplication
309 if BaseIPythonApplication.initialized():
309 if BaseIPythonApplication.initialized():
310 print(BaseIPythonApplication.instance().profile)
310 print(BaseIPythonApplication.instance().profile)
311 else:
311 else:
312 error("profile is an application-level value, but you don't appear to be in an IPython application")
312 error("profile is an application-level value, but you don't appear to be in an IPython application")
313
313
314 @line_magic
314 @line_magic
315 def pprint(self, parameter_s=''):
315 def pprint(self, parameter_s=''):
316 """Toggle pretty printing on/off."""
316 """Toggle pretty printing on/off."""
317 ptformatter = self.shell.display_formatter.formatters['text/plain']
317 ptformatter = self.shell.display_formatter.formatters['text/plain']
318 ptformatter.pprint = bool(1 - ptformatter.pprint)
318 ptformatter.pprint = bool(1 - ptformatter.pprint)
319 print('Pretty printing has been turned',
319 print('Pretty printing has been turned',
320 ['OFF','ON'][ptformatter.pprint])
320 ['OFF','ON'][ptformatter.pprint])
321
321
322 @line_magic
322 @line_magic
323 def colors(self, parameter_s=''):
323 def colors(self, parameter_s=''):
324 """Switch color scheme for prompts, info system and exception handlers.
324 """Switch color scheme for prompts, info system and exception handlers.
325
325
326 Currently implemented schemes: NoColor, Linux, LightBG.
326 Currently implemented schemes: NoColor, Linux, LightBG.
327
327
328 Color scheme names are not case-sensitive.
328 Color scheme names are not case-sensitive.
329
329
330 Examples
330 Examples
331 --------
331 --------
332 To get a plain black and white terminal::
332 To get a plain black and white terminal::
333
333
334 %colors nocolor
334 %colors nocolor
335 """
335 """
336 def color_switch_err(name):
336 def color_switch_err(name):
337 warn('Error changing %s color schemes.\n%s' %
337 warn('Error changing %s color schemes.\n%s' %
338 (name, sys.exc_info()[1]))
338 (name, sys.exc_info()[1]))
339
339
340
340
341 new_scheme = parameter_s.strip()
341 new_scheme = parameter_s.strip()
342 if not new_scheme:
342 if not new_scheme:
343 raise UsageError(
343 raise UsageError(
344 "%colors: you must specify a color scheme. See '%colors?'")
344 "%colors: you must specify a color scheme. See '%colors?'")
345 # local shortcut
345 # local shortcut
346 shell = self.shell
346 shell = self.shell
347
347
348 import IPython.utils.rlineimpl as readline
348 import IPython.utils.rlineimpl as readline
349
349
350 if not shell.colors_force and \
350 if not shell.colors_force and \
351 not readline.have_readline and \
351 not readline.have_readline and \
352 (sys.platform == "win32" or sys.platform == "cli"):
352 (sys.platform == "win32" or sys.platform == "cli"):
353 msg = """\
353 msg = """\
354 Proper color support under MS Windows requires the pyreadline library.
354 Proper color support under MS Windows requires the pyreadline library.
355 You can find it at:
355 You can find it at:
356 http://ipython.org/pyreadline.html
356 http://ipython.org/pyreadline.html
357 Gary's readline needs the ctypes module, from:
357 Gary's readline needs the ctypes module, from:
358 http://starship.python.net/crew/theller/ctypes
358 http://starship.python.net/crew/theller/ctypes
359 (Note that ctypes is already part of Python versions 2.5 and newer).
359 (Note that ctypes is already part of Python versions 2.5 and newer).
360
360
361 Defaulting color scheme to 'NoColor'"""
361 Defaulting color scheme to 'NoColor'"""
362 new_scheme = 'NoColor'
362 new_scheme = 'NoColor'
363 warn(msg)
363 warn(msg)
364
364
365 # readline option is 0
365 # readline option is 0
366 if not shell.colors_force and not shell.has_readline:
366 if not shell.colors_force and not shell.has_readline:
367 new_scheme = 'NoColor'
367 new_scheme = 'NoColor'
368
368
369 # Set prompt colors
369 # Set prompt colors
370 try:
370 try:
371 shell.prompt_manager.color_scheme = new_scheme
371 shell.prompt_manager.color_scheme = new_scheme
372 except:
372 except:
373 color_switch_err('prompt')
373 color_switch_err('prompt')
374 else:
374 else:
375 shell.colors = \
375 shell.colors = \
376 shell.prompt_manager.color_scheme_table.active_scheme_name
376 shell.prompt_manager.color_scheme_table.active_scheme_name
377 # Set exception colors
377 # Set exception colors
378 try:
378 try:
379 shell.InteractiveTB.set_colors(scheme = new_scheme)
379 shell.InteractiveTB.set_colors(scheme = new_scheme)
380 shell.SyntaxTB.set_colors(scheme = new_scheme)
380 shell.SyntaxTB.set_colors(scheme = new_scheme)
381 except:
381 except:
382 color_switch_err('exception')
382 color_switch_err('exception')
383
383
384 # Set info (for 'object?') colors
384 # Set info (for 'object?') colors
385 if shell.color_info:
385 if shell.color_info:
386 try:
386 try:
387 shell.inspector.set_active_scheme(new_scheme)
387 shell.inspector.set_active_scheme(new_scheme)
388 except:
388 except:
389 color_switch_err('object inspector')
389 color_switch_err('object inspector')
390 else:
390 else:
391 shell.inspector.set_active_scheme('NoColor')
391 shell.inspector.set_active_scheme('NoColor')
392
392
393 @line_magic
393 @line_magic
394 def xmode(self, parameter_s=''):
394 def xmode(self, parameter_s=''):
395 """Switch modes for the exception handlers.
395 """Switch modes for the exception handlers.
396
396
397 Valid modes: Plain, Context and Verbose.
397 Valid modes: Plain, Context and Verbose.
398
398
399 If called without arguments, acts as a toggle."""
399 If called without arguments, acts as a toggle."""
400
400
401 def xmode_switch_err(name):
401 def xmode_switch_err(name):
402 warn('Error changing %s exception modes.\n%s' %
402 warn('Error changing %s exception modes.\n%s' %
403 (name,sys.exc_info()[1]))
403 (name,sys.exc_info()[1]))
404
404
405 shell = self.shell
405 shell = self.shell
406 new_mode = parameter_s.strip().capitalize()
406 new_mode = parameter_s.strip().capitalize()
407 try:
407 try:
408 shell.InteractiveTB.set_mode(mode=new_mode)
408 shell.InteractiveTB.set_mode(mode=new_mode)
409 print('Exception reporting mode:',shell.InteractiveTB.mode)
409 print('Exception reporting mode:',shell.InteractiveTB.mode)
410 except:
410 except:
411 xmode_switch_err('user')
411 xmode_switch_err('user')
412
412
413 @line_magic
413 @line_magic
414 def quickref(self,arg):
414 def quickref(self,arg):
415 """ Show a quick reference sheet """
415 """ Show a quick reference sheet """
416 from IPython.core.usage import quick_reference
416 from IPython.core.usage import quick_reference
417 qr = quick_reference + self._magic_docs(brief=True)
417 qr = quick_reference + self._magic_docs(brief=True)
418 page.page(qr)
418 page.page(qr)
419
419
420 @line_magic
420 @line_magic
421 def doctest_mode(self, parameter_s=''):
421 def doctest_mode(self, parameter_s=''):
422 """Toggle doctest mode on and off.
422 """Toggle doctest mode on and off.
423
423
424 This mode is intended to make IPython behave as much as possible like a
424 This mode is intended to make IPython behave as much as possible like a
425 plain Python shell, from the perspective of how its prompts, exceptions
425 plain Python shell, from the perspective of how its prompts, exceptions
426 and output look. This makes it easy to copy and paste parts of a
426 and output look. This makes it easy to copy and paste parts of a
427 session into doctests. It does so by:
427 session into doctests. It does so by:
428
428
429 - Changing the prompts to the classic ``>>>`` ones.
429 - Changing the prompts to the classic ``>>>`` ones.
430 - Changing the exception reporting mode to 'Plain'.
430 - Changing the exception reporting mode to 'Plain'.
431 - Disabling pretty-printing of output.
431 - Disabling pretty-printing of output.
432
432
433 Note that IPython also supports the pasting of code snippets that have
433 Note that IPython also supports the pasting of code snippets that have
434 leading '>>>' and '...' prompts in them. This means that you can paste
434 leading '>>>' and '...' prompts in them. This means that you can paste
435 doctests from files or docstrings (even if they have leading
435 doctests from files or docstrings (even if they have leading
436 whitespace), and the code will execute correctly. You can then use
436 whitespace), and the code will execute correctly. You can then use
437 '%history -t' to see the translated history; this will give you the
437 '%history -t' to see the translated history; this will give you the
438 input after removal of all the leading prompts and whitespace, which
438 input after removal of all the leading prompts and whitespace, which
439 can be pasted back into an editor.
439 can be pasted back into an editor.
440
440
441 With these features, you can switch into this mode easily whenever you
441 With these features, you can switch into this mode easily whenever you
442 need to do testing and changes to doctests, without having to leave
442 need to do testing and changes to doctests, without having to leave
443 your existing IPython session.
443 your existing IPython session.
444 """
444 """
445
445
446 # Shorthands
446 # Shorthands
447 shell = self.shell
447 shell = self.shell
448 pm = shell.prompt_manager
448 pm = shell.prompt_manager
449 meta = shell.meta
449 meta = shell.meta
450 disp_formatter = self.shell.display_formatter
450 disp_formatter = self.shell.display_formatter
451 ptformatter = disp_formatter.formatters['text/plain']
451 ptformatter = disp_formatter.formatters['text/plain']
452 # dstore is a data store kept in the instance metadata bag to track any
452 # dstore is a data store kept in the instance metadata bag to track any
453 # changes we make, so we can undo them later.
453 # changes we make, so we can undo them later.
454 dstore = meta.setdefault('doctest_mode',Struct())
454 dstore = meta.setdefault('doctest_mode',Struct())
455 save_dstore = dstore.setdefault
455 save_dstore = dstore.setdefault
456
456
457 # save a few values we'll need to recover later
457 # save a few values we'll need to recover later
458 mode = save_dstore('mode',False)
458 mode = save_dstore('mode',False)
459 save_dstore('rc_pprint',ptformatter.pprint)
459 save_dstore('rc_pprint',ptformatter.pprint)
460 save_dstore('xmode',shell.InteractiveTB.mode)
460 save_dstore('xmode',shell.InteractiveTB.mode)
461 save_dstore('rc_separate_out',shell.separate_out)
461 save_dstore('rc_separate_out',shell.separate_out)
462 save_dstore('rc_separate_out2',shell.separate_out2)
462 save_dstore('rc_separate_out2',shell.separate_out2)
463 save_dstore('rc_prompts_pad_left',pm.justify)
463 save_dstore('rc_prompts_pad_left',pm.justify)
464 save_dstore('rc_separate_in',shell.separate_in)
464 save_dstore('rc_separate_in',shell.separate_in)
465 save_dstore('rc_active_types',disp_formatter.active_types)
465 save_dstore('rc_active_types',disp_formatter.active_types)
466 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
466 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
467
467
468 if mode == False:
468 if mode == False:
469 # turn on
469 # turn on
470 pm.in_template = '>>> '
470 pm.in_template = '>>> '
471 pm.in2_template = '... '
471 pm.in2_template = '... '
472 pm.out_template = ''
472 pm.out_template = ''
473
473
474 # Prompt separators like plain python
474 # Prompt separators like plain python
475 shell.separate_in = ''
475 shell.separate_in = ''
476 shell.separate_out = ''
476 shell.separate_out = ''
477 shell.separate_out2 = ''
477 shell.separate_out2 = ''
478
478
479 pm.justify = False
479 pm.justify = False
480
480
481 ptformatter.pprint = False
481 ptformatter.pprint = False
482 disp_formatter.active_types = ['text/plain']
482 disp_formatter.active_types = ['text/plain']
483
483
484 shell.magic('xmode Plain')
484 shell.magic('xmode Plain')
485 else:
485 else:
486 # turn off
486 # turn off
487 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
487 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
488
488
489 shell.separate_in = dstore.rc_separate_in
489 shell.separate_in = dstore.rc_separate_in
490
490
491 shell.separate_out = dstore.rc_separate_out
491 shell.separate_out = dstore.rc_separate_out
492 shell.separate_out2 = dstore.rc_separate_out2
492 shell.separate_out2 = dstore.rc_separate_out2
493
493
494 pm.justify = dstore.rc_prompts_pad_left
494 pm.justify = dstore.rc_prompts_pad_left
495
495
496 ptformatter.pprint = dstore.rc_pprint
496 ptformatter.pprint = dstore.rc_pprint
497 disp_formatter.active_types = dstore.rc_active_types
497 disp_formatter.active_types = dstore.rc_active_types
498
498
499 shell.magic('xmode ' + dstore.xmode)
499 shell.magic('xmode ' + dstore.xmode)
500
500
501 # Store new mode and inform
501 # Store new mode and inform
502 dstore.mode = bool(1-int(mode))
502 dstore.mode = bool(1-int(mode))
503 mode_label = ['OFF','ON'][dstore.mode]
503 mode_label = ['OFF','ON'][dstore.mode]
504 print('Doctest mode is:', mode_label)
504 print('Doctest mode is:', mode_label)
505
505
506 @line_magic
506 @line_magic
507 def gui(self, parameter_s=''):
507 def gui(self, parameter_s=''):
508 """Enable or disable IPython GUI event loop integration.
508 """Enable or disable IPython GUI event loop integration.
509
509
510 %gui [GUINAME]
510 %gui [GUINAME]
511
511
512 This magic replaces IPython's threaded shells that were activated
512 This magic replaces IPython's threaded shells that were activated
513 using the (pylab/wthread/etc.) command line flags. GUI toolkits
513 using the (pylab/wthread/etc.) command line flags. GUI toolkits
514 can now be enabled at runtime and keyboard
514 can now be enabled at runtime and keyboard
515 interrupts should work without any problems. The following toolkits
515 interrupts should work without any problems. The following toolkits
516 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
516 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
517
517
518 %gui wx # enable wxPython event loop integration
518 %gui wx # enable wxPython event loop integration
519 %gui qt4|qt # enable PyQt4 event loop integration
519 %gui qt4|qt # enable PyQt4 event loop integration
520 %gui gtk # enable PyGTK event loop integration
520 %gui gtk # enable PyGTK event loop integration
521 %gui gtk3 # enable Gtk3 event loop integration
521 %gui gtk3 # enable Gtk3 event loop integration
522 %gui tk # enable Tk event loop integration
522 %gui tk # enable Tk event loop integration
523 %gui osx # enable Cocoa event loop integration
523 %gui osx # enable Cocoa event loop integration
524 # (requires %matplotlib 1.1)
524 # (requires %matplotlib 1.1)
525 %gui # disable all event loop integration
525 %gui # disable all event loop integration
526
526
527 WARNING: after any of these has been called you can simply create
527 WARNING: after any of these has been called you can simply create
528 an application object, but DO NOT start the event loop yourself, as
528 an application object, but DO NOT start the event loop yourself, as
529 we have already handled that.
529 we have already handled that.
530 """
530 """
531 opts, arg = self.parse_options(parameter_s, '')
531 opts, arg = self.parse_options(parameter_s, '')
532 if arg=='': arg = None
532 if arg=='': arg = None
533 try:
533 try:
534 return self.shell.enable_gui(arg)
534 return self.shell.enable_gui(arg)
535 except Exception as e:
535 except Exception as e:
536 # print simple error message, rather than traceback if we can't
536 # print simple error message, rather than traceback if we can't
537 # hook up the GUI
537 # hook up the GUI
538 error(str(e))
538 error(str(e))
539
539
540 @skip_doctest
540 @skip_doctest
541 @line_magic
541 @line_magic
542 def precision(self, s=''):
542 def precision(self, s=''):
543 """Set floating point precision for pretty printing.
543 """Set floating point precision for pretty printing.
544
544
545 Can set either integer precision or a format string.
545 Can set either integer precision or a format string.
546
546
547 If numpy has been imported and precision is an int,
547 If numpy has been imported and precision is an int,
548 numpy display precision will also be set, via ``numpy.set_printoptions``.
548 numpy display precision will also be set, via ``numpy.set_printoptions``.
549
549
550 If no argument is given, defaults will be restored.
550 If no argument is given, defaults will be restored.
551
551
552 Examples
552 Examples
553 --------
553 --------
554 ::
554 ::
555
555
556 In [1]: from math import pi
556 In [1]: from math import pi
557
557
558 In [2]: %precision 3
558 In [2]: %precision 3
559 Out[2]: u'%.3f'
559 Out[2]: u'%.3f'
560
560
561 In [3]: pi
561 In [3]: pi
562 Out[3]: 3.142
562 Out[3]: 3.142
563
563
564 In [4]: %precision %i
564 In [4]: %precision %i
565 Out[4]: u'%i'
565 Out[4]: u'%i'
566
566
567 In [5]: pi
567 In [5]: pi
568 Out[5]: 3
568 Out[5]: 3
569
569
570 In [6]: %precision %e
570 In [6]: %precision %e
571 Out[6]: u'%e'
571 Out[6]: u'%e'
572
572
573 In [7]: pi**10
573 In [7]: pi**10
574 Out[7]: 9.364805e+04
574 Out[7]: 9.364805e+04
575
575
576 In [8]: %precision
576 In [8]: %precision
577 Out[8]: u'%r'
577 Out[8]: u'%r'
578
578
579 In [9]: pi**10
579 In [9]: pi**10
580 Out[9]: 93648.047476082982
580 Out[9]: 93648.047476082982
581 """
581 """
582 ptformatter = self.shell.display_formatter.formatters['text/plain']
582 ptformatter = self.shell.display_formatter.formatters['text/plain']
583 ptformatter.float_precision = s
583 ptformatter.float_precision = s
584 return ptformatter.float_format
584 return ptformatter.float_format
585
585
586 @magic_arguments.magic_arguments()
586 @magic_arguments.magic_arguments()
587 @magic_arguments.argument(
587 @magic_arguments.argument(
588 '-e', '--export', action='store_true', default=False,
588 '-e', '--export', action='store_true', default=False,
589 help='Export IPython history as a notebook. The filename argument '
589 help='Export IPython history as a notebook. The filename argument '
590 'is used to specify the notebook name and format. For example '
590 'is used to specify the notebook name and format. For example '
591 'a filename of notebook.ipynb will result in a notebook name '
591 'a filename of notebook.ipynb will result in a notebook name '
592 'of "notebook" and a format of "json". Likewise using a ".py" '
592 'of "notebook" and a format of "json". Likewise using a ".py" '
593 'file extension will write the notebook as a Python script'
593 'file extension will write the notebook as a Python script'
594 )
594 )
595 @magic_arguments.argument(
595 @magic_arguments.argument(
596 '-f', '--format',
596 '-f', '--format',
597 help='Convert an existing IPython notebook to a new format. This option '
597 help='Convert an existing IPython notebook to a new format. This option '
598 'specifies the new format and can have the values: json, py. '
598 'specifies the new format and can have the values: json, py. '
599 'The target filename is chosen automatically based on the new '
599 'The target filename is chosen automatically based on the new '
600 'format. The filename argument gives the name of the source file.'
600 'format. The filename argument gives the name of the source file.'
601 )
601 )
602 @magic_arguments.argument(
602 @magic_arguments.argument(
603 'filename', type=unicode_type,
603 'filename', type=unicode_type,
604 help='Notebook name or filename'
604 help='Notebook name or filename'
605 )
605 )
606 @line_magic
606 @line_magic
607 def notebook(self, s):
607 def notebook(self, s):
608 """Export and convert IPython notebooks.
608 """Export and convert IPython notebooks.
609
609
610 This function can export the current IPython history to a notebook file
610 This function can export the current IPython history to a notebook file
611 or can convert an existing notebook file into a different format. For
611 or can convert an existing notebook file into a different format. For
612 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
612 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
613 To export the history to "foo.py" do "%notebook -e foo.py". To convert
613 To export the history to "foo.py" do "%notebook -e foo.py". To convert
614 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
614 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
615 formats include (json/ipynb, py).
615 formats include (json/ipynb, py).
616 """
616 """
617 args = magic_arguments.parse_argstring(self.notebook, s)
617 args = magic_arguments.parse_argstring(self.notebook, s)
618
618
619 from IPython.nbformat import current
619 from IPython.nbformat import current
620 args.filename = unquote_filename(args.filename)
620 args.filename = unquote_filename(args.filename)
621 if args.export:
621 if args.export:
622 fname, name, format = current.parse_filename(args.filename)
622 fname, name, format = current.parse_filename(args.filename)
623 cells = []
623 cells = []
624 hist = list(self.shell.history_manager.get_range())
624 hist = list(self.shell.history_manager.get_range())
625 for session, prompt_number, input in hist[:-1]:
625 for session, prompt_number, input in hist[:-1]:
626 cells.append(current.new_code_cell(prompt_number=prompt_number,
626 cells.append(current.new_code_cell(prompt_number=prompt_number,
627 input=input))
627 input=input))
628 worksheet = current.new_worksheet(cells=cells)
628 worksheet = current.new_worksheet(cells=cells)
629 nb = current.new_notebook(name=name,worksheets=[worksheet])
629 nb = current.new_notebook(name=name,worksheets=[worksheet])
630 with io.open(fname, 'w', encoding='utf-8') as f:
630 with io.open(fname, 'w', encoding='utf-8') as f:
631 current.write(nb, f, format);
631 current.write(nb, f, format);
632 elif args.format is not None:
632 elif args.format is not None:
633 old_fname, old_name, old_format = current.parse_filename(args.filename)
633 old_fname, old_name, old_format = current.parse_filename(args.filename)
634 new_format = args.format
634 new_format = args.format
635 if new_format == u'xml':
635 if new_format == u'xml':
636 raise ValueError('Notebooks cannot be written as xml.')
636 raise ValueError('Notebooks cannot be written as xml.')
637 elif new_format == u'ipynb' or new_format == u'json':
637 elif new_format == u'ipynb' or new_format == u'json':
638 new_fname = old_name + u'.ipynb'
638 new_fname = old_name + u'.ipynb'
639 new_format = u'json'
639 new_format = u'json'
640 elif new_format == u'py':
640 elif new_format == u'py':
641 new_fname = old_name + u'.py'
641 new_fname = old_name + u'.py'
642 else:
642 else:
643 raise ValueError('Invalid notebook format: %s' % new_format)
643 raise ValueError('Invalid notebook format: %s' % new_format)
644 with io.open(old_fname, 'r', encoding='utf-8') as f:
644 with io.open(old_fname, 'r', encoding='utf-8') as f:
645 nb = current.read(f, old_format)
645 nb = current.read(f, old_format)
646 with io.open(new_fname, 'w', encoding='utf-8') as f:
646 with io.open(new_fname, 'w', encoding='utf-8') as f:
647 current.write(nb, f, new_format)
647 current.write(nb, f, new_format)
@@ -1,873 +1,873 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 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 __all__ = ['Inspector','InspectColors']
18 __all__ = ['Inspector','InspectColors']
19
19
20 # stdlib modules
20 # stdlib modules
21 import inspect
21 import inspect
22 import linecache
22 import linecache
23 import os
23 import os
24 import types
24 import types
25 import io as stdlib_io
25 import io as stdlib_io
26
26
27 try:
27 try:
28 from itertools import izip_longest
28 from itertools import izip_longest
29 except ImportError:
29 except ImportError:
30 from itertools import zip_longest as izip_longest
30 from itertools import zip_longest as izip_longest
31
31
32 # IPython's own
32 # IPython's own
33 from IPython.core import page
33 from IPython.core import page
34 from IPython.testing.skipdoctest import skip_doctest_py3
34 from IPython.testing.skipdoctest import skip_doctest_py3
35 from IPython.utils import PyColorize
35 from IPython.utils import PyColorize
36 from IPython.utils import io
36 from IPython.utils import io
37 from IPython.utils import openpy
37 from IPython.utils import openpy
38 from IPython.utils import py3compat
38 from IPython.utils import py3compat
39 from IPython.utils.dir2 import safe_hasattr
39 from IPython.utils.dir2 import safe_hasattr
40 from IPython.utils.text import indent
40 from IPython.utils.text import indent
41 from IPython.utils.wildcard import list_namespace
41 from IPython.utils.wildcard import list_namespace
42 from IPython.utils.coloransi import *
42 from IPython.utils.coloransi import *
43 from IPython.utils.py3compat import cast_unicode, string_types
43 from IPython.utils.py3compat import cast_unicode, string_types
44
44
45 #****************************************************************************
45 #****************************************************************************
46 # Builtin color schemes
46 # Builtin color schemes
47
47
48 Colors = TermColors # just a shorthand
48 Colors = TermColors # just a shorthand
49
49
50 # Build a few color schemes
50 # Build a few color schemes
51 NoColor = ColorScheme(
51 NoColor = ColorScheme(
52 'NoColor',{
52 'NoColor',{
53 'header' : Colors.NoColor,
53 'header' : Colors.NoColor,
54 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
54 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
55 } )
55 } )
56
56
57 LinuxColors = ColorScheme(
57 LinuxColors = ColorScheme(
58 'Linux',{
58 'Linux',{
59 'header' : Colors.LightRed,
59 'header' : Colors.LightRed,
60 'normal' : Colors.Normal # color off (usu. Colors.Normal)
60 'normal' : Colors.Normal # color off (usu. Colors.Normal)
61 } )
61 } )
62
62
63 LightBGColors = ColorScheme(
63 LightBGColors = ColorScheme(
64 'LightBG',{
64 'LightBG',{
65 'header' : Colors.Red,
65 'header' : Colors.Red,
66 'normal' : Colors.Normal # color off (usu. Colors.Normal)
66 'normal' : Colors.Normal # color off (usu. Colors.Normal)
67 } )
67 } )
68
68
69 # Build table of color schemes (needed by the parser)
69 # Build table of color schemes (needed by the parser)
70 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
70 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
71 'Linux')
71 'Linux')
72
72
73 #****************************************************************************
73 #****************************************************************************
74 # Auxiliary functions and objects
74 # Auxiliary functions and objects
75
75
76 # See the messaging spec for the definition of all these fields. This list
76 # See the messaging spec for the definition of all these fields. This list
77 # effectively defines the order of display
77 # effectively defines the order of display
78 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
78 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
79 'length', 'file', 'definition', 'docstring', 'source',
79 'length', 'file', 'definition', 'docstring', 'source',
80 'init_definition', 'class_docstring', 'init_docstring',
80 'init_definition', 'class_docstring', 'init_docstring',
81 'call_def', 'call_docstring',
81 'call_def', 'call_docstring',
82 # These won't be printed but will be used to determine how to
82 # These won't be printed but will be used to determine how to
83 # format the object
83 # format the object
84 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
84 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
85 ]
85 ]
86
86
87
87
88 def object_info(**kw):
88 def object_info(**kw):
89 """Make an object info dict with all fields present."""
89 """Make an object info dict with all fields present."""
90 infodict = dict(izip_longest(info_fields, [None]))
90 infodict = dict(izip_longest(info_fields, [None]))
91 infodict.update(kw)
91 infodict.update(kw)
92 return infodict
92 return infodict
93
93
94
94
95 def get_encoding(obj):
95 def get_encoding(obj):
96 """Get encoding for python source file defining obj
96 """Get encoding for python source file defining obj
97
97
98 Returns None if obj is not defined in a sourcefile.
98 Returns None if obj is not defined in a sourcefile.
99 """
99 """
100 ofile = find_file(obj)
100 ofile = find_file(obj)
101 # run contents of file through pager starting at line where the object
101 # run contents of file through pager starting at line where the object
102 # is defined, as long as the file isn't binary and is actually on the
102 # is defined, as long as the file isn't binary and is actually on the
103 # filesystem.
103 # filesystem.
104 if ofile is None:
104 if ofile is None:
105 return None
105 return None
106 elif ofile.endswith(('.so', '.dll', '.pyd')):
106 elif ofile.endswith(('.so', '.dll', '.pyd')):
107 return None
107 return None
108 elif not os.path.isfile(ofile):
108 elif not os.path.isfile(ofile):
109 return None
109 return None
110 else:
110 else:
111 # Print only text files, not extension binaries. Note that
111 # Print only text files, not extension binaries. Note that
112 # getsourcelines returns lineno with 1-offset and page() uses
112 # getsourcelines returns lineno with 1-offset and page() uses
113 # 0-offset, so we must adjust.
113 # 0-offset, so we must adjust.
114 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
114 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
115 encoding, lines = openpy.detect_encoding(buffer.readline)
115 encoding, lines = openpy.detect_encoding(buffer.readline)
116 return encoding
116 return encoding
117
117
118 def getdoc(obj):
118 def getdoc(obj):
119 """Stable wrapper around inspect.getdoc.
119 """Stable wrapper around inspect.getdoc.
120
120
121 This can't crash because of attribute problems.
121 This can't crash because of attribute problems.
122
122
123 It also attempts to call a getdoc() method on the given object. This
123 It also attempts to call a getdoc() method on the given object. This
124 allows objects which provide their docstrings via non-standard mechanisms
124 allows objects which provide their docstrings via non-standard mechanisms
125 (like Pyro proxies) to still be inspected by ipython's ? system."""
125 (like Pyro proxies) to still be inspected by ipython's ? system."""
126 # Allow objects to offer customized documentation via a getdoc method:
126 # Allow objects to offer customized documentation via a getdoc method:
127 try:
127 try:
128 ds = obj.getdoc()
128 ds = obj.getdoc()
129 except Exception:
129 except Exception:
130 pass
130 pass
131 else:
131 else:
132 # if we get extra info, we add it to the normal docstring.
132 # if we get extra info, we add it to the normal docstring.
133 if isinstance(ds, string_types):
133 if isinstance(ds, string_types):
134 return inspect.cleandoc(ds)
134 return inspect.cleandoc(ds)
135
135
136 try:
136 try:
137 docstr = inspect.getdoc(obj)
137 docstr = inspect.getdoc(obj)
138 encoding = get_encoding(obj)
138 encoding = get_encoding(obj)
139 return py3compat.cast_unicode(docstr, encoding=encoding)
139 return py3compat.cast_unicode(docstr, encoding=encoding)
140 except Exception:
140 except Exception:
141 # Harden against an inspect failure, which can occur with
141 # Harden against an inspect failure, which can occur with
142 # SWIG-wrapped extensions.
142 # SWIG-wrapped extensions.
143 raise
143 raise
144 return None
144 return None
145
145
146
146
147 def getsource(obj,is_binary=False):
147 def getsource(obj,is_binary=False):
148 """Wrapper around inspect.getsource.
148 """Wrapper around inspect.getsource.
149
149
150 This can be modified by other projects to provide customized source
150 This can be modified by other projects to provide customized source
151 extraction.
151 extraction.
152
152
153 Inputs:
153 Inputs:
154
154
155 - obj: an object whose source code we will attempt to extract.
155 - obj: an object whose source code we will attempt to extract.
156
156
157 Optional inputs:
157 Optional inputs:
158
158
159 - is_binary: whether the object is known to come from a binary source.
159 - is_binary: whether the object is known to come from a binary source.
160 This implementation will skip returning any output for binary objects, but
160 This implementation will skip returning any output for binary objects, but
161 custom extractors may know how to meaningfully process them."""
161 custom extractors may know how to meaningfully process them."""
162
162
163 if is_binary:
163 if is_binary:
164 return None
164 return None
165 else:
165 else:
166 # get source if obj was decorated with @decorator
166 # get source if obj was decorated with @decorator
167 if hasattr(obj,"__wrapped__"):
167 if hasattr(obj,"__wrapped__"):
168 obj = obj.__wrapped__
168 obj = obj.__wrapped__
169 try:
169 try:
170 src = inspect.getsource(obj)
170 src = inspect.getsource(obj)
171 except TypeError:
171 except TypeError:
172 if hasattr(obj,'__class__'):
172 if hasattr(obj,'__class__'):
173 src = inspect.getsource(obj.__class__)
173 src = inspect.getsource(obj.__class__)
174 encoding = get_encoding(obj)
174 encoding = get_encoding(obj)
175 return cast_unicode(src, encoding=encoding)
175 return cast_unicode(src, encoding=encoding)
176
176
177 def getargspec(obj):
177 def getargspec(obj):
178 """Get the names and default values of a function's arguments.
178 """Get the names and default values of a function's arguments.
179
179
180 A tuple of four things is returned: (args, varargs, varkw, defaults).
180 A tuple of four things is returned: (args, varargs, varkw, defaults).
181 'args' is a list of the argument names (it may contain nested lists).
181 'args' is a list of the argument names (it may contain nested lists).
182 'varargs' and 'varkw' are the names of the * and ** arguments or None.
182 'varargs' and 'varkw' are the names of the * and ** arguments or None.
183 'defaults' is an n-tuple of the default values of the last n arguments.
183 'defaults' is an n-tuple of the default values of the last n arguments.
184
184
185 Modified version of inspect.getargspec from the Python Standard
185 Modified version of inspect.getargspec from the Python Standard
186 Library."""
186 Library."""
187
187
188 if inspect.isfunction(obj):
188 if inspect.isfunction(obj):
189 func_obj = obj
189 func_obj = obj
190 elif inspect.ismethod(obj):
190 elif inspect.ismethod(obj):
191 func_obj = obj.im_func
191 func_obj = obj.__func__
192 elif hasattr(obj, '__call__'):
192 elif hasattr(obj, '__call__'):
193 func_obj = obj.__call__
193 func_obj = obj.__call__
194 else:
194 else:
195 raise TypeError('arg is not a Python function')
195 raise TypeError('arg is not a Python function')
196 args, varargs, varkw = inspect.getargs(func_obj.__code__)
196 args, varargs, varkw = inspect.getargs(func_obj.__code__)
197 return args, varargs, varkw, func_obj.__defaults__
197 return args, varargs, varkw, func_obj.__defaults__
198
198
199
199
200 def format_argspec(argspec):
200 def format_argspec(argspec):
201 """Format argspect, convenience wrapper around inspect's.
201 """Format argspect, convenience wrapper around inspect's.
202
202
203 This takes a dict instead of ordered arguments and calls
203 This takes a dict instead of ordered arguments and calls
204 inspect.format_argspec with the arguments in the necessary order.
204 inspect.format_argspec with the arguments in the necessary order.
205 """
205 """
206 return inspect.formatargspec(argspec['args'], argspec['varargs'],
206 return inspect.formatargspec(argspec['args'], argspec['varargs'],
207 argspec['varkw'], argspec['defaults'])
207 argspec['varkw'], argspec['defaults'])
208
208
209
209
210 def call_tip(oinfo, format_call=True):
210 def call_tip(oinfo, format_call=True):
211 """Extract call tip data from an oinfo dict.
211 """Extract call tip data from an oinfo dict.
212
212
213 Parameters
213 Parameters
214 ----------
214 ----------
215 oinfo : dict
215 oinfo : dict
216
216
217 format_call : bool, optional
217 format_call : bool, optional
218 If True, the call line is formatted and returned as a string. If not, a
218 If True, the call line is formatted and returned as a string. If not, a
219 tuple of (name, argspec) is returned.
219 tuple of (name, argspec) is returned.
220
220
221 Returns
221 Returns
222 -------
222 -------
223 call_info : None, str or (str, dict) tuple.
223 call_info : None, str or (str, dict) tuple.
224 When format_call is True, the whole call information is formattted as a
224 When format_call is True, the whole call information is formattted as a
225 single string. Otherwise, the object's name and its argspec dict are
225 single string. Otherwise, the object's name and its argspec dict are
226 returned. If no call information is available, None is returned.
226 returned. If no call information is available, None is returned.
227
227
228 docstring : str or None
228 docstring : str or None
229 The most relevant docstring for calling purposes is returned, if
229 The most relevant docstring for calling purposes is returned, if
230 available. The priority is: call docstring for callable instances, then
230 available. The priority is: call docstring for callable instances, then
231 constructor docstring for classes, then main object's docstring otherwise
231 constructor docstring for classes, then main object's docstring otherwise
232 (regular functions).
232 (regular functions).
233 """
233 """
234 # Get call definition
234 # Get call definition
235 argspec = oinfo.get('argspec')
235 argspec = oinfo.get('argspec')
236 if argspec is None:
236 if argspec is None:
237 call_line = None
237 call_line = None
238 else:
238 else:
239 # Callable objects will have 'self' as their first argument, prune
239 # Callable objects will have 'self' as their first argument, prune
240 # it out if it's there for clarity (since users do *not* pass an
240 # it out if it's there for clarity (since users do *not* pass an
241 # extra first argument explicitly).
241 # extra first argument explicitly).
242 try:
242 try:
243 has_self = argspec['args'][0] == 'self'
243 has_self = argspec['args'][0] == 'self'
244 except (KeyError, IndexError):
244 except (KeyError, IndexError):
245 pass
245 pass
246 else:
246 else:
247 if has_self:
247 if has_self:
248 argspec['args'] = argspec['args'][1:]
248 argspec['args'] = argspec['args'][1:]
249
249
250 call_line = oinfo['name']+format_argspec(argspec)
250 call_line = oinfo['name']+format_argspec(argspec)
251
251
252 # Now get docstring.
252 # Now get docstring.
253 # The priority is: call docstring, constructor docstring, main one.
253 # The priority is: call docstring, constructor docstring, main one.
254 doc = oinfo.get('call_docstring')
254 doc = oinfo.get('call_docstring')
255 if doc is None:
255 if doc is None:
256 doc = oinfo.get('init_docstring')
256 doc = oinfo.get('init_docstring')
257 if doc is None:
257 if doc is None:
258 doc = oinfo.get('docstring','')
258 doc = oinfo.get('docstring','')
259
259
260 return call_line, doc
260 return call_line, doc
261
261
262
262
263 def find_file(obj):
263 def find_file(obj):
264 """Find the absolute path to the file where an object was defined.
264 """Find the absolute path to the file where an object was defined.
265
265
266 This is essentially a robust wrapper around `inspect.getabsfile`.
266 This is essentially a robust wrapper around `inspect.getabsfile`.
267
267
268 Returns None if no file can be found.
268 Returns None if no file can be found.
269
269
270 Parameters
270 Parameters
271 ----------
271 ----------
272 obj : any Python object
272 obj : any Python object
273
273
274 Returns
274 Returns
275 -------
275 -------
276 fname : str
276 fname : str
277 The absolute path to the file where the object was defined.
277 The absolute path to the file where the object was defined.
278 """
278 """
279 # get source if obj was decorated with @decorator
279 # get source if obj was decorated with @decorator
280 if safe_hasattr(obj, '__wrapped__'):
280 if safe_hasattr(obj, '__wrapped__'):
281 obj = obj.__wrapped__
281 obj = obj.__wrapped__
282
282
283 fname = None
283 fname = None
284 try:
284 try:
285 fname = inspect.getabsfile(obj)
285 fname = inspect.getabsfile(obj)
286 except TypeError:
286 except TypeError:
287 # For an instance, the file that matters is where its class was
287 # For an instance, the file that matters is where its class was
288 # declared.
288 # declared.
289 if hasattr(obj, '__class__'):
289 if hasattr(obj, '__class__'):
290 try:
290 try:
291 fname = inspect.getabsfile(obj.__class__)
291 fname = inspect.getabsfile(obj.__class__)
292 except TypeError:
292 except TypeError:
293 # Can happen for builtins
293 # Can happen for builtins
294 pass
294 pass
295 except:
295 except:
296 pass
296 pass
297 return cast_unicode(fname)
297 return cast_unicode(fname)
298
298
299
299
300 def find_source_lines(obj):
300 def find_source_lines(obj):
301 """Find the line number in a file where an object was defined.
301 """Find the line number in a file where an object was defined.
302
302
303 This is essentially a robust wrapper around `inspect.getsourcelines`.
303 This is essentially a robust wrapper around `inspect.getsourcelines`.
304
304
305 Returns None if no file can be found.
305 Returns None if no file can be found.
306
306
307 Parameters
307 Parameters
308 ----------
308 ----------
309 obj : any Python object
309 obj : any Python object
310
310
311 Returns
311 Returns
312 -------
312 -------
313 lineno : int
313 lineno : int
314 The line number where the object definition starts.
314 The line number where the object definition starts.
315 """
315 """
316 # get source if obj was decorated with @decorator
316 # get source if obj was decorated with @decorator
317 if safe_hasattr(obj, '__wrapped__'):
317 if safe_hasattr(obj, '__wrapped__'):
318 obj = obj.__wrapped__
318 obj = obj.__wrapped__
319
319
320 try:
320 try:
321 try:
321 try:
322 lineno = inspect.getsourcelines(obj)[1]
322 lineno = inspect.getsourcelines(obj)[1]
323 except TypeError:
323 except TypeError:
324 # For instances, try the class object like getsource() does
324 # For instances, try the class object like getsource() does
325 if hasattr(obj, '__class__'):
325 if hasattr(obj, '__class__'):
326 lineno = inspect.getsourcelines(obj.__class__)[1]
326 lineno = inspect.getsourcelines(obj.__class__)[1]
327 else:
327 else:
328 lineno = None
328 lineno = None
329 except:
329 except:
330 return None
330 return None
331
331
332 return lineno
332 return lineno
333
333
334
334
335 class Inspector:
335 class Inspector:
336 def __init__(self, color_table=InspectColors,
336 def __init__(self, color_table=InspectColors,
337 code_color_table=PyColorize.ANSICodeColors,
337 code_color_table=PyColorize.ANSICodeColors,
338 scheme='NoColor',
338 scheme='NoColor',
339 str_detail_level=0):
339 str_detail_level=0):
340 self.color_table = color_table
340 self.color_table = color_table
341 self.parser = PyColorize.Parser(code_color_table,out='str')
341 self.parser = PyColorize.Parser(code_color_table,out='str')
342 self.format = self.parser.format
342 self.format = self.parser.format
343 self.str_detail_level = str_detail_level
343 self.str_detail_level = str_detail_level
344 self.set_active_scheme(scheme)
344 self.set_active_scheme(scheme)
345
345
346 def _getdef(self,obj,oname=''):
346 def _getdef(self,obj,oname=''):
347 """Return the call signature for any callable object.
347 """Return the call signature for any callable object.
348
348
349 If any exception is generated, None is returned instead and the
349 If any exception is generated, None is returned instead and the
350 exception is suppressed."""
350 exception is suppressed."""
351
351
352 try:
352 try:
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
354 return cast_unicode(hdef)
354 return cast_unicode(hdef)
355 except:
355 except:
356 return None
356 return None
357
357
358 def __head(self,h):
358 def __head(self,h):
359 """Return a header string with proper colors."""
359 """Return a header string with proper colors."""
360 return '%s%s%s' % (self.color_table.active_colors.header,h,
360 return '%s%s%s' % (self.color_table.active_colors.header,h,
361 self.color_table.active_colors.normal)
361 self.color_table.active_colors.normal)
362
362
363 def set_active_scheme(self, scheme):
363 def set_active_scheme(self, scheme):
364 self.color_table.set_active_scheme(scheme)
364 self.color_table.set_active_scheme(scheme)
365 self.parser.color_table.set_active_scheme(scheme)
365 self.parser.color_table.set_active_scheme(scheme)
366
366
367 def noinfo(self, msg, oname):
367 def noinfo(self, msg, oname):
368 """Generic message when no information is found."""
368 """Generic message when no information is found."""
369 print('No %s found' % msg, end=' ')
369 print('No %s found' % msg, end=' ')
370 if oname:
370 if oname:
371 print('for %s' % oname)
371 print('for %s' % oname)
372 else:
372 else:
373 print()
373 print()
374
374
375 def pdef(self, obj, oname=''):
375 def pdef(self, obj, oname=''):
376 """Print the call signature for any callable object.
376 """Print the call signature for any callable object.
377
377
378 If the object is a class, print the constructor information."""
378 If the object is a class, print the constructor information."""
379
379
380 if not callable(obj):
380 if not callable(obj):
381 print('Object is not callable.')
381 print('Object is not callable.')
382 return
382 return
383
383
384 header = ''
384 header = ''
385
385
386 if inspect.isclass(obj):
386 if inspect.isclass(obj):
387 header = self.__head('Class constructor information:\n')
387 header = self.__head('Class constructor information:\n')
388 obj = obj.__init__
388 obj = obj.__init__
389 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
389 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
390 obj = obj.__call__
390 obj = obj.__call__
391
391
392 output = self._getdef(obj,oname)
392 output = self._getdef(obj,oname)
393 if output is None:
393 if output is None:
394 self.noinfo('definition header',oname)
394 self.noinfo('definition header',oname)
395 else:
395 else:
396 print(header,self.format(output), end=' ', file=io.stdout)
396 print(header,self.format(output), end=' ', file=io.stdout)
397
397
398 # In Python 3, all classes are new-style, so they all have __init__.
398 # In Python 3, all classes are new-style, so they all have __init__.
399 @skip_doctest_py3
399 @skip_doctest_py3
400 def pdoc(self,obj,oname='',formatter = None):
400 def pdoc(self,obj,oname='',formatter = None):
401 """Print the docstring for any object.
401 """Print the docstring for any object.
402
402
403 Optional:
403 Optional:
404 -formatter: a function to run the docstring through for specially
404 -formatter: a function to run the docstring through for specially
405 formatted docstrings.
405 formatted docstrings.
406
406
407 Examples
407 Examples
408 --------
408 --------
409
409
410 In [1]: class NoInit:
410 In [1]: class NoInit:
411 ...: pass
411 ...: pass
412
412
413 In [2]: class NoDoc:
413 In [2]: class NoDoc:
414 ...: def __init__(self):
414 ...: def __init__(self):
415 ...: pass
415 ...: pass
416
416
417 In [3]: %pdoc NoDoc
417 In [3]: %pdoc NoDoc
418 No documentation found for NoDoc
418 No documentation found for NoDoc
419
419
420 In [4]: %pdoc NoInit
420 In [4]: %pdoc NoInit
421 No documentation found for NoInit
421 No documentation found for NoInit
422
422
423 In [5]: obj = NoInit()
423 In [5]: obj = NoInit()
424
424
425 In [6]: %pdoc obj
425 In [6]: %pdoc obj
426 No documentation found for obj
426 No documentation found for obj
427
427
428 In [5]: obj2 = NoDoc()
428 In [5]: obj2 = NoDoc()
429
429
430 In [6]: %pdoc obj2
430 In [6]: %pdoc obj2
431 No documentation found for obj2
431 No documentation found for obj2
432 """
432 """
433
433
434 head = self.__head # For convenience
434 head = self.__head # For convenience
435 lines = []
435 lines = []
436 ds = getdoc(obj)
436 ds = getdoc(obj)
437 if formatter:
437 if formatter:
438 ds = formatter(ds)
438 ds = formatter(ds)
439 if ds:
439 if ds:
440 lines.append(head("Class Docstring:"))
440 lines.append(head("Class Docstring:"))
441 lines.append(indent(ds))
441 lines.append(indent(ds))
442 if inspect.isclass(obj) and hasattr(obj, '__init__'):
442 if inspect.isclass(obj) and hasattr(obj, '__init__'):
443 init_ds = getdoc(obj.__init__)
443 init_ds = getdoc(obj.__init__)
444 if init_ds is not None:
444 if init_ds is not None:
445 lines.append(head("Constructor Docstring:"))
445 lines.append(head("Constructor Docstring:"))
446 lines.append(indent(init_ds))
446 lines.append(indent(init_ds))
447 elif hasattr(obj,'__call__'):
447 elif hasattr(obj,'__call__'):
448 call_ds = getdoc(obj.__call__)
448 call_ds = getdoc(obj.__call__)
449 if call_ds:
449 if call_ds:
450 lines.append(head("Calling Docstring:"))
450 lines.append(head("Calling Docstring:"))
451 lines.append(indent(call_ds))
451 lines.append(indent(call_ds))
452
452
453 if not lines:
453 if not lines:
454 self.noinfo('documentation',oname)
454 self.noinfo('documentation',oname)
455 else:
455 else:
456 page.page('\n'.join(lines))
456 page.page('\n'.join(lines))
457
457
458 def psource(self,obj,oname=''):
458 def psource(self,obj,oname=''):
459 """Print the source code for an object."""
459 """Print the source code for an object."""
460
460
461 # Flush the source cache because inspect can return out-of-date source
461 # Flush the source cache because inspect can return out-of-date source
462 linecache.checkcache()
462 linecache.checkcache()
463 try:
463 try:
464 src = getsource(obj)
464 src = getsource(obj)
465 except:
465 except:
466 self.noinfo('source',oname)
466 self.noinfo('source',oname)
467 else:
467 else:
468 page.page(self.format(src))
468 page.page(self.format(src))
469
469
470 def pfile(self, obj, oname=''):
470 def pfile(self, obj, oname=''):
471 """Show the whole file where an object was defined."""
471 """Show the whole file where an object was defined."""
472
472
473 lineno = find_source_lines(obj)
473 lineno = find_source_lines(obj)
474 if lineno is None:
474 if lineno is None:
475 self.noinfo('file', oname)
475 self.noinfo('file', oname)
476 return
476 return
477
477
478 ofile = find_file(obj)
478 ofile = find_file(obj)
479 # run contents of file through pager starting at line where the object
479 # run contents of file through pager starting at line where the object
480 # is defined, as long as the file isn't binary and is actually on the
480 # is defined, as long as the file isn't binary and is actually on the
481 # filesystem.
481 # filesystem.
482 if ofile.endswith(('.so', '.dll', '.pyd')):
482 if ofile.endswith(('.so', '.dll', '.pyd')):
483 print('File %r is binary, not printing.' % ofile)
483 print('File %r is binary, not printing.' % ofile)
484 elif not os.path.isfile(ofile):
484 elif not os.path.isfile(ofile):
485 print('File %r does not exist, not printing.' % ofile)
485 print('File %r does not exist, not printing.' % ofile)
486 else:
486 else:
487 # Print only text files, not extension binaries. Note that
487 # Print only text files, not extension binaries. Note that
488 # getsourcelines returns lineno with 1-offset and page() uses
488 # getsourcelines returns lineno with 1-offset and page() uses
489 # 0-offset, so we must adjust.
489 # 0-offset, so we must adjust.
490 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
490 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
491
491
492 def _format_fields(self, fields, title_width=12):
492 def _format_fields(self, fields, title_width=12):
493 """Formats a list of fields for display.
493 """Formats a list of fields for display.
494
494
495 Parameters
495 Parameters
496 ----------
496 ----------
497 fields : list
497 fields : list
498 A list of 2-tuples: (field_title, field_content)
498 A list of 2-tuples: (field_title, field_content)
499 title_width : int
499 title_width : int
500 How many characters to pad titles to. Default 12.
500 How many characters to pad titles to. Default 12.
501 """
501 """
502 out = []
502 out = []
503 header = self.__head
503 header = self.__head
504 for title, content in fields:
504 for title, content in fields:
505 if len(content.splitlines()) > 1:
505 if len(content.splitlines()) > 1:
506 title = header(title + ":") + "\n"
506 title = header(title + ":") + "\n"
507 else:
507 else:
508 title = header((title+":").ljust(title_width))
508 title = header((title+":").ljust(title_width))
509 out.append(cast_unicode(title) + cast_unicode(content))
509 out.append(cast_unicode(title) + cast_unicode(content))
510 return "\n".join(out)
510 return "\n".join(out)
511
511
512 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
512 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
513 pinfo_fields1 = [("Type", "type_name"),
513 pinfo_fields1 = [("Type", "type_name"),
514 ]
514 ]
515
515
516 pinfo_fields2 = [("String Form", "string_form"),
516 pinfo_fields2 = [("String Form", "string_form"),
517 ]
517 ]
518
518
519 pinfo_fields3 = [("Length", "length"),
519 pinfo_fields3 = [("Length", "length"),
520 ("File", "file"),
520 ("File", "file"),
521 ("Definition", "definition"),
521 ("Definition", "definition"),
522 ]
522 ]
523
523
524 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
524 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
525 ("Constructor Docstring","init_docstring"),
525 ("Constructor Docstring","init_docstring"),
526 ("Call def", "call_def"),
526 ("Call def", "call_def"),
527 ("Call docstring", "call_docstring")]
527 ("Call docstring", "call_docstring")]
528
528
529 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
529 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
530 """Show detailed information about an object.
530 """Show detailed information about an object.
531
531
532 Optional arguments:
532 Optional arguments:
533
533
534 - oname: name of the variable pointing to the object.
534 - oname: name of the variable pointing to the object.
535
535
536 - formatter: special formatter for docstrings (see pdoc)
536 - formatter: special formatter for docstrings (see pdoc)
537
537
538 - info: a structure with some information fields which may have been
538 - info: a structure with some information fields which may have been
539 precomputed already.
539 precomputed already.
540
540
541 - detail_level: if set to 1, more information is given.
541 - detail_level: if set to 1, more information is given.
542 """
542 """
543 info = self.info(obj, oname=oname, formatter=formatter,
543 info = self.info(obj, oname=oname, formatter=formatter,
544 info=info, detail_level=detail_level)
544 info=info, detail_level=detail_level)
545 displayfields = []
545 displayfields = []
546 def add_fields(fields):
546 def add_fields(fields):
547 for title, key in fields:
547 for title, key in fields:
548 field = info[key]
548 field = info[key]
549 if field is not None:
549 if field is not None:
550 displayfields.append((title, field.rstrip()))
550 displayfields.append((title, field.rstrip()))
551
551
552 add_fields(self.pinfo_fields1)
552 add_fields(self.pinfo_fields1)
553
553
554 # Base class for old-style instances
554 # Base class for old-style instances
555 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
555 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
556 displayfields.append(("Base Class", info['base_class'].rstrip()))
556 displayfields.append(("Base Class", info['base_class'].rstrip()))
557
557
558 add_fields(self.pinfo_fields2)
558 add_fields(self.pinfo_fields2)
559
559
560 # Namespace
560 # Namespace
561 if info['namespace'] != 'Interactive':
561 if info['namespace'] != 'Interactive':
562 displayfields.append(("Namespace", info['namespace'].rstrip()))
562 displayfields.append(("Namespace", info['namespace'].rstrip()))
563
563
564 add_fields(self.pinfo_fields3)
564 add_fields(self.pinfo_fields3)
565
565
566 # Source or docstring, depending on detail level and whether
566 # Source or docstring, depending on detail level and whether
567 # source found.
567 # source found.
568 if detail_level > 0 and info['source'] is not None:
568 if detail_level > 0 and info['source'] is not None:
569 displayfields.append(("Source",
569 displayfields.append(("Source",
570 self.format(cast_unicode(info['source']))))
570 self.format(cast_unicode(info['source']))))
571 elif info['docstring'] is not None:
571 elif info['docstring'] is not None:
572 displayfields.append(("Docstring", info["docstring"]))
572 displayfields.append(("Docstring", info["docstring"]))
573
573
574 # Constructor info for classes
574 # Constructor info for classes
575 if info['isclass']:
575 if info['isclass']:
576 if info['init_definition'] or info['init_docstring']:
576 if info['init_definition'] or info['init_docstring']:
577 displayfields.append(("Constructor information", ""))
577 displayfields.append(("Constructor information", ""))
578 if info['init_definition'] is not None:
578 if info['init_definition'] is not None:
579 displayfields.append((" Definition",
579 displayfields.append((" Definition",
580 info['init_definition'].rstrip()))
580 info['init_definition'].rstrip()))
581 if info['init_docstring'] is not None:
581 if info['init_docstring'] is not None:
582 displayfields.append((" Docstring",
582 displayfields.append((" Docstring",
583 indent(info['init_docstring'])))
583 indent(info['init_docstring'])))
584
584
585 # Info for objects:
585 # Info for objects:
586 else:
586 else:
587 add_fields(self.pinfo_fields_obj)
587 add_fields(self.pinfo_fields_obj)
588
588
589 # Finally send to printer/pager:
589 # Finally send to printer/pager:
590 if displayfields:
590 if displayfields:
591 page.page(self._format_fields(displayfields))
591 page.page(self._format_fields(displayfields))
592
592
593 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
593 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
594 """Compute a dict with detailed information about an object.
594 """Compute a dict with detailed information about an object.
595
595
596 Optional arguments:
596 Optional arguments:
597
597
598 - oname: name of the variable pointing to the object.
598 - oname: name of the variable pointing to the object.
599
599
600 - formatter: special formatter for docstrings (see pdoc)
600 - formatter: special formatter for docstrings (see pdoc)
601
601
602 - info: a structure with some information fields which may have been
602 - info: a structure with some information fields which may have been
603 precomputed already.
603 precomputed already.
604
604
605 - detail_level: if set to 1, more information is given.
605 - detail_level: if set to 1, more information is given.
606 """
606 """
607
607
608 obj_type = type(obj)
608 obj_type = type(obj)
609
609
610 header = self.__head
610 header = self.__head
611 if info is None:
611 if info is None:
612 ismagic = 0
612 ismagic = 0
613 isalias = 0
613 isalias = 0
614 ospace = ''
614 ospace = ''
615 else:
615 else:
616 ismagic = info.ismagic
616 ismagic = info.ismagic
617 isalias = info.isalias
617 isalias = info.isalias
618 ospace = info.namespace
618 ospace = info.namespace
619
619
620 # Get docstring, special-casing aliases:
620 # Get docstring, special-casing aliases:
621 if isalias:
621 if isalias:
622 if not callable(obj):
622 if not callable(obj):
623 try:
623 try:
624 ds = "Alias to the system command:\n %s" % obj[1]
624 ds = "Alias to the system command:\n %s" % obj[1]
625 except:
625 except:
626 ds = "Alias: " + str(obj)
626 ds = "Alias: " + str(obj)
627 else:
627 else:
628 ds = "Alias to " + str(obj)
628 ds = "Alias to " + str(obj)
629 if obj.__doc__:
629 if obj.__doc__:
630 ds += "\nDocstring:\n" + obj.__doc__
630 ds += "\nDocstring:\n" + obj.__doc__
631 else:
631 else:
632 ds = getdoc(obj)
632 ds = getdoc(obj)
633 if ds is None:
633 if ds is None:
634 ds = '<no docstring>'
634 ds = '<no docstring>'
635 if formatter is not None:
635 if formatter is not None:
636 ds = formatter(ds)
636 ds = formatter(ds)
637
637
638 # store output in a dict, we initialize it here and fill it as we go
638 # store output in a dict, we initialize it here and fill it as we go
639 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
639 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
640
640
641 string_max = 200 # max size of strings to show (snipped if longer)
641 string_max = 200 # max size of strings to show (snipped if longer)
642 shalf = int((string_max -5)/2)
642 shalf = int((string_max -5)/2)
643
643
644 if ismagic:
644 if ismagic:
645 obj_type_name = 'Magic function'
645 obj_type_name = 'Magic function'
646 elif isalias:
646 elif isalias:
647 obj_type_name = 'System alias'
647 obj_type_name = 'System alias'
648 else:
648 else:
649 obj_type_name = obj_type.__name__
649 obj_type_name = obj_type.__name__
650 out['type_name'] = obj_type_name
650 out['type_name'] = obj_type_name
651
651
652 try:
652 try:
653 bclass = obj.__class__
653 bclass = obj.__class__
654 out['base_class'] = str(bclass)
654 out['base_class'] = str(bclass)
655 except: pass
655 except: pass
656
656
657 # String form, but snip if too long in ? form (full in ??)
657 # String form, but snip if too long in ? form (full in ??)
658 if detail_level >= self.str_detail_level:
658 if detail_level >= self.str_detail_level:
659 try:
659 try:
660 ostr = str(obj)
660 ostr = str(obj)
661 str_head = 'string_form'
661 str_head = 'string_form'
662 if not detail_level and len(ostr)>string_max:
662 if not detail_level and len(ostr)>string_max:
663 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
663 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
664 ostr = ("\n" + " " * len(str_head.expandtabs())).\
664 ostr = ("\n" + " " * len(str_head.expandtabs())).\
665 join(q.strip() for q in ostr.split("\n"))
665 join(q.strip() for q in ostr.split("\n"))
666 out[str_head] = ostr
666 out[str_head] = ostr
667 except:
667 except:
668 pass
668 pass
669
669
670 if ospace:
670 if ospace:
671 out['namespace'] = ospace
671 out['namespace'] = ospace
672
672
673 # Length (for strings and lists)
673 # Length (for strings and lists)
674 try:
674 try:
675 out['length'] = str(len(obj))
675 out['length'] = str(len(obj))
676 except: pass
676 except: pass
677
677
678 # Filename where object was defined
678 # Filename where object was defined
679 binary_file = False
679 binary_file = False
680 fname = find_file(obj)
680 fname = find_file(obj)
681 if fname is None:
681 if fname is None:
682 # if anything goes wrong, we don't want to show source, so it's as
682 # if anything goes wrong, we don't want to show source, so it's as
683 # if the file was binary
683 # if the file was binary
684 binary_file = True
684 binary_file = True
685 else:
685 else:
686 if fname.endswith(('.so', '.dll', '.pyd')):
686 if fname.endswith(('.so', '.dll', '.pyd')):
687 binary_file = True
687 binary_file = True
688 elif fname.endswith('<string>'):
688 elif fname.endswith('<string>'):
689 fname = 'Dynamically generated function. No source code available.'
689 fname = 'Dynamically generated function. No source code available.'
690 out['file'] = fname
690 out['file'] = fname
691
691
692 # reconstruct the function definition and print it:
692 # reconstruct the function definition and print it:
693 defln = self._getdef(obj, oname)
693 defln = self._getdef(obj, oname)
694 if defln:
694 if defln:
695 out['definition'] = self.format(defln)
695 out['definition'] = self.format(defln)
696
696
697 # Docstrings only in detail 0 mode, since source contains them (we
697 # Docstrings only in detail 0 mode, since source contains them (we
698 # avoid repetitions). If source fails, we add them back, see below.
698 # avoid repetitions). If source fails, we add them back, see below.
699 if ds and detail_level == 0:
699 if ds and detail_level == 0:
700 out['docstring'] = ds
700 out['docstring'] = ds
701
701
702 # Original source code for any callable
702 # Original source code for any callable
703 if detail_level:
703 if detail_level:
704 # Flush the source cache because inspect can return out-of-date
704 # Flush the source cache because inspect can return out-of-date
705 # source
705 # source
706 linecache.checkcache()
706 linecache.checkcache()
707 source = None
707 source = None
708 try:
708 try:
709 try:
709 try:
710 source = getsource(obj, binary_file)
710 source = getsource(obj, binary_file)
711 except TypeError:
711 except TypeError:
712 if hasattr(obj, '__class__'):
712 if hasattr(obj, '__class__'):
713 source = getsource(obj.__class__, binary_file)
713 source = getsource(obj.__class__, binary_file)
714 if source is not None:
714 if source is not None:
715 out['source'] = source.rstrip()
715 out['source'] = source.rstrip()
716 except Exception:
716 except Exception:
717 pass
717 pass
718
718
719 if ds and source is None:
719 if ds and source is None:
720 out['docstring'] = ds
720 out['docstring'] = ds
721
721
722
722
723 # Constructor docstring for classes
723 # Constructor docstring for classes
724 if inspect.isclass(obj):
724 if inspect.isclass(obj):
725 out['isclass'] = True
725 out['isclass'] = True
726 # reconstruct the function definition and print it:
726 # reconstruct the function definition and print it:
727 try:
727 try:
728 obj_init = obj.__init__
728 obj_init = obj.__init__
729 except AttributeError:
729 except AttributeError:
730 init_def = init_ds = None
730 init_def = init_ds = None
731 else:
731 else:
732 init_def = self._getdef(obj_init,oname)
732 init_def = self._getdef(obj_init,oname)
733 init_ds = getdoc(obj_init)
733 init_ds = getdoc(obj_init)
734 # Skip Python's auto-generated docstrings
734 # Skip Python's auto-generated docstrings
735 if init_ds and \
735 if init_ds and \
736 init_ds.startswith('x.__init__(...) initializes'):
736 init_ds.startswith('x.__init__(...) initializes'):
737 init_ds = None
737 init_ds = None
738
738
739 if init_def or init_ds:
739 if init_def or init_ds:
740 if init_def:
740 if init_def:
741 out['init_definition'] = self.format(init_def)
741 out['init_definition'] = self.format(init_def)
742 if init_ds:
742 if init_ds:
743 out['init_docstring'] = init_ds
743 out['init_docstring'] = init_ds
744
744
745 # and class docstring for instances:
745 # and class docstring for instances:
746 else:
746 else:
747 # First, check whether the instance docstring is identical to the
747 # First, check whether the instance docstring is identical to the
748 # class one, and print it separately if they don't coincide. In
748 # class one, and print it separately if they don't coincide. In
749 # most cases they will, but it's nice to print all the info for
749 # most cases they will, but it's nice to print all the info for
750 # objects which use instance-customized docstrings.
750 # objects which use instance-customized docstrings.
751 if ds:
751 if ds:
752 try:
752 try:
753 cls = getattr(obj,'__class__')
753 cls = getattr(obj,'__class__')
754 except:
754 except:
755 class_ds = None
755 class_ds = None
756 else:
756 else:
757 class_ds = getdoc(cls)
757 class_ds = getdoc(cls)
758 # Skip Python's auto-generated docstrings
758 # Skip Python's auto-generated docstrings
759 if class_ds and \
759 if class_ds and \
760 (class_ds.startswith('function(code, globals[,') or \
760 (class_ds.startswith('function(code, globals[,') or \
761 class_ds.startswith('instancemethod(function, instance,') or \
761 class_ds.startswith('instancemethod(function, instance,') or \
762 class_ds.startswith('module(name[,') ):
762 class_ds.startswith('module(name[,') ):
763 class_ds = None
763 class_ds = None
764 if class_ds and ds != class_ds:
764 if class_ds and ds != class_ds:
765 out['class_docstring'] = class_ds
765 out['class_docstring'] = class_ds
766
766
767 # Next, try to show constructor docstrings
767 # Next, try to show constructor docstrings
768 try:
768 try:
769 init_ds = getdoc(obj.__init__)
769 init_ds = getdoc(obj.__init__)
770 # Skip Python's auto-generated docstrings
770 # Skip Python's auto-generated docstrings
771 if init_ds and \
771 if init_ds and \
772 init_ds.startswith('x.__init__(...) initializes'):
772 init_ds.startswith('x.__init__(...) initializes'):
773 init_ds = None
773 init_ds = None
774 except AttributeError:
774 except AttributeError:
775 init_ds = None
775 init_ds = None
776 if init_ds:
776 if init_ds:
777 out['init_docstring'] = init_ds
777 out['init_docstring'] = init_ds
778
778
779 # Call form docstring for callable instances
779 # Call form docstring for callable instances
780 if safe_hasattr(obj, '__call__'):
780 if safe_hasattr(obj, '__call__'):
781 call_def = self._getdef(obj.__call__, oname)
781 call_def = self._getdef(obj.__call__, oname)
782 if call_def is not None:
782 if call_def is not None:
783 out['call_def'] = self.format(call_def)
783 out['call_def'] = self.format(call_def)
784 call_ds = getdoc(obj.__call__)
784 call_ds = getdoc(obj.__call__)
785 # Skip Python's auto-generated docstrings
785 # Skip Python's auto-generated docstrings
786 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
786 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
787 call_ds = None
787 call_ds = None
788 if call_ds:
788 if call_ds:
789 out['call_docstring'] = call_ds
789 out['call_docstring'] = call_ds
790
790
791 # Compute the object's argspec as a callable. The key is to decide
791 # Compute the object's argspec as a callable. The key is to decide
792 # whether to pull it from the object itself, from its __init__ or
792 # whether to pull it from the object itself, from its __init__ or
793 # from its __call__ method.
793 # from its __call__ method.
794
794
795 if inspect.isclass(obj):
795 if inspect.isclass(obj):
796 # Old-style classes need not have an __init__
796 # Old-style classes need not have an __init__
797 callable_obj = getattr(obj, "__init__", None)
797 callable_obj = getattr(obj, "__init__", None)
798 elif callable(obj):
798 elif callable(obj):
799 callable_obj = obj
799 callable_obj = obj
800 else:
800 else:
801 callable_obj = None
801 callable_obj = None
802
802
803 if callable_obj:
803 if callable_obj:
804 try:
804 try:
805 args, varargs, varkw, defaults = getargspec(callable_obj)
805 args, varargs, varkw, defaults = getargspec(callable_obj)
806 except (TypeError, AttributeError):
806 except (TypeError, AttributeError):
807 # For extensions/builtins we can't retrieve the argspec
807 # For extensions/builtins we can't retrieve the argspec
808 pass
808 pass
809 else:
809 else:
810 out['argspec'] = dict(args=args, varargs=varargs,
810 out['argspec'] = dict(args=args, varargs=varargs,
811 varkw=varkw, defaults=defaults)
811 varkw=varkw, defaults=defaults)
812
812
813 return object_info(**out)
813 return object_info(**out)
814
814
815
815
816 def psearch(self,pattern,ns_table,ns_search=[],
816 def psearch(self,pattern,ns_table,ns_search=[],
817 ignore_case=False,show_all=False):
817 ignore_case=False,show_all=False):
818 """Search namespaces with wildcards for objects.
818 """Search namespaces with wildcards for objects.
819
819
820 Arguments:
820 Arguments:
821
821
822 - pattern: string containing shell-like wildcards to use in namespace
822 - pattern: string containing shell-like wildcards to use in namespace
823 searches and optionally a type specification to narrow the search to
823 searches and optionally a type specification to narrow the search to
824 objects of that type.
824 objects of that type.
825
825
826 - ns_table: dict of name->namespaces for search.
826 - ns_table: dict of name->namespaces for search.
827
827
828 Optional arguments:
828 Optional arguments:
829
829
830 - ns_search: list of namespace names to include in search.
830 - ns_search: list of namespace names to include in search.
831
831
832 - ignore_case(False): make the search case-insensitive.
832 - ignore_case(False): make the search case-insensitive.
833
833
834 - show_all(False): show all names, including those starting with
834 - show_all(False): show all names, including those starting with
835 underscores.
835 underscores.
836 """
836 """
837 #print 'ps pattern:<%r>' % pattern # dbg
837 #print 'ps pattern:<%r>' % pattern # dbg
838
838
839 # defaults
839 # defaults
840 type_pattern = 'all'
840 type_pattern = 'all'
841 filter = ''
841 filter = ''
842
842
843 cmds = pattern.split()
843 cmds = pattern.split()
844 len_cmds = len(cmds)
844 len_cmds = len(cmds)
845 if len_cmds == 1:
845 if len_cmds == 1:
846 # Only filter pattern given
846 # Only filter pattern given
847 filter = cmds[0]
847 filter = cmds[0]
848 elif len_cmds == 2:
848 elif len_cmds == 2:
849 # Both filter and type specified
849 # Both filter and type specified
850 filter,type_pattern = cmds
850 filter,type_pattern = cmds
851 else:
851 else:
852 raise ValueError('invalid argument string for psearch: <%s>' %
852 raise ValueError('invalid argument string for psearch: <%s>' %
853 pattern)
853 pattern)
854
854
855 # filter search namespaces
855 # filter search namespaces
856 for name in ns_search:
856 for name in ns_search:
857 if name not in ns_table:
857 if name not in ns_table:
858 raise ValueError('invalid namespace <%s>. Valid names: %s' %
858 raise ValueError('invalid namespace <%s>. Valid names: %s' %
859 (name,ns_table.keys()))
859 (name,ns_table.keys()))
860
860
861 #print 'type_pattern:',type_pattern # dbg
861 #print 'type_pattern:',type_pattern # dbg
862 search_result, namespaces_seen = set(), set()
862 search_result, namespaces_seen = set(), set()
863 for ns_name in ns_search:
863 for ns_name in ns_search:
864 ns = ns_table[ns_name]
864 ns = ns_table[ns_name]
865 # Normally, locals and globals are the same, so we just check one.
865 # Normally, locals and globals are the same, so we just check one.
866 if id(ns) in namespaces_seen:
866 if id(ns) in namespaces_seen:
867 continue
867 continue
868 namespaces_seen.add(id(ns))
868 namespaces_seen.add(id(ns))
869 tmp_res = list_namespace(ns, type_pattern, filter,
869 tmp_res = list_namespace(ns, type_pattern, filter,
870 ignore_case=ignore_case, show_all=show_all)
870 ignore_case=ignore_case, show_all=show_all)
871 search_result.update(tmp_res)
871 search_result.update(tmp_res)
872
872
873 page.page('\n'.join(sorted(search_result)))
873 page.page('\n'.join(sorted(search_result)))
@@ -1,944 +1,944 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from unittest import TestCase
15 from unittest import TestCase
16
16
17 try:
17 try:
18 from importlib import invalidate_caches # Required from Python 3.3
18 from importlib import invalidate_caches # Required from Python 3.3
19 except ImportError:
19 except ImportError:
20 def invalidate_caches():
20 def invalidate_caches():
21 pass
21 pass
22
22
23 import nose.tools as nt
23 import nose.tools as nt
24
24
25 from IPython.core import magic
25 from IPython.core import magic
26 from IPython.core.magic import (Magics, magics_class, line_magic,
26 from IPython.core.magic import (Magics, magics_class, line_magic,
27 cell_magic, line_cell_magic,
27 cell_magic, line_cell_magic,
28 register_line_magic, register_cell_magic,
28 register_line_magic, register_cell_magic,
29 register_line_cell_magic)
29 register_line_cell_magic)
30 from IPython.core.magics import execution, script, code
30 from IPython.core.magics import execution, script, code
31 from IPython.nbformat.v3.tests.nbexamples import nb0
31 from IPython.nbformat.v3.tests.nbexamples import nb0
32 from IPython.nbformat import current
32 from IPython.nbformat import current
33 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
34 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
35 from IPython.utils import py3compat
35 from IPython.utils import py3compat
36 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
37 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
38 from IPython.utils.process import find_cmd
38 from IPython.utils.process import find_cmd
39
39
40 if py3compat.PY3:
40 if py3compat.PY3:
41 from io import StringIO
41 from io import StringIO
42 else:
42 else:
43 from StringIO import StringIO
43 from StringIO import StringIO
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Test functions begin
46 # Test functions begin
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 @magic.magics_class
49 @magic.magics_class
50 class DummyMagics(magic.Magics): pass
50 class DummyMagics(magic.Magics): pass
51
51
52 def test_extract_code_ranges():
52 def test_extract_code_ranges():
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
54 expected = [(0, 1),
54 expected = [(0, 1),
55 (2, 3),
55 (2, 3),
56 (4, 6),
56 (4, 6),
57 (6, 9),
57 (6, 9),
58 (9, 14),
58 (9, 14),
59 (16, None),
59 (16, None),
60 (None, 9),
60 (None, 9),
61 (9, None),
61 (9, None),
62 (None, 13),
62 (None, 13),
63 (None, None)]
63 (None, None)]
64 actual = list(code.extract_code_ranges(instr))
64 actual = list(code.extract_code_ranges(instr))
65 nt.assert_equal(actual, expected)
65 nt.assert_equal(actual, expected)
66
66
67 def test_extract_symbols():
67 def test_extract_symbols():
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
70 expected = [([], ['a']),
70 expected = [([], ['a']),
71 (["def b():\n return 42\n"], []),
71 (["def b():\n return 42\n"], []),
72 (["class A: pass\n"], []),
72 (["class A: pass\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
74 (["class A: pass\n"], ['a']),
74 (["class A: pass\n"], ['a']),
75 ([], ['z'])]
75 ([], ['z'])]
76 for symbols, exp in zip(symbols_args, expected):
76 for symbols, exp in zip(symbols_args, expected):
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
78
78
79
79
80 def test_extract_symbols_raises_exception_with_non_python_code():
80 def test_extract_symbols_raises_exception_with_non_python_code():
81 source = ("=begin A Ruby program :)=end\n"
81 source = ("=begin A Ruby program :)=end\n"
82 "def hello\n"
82 "def hello\n"
83 "puts 'Hello world'\n"
83 "puts 'Hello world'\n"
84 "end")
84 "end")
85 with nt.assert_raises(SyntaxError):
85 with nt.assert_raises(SyntaxError):
86 code.extract_symbols(source, "hello")
86 code.extract_symbols(source, "hello")
87
87
88 def test_config():
88 def test_config():
89 """ test that config magic does not raise
89 """ test that config magic does not raise
90 can happen if Configurable init is moved too early into
90 can happen if Configurable init is moved too early into
91 Magics.__init__ as then a Config object will be registerd as a
91 Magics.__init__ as then a Config object will be registerd as a
92 magic.
92 magic.
93 """
93 """
94 ## should not raise.
94 ## should not raise.
95 _ip.magic('config')
95 _ip.magic('config')
96
96
97 def test_rehashx():
97 def test_rehashx():
98 # clear up everything
98 # clear up everything
99 _ip = get_ipython()
99 _ip = get_ipython()
100 _ip.alias_manager.clear_aliases()
100 _ip.alias_manager.clear_aliases()
101 del _ip.db['syscmdlist']
101 del _ip.db['syscmdlist']
102
102
103 _ip.magic('rehashx')
103 _ip.magic('rehashx')
104 # Practically ALL ipython development systems will have more than 10 aliases
104 # Practically ALL ipython development systems will have more than 10 aliases
105
105
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
107 for name, cmd in _ip.alias_manager.aliases:
107 for name, cmd in _ip.alias_manager.aliases:
108 # we must strip dots from alias names
108 # we must strip dots from alias names
109 nt.assert_not_in('.', name)
109 nt.assert_not_in('.', name)
110
110
111 # rehashx must fill up syscmdlist
111 # rehashx must fill up syscmdlist
112 scoms = _ip.db['syscmdlist']
112 scoms = _ip.db['syscmdlist']
113 nt.assert_true(len(scoms) > 10)
113 nt.assert_true(len(scoms) > 10)
114
114
115
115
116 def test_magic_parse_options():
116 def test_magic_parse_options():
117 """Test that we don't mangle paths when parsing magic options."""
117 """Test that we don't mangle paths when parsing magic options."""
118 ip = get_ipython()
118 ip = get_ipython()
119 path = 'c:\\x'
119 path = 'c:\\x'
120 m = DummyMagics(ip)
120 m = DummyMagics(ip)
121 opts = m.parse_options('-f %s' % path,'f:')[0]
121 opts = m.parse_options('-f %s' % path,'f:')[0]
122 # argv splitting is os-dependent
122 # argv splitting is os-dependent
123 if os.name == 'posix':
123 if os.name == 'posix':
124 expected = 'c:x'
124 expected = 'c:x'
125 else:
125 else:
126 expected = path
126 expected = path
127 nt.assert_equal(opts['f'], expected)
127 nt.assert_equal(opts['f'], expected)
128
128
129 def test_magic_parse_long_options():
129 def test_magic_parse_long_options():
130 """Magic.parse_options can handle --foo=bar long options"""
130 """Magic.parse_options can handle --foo=bar long options"""
131 ip = get_ipython()
131 ip = get_ipython()
132 m = DummyMagics(ip)
132 m = DummyMagics(ip)
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
134 nt.assert_in('foo', opts)
134 nt.assert_in('foo', opts)
135 nt.assert_in('bar', opts)
135 nt.assert_in('bar', opts)
136 nt.assert_equal(opts['bar'], "bubble")
136 nt.assert_equal(opts['bar'], "bubble")
137
137
138
138
139 @dec.skip_without('sqlite3')
139 @dec.skip_without('sqlite3')
140 def doctest_hist_f():
140 def doctest_hist_f():
141 """Test %hist -f with temporary filename.
141 """Test %hist -f with temporary filename.
142
142
143 In [9]: import tempfile
143 In [9]: import tempfile
144
144
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
146
146
147 In [11]: %hist -nl -f $tfile 3
147 In [11]: %hist -nl -f $tfile 3
148
148
149 In [13]: import os; os.unlink(tfile)
149 In [13]: import os; os.unlink(tfile)
150 """
150 """
151
151
152
152
153 @dec.skip_without('sqlite3')
153 @dec.skip_without('sqlite3')
154 def doctest_hist_r():
154 def doctest_hist_r():
155 """Test %hist -r
155 """Test %hist -r
156
156
157 XXX - This test is not recording the output correctly. For some reason, in
157 XXX - This test is not recording the output correctly. For some reason, in
158 testing mode the raw history isn't getting populated. No idea why.
158 testing mode the raw history isn't getting populated. No idea why.
159 Disabling the output checking for now, though at least we do run it.
159 Disabling the output checking for now, though at least we do run it.
160
160
161 In [1]: 'hist' in _ip.lsmagic()
161 In [1]: 'hist' in _ip.lsmagic()
162 Out[1]: True
162 Out[1]: True
163
163
164 In [2]: x=1
164 In [2]: x=1
165
165
166 In [3]: %hist -rl 2
166 In [3]: %hist -rl 2
167 x=1 # random
167 x=1 # random
168 %hist -r 2
168 %hist -r 2
169 """
169 """
170
170
171
171
172 @dec.skip_without('sqlite3')
172 @dec.skip_without('sqlite3')
173 def doctest_hist_op():
173 def doctest_hist_op():
174 """Test %hist -op
174 """Test %hist -op
175
175
176 In [1]: class b(float):
176 In [1]: class b(float):
177 ...: pass
177 ...: pass
178 ...:
178 ...:
179
179
180 In [2]: class s(object):
180 In [2]: class s(object):
181 ...: def __str__(self):
181 ...: def __str__(self):
182 ...: return 's'
182 ...: return 's'
183 ...:
183 ...:
184
184
185 In [3]:
185 In [3]:
186
186
187 In [4]: class r(b):
187 In [4]: class r(b):
188 ...: def __repr__(self):
188 ...: def __repr__(self):
189 ...: return 'r'
189 ...: return 'r'
190 ...:
190 ...:
191
191
192 In [5]: class sr(s,r): pass
192 In [5]: class sr(s,r): pass
193 ...:
193 ...:
194
194
195 In [6]:
195 In [6]:
196
196
197 In [7]: bb=b()
197 In [7]: bb=b()
198
198
199 In [8]: ss=s()
199 In [8]: ss=s()
200
200
201 In [9]: rr=r()
201 In [9]: rr=r()
202
202
203 In [10]: ssrr=sr()
203 In [10]: ssrr=sr()
204
204
205 In [11]: 4.5
205 In [11]: 4.5
206 Out[11]: 4.5
206 Out[11]: 4.5
207
207
208 In [12]: str(ss)
208 In [12]: str(ss)
209 Out[12]: 's'
209 Out[12]: 's'
210
210
211 In [13]:
211 In [13]:
212
212
213 In [14]: %hist -op
213 In [14]: %hist -op
214 >>> class b:
214 >>> class b:
215 ... pass
215 ... pass
216 ...
216 ...
217 >>> class s(b):
217 >>> class s(b):
218 ... def __str__(self):
218 ... def __str__(self):
219 ... return 's'
219 ... return 's'
220 ...
220 ...
221 >>>
221 >>>
222 >>> class r(b):
222 >>> class r(b):
223 ... def __repr__(self):
223 ... def __repr__(self):
224 ... return 'r'
224 ... return 'r'
225 ...
225 ...
226 >>> class sr(s,r): pass
226 >>> class sr(s,r): pass
227 >>>
227 >>>
228 >>> bb=b()
228 >>> bb=b()
229 >>> ss=s()
229 >>> ss=s()
230 >>> rr=r()
230 >>> rr=r()
231 >>> ssrr=sr()
231 >>> ssrr=sr()
232 >>> 4.5
232 >>> 4.5
233 4.5
233 4.5
234 >>> str(ss)
234 >>> str(ss)
235 's'
235 's'
236 >>>
236 >>>
237 """
237 """
238
238
239
239
240 @dec.skip_without('sqlite3')
240 @dec.skip_without('sqlite3')
241 def test_macro():
241 def test_macro():
242 ip = get_ipython()
242 ip = get_ipython()
243 ip.history_manager.reset() # Clear any existing history.
243 ip.history_manager.reset() # Clear any existing history.
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
245 for i, cmd in enumerate(cmds, start=1):
245 for i, cmd in enumerate(cmds, start=1):
246 ip.history_manager.store_inputs(i, cmd)
246 ip.history_manager.store_inputs(i, cmd)
247 ip.magic("macro test 1-3")
247 ip.magic("macro test 1-3")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
249
249
250 # List macros
250 # List macros
251 nt.assert_in("test", ip.magic("macro"))
251 nt.assert_in("test", ip.magic("macro"))
252
252
253
253
254 @dec.skip_without('sqlite3')
254 @dec.skip_without('sqlite3')
255 def test_macro_run():
255 def test_macro_run():
256 """Test that we can run a multi-line macro successfully."""
256 """Test that we can run a multi-line macro successfully."""
257 ip = get_ipython()
257 ip = get_ipython()
258 ip.history_manager.reset()
258 ip.history_manager.reset()
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
260 "%macro test 2-3"]
260 "%macro test 2-3"]
261 for cmd in cmds:
261 for cmd in cmds:
262 ip.run_cell(cmd, store_history=True)
262 ip.run_cell(cmd, store_history=True)
263 nt.assert_equal(ip.user_ns["test"].value,
263 nt.assert_equal(ip.user_ns["test"].value,
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
265 with tt.AssertPrints("12"):
265 with tt.AssertPrints("12"):
266 ip.run_cell("test")
266 ip.run_cell("test")
267 with tt.AssertPrints("13"):
267 with tt.AssertPrints("13"):
268 ip.run_cell("test")
268 ip.run_cell("test")
269
269
270
270
271 def test_magic_magic():
271 def test_magic_magic():
272 """Test %magic"""
272 """Test %magic"""
273 ip = get_ipython()
273 ip = get_ipython()
274 with capture_output() as captured:
274 with capture_output() as captured:
275 ip.magic("magic")
275 ip.magic("magic")
276
276
277 stdout = captured.stdout
277 stdout = captured.stdout
278 nt.assert_in('%magic', stdout)
278 nt.assert_in('%magic', stdout)
279 nt.assert_in('IPython', stdout)
279 nt.assert_in('IPython', stdout)
280 nt.assert_in('Available', stdout)
280 nt.assert_in('Available', stdout)
281
281
282
282
283 @dec.skipif_not_numpy
283 @dec.skipif_not_numpy
284 def test_numpy_reset_array_undec():
284 def test_numpy_reset_array_undec():
285 "Test '%reset array' functionality"
285 "Test '%reset array' functionality"
286 _ip.ex('import numpy as np')
286 _ip.ex('import numpy as np')
287 _ip.ex('a = np.empty(2)')
287 _ip.ex('a = np.empty(2)')
288 nt.assert_in('a', _ip.user_ns)
288 nt.assert_in('a', _ip.user_ns)
289 _ip.magic('reset -f array')
289 _ip.magic('reset -f array')
290 nt.assert_not_in('a', _ip.user_ns)
290 nt.assert_not_in('a', _ip.user_ns)
291
291
292 def test_reset_out():
292 def test_reset_out():
293 "Test '%reset out' magic"
293 "Test '%reset out' magic"
294 _ip.run_cell("parrot = 'dead'", store_history=True)
294 _ip.run_cell("parrot = 'dead'", store_history=True)
295 # test '%reset -f out', make an Out prompt
295 # test '%reset -f out', make an Out prompt
296 _ip.run_cell("parrot", store_history=True)
296 _ip.run_cell("parrot", store_history=True)
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
298 _ip.magic('reset -f out')
298 _ip.magic('reset -f out')
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
301
301
302 def test_reset_in():
302 def test_reset_in():
303 "Test '%reset in' magic"
303 "Test '%reset in' magic"
304 # test '%reset -f in'
304 # test '%reset -f in'
305 _ip.run_cell("parrot", store_history=True)
305 _ip.run_cell("parrot", store_history=True)
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
307 _ip.magic('%reset -f in')
307 _ip.magic('%reset -f in')
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
310
310
311 def test_reset_dhist():
311 def test_reset_dhist():
312 "Test '%reset dhist' magic"
312 "Test '%reset dhist' magic"
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
315 _ip.magic('cd -')
315 _ip.magic('cd -')
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
317 _ip.magic('reset -f dhist')
317 _ip.magic('reset -f dhist')
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
320
320
321 def test_reset_in_length():
321 def test_reset_in_length():
322 "Test that '%reset in' preserves In[] length"
322 "Test that '%reset in' preserves In[] length"
323 _ip.run_cell("print 'foo'")
323 _ip.run_cell("print 'foo'")
324 _ip.run_cell("reset -f in")
324 _ip.run_cell("reset -f in")
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
326
326
327 def test_tb_syntaxerror():
327 def test_tb_syntaxerror():
328 """test %tb after a SyntaxError"""
328 """test %tb after a SyntaxError"""
329 ip = get_ipython()
329 ip = get_ipython()
330 ip.run_cell("for")
330 ip.run_cell("for")
331
331
332 # trap and validate stdout
332 # trap and validate stdout
333 save_stdout = sys.stdout
333 save_stdout = sys.stdout
334 try:
334 try:
335 sys.stdout = StringIO()
335 sys.stdout = StringIO()
336 ip.run_cell("%tb")
336 ip.run_cell("%tb")
337 out = sys.stdout.getvalue()
337 out = sys.stdout.getvalue()
338 finally:
338 finally:
339 sys.stdout = save_stdout
339 sys.stdout = save_stdout
340 # trim output, and only check the last line
340 # trim output, and only check the last line
341 last_line = out.rstrip().splitlines()[-1].strip()
341 last_line = out.rstrip().splitlines()[-1].strip()
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
343
343
344
344
345 def test_time():
345 def test_time():
346 ip = get_ipython()
346 ip = get_ipython()
347
347
348 with tt.AssertPrints("Wall time: "):
348 with tt.AssertPrints("Wall time: "):
349 ip.run_cell("%time None")
349 ip.run_cell("%time None")
350
350
351 ip.run_cell("def f(kmjy):\n"
351 ip.run_cell("def f(kmjy):\n"
352 " %time print (2*kmjy)")
352 " %time print (2*kmjy)")
353
353
354 with tt.AssertPrints("Wall time: "):
354 with tt.AssertPrints("Wall time: "):
355 with tt.AssertPrints("hihi", suppress=False):
355 with tt.AssertPrints("hihi", suppress=False):
356 ip.run_cell("f('hi')")
356 ip.run_cell("f('hi')")
357
357
358
358
359 @dec.skip_win32
359 @dec.skip_win32
360 def test_time2():
360 def test_time2():
361 ip = get_ipython()
361 ip = get_ipython()
362
362
363 with tt.AssertPrints("CPU times: user "):
363 with tt.AssertPrints("CPU times: user "):
364 ip.run_cell("%time None")
364 ip.run_cell("%time None")
365
365
366 def test_time3():
366 def test_time3():
367 """Erroneous magic function calls, issue gh-3334"""
367 """Erroneous magic function calls, issue gh-3334"""
368 ip = get_ipython()
368 ip = get_ipython()
369 ip.user_ns.pop('run', None)
369 ip.user_ns.pop('run', None)
370
370
371 with tt.AssertNotPrints("not found", channel='stderr'):
371 with tt.AssertNotPrints("not found", channel='stderr'):
372 ip.run_cell("%%time\n"
372 ip.run_cell("%%time\n"
373 "run = 0\n"
373 "run = 0\n"
374 "run += 1")
374 "run += 1")
375
375
376 def test_doctest_mode():
376 def test_doctest_mode():
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
378 _ip.magic('doctest_mode')
378 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
380
380
381
381
382 def test_parse_options():
382 def test_parse_options():
383 """Tests for basic options parsing in magics."""
383 """Tests for basic options parsing in magics."""
384 # These are only the most minimal of tests, more should be added later. At
384 # These are only the most minimal of tests, more should be added later. At
385 # the very least we check that basic text/unicode calls work OK.
385 # the very least we check that basic text/unicode calls work OK.
386 m = DummyMagics(_ip)
386 m = DummyMagics(_ip)
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
389
389
390
390
391 def test_dirops():
391 def test_dirops():
392 """Test various directory handling operations."""
392 """Test various directory handling operations."""
393 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
393 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
394 curpath = os.getcwdu
394 curpath = os.getcwdu
395 startdir = os.getcwdu()
395 startdir = os.getcwdu()
396 ipdir = os.path.realpath(_ip.ipython_dir)
396 ipdir = os.path.realpath(_ip.ipython_dir)
397 try:
397 try:
398 _ip.magic('cd "%s"' % ipdir)
398 _ip.magic('cd "%s"' % ipdir)
399 nt.assert_equal(curpath(), ipdir)
399 nt.assert_equal(curpath(), ipdir)
400 _ip.magic('cd -')
400 _ip.magic('cd -')
401 nt.assert_equal(curpath(), startdir)
401 nt.assert_equal(curpath(), startdir)
402 _ip.magic('pushd "%s"' % ipdir)
402 _ip.magic('pushd "%s"' % ipdir)
403 nt.assert_equal(curpath(), ipdir)
403 nt.assert_equal(curpath(), ipdir)
404 _ip.magic('popd')
404 _ip.magic('popd')
405 nt.assert_equal(curpath(), startdir)
405 nt.assert_equal(curpath(), startdir)
406 finally:
406 finally:
407 os.chdir(startdir)
407 os.chdir(startdir)
408
408
409
409
410 def test_xmode():
410 def test_xmode():
411 # Calling xmode three times should be a no-op
411 # Calling xmode three times should be a no-op
412 xmode = _ip.InteractiveTB.mode
412 xmode = _ip.InteractiveTB.mode
413 for i in range(3):
413 for i in range(3):
414 _ip.magic("xmode")
414 _ip.magic("xmode")
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
416
416
417 def test_reset_hard():
417 def test_reset_hard():
418 monitor = []
418 monitor = []
419 class A(object):
419 class A(object):
420 def __del__(self):
420 def __del__(self):
421 monitor.append(1)
421 monitor.append(1)
422 def __repr__(self):
422 def __repr__(self):
423 return "<A instance>"
423 return "<A instance>"
424
424
425 _ip.user_ns["a"] = A()
425 _ip.user_ns["a"] = A()
426 _ip.run_cell("a")
426 _ip.run_cell("a")
427
427
428 nt.assert_equal(monitor, [])
428 nt.assert_equal(monitor, [])
429 _ip.magic("reset -f")
429 _ip.magic("reset -f")
430 nt.assert_equal(monitor, [1])
430 nt.assert_equal(monitor, [1])
431
431
432 class TestXdel(tt.TempFileMixin):
432 class TestXdel(tt.TempFileMixin):
433 def test_xdel(self):
433 def test_xdel(self):
434 """Test that references from %run are cleared by xdel."""
434 """Test that references from %run are cleared by xdel."""
435 src = ("class A(object):\n"
435 src = ("class A(object):\n"
436 " monitor = []\n"
436 " monitor = []\n"
437 " def __del__(self):\n"
437 " def __del__(self):\n"
438 " self.monitor.append(1)\n"
438 " self.monitor.append(1)\n"
439 "a = A()\n")
439 "a = A()\n")
440 self.mktmp(src)
440 self.mktmp(src)
441 # %run creates some hidden references...
441 # %run creates some hidden references...
442 _ip.magic("run %s" % self.fname)
442 _ip.magic("run %s" % self.fname)
443 # ... as does the displayhook.
443 # ... as does the displayhook.
444 _ip.run_cell("a")
444 _ip.run_cell("a")
445
445
446 monitor = _ip.user_ns["A"].monitor
446 monitor = _ip.user_ns["A"].monitor
447 nt.assert_equal(monitor, [])
447 nt.assert_equal(monitor, [])
448
448
449 _ip.magic("xdel a")
449 _ip.magic("xdel a")
450
450
451 # Check that a's __del__ method has been called.
451 # Check that a's __del__ method has been called.
452 nt.assert_equal(monitor, [1])
452 nt.assert_equal(monitor, [1])
453
453
454 def doctest_who():
454 def doctest_who():
455 """doctest for %who
455 """doctest for %who
456
456
457 In [1]: %reset -f
457 In [1]: %reset -f
458
458
459 In [2]: alpha = 123
459 In [2]: alpha = 123
460
460
461 In [3]: beta = 'beta'
461 In [3]: beta = 'beta'
462
462
463 In [4]: %who int
463 In [4]: %who int
464 alpha
464 alpha
465
465
466 In [5]: %who str
466 In [5]: %who str
467 beta
467 beta
468
468
469 In [6]: %whos
469 In [6]: %whos
470 Variable Type Data/Info
470 Variable Type Data/Info
471 ----------------------------
471 ----------------------------
472 alpha int 123
472 alpha int 123
473 beta str beta
473 beta str beta
474
474
475 In [7]: %who_ls
475 In [7]: %who_ls
476 Out[7]: ['alpha', 'beta']
476 Out[7]: ['alpha', 'beta']
477 """
477 """
478
478
479 def test_whos():
479 def test_whos():
480 """Check that whos is protected against objects where repr() fails."""
480 """Check that whos is protected against objects where repr() fails."""
481 class A(object):
481 class A(object):
482 def __repr__(self):
482 def __repr__(self):
483 raise Exception()
483 raise Exception()
484 _ip.user_ns['a'] = A()
484 _ip.user_ns['a'] = A()
485 _ip.magic("whos")
485 _ip.magic("whos")
486
486
487 @py3compat.u_format
487 @py3compat.u_format
488 def doctest_precision():
488 def doctest_precision():
489 """doctest for %precision
489 """doctest for %precision
490
490
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
492
492
493 In [2]: %precision 5
493 In [2]: %precision 5
494 Out[2]: {u}'%.5f'
494 Out[2]: {u}'%.5f'
495
495
496 In [3]: f.float_format
496 In [3]: f.float_format
497 Out[3]: {u}'%.5f'
497 Out[3]: {u}'%.5f'
498
498
499 In [4]: %precision %e
499 In [4]: %precision %e
500 Out[4]: {u}'%e'
500 Out[4]: {u}'%e'
501
501
502 In [5]: f(3.1415927)
502 In [5]: f(3.1415927)
503 Out[5]: {u}'3.141593e+00'
503 Out[5]: {u}'3.141593e+00'
504 """
504 """
505
505
506 def test_psearch():
506 def test_psearch():
507 with tt.AssertPrints("dict.fromkeys"):
507 with tt.AssertPrints("dict.fromkeys"):
508 _ip.run_cell("dict.fr*?")
508 _ip.run_cell("dict.fr*?")
509
509
510 def test_timeit_shlex():
510 def test_timeit_shlex():
511 """test shlex issues with timeit (#1109)"""
511 """test shlex issues with timeit (#1109)"""
512 _ip.ex("def f(*a,**kw): pass")
512 _ip.ex("def f(*a,**kw): pass")
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
519
519
520
520
521 def test_timeit_arguments():
521 def test_timeit_arguments():
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
523 _ip.magic("timeit ('#')")
523 _ip.magic("timeit ('#')")
524
524
525
525
526 def test_timeit_special_syntax():
526 def test_timeit_special_syntax():
527 "Test %%timeit with IPython special syntax"
527 "Test %%timeit with IPython special syntax"
528 @register_line_magic
528 @register_line_magic
529 def lmagic(line):
529 def lmagic(line):
530 ip = get_ipython()
530 ip = get_ipython()
531 ip.user_ns['lmagic_out'] = line
531 ip.user_ns['lmagic_out'] = line
532
532
533 # line mode test
533 # line mode test
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
536 # cell mode test
536 # cell mode test
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
539
539
540 def test_timeit_return():
540 def test_timeit_return():
541 """
541 """
542 test wether timeit -o return object
542 test wether timeit -o return object
543 """
543 """
544
544
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
546 assert(res is not None)
546 assert(res is not None)
547
547
548 def test_timeit_quiet():
548 def test_timeit_quiet():
549 """
549 """
550 test quiet option of timeit magic
550 test quiet option of timeit magic
551 """
551 """
552 with tt.AssertNotPrints("loops"):
552 with tt.AssertNotPrints("loops"):
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
554
554
555 @dec.skipif(execution.profile is None)
555 @dec.skipif(execution.profile is None)
556 def test_prun_special_syntax():
556 def test_prun_special_syntax():
557 "Test %%prun with IPython special syntax"
557 "Test %%prun with IPython special syntax"
558 @register_line_magic
558 @register_line_magic
559 def lmagic(line):
559 def lmagic(line):
560 ip = get_ipython()
560 ip = get_ipython()
561 ip.user_ns['lmagic_out'] = line
561 ip.user_ns['lmagic_out'] = line
562
562
563 # line mode test
563 # line mode test
564 _ip.run_line_magic('prun', '-q %lmagic my line')
564 _ip.run_line_magic('prun', '-q %lmagic my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
566 # cell mode test
566 # cell mode test
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
569
569
570 @dec.skipif(execution.profile is None)
570 @dec.skipif(execution.profile is None)
571 def test_prun_quotes():
571 def test_prun_quotes():
572 "Test that prun does not clobber string escapes (GH #1302)"
572 "Test that prun does not clobber string escapes (GH #1302)"
573 _ip.magic(r"prun -q x = '\t'")
573 _ip.magic(r"prun -q x = '\t'")
574 nt.assert_equal(_ip.user_ns['x'], '\t')
574 nt.assert_equal(_ip.user_ns['x'], '\t')
575
575
576 def test_extension():
576 def test_extension():
577 tmpdir = TemporaryDirectory()
577 tmpdir = TemporaryDirectory()
578 orig_ipython_dir = _ip.ipython_dir
578 orig_ipython_dir = _ip.ipython_dir
579 try:
579 try:
580 _ip.ipython_dir = tmpdir.name
580 _ip.ipython_dir = tmpdir.name
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
583 _ip.magic("install_ext %s" % url)
583 _ip.magic("install_ext %s" % url)
584 _ip.user_ns.pop('arq', None)
584 _ip.user_ns.pop('arq', None)
585 invalidate_caches() # Clear import caches
585 invalidate_caches() # Clear import caches
586 _ip.magic("load_ext daft_extension")
586 _ip.magic("load_ext daft_extension")
587 nt.assert_equal(_ip.user_ns['arq'], 185)
587 nt.assert_equal(_ip.user_ns['arq'], 185)
588 _ip.magic("unload_ext daft_extension")
588 _ip.magic("unload_ext daft_extension")
589 assert 'arq' not in _ip.user_ns
589 assert 'arq' not in _ip.user_ns
590 finally:
590 finally:
591 _ip.ipython_dir = orig_ipython_dir
591 _ip.ipython_dir = orig_ipython_dir
592 tmpdir.cleanup()
592 tmpdir.cleanup()
593
593
594 def test_notebook_export_json():
594 def test_notebook_export_json():
595 with TemporaryDirectory() as td:
595 with TemporaryDirectory() as td:
596 outfile = os.path.join(td, "nb.ipynb")
596 outfile = os.path.join(td, "nb.ipynb")
597 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
597 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
598 _ip.magic("notebook -e %s" % outfile)
598 _ip.magic("notebook -e %s" % outfile)
599
599
600 def test_notebook_export_py():
600 def test_notebook_export_py():
601 with TemporaryDirectory() as td:
601 with TemporaryDirectory() as td:
602 outfile = os.path.join(td, "nb.py")
602 outfile = os.path.join(td, "nb.py")
603 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
603 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
604 _ip.magic("notebook -e %s" % outfile)
604 _ip.magic("notebook -e %s" % outfile)
605
605
606 def test_notebook_reformat_py():
606 def test_notebook_reformat_py():
607 with TemporaryDirectory() as td:
607 with TemporaryDirectory() as td:
608 infile = os.path.join(td, "nb.ipynb")
608 infile = os.path.join(td, "nb.ipynb")
609 with io.open(infile, 'w', encoding='utf-8') as f:
609 with io.open(infile, 'w', encoding='utf-8') as f:
610 current.write(nb0, f, 'json')
610 current.write(nb0, f, 'json')
611
611
612 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
612 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
613 _ip.magic("notebook -f py %s" % infile)
613 _ip.magic("notebook -f py %s" % infile)
614
614
615 def test_notebook_reformat_json():
615 def test_notebook_reformat_json():
616 with TemporaryDirectory() as td:
616 with TemporaryDirectory() as td:
617 infile = os.path.join(td, "nb.py")
617 infile = os.path.join(td, "nb.py")
618 with io.open(infile, 'w', encoding='utf-8') as f:
618 with io.open(infile, 'w', encoding='utf-8') as f:
619 current.write(nb0, f, 'py')
619 current.write(nb0, f, 'py')
620
620
621 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
621 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
622 _ip.magic("notebook -f ipynb %s" % infile)
622 _ip.magic("notebook -f ipynb %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
624
624
625 def test_env():
625 def test_env():
626 env = _ip.magic("env")
626 env = _ip.magic("env")
627 assert isinstance(env, dict), type(env)
627 assert isinstance(env, dict), type(env)
628
628
629
629
630 class CellMagicTestCase(TestCase):
630 class CellMagicTestCase(TestCase):
631
631
632 def check_ident(self, magic):
632 def check_ident(self, magic):
633 # Manually called, we get the result
633 # Manually called, we get the result
634 out = _ip.run_cell_magic(magic, 'a', 'b')
634 out = _ip.run_cell_magic(magic, 'a', 'b')
635 nt.assert_equal(out, ('a','b'))
635 nt.assert_equal(out, ('a','b'))
636 # Via run_cell, it goes into the user's namespace via displayhook
636 # Via run_cell, it goes into the user's namespace via displayhook
637 _ip.run_cell('%%' + magic +' c\nd')
637 _ip.run_cell('%%' + magic +' c\nd')
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
639
639
640 def test_cell_magic_func_deco(self):
640 def test_cell_magic_func_deco(self):
641 "Cell magic using simple decorator"
641 "Cell magic using simple decorator"
642 @register_cell_magic
642 @register_cell_magic
643 def cellm(line, cell):
643 def cellm(line, cell):
644 return line, cell
644 return line, cell
645
645
646 self.check_ident('cellm')
646 self.check_ident('cellm')
647
647
648 def test_cell_magic_reg(self):
648 def test_cell_magic_reg(self):
649 "Cell magic manually registered"
649 "Cell magic manually registered"
650 def cellm(line, cell):
650 def cellm(line, cell):
651 return line, cell
651 return line, cell
652
652
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
654 self.check_ident('cellm2')
654 self.check_ident('cellm2')
655
655
656 def test_cell_magic_class(self):
656 def test_cell_magic_class(self):
657 "Cell magics declared via a class"
657 "Cell magics declared via a class"
658 @magics_class
658 @magics_class
659 class MyMagics(Magics):
659 class MyMagics(Magics):
660
660
661 @cell_magic
661 @cell_magic
662 def cellm3(self, line, cell):
662 def cellm3(self, line, cell):
663 return line, cell
663 return line, cell
664
664
665 _ip.register_magics(MyMagics)
665 _ip.register_magics(MyMagics)
666 self.check_ident('cellm3')
666 self.check_ident('cellm3')
667
667
668 def test_cell_magic_class2(self):
668 def test_cell_magic_class2(self):
669 "Cell magics declared via a class, #2"
669 "Cell magics declared via a class, #2"
670 @magics_class
670 @magics_class
671 class MyMagics2(Magics):
671 class MyMagics2(Magics):
672
672
673 @cell_magic('cellm4')
673 @cell_magic('cellm4')
674 def cellm33(self, line, cell):
674 def cellm33(self, line, cell):
675 return line, cell
675 return line, cell
676
676
677 _ip.register_magics(MyMagics2)
677 _ip.register_magics(MyMagics2)
678 self.check_ident('cellm4')
678 self.check_ident('cellm4')
679 # Check that nothing is registered as 'cellm33'
679 # Check that nothing is registered as 'cellm33'
680 c33 = _ip.find_cell_magic('cellm33')
680 c33 = _ip.find_cell_magic('cellm33')
681 nt.assert_equal(c33, None)
681 nt.assert_equal(c33, None)
682
682
683 def test_file():
683 def test_file():
684 """Basic %%file"""
684 """Basic %%file"""
685 ip = get_ipython()
685 ip = get_ipython()
686 with TemporaryDirectory() as td:
686 with TemporaryDirectory() as td:
687 fname = os.path.join(td, 'file1')
687 fname = os.path.join(td, 'file1')
688 ip.run_cell_magic("file", fname, u'\n'.join([
688 ip.run_cell_magic("file", fname, u'\n'.join([
689 'line1',
689 'line1',
690 'line2',
690 'line2',
691 ]))
691 ]))
692 with open(fname) as f:
692 with open(fname) as f:
693 s = f.read()
693 s = f.read()
694 nt.assert_in('line1\n', s)
694 nt.assert_in('line1\n', s)
695 nt.assert_in('line2', s)
695 nt.assert_in('line2', s)
696
696
697 def test_file_var_expand():
697 def test_file_var_expand():
698 """%%file $filename"""
698 """%%file $filename"""
699 ip = get_ipython()
699 ip = get_ipython()
700 with TemporaryDirectory() as td:
700 with TemporaryDirectory() as td:
701 fname = os.path.join(td, 'file1')
701 fname = os.path.join(td, 'file1')
702 ip.user_ns['filename'] = fname
702 ip.user_ns['filename'] = fname
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
704 'line1',
704 'line1',
705 'line2',
705 'line2',
706 ]))
706 ]))
707 with open(fname) as f:
707 with open(fname) as f:
708 s = f.read()
708 s = f.read()
709 nt.assert_in('line1\n', s)
709 nt.assert_in('line1\n', s)
710 nt.assert_in('line2', s)
710 nt.assert_in('line2', s)
711
711
712 def test_file_unicode():
712 def test_file_unicode():
713 """%%file with unicode cell"""
713 """%%file with unicode cell"""
714 ip = get_ipython()
714 ip = get_ipython()
715 with TemporaryDirectory() as td:
715 with TemporaryDirectory() as td:
716 fname = os.path.join(td, 'file1')
716 fname = os.path.join(td, 'file1')
717 ip.run_cell_magic("file", fname, u'\n'.join([
717 ip.run_cell_magic("file", fname, u'\n'.join([
718 u'linΓ©1',
718 u'linΓ©1',
719 u'linΓ©2',
719 u'linΓ©2',
720 ]))
720 ]))
721 with io.open(fname, encoding='utf-8') as f:
721 with io.open(fname, encoding='utf-8') as f:
722 s = f.read()
722 s = f.read()
723 nt.assert_in(u'linΓ©1\n', s)
723 nt.assert_in(u'linΓ©1\n', s)
724 nt.assert_in(u'linΓ©2', s)
724 nt.assert_in(u'linΓ©2', s)
725
725
726 def test_file_amend():
726 def test_file_amend():
727 """%%file -a amends files"""
727 """%%file -a amends files"""
728 ip = get_ipython()
728 ip = get_ipython()
729 with TemporaryDirectory() as td:
729 with TemporaryDirectory() as td:
730 fname = os.path.join(td, 'file2')
730 fname = os.path.join(td, 'file2')
731 ip.run_cell_magic("file", fname, u'\n'.join([
731 ip.run_cell_magic("file", fname, u'\n'.join([
732 'line1',
732 'line1',
733 'line2',
733 'line2',
734 ]))
734 ]))
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
736 'line3',
736 'line3',
737 'line4',
737 'line4',
738 ]))
738 ]))
739 with open(fname) as f:
739 with open(fname) as f:
740 s = f.read()
740 s = f.read()
741 nt.assert_in('line1\n', s)
741 nt.assert_in('line1\n', s)
742 nt.assert_in('line3\n', s)
742 nt.assert_in('line3\n', s)
743
743
744
744
745 def test_script_config():
745 def test_script_config():
746 ip = get_ipython()
746 ip = get_ipython()
747 ip.config.ScriptMagics.script_magics = ['whoda']
747 ip.config.ScriptMagics.script_magics = ['whoda']
748 sm = script.ScriptMagics(shell=ip)
748 sm = script.ScriptMagics(shell=ip)
749 nt.assert_in('whoda', sm.magics['cell'])
749 nt.assert_in('whoda', sm.magics['cell'])
750
750
751 @dec.skip_win32
751 @dec.skip_win32
752 def test_script_out():
752 def test_script_out():
753 ip = get_ipython()
753 ip = get_ipython()
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
756
756
757 @dec.skip_win32
757 @dec.skip_win32
758 def test_script_err():
758 def test_script_err():
759 ip = get_ipython()
759 ip = get_ipython()
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
762
762
763 @dec.skip_win32
763 @dec.skip_win32
764 def test_script_out_err():
764 def test_script_out_err():
765 ip = get_ipython()
765 ip = get_ipython()
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
769
769
770 @dec.skip_win32
770 @dec.skip_win32
771 def test_script_bg_out():
771 def test_script_bg_out():
772 ip = get_ipython()
772 ip = get_ipython()
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
775
775
776 @dec.skip_win32
776 @dec.skip_win32
777 def test_script_bg_err():
777 def test_script_bg_err():
778 ip = get_ipython()
778 ip = get_ipython()
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
781
781
782 @dec.skip_win32
782 @dec.skip_win32
783 def test_script_bg_out_err():
783 def test_script_bg_out_err():
784 ip = get_ipython()
784 ip = get_ipython()
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
788
788
789 def test_script_defaults():
789 def test_script_defaults():
790 ip = get_ipython()
790 ip = get_ipython()
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
792 try:
792 try:
793 find_cmd(cmd)
793 find_cmd(cmd)
794 except Exception:
794 except Exception:
795 pass
795 pass
796 else:
796 else:
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
798
798
799
799
800 @magics_class
800 @magics_class
801 class FooFoo(Magics):
801 class FooFoo(Magics):
802 """class with both %foo and %%foo magics"""
802 """class with both %foo and %%foo magics"""
803 @line_magic('foo')
803 @line_magic('foo')
804 def line_foo(self, line):
804 def line_foo(self, line):
805 "I am line foo"
805 "I am line foo"
806 pass
806 pass
807
807
808 @cell_magic("foo")
808 @cell_magic("foo")
809 def cell_foo(self, line, cell):
809 def cell_foo(self, line, cell):
810 "I am cell foo, not line foo"
810 "I am cell foo, not line foo"
811 pass
811 pass
812
812
813 def test_line_cell_info():
813 def test_line_cell_info():
814 """%%foo and %foo magics are distinguishable to inspect"""
814 """%%foo and %foo magics are distinguishable to inspect"""
815 ip = get_ipython()
815 ip = get_ipython()
816 ip.magics_manager.register(FooFoo)
816 ip.magics_manager.register(FooFoo)
817 oinfo = ip.object_inspect('foo')
817 oinfo = ip.object_inspect('foo')
818 nt.assert_true(oinfo['found'])
818 nt.assert_true(oinfo['found'])
819 nt.assert_true(oinfo['ismagic'])
819 nt.assert_true(oinfo['ismagic'])
820
820
821 oinfo = ip.object_inspect('%%foo')
821 oinfo = ip.object_inspect('%%foo')
822 nt.assert_true(oinfo['found'])
822 nt.assert_true(oinfo['found'])
823 nt.assert_true(oinfo['ismagic'])
823 nt.assert_true(oinfo['ismagic'])
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
825
825
826 oinfo = ip.object_inspect('%foo')
826 oinfo = ip.object_inspect('%foo')
827 nt.assert_true(oinfo['found'])
827 nt.assert_true(oinfo['found'])
828 nt.assert_true(oinfo['ismagic'])
828 nt.assert_true(oinfo['ismagic'])
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
830
830
831 def test_multiple_magics():
831 def test_multiple_magics():
832 ip = get_ipython()
832 ip = get_ipython()
833 foo1 = FooFoo(ip)
833 foo1 = FooFoo(ip)
834 foo2 = FooFoo(ip)
834 foo2 = FooFoo(ip)
835 mm = ip.magics_manager
835 mm = ip.magics_manager
836 mm.register(foo1)
836 mm.register(foo1)
837 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
837 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
838 mm.register(foo2)
838 mm.register(foo2)
839 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
839 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
840
840
841 def test_alias_magic():
841 def test_alias_magic():
842 """Test %alias_magic."""
842 """Test %alias_magic."""
843 ip = get_ipython()
843 ip = get_ipython()
844 mm = ip.magics_manager
844 mm = ip.magics_manager
845
845
846 # Basic operation: both cell and line magics are created, if possible.
846 # Basic operation: both cell and line magics are created, if possible.
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
848 nt.assert_in('timeit_alias', mm.magics['line'])
848 nt.assert_in('timeit_alias', mm.magics['line'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
850
850
851 # --cell is specified, line magic not created.
851 # --cell is specified, line magic not created.
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
855
855
856 # Test that line alias is created successfully.
856 # Test that line alias is created successfully.
857 ip.run_line_magic('alias_magic', '--line env_alias env')
857 ip.run_line_magic('alias_magic', '--line env_alias env')
858 nt.assert_equal(ip.run_line_magic('env', ''),
858 nt.assert_equal(ip.run_line_magic('env', ''),
859 ip.run_line_magic('env_alias', ''))
859 ip.run_line_magic('env_alias', ''))
860
860
861 def test_save():
861 def test_save():
862 """Test %save."""
862 """Test %save."""
863 ip = get_ipython()
863 ip = get_ipython()
864 ip.history_manager.reset() # Clear any existing history.
864 ip.history_manager.reset() # Clear any existing history.
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
866 for i, cmd in enumerate(cmds, start=1):
866 for i, cmd in enumerate(cmds, start=1):
867 ip.history_manager.store_inputs(i, cmd)
867 ip.history_manager.store_inputs(i, cmd)
868 with TemporaryDirectory() as tmpdir:
868 with TemporaryDirectory() as tmpdir:
869 file = os.path.join(tmpdir, "testsave.py")
869 file = os.path.join(tmpdir, "testsave.py")
870 ip.run_line_magic("save", "%s 1-10" % file)
870 ip.run_line_magic("save", "%s 1-10" % file)
871 with open(file) as f:
871 with open(file) as f:
872 content = f.read()
872 content = f.read()
873 nt.assert_equal(content.count(cmds[0]), 1)
873 nt.assert_equal(content.count(cmds[0]), 1)
874 nt.assert_in('coding: utf-8', content)
874 nt.assert_in('coding: utf-8', content)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
876 with open(file) as f:
876 with open(file) as f:
877 content = f.read()
877 content = f.read()
878 nt.assert_equal(content.count(cmds[0]), 2)
878 nt.assert_equal(content.count(cmds[0]), 2)
879 nt.assert_in('coding: utf-8', content)
879 nt.assert_in('coding: utf-8', content)
880
880
881
881
882 def test_store():
882 def test_store():
883 """Test %store."""
883 """Test %store."""
884 ip = get_ipython()
884 ip = get_ipython()
885 ip.run_line_magic('load_ext', 'storemagic')
885 ip.run_line_magic('load_ext', 'storemagic')
886
886
887 # make sure the storage is empty
887 # make sure the storage is empty
888 ip.run_line_magic('store', '-z')
888 ip.run_line_magic('store', '-z')
889 ip.user_ns['var'] = 42
889 ip.user_ns['var'] = 42
890 ip.run_line_magic('store', 'var')
890 ip.run_line_magic('store', 'var')
891 ip.user_ns['var'] = 39
891 ip.user_ns['var'] = 39
892 ip.run_line_magic('store', '-r')
892 ip.run_line_magic('store', '-r')
893 nt.assert_equal(ip.user_ns['var'], 42)
893 nt.assert_equal(ip.user_ns['var'], 42)
894
894
895 ip.run_line_magic('store', '-d var')
895 ip.run_line_magic('store', '-d var')
896 ip.user_ns['var'] = 39
896 ip.user_ns['var'] = 39
897 ip.run_line_magic('store' , '-r')
897 ip.run_line_magic('store' , '-r')
898 nt.assert_equal(ip.user_ns['var'], 39)
898 nt.assert_equal(ip.user_ns['var'], 39)
899
899
900
900
901 def _run_edit_test(arg_s, exp_filename=None,
901 def _run_edit_test(arg_s, exp_filename=None,
902 exp_lineno=-1,
902 exp_lineno=-1,
903 exp_contents=None,
903 exp_contents=None,
904 exp_is_temp=None):
904 exp_is_temp=None):
905 ip = get_ipython()
905 ip = get_ipython()
906 M = code.CodeMagics(ip)
906 M = code.CodeMagics(ip)
907 last_call = ['','']
907 last_call = ['','']
908 opts,args = M.parse_options(arg_s,'prxn:')
908 opts,args = M.parse_options(arg_s,'prxn:')
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
910
910
911 if exp_filename is not None:
911 if exp_filename is not None:
912 nt.assert_equal(exp_filename, filename)
912 nt.assert_equal(exp_filename, filename)
913 if exp_contents is not None:
913 if exp_contents is not None:
914 with io.open(filename, 'r') as f:
914 with io.open(filename, 'r') as f:
915 contents = f.read()
915 contents = f.read()
916 nt.assert_equal(exp_contents, contents)
916 nt.assert_equal(exp_contents, contents)
917 if exp_lineno != -1:
917 if exp_lineno != -1:
918 nt.assert_equal(exp_lineno, lineno)
918 nt.assert_equal(exp_lineno, lineno)
919 if exp_is_temp is not None:
919 if exp_is_temp is not None:
920 nt.assert_equal(exp_is_temp, is_temp)
920 nt.assert_equal(exp_is_temp, is_temp)
921
921
922
922
923 def test_edit_interactive():
923 def test_edit_interactive():
924 """%edit on interactively defined objects"""
924 """%edit on interactively defined objects"""
925 ip = get_ipython()
925 ip = get_ipython()
926 n = ip.execution_count
926 n = ip.execution_count
927 ip.run_cell(u"def foo(): return 1", store_history=True)
927 ip.run_cell(u"def foo(): return 1", store_history=True)
928
928
929 try:
929 try:
930 _run_edit_test("foo")
930 _run_edit_test("foo")
931 except code.InteractivelyDefined as e:
931 except code.InteractivelyDefined as e:
932 nt.assert_equal(e.index, n)
932 nt.assert_equal(e.index, n)
933 else:
933 else:
934 raise AssertionError("Should have raised InteractivelyDefined")
934 raise AssertionError("Should have raised InteractivelyDefined")
935
935
936
936
937 def test_edit_cell():
937 def test_edit_cell():
938 """%edit [cell id]"""
938 """%edit [cell id]"""
939 ip = get_ipython()
939 ip = get_ipython()
940
940
941 ip.run_cell(u"def foo(): return 1", store_history=True)
941 ip.run_cell(u"def foo(): return 1", store_history=True)
942
942
943 # test
943 # test
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
@@ -1,1267 +1,1267 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultratb.py -- Spice up your tracebacks!
3 ultratb.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB::
11 Installation instructions for ColorTB::
12
12
13 import sys,ultratb
13 import sys,ultratb
14 sys.excepthook = ultratb.ColorTB()
14 sys.excepthook = ultratb.ColorTB()
15
15
16 * VerboseTB
16 * VerboseTB
17 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
18 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 of useful info when a traceback occurs. Ping originally had it spit out HTML
19 and intended it for CGI programmers, but why should they have all the fun? I
19 and intended it for CGI programmers, but why should they have all the fun? I
20 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 altered it to spit out colored text to the terminal. It's a bit overwhelming,
21 but kind of neat, and maybe useful for long-running programs that you believe
21 but kind of neat, and maybe useful for long-running programs that you believe
22 are bug-free. If a crash *does* occur in that type of program you want details.
22 are bug-free. If a crash *does* occur in that type of program you want details.
23 Give it a shot--you'll love it or you'll hate it.
23 Give it a shot--you'll love it or you'll hate it.
24
24
25 .. note::
25 .. note::
26
26
27 The Verbose mode prints the variables currently visible where the exception
27 The Verbose mode prints the variables currently visible where the exception
28 happened (shortening their strings if too long). This can potentially be
28 happened (shortening their strings if too long). This can potentially be
29 very slow, if you happen to have a huge data structure whose string
29 very slow, if you happen to have a huge data structure whose string
30 representation is complex to compute. Your computer may appear to freeze for
30 representation is complex to compute. Your computer may appear to freeze for
31 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
32 with Ctrl-C (maybe hitting it more than once).
32 with Ctrl-C (maybe hitting it more than once).
33
33
34 If you encounter this kind of situation often, you may want to use the
34 If you encounter this kind of situation often, you may want to use the
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
36 variables (but otherwise includes the information and context given by
36 variables (but otherwise includes the information and context given by
37 Verbose).
37 Verbose).
38
38
39
39
40 Installation instructions for ColorTB::
40 Installation instructions for ColorTB::
41
41
42 import sys,ultratb
42 import sys,ultratb
43 sys.excepthook = ultratb.VerboseTB()
43 sys.excepthook = ultratb.VerboseTB()
44
44
45 Note: Much of the code in this module was lifted verbatim from the standard
45 Note: Much of the code in this module was lifted verbatim from the standard
46 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
46 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
47
47
48 Color schemes
48 Color schemes
49 -------------
49 -------------
50
50
51 The colors are defined in the class TBTools through the use of the
51 The colors are defined in the class TBTools through the use of the
52 ColorSchemeTable class. Currently the following exist:
52 ColorSchemeTable class. Currently the following exist:
53
53
54 - NoColor: allows all of this module to be used in any terminal (the color
54 - NoColor: allows all of this module to be used in any terminal (the color
55 escapes are just dummy blank strings).
55 escapes are just dummy blank strings).
56
56
57 - Linux: is meant to look good in a terminal like the Linux console (black
57 - Linux: is meant to look good in a terminal like the Linux console (black
58 or very dark background).
58 or very dark background).
59
59
60 - LightBG: similar to Linux but swaps dark/light colors to be more readable
60 - LightBG: similar to Linux but swaps dark/light colors to be more readable
61 in light background terminals.
61 in light background terminals.
62
62
63 You can implement other color schemes easily, the syntax is fairly
63 You can implement other color schemes easily, the syntax is fairly
64 self-explanatory. Please send back new schemes you develop to the author for
64 self-explanatory. Please send back new schemes you develop to the author for
65 possible inclusion in future releases.
65 possible inclusion in future releases.
66
66
67 Inheritance diagram:
67 Inheritance diagram:
68
68
69 .. inheritance-diagram:: IPython.core.ultratb
69 .. inheritance-diagram:: IPython.core.ultratb
70 :parts: 3
70 :parts: 3
71 """
71 """
72
72
73 #*****************************************************************************
73 #*****************************************************************************
74 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
74 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
75 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
75 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
76 #
76 #
77 # Distributed under the terms of the BSD License. The full license is in
77 # Distributed under the terms of the BSD License. The full license is in
78 # the file COPYING, distributed as part of this software.
78 # the file COPYING, distributed as part of this software.
79 #*****************************************************************************
79 #*****************************************************************************
80
80
81 from __future__ import unicode_literals
81 from __future__ import unicode_literals
82 from __future__ import print_function
82 from __future__ import print_function
83
83
84 import inspect
84 import inspect
85 import keyword
85 import keyword
86 import linecache
86 import linecache
87 import os
87 import os
88 import pydoc
88 import pydoc
89 import re
89 import re
90 import sys
90 import sys
91 import time
91 import time
92 import tokenize
92 import tokenize
93 import traceback
93 import traceback
94 import types
94 import types
95
95
96 try: # Python 2
96 try: # Python 2
97 generate_tokens = tokenize.generate_tokens
97 generate_tokens = tokenize.generate_tokens
98 except AttributeError: # Python 3
98 except AttributeError: # Python 3
99 generate_tokens = tokenize.tokenize
99 generate_tokens = tokenize.tokenize
100
100
101 # For purposes of monkeypatching inspect to fix a bug in it.
101 # For purposes of monkeypatching inspect to fix a bug in it.
102 from inspect import getsourcefile, getfile, getmodule,\
102 from inspect import getsourcefile, getfile, getmodule,\
103 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
103 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
104
104
105 # IPython's own modules
105 # IPython's own modules
106 # Modified pdb which doesn't damage IPython's readline handling
106 # Modified pdb which doesn't damage IPython's readline handling
107 from IPython import get_ipython
107 from IPython import get_ipython
108 from IPython.core import debugger
108 from IPython.core import debugger
109 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.display_trap import DisplayTrap
110 from IPython.core.excolors import exception_colors
110 from IPython.core.excolors import exception_colors
111 from IPython.utils import PyColorize
111 from IPython.utils import PyColorize
112 from IPython.utils import io
112 from IPython.utils import io
113 from IPython.utils import openpy
113 from IPython.utils import openpy
114 from IPython.utils import path as util_path
114 from IPython.utils import path as util_path
115 from IPython.utils import py3compat
115 from IPython.utils import py3compat
116 from IPython.utils import ulinecache
116 from IPython.utils import ulinecache
117 from IPython.utils.data import uniq_stable
117 from IPython.utils.data import uniq_stable
118 from IPython.utils.warn import info, error
118 from IPython.utils.warn import info, error
119
119
120 # Globals
120 # Globals
121 # amount of space to put line numbers before verbose tracebacks
121 # amount of space to put line numbers before verbose tracebacks
122 INDENT_SIZE = 8
122 INDENT_SIZE = 8
123
123
124 # Default color scheme. This is used, for example, by the traceback
124 # Default color scheme. This is used, for example, by the traceback
125 # formatter. When running in an actual IPython instance, the user's rc.colors
125 # formatter. When running in an actual IPython instance, the user's rc.colors
126 # value is used, but havinga module global makes this functionality available
126 # value is used, but havinga module global makes this functionality available
127 # to users of ultratb who are NOT running inside ipython.
127 # to users of ultratb who are NOT running inside ipython.
128 DEFAULT_SCHEME = 'NoColor'
128 DEFAULT_SCHEME = 'NoColor'
129
129
130 #---------------------------------------------------------------------------
130 #---------------------------------------------------------------------------
131 # Code begins
131 # Code begins
132
132
133 # Utility functions
133 # Utility functions
134 def inspect_error():
134 def inspect_error():
135 """Print a message about internal inspect errors.
135 """Print a message about internal inspect errors.
136
136
137 These are unfortunately quite common."""
137 These are unfortunately quite common."""
138
138
139 error('Internal Python error in the inspect module.\n'
139 error('Internal Python error in the inspect module.\n'
140 'Below is the traceback from this internal error.\n')
140 'Below is the traceback from this internal error.\n')
141
141
142 # This function is a monkeypatch we apply to the Python inspect module. We have
142 # This function is a monkeypatch we apply to the Python inspect module. We have
143 # now found when it's needed (see discussion on issue gh-1456), and we have a
143 # now found when it's needed (see discussion on issue gh-1456), and we have a
144 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
144 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
145 # the monkeypatch is not applied. TK, Aug 2012.
145 # the monkeypatch is not applied. TK, Aug 2012.
146 def findsource(object):
146 def findsource(object):
147 """Return the entire source file and starting line number for an object.
147 """Return the entire source file and starting line number for an object.
148
148
149 The argument may be a module, class, method, function, traceback, frame,
149 The argument may be a module, class, method, function, traceback, frame,
150 or code object. The source code is returned as a list of all the lines
150 or code object. The source code is returned as a list of all the lines
151 in the file and the line number indexes a line in that list. An IOError
151 in the file and the line number indexes a line in that list. An IOError
152 is raised if the source code cannot be retrieved.
152 is raised if the source code cannot be retrieved.
153
153
154 FIXED version with which we monkeypatch the stdlib to work around a bug."""
154 FIXED version with which we monkeypatch the stdlib to work around a bug."""
155
155
156 file = getsourcefile(object) or getfile(object)
156 file = getsourcefile(object) or getfile(object)
157 # If the object is a frame, then trying to get the globals dict from its
157 # If the object is a frame, then trying to get the globals dict from its
158 # module won't work. Instead, the frame object itself has the globals
158 # module won't work. Instead, the frame object itself has the globals
159 # dictionary.
159 # dictionary.
160 globals_dict = None
160 globals_dict = None
161 if inspect.isframe(object):
161 if inspect.isframe(object):
162 # XXX: can this ever be false?
162 # XXX: can this ever be false?
163 globals_dict = object.f_globals
163 globals_dict = object.f_globals
164 else:
164 else:
165 module = getmodule(object, file)
165 module = getmodule(object, file)
166 if module:
166 if module:
167 globals_dict = module.__dict__
167 globals_dict = module.__dict__
168 lines = linecache.getlines(file, globals_dict)
168 lines = linecache.getlines(file, globals_dict)
169 if not lines:
169 if not lines:
170 raise IOError('could not get source code')
170 raise IOError('could not get source code')
171
171
172 if ismodule(object):
172 if ismodule(object):
173 return lines, 0
173 return lines, 0
174
174
175 if isclass(object):
175 if isclass(object):
176 name = object.__name__
176 name = object.__name__
177 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
177 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
178 # make some effort to find the best matching class definition:
178 # make some effort to find the best matching class definition:
179 # use the one with the least indentation, which is the one
179 # use the one with the least indentation, which is the one
180 # that's most probably not inside a function definition.
180 # that's most probably not inside a function definition.
181 candidates = []
181 candidates = []
182 for i in range(len(lines)):
182 for i in range(len(lines)):
183 match = pat.match(lines[i])
183 match = pat.match(lines[i])
184 if match:
184 if match:
185 # if it's at toplevel, it's already the best one
185 # if it's at toplevel, it's already the best one
186 if lines[i][0] == 'c':
186 if lines[i][0] == 'c':
187 return lines, i
187 return lines, i
188 # else add whitespace to candidate list
188 # else add whitespace to candidate list
189 candidates.append((match.group(1), i))
189 candidates.append((match.group(1), i))
190 if candidates:
190 if candidates:
191 # this will sort by whitespace, and by line number,
191 # this will sort by whitespace, and by line number,
192 # less whitespace first
192 # less whitespace first
193 candidates.sort()
193 candidates.sort()
194 return lines, candidates[0][1]
194 return lines, candidates[0][1]
195 else:
195 else:
196 raise IOError('could not find class definition')
196 raise IOError('could not find class definition')
197
197
198 if ismethod(object):
198 if ismethod(object):
199 object = object.im_func
199 object = object.__func__
200 if isfunction(object):
200 if isfunction(object):
201 object = object.__code__
201 object = object.__code__
202 if istraceback(object):
202 if istraceback(object):
203 object = object.tb_frame
203 object = object.tb_frame
204 if isframe(object):
204 if isframe(object):
205 object = object.f_code
205 object = object.f_code
206 if iscode(object):
206 if iscode(object):
207 if not hasattr(object, 'co_firstlineno'):
207 if not hasattr(object, 'co_firstlineno'):
208 raise IOError('could not find function definition')
208 raise IOError('could not find function definition')
209 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
209 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
210 pmatch = pat.match
210 pmatch = pat.match
211 # fperez - fix: sometimes, co_firstlineno can give a number larger than
211 # fperez - fix: sometimes, co_firstlineno can give a number larger than
212 # the length of lines, which causes an error. Safeguard against that.
212 # the length of lines, which causes an error. Safeguard against that.
213 lnum = min(object.co_firstlineno,len(lines))-1
213 lnum = min(object.co_firstlineno,len(lines))-1
214 while lnum > 0:
214 while lnum > 0:
215 if pmatch(lines[lnum]): break
215 if pmatch(lines[lnum]): break
216 lnum -= 1
216 lnum -= 1
217
217
218 return lines, lnum
218 return lines, lnum
219 raise IOError('could not find code object')
219 raise IOError('could not find code object')
220
220
221 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
221 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
222 inspect.findsource = findsource
222 inspect.findsource = findsource
223
223
224 def fix_frame_records_filenames(records):
224 def fix_frame_records_filenames(records):
225 """Try to fix the filenames in each record from inspect.getinnerframes().
225 """Try to fix the filenames in each record from inspect.getinnerframes().
226
226
227 Particularly, modules loaded from within zip files have useless filenames
227 Particularly, modules loaded from within zip files have useless filenames
228 attached to their code object, and inspect.getinnerframes() just uses it.
228 attached to their code object, and inspect.getinnerframes() just uses it.
229 """
229 """
230 fixed_records = []
230 fixed_records = []
231 for frame, filename, line_no, func_name, lines, index in records:
231 for frame, filename, line_no, func_name, lines, index in records:
232 # Look inside the frame's globals dictionary for __file__, which should
232 # Look inside the frame's globals dictionary for __file__, which should
233 # be better.
233 # be better.
234 better_fn = frame.f_globals.get('__file__', None)
234 better_fn = frame.f_globals.get('__file__', None)
235 if isinstance(better_fn, str):
235 if isinstance(better_fn, str):
236 # Check the type just in case someone did something weird with
236 # Check the type just in case someone did something weird with
237 # __file__. It might also be None if the error occurred during
237 # __file__. It might also be None if the error occurred during
238 # import.
238 # import.
239 filename = better_fn
239 filename = better_fn
240 fixed_records.append((frame, filename, line_no, func_name, lines, index))
240 fixed_records.append((frame, filename, line_no, func_name, lines, index))
241 return fixed_records
241 return fixed_records
242
242
243
243
244 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
244 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
245 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
245 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
246
246
247 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
247 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
248
248
249 # If the error is at the console, don't build any context, since it would
249 # If the error is at the console, don't build any context, since it would
250 # otherwise produce 5 blank lines printed out (there is no file at the
250 # otherwise produce 5 blank lines printed out (there is no file at the
251 # console)
251 # console)
252 rec_check = records[tb_offset:]
252 rec_check = records[tb_offset:]
253 try:
253 try:
254 rname = rec_check[0][1]
254 rname = rec_check[0][1]
255 if rname == '<ipython console>' or rname.endswith('<string>'):
255 if rname == '<ipython console>' or rname.endswith('<string>'):
256 return rec_check
256 return rec_check
257 except IndexError:
257 except IndexError:
258 pass
258 pass
259
259
260 aux = traceback.extract_tb(etb)
260 aux = traceback.extract_tb(etb)
261 assert len(records) == len(aux)
261 assert len(records) == len(aux)
262 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
262 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
263 maybeStart = lnum-1 - context//2
263 maybeStart = lnum-1 - context//2
264 start = max(maybeStart, 0)
264 start = max(maybeStart, 0)
265 end = start + context
265 end = start + context
266 lines = ulinecache.getlines(file)[start:end]
266 lines = ulinecache.getlines(file)[start:end]
267 buf = list(records[i])
267 buf = list(records[i])
268 buf[LNUM_POS] = lnum
268 buf[LNUM_POS] = lnum
269 buf[INDEX_POS] = lnum - 1 - start
269 buf[INDEX_POS] = lnum - 1 - start
270 buf[LINES_POS] = lines
270 buf[LINES_POS] = lines
271 records[i] = tuple(buf)
271 records[i] = tuple(buf)
272 return records[tb_offset:]
272 return records[tb_offset:]
273
273
274 # Helper function -- largely belongs to VerboseTB, but we need the same
274 # Helper function -- largely belongs to VerboseTB, but we need the same
275 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
275 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
276 # can be recognized properly by ipython.el's py-traceback-line-re
276 # can be recognized properly by ipython.el's py-traceback-line-re
277 # (SyntaxErrors have to be treated specially because they have no traceback)
277 # (SyntaxErrors have to be treated specially because they have no traceback)
278
278
279 _parser = PyColorize.Parser()
279 _parser = PyColorize.Parser()
280
280
281 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
281 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
282 numbers_width = INDENT_SIZE - 1
282 numbers_width = INDENT_SIZE - 1
283 res = []
283 res = []
284 i = lnum - index
284 i = lnum - index
285
285
286 # This lets us get fully syntax-highlighted tracebacks.
286 # This lets us get fully syntax-highlighted tracebacks.
287 if scheme is None:
287 if scheme is None:
288 ipinst = get_ipython()
288 ipinst = get_ipython()
289 if ipinst is not None:
289 if ipinst is not None:
290 scheme = ipinst.colors
290 scheme = ipinst.colors
291 else:
291 else:
292 scheme = DEFAULT_SCHEME
292 scheme = DEFAULT_SCHEME
293
293
294 _line_format = _parser.format2
294 _line_format = _parser.format2
295
295
296 for line in lines:
296 for line in lines:
297 line = py3compat.cast_unicode(line)
297 line = py3compat.cast_unicode(line)
298
298
299 new_line, err = _line_format(line, 'str', scheme)
299 new_line, err = _line_format(line, 'str', scheme)
300 if not err: line = new_line
300 if not err: line = new_line
301
301
302 if i == lnum:
302 if i == lnum:
303 # This is the line with the error
303 # This is the line with the error
304 pad = numbers_width - len(str(i))
304 pad = numbers_width - len(str(i))
305 if pad >= 3:
305 if pad >= 3:
306 marker = '-'*(pad-3) + '-> '
306 marker = '-'*(pad-3) + '-> '
307 elif pad == 2:
307 elif pad == 2:
308 marker = '> '
308 marker = '> '
309 elif pad == 1:
309 elif pad == 1:
310 marker = '>'
310 marker = '>'
311 else:
311 else:
312 marker = ''
312 marker = ''
313 num = marker + str(i)
313 num = marker + str(i)
314 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
314 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
315 Colors.line, line, Colors.Normal)
315 Colors.line, line, Colors.Normal)
316 else:
316 else:
317 num = '%*s' % (numbers_width,i)
317 num = '%*s' % (numbers_width,i)
318 line = '%s%s%s %s' %(Colors.lineno, num,
318 line = '%s%s%s %s' %(Colors.lineno, num,
319 Colors.Normal, line)
319 Colors.Normal, line)
320
320
321 res.append(line)
321 res.append(line)
322 if lvals and i == lnum:
322 if lvals and i == lnum:
323 res.append(lvals + '\n')
323 res.append(lvals + '\n')
324 i = i + 1
324 i = i + 1
325 return res
325 return res
326
326
327
327
328 #---------------------------------------------------------------------------
328 #---------------------------------------------------------------------------
329 # Module classes
329 # Module classes
330 class TBTools(object):
330 class TBTools(object):
331 """Basic tools used by all traceback printer classes."""
331 """Basic tools used by all traceback printer classes."""
332
332
333 # Number of frames to skip when reporting tracebacks
333 # Number of frames to skip when reporting tracebacks
334 tb_offset = 0
334 tb_offset = 0
335
335
336 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
336 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
337 # Whether to call the interactive pdb debugger after printing
337 # Whether to call the interactive pdb debugger after printing
338 # tracebacks or not
338 # tracebacks or not
339 self.call_pdb = call_pdb
339 self.call_pdb = call_pdb
340
340
341 # Output stream to write to. Note that we store the original value in
341 # Output stream to write to. Note that we store the original value in
342 # a private attribute and then make the public ostream a property, so
342 # a private attribute and then make the public ostream a property, so
343 # that we can delay accessing io.stdout until runtime. The way
343 # that we can delay accessing io.stdout until runtime. The way
344 # things are written now, the io.stdout object is dynamically managed
344 # things are written now, the io.stdout object is dynamically managed
345 # so a reference to it should NEVER be stored statically. This
345 # so a reference to it should NEVER be stored statically. This
346 # property approach confines this detail to a single location, and all
346 # property approach confines this detail to a single location, and all
347 # subclasses can simply access self.ostream for writing.
347 # subclasses can simply access self.ostream for writing.
348 self._ostream = ostream
348 self._ostream = ostream
349
349
350 # Create color table
350 # Create color table
351 self.color_scheme_table = exception_colors()
351 self.color_scheme_table = exception_colors()
352
352
353 self.set_colors(color_scheme)
353 self.set_colors(color_scheme)
354 self.old_scheme = color_scheme # save initial value for toggles
354 self.old_scheme = color_scheme # save initial value for toggles
355
355
356 if call_pdb:
356 if call_pdb:
357 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
357 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
358 else:
358 else:
359 self.pdb = None
359 self.pdb = None
360
360
361 def _get_ostream(self):
361 def _get_ostream(self):
362 """Output stream that exceptions are written to.
362 """Output stream that exceptions are written to.
363
363
364 Valid values are:
364 Valid values are:
365
365
366 - None: the default, which means that IPython will dynamically resolve
366 - None: the default, which means that IPython will dynamically resolve
367 to io.stdout. This ensures compatibility with most tools, including
367 to io.stdout. This ensures compatibility with most tools, including
368 Windows (where plain stdout doesn't recognize ANSI escapes).
368 Windows (where plain stdout doesn't recognize ANSI escapes).
369
369
370 - Any object with 'write' and 'flush' attributes.
370 - Any object with 'write' and 'flush' attributes.
371 """
371 """
372 return io.stdout if self._ostream is None else self._ostream
372 return io.stdout if self._ostream is None else self._ostream
373
373
374 def _set_ostream(self, val):
374 def _set_ostream(self, val):
375 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
375 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
376 self._ostream = val
376 self._ostream = val
377
377
378 ostream = property(_get_ostream, _set_ostream)
378 ostream = property(_get_ostream, _set_ostream)
379
379
380 def set_colors(self,*args,**kw):
380 def set_colors(self,*args,**kw):
381 """Shorthand access to the color table scheme selector method."""
381 """Shorthand access to the color table scheme selector method."""
382
382
383 # Set own color table
383 # Set own color table
384 self.color_scheme_table.set_active_scheme(*args,**kw)
384 self.color_scheme_table.set_active_scheme(*args,**kw)
385 # for convenience, set Colors to the active scheme
385 # for convenience, set Colors to the active scheme
386 self.Colors = self.color_scheme_table.active_colors
386 self.Colors = self.color_scheme_table.active_colors
387 # Also set colors of debugger
387 # Also set colors of debugger
388 if hasattr(self,'pdb') and self.pdb is not None:
388 if hasattr(self,'pdb') and self.pdb is not None:
389 self.pdb.set_colors(*args,**kw)
389 self.pdb.set_colors(*args,**kw)
390
390
391 def color_toggle(self):
391 def color_toggle(self):
392 """Toggle between the currently active color scheme and NoColor."""
392 """Toggle between the currently active color scheme and NoColor."""
393
393
394 if self.color_scheme_table.active_scheme_name == 'NoColor':
394 if self.color_scheme_table.active_scheme_name == 'NoColor':
395 self.color_scheme_table.set_active_scheme(self.old_scheme)
395 self.color_scheme_table.set_active_scheme(self.old_scheme)
396 self.Colors = self.color_scheme_table.active_colors
396 self.Colors = self.color_scheme_table.active_colors
397 else:
397 else:
398 self.old_scheme = self.color_scheme_table.active_scheme_name
398 self.old_scheme = self.color_scheme_table.active_scheme_name
399 self.color_scheme_table.set_active_scheme('NoColor')
399 self.color_scheme_table.set_active_scheme('NoColor')
400 self.Colors = self.color_scheme_table.active_colors
400 self.Colors = self.color_scheme_table.active_colors
401
401
402 def stb2text(self, stb):
402 def stb2text(self, stb):
403 """Convert a structured traceback (a list) to a string."""
403 """Convert a structured traceback (a list) to a string."""
404 return '\n'.join(stb)
404 return '\n'.join(stb)
405
405
406 def text(self, etype, value, tb, tb_offset=None, context=5):
406 def text(self, etype, value, tb, tb_offset=None, context=5):
407 """Return formatted traceback.
407 """Return formatted traceback.
408
408
409 Subclasses may override this if they add extra arguments.
409 Subclasses may override this if they add extra arguments.
410 """
410 """
411 tb_list = self.structured_traceback(etype, value, tb,
411 tb_list = self.structured_traceback(etype, value, tb,
412 tb_offset, context)
412 tb_offset, context)
413 return self.stb2text(tb_list)
413 return self.stb2text(tb_list)
414
414
415 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
415 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
416 context=5, mode=None):
416 context=5, mode=None):
417 """Return a list of traceback frames.
417 """Return a list of traceback frames.
418
418
419 Must be implemented by each class.
419 Must be implemented by each class.
420 """
420 """
421 raise NotImplementedError()
421 raise NotImplementedError()
422
422
423
423
424 #---------------------------------------------------------------------------
424 #---------------------------------------------------------------------------
425 class ListTB(TBTools):
425 class ListTB(TBTools):
426 """Print traceback information from a traceback list, with optional color.
426 """Print traceback information from a traceback list, with optional color.
427
427
428 Calling requires 3 arguments: (etype, evalue, elist)
428 Calling requires 3 arguments: (etype, evalue, elist)
429 as would be obtained by::
429 as would be obtained by::
430
430
431 etype, evalue, tb = sys.exc_info()
431 etype, evalue, tb = sys.exc_info()
432 if tb:
432 if tb:
433 elist = traceback.extract_tb(tb)
433 elist = traceback.extract_tb(tb)
434 else:
434 else:
435 elist = None
435 elist = None
436
436
437 It can thus be used by programs which need to process the traceback before
437 It can thus be used by programs which need to process the traceback before
438 printing (such as console replacements based on the code module from the
438 printing (such as console replacements based on the code module from the
439 standard library).
439 standard library).
440
440
441 Because they are meant to be called without a full traceback (only a
441 Because they are meant to be called without a full traceback (only a
442 list), instances of this class can't call the interactive pdb debugger."""
442 list), instances of this class can't call the interactive pdb debugger."""
443
443
444 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
444 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
445 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
445 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
446 ostream=ostream)
446 ostream=ostream)
447
447
448 def __call__(self, etype, value, elist):
448 def __call__(self, etype, value, elist):
449 self.ostream.flush()
449 self.ostream.flush()
450 self.ostream.write(self.text(etype, value, elist))
450 self.ostream.write(self.text(etype, value, elist))
451 self.ostream.write('\n')
451 self.ostream.write('\n')
452
452
453 def structured_traceback(self, etype, value, elist, tb_offset=None,
453 def structured_traceback(self, etype, value, elist, tb_offset=None,
454 context=5):
454 context=5):
455 """Return a color formatted string with the traceback info.
455 """Return a color formatted string with the traceback info.
456
456
457 Parameters
457 Parameters
458 ----------
458 ----------
459 etype : exception type
459 etype : exception type
460 Type of the exception raised.
460 Type of the exception raised.
461
461
462 value : object
462 value : object
463 Data stored in the exception
463 Data stored in the exception
464
464
465 elist : list
465 elist : list
466 List of frames, see class docstring for details.
466 List of frames, see class docstring for details.
467
467
468 tb_offset : int, optional
468 tb_offset : int, optional
469 Number of frames in the traceback to skip. If not given, the
469 Number of frames in the traceback to skip. If not given, the
470 instance value is used (set in constructor).
470 instance value is used (set in constructor).
471
471
472 context : int, optional
472 context : int, optional
473 Number of lines of context information to print.
473 Number of lines of context information to print.
474
474
475 Returns
475 Returns
476 -------
476 -------
477 String with formatted exception.
477 String with formatted exception.
478 """
478 """
479 tb_offset = self.tb_offset if tb_offset is None else tb_offset
479 tb_offset = self.tb_offset if tb_offset is None else tb_offset
480 Colors = self.Colors
480 Colors = self.Colors
481 out_list = []
481 out_list = []
482 if elist:
482 if elist:
483
483
484 if tb_offset and len(elist) > tb_offset:
484 if tb_offset and len(elist) > tb_offset:
485 elist = elist[tb_offset:]
485 elist = elist[tb_offset:]
486
486
487 out_list.append('Traceback %s(most recent call last)%s:' %
487 out_list.append('Traceback %s(most recent call last)%s:' %
488 (Colors.normalEm, Colors.Normal) + '\n')
488 (Colors.normalEm, Colors.Normal) + '\n')
489 out_list.extend(self._format_list(elist))
489 out_list.extend(self._format_list(elist))
490 # The exception info should be a single entry in the list.
490 # The exception info should be a single entry in the list.
491 lines = ''.join(self._format_exception_only(etype, value))
491 lines = ''.join(self._format_exception_only(etype, value))
492 out_list.append(lines)
492 out_list.append(lines)
493
493
494 # Note: this code originally read:
494 # Note: this code originally read:
495
495
496 ## for line in lines[:-1]:
496 ## for line in lines[:-1]:
497 ## out_list.append(" "+line)
497 ## out_list.append(" "+line)
498 ## out_list.append(lines[-1])
498 ## out_list.append(lines[-1])
499
499
500 # This means it was indenting everything but the last line by a little
500 # This means it was indenting everything but the last line by a little
501 # bit. I've disabled this for now, but if we see ugliness somewhre we
501 # bit. I've disabled this for now, but if we see ugliness somewhre we
502 # can restore it.
502 # can restore it.
503
503
504 return out_list
504 return out_list
505
505
506 def _format_list(self, extracted_list):
506 def _format_list(self, extracted_list):
507 """Format a list of traceback entry tuples for printing.
507 """Format a list of traceback entry tuples for printing.
508
508
509 Given a list of tuples as returned by extract_tb() or
509 Given a list of tuples as returned by extract_tb() or
510 extract_stack(), return a list of strings ready for printing.
510 extract_stack(), return a list of strings ready for printing.
511 Each string in the resulting list corresponds to the item with the
511 Each string in the resulting list corresponds to the item with the
512 same index in the argument list. Each string ends in a newline;
512 same index in the argument list. Each string ends in a newline;
513 the strings may contain internal newlines as well, for those items
513 the strings may contain internal newlines as well, for those items
514 whose source text line is not None.
514 whose source text line is not None.
515
515
516 Lifted almost verbatim from traceback.py
516 Lifted almost verbatim from traceback.py
517 """
517 """
518
518
519 Colors = self.Colors
519 Colors = self.Colors
520 list = []
520 list = []
521 for filename, lineno, name, line in extracted_list[:-1]:
521 for filename, lineno, name, line in extracted_list[:-1]:
522 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
522 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
523 (Colors.filename, filename, Colors.Normal,
523 (Colors.filename, filename, Colors.Normal,
524 Colors.lineno, lineno, Colors.Normal,
524 Colors.lineno, lineno, Colors.Normal,
525 Colors.name, name, Colors.Normal)
525 Colors.name, name, Colors.Normal)
526 if line:
526 if line:
527 item += ' %s\n' % line.strip()
527 item += ' %s\n' % line.strip()
528 list.append(item)
528 list.append(item)
529 # Emphasize the last entry
529 # Emphasize the last entry
530 filename, lineno, name, line = extracted_list[-1]
530 filename, lineno, name, line = extracted_list[-1]
531 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
531 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
532 (Colors.normalEm,
532 (Colors.normalEm,
533 Colors.filenameEm, filename, Colors.normalEm,
533 Colors.filenameEm, filename, Colors.normalEm,
534 Colors.linenoEm, lineno, Colors.normalEm,
534 Colors.linenoEm, lineno, Colors.normalEm,
535 Colors.nameEm, name, Colors.normalEm,
535 Colors.nameEm, name, Colors.normalEm,
536 Colors.Normal)
536 Colors.Normal)
537 if line:
537 if line:
538 item += '%s %s%s\n' % (Colors.line, line.strip(),
538 item += '%s %s%s\n' % (Colors.line, line.strip(),
539 Colors.Normal)
539 Colors.Normal)
540 list.append(item)
540 list.append(item)
541 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
541 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
542 return list
542 return list
543
543
544 def _format_exception_only(self, etype, value):
544 def _format_exception_only(self, etype, value):
545 """Format the exception part of a traceback.
545 """Format the exception part of a traceback.
546
546
547 The arguments are the exception type and value such as given by
547 The arguments are the exception type and value such as given by
548 sys.exc_info()[:2]. The return value is a list of strings, each ending
548 sys.exc_info()[:2]. The return value is a list of strings, each ending
549 in a newline. Normally, the list contains a single string; however,
549 in a newline. Normally, the list contains a single string; however,
550 for SyntaxError exceptions, it contains several lines that (when
550 for SyntaxError exceptions, it contains several lines that (when
551 printed) display detailed information about where the syntax error
551 printed) display detailed information about where the syntax error
552 occurred. The message indicating which exception occurred is the
552 occurred. The message indicating which exception occurred is the
553 always last string in the list.
553 always last string in the list.
554
554
555 Also lifted nearly verbatim from traceback.py
555 Also lifted nearly verbatim from traceback.py
556 """
556 """
557 have_filedata = False
557 have_filedata = False
558 Colors = self.Colors
558 Colors = self.Colors
559 list = []
559 list = []
560 stype = Colors.excName + etype.__name__ + Colors.Normal
560 stype = Colors.excName + etype.__name__ + Colors.Normal
561 if value is None:
561 if value is None:
562 # Not sure if this can still happen in Python 2.6 and above
562 # Not sure if this can still happen in Python 2.6 and above
563 list.append( py3compat.cast_unicode(stype) + '\n')
563 list.append( py3compat.cast_unicode(stype) + '\n')
564 else:
564 else:
565 if issubclass(etype, SyntaxError):
565 if issubclass(etype, SyntaxError):
566 have_filedata = True
566 have_filedata = True
567 #print 'filename is',filename # dbg
567 #print 'filename is',filename # dbg
568 if not value.filename: value.filename = "<string>"
568 if not value.filename: value.filename = "<string>"
569 if value.lineno:
569 if value.lineno:
570 lineno = value.lineno
570 lineno = value.lineno
571 textline = ulinecache.getline(value.filename, value.lineno)
571 textline = ulinecache.getline(value.filename, value.lineno)
572 else:
572 else:
573 lineno = 'unknown'
573 lineno = 'unknown'
574 textline = ''
574 textline = ''
575 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
575 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
576 (Colors.normalEm,
576 (Colors.normalEm,
577 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
577 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
578 Colors.linenoEm, lineno, Colors.Normal ))
578 Colors.linenoEm, lineno, Colors.Normal ))
579 if textline == '':
579 if textline == '':
580 textline = py3compat.cast_unicode(value.text, "utf-8")
580 textline = py3compat.cast_unicode(value.text, "utf-8")
581
581
582 if textline is not None:
582 if textline is not None:
583 i = 0
583 i = 0
584 while i < len(textline) and textline[i].isspace():
584 while i < len(textline) and textline[i].isspace():
585 i += 1
585 i += 1
586 list.append('%s %s%s\n' % (Colors.line,
586 list.append('%s %s%s\n' % (Colors.line,
587 textline.strip(),
587 textline.strip(),
588 Colors.Normal))
588 Colors.Normal))
589 if value.offset is not None:
589 if value.offset is not None:
590 s = ' '
590 s = ' '
591 for c in textline[i:value.offset-1]:
591 for c in textline[i:value.offset-1]:
592 if c.isspace():
592 if c.isspace():
593 s += c
593 s += c
594 else:
594 else:
595 s += ' '
595 s += ' '
596 list.append('%s%s^%s\n' % (Colors.caret, s,
596 list.append('%s%s^%s\n' % (Colors.caret, s,
597 Colors.Normal) )
597 Colors.Normal) )
598
598
599 try:
599 try:
600 s = value.msg
600 s = value.msg
601 except Exception:
601 except Exception:
602 s = self._some_str(value)
602 s = self._some_str(value)
603 if s:
603 if s:
604 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
604 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
605 Colors.Normal, s))
605 Colors.Normal, s))
606 else:
606 else:
607 list.append('%s\n' % str(stype))
607 list.append('%s\n' % str(stype))
608
608
609 # sync with user hooks
609 # sync with user hooks
610 if have_filedata:
610 if have_filedata:
611 ipinst = get_ipython()
611 ipinst = get_ipython()
612 if ipinst is not None:
612 if ipinst is not None:
613 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
613 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
614
614
615 return list
615 return list
616
616
617 def get_exception_only(self, etype, value):
617 def get_exception_only(self, etype, value):
618 """Only print the exception type and message, without a traceback.
618 """Only print the exception type and message, without a traceback.
619
619
620 Parameters
620 Parameters
621 ----------
621 ----------
622 etype : exception type
622 etype : exception type
623 value : exception value
623 value : exception value
624 """
624 """
625 return ListTB.structured_traceback(self, etype, value, [])
625 return ListTB.structured_traceback(self, etype, value, [])
626
626
627
627
628 def show_exception_only(self, etype, evalue):
628 def show_exception_only(self, etype, evalue):
629 """Only print the exception type and message, without a traceback.
629 """Only print the exception type and message, without a traceback.
630
630
631 Parameters
631 Parameters
632 ----------
632 ----------
633 etype : exception type
633 etype : exception type
634 value : exception value
634 value : exception value
635 """
635 """
636 # This method needs to use __call__ from *this* class, not the one from
636 # This method needs to use __call__ from *this* class, not the one from
637 # a subclass whose signature or behavior may be different
637 # a subclass whose signature or behavior may be different
638 ostream = self.ostream
638 ostream = self.ostream
639 ostream.flush()
639 ostream.flush()
640 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
640 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
641 ostream.flush()
641 ostream.flush()
642
642
643 def _some_str(self, value):
643 def _some_str(self, value):
644 # Lifted from traceback.py
644 # Lifted from traceback.py
645 try:
645 try:
646 return str(value)
646 return str(value)
647 except:
647 except:
648 return '<unprintable %s object>' % type(value).__name__
648 return '<unprintable %s object>' % type(value).__name__
649
649
650 #----------------------------------------------------------------------------
650 #----------------------------------------------------------------------------
651 class VerboseTB(TBTools):
651 class VerboseTB(TBTools):
652 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
652 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
653 of HTML. Requires inspect and pydoc. Crazy, man.
653 of HTML. Requires inspect and pydoc. Crazy, man.
654
654
655 Modified version which optionally strips the topmost entries from the
655 Modified version which optionally strips the topmost entries from the
656 traceback, to be used with alternate interpreters (because their own code
656 traceback, to be used with alternate interpreters (because their own code
657 would appear in the traceback)."""
657 would appear in the traceback)."""
658
658
659 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
659 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
660 tb_offset=0, long_header=False, include_vars=True,
660 tb_offset=0, long_header=False, include_vars=True,
661 check_cache=None):
661 check_cache=None):
662 """Specify traceback offset, headers and color scheme.
662 """Specify traceback offset, headers and color scheme.
663
663
664 Define how many frames to drop from the tracebacks. Calling it with
664 Define how many frames to drop from the tracebacks. Calling it with
665 tb_offset=1 allows use of this handler in interpreters which will have
665 tb_offset=1 allows use of this handler in interpreters which will have
666 their own code at the top of the traceback (VerboseTB will first
666 their own code at the top of the traceback (VerboseTB will first
667 remove that frame before printing the traceback info)."""
667 remove that frame before printing the traceback info)."""
668 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
668 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
669 ostream=ostream)
669 ostream=ostream)
670 self.tb_offset = tb_offset
670 self.tb_offset = tb_offset
671 self.long_header = long_header
671 self.long_header = long_header
672 self.include_vars = include_vars
672 self.include_vars = include_vars
673 # By default we use linecache.checkcache, but the user can provide a
673 # By default we use linecache.checkcache, but the user can provide a
674 # different check_cache implementation. This is used by the IPython
674 # different check_cache implementation. This is used by the IPython
675 # kernel to provide tracebacks for interactive code that is cached,
675 # kernel to provide tracebacks for interactive code that is cached,
676 # by a compiler instance that flushes the linecache but preserves its
676 # by a compiler instance that flushes the linecache but preserves its
677 # own code cache.
677 # own code cache.
678 if check_cache is None:
678 if check_cache is None:
679 check_cache = linecache.checkcache
679 check_cache = linecache.checkcache
680 self.check_cache = check_cache
680 self.check_cache = check_cache
681
681
682 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
682 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
683 context=5):
683 context=5):
684 """Return a nice text document describing the traceback."""
684 """Return a nice text document describing the traceback."""
685
685
686 tb_offset = self.tb_offset if tb_offset is None else tb_offset
686 tb_offset = self.tb_offset if tb_offset is None else tb_offset
687
687
688 # some locals
688 # some locals
689 try:
689 try:
690 etype = etype.__name__
690 etype = etype.__name__
691 except AttributeError:
691 except AttributeError:
692 pass
692 pass
693 Colors = self.Colors # just a shorthand + quicker name lookup
693 Colors = self.Colors # just a shorthand + quicker name lookup
694 ColorsNormal = Colors.Normal # used a lot
694 ColorsNormal = Colors.Normal # used a lot
695 col_scheme = self.color_scheme_table.active_scheme_name
695 col_scheme = self.color_scheme_table.active_scheme_name
696 indent = ' '*INDENT_SIZE
696 indent = ' '*INDENT_SIZE
697 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
697 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
698 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
698 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
699 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
699 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
700
700
701 # some internal-use functions
701 # some internal-use functions
702 def text_repr(value):
702 def text_repr(value):
703 """Hopefully pretty robust repr equivalent."""
703 """Hopefully pretty robust repr equivalent."""
704 # this is pretty horrible but should always return *something*
704 # this is pretty horrible but should always return *something*
705 try:
705 try:
706 return pydoc.text.repr(value)
706 return pydoc.text.repr(value)
707 except KeyboardInterrupt:
707 except KeyboardInterrupt:
708 raise
708 raise
709 except:
709 except:
710 try:
710 try:
711 return repr(value)
711 return repr(value)
712 except KeyboardInterrupt:
712 except KeyboardInterrupt:
713 raise
713 raise
714 except:
714 except:
715 try:
715 try:
716 # all still in an except block so we catch
716 # all still in an except block so we catch
717 # getattr raising
717 # getattr raising
718 name = getattr(value, '__name__', None)
718 name = getattr(value, '__name__', None)
719 if name:
719 if name:
720 # ick, recursion
720 # ick, recursion
721 return text_repr(name)
721 return text_repr(name)
722 klass = getattr(value, '__class__', None)
722 klass = getattr(value, '__class__', None)
723 if klass:
723 if klass:
724 return '%s instance' % text_repr(klass)
724 return '%s instance' % text_repr(klass)
725 except KeyboardInterrupt:
725 except KeyboardInterrupt:
726 raise
726 raise
727 except:
727 except:
728 return 'UNRECOVERABLE REPR FAILURE'
728 return 'UNRECOVERABLE REPR FAILURE'
729 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
729 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
730 def nullrepr(value, repr=text_repr): return ''
730 def nullrepr(value, repr=text_repr): return ''
731
731
732 # meat of the code begins
732 # meat of the code begins
733 try:
733 try:
734 etype = etype.__name__
734 etype = etype.__name__
735 except AttributeError:
735 except AttributeError:
736 pass
736 pass
737
737
738 if self.long_header:
738 if self.long_header:
739 # Header with the exception type, python version, and date
739 # Header with the exception type, python version, and date
740 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
740 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
741 date = time.ctime(time.time())
741 date = time.ctime(time.time())
742
742
743 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
743 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
744 exc, ' '*(75-len(str(etype))-len(pyver)),
744 exc, ' '*(75-len(str(etype))-len(pyver)),
745 pyver, date.rjust(75) )
745 pyver, date.rjust(75) )
746 head += "\nA problem occured executing Python code. Here is the sequence of function"\
746 head += "\nA problem occured executing Python code. Here is the sequence of function"\
747 "\ncalls leading up to the error, with the most recent (innermost) call last."
747 "\ncalls leading up to the error, with the most recent (innermost) call last."
748 else:
748 else:
749 # Simplified header
749 # Simplified header
750 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
750 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
751 'Traceback (most recent call last)'.\
751 'Traceback (most recent call last)'.\
752 rjust(75 - len(str(etype)) ) )
752 rjust(75 - len(str(etype)) ) )
753 frames = []
753 frames = []
754 # Flush cache before calling inspect. This helps alleviate some of the
754 # Flush cache before calling inspect. This helps alleviate some of the
755 # problems with python 2.3's inspect.py.
755 # problems with python 2.3's inspect.py.
756 ##self.check_cache()
756 ##self.check_cache()
757 # Drop topmost frames if requested
757 # Drop topmost frames if requested
758 try:
758 try:
759 # Try the default getinnerframes and Alex's: Alex's fixes some
759 # Try the default getinnerframes and Alex's: Alex's fixes some
760 # problems, but it generates empty tracebacks for console errors
760 # problems, but it generates empty tracebacks for console errors
761 # (5 blanks lines) where none should be returned.
761 # (5 blanks lines) where none should be returned.
762 #records = inspect.getinnerframes(etb, context)[tb_offset:]
762 #records = inspect.getinnerframes(etb, context)[tb_offset:]
763 #print 'python records:', records # dbg
763 #print 'python records:', records # dbg
764 records = _fixed_getinnerframes(etb, context, tb_offset)
764 records = _fixed_getinnerframes(etb, context, tb_offset)
765 #print 'alex records:', records # dbg
765 #print 'alex records:', records # dbg
766 except:
766 except:
767
767
768 # FIXME: I've been getting many crash reports from python 2.3
768 # FIXME: I've been getting many crash reports from python 2.3
769 # users, traceable to inspect.py. If I can find a small test-case
769 # users, traceable to inspect.py. If I can find a small test-case
770 # to reproduce this, I should either write a better workaround or
770 # to reproduce this, I should either write a better workaround or
771 # file a bug report against inspect (if that's the real problem).
771 # file a bug report against inspect (if that's the real problem).
772 # So far, I haven't been able to find an isolated example to
772 # So far, I haven't been able to find an isolated example to
773 # reproduce the problem.
773 # reproduce the problem.
774 inspect_error()
774 inspect_error()
775 traceback.print_exc(file=self.ostream)
775 traceback.print_exc(file=self.ostream)
776 info('\nUnfortunately, your original traceback can not be constructed.\n')
776 info('\nUnfortunately, your original traceback can not be constructed.\n')
777 return ''
777 return ''
778
778
779 # build some color string templates outside these nested loops
779 # build some color string templates outside these nested loops
780 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
780 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
781 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
781 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
782 ColorsNormal)
782 ColorsNormal)
783 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
783 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
784 (Colors.vName, Colors.valEm, ColorsNormal)
784 (Colors.vName, Colors.valEm, ColorsNormal)
785 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
785 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
786 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
786 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
787 Colors.vName, ColorsNormal)
787 Colors.vName, ColorsNormal)
788 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
788 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
789 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
789 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
790 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
790 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
791 ColorsNormal)
791 ColorsNormal)
792
792
793 # now, loop over all records printing context and info
793 # now, loop over all records printing context and info
794 abspath = os.path.abspath
794 abspath = os.path.abspath
795 for frame, file, lnum, func, lines, index in records:
795 for frame, file, lnum, func, lines, index in records:
796 #print '*** record:',file,lnum,func,lines,index # dbg
796 #print '*** record:',file,lnum,func,lines,index # dbg
797 if not file:
797 if not file:
798 file = '?'
798 file = '?'
799 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
799 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
800 # Guess that filenames like <string> aren't real filenames, so
800 # Guess that filenames like <string> aren't real filenames, so
801 # don't call abspath on them.
801 # don't call abspath on them.
802 try:
802 try:
803 file = abspath(file)
803 file = abspath(file)
804 except OSError:
804 except OSError:
805 # Not sure if this can still happen: abspath now works with
805 # Not sure if this can still happen: abspath now works with
806 # file names like <string>
806 # file names like <string>
807 pass
807 pass
808 file = py3compat.cast_unicode(file, util_path.fs_encoding)
808 file = py3compat.cast_unicode(file, util_path.fs_encoding)
809 link = tpl_link % file
809 link = tpl_link % file
810 args, varargs, varkw, locals = inspect.getargvalues(frame)
810 args, varargs, varkw, locals = inspect.getargvalues(frame)
811
811
812 if func == '?':
812 if func == '?':
813 call = ''
813 call = ''
814 else:
814 else:
815 # Decide whether to include variable details or not
815 # Decide whether to include variable details or not
816 var_repr = self.include_vars and eqrepr or nullrepr
816 var_repr = self.include_vars and eqrepr or nullrepr
817 try:
817 try:
818 call = tpl_call % (func,inspect.formatargvalues(args,
818 call = tpl_call % (func,inspect.formatargvalues(args,
819 varargs, varkw,
819 varargs, varkw,
820 locals,formatvalue=var_repr))
820 locals,formatvalue=var_repr))
821 except KeyError:
821 except KeyError:
822 # This happens in situations like errors inside generator
822 # This happens in situations like errors inside generator
823 # expressions, where local variables are listed in the
823 # expressions, where local variables are listed in the
824 # line, but can't be extracted from the frame. I'm not
824 # line, but can't be extracted from the frame. I'm not
825 # 100% sure this isn't actually a bug in inspect itself,
825 # 100% sure this isn't actually a bug in inspect itself,
826 # but since there's no info for us to compute with, the
826 # but since there's no info for us to compute with, the
827 # best we can do is report the failure and move on. Here
827 # best we can do is report the failure and move on. Here
828 # we must *not* call any traceback construction again,
828 # we must *not* call any traceback construction again,
829 # because that would mess up use of %debug later on. So we
829 # because that would mess up use of %debug later on. So we
830 # simply report the failure and move on. The only
830 # simply report the failure and move on. The only
831 # limitation will be that this frame won't have locals
831 # limitation will be that this frame won't have locals
832 # listed in the call signature. Quite subtle problem...
832 # listed in the call signature. Quite subtle problem...
833 # I can't think of a good way to validate this in a unit
833 # I can't think of a good way to validate this in a unit
834 # test, but running a script consisting of:
834 # test, but running a script consisting of:
835 # dict( (k,v.strip()) for (k,v) in range(10) )
835 # dict( (k,v.strip()) for (k,v) in range(10) )
836 # will illustrate the error, if this exception catch is
836 # will illustrate the error, if this exception catch is
837 # disabled.
837 # disabled.
838 call = tpl_call_fail % func
838 call = tpl_call_fail % func
839
839
840 # Don't attempt to tokenize binary files.
840 # Don't attempt to tokenize binary files.
841 if file.endswith(('.so', '.pyd', '.dll')):
841 if file.endswith(('.so', '.pyd', '.dll')):
842 frames.append('%s %s\n' % (link,call))
842 frames.append('%s %s\n' % (link,call))
843 continue
843 continue
844 elif file.endswith(('.pyc','.pyo')):
844 elif file.endswith(('.pyc','.pyo')):
845 # Look up the corresponding source file.
845 # Look up the corresponding source file.
846 file = openpy.source_from_cache(file)
846 file = openpy.source_from_cache(file)
847
847
848 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
848 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
849 line = getline(file, lnum[0])
849 line = getline(file, lnum[0])
850 lnum[0] += 1
850 lnum[0] += 1
851 return line
851 return line
852
852
853 # Build the list of names on this line of code where the exception
853 # Build the list of names on this line of code where the exception
854 # occurred.
854 # occurred.
855 try:
855 try:
856 names = []
856 names = []
857 name_cont = False
857 name_cont = False
858
858
859 for token_type, token, start, end, line in generate_tokens(linereader):
859 for token_type, token, start, end, line in generate_tokens(linereader):
860 # build composite names
860 # build composite names
861 if token_type == tokenize.NAME and token not in keyword.kwlist:
861 if token_type == tokenize.NAME and token not in keyword.kwlist:
862 if name_cont:
862 if name_cont:
863 # Continuation of a dotted name
863 # Continuation of a dotted name
864 try:
864 try:
865 names[-1].append(token)
865 names[-1].append(token)
866 except IndexError:
866 except IndexError:
867 names.append([token])
867 names.append([token])
868 name_cont = False
868 name_cont = False
869 else:
869 else:
870 # Regular new names. We append everything, the caller
870 # Regular new names. We append everything, the caller
871 # will be responsible for pruning the list later. It's
871 # will be responsible for pruning the list later. It's
872 # very tricky to try to prune as we go, b/c composite
872 # very tricky to try to prune as we go, b/c composite
873 # names can fool us. The pruning at the end is easy
873 # names can fool us. The pruning at the end is easy
874 # to do (or the caller can print a list with repeated
874 # to do (or the caller can print a list with repeated
875 # names if so desired.
875 # names if so desired.
876 names.append([token])
876 names.append([token])
877 elif token == '.':
877 elif token == '.':
878 name_cont = True
878 name_cont = True
879 elif token_type == tokenize.NEWLINE:
879 elif token_type == tokenize.NEWLINE:
880 break
880 break
881
881
882 except (IndexError, UnicodeDecodeError):
882 except (IndexError, UnicodeDecodeError):
883 # signals exit of tokenizer
883 # signals exit of tokenizer
884 pass
884 pass
885 except tokenize.TokenError as msg:
885 except tokenize.TokenError as msg:
886 _m = ("An unexpected error occurred while tokenizing input\n"
886 _m = ("An unexpected error occurred while tokenizing input\n"
887 "The following traceback may be corrupted or invalid\n"
887 "The following traceback may be corrupted or invalid\n"
888 "The error message is: %s\n" % msg)
888 "The error message is: %s\n" % msg)
889 error(_m)
889 error(_m)
890
890
891 # Join composite names (e.g. "dict.fromkeys")
891 # Join composite names (e.g. "dict.fromkeys")
892 names = ['.'.join(n) for n in names]
892 names = ['.'.join(n) for n in names]
893 # prune names list of duplicates, but keep the right order
893 # prune names list of duplicates, but keep the right order
894 unique_names = uniq_stable(names)
894 unique_names = uniq_stable(names)
895
895
896 # Start loop over vars
896 # Start loop over vars
897 lvals = []
897 lvals = []
898 if self.include_vars:
898 if self.include_vars:
899 for name_full in unique_names:
899 for name_full in unique_names:
900 name_base = name_full.split('.',1)[0]
900 name_base = name_full.split('.',1)[0]
901 if name_base in frame.f_code.co_varnames:
901 if name_base in frame.f_code.co_varnames:
902 if name_base in locals:
902 if name_base in locals:
903 try:
903 try:
904 value = repr(eval(name_full,locals))
904 value = repr(eval(name_full,locals))
905 except:
905 except:
906 value = undefined
906 value = undefined
907 else:
907 else:
908 value = undefined
908 value = undefined
909 name = tpl_local_var % name_full
909 name = tpl_local_var % name_full
910 else:
910 else:
911 if name_base in frame.f_globals:
911 if name_base in frame.f_globals:
912 try:
912 try:
913 value = repr(eval(name_full,frame.f_globals))
913 value = repr(eval(name_full,frame.f_globals))
914 except:
914 except:
915 value = undefined
915 value = undefined
916 else:
916 else:
917 value = undefined
917 value = undefined
918 name = tpl_global_var % name_full
918 name = tpl_global_var % name_full
919 lvals.append(tpl_name_val % (name,value))
919 lvals.append(tpl_name_val % (name,value))
920 if lvals:
920 if lvals:
921 lvals = '%s%s' % (indent,em_normal.join(lvals))
921 lvals = '%s%s' % (indent,em_normal.join(lvals))
922 else:
922 else:
923 lvals = ''
923 lvals = ''
924
924
925 level = '%s %s\n' % (link,call)
925 level = '%s %s\n' % (link,call)
926
926
927 if index is None:
927 if index is None:
928 frames.append(level)
928 frames.append(level)
929 else:
929 else:
930 frames.append('%s%s' % (level,''.join(
930 frames.append('%s%s' % (level,''.join(
931 _format_traceback_lines(lnum,index,lines,Colors,lvals,
931 _format_traceback_lines(lnum,index,lines,Colors,lvals,
932 col_scheme))))
932 col_scheme))))
933
933
934 # Get (safely) a string form of the exception info
934 # Get (safely) a string form of the exception info
935 try:
935 try:
936 etype_str,evalue_str = map(str,(etype,evalue))
936 etype_str,evalue_str = map(str,(etype,evalue))
937 except:
937 except:
938 # User exception is improperly defined.
938 # User exception is improperly defined.
939 etype,evalue = str,sys.exc_info()[:2]
939 etype,evalue = str,sys.exc_info()[:2]
940 etype_str,evalue_str = map(str,(etype,evalue))
940 etype_str,evalue_str = map(str,(etype,evalue))
941 # ... and format it
941 # ... and format it
942 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
942 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
943 ColorsNormal, py3compat.cast_unicode(evalue_str))]
943 ColorsNormal, py3compat.cast_unicode(evalue_str))]
944 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
944 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
945 try:
945 try:
946 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
946 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
947 except:
947 except:
948 # Every now and then, an object with funny inernals blows up
948 # Every now and then, an object with funny inernals blows up
949 # when dir() is called on it. We do the best we can to report
949 # when dir() is called on it. We do the best we can to report
950 # the problem and continue
950 # the problem and continue
951 _m = '%sException reporting error (object with broken dir())%s:'
951 _m = '%sException reporting error (object with broken dir())%s:'
952 exception.append(_m % (Colors.excName,ColorsNormal))
952 exception.append(_m % (Colors.excName,ColorsNormal))
953 etype_str,evalue_str = map(str,sys.exc_info()[:2])
953 etype_str,evalue_str = map(str,sys.exc_info()[:2])
954 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
954 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
955 ColorsNormal, py3compat.cast_unicode(evalue_str)))
955 ColorsNormal, py3compat.cast_unicode(evalue_str)))
956 names = []
956 names = []
957 for name in names:
957 for name in names:
958 value = text_repr(getattr(evalue, name))
958 value = text_repr(getattr(evalue, name))
959 exception.append('\n%s%s = %s' % (indent, name, value))
959 exception.append('\n%s%s = %s' % (indent, name, value))
960
960
961 # vds: >>
961 # vds: >>
962 if records:
962 if records:
963 filepath, lnum = records[-1][1:3]
963 filepath, lnum = records[-1][1:3]
964 #print "file:", str(file), "linenb", str(lnum) # dbg
964 #print "file:", str(file), "linenb", str(lnum) # dbg
965 filepath = os.path.abspath(filepath)
965 filepath = os.path.abspath(filepath)
966 ipinst = get_ipython()
966 ipinst = get_ipython()
967 if ipinst is not None:
967 if ipinst is not None:
968 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
968 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
969 # vds: <<
969 # vds: <<
970
970
971 # return all our info assembled as a single string
971 # return all our info assembled as a single string
972 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
972 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
973 return [head] + frames + [''.join(exception[0])]
973 return [head] + frames + [''.join(exception[0])]
974
974
975 def debugger(self,force=False):
975 def debugger(self,force=False):
976 """Call up the pdb debugger if desired, always clean up the tb
976 """Call up the pdb debugger if desired, always clean up the tb
977 reference.
977 reference.
978
978
979 Keywords:
979 Keywords:
980
980
981 - force(False): by default, this routine checks the instance call_pdb
981 - force(False): by default, this routine checks the instance call_pdb
982 flag and does not actually invoke the debugger if the flag is false.
982 flag and does not actually invoke the debugger if the flag is false.
983 The 'force' option forces the debugger to activate even if the flag
983 The 'force' option forces the debugger to activate even if the flag
984 is false.
984 is false.
985
985
986 If the call_pdb flag is set, the pdb interactive debugger is
986 If the call_pdb flag is set, the pdb interactive debugger is
987 invoked. In all cases, the self.tb reference to the current traceback
987 invoked. In all cases, the self.tb reference to the current traceback
988 is deleted to prevent lingering references which hamper memory
988 is deleted to prevent lingering references which hamper memory
989 management.
989 management.
990
990
991 Note that each call to pdb() does an 'import readline', so if your app
991 Note that each call to pdb() does an 'import readline', so if your app
992 requires a special setup for the readline completers, you'll have to
992 requires a special setup for the readline completers, you'll have to
993 fix that by hand after invoking the exception handler."""
993 fix that by hand after invoking the exception handler."""
994
994
995 if force or self.call_pdb:
995 if force or self.call_pdb:
996 if self.pdb is None:
996 if self.pdb is None:
997 self.pdb = debugger.Pdb(
997 self.pdb = debugger.Pdb(
998 self.color_scheme_table.active_scheme_name)
998 self.color_scheme_table.active_scheme_name)
999 # the system displayhook may have changed, restore the original
999 # the system displayhook may have changed, restore the original
1000 # for pdb
1000 # for pdb
1001 display_trap = DisplayTrap(hook=sys.__displayhook__)
1001 display_trap = DisplayTrap(hook=sys.__displayhook__)
1002 with display_trap:
1002 with display_trap:
1003 self.pdb.reset()
1003 self.pdb.reset()
1004 # Find the right frame so we don't pop up inside ipython itself
1004 # Find the right frame so we don't pop up inside ipython itself
1005 if hasattr(self,'tb') and self.tb is not None:
1005 if hasattr(self,'tb') and self.tb is not None:
1006 etb = self.tb
1006 etb = self.tb
1007 else:
1007 else:
1008 etb = self.tb = sys.last_traceback
1008 etb = self.tb = sys.last_traceback
1009 while self.tb is not None and self.tb.tb_next is not None:
1009 while self.tb is not None and self.tb.tb_next is not None:
1010 self.tb = self.tb.tb_next
1010 self.tb = self.tb.tb_next
1011 if etb and etb.tb_next:
1011 if etb and etb.tb_next:
1012 etb = etb.tb_next
1012 etb = etb.tb_next
1013 self.pdb.botframe = etb.tb_frame
1013 self.pdb.botframe = etb.tb_frame
1014 self.pdb.interaction(self.tb.tb_frame, self.tb)
1014 self.pdb.interaction(self.tb.tb_frame, self.tb)
1015
1015
1016 if hasattr(self,'tb'):
1016 if hasattr(self,'tb'):
1017 del self.tb
1017 del self.tb
1018
1018
1019 def handler(self, info=None):
1019 def handler(self, info=None):
1020 (etype, evalue, etb) = info or sys.exc_info()
1020 (etype, evalue, etb) = info or sys.exc_info()
1021 self.tb = etb
1021 self.tb = etb
1022 ostream = self.ostream
1022 ostream = self.ostream
1023 ostream.flush()
1023 ostream.flush()
1024 ostream.write(self.text(etype, evalue, etb))
1024 ostream.write(self.text(etype, evalue, etb))
1025 ostream.write('\n')
1025 ostream.write('\n')
1026 ostream.flush()
1026 ostream.flush()
1027
1027
1028 # Changed so an instance can just be called as VerboseTB_inst() and print
1028 # Changed so an instance can just be called as VerboseTB_inst() and print
1029 # out the right info on its own.
1029 # out the right info on its own.
1030 def __call__(self, etype=None, evalue=None, etb=None):
1030 def __call__(self, etype=None, evalue=None, etb=None):
1031 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1031 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1032 if etb is None:
1032 if etb is None:
1033 self.handler()
1033 self.handler()
1034 else:
1034 else:
1035 self.handler((etype, evalue, etb))
1035 self.handler((etype, evalue, etb))
1036 try:
1036 try:
1037 self.debugger()
1037 self.debugger()
1038 except KeyboardInterrupt:
1038 except KeyboardInterrupt:
1039 print("\nKeyboardInterrupt")
1039 print("\nKeyboardInterrupt")
1040
1040
1041 #----------------------------------------------------------------------------
1041 #----------------------------------------------------------------------------
1042 class FormattedTB(VerboseTB, ListTB):
1042 class FormattedTB(VerboseTB, ListTB):
1043 """Subclass ListTB but allow calling with a traceback.
1043 """Subclass ListTB but allow calling with a traceback.
1044
1044
1045 It can thus be used as a sys.excepthook for Python > 2.1.
1045 It can thus be used as a sys.excepthook for Python > 2.1.
1046
1046
1047 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1047 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1048
1048
1049 Allows a tb_offset to be specified. This is useful for situations where
1049 Allows a tb_offset to be specified. This is useful for situations where
1050 one needs to remove a number of topmost frames from the traceback (such as
1050 one needs to remove a number of topmost frames from the traceback (such as
1051 occurs with python programs that themselves execute other python code,
1051 occurs with python programs that themselves execute other python code,
1052 like Python shells). """
1052 like Python shells). """
1053
1053
1054 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1054 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1055 ostream=None,
1055 ostream=None,
1056 tb_offset=0, long_header=False, include_vars=False,
1056 tb_offset=0, long_header=False, include_vars=False,
1057 check_cache=None):
1057 check_cache=None):
1058
1058
1059 # NEVER change the order of this list. Put new modes at the end:
1059 # NEVER change the order of this list. Put new modes at the end:
1060 self.valid_modes = ['Plain','Context','Verbose']
1060 self.valid_modes = ['Plain','Context','Verbose']
1061 self.verbose_modes = self.valid_modes[1:3]
1061 self.verbose_modes = self.valid_modes[1:3]
1062
1062
1063 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1063 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1064 ostream=ostream, tb_offset=tb_offset,
1064 ostream=ostream, tb_offset=tb_offset,
1065 long_header=long_header, include_vars=include_vars,
1065 long_header=long_header, include_vars=include_vars,
1066 check_cache=check_cache)
1066 check_cache=check_cache)
1067
1067
1068 # Different types of tracebacks are joined with different separators to
1068 # Different types of tracebacks are joined with different separators to
1069 # form a single string. They are taken from this dict
1069 # form a single string. They are taken from this dict
1070 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1070 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1071 # set_mode also sets the tb_join_char attribute
1071 # set_mode also sets the tb_join_char attribute
1072 self.set_mode(mode)
1072 self.set_mode(mode)
1073
1073
1074 def _extract_tb(self,tb):
1074 def _extract_tb(self,tb):
1075 if tb:
1075 if tb:
1076 return traceback.extract_tb(tb)
1076 return traceback.extract_tb(tb)
1077 else:
1077 else:
1078 return None
1078 return None
1079
1079
1080 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1080 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1081 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1081 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1082 mode = self.mode
1082 mode = self.mode
1083 if mode in self.verbose_modes:
1083 if mode in self.verbose_modes:
1084 # Verbose modes need a full traceback
1084 # Verbose modes need a full traceback
1085 return VerboseTB.structured_traceback(
1085 return VerboseTB.structured_traceback(
1086 self, etype, value, tb, tb_offset, context
1086 self, etype, value, tb, tb_offset, context
1087 )
1087 )
1088 else:
1088 else:
1089 # We must check the source cache because otherwise we can print
1089 # We must check the source cache because otherwise we can print
1090 # out-of-date source code.
1090 # out-of-date source code.
1091 self.check_cache()
1091 self.check_cache()
1092 # Now we can extract and format the exception
1092 # Now we can extract and format the exception
1093 elist = self._extract_tb(tb)
1093 elist = self._extract_tb(tb)
1094 return ListTB.structured_traceback(
1094 return ListTB.structured_traceback(
1095 self, etype, value, elist, tb_offset, context
1095 self, etype, value, elist, tb_offset, context
1096 )
1096 )
1097
1097
1098 def stb2text(self, stb):
1098 def stb2text(self, stb):
1099 """Convert a structured traceback (a list) to a string."""
1099 """Convert a structured traceback (a list) to a string."""
1100 return self.tb_join_char.join(stb)
1100 return self.tb_join_char.join(stb)
1101
1101
1102
1102
1103 def set_mode(self,mode=None):
1103 def set_mode(self,mode=None):
1104 """Switch to the desired mode.
1104 """Switch to the desired mode.
1105
1105
1106 If mode is not specified, cycles through the available modes."""
1106 If mode is not specified, cycles through the available modes."""
1107
1107
1108 if not mode:
1108 if not mode:
1109 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1109 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1110 len(self.valid_modes)
1110 len(self.valid_modes)
1111 self.mode = self.valid_modes[new_idx]
1111 self.mode = self.valid_modes[new_idx]
1112 elif mode not in self.valid_modes:
1112 elif mode not in self.valid_modes:
1113 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1113 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1114 'Valid modes: '+str(self.valid_modes))
1114 'Valid modes: '+str(self.valid_modes))
1115 else:
1115 else:
1116 self.mode = mode
1116 self.mode = mode
1117 # include variable details only in 'Verbose' mode
1117 # include variable details only in 'Verbose' mode
1118 self.include_vars = (self.mode == self.valid_modes[2])
1118 self.include_vars = (self.mode == self.valid_modes[2])
1119 # Set the join character for generating text tracebacks
1119 # Set the join character for generating text tracebacks
1120 self.tb_join_char = self._join_chars[self.mode]
1120 self.tb_join_char = self._join_chars[self.mode]
1121
1121
1122 # some convenient shorcuts
1122 # some convenient shorcuts
1123 def plain(self):
1123 def plain(self):
1124 self.set_mode(self.valid_modes[0])
1124 self.set_mode(self.valid_modes[0])
1125
1125
1126 def context(self):
1126 def context(self):
1127 self.set_mode(self.valid_modes[1])
1127 self.set_mode(self.valid_modes[1])
1128
1128
1129 def verbose(self):
1129 def verbose(self):
1130 self.set_mode(self.valid_modes[2])
1130 self.set_mode(self.valid_modes[2])
1131
1131
1132 #----------------------------------------------------------------------------
1132 #----------------------------------------------------------------------------
1133 class AutoFormattedTB(FormattedTB):
1133 class AutoFormattedTB(FormattedTB):
1134 """A traceback printer which can be called on the fly.
1134 """A traceback printer which can be called on the fly.
1135
1135
1136 It will find out about exceptions by itself.
1136 It will find out about exceptions by itself.
1137
1137
1138 A brief example::
1138 A brief example::
1139
1139
1140 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1140 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1141 try:
1141 try:
1142 ...
1142 ...
1143 except:
1143 except:
1144 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1144 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1145 """
1145 """
1146
1146
1147 def __call__(self,etype=None,evalue=None,etb=None,
1147 def __call__(self,etype=None,evalue=None,etb=None,
1148 out=None,tb_offset=None):
1148 out=None,tb_offset=None):
1149 """Print out a formatted exception traceback.
1149 """Print out a formatted exception traceback.
1150
1150
1151 Optional arguments:
1151 Optional arguments:
1152 - out: an open file-like object to direct output to.
1152 - out: an open file-like object to direct output to.
1153
1153
1154 - tb_offset: the number of frames to skip over in the stack, on a
1154 - tb_offset: the number of frames to skip over in the stack, on a
1155 per-call basis (this overrides temporarily the instance's tb_offset
1155 per-call basis (this overrides temporarily the instance's tb_offset
1156 given at initialization time. """
1156 given at initialization time. """
1157
1157
1158
1158
1159 if out is None:
1159 if out is None:
1160 out = self.ostream
1160 out = self.ostream
1161 out.flush()
1161 out.flush()
1162 out.write(self.text(etype, evalue, etb, tb_offset))
1162 out.write(self.text(etype, evalue, etb, tb_offset))
1163 out.write('\n')
1163 out.write('\n')
1164 out.flush()
1164 out.flush()
1165 # FIXME: we should remove the auto pdb behavior from here and leave
1165 # FIXME: we should remove the auto pdb behavior from here and leave
1166 # that to the clients.
1166 # that to the clients.
1167 try:
1167 try:
1168 self.debugger()
1168 self.debugger()
1169 except KeyboardInterrupt:
1169 except KeyboardInterrupt:
1170 print("\nKeyboardInterrupt")
1170 print("\nKeyboardInterrupt")
1171
1171
1172 def structured_traceback(self, etype=None, value=None, tb=None,
1172 def structured_traceback(self, etype=None, value=None, tb=None,
1173 tb_offset=None, context=5):
1173 tb_offset=None, context=5):
1174 if etype is None:
1174 if etype is None:
1175 etype,value,tb = sys.exc_info()
1175 etype,value,tb = sys.exc_info()
1176 self.tb = tb
1176 self.tb = tb
1177 return FormattedTB.structured_traceback(
1177 return FormattedTB.structured_traceback(
1178 self, etype, value, tb, tb_offset, context)
1178 self, etype, value, tb, tb_offset, context)
1179
1179
1180 #---------------------------------------------------------------------------
1180 #---------------------------------------------------------------------------
1181
1181
1182 # A simple class to preserve Nathan's original functionality.
1182 # A simple class to preserve Nathan's original functionality.
1183 class ColorTB(FormattedTB):
1183 class ColorTB(FormattedTB):
1184 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1184 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1185 def __init__(self,color_scheme='Linux',call_pdb=0):
1185 def __init__(self,color_scheme='Linux',call_pdb=0):
1186 FormattedTB.__init__(self,color_scheme=color_scheme,
1186 FormattedTB.__init__(self,color_scheme=color_scheme,
1187 call_pdb=call_pdb)
1187 call_pdb=call_pdb)
1188
1188
1189
1189
1190 class SyntaxTB(ListTB):
1190 class SyntaxTB(ListTB):
1191 """Extension which holds some state: the last exception value"""
1191 """Extension which holds some state: the last exception value"""
1192
1192
1193 def __init__(self,color_scheme = 'NoColor'):
1193 def __init__(self,color_scheme = 'NoColor'):
1194 ListTB.__init__(self,color_scheme)
1194 ListTB.__init__(self,color_scheme)
1195 self.last_syntax_error = None
1195 self.last_syntax_error = None
1196
1196
1197 def __call__(self, etype, value, elist):
1197 def __call__(self, etype, value, elist):
1198 self.last_syntax_error = value
1198 self.last_syntax_error = value
1199 ListTB.__call__(self,etype,value,elist)
1199 ListTB.__call__(self,etype,value,elist)
1200
1200
1201 def structured_traceback(self, etype, value, elist, tb_offset=None,
1201 def structured_traceback(self, etype, value, elist, tb_offset=None,
1202 context=5):
1202 context=5):
1203 # If the source file has been edited, the line in the syntax error can
1203 # If the source file has been edited, the line in the syntax error can
1204 # be wrong (retrieved from an outdated cache). This replaces it with
1204 # be wrong (retrieved from an outdated cache). This replaces it with
1205 # the current value.
1205 # the current value.
1206 if isinstance(value, SyntaxError) \
1206 if isinstance(value, SyntaxError) \
1207 and isinstance(value.filename, py3compat.string_types) \
1207 and isinstance(value.filename, py3compat.string_types) \
1208 and isinstance(value.lineno, int):
1208 and isinstance(value.lineno, int):
1209 linecache.checkcache(value.filename)
1209 linecache.checkcache(value.filename)
1210 newtext = ulinecache.getline(value.filename, value.lineno)
1210 newtext = ulinecache.getline(value.filename, value.lineno)
1211 if newtext:
1211 if newtext:
1212 value.text = newtext
1212 value.text = newtext
1213 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1213 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1214 tb_offset=tb_offset, context=context)
1214 tb_offset=tb_offset, context=context)
1215
1215
1216 def clear_err_state(self):
1216 def clear_err_state(self):
1217 """Return the current error state and clear it"""
1217 """Return the current error state and clear it"""
1218 e = self.last_syntax_error
1218 e = self.last_syntax_error
1219 self.last_syntax_error = None
1219 self.last_syntax_error = None
1220 return e
1220 return e
1221
1221
1222 def stb2text(self, stb):
1222 def stb2text(self, stb):
1223 """Convert a structured traceback (a list) to a string."""
1223 """Convert a structured traceback (a list) to a string."""
1224 return ''.join(stb)
1224 return ''.join(stb)
1225
1225
1226
1226
1227 #----------------------------------------------------------------------------
1227 #----------------------------------------------------------------------------
1228 # module testing (minimal)
1228 # module testing (minimal)
1229 if __name__ == "__main__":
1229 if __name__ == "__main__":
1230 def spam(c, d_e):
1230 def spam(c, d_e):
1231 (d, e) = d_e
1231 (d, e) = d_e
1232 x = c + d
1232 x = c + d
1233 y = c * d
1233 y = c * d
1234 foo(x, y)
1234 foo(x, y)
1235
1235
1236 def foo(a, b, bar=1):
1236 def foo(a, b, bar=1):
1237 eggs(a, b + bar)
1237 eggs(a, b + bar)
1238
1238
1239 def eggs(f, g, z=globals()):
1239 def eggs(f, g, z=globals()):
1240 h = f + g
1240 h = f + g
1241 i = f - g
1241 i = f - g
1242 return h / i
1242 return h / i
1243
1243
1244 print('')
1244 print('')
1245 print('*** Before ***')
1245 print('*** Before ***')
1246 try:
1246 try:
1247 print(spam(1, (2, 3)))
1247 print(spam(1, (2, 3)))
1248 except:
1248 except:
1249 traceback.print_exc()
1249 traceback.print_exc()
1250 print('')
1250 print('')
1251
1251
1252 handler = ColorTB()
1252 handler = ColorTB()
1253 print('*** ColorTB ***')
1253 print('*** ColorTB ***')
1254 try:
1254 try:
1255 print(spam(1, (2, 3)))
1255 print(spam(1, (2, 3)))
1256 except:
1256 except:
1257 handler(*sys.exc_info())
1257 handler(*sys.exc_info())
1258 print('')
1258 print('')
1259
1259
1260 handler = VerboseTB()
1260 handler = VerboseTB()
1261 print('*** VerboseTB ***')
1261 print('*** VerboseTB ***')
1262 try:
1262 try:
1263 print(spam(1, (2, 3)))
1263 print(spam(1, (2, 3)))
1264 except:
1264 except:
1265 handler(*sys.exc_info())
1265 handler(*sys.exc_info())
1266 print('')
1266 print('')
1267
1267
@@ -1,509 +1,509 b''
1 """IPython extension to reload modules before executing user code.
1 """IPython extension to reload modules before executing user code.
2
2
3 ``autoreload`` reloads modules automatically before entering the execution of
3 ``autoreload`` reloads modules automatically before entering the execution of
4 code typed at the IPython prompt.
4 code typed at the IPython prompt.
5
5
6 This makes for example the following workflow possible:
6 This makes for example the following workflow possible:
7
7
8 .. sourcecode:: ipython
8 .. sourcecode:: ipython
9
9
10 In [1]: %load_ext autoreload
10 In [1]: %load_ext autoreload
11
11
12 In [2]: %autoreload 2
12 In [2]: %autoreload 2
13
13
14 In [3]: from foo import some_function
14 In [3]: from foo import some_function
15
15
16 In [4]: some_function()
16 In [4]: some_function()
17 Out[4]: 42
17 Out[4]: 42
18
18
19 In [5]: # open foo.py in an editor and change some_function to return 43
19 In [5]: # open foo.py in an editor and change some_function to return 43
20
20
21 In [6]: some_function()
21 In [6]: some_function()
22 Out[6]: 43
22 Out[6]: 43
23
23
24 The module was reloaded without reloading it explicitly, and the object
24 The module was reloaded without reloading it explicitly, and the object
25 imported with ``from foo import ...`` was also updated.
25 imported with ``from foo import ...`` was also updated.
26
26
27 Usage
27 Usage
28 =====
28 =====
29
29
30 The following magic commands are provided:
30 The following magic commands are provided:
31
31
32 ``%autoreload``
32 ``%autoreload``
33
33
34 Reload all modules (except those excluded by ``%aimport``)
34 Reload all modules (except those excluded by ``%aimport``)
35 automatically now.
35 automatically now.
36
36
37 ``%autoreload 0``
37 ``%autoreload 0``
38
38
39 Disable automatic reloading.
39 Disable automatic reloading.
40
40
41 ``%autoreload 1``
41 ``%autoreload 1``
42
42
43 Reload all modules imported with ``%aimport`` every time before
43 Reload all modules imported with ``%aimport`` every time before
44 executing the Python code typed.
44 executing the Python code typed.
45
45
46 ``%autoreload 2``
46 ``%autoreload 2``
47
47
48 Reload all modules (except those excluded by ``%aimport``) every
48 Reload all modules (except those excluded by ``%aimport``) every
49 time before executing the Python code typed.
49 time before executing the Python code typed.
50
50
51 ``%aimport``
51 ``%aimport``
52
52
53 List modules which are to be automatically imported or not to be imported.
53 List modules which are to be automatically imported or not to be imported.
54
54
55 ``%aimport foo``
55 ``%aimport foo``
56
56
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
58
58
59 ``%aimport -foo``
59 ``%aimport -foo``
60
60
61 Mark module 'foo' to not be autoreloaded.
61 Mark module 'foo' to not be autoreloaded.
62
62
63 Caveats
63 Caveats
64 =======
64 =======
65
65
66 Reloading Python modules in a reliable way is in general difficult,
66 Reloading Python modules in a reliable way is in general difficult,
67 and unexpected things may occur. ``%autoreload`` tries to work around
67 and unexpected things may occur. ``%autoreload`` tries to work around
68 common pitfalls by replacing function code objects and parts of
68 common pitfalls by replacing function code objects and parts of
69 classes previously in the module with new versions. This makes the
69 classes previously in the module with new versions. This makes the
70 following things to work:
70 following things to work:
71
71
72 - Functions and classes imported via 'from xxx import foo' are upgraded
72 - Functions and classes imported via 'from xxx import foo' are upgraded
73 to new versions when 'xxx' is reloaded.
73 to new versions when 'xxx' is reloaded.
74
74
75 - Methods and properties of classes are upgraded on reload, so that
75 - Methods and properties of classes are upgraded on reload, so that
76 calling 'c.foo()' on an object 'c' created before the reload causes
76 calling 'c.foo()' on an object 'c' created before the reload causes
77 the new code for 'foo' to be executed.
77 the new code for 'foo' to be executed.
78
78
79 Some of the known remaining caveats are:
79 Some of the known remaining caveats are:
80
80
81 - Replacing code objects does not always succeed: changing a @property
81 - Replacing code objects does not always succeed: changing a @property
82 in a class to an ordinary method or a method to a member variable
82 in a class to an ordinary method or a method to a member variable
83 can cause problems (but in old objects only).
83 can cause problems (but in old objects only).
84
84
85 - Functions that are removed (eg. via monkey-patching) from a module
85 - Functions that are removed (eg. via monkey-patching) from a module
86 before it is reloaded are not upgraded.
86 before it is reloaded are not upgraded.
87
87
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
89 """
89 """
90 from __future__ import print_function
90 from __future__ import print_function
91
91
92 skip_doctest = True
92 skip_doctest = True
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Copyright (C) 2000 Thomas Heller
95 # Copyright (C) 2000 Thomas Heller
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
97 # Copyright (C) 2012 The IPython Development Team
97 # Copyright (C) 2012 The IPython Development Team
98 #
98 #
99 # Distributed under the terms of the BSD License. The full license is in
99 # Distributed under the terms of the BSD License. The full license is in
100 # the file COPYING, distributed as part of this software.
100 # the file COPYING, distributed as part of this software.
101 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
102 #
102 #
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
104 # code by Thomas Heller.
104 # code by Thomas Heller.
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Imports
107 # Imports
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 import os
110 import os
111 import sys
111 import sys
112 import traceback
112 import traceback
113 import types
113 import types
114 import weakref
114 import weakref
115
115
116 try:
116 try:
117 # Reload is not defined by default in Python3.
117 # Reload is not defined by default in Python3.
118 reload
118 reload
119 except NameError:
119 except NameError:
120 from imp import reload
120 from imp import reload
121
121
122 from IPython.utils import openpy
122 from IPython.utils import openpy
123 from IPython.utils.py3compat import PY3
123 from IPython.utils.py3compat import PY3
124
124
125 #------------------------------------------------------------------------------
125 #------------------------------------------------------------------------------
126 # Autoreload functionality
126 # Autoreload functionality
127 #------------------------------------------------------------------------------
127 #------------------------------------------------------------------------------
128
128
129 class ModuleReloader(object):
129 class ModuleReloader(object):
130 enabled = False
130 enabled = False
131 """Whether this reloader is enabled"""
131 """Whether this reloader is enabled"""
132
132
133 failed = {}
133 failed = {}
134 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
134 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
135
135
136 modules = {}
136 modules = {}
137 """Modules specially marked as autoreloadable."""
137 """Modules specially marked as autoreloadable."""
138
138
139 skip_modules = {}
139 skip_modules = {}
140 """Modules specially marked as not autoreloadable."""
140 """Modules specially marked as not autoreloadable."""
141
141
142 check_all = True
142 check_all = True
143 """Autoreload all modules, not just those listed in 'modules'"""
143 """Autoreload all modules, not just those listed in 'modules'"""
144
144
145 old_objects = {}
145 old_objects = {}
146 """(module-name, name) -> weakref, for replacing old code objects"""
146 """(module-name, name) -> weakref, for replacing old code objects"""
147
147
148 def mark_module_skipped(self, module_name):
148 def mark_module_skipped(self, module_name):
149 """Skip reloading the named module in the future"""
149 """Skip reloading the named module in the future"""
150 try:
150 try:
151 del self.modules[module_name]
151 del self.modules[module_name]
152 except KeyError:
152 except KeyError:
153 pass
153 pass
154 self.skip_modules[module_name] = True
154 self.skip_modules[module_name] = True
155
155
156 def mark_module_reloadable(self, module_name):
156 def mark_module_reloadable(self, module_name):
157 """Reload the named module in the future (if it is imported)"""
157 """Reload the named module in the future (if it is imported)"""
158 try:
158 try:
159 del self.skip_modules[module_name]
159 del self.skip_modules[module_name]
160 except KeyError:
160 except KeyError:
161 pass
161 pass
162 self.modules[module_name] = True
162 self.modules[module_name] = True
163
163
164 def aimport_module(self, module_name):
164 def aimport_module(self, module_name):
165 """Import a module, and mark it reloadable
165 """Import a module, and mark it reloadable
166
166
167 Returns
167 Returns
168 -------
168 -------
169 top_module : module
169 top_module : module
170 The imported module if it is top-level, or the top-level
170 The imported module if it is top-level, or the top-level
171 top_name : module
171 top_name : module
172 Name of top_module
172 Name of top_module
173
173
174 """
174 """
175 self.mark_module_reloadable(module_name)
175 self.mark_module_reloadable(module_name)
176
176
177 __import__(module_name)
177 __import__(module_name)
178 top_name = module_name.split('.')[0]
178 top_name = module_name.split('.')[0]
179 top_module = sys.modules[top_name]
179 top_module = sys.modules[top_name]
180 return top_module, top_name
180 return top_module, top_name
181
181
182 def check(self, check_all=False):
182 def check(self, check_all=False):
183 """Check whether some modules need to be reloaded."""
183 """Check whether some modules need to be reloaded."""
184
184
185 if not self.enabled and not check_all:
185 if not self.enabled and not check_all:
186 return
186 return
187
187
188 if check_all or self.check_all:
188 if check_all or self.check_all:
189 modules = sys.modules.keys()
189 modules = sys.modules.keys()
190 else:
190 else:
191 modules = self.modules.keys()
191 modules = self.modules.keys()
192
192
193 for modname in modules:
193 for modname in modules:
194 m = sys.modules.get(modname, None)
194 m = sys.modules.get(modname, None)
195
195
196 if modname in self.skip_modules:
196 if modname in self.skip_modules:
197 continue
197 continue
198
198
199 if not hasattr(m, '__file__'):
199 if not hasattr(m, '__file__'):
200 continue
200 continue
201
201
202 if m.__name__ == '__main__':
202 if m.__name__ == '__main__':
203 # we cannot reload(__main__)
203 # we cannot reload(__main__)
204 continue
204 continue
205
205
206 filename = m.__file__
206 filename = m.__file__
207 path, ext = os.path.splitext(filename)
207 path, ext = os.path.splitext(filename)
208
208
209 if ext.lower() == '.py':
209 if ext.lower() == '.py':
210 pyc_filename = openpy.cache_from_source(filename)
210 pyc_filename = openpy.cache_from_source(filename)
211 py_filename = filename
211 py_filename = filename
212 else:
212 else:
213 pyc_filename = filename
213 pyc_filename = filename
214 try:
214 try:
215 py_filename = openpy.source_from_cache(filename)
215 py_filename = openpy.source_from_cache(filename)
216 except ValueError:
216 except ValueError:
217 continue
217 continue
218
218
219 try:
219 try:
220 pymtime = os.stat(py_filename).st_mtime
220 pymtime = os.stat(py_filename).st_mtime
221 if pymtime <= os.stat(pyc_filename).st_mtime:
221 if pymtime <= os.stat(pyc_filename).st_mtime:
222 continue
222 continue
223 if self.failed.get(py_filename, None) == pymtime:
223 if self.failed.get(py_filename, None) == pymtime:
224 continue
224 continue
225 except OSError:
225 except OSError:
226 continue
226 continue
227
227
228 try:
228 try:
229 superreload(m, reload, self.old_objects)
229 superreload(m, reload, self.old_objects)
230 if py_filename in self.failed:
230 if py_filename in self.failed:
231 del self.failed[py_filename]
231 del self.failed[py_filename]
232 except:
232 except:
233 print("[autoreload of %s failed: %s]" % (
233 print("[autoreload of %s failed: %s]" % (
234 modname, traceback.format_exc(1)), file=sys.stderr)
234 modname, traceback.format_exc(1)), file=sys.stderr)
235 self.failed[py_filename] = pymtime
235 self.failed[py_filename] = pymtime
236
236
237 #------------------------------------------------------------------------------
237 #------------------------------------------------------------------------------
238 # superreload
238 # superreload
239 #------------------------------------------------------------------------------
239 #------------------------------------------------------------------------------
240
240
241 if PY3:
241 if PY3:
242 func_attrs = ['__code__', '__defaults__', '__doc__',
242 func_attrs = ['__code__', '__defaults__', '__doc__',
243 '__closure__', '__globals__', '__dict__']
243 '__closure__', '__globals__', '__dict__']
244 else:
244 else:
245 func_attrs = ['func_code', 'func_defaults', 'func_doc',
245 func_attrs = ['func_code', 'func_defaults', 'func_doc',
246 'func_closure', 'func_globals', 'func_dict']
246 'func_closure', 'func_globals', 'func_dict']
247
247
248
248
249 def update_function(old, new):
249 def update_function(old, new):
250 """Upgrade the code object of a function"""
250 """Upgrade the code object of a function"""
251 for name in func_attrs:
251 for name in func_attrs:
252 try:
252 try:
253 setattr(old, name, getattr(new, name))
253 setattr(old, name, getattr(new, name))
254 except (AttributeError, TypeError):
254 except (AttributeError, TypeError):
255 pass
255 pass
256
256
257
257
258 def update_class(old, new):
258 def update_class(old, new):
259 """Replace stuff in the __dict__ of a class, and upgrade
259 """Replace stuff in the __dict__ of a class, and upgrade
260 method code objects"""
260 method code objects"""
261 for key in old.__dict__.keys():
261 for key in old.__dict__.keys():
262 old_obj = getattr(old, key)
262 old_obj = getattr(old, key)
263
263
264 try:
264 try:
265 new_obj = getattr(new, key)
265 new_obj = getattr(new, key)
266 except AttributeError:
266 except AttributeError:
267 # obsolete attribute: remove it
267 # obsolete attribute: remove it
268 try:
268 try:
269 delattr(old, key)
269 delattr(old, key)
270 except (AttributeError, TypeError):
270 except (AttributeError, TypeError):
271 pass
271 pass
272 continue
272 continue
273
273
274 if update_generic(old_obj, new_obj): continue
274 if update_generic(old_obj, new_obj): continue
275
275
276 try:
276 try:
277 setattr(old, key, getattr(new, key))
277 setattr(old, key, getattr(new, key))
278 except (AttributeError, TypeError):
278 except (AttributeError, TypeError):
279 pass # skip non-writable attributes
279 pass # skip non-writable attributes
280
280
281
281
282 def update_property(old, new):
282 def update_property(old, new):
283 """Replace get/set/del functions of a property"""
283 """Replace get/set/del functions of a property"""
284 update_generic(old.fdel, new.fdel)
284 update_generic(old.fdel, new.fdel)
285 update_generic(old.fget, new.fget)
285 update_generic(old.fget, new.fget)
286 update_generic(old.fset, new.fset)
286 update_generic(old.fset, new.fset)
287
287
288
288
289 def isinstance2(a, b, typ):
289 def isinstance2(a, b, typ):
290 return isinstance(a, typ) and isinstance(b, typ)
290 return isinstance(a, typ) and isinstance(b, typ)
291
291
292
292
293 UPDATE_RULES = [
293 UPDATE_RULES = [
294 (lambda a, b: isinstance2(a, b, type),
294 (lambda a, b: isinstance2(a, b, type),
295 update_class),
295 update_class),
296 (lambda a, b: isinstance2(a, b, types.FunctionType),
296 (lambda a, b: isinstance2(a, b, types.FunctionType),
297 update_function),
297 update_function),
298 (lambda a, b: isinstance2(a, b, property),
298 (lambda a, b: isinstance2(a, b, property),
299 update_property),
299 update_property),
300 ]
300 ]
301
301
302
302
303 if PY3:
303 if PY3:
304 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
304 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
305 lambda a, b: update_function(a.__func__, b.__func__)),
305 lambda a, b: update_function(a.__func__, b.__func__)),
306 ])
306 ])
307 else:
307 else:
308 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
308 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
309 update_class),
309 update_class),
310 (lambda a, b: isinstance2(a, b, types.MethodType),
310 (lambda a, b: isinstance2(a, b, types.MethodType),
311 lambda a, b: update_function(a.im_func, b.im_func)),
311 lambda a, b: update_function(a.__func__, b.__func__)),
312 ])
312 ])
313
313
314
314
315 def update_generic(a, b):
315 def update_generic(a, b):
316 for type_check, update in UPDATE_RULES:
316 for type_check, update in UPDATE_RULES:
317 if type_check(a, b):
317 if type_check(a, b):
318 update(a, b)
318 update(a, b)
319 return True
319 return True
320 return False
320 return False
321
321
322
322
323 class StrongRef(object):
323 class StrongRef(object):
324 def __init__(self, obj):
324 def __init__(self, obj):
325 self.obj = obj
325 self.obj = obj
326 def __call__(self):
326 def __call__(self):
327 return self.obj
327 return self.obj
328
328
329
329
330 def superreload(module, reload=reload, old_objects={}):
330 def superreload(module, reload=reload, old_objects={}):
331 """Enhanced version of the builtin reload function.
331 """Enhanced version of the builtin reload function.
332
332
333 superreload remembers objects previously in the module, and
333 superreload remembers objects previously in the module, and
334
334
335 - upgrades the class dictionary of every old class in the module
335 - upgrades the class dictionary of every old class in the module
336 - upgrades the code object of every old function and method
336 - upgrades the code object of every old function and method
337 - clears the module's namespace before reloading
337 - clears the module's namespace before reloading
338
338
339 """
339 """
340
340
341 # collect old objects in the module
341 # collect old objects in the module
342 for name, obj in module.__dict__.items():
342 for name, obj in module.__dict__.items():
343 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
343 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
344 continue
344 continue
345 key = (module.__name__, name)
345 key = (module.__name__, name)
346 try:
346 try:
347 old_objects.setdefault(key, []).append(weakref.ref(obj))
347 old_objects.setdefault(key, []).append(weakref.ref(obj))
348 except TypeError:
348 except TypeError:
349 # weakref doesn't work for all types;
349 # weakref doesn't work for all types;
350 # create strong references for 'important' cases
350 # create strong references for 'important' cases
351 if not PY3 and isinstance(obj, types.ClassType):
351 if not PY3 and isinstance(obj, types.ClassType):
352 old_objects.setdefault(key, []).append(StrongRef(obj))
352 old_objects.setdefault(key, []).append(StrongRef(obj))
353
353
354 # reload module
354 # reload module
355 try:
355 try:
356 # clear namespace first from old cruft
356 # clear namespace first from old cruft
357 old_dict = module.__dict__.copy()
357 old_dict = module.__dict__.copy()
358 old_name = module.__name__
358 old_name = module.__name__
359 module.__dict__.clear()
359 module.__dict__.clear()
360 module.__dict__['__name__'] = old_name
360 module.__dict__['__name__'] = old_name
361 module.__dict__['__loader__'] = old_dict['__loader__']
361 module.__dict__['__loader__'] = old_dict['__loader__']
362 except (TypeError, AttributeError, KeyError):
362 except (TypeError, AttributeError, KeyError):
363 pass
363 pass
364
364
365 try:
365 try:
366 module = reload(module)
366 module = reload(module)
367 except:
367 except:
368 # restore module dictionary on failed reload
368 # restore module dictionary on failed reload
369 module.__dict__.update(old_dict)
369 module.__dict__.update(old_dict)
370 raise
370 raise
371
371
372 # iterate over all objects and update functions & classes
372 # iterate over all objects and update functions & classes
373 for name, new_obj in module.__dict__.items():
373 for name, new_obj in module.__dict__.items():
374 key = (module.__name__, name)
374 key = (module.__name__, name)
375 if key not in old_objects: continue
375 if key not in old_objects: continue
376
376
377 new_refs = []
377 new_refs = []
378 for old_ref in old_objects[key]:
378 for old_ref in old_objects[key]:
379 old_obj = old_ref()
379 old_obj = old_ref()
380 if old_obj is None: continue
380 if old_obj is None: continue
381 new_refs.append(old_ref)
381 new_refs.append(old_ref)
382 update_generic(old_obj, new_obj)
382 update_generic(old_obj, new_obj)
383
383
384 if new_refs:
384 if new_refs:
385 old_objects[key] = new_refs
385 old_objects[key] = new_refs
386 else:
386 else:
387 del old_objects[key]
387 del old_objects[key]
388
388
389 return module
389 return module
390
390
391 #------------------------------------------------------------------------------
391 #------------------------------------------------------------------------------
392 # IPython connectivity
392 # IPython connectivity
393 #------------------------------------------------------------------------------
393 #------------------------------------------------------------------------------
394
394
395 from IPython.core.hooks import TryNext
395 from IPython.core.hooks import TryNext
396 from IPython.core.magic import Magics, magics_class, line_magic
396 from IPython.core.magic import Magics, magics_class, line_magic
397
397
398 @magics_class
398 @magics_class
399 class AutoreloadMagics(Magics):
399 class AutoreloadMagics(Magics):
400 def __init__(self, *a, **kw):
400 def __init__(self, *a, **kw):
401 super(AutoreloadMagics, self).__init__(*a, **kw)
401 super(AutoreloadMagics, self).__init__(*a, **kw)
402 self._reloader = ModuleReloader()
402 self._reloader = ModuleReloader()
403 self._reloader.check_all = False
403 self._reloader.check_all = False
404
404
405 @line_magic
405 @line_magic
406 def autoreload(self, parameter_s=''):
406 def autoreload(self, parameter_s=''):
407 r"""%autoreload => Reload modules automatically
407 r"""%autoreload => Reload modules automatically
408
408
409 %autoreload
409 %autoreload
410 Reload all modules (except those excluded by %aimport) automatically
410 Reload all modules (except those excluded by %aimport) automatically
411 now.
411 now.
412
412
413 %autoreload 0
413 %autoreload 0
414 Disable automatic reloading.
414 Disable automatic reloading.
415
415
416 %autoreload 1
416 %autoreload 1
417 Reload all modules imported with %aimport every time before executing
417 Reload all modules imported with %aimport every time before executing
418 the Python code typed.
418 the Python code typed.
419
419
420 %autoreload 2
420 %autoreload 2
421 Reload all modules (except those excluded by %aimport) every time
421 Reload all modules (except those excluded by %aimport) every time
422 before executing the Python code typed.
422 before executing the Python code typed.
423
423
424 Reloading Python modules in a reliable way is in general
424 Reloading Python modules in a reliable way is in general
425 difficult, and unexpected things may occur. %autoreload tries to
425 difficult, and unexpected things may occur. %autoreload tries to
426 work around common pitfalls by replacing function code objects and
426 work around common pitfalls by replacing function code objects and
427 parts of classes previously in the module with new versions. This
427 parts of classes previously in the module with new versions. This
428 makes the following things to work:
428 makes the following things to work:
429
429
430 - Functions and classes imported via 'from xxx import foo' are upgraded
430 - Functions and classes imported via 'from xxx import foo' are upgraded
431 to new versions when 'xxx' is reloaded.
431 to new versions when 'xxx' is reloaded.
432
432
433 - Methods and properties of classes are upgraded on reload, so that
433 - Methods and properties of classes are upgraded on reload, so that
434 calling 'c.foo()' on an object 'c' created before the reload causes
434 calling 'c.foo()' on an object 'c' created before the reload causes
435 the new code for 'foo' to be executed.
435 the new code for 'foo' to be executed.
436
436
437 Some of the known remaining caveats are:
437 Some of the known remaining caveats are:
438
438
439 - Replacing code objects does not always succeed: changing a @property
439 - Replacing code objects does not always succeed: changing a @property
440 in a class to an ordinary method or a method to a member variable
440 in a class to an ordinary method or a method to a member variable
441 can cause problems (but in old objects only).
441 can cause problems (but in old objects only).
442
442
443 - Functions that are removed (eg. via monkey-patching) from a module
443 - Functions that are removed (eg. via monkey-patching) from a module
444 before it is reloaded are not upgraded.
444 before it is reloaded are not upgraded.
445
445
446 - C extension modules cannot be reloaded, and so cannot be
446 - C extension modules cannot be reloaded, and so cannot be
447 autoreloaded.
447 autoreloaded.
448
448
449 """
449 """
450 if parameter_s == '':
450 if parameter_s == '':
451 self._reloader.check(True)
451 self._reloader.check(True)
452 elif parameter_s == '0':
452 elif parameter_s == '0':
453 self._reloader.enabled = False
453 self._reloader.enabled = False
454 elif parameter_s == '1':
454 elif parameter_s == '1':
455 self._reloader.check_all = False
455 self._reloader.check_all = False
456 self._reloader.enabled = True
456 self._reloader.enabled = True
457 elif parameter_s == '2':
457 elif parameter_s == '2':
458 self._reloader.check_all = True
458 self._reloader.check_all = True
459 self._reloader.enabled = True
459 self._reloader.enabled = True
460
460
461 @line_magic
461 @line_magic
462 def aimport(self, parameter_s='', stream=None):
462 def aimport(self, parameter_s='', stream=None):
463 """%aimport => Import modules for automatic reloading.
463 """%aimport => Import modules for automatic reloading.
464
464
465 %aimport
465 %aimport
466 List modules to automatically import and not to import.
466 List modules to automatically import and not to import.
467
467
468 %aimport foo
468 %aimport foo
469 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
469 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
470
470
471 %aimport -foo
471 %aimport -foo
472 Mark module 'foo' to not be autoreloaded for %autoreload 1
472 Mark module 'foo' to not be autoreloaded for %autoreload 1
473 """
473 """
474 modname = parameter_s
474 modname = parameter_s
475 if not modname:
475 if not modname:
476 to_reload = self._reloader.modules.keys()
476 to_reload = self._reloader.modules.keys()
477 to_reload.sort()
477 to_reload.sort()
478 to_skip = self._reloader.skip_modules.keys()
478 to_skip = self._reloader.skip_modules.keys()
479 to_skip.sort()
479 to_skip.sort()
480 if stream is None:
480 if stream is None:
481 stream = sys.stdout
481 stream = sys.stdout
482 if self._reloader.check_all:
482 if self._reloader.check_all:
483 stream.write("Modules to reload:\nall-except-skipped\n")
483 stream.write("Modules to reload:\nall-except-skipped\n")
484 else:
484 else:
485 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
485 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
486 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
486 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
487 elif modname.startswith('-'):
487 elif modname.startswith('-'):
488 modname = modname[1:]
488 modname = modname[1:]
489 self._reloader.mark_module_skipped(modname)
489 self._reloader.mark_module_skipped(modname)
490 else:
490 else:
491 top_module, top_name = self._reloader.aimport_module(modname)
491 top_module, top_name = self._reloader.aimport_module(modname)
492
492
493 # Inject module to user namespace
493 # Inject module to user namespace
494 self.shell.push({top_name: top_module})
494 self.shell.push({top_name: top_module})
495
495
496 def pre_run_code_hook(self, ip):
496 def pre_run_code_hook(self, ip):
497 if not self._reloader.enabled:
497 if not self._reloader.enabled:
498 raise TryNext
498 raise TryNext
499 try:
499 try:
500 self._reloader.check()
500 self._reloader.check()
501 except:
501 except:
502 pass
502 pass
503
503
504
504
505 def load_ipython_extension(ip):
505 def load_ipython_extension(ip):
506 """Load the extension in IPython."""
506 """Load the extension in IPython."""
507 auto_reload = AutoreloadMagics(ip)
507 auto_reload = AutoreloadMagics(ip)
508 ip.register_magics(auto_reload)
508 ip.register_magics(auto_reload)
509 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
509 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
@@ -1,764 +1,764 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by setting the
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 by interactively disabling it with %Pprint. This is required so that IPython
8 by interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import doctest
22 import doctest
23 import inspect
23 import inspect
24 import logging
24 import logging
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28 import traceback
28 import traceback
29 import unittest
29 import unittest
30
30
31 from inspect import getmodule
31 from inspect import getmodule
32
32
33 # We are overriding the default doctest runner, so we need to import a few
33 # We are overriding the default doctest runner, so we need to import a few
34 # things from doctest directly
34 # things from doctest directly
35 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
35 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
36 _unittest_reportflags, DocTestRunner,
36 _unittest_reportflags, DocTestRunner,
37 _extract_future_flags, pdb, _OutputRedirectingPdb,
37 _extract_future_flags, pdb, _OutputRedirectingPdb,
38 _exception_traceback,
38 _exception_traceback,
39 linecache)
39 linecache)
40
40
41 # Third-party modules
41 # Third-party modules
42 import nose.core
42 import nose.core
43
43
44 from nose.plugins import doctests, Plugin
44 from nose.plugins import doctests, Plugin
45 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
45 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
46
46
47 # Our own imports
47 # Our own imports
48 from IPython.utils.py3compat import builtin_mod, PY3
48 from IPython.utils.py3compat import builtin_mod, PY3
49
49
50 if PY3:
50 if PY3:
51 from io import StringIO
51 from io import StringIO
52 else:
52 else:
53 from StringIO import StringIO
53 from StringIO import StringIO
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Module globals and other constants
56 # Module globals and other constants
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Classes and functions
63 # Classes and functions
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 def is_extension_module(filename):
66 def is_extension_module(filename):
67 """Return whether the given filename is an extension module.
67 """Return whether the given filename is an extension module.
68
68
69 This simply checks that the extension is either .so or .pyd.
69 This simply checks that the extension is either .so or .pyd.
70 """
70 """
71 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
71 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
72
72
73
73
74 class DocTestSkip(object):
74 class DocTestSkip(object):
75 """Object wrapper for doctests to be skipped."""
75 """Object wrapper for doctests to be skipped."""
76
76
77 ds_skip = """Doctest to skip.
77 ds_skip = """Doctest to skip.
78 >>> 1 #doctest: +SKIP
78 >>> 1 #doctest: +SKIP
79 """
79 """
80
80
81 def __init__(self,obj):
81 def __init__(self,obj):
82 self.obj = obj
82 self.obj = obj
83
83
84 def __getattribute__(self,key):
84 def __getattribute__(self,key):
85 if key == '__doc__':
85 if key == '__doc__':
86 return DocTestSkip.ds_skip
86 return DocTestSkip.ds_skip
87 else:
87 else:
88 return getattr(object.__getattribute__(self,'obj'),key)
88 return getattr(object.__getattribute__(self,'obj'),key)
89
89
90 # Modified version of the one in the stdlib, that fixes a python bug (doctests
90 # Modified version of the one in the stdlib, that fixes a python bug (doctests
91 # not found in extension modules, http://bugs.python.org/issue3158)
91 # not found in extension modules, http://bugs.python.org/issue3158)
92 class DocTestFinder(doctest.DocTestFinder):
92 class DocTestFinder(doctest.DocTestFinder):
93
93
94 def _from_module(self, module, object):
94 def _from_module(self, module, object):
95 """
95 """
96 Return true if the given object is defined in the given
96 Return true if the given object is defined in the given
97 module.
97 module.
98 """
98 """
99 if module is None:
99 if module is None:
100 return True
100 return True
101 elif inspect.isfunction(object):
101 elif inspect.isfunction(object):
102 return module.__dict__ is object.__globals__
102 return module.__dict__ is object.__globals__
103 elif inspect.isbuiltin(object):
103 elif inspect.isbuiltin(object):
104 return module.__name__ == object.__module__
104 return module.__name__ == object.__module__
105 elif inspect.isclass(object):
105 elif inspect.isclass(object):
106 return module.__name__ == object.__module__
106 return module.__name__ == object.__module__
107 elif inspect.ismethod(object):
107 elif inspect.ismethod(object):
108 # This one may be a bug in cython that fails to correctly set the
108 # This one may be a bug in cython that fails to correctly set the
109 # __module__ attribute of methods, but since the same error is easy
109 # __module__ attribute of methods, but since the same error is easy
110 # to make by extension code writers, having this safety in place
110 # to make by extension code writers, having this safety in place
111 # isn't such a bad idea
111 # isn't such a bad idea
112 return module.__name__ == object.im_class.__module__
112 return module.__name__ == object.__self__.__class__.__module__
113 elif inspect.getmodule(object) is not None:
113 elif inspect.getmodule(object) is not None:
114 return module is inspect.getmodule(object)
114 return module is inspect.getmodule(object)
115 elif hasattr(object, '__module__'):
115 elif hasattr(object, '__module__'):
116 return module.__name__ == object.__module__
116 return module.__name__ == object.__module__
117 elif isinstance(object, property):
117 elif isinstance(object, property):
118 return True # [XX] no way not be sure.
118 return True # [XX] no way not be sure.
119 else:
119 else:
120 raise ValueError("object must be a class or function")
120 raise ValueError("object must be a class or function")
121
121
122 def _find(self, tests, obj, name, module, source_lines, globs, seen):
122 def _find(self, tests, obj, name, module, source_lines, globs, seen):
123 """
123 """
124 Find tests for the given object and any contained objects, and
124 Find tests for the given object and any contained objects, and
125 add them to `tests`.
125 add them to `tests`.
126 """
126 """
127 #print '_find for:', obj, name, module # dbg
127 #print '_find for:', obj, name, module # dbg
128 if hasattr(obj,"skip_doctest"):
128 if hasattr(obj,"skip_doctest"):
129 #print 'SKIPPING DOCTEST FOR:',obj # dbg
129 #print 'SKIPPING DOCTEST FOR:',obj # dbg
130 obj = DocTestSkip(obj)
130 obj = DocTestSkip(obj)
131
131
132 doctest.DocTestFinder._find(self,tests, obj, name, module,
132 doctest.DocTestFinder._find(self,tests, obj, name, module,
133 source_lines, globs, seen)
133 source_lines, globs, seen)
134
134
135 # Below we re-run pieces of the above method with manual modifications,
135 # Below we re-run pieces of the above method with manual modifications,
136 # because the original code is buggy and fails to correctly identify
136 # because the original code is buggy and fails to correctly identify
137 # doctests in extension modules.
137 # doctests in extension modules.
138
138
139 # Local shorthands
139 # Local shorthands
140 from inspect import isroutine, isclass, ismodule
140 from inspect import isroutine, isclass, ismodule
141
141
142 # Look for tests in a module's contained objects.
142 # Look for tests in a module's contained objects.
143 if inspect.ismodule(obj) and self._recurse:
143 if inspect.ismodule(obj) and self._recurse:
144 for valname, val in obj.__dict__.items():
144 for valname, val in obj.__dict__.items():
145 valname1 = '%s.%s' % (name, valname)
145 valname1 = '%s.%s' % (name, valname)
146 if ( (isroutine(val) or isclass(val))
146 if ( (isroutine(val) or isclass(val))
147 and self._from_module(module, val) ):
147 and self._from_module(module, val) ):
148
148
149 self._find(tests, val, valname1, module, source_lines,
149 self._find(tests, val, valname1, module, source_lines,
150 globs, seen)
150 globs, seen)
151
151
152 # Look for tests in a class's contained objects.
152 # Look for tests in a class's contained objects.
153 if inspect.isclass(obj) and self._recurse:
153 if inspect.isclass(obj) and self._recurse:
154 #print 'RECURSE into class:',obj # dbg
154 #print 'RECURSE into class:',obj # dbg
155 for valname, val in obj.__dict__.items():
155 for valname, val in obj.__dict__.items():
156 # Special handling for staticmethod/classmethod.
156 # Special handling for staticmethod/classmethod.
157 if isinstance(val, staticmethod):
157 if isinstance(val, staticmethod):
158 val = getattr(obj, valname)
158 val = getattr(obj, valname)
159 if isinstance(val, classmethod):
159 if isinstance(val, classmethod):
160 val = getattr(obj, valname).im_func
160 val = getattr(obj, valname).__func__
161
161
162 # Recurse to methods, properties, and nested classes.
162 # Recurse to methods, properties, and nested classes.
163 if ((inspect.isfunction(val) or inspect.isclass(val) or
163 if ((inspect.isfunction(val) or inspect.isclass(val) or
164 inspect.ismethod(val) or
164 inspect.ismethod(val) or
165 isinstance(val, property)) and
165 isinstance(val, property)) and
166 self._from_module(module, val)):
166 self._from_module(module, val)):
167 valname = '%s.%s' % (name, valname)
167 valname = '%s.%s' % (name, valname)
168 self._find(tests, val, valname, module, source_lines,
168 self._find(tests, val, valname, module, source_lines,
169 globs, seen)
169 globs, seen)
170
170
171
171
172 class IPDoctestOutputChecker(doctest.OutputChecker):
172 class IPDoctestOutputChecker(doctest.OutputChecker):
173 """Second-chance checker with support for random tests.
173 """Second-chance checker with support for random tests.
174
174
175 If the default comparison doesn't pass, this checker looks in the expected
175 If the default comparison doesn't pass, this checker looks in the expected
176 output string for flags that tell us to ignore the output.
176 output string for flags that tell us to ignore the output.
177 """
177 """
178
178
179 random_re = re.compile(r'#\s*random\s+')
179 random_re = re.compile(r'#\s*random\s+')
180
180
181 def check_output(self, want, got, optionflags):
181 def check_output(self, want, got, optionflags):
182 """Check output, accepting special markers embedded in the output.
182 """Check output, accepting special markers embedded in the output.
183
183
184 If the output didn't pass the default validation but the special string
184 If the output didn't pass the default validation but the special string
185 '#random' is included, we accept it."""
185 '#random' is included, we accept it."""
186
186
187 # Let the original tester verify first, in case people have valid tests
187 # Let the original tester verify first, in case people have valid tests
188 # that happen to have a comment saying '#random' embedded in.
188 # that happen to have a comment saying '#random' embedded in.
189 ret = doctest.OutputChecker.check_output(self, want, got,
189 ret = doctest.OutputChecker.check_output(self, want, got,
190 optionflags)
190 optionflags)
191 if not ret and self.random_re.search(want):
191 if not ret and self.random_re.search(want):
192 #print >> sys.stderr, 'RANDOM OK:',want # dbg
192 #print >> sys.stderr, 'RANDOM OK:',want # dbg
193 return True
193 return True
194
194
195 return ret
195 return ret
196
196
197
197
198 class DocTestCase(doctests.DocTestCase):
198 class DocTestCase(doctests.DocTestCase):
199 """Proxy for DocTestCase: provides an address() method that
199 """Proxy for DocTestCase: provides an address() method that
200 returns the correct address for the doctest case. Otherwise
200 returns the correct address for the doctest case. Otherwise
201 acts as a proxy to the test case. To provide hints for address(),
201 acts as a proxy to the test case. To provide hints for address(),
202 an obj may also be passed -- this will be used as the test object
202 an obj may also be passed -- this will be used as the test object
203 for purposes of determining the test address, if it is provided.
203 for purposes of determining the test address, if it is provided.
204 """
204 """
205
205
206 # Note: this method was taken from numpy's nosetester module.
206 # Note: this method was taken from numpy's nosetester module.
207
207
208 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
208 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
209 # its constructor that blocks non-default arguments from being passed
209 # its constructor that blocks non-default arguments from being passed
210 # down into doctest.DocTestCase
210 # down into doctest.DocTestCase
211
211
212 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
212 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
213 checker=None, obj=None, result_var='_'):
213 checker=None, obj=None, result_var='_'):
214 self._result_var = result_var
214 self._result_var = result_var
215 doctests.DocTestCase.__init__(self, test,
215 doctests.DocTestCase.__init__(self, test,
216 optionflags=optionflags,
216 optionflags=optionflags,
217 setUp=setUp, tearDown=tearDown,
217 setUp=setUp, tearDown=tearDown,
218 checker=checker)
218 checker=checker)
219 # Now we must actually copy the original constructor from the stdlib
219 # Now we must actually copy the original constructor from the stdlib
220 # doctest class, because we can't call it directly and a bug in nose
220 # doctest class, because we can't call it directly and a bug in nose
221 # means it never gets passed the right arguments.
221 # means it never gets passed the right arguments.
222
222
223 self._dt_optionflags = optionflags
223 self._dt_optionflags = optionflags
224 self._dt_checker = checker
224 self._dt_checker = checker
225 self._dt_test = test
225 self._dt_test = test
226 self._dt_test_globs_ori = test.globs
226 self._dt_test_globs_ori = test.globs
227 self._dt_setUp = setUp
227 self._dt_setUp = setUp
228 self._dt_tearDown = tearDown
228 self._dt_tearDown = tearDown
229
229
230 # XXX - store this runner once in the object!
230 # XXX - store this runner once in the object!
231 runner = IPDocTestRunner(optionflags=optionflags,
231 runner = IPDocTestRunner(optionflags=optionflags,
232 checker=checker, verbose=False)
232 checker=checker, verbose=False)
233 self._dt_runner = runner
233 self._dt_runner = runner
234
234
235
235
236 # Each doctest should remember the directory it was loaded from, so
236 # Each doctest should remember the directory it was loaded from, so
237 # things like %run work without too many contortions
237 # things like %run work without too many contortions
238 self._ori_dir = os.path.dirname(test.filename)
238 self._ori_dir = os.path.dirname(test.filename)
239
239
240 # Modified runTest from the default stdlib
240 # Modified runTest from the default stdlib
241 def runTest(self):
241 def runTest(self):
242 test = self._dt_test
242 test = self._dt_test
243 runner = self._dt_runner
243 runner = self._dt_runner
244
244
245 old = sys.stdout
245 old = sys.stdout
246 new = StringIO()
246 new = StringIO()
247 optionflags = self._dt_optionflags
247 optionflags = self._dt_optionflags
248
248
249 if not (optionflags & REPORTING_FLAGS):
249 if not (optionflags & REPORTING_FLAGS):
250 # The option flags don't include any reporting flags,
250 # The option flags don't include any reporting flags,
251 # so add the default reporting flags
251 # so add the default reporting flags
252 optionflags |= _unittest_reportflags
252 optionflags |= _unittest_reportflags
253
253
254 try:
254 try:
255 # Save our current directory and switch out to the one where the
255 # Save our current directory and switch out to the one where the
256 # test was originally created, in case another doctest did a
256 # test was originally created, in case another doctest did a
257 # directory change. We'll restore this in the finally clause.
257 # directory change. We'll restore this in the finally clause.
258 curdir = os.getcwdu()
258 curdir = os.getcwdu()
259 #print 'runTest in dir:', self._ori_dir # dbg
259 #print 'runTest in dir:', self._ori_dir # dbg
260 os.chdir(self._ori_dir)
260 os.chdir(self._ori_dir)
261
261
262 runner.DIVIDER = "-"*70
262 runner.DIVIDER = "-"*70
263 failures, tries = runner.run(test,out=new.write,
263 failures, tries = runner.run(test,out=new.write,
264 clear_globs=False)
264 clear_globs=False)
265 finally:
265 finally:
266 sys.stdout = old
266 sys.stdout = old
267 os.chdir(curdir)
267 os.chdir(curdir)
268
268
269 if failures:
269 if failures:
270 raise self.failureException(self.format_failure(new.getvalue()))
270 raise self.failureException(self.format_failure(new.getvalue()))
271
271
272 def setUp(self):
272 def setUp(self):
273 """Modified test setup that syncs with ipython namespace"""
273 """Modified test setup that syncs with ipython namespace"""
274 #print "setUp test", self._dt_test.examples # dbg
274 #print "setUp test", self._dt_test.examples # dbg
275 if isinstance(self._dt_test.examples[0], IPExample):
275 if isinstance(self._dt_test.examples[0], IPExample):
276 # for IPython examples *only*, we swap the globals with the ipython
276 # for IPython examples *only*, we swap the globals with the ipython
277 # namespace, after updating it with the globals (which doctest
277 # namespace, after updating it with the globals (which doctest
278 # fills with the necessary info from the module being tested).
278 # fills with the necessary info from the module being tested).
279 self.user_ns_orig = {}
279 self.user_ns_orig = {}
280 self.user_ns_orig.update(_ip.user_ns)
280 self.user_ns_orig.update(_ip.user_ns)
281 _ip.user_ns.update(self._dt_test.globs)
281 _ip.user_ns.update(self._dt_test.globs)
282 # We must remove the _ key in the namespace, so that Python's
282 # We must remove the _ key in the namespace, so that Python's
283 # doctest code sets it naturally
283 # doctest code sets it naturally
284 _ip.user_ns.pop('_', None)
284 _ip.user_ns.pop('_', None)
285 _ip.user_ns['__builtins__'] = builtin_mod
285 _ip.user_ns['__builtins__'] = builtin_mod
286 self._dt_test.globs = _ip.user_ns
286 self._dt_test.globs = _ip.user_ns
287
287
288 super(DocTestCase, self).setUp()
288 super(DocTestCase, self).setUp()
289
289
290 def tearDown(self):
290 def tearDown(self):
291
291
292 # Undo the test.globs reassignment we made, so that the parent class
292 # Undo the test.globs reassignment we made, so that the parent class
293 # teardown doesn't destroy the ipython namespace
293 # teardown doesn't destroy the ipython namespace
294 if isinstance(self._dt_test.examples[0], IPExample):
294 if isinstance(self._dt_test.examples[0], IPExample):
295 self._dt_test.globs = self._dt_test_globs_ori
295 self._dt_test.globs = self._dt_test_globs_ori
296 _ip.user_ns.clear()
296 _ip.user_ns.clear()
297 _ip.user_ns.update(self.user_ns_orig)
297 _ip.user_ns.update(self.user_ns_orig)
298
298
299 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
299 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
300 # it does look like one to me: its tearDown method tries to run
300 # it does look like one to me: its tearDown method tries to run
301 #
301 #
302 # delattr(builtin_mod, self._result_var)
302 # delattr(builtin_mod, self._result_var)
303 #
303 #
304 # without checking that the attribute really is there; it implicitly
304 # without checking that the attribute really is there; it implicitly
305 # assumes it should have been set via displayhook. But if the
305 # assumes it should have been set via displayhook. But if the
306 # displayhook was never called, this doesn't necessarily happen. I
306 # displayhook was never called, this doesn't necessarily happen. I
307 # haven't been able to find a little self-contained example outside of
307 # haven't been able to find a little self-contained example outside of
308 # ipython that would show the problem so I can report it to the nose
308 # ipython that would show the problem so I can report it to the nose
309 # team, but it does happen a lot in our code.
309 # team, but it does happen a lot in our code.
310 #
310 #
311 # So here, we just protect as narrowly as possible by trapping an
311 # So here, we just protect as narrowly as possible by trapping an
312 # attribute error whose message would be the name of self._result_var,
312 # attribute error whose message would be the name of self._result_var,
313 # and letting any other error propagate.
313 # and letting any other error propagate.
314 try:
314 try:
315 super(DocTestCase, self).tearDown()
315 super(DocTestCase, self).tearDown()
316 except AttributeError as exc:
316 except AttributeError as exc:
317 if exc.args[0] != self._result_var:
317 if exc.args[0] != self._result_var:
318 raise
318 raise
319
319
320
320
321 # A simple subclassing of the original with a different class name, so we can
321 # A simple subclassing of the original with a different class name, so we can
322 # distinguish and treat differently IPython examples from pure python ones.
322 # distinguish and treat differently IPython examples from pure python ones.
323 class IPExample(doctest.Example): pass
323 class IPExample(doctest.Example): pass
324
324
325
325
326 class IPExternalExample(doctest.Example):
326 class IPExternalExample(doctest.Example):
327 """Doctest examples to be run in an external process."""
327 """Doctest examples to be run in an external process."""
328
328
329 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
329 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
330 options=None):
330 options=None):
331 # Parent constructor
331 # Parent constructor
332 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
332 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
333
333
334 # An EXTRA newline is needed to prevent pexpect hangs
334 # An EXTRA newline is needed to prevent pexpect hangs
335 self.source += '\n'
335 self.source += '\n'
336
336
337
337
338 class IPDocTestParser(doctest.DocTestParser):
338 class IPDocTestParser(doctest.DocTestParser):
339 """
339 """
340 A class used to parse strings containing doctest examples.
340 A class used to parse strings containing doctest examples.
341
341
342 Note: This is a version modified to properly recognize IPython input and
342 Note: This is a version modified to properly recognize IPython input and
343 convert any IPython examples into valid Python ones.
343 convert any IPython examples into valid Python ones.
344 """
344 """
345 # This regular expression is used to find doctest examples in a
345 # This regular expression is used to find doctest examples in a
346 # string. It defines three groups: `source` is the source code
346 # string. It defines three groups: `source` is the source code
347 # (including leading indentation and prompts); `indent` is the
347 # (including leading indentation and prompts); `indent` is the
348 # indentation of the first (PS1) line of the source code; and
348 # indentation of the first (PS1) line of the source code; and
349 # `want` is the expected output (including leading indentation).
349 # `want` is the expected output (including leading indentation).
350
350
351 # Classic Python prompts or default IPython ones
351 # Classic Python prompts or default IPython ones
352 _PS1_PY = r'>>>'
352 _PS1_PY = r'>>>'
353 _PS2_PY = r'\.\.\.'
353 _PS2_PY = r'\.\.\.'
354
354
355 _PS1_IP = r'In\ \[\d+\]:'
355 _PS1_IP = r'In\ \[\d+\]:'
356 _PS2_IP = r'\ \ \ \.\.\.+:'
356 _PS2_IP = r'\ \ \ \.\.\.+:'
357
357
358 _RE_TPL = r'''
358 _RE_TPL = r'''
359 # Source consists of a PS1 line followed by zero or more PS2 lines.
359 # Source consists of a PS1 line followed by zero or more PS2 lines.
360 (?P<source>
360 (?P<source>
361 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
361 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
362 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
362 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
363 \n? # a newline
363 \n? # a newline
364 # Want consists of any non-blank lines that do not start with PS1.
364 # Want consists of any non-blank lines that do not start with PS1.
365 (?P<want> (?:(?![ ]*$) # Not a blank line
365 (?P<want> (?:(?![ ]*$) # Not a blank line
366 (?![ ]*%s) # Not a line starting with PS1
366 (?![ ]*%s) # Not a line starting with PS1
367 (?![ ]*%s) # Not a line starting with PS2
367 (?![ ]*%s) # Not a line starting with PS2
368 .*$\n? # But any other line
368 .*$\n? # But any other line
369 )*)
369 )*)
370 '''
370 '''
371
371
372 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
372 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
373 re.MULTILINE | re.VERBOSE)
373 re.MULTILINE | re.VERBOSE)
374
374
375 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
375 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
376 re.MULTILINE | re.VERBOSE)
376 re.MULTILINE | re.VERBOSE)
377
377
378 # Mark a test as being fully random. In this case, we simply append the
378 # Mark a test as being fully random. In this case, we simply append the
379 # random marker ('#random') to each individual example's output. This way
379 # random marker ('#random') to each individual example's output. This way
380 # we don't need to modify any other code.
380 # we don't need to modify any other code.
381 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
381 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
382
382
383 # Mark tests to be executed in an external process - currently unsupported.
383 # Mark tests to be executed in an external process - currently unsupported.
384 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
384 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
385
385
386 def ip2py(self,source):
386 def ip2py(self,source):
387 """Convert input IPython source into valid Python."""
387 """Convert input IPython source into valid Python."""
388 block = _ip.input_transformer_manager.transform_cell(source)
388 block = _ip.input_transformer_manager.transform_cell(source)
389 if len(block.splitlines()) == 1:
389 if len(block.splitlines()) == 1:
390 return _ip.prefilter(block)
390 return _ip.prefilter(block)
391 else:
391 else:
392 return block
392 return block
393
393
394 def parse(self, string, name='<string>'):
394 def parse(self, string, name='<string>'):
395 """
395 """
396 Divide the given string into examples and intervening text,
396 Divide the given string into examples and intervening text,
397 and return them as a list of alternating Examples and strings.
397 and return them as a list of alternating Examples and strings.
398 Line numbers for the Examples are 0-based. The optional
398 Line numbers for the Examples are 0-based. The optional
399 argument `name` is a name identifying this string, and is only
399 argument `name` is a name identifying this string, and is only
400 used for error messages.
400 used for error messages.
401 """
401 """
402
402
403 #print 'Parse string:\n',string # dbg
403 #print 'Parse string:\n',string # dbg
404
404
405 string = string.expandtabs()
405 string = string.expandtabs()
406 # If all lines begin with the same indentation, then strip it.
406 # If all lines begin with the same indentation, then strip it.
407 min_indent = self._min_indent(string)
407 min_indent = self._min_indent(string)
408 if min_indent > 0:
408 if min_indent > 0:
409 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
409 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
410
410
411 output = []
411 output = []
412 charno, lineno = 0, 0
412 charno, lineno = 0, 0
413
413
414 # We make 'all random' tests by adding the '# random' mark to every
414 # We make 'all random' tests by adding the '# random' mark to every
415 # block of output in the test.
415 # block of output in the test.
416 if self._RANDOM_TEST.search(string):
416 if self._RANDOM_TEST.search(string):
417 random_marker = '\n# random'
417 random_marker = '\n# random'
418 else:
418 else:
419 random_marker = ''
419 random_marker = ''
420
420
421 # Whether to convert the input from ipython to python syntax
421 # Whether to convert the input from ipython to python syntax
422 ip2py = False
422 ip2py = False
423 # Find all doctest examples in the string. First, try them as Python
423 # Find all doctest examples in the string. First, try them as Python
424 # examples, then as IPython ones
424 # examples, then as IPython ones
425 terms = list(self._EXAMPLE_RE_PY.finditer(string))
425 terms = list(self._EXAMPLE_RE_PY.finditer(string))
426 if terms:
426 if terms:
427 # Normal Python example
427 # Normal Python example
428 #print '-'*70 # dbg
428 #print '-'*70 # dbg
429 #print 'PyExample, Source:\n',string # dbg
429 #print 'PyExample, Source:\n',string # dbg
430 #print '-'*70 # dbg
430 #print '-'*70 # dbg
431 Example = doctest.Example
431 Example = doctest.Example
432 else:
432 else:
433 # It's an ipython example. Note that IPExamples are run
433 # It's an ipython example. Note that IPExamples are run
434 # in-process, so their syntax must be turned into valid python.
434 # in-process, so their syntax must be turned into valid python.
435 # IPExternalExamples are run out-of-process (via pexpect) so they
435 # IPExternalExamples are run out-of-process (via pexpect) so they
436 # don't need any filtering (a real ipython will be executing them).
436 # don't need any filtering (a real ipython will be executing them).
437 terms = list(self._EXAMPLE_RE_IP.finditer(string))
437 terms = list(self._EXAMPLE_RE_IP.finditer(string))
438 if self._EXTERNAL_IP.search(string):
438 if self._EXTERNAL_IP.search(string):
439 #print '-'*70 # dbg
439 #print '-'*70 # dbg
440 #print 'IPExternalExample, Source:\n',string # dbg
440 #print 'IPExternalExample, Source:\n',string # dbg
441 #print '-'*70 # dbg
441 #print '-'*70 # dbg
442 Example = IPExternalExample
442 Example = IPExternalExample
443 else:
443 else:
444 #print '-'*70 # dbg
444 #print '-'*70 # dbg
445 #print 'IPExample, Source:\n',string # dbg
445 #print 'IPExample, Source:\n',string # dbg
446 #print '-'*70 # dbg
446 #print '-'*70 # dbg
447 Example = IPExample
447 Example = IPExample
448 ip2py = True
448 ip2py = True
449
449
450 for m in terms:
450 for m in terms:
451 # Add the pre-example text to `output`.
451 # Add the pre-example text to `output`.
452 output.append(string[charno:m.start()])
452 output.append(string[charno:m.start()])
453 # Update lineno (lines before this example)
453 # Update lineno (lines before this example)
454 lineno += string.count('\n', charno, m.start())
454 lineno += string.count('\n', charno, m.start())
455 # Extract info from the regexp match.
455 # Extract info from the regexp match.
456 (source, options, want, exc_msg) = \
456 (source, options, want, exc_msg) = \
457 self._parse_example(m, name, lineno,ip2py)
457 self._parse_example(m, name, lineno,ip2py)
458
458
459 # Append the random-output marker (it defaults to empty in most
459 # Append the random-output marker (it defaults to empty in most
460 # cases, it's only non-empty for 'all-random' tests):
460 # cases, it's only non-empty for 'all-random' tests):
461 want += random_marker
461 want += random_marker
462
462
463 if Example is IPExternalExample:
463 if Example is IPExternalExample:
464 options[doctest.NORMALIZE_WHITESPACE] = True
464 options[doctest.NORMALIZE_WHITESPACE] = True
465 want += '\n'
465 want += '\n'
466
466
467 # Create an Example, and add it to the list.
467 # Create an Example, and add it to the list.
468 if not self._IS_BLANK_OR_COMMENT(source):
468 if not self._IS_BLANK_OR_COMMENT(source):
469 output.append(Example(source, want, exc_msg,
469 output.append(Example(source, want, exc_msg,
470 lineno=lineno,
470 lineno=lineno,
471 indent=min_indent+len(m.group('indent')),
471 indent=min_indent+len(m.group('indent')),
472 options=options))
472 options=options))
473 # Update lineno (lines inside this example)
473 # Update lineno (lines inside this example)
474 lineno += string.count('\n', m.start(), m.end())
474 lineno += string.count('\n', m.start(), m.end())
475 # Update charno.
475 # Update charno.
476 charno = m.end()
476 charno = m.end()
477 # Add any remaining post-example text to `output`.
477 # Add any remaining post-example text to `output`.
478 output.append(string[charno:])
478 output.append(string[charno:])
479 return output
479 return output
480
480
481 def _parse_example(self, m, name, lineno,ip2py=False):
481 def _parse_example(self, m, name, lineno,ip2py=False):
482 """
482 """
483 Given a regular expression match from `_EXAMPLE_RE` (`m`),
483 Given a regular expression match from `_EXAMPLE_RE` (`m`),
484 return a pair `(source, want)`, where `source` is the matched
484 return a pair `(source, want)`, where `source` is the matched
485 example's source code (with prompts and indentation stripped);
485 example's source code (with prompts and indentation stripped);
486 and `want` is the example's expected output (with indentation
486 and `want` is the example's expected output (with indentation
487 stripped).
487 stripped).
488
488
489 `name` is the string's name, and `lineno` is the line number
489 `name` is the string's name, and `lineno` is the line number
490 where the example starts; both are used for error messages.
490 where the example starts; both are used for error messages.
491
491
492 Optional:
492 Optional:
493 `ip2py`: if true, filter the input via IPython to convert the syntax
493 `ip2py`: if true, filter the input via IPython to convert the syntax
494 into valid python.
494 into valid python.
495 """
495 """
496
496
497 # Get the example's indentation level.
497 # Get the example's indentation level.
498 indent = len(m.group('indent'))
498 indent = len(m.group('indent'))
499
499
500 # Divide source into lines; check that they're properly
500 # Divide source into lines; check that they're properly
501 # indented; and then strip their indentation & prompts.
501 # indented; and then strip their indentation & prompts.
502 source_lines = m.group('source').split('\n')
502 source_lines = m.group('source').split('\n')
503
503
504 # We're using variable-length input prompts
504 # We're using variable-length input prompts
505 ps1 = m.group('ps1')
505 ps1 = m.group('ps1')
506 ps2 = m.group('ps2')
506 ps2 = m.group('ps2')
507 ps1_len = len(ps1)
507 ps1_len = len(ps1)
508
508
509 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
509 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
510 if ps2:
510 if ps2:
511 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
511 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
512
512
513 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
513 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
514
514
515 if ip2py:
515 if ip2py:
516 # Convert source input from IPython into valid Python syntax
516 # Convert source input from IPython into valid Python syntax
517 source = self.ip2py(source)
517 source = self.ip2py(source)
518
518
519 # Divide want into lines; check that it's properly indented; and
519 # Divide want into lines; check that it's properly indented; and
520 # then strip the indentation. Spaces before the last newline should
520 # then strip the indentation. Spaces before the last newline should
521 # be preserved, so plain rstrip() isn't good enough.
521 # be preserved, so plain rstrip() isn't good enough.
522 want = m.group('want')
522 want = m.group('want')
523 want_lines = want.split('\n')
523 want_lines = want.split('\n')
524 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
524 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
525 del want_lines[-1] # forget final newline & spaces after it
525 del want_lines[-1] # forget final newline & spaces after it
526 self._check_prefix(want_lines, ' '*indent, name,
526 self._check_prefix(want_lines, ' '*indent, name,
527 lineno + len(source_lines))
527 lineno + len(source_lines))
528
528
529 # Remove ipython output prompt that might be present in the first line
529 # Remove ipython output prompt that might be present in the first line
530 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
530 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
531
531
532 want = '\n'.join([wl[indent:] for wl in want_lines])
532 want = '\n'.join([wl[indent:] for wl in want_lines])
533
533
534 # If `want` contains a traceback message, then extract it.
534 # If `want` contains a traceback message, then extract it.
535 m = self._EXCEPTION_RE.match(want)
535 m = self._EXCEPTION_RE.match(want)
536 if m:
536 if m:
537 exc_msg = m.group('msg')
537 exc_msg = m.group('msg')
538 else:
538 else:
539 exc_msg = None
539 exc_msg = None
540
540
541 # Extract options from the source.
541 # Extract options from the source.
542 options = self._find_options(source, name, lineno)
542 options = self._find_options(source, name, lineno)
543
543
544 return source, options, want, exc_msg
544 return source, options, want, exc_msg
545
545
546 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
546 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
547 """
547 """
548 Given the lines of a source string (including prompts and
548 Given the lines of a source string (including prompts and
549 leading indentation), check to make sure that every prompt is
549 leading indentation), check to make sure that every prompt is
550 followed by a space character. If any line is not followed by
550 followed by a space character. If any line is not followed by
551 a space character, then raise ValueError.
551 a space character, then raise ValueError.
552
552
553 Note: IPython-modified version which takes the input prompt length as a
553 Note: IPython-modified version which takes the input prompt length as a
554 parameter, so that prompts of variable length can be dealt with.
554 parameter, so that prompts of variable length can be dealt with.
555 """
555 """
556 space_idx = indent+ps1_len
556 space_idx = indent+ps1_len
557 min_len = space_idx+1
557 min_len = space_idx+1
558 for i, line in enumerate(lines):
558 for i, line in enumerate(lines):
559 if len(line) >= min_len and line[space_idx] != ' ':
559 if len(line) >= min_len and line[space_idx] != ' ':
560 raise ValueError('line %r of the docstring for %s '
560 raise ValueError('line %r of the docstring for %s '
561 'lacks blank after %s: %r' %
561 'lacks blank after %s: %r' %
562 (lineno+i+1, name,
562 (lineno+i+1, name,
563 line[indent:space_idx], line))
563 line[indent:space_idx], line))
564
564
565
565
566 SKIP = doctest.register_optionflag('SKIP')
566 SKIP = doctest.register_optionflag('SKIP')
567
567
568
568
569 class IPDocTestRunner(doctest.DocTestRunner,object):
569 class IPDocTestRunner(doctest.DocTestRunner,object):
570 """Test runner that synchronizes the IPython namespace with test globals.
570 """Test runner that synchronizes the IPython namespace with test globals.
571 """
571 """
572
572
573 def run(self, test, compileflags=None, out=None, clear_globs=True):
573 def run(self, test, compileflags=None, out=None, clear_globs=True):
574
574
575 # Hack: ipython needs access to the execution context of the example,
575 # Hack: ipython needs access to the execution context of the example,
576 # so that it can propagate user variables loaded by %run into
576 # so that it can propagate user variables loaded by %run into
577 # test.globs. We put them here into our modified %run as a function
577 # test.globs. We put them here into our modified %run as a function
578 # attribute. Our new %run will then only make the namespace update
578 # attribute. Our new %run will then only make the namespace update
579 # when called (rather than unconconditionally updating test.globs here
579 # when called (rather than unconconditionally updating test.globs here
580 # for all examples, most of which won't be calling %run anyway).
580 # for all examples, most of which won't be calling %run anyway).
581 #_ip._ipdoctest_test_globs = test.globs
581 #_ip._ipdoctest_test_globs = test.globs
582 #_ip._ipdoctest_test_filename = test.filename
582 #_ip._ipdoctest_test_filename = test.filename
583
583
584 test.globs.update(_ip.user_ns)
584 test.globs.update(_ip.user_ns)
585
585
586 return super(IPDocTestRunner,self).run(test,
586 return super(IPDocTestRunner,self).run(test,
587 compileflags,out,clear_globs)
587 compileflags,out,clear_globs)
588
588
589
589
590 class DocFileCase(doctest.DocFileCase):
590 class DocFileCase(doctest.DocFileCase):
591 """Overrides to provide filename
591 """Overrides to provide filename
592 """
592 """
593 def address(self):
593 def address(self):
594 return (self._dt_test.filename, None, None)
594 return (self._dt_test.filename, None, None)
595
595
596
596
597 class ExtensionDoctest(doctests.Doctest):
597 class ExtensionDoctest(doctests.Doctest):
598 """Nose Plugin that supports doctests in extension modules.
598 """Nose Plugin that supports doctests in extension modules.
599 """
599 """
600 name = 'extdoctest' # call nosetests with --with-extdoctest
600 name = 'extdoctest' # call nosetests with --with-extdoctest
601 enabled = True
601 enabled = True
602
602
603 def options(self, parser, env=os.environ):
603 def options(self, parser, env=os.environ):
604 Plugin.options(self, parser, env)
604 Plugin.options(self, parser, env)
605 parser.add_option('--doctest-tests', action='store_true',
605 parser.add_option('--doctest-tests', action='store_true',
606 dest='doctest_tests',
606 dest='doctest_tests',
607 default=env.get('NOSE_DOCTEST_TESTS',True),
607 default=env.get('NOSE_DOCTEST_TESTS',True),
608 help="Also look for doctests in test modules. "
608 help="Also look for doctests in test modules. "
609 "Note that classes, methods and functions should "
609 "Note that classes, methods and functions should "
610 "have either doctests or non-doctest tests, "
610 "have either doctests or non-doctest tests, "
611 "not both. [NOSE_DOCTEST_TESTS]")
611 "not both. [NOSE_DOCTEST_TESTS]")
612 parser.add_option('--doctest-extension', action="append",
612 parser.add_option('--doctest-extension', action="append",
613 dest="doctestExtension",
613 dest="doctestExtension",
614 help="Also look for doctests in files with "
614 help="Also look for doctests in files with "
615 "this extension [NOSE_DOCTEST_EXTENSION]")
615 "this extension [NOSE_DOCTEST_EXTENSION]")
616 # Set the default as a list, if given in env; otherwise
616 # Set the default as a list, if given in env; otherwise
617 # an additional value set on the command line will cause
617 # an additional value set on the command line will cause
618 # an error.
618 # an error.
619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
620 if env_setting is not None:
620 if env_setting is not None:
621 parser.set_defaults(doctestExtension=tolist(env_setting))
621 parser.set_defaults(doctestExtension=tolist(env_setting))
622
622
623
623
624 def configure(self, options, config):
624 def configure(self, options, config):
625 Plugin.configure(self, options, config)
625 Plugin.configure(self, options, config)
626 # Pull standard doctest plugin out of config; we will do doctesting
626 # Pull standard doctest plugin out of config; we will do doctesting
627 config.plugins.plugins = [p for p in config.plugins.plugins
627 config.plugins.plugins = [p for p in config.plugins.plugins
628 if p.name != 'doctest']
628 if p.name != 'doctest']
629 self.doctest_tests = options.doctest_tests
629 self.doctest_tests = options.doctest_tests
630 self.extension = tolist(options.doctestExtension)
630 self.extension = tolist(options.doctestExtension)
631
631
632 self.parser = doctest.DocTestParser()
632 self.parser = doctest.DocTestParser()
633 self.finder = DocTestFinder()
633 self.finder = DocTestFinder()
634 self.checker = IPDoctestOutputChecker()
634 self.checker = IPDoctestOutputChecker()
635 self.globs = None
635 self.globs = None
636 self.extraglobs = None
636 self.extraglobs = None
637
637
638
638
639 def loadTestsFromExtensionModule(self,filename):
639 def loadTestsFromExtensionModule(self,filename):
640 bpath,mod = os.path.split(filename)
640 bpath,mod = os.path.split(filename)
641 modname = os.path.splitext(mod)[0]
641 modname = os.path.splitext(mod)[0]
642 try:
642 try:
643 sys.path.append(bpath)
643 sys.path.append(bpath)
644 module = __import__(modname)
644 module = __import__(modname)
645 tests = list(self.loadTestsFromModule(module))
645 tests = list(self.loadTestsFromModule(module))
646 finally:
646 finally:
647 sys.path.pop()
647 sys.path.pop()
648 return tests
648 return tests
649
649
650 # NOTE: the method below is almost a copy of the original one in nose, with
650 # NOTE: the method below is almost a copy of the original one in nose, with
651 # a few modifications to control output checking.
651 # a few modifications to control output checking.
652
652
653 def loadTestsFromModule(self, module):
653 def loadTestsFromModule(self, module):
654 #print '*** ipdoctest - lTM',module # dbg
654 #print '*** ipdoctest - lTM',module # dbg
655
655
656 if not self.matches(module.__name__):
656 if not self.matches(module.__name__):
657 log.debug("Doctest doesn't want module %s", module)
657 log.debug("Doctest doesn't want module %s", module)
658 return
658 return
659
659
660 tests = self.finder.find(module,globs=self.globs,
660 tests = self.finder.find(module,globs=self.globs,
661 extraglobs=self.extraglobs)
661 extraglobs=self.extraglobs)
662 if not tests:
662 if not tests:
663 return
663 return
664
664
665 # always use whitespace and ellipsis options
665 # always use whitespace and ellipsis options
666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
667
667
668 tests.sort()
668 tests.sort()
669 module_file = module.__file__
669 module_file = module.__file__
670 if module_file[-4:] in ('.pyc', '.pyo'):
670 if module_file[-4:] in ('.pyc', '.pyo'):
671 module_file = module_file[:-1]
671 module_file = module_file[:-1]
672 for test in tests:
672 for test in tests:
673 if not test.examples:
673 if not test.examples:
674 continue
674 continue
675 if not test.filename:
675 if not test.filename:
676 test.filename = module_file
676 test.filename = module_file
677
677
678 yield DocTestCase(test,
678 yield DocTestCase(test,
679 optionflags=optionflags,
679 optionflags=optionflags,
680 checker=self.checker)
680 checker=self.checker)
681
681
682
682
683 def loadTestsFromFile(self, filename):
683 def loadTestsFromFile(self, filename):
684 #print "ipdoctest - from file", filename # dbg
684 #print "ipdoctest - from file", filename # dbg
685 if is_extension_module(filename):
685 if is_extension_module(filename):
686 for t in self.loadTestsFromExtensionModule(filename):
686 for t in self.loadTestsFromExtensionModule(filename):
687 yield t
687 yield t
688 else:
688 else:
689 if self.extension and anyp(filename.endswith, self.extension):
689 if self.extension and anyp(filename.endswith, self.extension):
690 name = os.path.basename(filename)
690 name = os.path.basename(filename)
691 dh = open(filename)
691 dh = open(filename)
692 try:
692 try:
693 doc = dh.read()
693 doc = dh.read()
694 finally:
694 finally:
695 dh.close()
695 dh.close()
696 test = self.parser.get_doctest(
696 test = self.parser.get_doctest(
697 doc, globs={'__file__': filename}, name=name,
697 doc, globs={'__file__': filename}, name=name,
698 filename=filename, lineno=0)
698 filename=filename, lineno=0)
699 if test.examples:
699 if test.examples:
700 #print 'FileCase:',test.examples # dbg
700 #print 'FileCase:',test.examples # dbg
701 yield DocFileCase(test)
701 yield DocFileCase(test)
702 else:
702 else:
703 yield False # no tests to load
703 yield False # no tests to load
704
704
705
705
706 class IPythonDoctest(ExtensionDoctest):
706 class IPythonDoctest(ExtensionDoctest):
707 """Nose Plugin that supports doctests in extension modules.
707 """Nose Plugin that supports doctests in extension modules.
708 """
708 """
709 name = 'ipdoctest' # call nosetests with --with-ipdoctest
709 name = 'ipdoctest' # call nosetests with --with-ipdoctest
710 enabled = True
710 enabled = True
711
711
712 def makeTest(self, obj, parent):
712 def makeTest(self, obj, parent):
713 """Look for doctests in the given object, which will be a
713 """Look for doctests in the given object, which will be a
714 function, method or class.
714 function, method or class.
715 """
715 """
716 #print 'Plugin analyzing:', obj, parent # dbg
716 #print 'Plugin analyzing:', obj, parent # dbg
717 # always use whitespace and ellipsis options
717 # always use whitespace and ellipsis options
718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
719
719
720 doctests = self.finder.find(obj, module=getmodule(parent))
720 doctests = self.finder.find(obj, module=getmodule(parent))
721 if doctests:
721 if doctests:
722 for test in doctests:
722 for test in doctests:
723 if len(test.examples) == 0:
723 if len(test.examples) == 0:
724 continue
724 continue
725
725
726 yield DocTestCase(test, obj=obj,
726 yield DocTestCase(test, obj=obj,
727 optionflags=optionflags,
727 optionflags=optionflags,
728 checker=self.checker)
728 checker=self.checker)
729
729
730 def options(self, parser, env=os.environ):
730 def options(self, parser, env=os.environ):
731 #print "Options for nose plugin:", self.name # dbg
731 #print "Options for nose plugin:", self.name # dbg
732 Plugin.options(self, parser, env)
732 Plugin.options(self, parser, env)
733 parser.add_option('--ipdoctest-tests', action='store_true',
733 parser.add_option('--ipdoctest-tests', action='store_true',
734 dest='ipdoctest_tests',
734 dest='ipdoctest_tests',
735 default=env.get('NOSE_IPDOCTEST_TESTS',True),
735 default=env.get('NOSE_IPDOCTEST_TESTS',True),
736 help="Also look for doctests in test modules. "
736 help="Also look for doctests in test modules. "
737 "Note that classes, methods and functions should "
737 "Note that classes, methods and functions should "
738 "have either doctests or non-doctest tests, "
738 "have either doctests or non-doctest tests, "
739 "not both. [NOSE_IPDOCTEST_TESTS]")
739 "not both. [NOSE_IPDOCTEST_TESTS]")
740 parser.add_option('--ipdoctest-extension', action="append",
740 parser.add_option('--ipdoctest-extension', action="append",
741 dest="ipdoctest_extension",
741 dest="ipdoctest_extension",
742 help="Also look for doctests in files with "
742 help="Also look for doctests in files with "
743 "this extension [NOSE_IPDOCTEST_EXTENSION]")
743 "this extension [NOSE_IPDOCTEST_EXTENSION]")
744 # Set the default as a list, if given in env; otherwise
744 # Set the default as a list, if given in env; otherwise
745 # an additional value set on the command line will cause
745 # an additional value set on the command line will cause
746 # an error.
746 # an error.
747 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
747 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
748 if env_setting is not None:
748 if env_setting is not None:
749 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
749 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
750
750
751 def configure(self, options, config):
751 def configure(self, options, config):
752 #print "Configuring nose plugin:", self.name # dbg
752 #print "Configuring nose plugin:", self.name # dbg
753 Plugin.configure(self, options, config)
753 Plugin.configure(self, options, config)
754 # Pull standard doctest plugin out of config; we will do doctesting
754 # Pull standard doctest plugin out of config; we will do doctesting
755 config.plugins.plugins = [p for p in config.plugins.plugins
755 config.plugins.plugins = [p for p in config.plugins.plugins
756 if p.name != 'doctest']
756 if p.name != 'doctest']
757 self.doctest_tests = options.ipdoctest_tests
757 self.doctest_tests = options.ipdoctest_tests
758 self.extension = tolist(options.ipdoctest_extension)
758 self.extension = tolist(options.ipdoctest_extension)
759
759
760 self.parser = IPDocTestParser()
760 self.parser = IPDocTestParser()
761 self.finder = DocTestFinder(parser=self.parser)
761 self.finder = DocTestFinder(parser=self.parser)
762 self.checker = IPDoctestOutputChecker()
762 self.checker = IPDoctestOutputChecker()
763 self.globs = None
763 self.globs = None
764 self.extraglobs = None
764 self.extraglobs = None
@@ -1,169 +1,169 b''
1 """Tests for the decorators we've created for IPython.
1 """Tests for the decorators we've created for IPython.
2 """
2 """
3 from __future__ import print_function
3 from __future__ import print_function
4
4
5 # Module imports
5 # Module imports
6 # Std lib
6 # Std lib
7 import inspect
7 import inspect
8 import sys
8 import sys
9
9
10 # Third party
10 # Third party
11 import nose.tools as nt
11 import nose.tools as nt
12
12
13 # Our own
13 # Our own
14 from IPython.testing import decorators as dec
14 from IPython.testing import decorators as dec
15 from IPython.testing.skipdoctest import skip_doctest
15 from IPython.testing.skipdoctest import skip_doctest
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Utilities
18 # Utilities
19
19
20 # Note: copied from OInspect, kept here so the testing stuff doesn't create
20 # Note: copied from OInspect, kept here so the testing stuff doesn't create
21 # circular dependencies and is easier to reuse.
21 # circular dependencies and is easier to reuse.
22 def getargspec(obj):
22 def getargspec(obj):
23 """Get the names and default values of a function's arguments.
23 """Get the names and default values of a function's arguments.
24
24
25 A tuple of four things is returned: (args, varargs, varkw, defaults).
25 A tuple of four things is returned: (args, varargs, varkw, defaults).
26 'args' is a list of the argument names (it may contain nested lists).
26 'args' is a list of the argument names (it may contain nested lists).
27 'varargs' and 'varkw' are the names of the * and ** arguments or None.
27 'varargs' and 'varkw' are the names of the * and ** arguments or None.
28 'defaults' is an n-tuple of the default values of the last n arguments.
28 'defaults' is an n-tuple of the default values of the last n arguments.
29
29
30 Modified version of inspect.getargspec from the Python Standard
30 Modified version of inspect.getargspec from the Python Standard
31 Library."""
31 Library."""
32
32
33 if inspect.isfunction(obj):
33 if inspect.isfunction(obj):
34 func_obj = obj
34 func_obj = obj
35 elif inspect.ismethod(obj):
35 elif inspect.ismethod(obj):
36 func_obj = obj.im_func
36 func_obj = obj.__func__
37 else:
37 else:
38 raise TypeError('arg is not a Python function')
38 raise TypeError('arg is not a Python function')
39 args, varargs, varkw = inspect.getargs(func_obj.__code__)
39 args, varargs, varkw = inspect.getargs(func_obj.__code__)
40 return args, varargs, varkw, func_obj.__defaults__
40 return args, varargs, varkw, func_obj.__defaults__
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Testing functions
43 # Testing functions
44
44
45 @dec.as_unittest
45 @dec.as_unittest
46 def trivial():
46 def trivial():
47 """A trivial test"""
47 """A trivial test"""
48 pass
48 pass
49
49
50
50
51 @dec.skip
51 @dec.skip
52 def test_deliberately_broken():
52 def test_deliberately_broken():
53 """A deliberately broken test - we want to skip this one."""
53 """A deliberately broken test - we want to skip this one."""
54 1/0
54 1/0
55
55
56 @dec.skip('Testing the skip decorator')
56 @dec.skip('Testing the skip decorator')
57 def test_deliberately_broken2():
57 def test_deliberately_broken2():
58 """Another deliberately broken test - we want to skip this one."""
58 """Another deliberately broken test - we want to skip this one."""
59 1/0
59 1/0
60
60
61
61
62 # Verify that we can correctly skip the doctest for a function at will, but
62 # Verify that we can correctly skip the doctest for a function at will, but
63 # that the docstring itself is NOT destroyed by the decorator.
63 # that the docstring itself is NOT destroyed by the decorator.
64 @skip_doctest
64 @skip_doctest
65 def doctest_bad(x,y=1,**k):
65 def doctest_bad(x,y=1,**k):
66 """A function whose doctest we need to skip.
66 """A function whose doctest we need to skip.
67
67
68 >>> 1+1
68 >>> 1+1
69 3
69 3
70 """
70 """
71 print('x:',x)
71 print('x:',x)
72 print('y:',y)
72 print('y:',y)
73 print('k:',k)
73 print('k:',k)
74
74
75
75
76 def call_doctest_bad():
76 def call_doctest_bad():
77 """Check that we can still call the decorated functions.
77 """Check that we can still call the decorated functions.
78
78
79 >>> doctest_bad(3,y=4)
79 >>> doctest_bad(3,y=4)
80 x: 3
80 x: 3
81 y: 4
81 y: 4
82 k: {}
82 k: {}
83 """
83 """
84 pass
84 pass
85
85
86
86
87 def test_skip_dt_decorator():
87 def test_skip_dt_decorator():
88 """Doctest-skipping decorator should preserve the docstring.
88 """Doctest-skipping decorator should preserve the docstring.
89 """
89 """
90 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
90 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
91 check = """A function whose doctest we need to skip.
91 check = """A function whose doctest we need to skip.
92
92
93 >>> 1+1
93 >>> 1+1
94 3
94 3
95 """
95 """
96 # Fetch the docstring from doctest_bad after decoration.
96 # Fetch the docstring from doctest_bad after decoration.
97 val = doctest_bad.__doc__
97 val = doctest_bad.__doc__
98
98
99 nt.assert_equal(check,val,"doctest_bad docstrings don't match")
99 nt.assert_equal(check,val,"doctest_bad docstrings don't match")
100
100
101
101
102 # Doctest skipping should work for class methods too
102 # Doctest skipping should work for class methods too
103 class FooClass(object):
103 class FooClass(object):
104 """FooClass
104 """FooClass
105
105
106 Example:
106 Example:
107
107
108 >>> 1+1
108 >>> 1+1
109 2
109 2
110 """
110 """
111
111
112 @skip_doctest
112 @skip_doctest
113 def __init__(self,x):
113 def __init__(self,x):
114 """Make a FooClass.
114 """Make a FooClass.
115
115
116 Example:
116 Example:
117
117
118 >>> f = FooClass(3)
118 >>> f = FooClass(3)
119 junk
119 junk
120 """
120 """
121 print('Making a FooClass.')
121 print('Making a FooClass.')
122 self.x = x
122 self.x = x
123
123
124 @skip_doctest
124 @skip_doctest
125 def bar(self,y):
125 def bar(self,y):
126 """Example:
126 """Example:
127
127
128 >>> ff = FooClass(3)
128 >>> ff = FooClass(3)
129 >>> ff.bar(0)
129 >>> ff.bar(0)
130 boom!
130 boom!
131 >>> 1/0
131 >>> 1/0
132 bam!
132 bam!
133 """
133 """
134 return 1/y
134 return 1/y
135
135
136 def baz(self,y):
136 def baz(self,y):
137 """Example:
137 """Example:
138
138
139 >>> ff2 = FooClass(3)
139 >>> ff2 = FooClass(3)
140 Making a FooClass.
140 Making a FooClass.
141 >>> ff2.baz(3)
141 >>> ff2.baz(3)
142 True
142 True
143 """
143 """
144 return self.x==y
144 return self.x==y
145
145
146
146
147 def test_skip_dt_decorator2():
147 def test_skip_dt_decorator2():
148 """Doctest-skipping decorator should preserve function signature.
148 """Doctest-skipping decorator should preserve function signature.
149 """
149 """
150 # Hardcoded correct answer
150 # Hardcoded correct answer
151 dtargs = (['x', 'y'], None, 'k', (1,))
151 dtargs = (['x', 'y'], None, 'k', (1,))
152 # Introspect out the value
152 # Introspect out the value
153 dtargsr = getargspec(doctest_bad)
153 dtargsr = getargspec(doctest_bad)
154 assert dtargsr==dtargs, \
154 assert dtargsr==dtargs, \
155 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
155 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
156
156
157
157
158 @dec.skip_linux
158 @dec.skip_linux
159 def test_linux():
159 def test_linux():
160 nt.assert_false(sys.platform.startswith('linux'),"This test can't run under linux")
160 nt.assert_false(sys.platform.startswith('linux'),"This test can't run under linux")
161
161
162 @dec.skip_win32
162 @dec.skip_win32
163 def test_win32():
163 def test_win32():
164 nt.assert_not_equal(sys.platform,'win32',"This test can't run under windows")
164 nt.assert_not_equal(sys.platform,'win32',"This test can't run under windows")
165
165
166 @dec.skip_osx
166 @dec.skip_osx
167 def test_osx():
167 def test_osx():
168 nt.assert_not_equal(sys.platform,'darwin',"This test can't run under osx")
168 nt.assert_not_equal(sys.platform,'darwin',"This test can't run under osx")
169
169
General Comments 0
You need to be logged in to leave comments. Login now