##// END OF EJS Templates
Merge pull request #2476 from minrk/editmagic...
Min RK -
r9024:c679a6cc merge
parent child Browse files
Show More
@@ -1,531 +1,554
1 """Implementation of code management magic functions.
1 """Implementation of code management 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
14
15 # Stdlib
15 # Stdlib
16 import inspect
16 import inspect
17 import io
17 import io
18 import json
18 import json
19 import os
19 import os
20 import re
20 import sys
21 import sys
21 from urllib2 import urlopen
22 from urllib2 import urlopen
22
23
23 # Our own packages
24 # Our own packages
24 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
25 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
25 from IPython.core.macro import Macro
26 from IPython.core.macro import Macro
26 from IPython.core.magic import Magics, magics_class, line_magic
27 from IPython.core.magic import Magics, magics_class, line_magic
27 from IPython.core.oinspect import find_file, find_source_lines
28 from IPython.core.oinspect import find_file, find_source_lines
28 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.utils import openpy
30 from IPython.utils import openpy
30 from IPython.utils import py3compat
31 from IPython.utils import py3compat
31 from IPython.utils.io import file_read
32 from IPython.utils.io import file_read
32 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.warn import warn
34 from IPython.utils.warn import warn
34
35
35 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
36 # Magic implementation classes
37 # Magic implementation classes
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38
39
39 # Used for exception handling in magic_edit
40 # Used for exception handling in magic_edit
40 class MacroToEdit(ValueError): pass
41 class MacroToEdit(ValueError): pass
41
42
43 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
44
45 class InteractivelyDefined(Exception):
46 """Exception for interactively defined variable in magic_edit"""
47 def __init__(self, index):
48 self.index = index
49
42
50
43 @magics_class
51 @magics_class
44 class CodeMagics(Magics):
52 class CodeMagics(Magics):
45 """Magics related to code management (loading, saving, editing, ...)."""
53 """Magics related to code management (loading, saving, editing, ...)."""
46
54
47 @line_magic
55 @line_magic
48 def save(self, parameter_s=''):
56 def save(self, parameter_s=''):
49 """Save a set of lines or a macro to a given filename.
57 """Save a set of lines or a macro to a given filename.
50
58
51 Usage:\\
59 Usage:\\
52 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
60 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
53
61
54 Options:
62 Options:
55
63
56 -r: use 'raw' input. By default, the 'processed' history is used,
64 -r: use 'raw' input. By default, the 'processed' history is used,
57 so that magics are loaded in their transformed version to valid
65 so that magics are loaded in their transformed version to valid
58 Python. If this option is given, the raw input as typed as the
66 Python. If this option is given, the raw input as typed as the
59 command line is used instead.
67 command line is used instead.
60
68
61 -f: force overwrite. If file exists, %save will prompt for overwrite
69 -f: force overwrite. If file exists, %save will prompt for overwrite
62 unless -f is given.
70 unless -f is given.
63
71
64 -a: append to the file instead of overwriting it.
72 -a: append to the file instead of overwriting it.
65
73
66 This function uses the same syntax as %history for input ranges,
74 This function uses the same syntax as %history for input ranges,
67 then saves the lines to the filename you specify.
75 then saves the lines to the filename you specify.
68
76
69 It adds a '.py' extension to the file if you don't do so yourself, and
77 It adds a '.py' extension to the file if you don't do so yourself, and
70 it asks for confirmation before overwriting existing files.
78 it asks for confirmation before overwriting existing files.
71
79
72 If `-r` option is used, the default extension is `.ipy`.
80 If `-r` option is used, the default extension is `.ipy`.
73 """
81 """
74
82
75 opts,args = self.parse_options(parameter_s,'fra',mode='list')
83 opts,args = self.parse_options(parameter_s,'fra',mode='list')
76 if not args:
84 if not args:
77 raise UsageError('Missing filename.')
85 raise UsageError('Missing filename.')
78 raw = 'r' in opts
86 raw = 'r' in opts
79 force = 'f' in opts
87 force = 'f' in opts
80 append = 'a' in opts
88 append = 'a' in opts
81 mode = 'a' if append else 'w'
89 mode = 'a' if append else 'w'
82 ext = u'.ipy' if raw else u'.py'
90 ext = u'.ipy' if raw else u'.py'
83 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
91 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
84 if not fname.endswith((u'.py',u'.ipy')):
92 if not fname.endswith((u'.py',u'.ipy')):
85 fname += ext
93 fname += ext
86 file_exists = os.path.isfile(fname)
94 file_exists = os.path.isfile(fname)
87 if file_exists and not force and not append:
95 if file_exists and not force and not append:
88 try:
96 try:
89 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
97 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
90 except StdinNotImplementedError:
98 except StdinNotImplementedError:
91 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
99 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
92 return
100 return
93 if not overwrite :
101 if not overwrite :
94 print 'Operation cancelled.'
102 print 'Operation cancelled.'
95 return
103 return
96 try:
104 try:
97 cmds = self.shell.find_user_code(codefrom,raw)
105 cmds = self.shell.find_user_code(codefrom,raw)
98 except (TypeError, ValueError) as e:
106 except (TypeError, ValueError) as e:
99 print e.args[0]
107 print e.args[0]
100 return
108 return
101 out = py3compat.cast_unicode(cmds)
109 out = py3compat.cast_unicode(cmds)
102 with io.open(fname, mode, encoding="utf-8") as f:
110 with io.open(fname, mode, encoding="utf-8") as f:
103 if not file_exists or not append:
111 if not file_exists or not append:
104 f.write(u"# coding: utf-8\n")
112 f.write(u"# coding: utf-8\n")
105 f.write(out)
113 f.write(out)
106 # make sure we end on a newline
114 # make sure we end on a newline
107 if not out.endswith(u'\n'):
115 if not out.endswith(u'\n'):
108 f.write(u'\n')
116 f.write(u'\n')
109 print 'The following commands were written to file `%s`:' % fname
117 print 'The following commands were written to file `%s`:' % fname
110 print cmds
118 print cmds
111
119
112 @line_magic
120 @line_magic
113 def pastebin(self, parameter_s=''):
121 def pastebin(self, parameter_s=''):
114 """Upload code to Github's Gist paste bin, returning the URL.
122 """Upload code to Github's Gist paste bin, returning the URL.
115
123
116 Usage:\\
124 Usage:\\
117 %pastebin [-d "Custom description"] 1-7
125 %pastebin [-d "Custom description"] 1-7
118
126
119 The argument can be an input history range, a filename, or the name of a
127 The argument can be an input history range, a filename, or the name of a
120 string or macro.
128 string or macro.
121
129
122 Options:
130 Options:
123
131
124 -d: Pass a custom description for the gist. The default will say
132 -d: Pass a custom description for the gist. The default will say
125 "Pasted from IPython".
133 "Pasted from IPython".
126 """
134 """
127 opts, args = self.parse_options(parameter_s, 'd:')
135 opts, args = self.parse_options(parameter_s, 'd:')
128
136
129 try:
137 try:
130 code = self.shell.find_user_code(args)
138 code = self.shell.find_user_code(args)
131 except (ValueError, TypeError) as e:
139 except (ValueError, TypeError) as e:
132 print e.args[0]
140 print e.args[0]
133 return
141 return
134
142
135 post_data = json.dumps({
143 post_data = json.dumps({
136 "description": opts.get('d', "Pasted from IPython"),
144 "description": opts.get('d', "Pasted from IPython"),
137 "public": True,
145 "public": True,
138 "files": {
146 "files": {
139 "file1.py": {
147 "file1.py": {
140 "content": code
148 "content": code
141 }
149 }
142 }
150 }
143 }).encode('utf-8')
151 }).encode('utf-8')
144
152
145 response = urlopen("https://api.github.com/gists", post_data)
153 response = urlopen("https://api.github.com/gists", post_data)
146 response_data = json.loads(response.read().decode('utf-8'))
154 response_data = json.loads(response.read().decode('utf-8'))
147 return response_data['html_url']
155 return response_data['html_url']
148
156
149 @line_magic
157 @line_magic
150 def loadpy(self, arg_s):
158 def loadpy(self, arg_s):
151 """Alias of `%load`
159 """Alias of `%load`
152
160
153 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
161 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
154 extension. So it has been renamed simply into %load. You can look at
162 extension. So it has been renamed simply into %load. You can look at
155 `%load`'s docstring for more info.
163 `%load`'s docstring for more info.
156 """
164 """
157 self.load(arg_s)
165 self.load(arg_s)
158
166
159 @line_magic
167 @line_magic
160 def load(self, arg_s):
168 def load(self, arg_s):
161 """Load code into the current frontend.
169 """Load code into the current frontend.
162
170
163 Usage:\\
171 Usage:\\
164 %load [options] source
172 %load [options] source
165
173
166 where source can be a filename, URL, input history range or macro
174 where source can be a filename, URL, input history range or macro
167
175
168 Options:
176 Options:
169 --------
177 --------
170 -y : Don't ask confirmation for loading source above 200 000 characters.
178 -y : Don't ask confirmation for loading source above 200 000 characters.
171
179
172 This magic command can either take a local filename, a URL, an history
180 This magic command can either take a local filename, a URL, an history
173 range (see %history) or a macro as argument, it will prompt for
181 range (see %history) or a macro as argument, it will prompt for
174 confirmation before loading source with more than 200 000 characters, unless
182 confirmation before loading source with more than 200 000 characters, unless
175 -y flag is passed or if the frontend does not support raw_input::
183 -y flag is passed or if the frontend does not support raw_input::
176
184
177 %load myscript.py
185 %load myscript.py
178 %load 7-27
186 %load 7-27
179 %load myMacro
187 %load myMacro
180 %load http://www.example.com/myscript.py
188 %load http://www.example.com/myscript.py
181 """
189 """
182 opts,args = self.parse_options(arg_s,'y')
190 opts,args = self.parse_options(arg_s,'y')
183 if not args:
191 if not args:
184 raise UsageError('Missing filename, URL, input history range, '
192 raise UsageError('Missing filename, URL, input history range, '
185 'or macro.')
193 'or macro.')
186
194
187 contents = self.shell.find_user_code(args)
195 contents = self.shell.find_user_code(args)
188 l = len(contents)
196 l = len(contents)
189
197
190 # 200 000 is ~ 2500 full 80 caracter lines
198 # 200 000 is ~ 2500 full 80 caracter lines
191 # so in average, more than 5000 lines
199 # so in average, more than 5000 lines
192 if l > 200000 and 'y' not in opts:
200 if l > 200000 and 'y' not in opts:
193 try:
201 try:
194 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
202 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
195 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
203 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
196 except StdinNotImplementedError:
204 except StdinNotImplementedError:
197 #asume yes if raw input not implemented
205 #asume yes if raw input not implemented
198 ans = True
206 ans = True
199
207
200 if ans is False :
208 if ans is False :
201 print 'Operation cancelled.'
209 print 'Operation cancelled.'
202 return
210 return
203
211
204 self.shell.set_next_input(contents)
212 self.shell.set_next_input(contents)
205
213
206 @staticmethod
214 @staticmethod
207 def _find_edit_target(shell, args, opts, last_call):
215 def _find_edit_target(shell, args, opts, last_call):
208 """Utility method used by magic_edit to find what to edit."""
216 """Utility method used by magic_edit to find what to edit."""
209
217
210 def make_filename(arg):
218 def make_filename(arg):
211 "Make a filename from the given args"
219 "Make a filename from the given args"
212 arg = unquote_filename(arg)
220 arg = unquote_filename(arg)
213 try:
221 try:
214 filename = get_py_filename(arg)
222 filename = get_py_filename(arg)
215 except IOError:
223 except IOError:
216 # If it ends with .py but doesn't already exist, assume we want
224 # If it ends with .py but doesn't already exist, assume we want
217 # a new file.
225 # a new file.
218 if arg.endswith('.py'):
226 if arg.endswith('.py'):
219 filename = arg
227 filename = arg
220 else:
228 else:
221 filename = None
229 filename = None
222 return filename
230 return filename
223
231
224 # Set a few locals from the options for convenience:
232 # Set a few locals from the options for convenience:
225 opts_prev = 'p' in opts
233 opts_prev = 'p' in opts
226 opts_raw = 'r' in opts
234 opts_raw = 'r' in opts
227
235
228 # custom exceptions
236 # custom exceptions
229 class DataIsObject(Exception): pass
237 class DataIsObject(Exception): pass
230
238
231 # Default line number value
239 # Default line number value
232 lineno = opts.get('n',None)
240 lineno = opts.get('n',None)
233
241
234 if opts_prev:
242 if opts_prev:
235 args = '_%s' % last_call[0]
243 args = '_%s' % last_call[0]
236 if args not in shell.user_ns:
244 if args not in shell.user_ns:
237 args = last_call[1]
245 args = last_call[1]
238
246
239 # use last_call to remember the state of the previous call, but don't
247 # use last_call to remember the state of the previous call, but don't
240 # let it be clobbered by successive '-p' calls.
248 # let it be clobbered by successive '-p' calls.
241 try:
249 try:
242 last_call[0] = shell.displayhook.prompt_count
250 last_call[0] = shell.displayhook.prompt_count
243 if not opts_prev:
251 if not opts_prev:
244 last_call[1] = args
252 last_call[1] = args
245 except:
253 except:
246 pass
254 pass
247
255
248 # by default this is done with temp files, except when the given
256 # by default this is done with temp files, except when the given
249 # arg is a filename
257 # arg is a filename
250 use_temp = True
258 use_temp = True
251
259
252 data = ''
260 data = ''
253
261
254 # First, see if the arguments should be a filename.
262 # First, see if the arguments should be a filename.
255 filename = make_filename(args)
263 filename = make_filename(args)
256 if filename:
264 if filename:
257 use_temp = False
265 use_temp = False
258 elif args:
266 elif args:
259 # Mode where user specifies ranges of lines, like in %macro.
267 # Mode where user specifies ranges of lines, like in %macro.
260 data = shell.extract_input_lines(args, opts_raw)
268 data = shell.extract_input_lines(args, opts_raw)
261 if not data:
269 if not data:
262 try:
270 try:
263 # Load the parameter given as a variable. If not a string,
271 # Load the parameter given as a variable. If not a string,
264 # process it as an object instead (below)
272 # process it as an object instead (below)
265
273
266 #print '*** args',args,'type',type(args) # dbg
274 #print '*** args',args,'type',type(args) # dbg
267 data = eval(args, shell.user_ns)
275 data = eval(args, shell.user_ns)
268 if not isinstance(data, basestring):
276 if not isinstance(data, basestring):
269 raise DataIsObject
277 raise DataIsObject
270
278
271 except (NameError,SyntaxError):
279 except (NameError,SyntaxError):
272 # given argument is not a variable, try as a filename
280 # given argument is not a variable, try as a filename
273 filename = make_filename(args)
281 filename = make_filename(args)
274 if filename is None:
282 if filename is None:
275 warn("Argument given (%s) can't be found as a variable "
283 warn("Argument given (%s) can't be found as a variable "
276 "or as a filename." % args)
284 "or as a filename." % args)
277 return
285 return (None, None, None)
278 use_temp = False
286 use_temp = False
279
287
280 except DataIsObject:
288 except DataIsObject:
281 # macros have a special edit function
289 # macros have a special edit function
282 if isinstance(data, Macro):
290 if isinstance(data, Macro):
283 raise MacroToEdit(data)
291 raise MacroToEdit(data)
284
292
285 # For objects, try to edit the file where they are defined
293 # For objects, try to edit the file where they are defined
286 filename = find_file(data)
294 filename = find_file(data)
287 if filename:
295 if filename:
288 if 'fakemodule' in filename.lower() and \
296 if 'fakemodule' in filename.lower() and \
289 inspect.isclass(data):
297 inspect.isclass(data):
290 # class created by %edit? Try to find source
298 # class created by %edit? Try to find source
291 # by looking for method definitions instead, the
299 # by looking for method definitions instead, the
292 # __module__ in those classes is FakeModule.
300 # __module__ in those classes is FakeModule.
293 attrs = [getattr(data, aname) for aname in dir(data)]
301 attrs = [getattr(data, aname) for aname in dir(data)]
294 for attr in attrs:
302 for attr in attrs:
295 if not inspect.ismethod(attr):
303 if not inspect.ismethod(attr):
296 continue
304 continue
297 filename = find_file(attr)
305 filename = find_file(attr)
298 if filename and \
306 if filename and \
299 'fakemodule' not in filename.lower():
307 'fakemodule' not in filename.lower():
300 # change the attribute to be the edit
308 # change the attribute to be the edit
301 # target instead
309 # target instead
302 data = attr
310 data = attr
303 break
311 break
304
312
313 m = ipython_input_pat.match(os.path.basename(filename))
314 if m:
315 raise InteractivelyDefined(int(m.groups()[0]))
316
305 datafile = 1
317 datafile = 1
306 if filename is None:
318 if filename is None:
307 filename = make_filename(args)
319 filename = make_filename(args)
308 datafile = 1
320 datafile = 1
321 if filename is not None:
322 # only warn about this if we get a real name
309 warn('Could not find file where `%s` is defined.\n'
323 warn('Could not find file where `%s` is defined.\n'
310 'Opening a file named `%s`' % (args, filename))
324 'Opening a file named `%s`' % (args, filename))
311 # Now, make sure we can actually read the source (if it was
325 # Now, make sure we can actually read the source (if it was
312 # in a temp file it's gone by now).
326 # in a temp file it's gone by now).
313 if datafile:
327 if datafile:
314 if lineno is None:
328 if lineno is None:
315 lineno = find_source_lines(data)
329 lineno = find_source_lines(data)
316 if lineno is None:
330 if lineno is None:
317 filename = make_filename(args)
331 filename = make_filename(args)
318 if filename is None:
332 if filename is None:
319 warn('The file `%s` where `%s` was defined '
333 warn('The file where `%s` was defined '
320 'cannot be read.' % (filename, data))
334 'cannot be read or found.' % data)
321 return
335 return (None, None, None)
322 use_temp = False
336 use_temp = False
323
337
324 if use_temp:
338 if use_temp:
325 filename = shell.mktempfile(data)
339 filename = shell.mktempfile(data)
326 print 'IPython will make a temporary file named:',filename
340 print 'IPython will make a temporary file named:',filename
327
341
328 return filename, lineno, use_temp
342 return filename, lineno, use_temp
329
343
330 def _edit_macro(self,mname,macro):
344 def _edit_macro(self,mname,macro):
331 """open an editor with the macro data in a file"""
345 """open an editor with the macro data in a file"""
332 filename = self.shell.mktempfile(macro.value)
346 filename = self.shell.mktempfile(macro.value)
333 self.shell.hooks.editor(filename)
347 self.shell.hooks.editor(filename)
334
348
335 # and make a new macro object, to replace the old one
349 # and make a new macro object, to replace the old one
336 mfile = open(filename)
350 mfile = open(filename)
337 mvalue = mfile.read()
351 mvalue = mfile.read()
338 mfile.close()
352 mfile.close()
339 self.shell.user_ns[mname] = Macro(mvalue)
353 self.shell.user_ns[mname] = Macro(mvalue)
340
354
341 @skip_doctest
355 @skip_doctest
342 @line_magic
356 @line_magic
343 def edit(self, parameter_s='',last_call=['','']):
357 def edit(self, parameter_s='',last_call=['','']):
344 """Bring up an editor and execute the resulting code.
358 """Bring up an editor and execute the resulting code.
345
359
346 Usage:
360 Usage:
347 %edit [options] [args]
361 %edit [options] [args]
348
362
349 %edit runs IPython's editor hook. The default version of this hook is
363 %edit runs IPython's editor hook. The default version of this hook is
350 set to call the editor specified by your $EDITOR environment variable.
364 set to call the editor specified by your $EDITOR environment variable.
351 If this isn't found, it will default to vi under Linux/Unix and to
365 If this isn't found, it will default to vi under Linux/Unix and to
352 notepad under Windows. See the end of this docstring for how to change
366 notepad under Windows. See the end of this docstring for how to change
353 the editor hook.
367 the editor hook.
354
368
355 You can also set the value of this editor via the
369 You can also set the value of this editor via the
356 ``TerminalInteractiveShell.editor`` option in your configuration file.
370 ``TerminalInteractiveShell.editor`` option in your configuration file.
357 This is useful if you wish to use a different editor from your typical
371 This is useful if you wish to use a different editor from your typical
358 default with IPython (and for Windows users who typically don't set
372 default with IPython (and for Windows users who typically don't set
359 environment variables).
373 environment variables).
360
374
361 This command allows you to conveniently edit multi-line code right in
375 This command allows you to conveniently edit multi-line code right in
362 your IPython session.
376 your IPython session.
363
377
364 If called without arguments, %edit opens up an empty editor with a
378 If called without arguments, %edit opens up an empty editor with a
365 temporary file and will execute the contents of this file when you
379 temporary file and will execute the contents of this file when you
366 close it (don't forget to save it!).
380 close it (don't forget to save it!).
367
381
368
382
369 Options:
383 Options:
370
384
371 -n <number>: open the editor at a specified line number. By default,
385 -n <number>: open the editor at a specified line number. By default,
372 the IPython editor hook uses the unix syntax 'editor +N filename', but
386 the IPython editor hook uses the unix syntax 'editor +N filename', but
373 you can configure this by providing your own modified hook if your
387 you can configure this by providing your own modified hook if your
374 favorite editor supports line-number specifications with a different
388 favorite editor supports line-number specifications with a different
375 syntax.
389 syntax.
376
390
377 -p: this will call the editor with the same data as the previous time
391 -p: this will call the editor with the same data as the previous time
378 it was used, regardless of how long ago (in your current session) it
392 it was used, regardless of how long ago (in your current session) it
379 was.
393 was.
380
394
381 -r: use 'raw' input. This option only applies to input taken from the
395 -r: use 'raw' input. This option only applies to input taken from the
382 user's history. By default, the 'processed' history is used, so that
396 user's history. By default, the 'processed' history is used, so that
383 magics are loaded in their transformed version to valid Python. If
397 magics are loaded in their transformed version to valid Python. If
384 this option is given, the raw input as typed as the command line is
398 this option is given, the raw input as typed as the command line is
385 used instead. When you exit the editor, it will be executed by
399 used instead. When you exit the editor, it will be executed by
386 IPython's own processor.
400 IPython's own processor.
387
401
388 -x: do not execute the edited code immediately upon exit. This is
402 -x: do not execute the edited code immediately upon exit. This is
389 mainly useful if you are editing programs which need to be called with
403 mainly useful if you are editing programs which need to be called with
390 command line arguments, which you can then do using %run.
404 command line arguments, which you can then do using %run.
391
405
392
406
393 Arguments:
407 Arguments:
394
408
395 If arguments are given, the following possibilities exist:
409 If arguments are given, the following possibilities exist:
396
410
397 - If the argument is a filename, IPython will load that into the
411 - If the argument is a filename, IPython will load that into the
398 editor. It will execute its contents with execfile() when you exit,
412 editor. It will execute its contents with execfile() when you exit,
399 loading any code in the file into your interactive namespace.
413 loading any code in the file into your interactive namespace.
400
414
401 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
415 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
402 The syntax is the same as in the %history magic.
416 The syntax is the same as in the %history magic.
403
417
404 - If the argument is a string variable, its contents are loaded
418 - If the argument is a string variable, its contents are loaded
405 into the editor. You can thus edit any string which contains
419 into the editor. You can thus edit any string which contains
406 python code (including the result of previous edits).
420 python code (including the result of previous edits).
407
421
408 - If the argument is the name of an object (other than a string),
422 - If the argument is the name of an object (other than a string),
409 IPython will try to locate the file where it was defined and open the
423 IPython will try to locate the file where it was defined and open the
410 editor at the point where it is defined. You can use `%edit function`
424 editor at the point where it is defined. You can use `%edit function`
411 to load an editor exactly at the point where 'function' is defined,
425 to load an editor exactly at the point where 'function' is defined,
412 edit it and have the file be executed automatically.
426 edit it and have the file be executed automatically.
413
427
414 - If the object is a macro (see %macro for details), this opens up your
428 - If the object is a macro (see %macro for details), this opens up your
415 specified editor with a temporary file containing the macro's data.
429 specified editor with a temporary file containing the macro's data.
416 Upon exit, the macro is reloaded with the contents of the file.
430 Upon exit, the macro is reloaded with the contents of the file.
417
431
418 Note: opening at an exact line is only supported under Unix, and some
432 Note: opening at an exact line is only supported under Unix, and some
419 editors (like kedit and gedit up to Gnome 2.8) do not understand the
433 editors (like kedit and gedit up to Gnome 2.8) do not understand the
420 '+NUMBER' parameter necessary for this feature. Good editors like
434 '+NUMBER' parameter necessary for this feature. Good editors like
421 (X)Emacs, vi, jed, pico and joe all do.
435 (X)Emacs, vi, jed, pico and joe all do.
422
436
423 After executing your code, %edit will return as output the code you
437 After executing your code, %edit will return as output the code you
424 typed in the editor (except when it was an existing file). This way
438 typed in the editor (except when it was an existing file). This way
425 you can reload the code in further invocations of %edit as a variable,
439 you can reload the code in further invocations of %edit as a variable,
426 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
440 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
427 the output.
441 the output.
428
442
429 Note that %edit is also available through the alias %ed.
443 Note that %edit is also available through the alias %ed.
430
444
431 This is an example of creating a simple function inside the editor and
445 This is an example of creating a simple function inside the editor and
432 then modifying it. First, start up the editor::
446 then modifying it. First, start up the editor::
433
447
434 In [1]: edit
448 In [1]: edit
435 Editing... done. Executing edited code...
449 Editing... done. Executing edited code...
436 Out[1]: 'def foo():\\n print "foo() was defined in an editing
450 Out[1]: 'def foo():\\n print "foo() was defined in an editing
437 session"\\n'
451 session"\\n'
438
452
439 We can then call the function foo()::
453 We can then call the function foo()::
440
454
441 In [2]: foo()
455 In [2]: foo()
442 foo() was defined in an editing session
456 foo() was defined in an editing session
443
457
444 Now we edit foo. IPython automatically loads the editor with the
458 Now we edit foo. IPython automatically loads the editor with the
445 (temporary) file where foo() was previously defined::
459 (temporary) file where foo() was previously defined::
446
460
447 In [3]: edit foo
461 In [3]: edit foo
448 Editing... done. Executing edited code...
462 Editing... done. Executing edited code...
449
463
450 And if we call foo() again we get the modified version::
464 And if we call foo() again we get the modified version::
451
465
452 In [4]: foo()
466 In [4]: foo()
453 foo() has now been changed!
467 foo() has now been changed!
454
468
455 Here is an example of how to edit a code snippet successive
469 Here is an example of how to edit a code snippet successive
456 times. First we call the editor::
470 times. First we call the editor::
457
471
458 In [5]: edit
472 In [5]: edit
459 Editing... done. Executing edited code...
473 Editing... done. Executing edited code...
460 hello
474 hello
461 Out[5]: "print 'hello'\\n"
475 Out[5]: "print 'hello'\\n"
462
476
463 Now we call it again with the previous output (stored in _)::
477 Now we call it again with the previous output (stored in _)::
464
478
465 In [6]: edit _
479 In [6]: edit _
466 Editing... done. Executing edited code...
480 Editing... done. Executing edited code...
467 hello world
481 hello world
468 Out[6]: "print 'hello world'\\n"
482 Out[6]: "print 'hello world'\\n"
469
483
470 Now we call it with the output #8 (stored in _8, also as Out[8])::
484 Now we call it with the output #8 (stored in _8, also as Out[8])::
471
485
472 In [7]: edit _8
486 In [7]: edit _8
473 Editing... done. Executing edited code...
487 Editing... done. Executing edited code...
474 hello again
488 hello again
475 Out[7]: "print 'hello again'\\n"
489 Out[7]: "print 'hello again'\\n"
476
490
477
491
478 Changing the default editor hook:
492 Changing the default editor hook:
479
493
480 If you wish to write your own editor hook, you can put it in a
494 If you wish to write your own editor hook, you can put it in a
481 configuration file which you load at startup time. The default hook
495 configuration file which you load at startup time. The default hook
482 is defined in the IPython.core.hooks module, and you can use that as a
496 is defined in the IPython.core.hooks module, and you can use that as a
483 starting example for further modifications. That file also has
497 starting example for further modifications. That file also has
484 general instructions on how to set a new hook for use once you've
498 general instructions on how to set a new hook for use once you've
485 defined it."""
499 defined it."""
486 opts,args = self.parse_options(parameter_s,'prxn:')
500 opts,args = self.parse_options(parameter_s,'prxn:')
487
501
488 try:
502 try:
489 filename, lineno, is_temp = self._find_edit_target(self.shell,
503 filename, lineno, is_temp = self._find_edit_target(self.shell,
490 args, opts, last_call)
504 args, opts, last_call)
491 except MacroToEdit as e:
505 except MacroToEdit as e:
492 self._edit_macro(args, e.args[0])
506 self._edit_macro(args, e.args[0])
493 return
507 return
508 except InteractivelyDefined as e:
509 print "Editing In[%i]" % e.index
510 args = str(e.index)
511 filename, lineno, is_temp = self._find_edit_target(self.shell,
512 args, opts, last_call)
513 if filename is None:
514 # nothing was found, warnings have already been issued,
515 # just give up.
516 return
494
517
495 # do actual editing here
518 # do actual editing here
496 print 'Editing...',
519 print 'Editing...',
497 sys.stdout.flush()
520 sys.stdout.flush()
498 try:
521 try:
499 # Quote filenames that may have spaces in them
522 # Quote filenames that may have spaces in them
500 if ' ' in filename:
523 if ' ' in filename:
501 filename = "'%s'" % filename
524 filename = "'%s'" % filename
502 self.shell.hooks.editor(filename,lineno)
525 self.shell.hooks.editor(filename,lineno)
503 except TryNext:
526 except TryNext:
504 warn('Could not open editor')
527 warn('Could not open editor')
505 return
528 return
506
529
507 # XXX TODO: should this be generalized for all string vars?
530 # XXX TODO: should this be generalized for all string vars?
508 # For now, this is special-cased to blocks created by cpaste
531 # For now, this is special-cased to blocks created by cpaste
509 if args.strip() == 'pasted_block':
532 if args.strip() == 'pasted_block':
510 self.shell.user_ns['pasted_block'] = file_read(filename)
533 self.shell.user_ns['pasted_block'] = file_read(filename)
511
534
512 if 'x' in opts: # -x prevents actual execution
535 if 'x' in opts: # -x prevents actual execution
513 print
536 print
514 else:
537 else:
515 print 'done. Executing edited code...'
538 print 'done. Executing edited code...'
516 if 'r' in opts: # Untranslated IPython code
539 if 'r' in opts: # Untranslated IPython code
517 self.shell.run_cell(file_read(filename),
540 self.shell.run_cell(file_read(filename),
518 store_history=False)
541 store_history=False)
519 else:
542 else:
520 self.shell.safe_execfile(filename, self.shell.user_ns,
543 self.shell.safe_execfile(filename, self.shell.user_ns,
521 self.shell.user_ns)
544 self.shell.user_ns)
522
545
523 if is_temp:
546 if is_temp:
524 try:
547 try:
525 return open(filename).read()
548 return open(filename).read()
526 except IOError as msg:
549 except IOError as msg:
527 if msg.filename == filename:
550 if msg.filename == filename:
528 warn('File not found. Did you forget to save?')
551 warn('File not found. Did you forget to save?')
529 return
552 return
530 else:
553 else:
531 self.shell.showtraceback()
554 self.shell.showtraceback()
@@ -1,873 +1,875
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 __builtin__
21 import __builtin__
22 import inspect
22 import inspect
23 import linecache
23 import linecache
24 import os
24 import os
25 import sys
25 import sys
26 import types
26 import types
27 import io as stdlib_io
27 import io as stdlib_io
28
28
29 from collections import namedtuple
29 from collections import namedtuple
30 try:
30 try:
31 from itertools import izip_longest
31 from itertools import izip_longest
32 except ImportError:
32 except ImportError:
33 from itertools import zip_longest as izip_longest
33 from itertools import zip_longest as izip_longest
34
34
35 # IPython's own
35 # IPython's own
36 from IPython.core import page
36 from IPython.core import page
37 from IPython.testing.skipdoctest import skip_doctest_py3
37 from IPython.testing.skipdoctest import skip_doctest_py3
38 from IPython.utils import PyColorize
38 from IPython.utils import PyColorize
39 from IPython.utils import io
39 from IPython.utils import io
40 from IPython.utils import openpy
40 from IPython.utils import openpy
41 from IPython.utils import py3compat
41 from IPython.utils import py3compat
42 from IPython.utils.text import indent
42 from IPython.utils.text import indent
43 from IPython.utils.wildcard import list_namespace
43 from IPython.utils.wildcard import list_namespace
44 from IPython.utils.coloransi import *
44 from IPython.utils.coloransi import *
45 from IPython.utils.py3compat import cast_unicode
45 from IPython.utils.py3compat import cast_unicode
46
46
47 #****************************************************************************
47 #****************************************************************************
48 # Builtin color schemes
48 # Builtin color schemes
49
49
50 Colors = TermColors # just a shorthand
50 Colors = TermColors # just a shorthand
51
51
52 # Build a few color schemes
52 # Build a few color schemes
53 NoColor = ColorScheme(
53 NoColor = ColorScheme(
54 'NoColor',{
54 'NoColor',{
55 'header' : Colors.NoColor,
55 'header' : Colors.NoColor,
56 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
56 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
57 } )
57 } )
58
58
59 LinuxColors = ColorScheme(
59 LinuxColors = ColorScheme(
60 'Linux',{
60 'Linux',{
61 'header' : Colors.LightRed,
61 'header' : Colors.LightRed,
62 'normal' : Colors.Normal # color off (usu. Colors.Normal)
62 'normal' : Colors.Normal # color off (usu. Colors.Normal)
63 } )
63 } )
64
64
65 LightBGColors = ColorScheme(
65 LightBGColors = ColorScheme(
66 'LightBG',{
66 'LightBG',{
67 'header' : Colors.Red,
67 'header' : Colors.Red,
68 'normal' : Colors.Normal # color off (usu. Colors.Normal)
68 'normal' : Colors.Normal # color off (usu. Colors.Normal)
69 } )
69 } )
70
70
71 # Build table of color schemes (needed by the parser)
71 # Build table of color schemes (needed by the parser)
72 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
72 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
73 'Linux')
73 'Linux')
74
74
75 #****************************************************************************
75 #****************************************************************************
76 # Auxiliary functions and objects
76 # Auxiliary functions and objects
77
77
78 # See the messaging spec for the definition of all these fields. This list
78 # See the messaging spec for the definition of all these fields. This list
79 # effectively defines the order of display
79 # effectively defines the order of display
80 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
80 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
81 'length', 'file', 'definition', 'docstring', 'source',
81 'length', 'file', 'definition', 'docstring', 'source',
82 'init_definition', 'class_docstring', 'init_docstring',
82 'init_definition', 'class_docstring', 'init_docstring',
83 'call_def', 'call_docstring',
83 'call_def', 'call_docstring',
84 # These won't be printed but will be used to determine how to
84 # These won't be printed but will be used to determine how to
85 # format the object
85 # format the object
86 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
86 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
87 ]
87 ]
88
88
89
89
90 def object_info(**kw):
90 def object_info(**kw):
91 """Make an object info dict with all fields present."""
91 """Make an object info dict with all fields present."""
92 infodict = dict(izip_longest(info_fields, [None]))
92 infodict = dict(izip_longest(info_fields, [None]))
93 infodict.update(kw)
93 infodict.update(kw)
94 return infodict
94 return infodict
95
95
96
96
97 def get_encoding(obj):
97 def get_encoding(obj):
98 """Get encoding for python source file defining obj
98 """Get encoding for python source file defining obj
99
99
100 Returns None if obj is not defined in a sourcefile.
100 Returns None if obj is not defined in a sourcefile.
101 """
101 """
102 ofile = find_file(obj)
102 ofile = find_file(obj)
103 # run contents of file through pager starting at line where the object
103 # run contents of file through pager starting at line where the object
104 # is defined, as long as the file isn't binary and is actually on the
104 # is defined, as long as the file isn't binary and is actually on the
105 # filesystem.
105 # filesystem.
106 if ofile is None:
106 if ofile is None:
107 return None
107 return None
108 elif ofile.endswith(('.so', '.dll', '.pyd')):
108 elif ofile.endswith(('.so', '.dll', '.pyd')):
109 return None
109 return None
110 elif not os.path.isfile(ofile):
110 elif not os.path.isfile(ofile):
111 return None
111 return None
112 else:
112 else:
113 # Print only text files, not extension binaries. Note that
113 # Print only text files, not extension binaries. Note that
114 # getsourcelines returns lineno with 1-offset and page() uses
114 # getsourcelines returns lineno with 1-offset and page() uses
115 # 0-offset, so we must adjust.
115 # 0-offset, so we must adjust.
116 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
116 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
117 encoding, lines = openpy.detect_encoding(buffer.readline)
117 encoding, lines = openpy.detect_encoding(buffer.readline)
118 return encoding
118 return encoding
119
119
120 def getdoc(obj):
120 def getdoc(obj):
121 """Stable wrapper around inspect.getdoc.
121 """Stable wrapper around inspect.getdoc.
122
122
123 This can't crash because of attribute problems.
123 This can't crash because of attribute problems.
124
124
125 It also attempts to call a getdoc() method on the given object. This
125 It also attempts to call a getdoc() method on the given object. This
126 allows objects which provide their docstrings via non-standard mechanisms
126 allows objects which provide their docstrings via non-standard mechanisms
127 (like Pyro proxies) to still be inspected by ipython's ? system."""
127 (like Pyro proxies) to still be inspected by ipython's ? system."""
128 # Allow objects to offer customized documentation via a getdoc method:
128 # Allow objects to offer customized documentation via a getdoc method:
129 try:
129 try:
130 ds = obj.getdoc()
130 ds = obj.getdoc()
131 except Exception:
131 except Exception:
132 pass
132 pass
133 else:
133 else:
134 # if we get extra info, we add it to the normal docstring.
134 # if we get extra info, we add it to the normal docstring.
135 if isinstance(ds, basestring):
135 if isinstance(ds, basestring):
136 return inspect.cleandoc(ds)
136 return inspect.cleandoc(ds)
137
137
138 try:
138 try:
139 docstr = inspect.getdoc(obj)
139 docstr = inspect.getdoc(obj)
140 encoding = get_encoding(obj)
140 encoding = get_encoding(obj)
141 return py3compat.cast_unicode(docstr, encoding=encoding)
141 return py3compat.cast_unicode(docstr, encoding=encoding)
142 except Exception:
142 except Exception:
143 # Harden against an inspect failure, which can occur with
143 # Harden against an inspect failure, which can occur with
144 # SWIG-wrapped extensions.
144 # SWIG-wrapped extensions.
145 raise
145 raise
146 return None
146 return None
147
147
148
148
149 def getsource(obj,is_binary=False):
149 def getsource(obj,is_binary=False):
150 """Wrapper around inspect.getsource.
150 """Wrapper around inspect.getsource.
151
151
152 This can be modified by other projects to provide customized source
152 This can be modified by other projects to provide customized source
153 extraction.
153 extraction.
154
154
155 Inputs:
155 Inputs:
156
156
157 - obj: an object whose source code we will attempt to extract.
157 - obj: an object whose source code we will attempt to extract.
158
158
159 Optional inputs:
159 Optional inputs:
160
160
161 - is_binary: whether the object is known to come from a binary source.
161 - is_binary: whether the object is known to come from a binary source.
162 This implementation will skip returning any output for binary objects, but
162 This implementation will skip returning any output for binary objects, but
163 custom extractors may know how to meaningfully process them."""
163 custom extractors may know how to meaningfully process them."""
164
164
165 if is_binary:
165 if is_binary:
166 return None
166 return None
167 else:
167 else:
168 # get source if obj was decorated with @decorator
168 # get source if obj was decorated with @decorator
169 if hasattr(obj,"__wrapped__"):
169 if hasattr(obj,"__wrapped__"):
170 obj = obj.__wrapped__
170 obj = obj.__wrapped__
171 try:
171 try:
172 src = inspect.getsource(obj)
172 src = inspect.getsource(obj)
173 except TypeError:
173 except TypeError:
174 if hasattr(obj,'__class__'):
174 if hasattr(obj,'__class__'):
175 src = inspect.getsource(obj.__class__)
175 src = inspect.getsource(obj.__class__)
176 encoding = get_encoding(obj)
176 encoding = get_encoding(obj)
177 return cast_unicode(src, encoding=encoding)
177 return cast_unicode(src, encoding=encoding)
178
178
179 def getargspec(obj):
179 def getargspec(obj):
180 """Get the names and default values of a function's arguments.
180 """Get the names and default values of a function's arguments.
181
181
182 A tuple of four things is returned: (args, varargs, varkw, defaults).
182 A tuple of four things is returned: (args, varargs, varkw, defaults).
183 'args' is a list of the argument names (it may contain nested lists).
183 'args' is a list of the argument names (it may contain nested lists).
184 'varargs' and 'varkw' are the names of the * and ** arguments or None.
184 'varargs' and 'varkw' are the names of the * and ** arguments or None.
185 'defaults' is an n-tuple of the default values of the last n arguments.
185 'defaults' is an n-tuple of the default values of the last n arguments.
186
186
187 Modified version of inspect.getargspec from the Python Standard
187 Modified version of inspect.getargspec from the Python Standard
188 Library."""
188 Library."""
189
189
190 if inspect.isfunction(obj):
190 if inspect.isfunction(obj):
191 func_obj = obj
191 func_obj = obj
192 elif inspect.ismethod(obj):
192 elif inspect.ismethod(obj):
193 func_obj = obj.im_func
193 func_obj = obj.im_func
194 elif hasattr(obj, '__call__'):
194 elif hasattr(obj, '__call__'):
195 func_obj = obj.__call__
195 func_obj = obj.__call__
196 else:
196 else:
197 raise TypeError('arg is not a Python function')
197 raise TypeError('arg is not a Python function')
198 args, varargs, varkw = inspect.getargs(func_obj.func_code)
198 args, varargs, varkw = inspect.getargs(func_obj.func_code)
199 return args, varargs, varkw, func_obj.func_defaults
199 return args, varargs, varkw, func_obj.func_defaults
200
200
201
201
202 def format_argspec(argspec):
202 def format_argspec(argspec):
203 """Format argspect, convenience wrapper around inspect's.
203 """Format argspect, convenience wrapper around inspect's.
204
204
205 This takes a dict instead of ordered arguments and calls
205 This takes a dict instead of ordered arguments and calls
206 inspect.format_argspec with the arguments in the necessary order.
206 inspect.format_argspec with the arguments in the necessary order.
207 """
207 """
208 return inspect.formatargspec(argspec['args'], argspec['varargs'],
208 return inspect.formatargspec(argspec['args'], argspec['varargs'],
209 argspec['varkw'], argspec['defaults'])
209 argspec['varkw'], argspec['defaults'])
210
210
211
211
212 def call_tip(oinfo, format_call=True):
212 def call_tip(oinfo, format_call=True):
213 """Extract call tip data from an oinfo dict.
213 """Extract call tip data from an oinfo dict.
214
214
215 Parameters
215 Parameters
216 ----------
216 ----------
217 oinfo : dict
217 oinfo : dict
218
218
219 format_call : bool, optional
219 format_call : bool, optional
220 If True, the call line is formatted and returned as a string. If not, a
220 If True, the call line is formatted and returned as a string. If not, a
221 tuple of (name, argspec) is returned.
221 tuple of (name, argspec) is returned.
222
222
223 Returns
223 Returns
224 -------
224 -------
225 call_info : None, str or (str, dict) tuple.
225 call_info : None, str or (str, dict) tuple.
226 When format_call is True, the whole call information is formattted as a
226 When format_call is True, the whole call information is formattted as a
227 single string. Otherwise, the object's name and its argspec dict are
227 single string. Otherwise, the object's name and its argspec dict are
228 returned. If no call information is available, None is returned.
228 returned. If no call information is available, None is returned.
229
229
230 docstring : str or None
230 docstring : str or None
231 The most relevant docstring for calling purposes is returned, if
231 The most relevant docstring for calling purposes is returned, if
232 available. The priority is: call docstring for callable instances, then
232 available. The priority is: call docstring for callable instances, then
233 constructor docstring for classes, then main object's docstring otherwise
233 constructor docstring for classes, then main object's docstring otherwise
234 (regular functions).
234 (regular functions).
235 """
235 """
236 # Get call definition
236 # Get call definition
237 argspec = oinfo.get('argspec')
237 argspec = oinfo.get('argspec')
238 if argspec is None:
238 if argspec is None:
239 call_line = None
239 call_line = None
240 else:
240 else:
241 # Callable objects will have 'self' as their first argument, prune
241 # Callable objects will have 'self' as their first argument, prune
242 # it out if it's there for clarity (since users do *not* pass an
242 # it out if it's there for clarity (since users do *not* pass an
243 # extra first argument explicitly).
243 # extra first argument explicitly).
244 try:
244 try:
245 has_self = argspec['args'][0] == 'self'
245 has_self = argspec['args'][0] == 'self'
246 except (KeyError, IndexError):
246 except (KeyError, IndexError):
247 pass
247 pass
248 else:
248 else:
249 if has_self:
249 if has_self:
250 argspec['args'] = argspec['args'][1:]
250 argspec['args'] = argspec['args'][1:]
251
251
252 call_line = oinfo['name']+format_argspec(argspec)
252 call_line = oinfo['name']+format_argspec(argspec)
253
253
254 # Now get docstring.
254 # Now get docstring.
255 # The priority is: call docstring, constructor docstring, main one.
255 # The priority is: call docstring, constructor docstring, main one.
256 doc = oinfo.get('call_docstring')
256 doc = oinfo.get('call_docstring')
257 if doc is None:
257 if doc is None:
258 doc = oinfo.get('init_docstring')
258 doc = oinfo.get('init_docstring')
259 if doc is None:
259 if doc is None:
260 doc = oinfo.get('docstring','')
260 doc = oinfo.get('docstring','')
261
261
262 return call_line, doc
262 return call_line, doc
263
263
264
264
265 def find_file(obj):
265 def find_file(obj):
266 """Find the absolute path to the file where an object was defined.
266 """Find the absolute path to the file where an object was defined.
267
267
268 This is essentially a robust wrapper around `inspect.getabsfile`.
268 This is essentially a robust wrapper around `inspect.getabsfile`.
269
269
270 Returns None if no file can be found.
270 Returns None if no file can be found.
271
271
272 Parameters
272 Parameters
273 ----------
273 ----------
274 obj : any Python object
274 obj : any Python object
275
275
276 Returns
276 Returns
277 -------
277 -------
278 fname : str
278 fname : str
279 The absolute path to the file where the object was defined.
279 The absolute path to the file where the object was defined.
280 """
280 """
281 # get source if obj was decorated with @decorator
281 # get source if obj was decorated with @decorator
282 if hasattr(obj, '__wrapped__'):
282 if hasattr(obj, '__wrapped__'):
283 obj = obj.__wrapped__
283 obj = obj.__wrapped__
284
284
285 fname = None
285 fname = None
286 try:
286 try:
287 fname = inspect.getabsfile(obj)
287 fname = inspect.getabsfile(obj)
288 except TypeError:
288 except TypeError:
289 # For an instance, the file that matters is where its class was
289 # For an instance, the file that matters is where its class was
290 # declared.
290 # declared.
291 if hasattr(obj, '__class__'):
291 if hasattr(obj, '__class__'):
292 try:
292 try:
293 fname = inspect.getabsfile(obj.__class__)
293 fname = inspect.getabsfile(obj.__class__)
294 except TypeError:
294 except TypeError:
295 # Can happen for builtins
295 # Can happen for builtins
296 pass
296 pass
297 except:
297 except:
298 pass
298 pass
299 return fname
299 return cast_unicode(fname)
300
300
301
301
302 def find_source_lines(obj):
302 def find_source_lines(obj):
303 """Find the line number in a file where an object was defined.
303 """Find the line number in a file where an object was defined.
304
304
305 This is essentially a robust wrapper around `inspect.getsourcelines`.
305 This is essentially a robust wrapper around `inspect.getsourcelines`.
306
306
307 Returns None if no file can be found.
307 Returns None if no file can be found.
308
308
309 Parameters
309 Parameters
310 ----------
310 ----------
311 obj : any Python object
311 obj : any Python object
312
312
313 Returns
313 Returns
314 -------
314 -------
315 lineno : int
315 lineno : int
316 The line number where the object definition starts.
316 The line number where the object definition starts.
317 """
317 """
318 # get source if obj was decorated with @decorator
318 # get source if obj was decorated with @decorator
319 if hasattr(obj, '__wrapped__'):
319 if hasattr(obj, '__wrapped__'):
320 obj = obj.__wrapped__
320 obj = obj.__wrapped__
321
321
322 try:
322 try:
323 try:
323 try:
324 lineno = inspect.getsourcelines(obj)[1]
324 lineno = inspect.getsourcelines(obj)[1]
325 except TypeError:
325 except TypeError:
326 # For instances, try the class object like getsource() does
326 # For instances, try the class object like getsource() does
327 if hasattr(obj, '__class__'):
327 if hasattr(obj, '__class__'):
328 lineno = inspect.getsourcelines(obj.__class__)[1]
328 lineno = inspect.getsourcelines(obj.__class__)[1]
329 else:
330 lineno = None
329 except:
331 except:
330 return None
332 return None
331
333
332 return lineno
334 return lineno
333
335
334
336
335 class Inspector:
337 class Inspector:
336 def __init__(self, color_table=InspectColors,
338 def __init__(self, color_table=InspectColors,
337 code_color_table=PyColorize.ANSICodeColors,
339 code_color_table=PyColorize.ANSICodeColors,
338 scheme='NoColor',
340 scheme='NoColor',
339 str_detail_level=0):
341 str_detail_level=0):
340 self.color_table = color_table
342 self.color_table = color_table
341 self.parser = PyColorize.Parser(code_color_table,out='str')
343 self.parser = PyColorize.Parser(code_color_table,out='str')
342 self.format = self.parser.format
344 self.format = self.parser.format
343 self.str_detail_level = str_detail_level
345 self.str_detail_level = str_detail_level
344 self.set_active_scheme(scheme)
346 self.set_active_scheme(scheme)
345
347
346 def _getdef(self,obj,oname=''):
348 def _getdef(self,obj,oname=''):
347 """Return the call signature for any callable object.
349 """Return the call signature for any callable object.
348
350
349 If any exception is generated, None is returned instead and the
351 If any exception is generated, None is returned instead and the
350 exception is suppressed."""
352 exception is suppressed."""
351
353
352 try:
354 try:
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
355 hdef = oname + inspect.formatargspec(*getargspec(obj))
354 return cast_unicode(hdef)
356 return cast_unicode(hdef)
355 except:
357 except:
356 return None
358 return None
357
359
358 def __head(self,h):
360 def __head(self,h):
359 """Return a header string with proper colors."""
361 """Return a header string with proper colors."""
360 return '%s%s%s' % (self.color_table.active_colors.header,h,
362 return '%s%s%s' % (self.color_table.active_colors.header,h,
361 self.color_table.active_colors.normal)
363 self.color_table.active_colors.normal)
362
364
363 def set_active_scheme(self, scheme):
365 def set_active_scheme(self, scheme):
364 self.color_table.set_active_scheme(scheme)
366 self.color_table.set_active_scheme(scheme)
365 self.parser.color_table.set_active_scheme(scheme)
367 self.parser.color_table.set_active_scheme(scheme)
366
368
367 def noinfo(self, msg, oname):
369 def noinfo(self, msg, oname):
368 """Generic message when no information is found."""
370 """Generic message when no information is found."""
369 print('No %s found' % msg, end=' ')
371 print('No %s found' % msg, end=' ')
370 if oname:
372 if oname:
371 print('for %s' % oname)
373 print('for %s' % oname)
372 else:
374 else:
373 print()
375 print()
374
376
375 def pdef(self, obj, oname=''):
377 def pdef(self, obj, oname=''):
376 """Print the call signature for any callable object.
378 """Print the call signature for any callable object.
377
379
378 If the object is a class, print the constructor information."""
380 If the object is a class, print the constructor information."""
379
381
380 if not callable(obj):
382 if not callable(obj):
381 print('Object is not callable.')
383 print('Object is not callable.')
382 return
384 return
383
385
384 header = ''
386 header = ''
385
387
386 if inspect.isclass(obj):
388 if inspect.isclass(obj):
387 header = self.__head('Class constructor information:\n')
389 header = self.__head('Class constructor information:\n')
388 obj = obj.__init__
390 obj = obj.__init__
389 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
391 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
390 obj = obj.__call__
392 obj = obj.__call__
391
393
392 output = self._getdef(obj,oname)
394 output = self._getdef(obj,oname)
393 if output is None:
395 if output is None:
394 self.noinfo('definition header',oname)
396 self.noinfo('definition header',oname)
395 else:
397 else:
396 print(header,self.format(output), end=' ', file=io.stdout)
398 print(header,self.format(output), end=' ', file=io.stdout)
397
399
398 # In Python 3, all classes are new-style, so they all have __init__.
400 # In Python 3, all classes are new-style, so they all have __init__.
399 @skip_doctest_py3
401 @skip_doctest_py3
400 def pdoc(self,obj,oname='',formatter = None):
402 def pdoc(self,obj,oname='',formatter = None):
401 """Print the docstring for any object.
403 """Print the docstring for any object.
402
404
403 Optional:
405 Optional:
404 -formatter: a function to run the docstring through for specially
406 -formatter: a function to run the docstring through for specially
405 formatted docstrings.
407 formatted docstrings.
406
408
407 Examples
409 Examples
408 --------
410 --------
409
411
410 In [1]: class NoInit:
412 In [1]: class NoInit:
411 ...: pass
413 ...: pass
412
414
413 In [2]: class NoDoc:
415 In [2]: class NoDoc:
414 ...: def __init__(self):
416 ...: def __init__(self):
415 ...: pass
417 ...: pass
416
418
417 In [3]: %pdoc NoDoc
419 In [3]: %pdoc NoDoc
418 No documentation found for NoDoc
420 No documentation found for NoDoc
419
421
420 In [4]: %pdoc NoInit
422 In [4]: %pdoc NoInit
421 No documentation found for NoInit
423 No documentation found for NoInit
422
424
423 In [5]: obj = NoInit()
425 In [5]: obj = NoInit()
424
426
425 In [6]: %pdoc obj
427 In [6]: %pdoc obj
426 No documentation found for obj
428 No documentation found for obj
427
429
428 In [5]: obj2 = NoDoc()
430 In [5]: obj2 = NoDoc()
429
431
430 In [6]: %pdoc obj2
432 In [6]: %pdoc obj2
431 No documentation found for obj2
433 No documentation found for obj2
432 """
434 """
433
435
434 head = self.__head # For convenience
436 head = self.__head # For convenience
435 lines = []
437 lines = []
436 ds = getdoc(obj)
438 ds = getdoc(obj)
437 if formatter:
439 if formatter:
438 ds = formatter(ds)
440 ds = formatter(ds)
439 if ds:
441 if ds:
440 lines.append(head("Class Docstring:"))
442 lines.append(head("Class Docstring:"))
441 lines.append(indent(ds))
443 lines.append(indent(ds))
442 if inspect.isclass(obj) and hasattr(obj, '__init__'):
444 if inspect.isclass(obj) and hasattr(obj, '__init__'):
443 init_ds = getdoc(obj.__init__)
445 init_ds = getdoc(obj.__init__)
444 if init_ds is not None:
446 if init_ds is not None:
445 lines.append(head("Constructor Docstring:"))
447 lines.append(head("Constructor Docstring:"))
446 lines.append(indent(init_ds))
448 lines.append(indent(init_ds))
447 elif hasattr(obj,'__call__'):
449 elif hasattr(obj,'__call__'):
448 call_ds = getdoc(obj.__call__)
450 call_ds = getdoc(obj.__call__)
449 if call_ds:
451 if call_ds:
450 lines.append(head("Calling Docstring:"))
452 lines.append(head("Calling Docstring:"))
451 lines.append(indent(call_ds))
453 lines.append(indent(call_ds))
452
454
453 if not lines:
455 if not lines:
454 self.noinfo('documentation',oname)
456 self.noinfo('documentation',oname)
455 else:
457 else:
456 page.page('\n'.join(lines))
458 page.page('\n'.join(lines))
457
459
458 def psource(self,obj,oname=''):
460 def psource(self,obj,oname=''):
459 """Print the source code for an object."""
461 """Print the source code for an object."""
460
462
461 # Flush the source cache because inspect can return out-of-date source
463 # Flush the source cache because inspect can return out-of-date source
462 linecache.checkcache()
464 linecache.checkcache()
463 try:
465 try:
464 src = getsource(obj)
466 src = getsource(obj)
465 except:
467 except:
466 self.noinfo('source',oname)
468 self.noinfo('source',oname)
467 else:
469 else:
468 page.page(self.format(src))
470 page.page(self.format(src))
469
471
470 def pfile(self, obj, oname=''):
472 def pfile(self, obj, oname=''):
471 """Show the whole file where an object was defined."""
473 """Show the whole file where an object was defined."""
472
474
473 lineno = find_source_lines(obj)
475 lineno = find_source_lines(obj)
474 if lineno is None:
476 if lineno is None:
475 self.noinfo('file', oname)
477 self.noinfo('file', oname)
476 return
478 return
477
479
478 ofile = find_file(obj)
480 ofile = find_file(obj)
479 # run contents of file through pager starting at line where the object
481 # 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
482 # is defined, as long as the file isn't binary and is actually on the
481 # filesystem.
483 # filesystem.
482 if ofile.endswith(('.so', '.dll', '.pyd')):
484 if ofile.endswith(('.so', '.dll', '.pyd')):
483 print('File %r is binary, not printing.' % ofile)
485 print('File %r is binary, not printing.' % ofile)
484 elif not os.path.isfile(ofile):
486 elif not os.path.isfile(ofile):
485 print('File %r does not exist, not printing.' % ofile)
487 print('File %r does not exist, not printing.' % ofile)
486 else:
488 else:
487 # Print only text files, not extension binaries. Note that
489 # Print only text files, not extension binaries. Note that
488 # getsourcelines returns lineno with 1-offset and page() uses
490 # getsourcelines returns lineno with 1-offset and page() uses
489 # 0-offset, so we must adjust.
491 # 0-offset, so we must adjust.
490 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
492 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
491
493
492 def _format_fields(self, fields, title_width=12):
494 def _format_fields(self, fields, title_width=12):
493 """Formats a list of fields for display.
495 """Formats a list of fields for display.
494
496
495 Parameters
497 Parameters
496 ----------
498 ----------
497 fields : list
499 fields : list
498 A list of 2-tuples: (field_title, field_content)
500 A list of 2-tuples: (field_title, field_content)
499 title_width : int
501 title_width : int
500 How many characters to pad titles to. Default 12.
502 How many characters to pad titles to. Default 12.
501 """
503 """
502 out = []
504 out = []
503 header = self.__head
505 header = self.__head
504 for title, content in fields:
506 for title, content in fields:
505 if len(content.splitlines()) > 1:
507 if len(content.splitlines()) > 1:
506 title = header(title + ":") + "\n"
508 title = header(title + ":") + "\n"
507 else:
509 else:
508 title = header((title+":").ljust(title_width))
510 title = header((title+":").ljust(title_width))
509 out.append(cast_unicode(title) + cast_unicode(content))
511 out.append(cast_unicode(title) + cast_unicode(content))
510 return "\n".join(out)
512 return "\n".join(out)
511
513
512 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
514 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
513 pinfo_fields1 = [("Type", "type_name"),
515 pinfo_fields1 = [("Type", "type_name"),
514 ]
516 ]
515
517
516 pinfo_fields2 = [("String Form", "string_form"),
518 pinfo_fields2 = [("String Form", "string_form"),
517 ]
519 ]
518
520
519 pinfo_fields3 = [("Length", "length"),
521 pinfo_fields3 = [("Length", "length"),
520 ("File", "file"),
522 ("File", "file"),
521 ("Definition", "definition"),
523 ("Definition", "definition"),
522 ]
524 ]
523
525
524 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
526 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
525 ("Constructor Docstring","init_docstring"),
527 ("Constructor Docstring","init_docstring"),
526 ("Call def", "call_def"),
528 ("Call def", "call_def"),
527 ("Call docstring", "call_docstring")]
529 ("Call docstring", "call_docstring")]
528
530
529 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
531 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
530 """Show detailed information about an object.
532 """Show detailed information about an object.
531
533
532 Optional arguments:
534 Optional arguments:
533
535
534 - oname: name of the variable pointing to the object.
536 - oname: name of the variable pointing to the object.
535
537
536 - formatter: special formatter for docstrings (see pdoc)
538 - formatter: special formatter for docstrings (see pdoc)
537
539
538 - info: a structure with some information fields which may have been
540 - info: a structure with some information fields which may have been
539 precomputed already.
541 precomputed already.
540
542
541 - detail_level: if set to 1, more information is given.
543 - detail_level: if set to 1, more information is given.
542 """
544 """
543 info = self.info(obj, oname=oname, formatter=formatter,
545 info = self.info(obj, oname=oname, formatter=formatter,
544 info=info, detail_level=detail_level)
546 info=info, detail_level=detail_level)
545 displayfields = []
547 displayfields = []
546 def add_fields(fields):
548 def add_fields(fields):
547 for title, key in fields:
549 for title, key in fields:
548 field = info[key]
550 field = info[key]
549 if field is not None:
551 if field is not None:
550 displayfields.append((title, field.rstrip()))
552 displayfields.append((title, field.rstrip()))
551
553
552 add_fields(self.pinfo_fields1)
554 add_fields(self.pinfo_fields1)
553
555
554 # Base class for old-style instances
556 # Base class for old-style instances
555 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
557 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
556 displayfields.append(("Base Class", info['base_class'].rstrip()))
558 displayfields.append(("Base Class", info['base_class'].rstrip()))
557
559
558 add_fields(self.pinfo_fields2)
560 add_fields(self.pinfo_fields2)
559
561
560 # Namespace
562 # Namespace
561 if info['namespace'] != 'Interactive':
563 if info['namespace'] != 'Interactive':
562 displayfields.append(("Namespace", info['namespace'].rstrip()))
564 displayfields.append(("Namespace", info['namespace'].rstrip()))
563
565
564 add_fields(self.pinfo_fields3)
566 add_fields(self.pinfo_fields3)
565
567
566 # Source or docstring, depending on detail level and whether
568 # Source or docstring, depending on detail level and whether
567 # source found.
569 # source found.
568 if detail_level > 0 and info['source'] is not None:
570 if detail_level > 0 and info['source'] is not None:
569 displayfields.append(("Source",
571 displayfields.append(("Source",
570 self.format(cast_unicode(info['source']))))
572 self.format(cast_unicode(info['source']))))
571 elif info['docstring'] is not None:
573 elif info['docstring'] is not None:
572 displayfields.append(("Docstring", info["docstring"]))
574 displayfields.append(("Docstring", info["docstring"]))
573
575
574 # Constructor info for classes
576 # Constructor info for classes
575 if info['isclass']:
577 if info['isclass']:
576 if info['init_definition'] or info['init_docstring']:
578 if info['init_definition'] or info['init_docstring']:
577 displayfields.append(("Constructor information", ""))
579 displayfields.append(("Constructor information", ""))
578 if info['init_definition'] is not None:
580 if info['init_definition'] is not None:
579 displayfields.append((" Definition",
581 displayfields.append((" Definition",
580 info['init_definition'].rstrip()))
582 info['init_definition'].rstrip()))
581 if info['init_docstring'] is not None:
583 if info['init_docstring'] is not None:
582 displayfields.append((" Docstring",
584 displayfields.append((" Docstring",
583 indent(info['init_docstring'])))
585 indent(info['init_docstring'])))
584
586
585 # Info for objects:
587 # Info for objects:
586 else:
588 else:
587 add_fields(self.pinfo_fields_obj)
589 add_fields(self.pinfo_fields_obj)
588
590
589 # Finally send to printer/pager:
591 # Finally send to printer/pager:
590 if displayfields:
592 if displayfields:
591 page.page(self._format_fields(displayfields))
593 page.page(self._format_fields(displayfields))
592
594
593 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
595 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
594 """Compute a dict with detailed information about an object.
596 """Compute a dict with detailed information about an object.
595
597
596 Optional arguments:
598 Optional arguments:
597
599
598 - oname: name of the variable pointing to the object.
600 - oname: name of the variable pointing to the object.
599
601
600 - formatter: special formatter for docstrings (see pdoc)
602 - formatter: special formatter for docstrings (see pdoc)
601
603
602 - info: a structure with some information fields which may have been
604 - info: a structure with some information fields which may have been
603 precomputed already.
605 precomputed already.
604
606
605 - detail_level: if set to 1, more information is given.
607 - detail_level: if set to 1, more information is given.
606 """
608 """
607
609
608 obj_type = type(obj)
610 obj_type = type(obj)
609
611
610 header = self.__head
612 header = self.__head
611 if info is None:
613 if info is None:
612 ismagic = 0
614 ismagic = 0
613 isalias = 0
615 isalias = 0
614 ospace = ''
616 ospace = ''
615 else:
617 else:
616 ismagic = info.ismagic
618 ismagic = info.ismagic
617 isalias = info.isalias
619 isalias = info.isalias
618 ospace = info.namespace
620 ospace = info.namespace
619
621
620 # Get docstring, special-casing aliases:
622 # Get docstring, special-casing aliases:
621 if isalias:
623 if isalias:
622 if not callable(obj):
624 if not callable(obj):
623 try:
625 try:
624 ds = "Alias to the system command:\n %s" % obj[1]
626 ds = "Alias to the system command:\n %s" % obj[1]
625 except:
627 except:
626 ds = "Alias: " + str(obj)
628 ds = "Alias: " + str(obj)
627 else:
629 else:
628 ds = "Alias to " + str(obj)
630 ds = "Alias to " + str(obj)
629 if obj.__doc__:
631 if obj.__doc__:
630 ds += "\nDocstring:\n" + obj.__doc__
632 ds += "\nDocstring:\n" + obj.__doc__
631 else:
633 else:
632 ds = getdoc(obj)
634 ds = getdoc(obj)
633 if ds is None:
635 if ds is None:
634 ds = '<no docstring>'
636 ds = '<no docstring>'
635 if formatter is not None:
637 if formatter is not None:
636 ds = formatter(ds)
638 ds = formatter(ds)
637
639
638 # store output in a dict, we initialize it here and fill it as we go
640 # 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)
641 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
640
642
641 string_max = 200 # max size of strings to show (snipped if longer)
643 string_max = 200 # max size of strings to show (snipped if longer)
642 shalf = int((string_max -5)/2)
644 shalf = int((string_max -5)/2)
643
645
644 if ismagic:
646 if ismagic:
645 obj_type_name = 'Magic function'
647 obj_type_name = 'Magic function'
646 elif isalias:
648 elif isalias:
647 obj_type_name = 'System alias'
649 obj_type_name = 'System alias'
648 else:
650 else:
649 obj_type_name = obj_type.__name__
651 obj_type_name = obj_type.__name__
650 out['type_name'] = obj_type_name
652 out['type_name'] = obj_type_name
651
653
652 try:
654 try:
653 bclass = obj.__class__
655 bclass = obj.__class__
654 out['base_class'] = str(bclass)
656 out['base_class'] = str(bclass)
655 except: pass
657 except: pass
656
658
657 # String form, but snip if too long in ? form (full in ??)
659 # String form, but snip if too long in ? form (full in ??)
658 if detail_level >= self.str_detail_level:
660 if detail_level >= self.str_detail_level:
659 try:
661 try:
660 ostr = str(obj)
662 ostr = str(obj)
661 str_head = 'string_form'
663 str_head = 'string_form'
662 if not detail_level and len(ostr)>string_max:
664 if not detail_level and len(ostr)>string_max:
663 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
665 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
664 ostr = ("\n" + " " * len(str_head.expandtabs())).\
666 ostr = ("\n" + " " * len(str_head.expandtabs())).\
665 join(q.strip() for q in ostr.split("\n"))
667 join(q.strip() for q in ostr.split("\n"))
666 out[str_head] = ostr
668 out[str_head] = ostr
667 except:
669 except:
668 pass
670 pass
669
671
670 if ospace:
672 if ospace:
671 out['namespace'] = ospace
673 out['namespace'] = ospace
672
674
673 # Length (for strings and lists)
675 # Length (for strings and lists)
674 try:
676 try:
675 out['length'] = str(len(obj))
677 out['length'] = str(len(obj))
676 except: pass
678 except: pass
677
679
678 # Filename where object was defined
680 # Filename where object was defined
679 binary_file = False
681 binary_file = False
680 fname = find_file(obj)
682 fname = find_file(obj)
681 if fname is None:
683 if fname is None:
682 # if anything goes wrong, we don't want to show source, so it's as
684 # if anything goes wrong, we don't want to show source, so it's as
683 # if the file was binary
685 # if the file was binary
684 binary_file = True
686 binary_file = True
685 else:
687 else:
686 if fname.endswith(('.so', '.dll', '.pyd')):
688 if fname.endswith(('.so', '.dll', '.pyd')):
687 binary_file = True
689 binary_file = True
688 elif fname.endswith('<string>'):
690 elif fname.endswith('<string>'):
689 fname = 'Dynamically generated function. No source code available.'
691 fname = 'Dynamically generated function. No source code available.'
690 out['file'] = fname
692 out['file'] = fname
691
693
692 # reconstruct the function definition and print it:
694 # reconstruct the function definition and print it:
693 defln = self._getdef(obj, oname)
695 defln = self._getdef(obj, oname)
694 if defln:
696 if defln:
695 out['definition'] = self.format(defln)
697 out['definition'] = self.format(defln)
696
698
697 # Docstrings only in detail 0 mode, since source contains them (we
699 # Docstrings only in detail 0 mode, since source contains them (we
698 # avoid repetitions). If source fails, we add them back, see below.
700 # avoid repetitions). If source fails, we add them back, see below.
699 if ds and detail_level == 0:
701 if ds and detail_level == 0:
700 out['docstring'] = ds
702 out['docstring'] = ds
701
703
702 # Original source code for any callable
704 # Original source code for any callable
703 if detail_level:
705 if detail_level:
704 # Flush the source cache because inspect can return out-of-date
706 # Flush the source cache because inspect can return out-of-date
705 # source
707 # source
706 linecache.checkcache()
708 linecache.checkcache()
707 source = None
709 source = None
708 try:
710 try:
709 try:
711 try:
710 source = getsource(obj, binary_file)
712 source = getsource(obj, binary_file)
711 except TypeError:
713 except TypeError:
712 if hasattr(obj, '__class__'):
714 if hasattr(obj, '__class__'):
713 source = getsource(obj.__class__, binary_file)
715 source = getsource(obj.__class__, binary_file)
714 if source is not None:
716 if source is not None:
715 out['source'] = source.rstrip()
717 out['source'] = source.rstrip()
716 except Exception:
718 except Exception:
717 pass
719 pass
718
720
719 if ds and source is None:
721 if ds and source is None:
720 out['docstring'] = ds
722 out['docstring'] = ds
721
723
722
724
723 # Constructor docstring for classes
725 # Constructor docstring for classes
724 if inspect.isclass(obj):
726 if inspect.isclass(obj):
725 out['isclass'] = True
727 out['isclass'] = True
726 # reconstruct the function definition and print it:
728 # reconstruct the function definition and print it:
727 try:
729 try:
728 obj_init = obj.__init__
730 obj_init = obj.__init__
729 except AttributeError:
731 except AttributeError:
730 init_def = init_ds = None
732 init_def = init_ds = None
731 else:
733 else:
732 init_def = self._getdef(obj_init,oname)
734 init_def = self._getdef(obj_init,oname)
733 init_ds = getdoc(obj_init)
735 init_ds = getdoc(obj_init)
734 # Skip Python's auto-generated docstrings
736 # Skip Python's auto-generated docstrings
735 if init_ds and \
737 if init_ds and \
736 init_ds.startswith('x.__init__(...) initializes'):
738 init_ds.startswith('x.__init__(...) initializes'):
737 init_ds = None
739 init_ds = None
738
740
739 if init_def or init_ds:
741 if init_def or init_ds:
740 if init_def:
742 if init_def:
741 out['init_definition'] = self.format(init_def)
743 out['init_definition'] = self.format(init_def)
742 if init_ds:
744 if init_ds:
743 out['init_docstring'] = init_ds
745 out['init_docstring'] = init_ds
744
746
745 # and class docstring for instances:
747 # and class docstring for instances:
746 else:
748 else:
747 # First, check whether the instance docstring is identical to the
749 # First, check whether the instance docstring is identical to the
748 # class one, and print it separately if they don't coincide. In
750 # 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
751 # most cases they will, but it's nice to print all the info for
750 # objects which use instance-customized docstrings.
752 # objects which use instance-customized docstrings.
751 if ds:
753 if ds:
752 try:
754 try:
753 cls = getattr(obj,'__class__')
755 cls = getattr(obj,'__class__')
754 except:
756 except:
755 class_ds = None
757 class_ds = None
756 else:
758 else:
757 class_ds = getdoc(cls)
759 class_ds = getdoc(cls)
758 # Skip Python's auto-generated docstrings
760 # Skip Python's auto-generated docstrings
759 if class_ds and \
761 if class_ds and \
760 (class_ds.startswith('function(code, globals[,') or \
762 (class_ds.startswith('function(code, globals[,') or \
761 class_ds.startswith('instancemethod(function, instance,') or \
763 class_ds.startswith('instancemethod(function, instance,') or \
762 class_ds.startswith('module(name[,') ):
764 class_ds.startswith('module(name[,') ):
763 class_ds = None
765 class_ds = None
764 if class_ds and ds != class_ds:
766 if class_ds and ds != class_ds:
765 out['class_docstring'] = class_ds
767 out['class_docstring'] = class_ds
766
768
767 # Next, try to show constructor docstrings
769 # Next, try to show constructor docstrings
768 try:
770 try:
769 init_ds = getdoc(obj.__init__)
771 init_ds = getdoc(obj.__init__)
770 # Skip Python's auto-generated docstrings
772 # Skip Python's auto-generated docstrings
771 if init_ds and \
773 if init_ds and \
772 init_ds.startswith('x.__init__(...) initializes'):
774 init_ds.startswith('x.__init__(...) initializes'):
773 init_ds = None
775 init_ds = None
774 except AttributeError:
776 except AttributeError:
775 init_ds = None
777 init_ds = None
776 if init_ds:
778 if init_ds:
777 out['init_docstring'] = init_ds
779 out['init_docstring'] = init_ds
778
780
779 # Call form docstring for callable instances
781 # Call form docstring for callable instances
780 if hasattr(obj, '__call__'):
782 if hasattr(obj, '__call__'):
781 call_def = self._getdef(obj.__call__, oname)
783 call_def = self._getdef(obj.__call__, oname)
782 if call_def is not None:
784 if call_def is not None:
783 out['call_def'] = self.format(call_def)
785 out['call_def'] = self.format(call_def)
784 call_ds = getdoc(obj.__call__)
786 call_ds = getdoc(obj.__call__)
785 # Skip Python's auto-generated docstrings
787 # Skip Python's auto-generated docstrings
786 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
788 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
787 call_ds = None
789 call_ds = None
788 if call_ds:
790 if call_ds:
789 out['call_docstring'] = call_ds
791 out['call_docstring'] = call_ds
790
792
791 # Compute the object's argspec as a callable. The key is to decide
793 # 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
794 # whether to pull it from the object itself, from its __init__ or
793 # from its __call__ method.
795 # from its __call__ method.
794
796
795 if inspect.isclass(obj):
797 if inspect.isclass(obj):
796 # Old-style classes need not have an __init__
798 # Old-style classes need not have an __init__
797 callable_obj = getattr(obj, "__init__", None)
799 callable_obj = getattr(obj, "__init__", None)
798 elif callable(obj):
800 elif callable(obj):
799 callable_obj = obj
801 callable_obj = obj
800 else:
802 else:
801 callable_obj = None
803 callable_obj = None
802
804
803 if callable_obj:
805 if callable_obj:
804 try:
806 try:
805 args, varargs, varkw, defaults = getargspec(callable_obj)
807 args, varargs, varkw, defaults = getargspec(callable_obj)
806 except (TypeError, AttributeError):
808 except (TypeError, AttributeError):
807 # For extensions/builtins we can't retrieve the argspec
809 # For extensions/builtins we can't retrieve the argspec
808 pass
810 pass
809 else:
811 else:
810 out['argspec'] = dict(args=args, varargs=varargs,
812 out['argspec'] = dict(args=args, varargs=varargs,
811 varkw=varkw, defaults=defaults)
813 varkw=varkw, defaults=defaults)
812
814
813 return object_info(**out)
815 return object_info(**out)
814
816
815
817
816 def psearch(self,pattern,ns_table,ns_search=[],
818 def psearch(self,pattern,ns_table,ns_search=[],
817 ignore_case=False,show_all=False):
819 ignore_case=False,show_all=False):
818 """Search namespaces with wildcards for objects.
820 """Search namespaces with wildcards for objects.
819
821
820 Arguments:
822 Arguments:
821
823
822 - pattern: string containing shell-like wildcards to use in namespace
824 - pattern: string containing shell-like wildcards to use in namespace
823 searches and optionally a type specification to narrow the search to
825 searches and optionally a type specification to narrow the search to
824 objects of that type.
826 objects of that type.
825
827
826 - ns_table: dict of name->namespaces for search.
828 - ns_table: dict of name->namespaces for search.
827
829
828 Optional arguments:
830 Optional arguments:
829
831
830 - ns_search: list of namespace names to include in search.
832 - ns_search: list of namespace names to include in search.
831
833
832 - ignore_case(False): make the search case-insensitive.
834 - ignore_case(False): make the search case-insensitive.
833
835
834 - show_all(False): show all names, including those starting with
836 - show_all(False): show all names, including those starting with
835 underscores.
837 underscores.
836 """
838 """
837 #print 'ps pattern:<%r>' % pattern # dbg
839 #print 'ps pattern:<%r>' % pattern # dbg
838
840
839 # defaults
841 # defaults
840 type_pattern = 'all'
842 type_pattern = 'all'
841 filter = ''
843 filter = ''
842
844
843 cmds = pattern.split()
845 cmds = pattern.split()
844 len_cmds = len(cmds)
846 len_cmds = len(cmds)
845 if len_cmds == 1:
847 if len_cmds == 1:
846 # Only filter pattern given
848 # Only filter pattern given
847 filter = cmds[0]
849 filter = cmds[0]
848 elif len_cmds == 2:
850 elif len_cmds == 2:
849 # Both filter and type specified
851 # Both filter and type specified
850 filter,type_pattern = cmds
852 filter,type_pattern = cmds
851 else:
853 else:
852 raise ValueError('invalid argument string for psearch: <%s>' %
854 raise ValueError('invalid argument string for psearch: <%s>' %
853 pattern)
855 pattern)
854
856
855 # filter search namespaces
857 # filter search namespaces
856 for name in ns_search:
858 for name in ns_search:
857 if name not in ns_table:
859 if name not in ns_table:
858 raise ValueError('invalid namespace <%s>. Valid names: %s' %
860 raise ValueError('invalid namespace <%s>. Valid names: %s' %
859 (name,ns_table.keys()))
861 (name,ns_table.keys()))
860
862
861 #print 'type_pattern:',type_pattern # dbg
863 #print 'type_pattern:',type_pattern # dbg
862 search_result, namespaces_seen = set(), set()
864 search_result, namespaces_seen = set(), set()
863 for ns_name in ns_search:
865 for ns_name in ns_search:
864 ns = ns_table[ns_name]
866 ns = ns_table[ns_name]
865 # Normally, locals and globals are the same, so we just check one.
867 # Normally, locals and globals are the same, so we just check one.
866 if id(ns) in namespaces_seen:
868 if id(ns) in namespaces_seen:
867 continue
869 continue
868 namespaces_seen.add(id(ns))
870 namespaces_seen.add(id(ns))
869 tmp_res = list_namespace(ns, type_pattern, filter,
871 tmp_res = list_namespace(ns, type_pattern, filter,
870 ignore_case=ignore_case, show_all=show_all)
872 ignore_case=ignore_case, show_all=show_all)
871 search_result.update(tmp_res)
873 search_result.update(tmp_res)
872
874
873 page.page('\n'.join(sorted(search_result)))
875 page.page('\n'.join(sorted(search_result)))
@@ -1,794 +1,840
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 StringIO import StringIO
15 from StringIO import StringIO
16 from unittest import TestCase
16 from unittest import TestCase
17
17
18 try:
18 try:
19 from importlib import invalidate_caches # Required from Python 3.3
19 from importlib import invalidate_caches # Required from Python 3.3
20 except ImportError:
20 except ImportError:
21 def invalidate_caches():
21 def invalidate_caches():
22 pass
22 pass
23
23
24 import nose.tools as nt
24 import nose.tools as nt
25
25
26 from IPython.core import magic
26 from IPython.core import magic
27 from IPython.core.magic import (Magics, magics_class, line_magic,
27 from IPython.core.magic import (Magics, magics_class, line_magic,
28 cell_magic, line_cell_magic,
28 cell_magic, line_cell_magic,
29 register_line_magic, register_cell_magic,
29 register_line_magic, register_cell_magic,
30 register_line_cell_magic)
30 register_line_cell_magic)
31 from IPython.core.magics import execution, script
31 from IPython.core.magics import execution, script, code
32 from IPython.nbformat.v3.tests.nbexamples import nb0
32 from IPython.nbformat.v3.tests.nbexamples import nb0
33 from IPython.nbformat import current
33 from IPython.nbformat import current
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
36 from IPython.utils import py3compat
36 from IPython.utils import py3compat
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 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Test functions begin
41 # Test functions begin
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 @magic.magics_class
44 @magic.magics_class
45 class DummyMagics(magic.Magics): pass
45 class DummyMagics(magic.Magics): pass
46
46
47 def test_rehashx():
47 def test_rehashx():
48 # clear up everything
48 # clear up everything
49 _ip = get_ipython()
49 _ip = get_ipython()
50 _ip.alias_manager.alias_table.clear()
50 _ip.alias_manager.alias_table.clear()
51 del _ip.db['syscmdlist']
51 del _ip.db['syscmdlist']
52
52
53 _ip.magic('rehashx')
53 _ip.magic('rehashx')
54 # Practically ALL ipython development systems will have more than 10 aliases
54 # Practically ALL ipython development systems will have more than 10 aliases
55
55
56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
57 for key, val in _ip.alias_manager.alias_table.iteritems():
57 for key, val in _ip.alias_manager.alias_table.iteritems():
58 # we must strip dots from alias names
58 # we must strip dots from alias names
59 nt.assert_true('.' not in key)
59 nt.assert_true('.' not in key)
60
60
61 # rehashx must fill up syscmdlist
61 # rehashx must fill up syscmdlist
62 scoms = _ip.db['syscmdlist']
62 scoms = _ip.db['syscmdlist']
63 yield (nt.assert_true, len(scoms) > 10)
63 yield (nt.assert_true, len(scoms) > 10)
64
64
65
65
66 def test_magic_parse_options():
66 def test_magic_parse_options():
67 """Test that we don't mangle paths when parsing magic options."""
67 """Test that we don't mangle paths when parsing magic options."""
68 ip = get_ipython()
68 ip = get_ipython()
69 path = 'c:\\x'
69 path = 'c:\\x'
70 m = DummyMagics(ip)
70 m = DummyMagics(ip)
71 opts = m.parse_options('-f %s' % path,'f:')[0]
71 opts = m.parse_options('-f %s' % path,'f:')[0]
72 # argv splitting is os-dependent
72 # argv splitting is os-dependent
73 if os.name == 'posix':
73 if os.name == 'posix':
74 expected = 'c:x'
74 expected = 'c:x'
75 else:
75 else:
76 expected = path
76 expected = path
77 nt.assert_equal(opts['f'], expected)
77 nt.assert_equal(opts['f'], expected)
78
78
79 def test_magic_parse_long_options():
79 def test_magic_parse_long_options():
80 """Magic.parse_options can handle --foo=bar long options"""
80 """Magic.parse_options can handle --foo=bar long options"""
81 ip = get_ipython()
81 ip = get_ipython()
82 m = DummyMagics(ip)
82 m = DummyMagics(ip)
83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
84 nt.assert_true('foo' in opts)
84 nt.assert_true('foo' in opts)
85 nt.assert_true('bar' in opts)
85 nt.assert_true('bar' in opts)
86 nt.assert_true(opts['bar'], "bubble")
86 nt.assert_true(opts['bar'], "bubble")
87
87
88
88
89 @dec.skip_without('sqlite3')
89 @dec.skip_without('sqlite3')
90 def doctest_hist_f():
90 def doctest_hist_f():
91 """Test %hist -f with temporary filename.
91 """Test %hist -f with temporary filename.
92
92
93 In [9]: import tempfile
93 In [9]: import tempfile
94
94
95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
96
96
97 In [11]: %hist -nl -f $tfile 3
97 In [11]: %hist -nl -f $tfile 3
98
98
99 In [13]: import os; os.unlink(tfile)
99 In [13]: import os; os.unlink(tfile)
100 """
100 """
101
101
102
102
103 @dec.skip_without('sqlite3')
103 @dec.skip_without('sqlite3')
104 def doctest_hist_r():
104 def doctest_hist_r():
105 """Test %hist -r
105 """Test %hist -r
106
106
107 XXX - This test is not recording the output correctly. For some reason, in
107 XXX - This test is not recording the output correctly. For some reason, in
108 testing mode the raw history isn't getting populated. No idea why.
108 testing mode the raw history isn't getting populated. No idea why.
109 Disabling the output checking for now, though at least we do run it.
109 Disabling the output checking for now, though at least we do run it.
110
110
111 In [1]: 'hist' in _ip.lsmagic()
111 In [1]: 'hist' in _ip.lsmagic()
112 Out[1]: True
112 Out[1]: True
113
113
114 In [2]: x=1
114 In [2]: x=1
115
115
116 In [3]: %hist -rl 2
116 In [3]: %hist -rl 2
117 x=1 # random
117 x=1 # random
118 %hist -r 2
118 %hist -r 2
119 """
119 """
120
120
121
121
122 @dec.skip_without('sqlite3')
122 @dec.skip_without('sqlite3')
123 def doctest_hist_op():
123 def doctest_hist_op():
124 """Test %hist -op
124 """Test %hist -op
125
125
126 In [1]: class b(float):
126 In [1]: class b(float):
127 ...: pass
127 ...: pass
128 ...:
128 ...:
129
129
130 In [2]: class s(object):
130 In [2]: class s(object):
131 ...: def __str__(self):
131 ...: def __str__(self):
132 ...: return 's'
132 ...: return 's'
133 ...:
133 ...:
134
134
135 In [3]:
135 In [3]:
136
136
137 In [4]: class r(b):
137 In [4]: class r(b):
138 ...: def __repr__(self):
138 ...: def __repr__(self):
139 ...: return 'r'
139 ...: return 'r'
140 ...:
140 ...:
141
141
142 In [5]: class sr(s,r): pass
142 In [5]: class sr(s,r): pass
143 ...:
143 ...:
144
144
145 In [6]:
145 In [6]:
146
146
147 In [7]: bb=b()
147 In [7]: bb=b()
148
148
149 In [8]: ss=s()
149 In [8]: ss=s()
150
150
151 In [9]: rr=r()
151 In [9]: rr=r()
152
152
153 In [10]: ssrr=sr()
153 In [10]: ssrr=sr()
154
154
155 In [11]: 4.5
155 In [11]: 4.5
156 Out[11]: 4.5
156 Out[11]: 4.5
157
157
158 In [12]: str(ss)
158 In [12]: str(ss)
159 Out[12]: 's'
159 Out[12]: 's'
160
160
161 In [13]:
161 In [13]:
162
162
163 In [14]: %hist -op
163 In [14]: %hist -op
164 >>> class b:
164 >>> class b:
165 ... pass
165 ... pass
166 ...
166 ...
167 >>> class s(b):
167 >>> class s(b):
168 ... def __str__(self):
168 ... def __str__(self):
169 ... return 's'
169 ... return 's'
170 ...
170 ...
171 >>>
171 >>>
172 >>> class r(b):
172 >>> class r(b):
173 ... def __repr__(self):
173 ... def __repr__(self):
174 ... return 'r'
174 ... return 'r'
175 ...
175 ...
176 >>> class sr(s,r): pass
176 >>> class sr(s,r): pass
177 >>>
177 >>>
178 >>> bb=b()
178 >>> bb=b()
179 >>> ss=s()
179 >>> ss=s()
180 >>> rr=r()
180 >>> rr=r()
181 >>> ssrr=sr()
181 >>> ssrr=sr()
182 >>> 4.5
182 >>> 4.5
183 4.5
183 4.5
184 >>> str(ss)
184 >>> str(ss)
185 's'
185 's'
186 >>>
186 >>>
187 """
187 """
188
188
189
189
190 @dec.skip_without('sqlite3')
190 @dec.skip_without('sqlite3')
191 def test_macro():
191 def test_macro():
192 ip = get_ipython()
192 ip = get_ipython()
193 ip.history_manager.reset() # Clear any existing history.
193 ip.history_manager.reset() # Clear any existing history.
194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
195 for i, cmd in enumerate(cmds, start=1):
195 for i, cmd in enumerate(cmds, start=1):
196 ip.history_manager.store_inputs(i, cmd)
196 ip.history_manager.store_inputs(i, cmd)
197 ip.magic("macro test 1-3")
197 ip.magic("macro test 1-3")
198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
199
199
200 # List macros.
200 # List macros.
201 assert "test" in ip.magic("macro")
201 assert "test" in ip.magic("macro")
202
202
203
203
204 @dec.skip_without('sqlite3')
204 @dec.skip_without('sqlite3')
205 def test_macro_run():
205 def test_macro_run():
206 """Test that we can run a multi-line macro successfully."""
206 """Test that we can run a multi-line macro successfully."""
207 ip = get_ipython()
207 ip = get_ipython()
208 ip.history_manager.reset()
208 ip.history_manager.reset()
209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
210 "%macro test 2-3"]
210 "%macro test 2-3"]
211 for cmd in cmds:
211 for cmd in cmds:
212 ip.run_cell(cmd, store_history=True)
212 ip.run_cell(cmd, store_history=True)
213 nt.assert_equal(ip.user_ns["test"].value,
213 nt.assert_equal(ip.user_ns["test"].value,
214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
215 with tt.AssertPrints("12"):
215 with tt.AssertPrints("12"):
216 ip.run_cell("test")
216 ip.run_cell("test")
217 with tt.AssertPrints("13"):
217 with tt.AssertPrints("13"):
218 ip.run_cell("test")
218 ip.run_cell("test")
219
219
220
220
221 @dec.skipif_not_numpy
221 @dec.skipif_not_numpy
222 def test_numpy_reset_array_undec():
222 def test_numpy_reset_array_undec():
223 "Test '%reset array' functionality"
223 "Test '%reset array' functionality"
224 _ip.ex('import numpy as np')
224 _ip.ex('import numpy as np')
225 _ip.ex('a = np.empty(2)')
225 _ip.ex('a = np.empty(2)')
226 yield (nt.assert_true, 'a' in _ip.user_ns)
226 yield (nt.assert_true, 'a' in _ip.user_ns)
227 _ip.magic('reset -f array')
227 _ip.magic('reset -f array')
228 yield (nt.assert_false, 'a' in _ip.user_ns)
228 yield (nt.assert_false, 'a' in _ip.user_ns)
229
229
230 def test_reset_out():
230 def test_reset_out():
231 "Test '%reset out' magic"
231 "Test '%reset out' magic"
232 _ip.run_cell("parrot = 'dead'", store_history=True)
232 _ip.run_cell("parrot = 'dead'", store_history=True)
233 # test '%reset -f out', make an Out prompt
233 # test '%reset -f out', make an Out prompt
234 _ip.run_cell("parrot", store_history=True)
234 _ip.run_cell("parrot", store_history=True)
235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
236 _ip.magic('reset -f out')
236 _ip.magic('reset -f out')
237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
239
239
240 def test_reset_in():
240 def test_reset_in():
241 "Test '%reset in' magic"
241 "Test '%reset in' magic"
242 # test '%reset -f in'
242 # test '%reset -f in'
243 _ip.run_cell("parrot", store_history=True)
243 _ip.run_cell("parrot", store_history=True)
244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
245 _ip.magic('%reset -f in')
245 _ip.magic('%reset -f in')
246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
248
248
249 def test_reset_dhist():
249 def test_reset_dhist():
250 "Test '%reset dhist' magic"
250 "Test '%reset dhist' magic"
251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
253 _ip.magic('cd -')
253 _ip.magic('cd -')
254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
255 _ip.magic('reset -f dhist')
255 _ip.magic('reset -f dhist')
256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
257 _ip.run_cell("_dh = [d for d in tmp]") #restore
257 _ip.run_cell("_dh = [d for d in tmp]") #restore
258
258
259 def test_reset_in_length():
259 def test_reset_in_length():
260 "Test that '%reset in' preserves In[] length"
260 "Test that '%reset in' preserves In[] length"
261 _ip.run_cell("print 'foo'")
261 _ip.run_cell("print 'foo'")
262 _ip.run_cell("reset -f in")
262 _ip.run_cell("reset -f in")
263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
264
264
265 def test_time():
265 def test_time():
266 _ip.magic('time None')
266 _ip.magic('time None')
267
267
268 def test_tb_syntaxerror():
268 def test_tb_syntaxerror():
269 """test %tb after a SyntaxError"""
269 """test %tb after a SyntaxError"""
270 ip = get_ipython()
270 ip = get_ipython()
271 ip.run_cell("for")
271 ip.run_cell("for")
272
272
273 # trap and validate stdout
273 # trap and validate stdout
274 save_stdout = sys.stdout
274 save_stdout = sys.stdout
275 try:
275 try:
276 sys.stdout = StringIO()
276 sys.stdout = StringIO()
277 ip.run_cell("%tb")
277 ip.run_cell("%tb")
278 out = sys.stdout.getvalue()
278 out = sys.stdout.getvalue()
279 finally:
279 finally:
280 sys.stdout = save_stdout
280 sys.stdout = save_stdout
281 # trim output, and only check the last line
281 # trim output, and only check the last line
282 last_line = out.rstrip().splitlines()[-1].strip()
282 last_line = out.rstrip().splitlines()[-1].strip()
283 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
283 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
284
284
285
285
286 def test_time():
286 def test_time():
287 ip = get_ipython()
287 ip = get_ipython()
288
288
289 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
289 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
290 ip.run_cell("%time None")
290 ip.run_cell("%time None")
291
291
292 ip.run_cell("def f(kmjy):\n"
292 ip.run_cell("def f(kmjy):\n"
293 " %time print (2*kmjy)")
293 " %time print (2*kmjy)")
294
294
295 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
295 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
296 with tt.AssertPrints("hihi", suppress=False):
296 with tt.AssertPrints("hihi", suppress=False):
297 ip.run_cell("f('hi')")
297 ip.run_cell("f('hi')")
298
298
299 def test_doctest_mode():
299 def test_doctest_mode():
300 "Toggle doctest_mode twice, it should be a no-op and run without error"
300 "Toggle doctest_mode twice, it should be a no-op and run without error"
301 _ip.magic('doctest_mode')
301 _ip.magic('doctest_mode')
302 _ip.magic('doctest_mode')
302 _ip.magic('doctest_mode')
303
303
304
304
305 def test_parse_options():
305 def test_parse_options():
306 """Tests for basic options parsing in magics."""
306 """Tests for basic options parsing in magics."""
307 # These are only the most minimal of tests, more should be added later. At
307 # These are only the most minimal of tests, more should be added later. At
308 # the very least we check that basic text/unicode calls work OK.
308 # the very least we check that basic text/unicode calls work OK.
309 m = DummyMagics(_ip)
309 m = DummyMagics(_ip)
310 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
310 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
311 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
311 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
312
312
313
313
314 def test_dirops():
314 def test_dirops():
315 """Test various directory handling operations."""
315 """Test various directory handling operations."""
316 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
316 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
317 curpath = os.getcwdu
317 curpath = os.getcwdu
318 startdir = os.getcwdu()
318 startdir = os.getcwdu()
319 ipdir = os.path.realpath(_ip.ipython_dir)
319 ipdir = os.path.realpath(_ip.ipython_dir)
320 try:
320 try:
321 _ip.magic('cd "%s"' % ipdir)
321 _ip.magic('cd "%s"' % ipdir)
322 nt.assert_equal(curpath(), ipdir)
322 nt.assert_equal(curpath(), ipdir)
323 _ip.magic('cd -')
323 _ip.magic('cd -')
324 nt.assert_equal(curpath(), startdir)
324 nt.assert_equal(curpath(), startdir)
325 _ip.magic('pushd "%s"' % ipdir)
325 _ip.magic('pushd "%s"' % ipdir)
326 nt.assert_equal(curpath(), ipdir)
326 nt.assert_equal(curpath(), ipdir)
327 _ip.magic('popd')
327 _ip.magic('popd')
328 nt.assert_equal(curpath(), startdir)
328 nt.assert_equal(curpath(), startdir)
329 finally:
329 finally:
330 os.chdir(startdir)
330 os.chdir(startdir)
331
331
332
332
333 def test_xmode():
333 def test_xmode():
334 # Calling xmode three times should be a no-op
334 # Calling xmode three times should be a no-op
335 xmode = _ip.InteractiveTB.mode
335 xmode = _ip.InteractiveTB.mode
336 for i in range(3):
336 for i in range(3):
337 _ip.magic("xmode")
337 _ip.magic("xmode")
338 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
338 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
339
339
340 def test_reset_hard():
340 def test_reset_hard():
341 monitor = []
341 monitor = []
342 class A(object):
342 class A(object):
343 def __del__(self):
343 def __del__(self):
344 monitor.append(1)
344 monitor.append(1)
345 def __repr__(self):
345 def __repr__(self):
346 return "<A instance>"
346 return "<A instance>"
347
347
348 _ip.user_ns["a"] = A()
348 _ip.user_ns["a"] = A()
349 _ip.run_cell("a")
349 _ip.run_cell("a")
350
350
351 nt.assert_equal(monitor, [])
351 nt.assert_equal(monitor, [])
352 _ip.magic("reset -f")
352 _ip.magic("reset -f")
353 nt.assert_equal(monitor, [1])
353 nt.assert_equal(monitor, [1])
354
354
355 class TestXdel(tt.TempFileMixin):
355 class TestXdel(tt.TempFileMixin):
356 def test_xdel(self):
356 def test_xdel(self):
357 """Test that references from %run are cleared by xdel."""
357 """Test that references from %run are cleared by xdel."""
358 src = ("class A(object):\n"
358 src = ("class A(object):\n"
359 " monitor = []\n"
359 " monitor = []\n"
360 " def __del__(self):\n"
360 " def __del__(self):\n"
361 " self.monitor.append(1)\n"
361 " self.monitor.append(1)\n"
362 "a = A()\n")
362 "a = A()\n")
363 self.mktmp(src)
363 self.mktmp(src)
364 # %run creates some hidden references...
364 # %run creates some hidden references...
365 _ip.magic("run %s" % self.fname)
365 _ip.magic("run %s" % self.fname)
366 # ... as does the displayhook.
366 # ... as does the displayhook.
367 _ip.run_cell("a")
367 _ip.run_cell("a")
368
368
369 monitor = _ip.user_ns["A"].monitor
369 monitor = _ip.user_ns["A"].monitor
370 nt.assert_equal(monitor, [])
370 nt.assert_equal(monitor, [])
371
371
372 _ip.magic("xdel a")
372 _ip.magic("xdel a")
373
373
374 # Check that a's __del__ method has been called.
374 # Check that a's __del__ method has been called.
375 nt.assert_equal(monitor, [1])
375 nt.assert_equal(monitor, [1])
376
376
377 def doctest_who():
377 def doctest_who():
378 """doctest for %who
378 """doctest for %who
379
379
380 In [1]: %reset -f
380 In [1]: %reset -f
381
381
382 In [2]: alpha = 123
382 In [2]: alpha = 123
383
383
384 In [3]: beta = 'beta'
384 In [3]: beta = 'beta'
385
385
386 In [4]: %who int
386 In [4]: %who int
387 alpha
387 alpha
388
388
389 In [5]: %who str
389 In [5]: %who str
390 beta
390 beta
391
391
392 In [6]: %whos
392 In [6]: %whos
393 Variable Type Data/Info
393 Variable Type Data/Info
394 ----------------------------
394 ----------------------------
395 alpha int 123
395 alpha int 123
396 beta str beta
396 beta str beta
397
397
398 In [7]: %who_ls
398 In [7]: %who_ls
399 Out[7]: ['alpha', 'beta']
399 Out[7]: ['alpha', 'beta']
400 """
400 """
401
401
402 def test_whos():
402 def test_whos():
403 """Check that whos is protected against objects where repr() fails."""
403 """Check that whos is protected against objects where repr() fails."""
404 class A(object):
404 class A(object):
405 def __repr__(self):
405 def __repr__(self):
406 raise Exception()
406 raise Exception()
407 _ip.user_ns['a'] = A()
407 _ip.user_ns['a'] = A()
408 _ip.magic("whos")
408 _ip.magic("whos")
409
409
410 @py3compat.u_format
410 @py3compat.u_format
411 def doctest_precision():
411 def doctest_precision():
412 """doctest for %precision
412 """doctest for %precision
413
413
414 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
414 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
415
415
416 In [2]: %precision 5
416 In [2]: %precision 5
417 Out[2]: {u}'%.5f'
417 Out[2]: {u}'%.5f'
418
418
419 In [3]: f.float_format
419 In [3]: f.float_format
420 Out[3]: {u}'%.5f'
420 Out[3]: {u}'%.5f'
421
421
422 In [4]: %precision %e
422 In [4]: %precision %e
423 Out[4]: {u}'%e'
423 Out[4]: {u}'%e'
424
424
425 In [5]: f(3.1415927)
425 In [5]: f(3.1415927)
426 Out[5]: {u}'3.141593e+00'
426 Out[5]: {u}'3.141593e+00'
427 """
427 """
428
428
429 def test_psearch():
429 def test_psearch():
430 with tt.AssertPrints("dict.fromkeys"):
430 with tt.AssertPrints("dict.fromkeys"):
431 _ip.run_cell("dict.fr*?")
431 _ip.run_cell("dict.fr*?")
432
432
433 def test_timeit_shlex():
433 def test_timeit_shlex():
434 """test shlex issues with timeit (#1109)"""
434 """test shlex issues with timeit (#1109)"""
435 _ip.ex("def f(*a,**kw): pass")
435 _ip.ex("def f(*a,**kw): pass")
436 _ip.magic('timeit -n1 "this is a bug".count(" ")')
436 _ip.magic('timeit -n1 "this is a bug".count(" ")')
437 _ip.magic('timeit -r1 -n1 f(" ", 1)')
437 _ip.magic('timeit -r1 -n1 f(" ", 1)')
438 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
438 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
439 _ip.magic('timeit -r1 -n1 ("a " + "b")')
439 _ip.magic('timeit -r1 -n1 ("a " + "b")')
440 _ip.magic('timeit -r1 -n1 f("a " + "b")')
440 _ip.magic('timeit -r1 -n1 f("a " + "b")')
441 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
441 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
442
442
443
443
444 def test_timeit_arguments():
444 def test_timeit_arguments():
445 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
445 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
446 _ip.magic("timeit ('#')")
446 _ip.magic("timeit ('#')")
447
447
448
448
449 def test_timeit_special_syntax():
449 def test_timeit_special_syntax():
450 "Test %%timeit with IPython special syntax"
450 "Test %%timeit with IPython special syntax"
451 from IPython.core.magic import register_line_magic
451 from IPython.core.magic import register_line_magic
452
452
453 @register_line_magic
453 @register_line_magic
454 def lmagic(line):
454 def lmagic(line):
455 ip = get_ipython()
455 ip = get_ipython()
456 ip.user_ns['lmagic_out'] = line
456 ip.user_ns['lmagic_out'] = line
457
457
458 # line mode test
458 # line mode test
459 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
459 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
460 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
460 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
461 # cell mode test
461 # cell mode test
462 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
462 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
463 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
463 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
464
464
465
465
466 @dec.skipif(execution.profile is None)
466 @dec.skipif(execution.profile is None)
467 def test_prun_quotes():
467 def test_prun_quotes():
468 "Test that prun does not clobber string escapes (GH #1302)"
468 "Test that prun does not clobber string escapes (GH #1302)"
469 _ip.magic(r"prun -q x = '\t'")
469 _ip.magic(r"prun -q x = '\t'")
470 nt.assert_equal(_ip.user_ns['x'], '\t')
470 nt.assert_equal(_ip.user_ns['x'], '\t')
471
471
472 def test_extension():
472 def test_extension():
473 tmpdir = TemporaryDirectory()
473 tmpdir = TemporaryDirectory()
474 orig_ipython_dir = _ip.ipython_dir
474 orig_ipython_dir = _ip.ipython_dir
475 try:
475 try:
476 _ip.ipython_dir = tmpdir.name
476 _ip.ipython_dir = tmpdir.name
477 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
477 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
478 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
478 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
479 _ip.magic("install_ext %s" % url)
479 _ip.magic("install_ext %s" % url)
480 _ip.user_ns.pop('arq', None)
480 _ip.user_ns.pop('arq', None)
481 invalidate_caches() # Clear import caches
481 invalidate_caches() # Clear import caches
482 _ip.magic("load_ext daft_extension")
482 _ip.magic("load_ext daft_extension")
483 nt.assert_equal(_ip.user_ns['arq'], 185)
483 nt.assert_equal(_ip.user_ns['arq'], 185)
484 _ip.magic("unload_ext daft_extension")
484 _ip.magic("unload_ext daft_extension")
485 assert 'arq' not in _ip.user_ns
485 assert 'arq' not in _ip.user_ns
486 finally:
486 finally:
487 _ip.ipython_dir = orig_ipython_dir
487 _ip.ipython_dir = orig_ipython_dir
488 tmpdir.cleanup()
488 tmpdir.cleanup()
489
489
490 def test_notebook_export_json():
490 def test_notebook_export_json():
491 with TemporaryDirectory() as td:
491 with TemporaryDirectory() as td:
492 outfile = os.path.join(td, "nb.ipynb")
492 outfile = os.path.join(td, "nb.ipynb")
493 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
493 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
494 _ip.magic("notebook -e %s" % outfile)
494 _ip.magic("notebook -e %s" % outfile)
495
495
496 def test_notebook_export_py():
496 def test_notebook_export_py():
497 with TemporaryDirectory() as td:
497 with TemporaryDirectory() as td:
498 outfile = os.path.join(td, "nb.py")
498 outfile = os.path.join(td, "nb.py")
499 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
499 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
500 _ip.magic("notebook -e %s" % outfile)
500 _ip.magic("notebook -e %s" % outfile)
501
501
502 def test_notebook_reformat_py():
502 def test_notebook_reformat_py():
503 with TemporaryDirectory() as td:
503 with TemporaryDirectory() as td:
504 infile = os.path.join(td, "nb.ipynb")
504 infile = os.path.join(td, "nb.ipynb")
505 with io.open(infile, 'w', encoding='utf-8') as f:
505 with io.open(infile, 'w', encoding='utf-8') as f:
506 current.write(nb0, f, 'json')
506 current.write(nb0, f, 'json')
507
507
508 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
508 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
509 _ip.magic("notebook -f py %s" % infile)
509 _ip.magic("notebook -f py %s" % infile)
510
510
511 def test_notebook_reformat_json():
511 def test_notebook_reformat_json():
512 with TemporaryDirectory() as td:
512 with TemporaryDirectory() as td:
513 infile = os.path.join(td, "nb.py")
513 infile = os.path.join(td, "nb.py")
514 with io.open(infile, 'w', encoding='utf-8') as f:
514 with io.open(infile, 'w', encoding='utf-8') as f:
515 current.write(nb0, f, 'py')
515 current.write(nb0, f, 'py')
516
516
517 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
517 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
518 _ip.magic("notebook -f ipynb %s" % infile)
518 _ip.magic("notebook -f ipynb %s" % infile)
519 _ip.magic("notebook -f json %s" % infile)
519 _ip.magic("notebook -f json %s" % infile)
520
520
521 def test_env():
521 def test_env():
522 env = _ip.magic("env")
522 env = _ip.magic("env")
523 assert isinstance(env, dict), type(env)
523 assert isinstance(env, dict), type(env)
524
524
525
525
526 class CellMagicTestCase(TestCase):
526 class CellMagicTestCase(TestCase):
527
527
528 def check_ident(self, magic):
528 def check_ident(self, magic):
529 # Manually called, we get the result
529 # Manually called, we get the result
530 out = _ip.run_cell_magic(magic, 'a', 'b')
530 out = _ip.run_cell_magic(magic, 'a', 'b')
531 nt.assert_equal(out, ('a','b'))
531 nt.assert_equal(out, ('a','b'))
532 # Via run_cell, it goes into the user's namespace via displayhook
532 # Via run_cell, it goes into the user's namespace via displayhook
533 _ip.run_cell('%%' + magic +' c\nd')
533 _ip.run_cell('%%' + magic +' c\nd')
534 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
534 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
535
535
536 def test_cell_magic_func_deco(self):
536 def test_cell_magic_func_deco(self):
537 "Cell magic using simple decorator"
537 "Cell magic using simple decorator"
538 @register_cell_magic
538 @register_cell_magic
539 def cellm(line, cell):
539 def cellm(line, cell):
540 return line, cell
540 return line, cell
541
541
542 self.check_ident('cellm')
542 self.check_ident('cellm')
543
543
544 def test_cell_magic_reg(self):
544 def test_cell_magic_reg(self):
545 "Cell magic manually registered"
545 "Cell magic manually registered"
546 def cellm(line, cell):
546 def cellm(line, cell):
547 return line, cell
547 return line, cell
548
548
549 _ip.register_magic_function(cellm, 'cell', 'cellm2')
549 _ip.register_magic_function(cellm, 'cell', 'cellm2')
550 self.check_ident('cellm2')
550 self.check_ident('cellm2')
551
551
552 def test_cell_magic_class(self):
552 def test_cell_magic_class(self):
553 "Cell magics declared via a class"
553 "Cell magics declared via a class"
554 @magics_class
554 @magics_class
555 class MyMagics(Magics):
555 class MyMagics(Magics):
556
556
557 @cell_magic
557 @cell_magic
558 def cellm3(self, line, cell):
558 def cellm3(self, line, cell):
559 return line, cell
559 return line, cell
560
560
561 _ip.register_magics(MyMagics)
561 _ip.register_magics(MyMagics)
562 self.check_ident('cellm3')
562 self.check_ident('cellm3')
563
563
564 def test_cell_magic_class2(self):
564 def test_cell_magic_class2(self):
565 "Cell magics declared via a class, #2"
565 "Cell magics declared via a class, #2"
566 @magics_class
566 @magics_class
567 class MyMagics2(Magics):
567 class MyMagics2(Magics):
568
568
569 @cell_magic('cellm4')
569 @cell_magic('cellm4')
570 def cellm33(self, line, cell):
570 def cellm33(self, line, cell):
571 return line, cell
571 return line, cell
572
572
573 _ip.register_magics(MyMagics2)
573 _ip.register_magics(MyMagics2)
574 self.check_ident('cellm4')
574 self.check_ident('cellm4')
575 # Check that nothing is registered as 'cellm33'
575 # Check that nothing is registered as 'cellm33'
576 c33 = _ip.find_cell_magic('cellm33')
576 c33 = _ip.find_cell_magic('cellm33')
577 nt.assert_equal(c33, None)
577 nt.assert_equal(c33, None)
578
578
579 def test_file():
579 def test_file():
580 """Basic %%file"""
580 """Basic %%file"""
581 ip = get_ipython()
581 ip = get_ipython()
582 with TemporaryDirectory() as td:
582 with TemporaryDirectory() as td:
583 fname = os.path.join(td, 'file1')
583 fname = os.path.join(td, 'file1')
584 ip.run_cell_magic("file", fname, u'\n'.join([
584 ip.run_cell_magic("file", fname, u'\n'.join([
585 'line1',
585 'line1',
586 'line2',
586 'line2',
587 ]))
587 ]))
588 with open(fname) as f:
588 with open(fname) as f:
589 s = f.read()
589 s = f.read()
590 nt.assert_in('line1\n', s)
590 nt.assert_in('line1\n', s)
591 nt.assert_in('line2', s)
591 nt.assert_in('line2', s)
592
592
593 def test_file_var_expand():
593 def test_file_var_expand():
594 """%%file $filename"""
594 """%%file $filename"""
595 ip = get_ipython()
595 ip = get_ipython()
596 with TemporaryDirectory() as td:
596 with TemporaryDirectory() as td:
597 fname = os.path.join(td, 'file1')
597 fname = os.path.join(td, 'file1')
598 ip.user_ns['filename'] = fname
598 ip.user_ns['filename'] = fname
599 ip.run_cell_magic("file", '$filename', u'\n'.join([
599 ip.run_cell_magic("file", '$filename', u'\n'.join([
600 'line1',
600 'line1',
601 'line2',
601 'line2',
602 ]))
602 ]))
603 with open(fname) as f:
603 with open(fname) as f:
604 s = f.read()
604 s = f.read()
605 nt.assert_in('line1\n', s)
605 nt.assert_in('line1\n', s)
606 nt.assert_in('line2', s)
606 nt.assert_in('line2', s)
607
607
608 def test_file_unicode():
608 def test_file_unicode():
609 """%%file with unicode cell"""
609 """%%file with unicode cell"""
610 ip = get_ipython()
610 ip = get_ipython()
611 with TemporaryDirectory() as td:
611 with TemporaryDirectory() as td:
612 fname = os.path.join(td, 'file1')
612 fname = os.path.join(td, 'file1')
613 ip.run_cell_magic("file", fname, u'\n'.join([
613 ip.run_cell_magic("file", fname, u'\n'.join([
614 u'linΓ©1',
614 u'linΓ©1',
615 u'linΓ©2',
615 u'linΓ©2',
616 ]))
616 ]))
617 with io.open(fname, encoding='utf-8') as f:
617 with io.open(fname, encoding='utf-8') as f:
618 s = f.read()
618 s = f.read()
619 nt.assert_in(u'linΓ©1\n', s)
619 nt.assert_in(u'linΓ©1\n', s)
620 nt.assert_in(u'linΓ©2', s)
620 nt.assert_in(u'linΓ©2', s)
621
621
622 def test_file_amend():
622 def test_file_amend():
623 """%%file -a amends files"""
623 """%%file -a amends files"""
624 ip = get_ipython()
624 ip = get_ipython()
625 with TemporaryDirectory() as td:
625 with TemporaryDirectory() as td:
626 fname = os.path.join(td, 'file2')
626 fname = os.path.join(td, 'file2')
627 ip.run_cell_magic("file", fname, u'\n'.join([
627 ip.run_cell_magic("file", fname, u'\n'.join([
628 'line1',
628 'line1',
629 'line2',
629 'line2',
630 ]))
630 ]))
631 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
631 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
632 'line3',
632 'line3',
633 'line4',
633 'line4',
634 ]))
634 ]))
635 with open(fname) as f:
635 with open(fname) as f:
636 s = f.read()
636 s = f.read()
637 nt.assert_in('line1\n', s)
637 nt.assert_in('line1\n', s)
638 nt.assert_in('line3\n', s)
638 nt.assert_in('line3\n', s)
639
639
640
640
641 def test_script_config():
641 def test_script_config():
642 ip = get_ipython()
642 ip = get_ipython()
643 ip.config.ScriptMagics.script_magics = ['whoda']
643 ip.config.ScriptMagics.script_magics = ['whoda']
644 sm = script.ScriptMagics(shell=ip)
644 sm = script.ScriptMagics(shell=ip)
645 nt.assert_in('whoda', sm.magics['cell'])
645 nt.assert_in('whoda', sm.magics['cell'])
646
646
647 @dec.skip_win32
647 @dec.skip_win32
648 def test_script_out():
648 def test_script_out():
649 ip = get_ipython()
649 ip = get_ipython()
650 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
650 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
651 nt.assert_equal(ip.user_ns['output'], 'hi\n')
651 nt.assert_equal(ip.user_ns['output'], 'hi\n')
652
652
653 @dec.skip_win32
653 @dec.skip_win32
654 def test_script_err():
654 def test_script_err():
655 ip = get_ipython()
655 ip = get_ipython()
656 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
656 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
657 nt.assert_equal(ip.user_ns['error'], 'hello\n')
657 nt.assert_equal(ip.user_ns['error'], 'hello\n')
658
658
659 @dec.skip_win32
659 @dec.skip_win32
660 def test_script_out_err():
660 def test_script_out_err():
661 ip = get_ipython()
661 ip = get_ipython()
662 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
662 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
663 nt.assert_equal(ip.user_ns['output'], 'hi\n')
663 nt.assert_equal(ip.user_ns['output'], 'hi\n')
664 nt.assert_equal(ip.user_ns['error'], 'hello\n')
664 nt.assert_equal(ip.user_ns['error'], 'hello\n')
665
665
666 @dec.skip_win32
666 @dec.skip_win32
667 def test_script_bg_out():
667 def test_script_bg_out():
668 ip = get_ipython()
668 ip = get_ipython()
669 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
669 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
670 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
670 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
671
671
672 @dec.skip_win32
672 @dec.skip_win32
673 def test_script_bg_err():
673 def test_script_bg_err():
674 ip = get_ipython()
674 ip = get_ipython()
675 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
675 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
676 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
676 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
677
677
678 @dec.skip_win32
678 @dec.skip_win32
679 def test_script_bg_out_err():
679 def test_script_bg_out_err():
680 ip = get_ipython()
680 ip = get_ipython()
681 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
681 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
682 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
682 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
683 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
683 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
684
684
685 def test_script_defaults():
685 def test_script_defaults():
686 ip = get_ipython()
686 ip = get_ipython()
687 for cmd in ['sh', 'bash', 'perl', 'ruby']:
687 for cmd in ['sh', 'bash', 'perl', 'ruby']:
688 try:
688 try:
689 find_cmd(cmd)
689 find_cmd(cmd)
690 except Exception:
690 except Exception:
691 pass
691 pass
692 else:
692 else:
693 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
693 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
694
694
695
695
696 @magics_class
696 @magics_class
697 class FooFoo(Magics):
697 class FooFoo(Magics):
698 """class with both %foo and %%foo magics"""
698 """class with both %foo and %%foo magics"""
699 @line_magic('foo')
699 @line_magic('foo')
700 def line_foo(self, line):
700 def line_foo(self, line):
701 "I am line foo"
701 "I am line foo"
702 pass
702 pass
703
703
704 @cell_magic("foo")
704 @cell_magic("foo")
705 def cell_foo(self, line, cell):
705 def cell_foo(self, line, cell):
706 "I am cell foo, not line foo"
706 "I am cell foo, not line foo"
707 pass
707 pass
708
708
709 def test_line_cell_info():
709 def test_line_cell_info():
710 """%%foo and %foo magics are distinguishable to inspect"""
710 """%%foo and %foo magics are distinguishable to inspect"""
711 ip = get_ipython()
711 ip = get_ipython()
712 ip.magics_manager.register(FooFoo)
712 ip.magics_manager.register(FooFoo)
713 oinfo = ip.object_inspect('foo')
713 oinfo = ip.object_inspect('foo')
714 nt.assert_true(oinfo['found'])
714 nt.assert_true(oinfo['found'])
715 nt.assert_true(oinfo['ismagic'])
715 nt.assert_true(oinfo['ismagic'])
716
716
717 oinfo = ip.object_inspect('%%foo')
717 oinfo = ip.object_inspect('%%foo')
718 nt.assert_true(oinfo['found'])
718 nt.assert_true(oinfo['found'])
719 nt.assert_true(oinfo['ismagic'])
719 nt.assert_true(oinfo['ismagic'])
720 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
720 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
721
721
722 oinfo = ip.object_inspect('%foo')
722 oinfo = ip.object_inspect('%foo')
723 nt.assert_true(oinfo['found'])
723 nt.assert_true(oinfo['found'])
724 nt.assert_true(oinfo['ismagic'])
724 nt.assert_true(oinfo['ismagic'])
725 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
725 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
726
726
727 def test_multiple_magics():
727 def test_multiple_magics():
728 ip = get_ipython()
728 ip = get_ipython()
729 foo1 = FooFoo(ip)
729 foo1 = FooFoo(ip)
730 foo2 = FooFoo(ip)
730 foo2 = FooFoo(ip)
731 mm = ip.magics_manager
731 mm = ip.magics_manager
732 mm.register(foo1)
732 mm.register(foo1)
733 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
733 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
734 mm.register(foo2)
734 mm.register(foo2)
735 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
735 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
736
736
737 def test_alias_magic():
737 def test_alias_magic():
738 """Test %alias_magic."""
738 """Test %alias_magic."""
739 ip = get_ipython()
739 ip = get_ipython()
740 mm = ip.magics_manager
740 mm = ip.magics_manager
741
741
742 # Basic operation: both cell and line magics are created, if possible.
742 # Basic operation: both cell and line magics are created, if possible.
743 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
743 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
744 nt.assert_true('timeit_alias' in mm.magics['line'])
744 nt.assert_true('timeit_alias' in mm.magics['line'])
745 nt.assert_true('timeit_alias' in mm.magics['cell'])
745 nt.assert_true('timeit_alias' in mm.magics['cell'])
746
746
747 # --cell is specified, line magic not created.
747 # --cell is specified, line magic not created.
748 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
748 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
749 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
749 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
750 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
750 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
751
751
752 # Test that line alias is created successfully.
752 # Test that line alias is created successfully.
753 ip.run_line_magic('alias_magic', '--line env_alias env')
753 ip.run_line_magic('alias_magic', '--line env_alias env')
754 nt.assert_equal(ip.run_line_magic('env', ''),
754 nt.assert_equal(ip.run_line_magic('env', ''),
755 ip.run_line_magic('env_alias', ''))
755 ip.run_line_magic('env_alias', ''))
756
756
757 def test_save():
757 def test_save():
758 """Test %save."""
758 """Test %save."""
759 ip = get_ipython()
759 ip = get_ipython()
760 ip.history_manager.reset() # Clear any existing history.
760 ip.history_manager.reset() # Clear any existing history.
761 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
761 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
762 for i, cmd in enumerate(cmds, start=1):
762 for i, cmd in enumerate(cmds, start=1):
763 ip.history_manager.store_inputs(i, cmd)
763 ip.history_manager.store_inputs(i, cmd)
764 with TemporaryDirectory() as tmpdir:
764 with TemporaryDirectory() as tmpdir:
765 file = os.path.join(tmpdir, "testsave.py")
765 file = os.path.join(tmpdir, "testsave.py")
766 ip.run_line_magic("save", "%s 1-10" % file)
766 ip.run_line_magic("save", "%s 1-10" % file)
767 with open(file) as f:
767 with open(file) as f:
768 content = f.read()
768 content = f.read()
769 nt.assert_equal(content.count(cmds[0]), 1)
769 nt.assert_equal(content.count(cmds[0]), 1)
770 nt.assert_true('coding: utf-8' in content)
770 nt.assert_true('coding: utf-8' in content)
771 ip.run_line_magic("save", "-a %s 1-10" % file)
771 ip.run_line_magic("save", "-a %s 1-10" % file)
772 with open(file) as f:
772 with open(file) as f:
773 content = f.read()
773 content = f.read()
774 nt.assert_equal(content.count(cmds[0]), 2)
774 nt.assert_equal(content.count(cmds[0]), 2)
775 nt.assert_true('coding: utf-8' in content)
775 nt.assert_true('coding: utf-8' in content)
776
776
777
777
778 def test_store():
778 def test_store():
779 """Test %store."""
779 """Test %store."""
780 ip = get_ipython()
780 ip = get_ipython()
781 ip.run_line_magic('load_ext', 'storemagic')
781 ip.run_line_magic('load_ext', 'storemagic')
782
782
783 # make sure the storage is empty
783 # make sure the storage is empty
784 ip.run_line_magic('store', '-z')
784 ip.run_line_magic('store', '-z')
785 ip.user_ns['var'] = 42
785 ip.user_ns['var'] = 42
786 ip.run_line_magic('store', 'var')
786 ip.run_line_magic('store', 'var')
787 ip.user_ns['var'] = 39
787 ip.user_ns['var'] = 39
788 ip.run_line_magic('store', '-r')
788 ip.run_line_magic('store', '-r')
789 nt.assert_equal(ip.user_ns['var'], 42)
789 nt.assert_equal(ip.user_ns['var'], 42)
790
790
791 ip.run_line_magic('store', '-d var')
791 ip.run_line_magic('store', '-d var')
792 ip.user_ns['var'] = 39
792 ip.user_ns['var'] = 39
793 ip.run_line_magic('store' , '-r')
793 ip.run_line_magic('store' , '-r')
794 nt.assert_equal(ip.user_ns['var'], 39)
794 nt.assert_equal(ip.user_ns['var'], 39)
795
796
797 def _run_edit_test(arg_s, exp_filename=None,
798 exp_lineno=-1,
799 exp_contents=None,
800 exp_is_temp=None):
801 ip = get_ipython()
802 M = code.CodeMagics(ip)
803 last_call = ['','']
804 opts,args = M.parse_options(arg_s,'prxn:')
805 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
806
807 if exp_filename is not None:
808 nt.assert_equal(exp_filename, filename)
809 if exp_contents is not None:
810 with io.open(filename, 'r') as f:
811 contents = f.read()
812 nt.assert_equal(exp_contents, contents)
813 if exp_lineno != -1:
814 nt.assert_equal(exp_lineno, lineno)
815 if exp_is_temp is not None:
816 nt.assert_equal(exp_is_temp, is_temp)
817
818
819 def test_edit_interactive():
820 """%edit on interactively defined objects"""
821 ip = get_ipython()
822 n = ip.execution_count
823 ip.run_cell(u"def foo(): return 1", store_history=True)
824
825 try:
826 _run_edit_test("foo")
827 except code.InteractivelyDefined as e:
828 nt.assert_equal(e.index, n)
829 else:
830 nt.fail("Should have raised InteractivelyDefined")
831
832
833 def test_edit_cell():
834 """%edit [cell id]"""
835 ip = get_ipython()
836
837 ip.run_cell(u"def foo(): return 1", store_history=True)
838
839 # test
840 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
General Comments 0
You need to be logged in to leave comments. Login now