##// END OF EJS Templates
Merge pull request #2131 from doda/master...
Thomas Kluyver -
r7869:7efca4ef merge
parent child Browse files
Show More
@@ -1,521 +1,531 b''
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 sys
20 import sys
21 from urllib2 import urlopen
21 from urllib2 import urlopen
22
22
23 # Our own packages
23 # Our own packages
24 from IPython.core.error import TryNext, StdinNotImplementedError
24 from IPython.core.error import TryNext, StdinNotImplementedError
25 from IPython.core.macro import Macro
25 from IPython.core.macro import Macro
26 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.magic import Magics, magics_class, line_magic
27 from IPython.core.oinspect import find_file, find_source_lines
27 from IPython.core.oinspect import find_file, find_source_lines
28 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.utils import openpy
29 from IPython.utils import openpy
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31 from IPython.utils.io import file_read
31 from IPython.utils.io import file_read
32 from IPython.utils.path import get_py_filename, unquote_filename
32 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.warn import warn
33 from IPython.utils.warn import warn
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Magic implementation classes
36 # Magic implementation classes
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 # Used for exception handling in magic_edit
39 # Used for exception handling in magic_edit
40 class MacroToEdit(ValueError): pass
40 class MacroToEdit(ValueError): pass
41
41
42
42
43 @magics_class
43 @magics_class
44 class CodeMagics(Magics):
44 class CodeMagics(Magics):
45 """Magics related to code management (loading, saving, editing, ...)."""
45 """Magics related to code management (loading, saving, editing, ...)."""
46
46
47 @line_magic
47 @line_magic
48 def save(self, parameter_s=''):
48 def save(self, parameter_s=''):
49 """Save a set of lines or a macro to a given filename.
49 """Save a set of lines or a macro to a given filename.
50
50
51 Usage:\\
51 Usage:\\
52 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
52 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
53
53
54 Options:
54 Options:
55
55
56 -r: use 'raw' input. By default, the 'processed' history is used,
56 -r: use 'raw' input. By default, the 'processed' history is used,
57 so that magics are loaded in their transformed version to valid
57 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
58 Python. If this option is given, the raw input as typed as the
59 command line is used instead.
59 command line is used instead.
60
60
61 -f: force overwrite. If file exists, %save will prompt for overwrite
61 -f: force overwrite. If file exists, %save will prompt for overwrite
62 unless -f is given.
62 unless -f is given.
63
63
64 -a: append to the file instead of overwriting it.
65
64 This function uses the same syntax as %history for input ranges,
66 This function uses the same syntax as %history for input ranges,
65 then saves the lines to the filename you specify.
67 then saves the lines to the filename you specify.
66
68
67 It adds a '.py' extension to the file if you don't do so yourself, and
69 It adds a '.py' extension to the file if you don't do so yourself, and
68 it asks for confirmation before overwriting existing files.
70 it asks for confirmation before overwriting existing files.
69
71
70 If `-r` option is used, the default extension is `.ipy`.
72 If `-r` option is used, the default extension is `.ipy`.
71 """
73 """
72
74
73 opts,args = self.parse_options(parameter_s,'fr',mode='list')
75 opts,args = self.parse_options(parameter_s,'fra',mode='list')
74 raw = 'r' in opts
76 raw = 'r' in opts
75 force = 'f' in opts
77 force = 'f' in opts
78 append = 'a' in opts
79 mode = 'a' if append else 'w'
76 ext = u'.ipy' if raw else u'.py'
80 ext = u'.ipy' if raw else u'.py'
77 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
81 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
78 if not fname.endswith((u'.py',u'.ipy')):
82 if not fname.endswith((u'.py',u'.ipy')):
79 fname += ext
83 fname += ext
80 if os.path.isfile(fname) and not force:
84 file_exists = os.path.isfile(fname)
85 if file_exists and not force and not append:
81 try:
86 try:
82 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
87 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
83 except StdinNotImplementedError:
88 except StdinNotImplementedError:
84 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
89 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
85 return
90 return
86 if not overwrite :
91 if not overwrite :
87 print 'Operation cancelled.'
92 print 'Operation cancelled.'
88 return
93 return
89 try:
94 try:
90 cmds = self.shell.find_user_code(codefrom,raw)
95 cmds = self.shell.find_user_code(codefrom,raw)
91 except (TypeError, ValueError) as e:
96 except (TypeError, ValueError) as e:
92 print e.args[0]
97 print e.args[0]
93 return
98 return
94 with io.open(fname,'w', encoding="utf-8") as f:
99 out = py3compat.cast_unicode(cmds)
95 f.write(u"# coding: utf-8\n")
100 with io.open(fname, mode, encoding="utf-8") as f:
96 f.write(py3compat.cast_unicode(cmds))
101 if not file_exists or not append:
102 f.write(u"# coding: utf-8\n")
103 f.write(out)
104 # make sure we end on a newline
105 if not out.endswith(u'\n'):
106 f.write(u'\n')
97 print 'The following commands were written to file `%s`:' % fname
107 print 'The following commands were written to file `%s`:' % fname
98 print cmds
108 print cmds
99
109
100 @line_magic
110 @line_magic
101 def pastebin(self, parameter_s=''):
111 def pastebin(self, parameter_s=''):
102 """Upload code to Github's Gist paste bin, returning the URL.
112 """Upload code to Github's Gist paste bin, returning the URL.
103
113
104 Usage:\\
114 Usage:\\
105 %pastebin [-d "Custom description"] 1-7
115 %pastebin [-d "Custom description"] 1-7
106
116
107 The argument can be an input history range, a filename, or the name of a
117 The argument can be an input history range, a filename, or the name of a
108 string or macro.
118 string or macro.
109
119
110 Options:
120 Options:
111
121
112 -d: Pass a custom description for the gist. The default will say
122 -d: Pass a custom description for the gist. The default will say
113 "Pasted from IPython".
123 "Pasted from IPython".
114 """
124 """
115 opts, args = self.parse_options(parameter_s, 'd:')
125 opts, args = self.parse_options(parameter_s, 'd:')
116
126
117 try:
127 try:
118 code = self.shell.find_user_code(args)
128 code = self.shell.find_user_code(args)
119 except (ValueError, TypeError) as e:
129 except (ValueError, TypeError) as e:
120 print e.args[0]
130 print e.args[0]
121 return
131 return
122
132
123 post_data = json.dumps({
133 post_data = json.dumps({
124 "description": opts.get('d', "Pasted from IPython"),
134 "description": opts.get('d', "Pasted from IPython"),
125 "public": True,
135 "public": True,
126 "files": {
136 "files": {
127 "file1.py": {
137 "file1.py": {
128 "content": code
138 "content": code
129 }
139 }
130 }
140 }
131 }).encode('utf-8')
141 }).encode('utf-8')
132
142
133 response = urlopen("https://api.github.com/gists", post_data)
143 response = urlopen("https://api.github.com/gists", post_data)
134 response_data = json.loads(response.read().decode('utf-8'))
144 response_data = json.loads(response.read().decode('utf-8'))
135 return response_data['html_url']
145 return response_data['html_url']
136
146
137 @line_magic
147 @line_magic
138 def loadpy(self, arg_s):
148 def loadpy(self, arg_s):
139 """Alias of `%load`
149 """Alias of `%load`
140
150
141 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
151 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
142 extension. So it has been renamed simply into %load. You can look at
152 extension. So it has been renamed simply into %load. You can look at
143 `%load`'s docstring for more info.
153 `%load`'s docstring for more info.
144 """
154 """
145 self.load(arg_s)
155 self.load(arg_s)
146
156
147 @line_magic
157 @line_magic
148 def load(self, arg_s):
158 def load(self, arg_s):
149 """Load code into the current frontend.
159 """Load code into the current frontend.
150
160
151 Usage:\\
161 Usage:\\
152 %load [options] source
162 %load [options] source
153
163
154 where source can be a filename, URL, input history range or macro
164 where source can be a filename, URL, input history range or macro
155
165
156 Options:
166 Options:
157 --------
167 --------
158 -y : Don't ask confirmation for loading source above 200 000 characters.
168 -y : Don't ask confirmation for loading source above 200 000 characters.
159
169
160 This magic command can either take a local filename, a URL, an history
170 This magic command can either take a local filename, a URL, an history
161 range (see %history) or a macro as argument, it will prompt for
171 range (see %history) or a macro as argument, it will prompt for
162 confirmation before loading source with more than 200 000 characters, unless
172 confirmation before loading source with more than 200 000 characters, unless
163 -y flag is passed or if the frontend does not support raw_input::
173 -y flag is passed or if the frontend does not support raw_input::
164
174
165 %load myscript.py
175 %load myscript.py
166 %load 7-27
176 %load 7-27
167 %load myMacro
177 %load myMacro
168 %load http://www.example.com/myscript.py
178 %load http://www.example.com/myscript.py
169 """
179 """
170 opts,args = self.parse_options(arg_s,'y')
180 opts,args = self.parse_options(arg_s,'y')
171
181
172 contents = self.shell.find_user_code(args)
182 contents = self.shell.find_user_code(args)
173 l = len(contents)
183 l = len(contents)
174
184
175 # 200 000 is ~ 2500 full 80 caracter lines
185 # 200 000 is ~ 2500 full 80 caracter lines
176 # so in average, more than 5000 lines
186 # so in average, more than 5000 lines
177 if l > 200000 and 'y' not in opts:
187 if l > 200000 and 'y' not in opts:
178 try:
188 try:
179 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
189 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
180 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
190 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
181 except StdinNotImplementedError:
191 except StdinNotImplementedError:
182 #asume yes if raw input not implemented
192 #asume yes if raw input not implemented
183 ans = True
193 ans = True
184
194
185 if ans is False :
195 if ans is False :
186 print 'Operation cancelled.'
196 print 'Operation cancelled.'
187 return
197 return
188
198
189 self.shell.set_next_input(contents)
199 self.shell.set_next_input(contents)
190
200
191 @staticmethod
201 @staticmethod
192 def _find_edit_target(shell, args, opts, last_call):
202 def _find_edit_target(shell, args, opts, last_call):
193 """Utility method used by magic_edit to find what to edit."""
203 """Utility method used by magic_edit to find what to edit."""
194
204
195 def make_filename(arg):
205 def make_filename(arg):
196 "Make a filename from the given args"
206 "Make a filename from the given args"
197 arg = unquote_filename(arg)
207 arg = unquote_filename(arg)
198 try:
208 try:
199 filename = get_py_filename(arg)
209 filename = get_py_filename(arg)
200 except IOError:
210 except IOError:
201 # If it ends with .py but doesn't already exist, assume we want
211 # If it ends with .py but doesn't already exist, assume we want
202 # a new file.
212 # a new file.
203 if arg.endswith('.py'):
213 if arg.endswith('.py'):
204 filename = arg
214 filename = arg
205 else:
215 else:
206 filename = None
216 filename = None
207 return filename
217 return filename
208
218
209 # Set a few locals from the options for convenience:
219 # Set a few locals from the options for convenience:
210 opts_prev = 'p' in opts
220 opts_prev = 'p' in opts
211 opts_raw = 'r' in opts
221 opts_raw = 'r' in opts
212
222
213 # custom exceptions
223 # custom exceptions
214 class DataIsObject(Exception): pass
224 class DataIsObject(Exception): pass
215
225
216 # Default line number value
226 # Default line number value
217 lineno = opts.get('n',None)
227 lineno = opts.get('n',None)
218
228
219 if opts_prev:
229 if opts_prev:
220 args = '_%s' % last_call[0]
230 args = '_%s' % last_call[0]
221 if not shell.user_ns.has_key(args):
231 if not shell.user_ns.has_key(args):
222 args = last_call[1]
232 args = last_call[1]
223
233
224 # use last_call to remember the state of the previous call, but don't
234 # use last_call to remember the state of the previous call, but don't
225 # let it be clobbered by successive '-p' calls.
235 # let it be clobbered by successive '-p' calls.
226 try:
236 try:
227 last_call[0] = shell.displayhook.prompt_count
237 last_call[0] = shell.displayhook.prompt_count
228 if not opts_prev:
238 if not opts_prev:
229 last_call[1] = args
239 last_call[1] = args
230 except:
240 except:
231 pass
241 pass
232
242
233 # by default this is done with temp files, except when the given
243 # by default this is done with temp files, except when the given
234 # arg is a filename
244 # arg is a filename
235 use_temp = True
245 use_temp = True
236
246
237 data = ''
247 data = ''
238
248
239 # First, see if the arguments should be a filename.
249 # First, see if the arguments should be a filename.
240 filename = make_filename(args)
250 filename = make_filename(args)
241 if filename:
251 if filename:
242 use_temp = False
252 use_temp = False
243 elif args:
253 elif args:
244 # Mode where user specifies ranges of lines, like in %macro.
254 # Mode where user specifies ranges of lines, like in %macro.
245 data = shell.extract_input_lines(args, opts_raw)
255 data = shell.extract_input_lines(args, opts_raw)
246 if not data:
256 if not data:
247 try:
257 try:
248 # Load the parameter given as a variable. If not a string,
258 # Load the parameter given as a variable. If not a string,
249 # process it as an object instead (below)
259 # process it as an object instead (below)
250
260
251 #print '*** args',args,'type',type(args) # dbg
261 #print '*** args',args,'type',type(args) # dbg
252 data = eval(args, shell.user_ns)
262 data = eval(args, shell.user_ns)
253 if not isinstance(data, basestring):
263 if not isinstance(data, basestring):
254 raise DataIsObject
264 raise DataIsObject
255
265
256 except (NameError,SyntaxError):
266 except (NameError,SyntaxError):
257 # given argument is not a variable, try as a filename
267 # given argument is not a variable, try as a filename
258 filename = make_filename(args)
268 filename = make_filename(args)
259 if filename is None:
269 if filename is None:
260 warn("Argument given (%s) can't be found as a variable "
270 warn("Argument given (%s) can't be found as a variable "
261 "or as a filename." % args)
271 "or as a filename." % args)
262 return
272 return
263 use_temp = False
273 use_temp = False
264
274
265 except DataIsObject:
275 except DataIsObject:
266 # macros have a special edit function
276 # macros have a special edit function
267 if isinstance(data, Macro):
277 if isinstance(data, Macro):
268 raise MacroToEdit(data)
278 raise MacroToEdit(data)
269
279
270 # For objects, try to edit the file where they are defined
280 # For objects, try to edit the file where they are defined
271 filename = find_file(data)
281 filename = find_file(data)
272 if filename:
282 if filename:
273 if 'fakemodule' in filename.lower() and \
283 if 'fakemodule' in filename.lower() and \
274 inspect.isclass(data):
284 inspect.isclass(data):
275 # class created by %edit? Try to find source
285 # class created by %edit? Try to find source
276 # by looking for method definitions instead, the
286 # by looking for method definitions instead, the
277 # __module__ in those classes is FakeModule.
287 # __module__ in those classes is FakeModule.
278 attrs = [getattr(data, aname) for aname in dir(data)]
288 attrs = [getattr(data, aname) for aname in dir(data)]
279 for attr in attrs:
289 for attr in attrs:
280 if not inspect.ismethod(attr):
290 if not inspect.ismethod(attr):
281 continue
291 continue
282 filename = find_file(attr)
292 filename = find_file(attr)
283 if filename and \
293 if filename and \
284 'fakemodule' not in filename.lower():
294 'fakemodule' not in filename.lower():
285 # change the attribute to be the edit
295 # change the attribute to be the edit
286 # target instead
296 # target instead
287 data = attr
297 data = attr
288 break
298 break
289
299
290 datafile = 1
300 datafile = 1
291 if filename is None:
301 if filename is None:
292 filename = make_filename(args)
302 filename = make_filename(args)
293 datafile = 1
303 datafile = 1
294 warn('Could not find file where `%s` is defined.\n'
304 warn('Could not find file where `%s` is defined.\n'
295 'Opening a file named `%s`' % (args, filename))
305 'Opening a file named `%s`' % (args, filename))
296 # Now, make sure we can actually read the source (if it was
306 # Now, make sure we can actually read the source (if it was
297 # in a temp file it's gone by now).
307 # in a temp file it's gone by now).
298 if datafile:
308 if datafile:
299 if lineno is None:
309 if lineno is None:
300 lineno = find_source_lines(data)
310 lineno = find_source_lines(data)
301 if lineno is None:
311 if lineno is None:
302 filename = make_filename(args)
312 filename = make_filename(args)
303 if filename is None:
313 if filename is None:
304 warn('The file `%s` where `%s` was defined '
314 warn('The file `%s` where `%s` was defined '
305 'cannot be read.' % (filename, data))
315 'cannot be read.' % (filename, data))
306 return
316 return
307 use_temp = False
317 use_temp = False
308
318
309 if use_temp:
319 if use_temp:
310 filename = shell.mktempfile(data)
320 filename = shell.mktempfile(data)
311 print 'IPython will make a temporary file named:',filename
321 print 'IPython will make a temporary file named:',filename
312
322
313 return filename, lineno, use_temp
323 return filename, lineno, use_temp
314
324
315 def _edit_macro(self,mname,macro):
325 def _edit_macro(self,mname,macro):
316 """open an editor with the macro data in a file"""
326 """open an editor with the macro data in a file"""
317 filename = self.shell.mktempfile(macro.value)
327 filename = self.shell.mktempfile(macro.value)
318 self.shell.hooks.editor(filename)
328 self.shell.hooks.editor(filename)
319
329
320 # and make a new macro object, to replace the old one
330 # and make a new macro object, to replace the old one
321 mfile = open(filename)
331 mfile = open(filename)
322 mvalue = mfile.read()
332 mvalue = mfile.read()
323 mfile.close()
333 mfile.close()
324 self.shell.user_ns[mname] = Macro(mvalue)
334 self.shell.user_ns[mname] = Macro(mvalue)
325
335
326 @line_magic
336 @line_magic
327 def ed(self, parameter_s=''):
337 def ed(self, parameter_s=''):
328 """Alias to %edit."""
338 """Alias to %edit."""
329 return self.edit(parameter_s)
339 return self.edit(parameter_s)
330
340
331 @skip_doctest
341 @skip_doctest
332 @line_magic
342 @line_magic
333 def edit(self, parameter_s='',last_call=['','']):
343 def edit(self, parameter_s='',last_call=['','']):
334 """Bring up an editor and execute the resulting code.
344 """Bring up an editor and execute the resulting code.
335
345
336 Usage:
346 Usage:
337 %edit [options] [args]
347 %edit [options] [args]
338
348
339 %edit runs IPython's editor hook. The default version of this hook is
349 %edit runs IPython's editor hook. The default version of this hook is
340 set to call the editor specified by your $EDITOR environment variable.
350 set to call the editor specified by your $EDITOR environment variable.
341 If this isn't found, it will default to vi under Linux/Unix and to
351 If this isn't found, it will default to vi under Linux/Unix and to
342 notepad under Windows. See the end of this docstring for how to change
352 notepad under Windows. See the end of this docstring for how to change
343 the editor hook.
353 the editor hook.
344
354
345 You can also set the value of this editor via the
355 You can also set the value of this editor via the
346 ``TerminalInteractiveShell.editor`` option in your configuration file.
356 ``TerminalInteractiveShell.editor`` option in your configuration file.
347 This is useful if you wish to use a different editor from your typical
357 This is useful if you wish to use a different editor from your typical
348 default with IPython (and for Windows users who typically don't set
358 default with IPython (and for Windows users who typically don't set
349 environment variables).
359 environment variables).
350
360
351 This command allows you to conveniently edit multi-line code right in
361 This command allows you to conveniently edit multi-line code right in
352 your IPython session.
362 your IPython session.
353
363
354 If called without arguments, %edit opens up an empty editor with a
364 If called without arguments, %edit opens up an empty editor with a
355 temporary file and will execute the contents of this file when you
365 temporary file and will execute the contents of this file when you
356 close it (don't forget to save it!).
366 close it (don't forget to save it!).
357
367
358
368
359 Options:
369 Options:
360
370
361 -n <number>: open the editor at a specified line number. By default,
371 -n <number>: open the editor at a specified line number. By default,
362 the IPython editor hook uses the unix syntax 'editor +N filename', but
372 the IPython editor hook uses the unix syntax 'editor +N filename', but
363 you can configure this by providing your own modified hook if your
373 you can configure this by providing your own modified hook if your
364 favorite editor supports line-number specifications with a different
374 favorite editor supports line-number specifications with a different
365 syntax.
375 syntax.
366
376
367 -p: this will call the editor with the same data as the previous time
377 -p: this will call the editor with the same data as the previous time
368 it was used, regardless of how long ago (in your current session) it
378 it was used, regardless of how long ago (in your current session) it
369 was.
379 was.
370
380
371 -r: use 'raw' input. This option only applies to input taken from the
381 -r: use 'raw' input. This option only applies to input taken from the
372 user's history. By default, the 'processed' history is used, so that
382 user's history. By default, the 'processed' history is used, so that
373 magics are loaded in their transformed version to valid Python. If
383 magics are loaded in their transformed version to valid Python. If
374 this option is given, the raw input as typed as the command line is
384 this option is given, the raw input as typed as the command line is
375 used instead. When you exit the editor, it will be executed by
385 used instead. When you exit the editor, it will be executed by
376 IPython's own processor.
386 IPython's own processor.
377
387
378 -x: do not execute the edited code immediately upon exit. This is
388 -x: do not execute the edited code immediately upon exit. This is
379 mainly useful if you are editing programs which need to be called with
389 mainly useful if you are editing programs which need to be called with
380 command line arguments, which you can then do using %run.
390 command line arguments, which you can then do using %run.
381
391
382
392
383 Arguments:
393 Arguments:
384
394
385 If arguments are given, the following possibilities exist:
395 If arguments are given, the following possibilities exist:
386
396
387 - If the argument is a filename, IPython will load that into the
397 - If the argument is a filename, IPython will load that into the
388 editor. It will execute its contents with execfile() when you exit,
398 editor. It will execute its contents with execfile() when you exit,
389 loading any code in the file into your interactive namespace.
399 loading any code in the file into your interactive namespace.
390
400
391 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
401 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
392 The syntax is the same as in the %history magic.
402 The syntax is the same as in the %history magic.
393
403
394 - If the argument is a string variable, its contents are loaded
404 - If the argument is a string variable, its contents are loaded
395 into the editor. You can thus edit any string which contains
405 into the editor. You can thus edit any string which contains
396 python code (including the result of previous edits).
406 python code (including the result of previous edits).
397
407
398 - If the argument is the name of an object (other than a string),
408 - If the argument is the name of an object (other than a string),
399 IPython will try to locate the file where it was defined and open the
409 IPython will try to locate the file where it was defined and open the
400 editor at the point where it is defined. You can use `%edit function`
410 editor at the point where it is defined. You can use `%edit function`
401 to load an editor exactly at the point where 'function' is defined,
411 to load an editor exactly at the point where 'function' is defined,
402 edit it and have the file be executed automatically.
412 edit it and have the file be executed automatically.
403
413
404 - If the object is a macro (see %macro for details), this opens up your
414 - If the object is a macro (see %macro for details), this opens up your
405 specified editor with a temporary file containing the macro's data.
415 specified editor with a temporary file containing the macro's data.
406 Upon exit, the macro is reloaded with the contents of the file.
416 Upon exit, the macro is reloaded with the contents of the file.
407
417
408 Note: opening at an exact line is only supported under Unix, and some
418 Note: opening at an exact line is only supported under Unix, and some
409 editors (like kedit and gedit up to Gnome 2.8) do not understand the
419 editors (like kedit and gedit up to Gnome 2.8) do not understand the
410 '+NUMBER' parameter necessary for this feature. Good editors like
420 '+NUMBER' parameter necessary for this feature. Good editors like
411 (X)Emacs, vi, jed, pico and joe all do.
421 (X)Emacs, vi, jed, pico and joe all do.
412
422
413 After executing your code, %edit will return as output the code you
423 After executing your code, %edit will return as output the code you
414 typed in the editor (except when it was an existing file). This way
424 typed in the editor (except when it was an existing file). This way
415 you can reload the code in further invocations of %edit as a variable,
425 you can reload the code in further invocations of %edit as a variable,
416 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
426 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
417 the output.
427 the output.
418
428
419 Note that %edit is also available through the alias %ed.
429 Note that %edit is also available through the alias %ed.
420
430
421 This is an example of creating a simple function inside the editor and
431 This is an example of creating a simple function inside the editor and
422 then modifying it. First, start up the editor::
432 then modifying it. First, start up the editor::
423
433
424 In [1]: ed
434 In [1]: ed
425 Editing... done. Executing edited code...
435 Editing... done. Executing edited code...
426 Out[1]: 'def foo():\\n print "foo() was defined in an editing
436 Out[1]: 'def foo():\\n print "foo() was defined in an editing
427 session"\\n'
437 session"\\n'
428
438
429 We can then call the function foo()::
439 We can then call the function foo()::
430
440
431 In [2]: foo()
441 In [2]: foo()
432 foo() was defined in an editing session
442 foo() was defined in an editing session
433
443
434 Now we edit foo. IPython automatically loads the editor with the
444 Now we edit foo. IPython automatically loads the editor with the
435 (temporary) file where foo() was previously defined::
445 (temporary) file where foo() was previously defined::
436
446
437 In [3]: ed foo
447 In [3]: ed foo
438 Editing... done. Executing edited code...
448 Editing... done. Executing edited code...
439
449
440 And if we call foo() again we get the modified version::
450 And if we call foo() again we get the modified version::
441
451
442 In [4]: foo()
452 In [4]: foo()
443 foo() has now been changed!
453 foo() has now been changed!
444
454
445 Here is an example of how to edit a code snippet successive
455 Here is an example of how to edit a code snippet successive
446 times. First we call the editor::
456 times. First we call the editor::
447
457
448 In [5]: ed
458 In [5]: ed
449 Editing... done. Executing edited code...
459 Editing... done. Executing edited code...
450 hello
460 hello
451 Out[5]: "print 'hello'\\n"
461 Out[5]: "print 'hello'\\n"
452
462
453 Now we call it again with the previous output (stored in _)::
463 Now we call it again with the previous output (stored in _)::
454
464
455 In [6]: ed _
465 In [6]: ed _
456 Editing... done. Executing edited code...
466 Editing... done. Executing edited code...
457 hello world
467 hello world
458 Out[6]: "print 'hello world'\\n"
468 Out[6]: "print 'hello world'\\n"
459
469
460 Now we call it with the output #8 (stored in _8, also as Out[8])::
470 Now we call it with the output #8 (stored in _8, also as Out[8])::
461
471
462 In [7]: ed _8
472 In [7]: ed _8
463 Editing... done. Executing edited code...
473 Editing... done. Executing edited code...
464 hello again
474 hello again
465 Out[7]: "print 'hello again'\\n"
475 Out[7]: "print 'hello again'\\n"
466
476
467
477
468 Changing the default editor hook:
478 Changing the default editor hook:
469
479
470 If you wish to write your own editor hook, you can put it in a
480 If you wish to write your own editor hook, you can put it in a
471 configuration file which you load at startup time. The default hook
481 configuration file which you load at startup time. The default hook
472 is defined in the IPython.core.hooks module, and you can use that as a
482 is defined in the IPython.core.hooks module, and you can use that as a
473 starting example for further modifications. That file also has
483 starting example for further modifications. That file also has
474 general instructions on how to set a new hook for use once you've
484 general instructions on how to set a new hook for use once you've
475 defined it."""
485 defined it."""
476 opts,args = self.parse_options(parameter_s,'prxn:')
486 opts,args = self.parse_options(parameter_s,'prxn:')
477
487
478 try:
488 try:
479 filename, lineno, is_temp = self._find_edit_target(self.shell,
489 filename, lineno, is_temp = self._find_edit_target(self.shell,
480 args, opts, last_call)
490 args, opts, last_call)
481 except MacroToEdit as e:
491 except MacroToEdit as e:
482 self._edit_macro(args, e.args[0])
492 self._edit_macro(args, e.args[0])
483 return
493 return
484
494
485 # do actual editing here
495 # do actual editing here
486 print 'Editing...',
496 print 'Editing...',
487 sys.stdout.flush()
497 sys.stdout.flush()
488 try:
498 try:
489 # Quote filenames that may have spaces in them
499 # Quote filenames that may have spaces in them
490 if ' ' in filename:
500 if ' ' in filename:
491 filename = "'%s'" % filename
501 filename = "'%s'" % filename
492 self.shell.hooks.editor(filename,lineno)
502 self.shell.hooks.editor(filename,lineno)
493 except TryNext:
503 except TryNext:
494 warn('Could not open editor')
504 warn('Could not open editor')
495 return
505 return
496
506
497 # XXX TODO: should this be generalized for all string vars?
507 # XXX TODO: should this be generalized for all string vars?
498 # For now, this is special-cased to blocks created by cpaste
508 # For now, this is special-cased to blocks created by cpaste
499 if args.strip() == 'pasted_block':
509 if args.strip() == 'pasted_block':
500 self.shell.user_ns['pasted_block'] = file_read(filename)
510 self.shell.user_ns['pasted_block'] = file_read(filename)
501
511
502 if 'x' in opts: # -x prevents actual execution
512 if 'x' in opts: # -x prevents actual execution
503 print
513 print
504 else:
514 else:
505 print 'done. Executing edited code...'
515 print 'done. Executing edited code...'
506 if 'r' in opts: # Untranslated IPython code
516 if 'r' in opts: # Untranslated IPython code
507 self.shell.run_cell(file_read(filename),
517 self.shell.run_cell(file_read(filename),
508 store_history=False)
518 store_history=False)
509 else:
519 else:
510 self.shell.safe_execfile(filename, self.shell.user_ns,
520 self.shell.safe_execfile(filename, self.shell.user_ns,
511 self.shell.user_ns)
521 self.shell.user_ns)
512
522
513 if is_temp:
523 if is_temp:
514 try:
524 try:
515 return open(filename).read()
525 return open(filename).read()
516 except IOError as msg:
526 except IOError as msg:
517 if msg.filename == filename:
527 if msg.filename == filename:
518 warn('File not found. Did you forget to save?')
528 warn('File not found. Did you forget to save?')
519 return
529 return
520 else:
530 else:
521 self.shell.showtraceback()
531 self.shell.showtraceback()
@@ -1,151 +1,151 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for the IPython tab-completion machinery.
2 """Tests for the IPython tab-completion machinery.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Module imports
5 # Module imports
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7
7
8 # stdlib
8 # stdlib
9 import os
9 import os
10 import shutil
10 import shutil
11 import sys
11 import sys
12 import tempfile
12 import tempfile
13 import unittest
13 import unittest
14 from datetime import datetime
14 from datetime import datetime
15
15
16 # third party
16 # third party
17 import nose.tools as nt
17 import nose.tools as nt
18
18
19 # our own packages
19 # our own packages
20 from IPython.config.loader import Config
20 from IPython.config.loader import Config
21 from IPython.utils.tempdir import TemporaryDirectory
21 from IPython.utils.tempdir import TemporaryDirectory
22 from IPython.core.history import HistoryManager, extract_hist_ranges
22 from IPython.core.history import HistoryManager, extract_hist_ranges
23 from IPython.utils import py3compat
23 from IPython.utils import py3compat
24
24
25 def setUp():
25 def setUp():
26 nt.assert_equal(sys.getdefaultencoding(), "utf-8" if py3compat.PY3 else "ascii")
26 nt.assert_equal(sys.getdefaultencoding(), "utf-8" if py3compat.PY3 else "ascii")
27
27
28 def test_history():
28 def test_history():
29 ip = get_ipython()
29 ip = get_ipython()
30 with TemporaryDirectory() as tmpdir:
30 with TemporaryDirectory() as tmpdir:
31 hist_manager_ori = ip.history_manager
31 hist_manager_ori = ip.history_manager
32 hist_file = os.path.join(tmpdir, 'history.sqlite')
32 hist_file = os.path.join(tmpdir, 'history.sqlite')
33 try:
33 try:
34 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
34 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
35 hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='β‚¬Γ†ΒΎΓ·ΓŸ'"]
35 hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='β‚¬Γ†ΒΎΓ·ΓŸ'"]
36 for i, h in enumerate(hist, start=1):
36 for i, h in enumerate(hist, start=1):
37 ip.history_manager.store_inputs(i, h)
37 ip.history_manager.store_inputs(i, h)
38
38
39 ip.history_manager.db_log_output = True
39 ip.history_manager.db_log_output = True
40 # Doesn't match the input, but we'll just check it's stored.
40 # Doesn't match the input, but we'll just check it's stored.
41 ip.history_manager.output_hist_reprs[3] = "spam"
41 ip.history_manager.output_hist_reprs[3] = "spam"
42 ip.history_manager.store_output(3)
42 ip.history_manager.store_output(3)
43
43
44 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
44 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
45
45
46 # Detailed tests for _get_range_session
46 # Detailed tests for _get_range_session
47 grs = ip.history_manager._get_range_session
47 grs = ip.history_manager._get_range_session
48 nt.assert_equal(list(grs(start=2,stop=-1)), zip([0], [2], hist[1:-1]))
48 nt.assert_equal(list(grs(start=2,stop=-1)), zip([0], [2], hist[1:-1]))
49 nt.assert_equal(list(grs(start=-2)), zip([0,0], [2,3], hist[-2:]))
49 nt.assert_equal(list(grs(start=-2)), zip([0,0], [2,3], hist[-2:]))
50 nt.assert_equal(list(grs(output=True)), zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam'])))
50 nt.assert_equal(list(grs(output=True)), zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam'])))
51
51
52 # Check whether specifying a range beyond the end of the current
52 # Check whether specifying a range beyond the end of the current
53 # session results in an error (gh-804)
53 # session results in an error (gh-804)
54 ip.magic('%hist 2-500')
54 ip.magic('%hist 2-500')
55
55
56 # Check that we can write non-ascii characters to a file
56 # Check that we can write non-ascii characters to a file
57 ip.magic("%%hist -f %s" % os.path.join(tmpdir, "test1"))
57 ip.magic("%%hist -f %s" % os.path.join(tmpdir, "test1"))
58 ip.magic("%%hist -pf %s" % os.path.join(tmpdir, "test2"))
58 ip.magic("%%hist -pf %s" % os.path.join(tmpdir, "test2"))
59 ip.magic("%%hist -nf %s" % os.path.join(tmpdir, "test3"))
59 ip.magic("%%hist -nf %s" % os.path.join(tmpdir, "test3"))
60 ip.magic("%%save %s 1-10" % os.path.join(tmpdir, "test4"))
60 ip.magic("%%save %s 1-10" % os.path.join(tmpdir, "test4"))
61
61
62 # New session
62 # New session
63 ip.history_manager.reset()
63 ip.history_manager.reset()
64 newcmds = ["z=5","class X(object):\n pass", "k='p'"]
64 newcmds = ["z=5","class X(object):\n pass", "k='p'"]
65 for i, cmd in enumerate(newcmds, start=1):
65 for i, cmd in enumerate(newcmds, start=1):
66 ip.history_manager.store_inputs(i, cmd)
66 ip.history_manager.store_inputs(i, cmd)
67 gothist = ip.history_manager.get_range(start=1, stop=4)
67 gothist = ip.history_manager.get_range(start=1, stop=4)
68 nt.assert_equal(list(gothist), zip([0,0,0],[1,2,3], newcmds))
68 nt.assert_equal(list(gothist), zip([0,0,0],[1,2,3], newcmds))
69 # Previous session:
69 # Previous session:
70 gothist = ip.history_manager.get_range(-1, 1, 4)
70 gothist = ip.history_manager.get_range(-1, 1, 4)
71 nt.assert_equal(list(gothist), zip([1,1,1],[1,2,3], hist))
71 nt.assert_equal(list(gothist), zip([1,1,1],[1,2,3], hist))
72
72
73 # Check get_hist_tail
73 # Check get_hist_tail
74 gothist = ip.history_manager.get_tail(4, output=True,
74 gothist = ip.history_manager.get_tail(4, output=True,
75 include_latest=True)
75 include_latest=True)
76 expected = [(1, 3, (hist[-1], "spam")),
76 expected = [(1, 3, (hist[-1], "spam")),
77 (2, 1, (newcmds[0], None)),
77 (2, 1, (newcmds[0], None)),
78 (2, 2, (newcmds[1], None)),
78 (2, 2, (newcmds[1], None)),
79 (2, 3, (newcmds[2], None)),]
79 (2, 3, (newcmds[2], None)),]
80 nt.assert_equal(list(gothist), expected)
80 nt.assert_equal(list(gothist), expected)
81
81
82 gothist = ip.history_manager.get_tail(2)
82 gothist = ip.history_manager.get_tail(2)
83 expected = [(2, 1, newcmds[0]),
83 expected = [(2, 1, newcmds[0]),
84 (2, 2, newcmds[1])]
84 (2, 2, newcmds[1])]
85 nt.assert_equal(list(gothist), expected)
85 nt.assert_equal(list(gothist), expected)
86
86
87 # Check get_hist_search
87 # Check get_hist_search
88 gothist = ip.history_manager.search("*test*")
88 gothist = ip.history_manager.search("*test*")
89 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
89 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
90 gothist = ip.history_manager.search("b*", output=True)
90 gothist = ip.history_manager.search("b*", output=True)
91 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
91 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
92
92
93 # Cross testing: check that magic %save can get previous session.
93 # Cross testing: check that magic %save can get previous session.
94 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
94 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
95 ip.magic("save " + testfilename + " ~1/1-3")
95 ip.magic("save " + testfilename + " ~1/1-3")
96 with py3compat.open(testfilename, encoding='utf-8') as testfile:
96 with py3compat.open(testfilename, encoding='utf-8') as testfile:
97 nt.assert_equal(testfile.read(),
97 nt.assert_equal(testfile.read(),
98 u"# coding: utf-8\n" + u"\n".join(hist))
98 u"# coding: utf-8\n" + u"\n".join(hist)+u"\n")
99
99
100 # Duplicate line numbers - check that it doesn't crash, and
100 # Duplicate line numbers - check that it doesn't crash, and
101 # gets a new session
101 # gets a new session
102 ip.history_manager.store_inputs(1, "rogue")
102 ip.history_manager.store_inputs(1, "rogue")
103 ip.history_manager.writeout_cache()
103 ip.history_manager.writeout_cache()
104 nt.assert_equal(ip.history_manager.session_number, 3)
104 nt.assert_equal(ip.history_manager.session_number, 3)
105 finally:
105 finally:
106 # Restore history manager
106 # Restore history manager
107 ip.history_manager = hist_manager_ori
107 ip.history_manager = hist_manager_ori
108
108
109
109
110 def test_extract_hist_ranges():
110 def test_extract_hist_ranges():
111 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5"
111 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5"
112 expected = [(0, 1, 2), # 0 == current session
112 expected = [(0, 1, 2), # 0 == current session
113 (2, 3, 4),
113 (2, 3, 4),
114 (-4, 5, 7),
114 (-4, 5, 7),
115 (-4, 7, 10),
115 (-4, 7, 10),
116 (-9, 2, None), # None == to end
116 (-9, 2, None), # None == to end
117 (-8, 1, None),
117 (-8, 1, None),
118 (-7, 1, 6)]
118 (-7, 1, 6)]
119 actual = list(extract_hist_ranges(instr))
119 actual = list(extract_hist_ranges(instr))
120 nt.assert_equal(actual, expected)
120 nt.assert_equal(actual, expected)
121
121
122 def test_magic_rerun():
122 def test_magic_rerun():
123 """Simple test for %rerun (no args -> rerun last line)"""
123 """Simple test for %rerun (no args -> rerun last line)"""
124 ip = get_ipython()
124 ip = get_ipython()
125 ip.run_cell("a = 10", store_history=True)
125 ip.run_cell("a = 10", store_history=True)
126 ip.run_cell("a += 1", store_history=True)
126 ip.run_cell("a += 1", store_history=True)
127 nt.assert_equal(ip.user_ns["a"], 11)
127 nt.assert_equal(ip.user_ns["a"], 11)
128 ip.run_cell("%rerun", store_history=True)
128 ip.run_cell("%rerun", store_history=True)
129 nt.assert_equal(ip.user_ns["a"], 12)
129 nt.assert_equal(ip.user_ns["a"], 12)
130
130
131 def test_timestamp_type():
131 def test_timestamp_type():
132 ip = get_ipython()
132 ip = get_ipython()
133 info = ip.history_manager.get_session_info()
133 info = ip.history_manager.get_session_info()
134 nt.assert_true(isinstance(info[1], datetime))
134 nt.assert_true(isinstance(info[1], datetime))
135
135
136 def test_hist_file_config():
136 def test_hist_file_config():
137 cfg = Config()
137 cfg = Config()
138 tfile = tempfile.NamedTemporaryFile(delete=False)
138 tfile = tempfile.NamedTemporaryFile(delete=False)
139 cfg.HistoryManager.hist_file = tfile.name
139 cfg.HistoryManager.hist_file = tfile.name
140 try:
140 try:
141 hm = HistoryManager(shell=get_ipython(), config=cfg)
141 hm = HistoryManager(shell=get_ipython(), config=cfg)
142 nt.assert_equals(hm.hist_file, cfg.HistoryManager.hist_file)
142 nt.assert_equals(hm.hist_file, cfg.HistoryManager.hist_file)
143 finally:
143 finally:
144 try:
144 try:
145 os.remove(tfile.name)
145 os.remove(tfile.name)
146 except OSError:
146 except OSError:
147 # same catch as in testing.tools.TempFileMixin
147 # same catch as in testing.tools.TempFileMixin
148 # On Windows, even though we close the file, we still can't
148 # On Windows, even though we close the file, we still can't
149 # delete it. I have no clue why
149 # delete it. I have no clue why
150 pass
150 pass
151
151
@@ -1,744 +1,764 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from 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
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_equals(opts['f'], expected)
77 nt.assert_equals(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_equals(last_line, "SyntaxError: invalid syntax")
283 nt.assert_equals(last_line, "SyntaxError: invalid syntax")
284
284
285
285
286 @py3compat.doctest_refactor_print
286 @py3compat.doctest_refactor_print
287 def doctest_time():
287 def doctest_time():
288 """
288 """
289 In [10]: %time None
289 In [10]: %time None
290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
291 Wall time: 0.00 s
291 Wall time: 0.00 s
292
292
293 In [11]: def f(kmjy):
293 In [11]: def f(kmjy):
294 ....: %time print 2*kmjy
294 ....: %time print 2*kmjy
295
295
296 In [12]: f(3)
296 In [12]: f(3)
297 6
297 6
298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
299 Wall time: 0.00 s
299 Wall time: 0.00 s
300 """
300 """
301
301
302
302
303 def test_doctest_mode():
303 def test_doctest_mode():
304 "Toggle doctest_mode twice, it should be a no-op and run without error"
304 "Toggle doctest_mode twice, it should be a no-op and run without error"
305 _ip.magic('doctest_mode')
305 _ip.magic('doctest_mode')
306 _ip.magic('doctest_mode')
306 _ip.magic('doctest_mode')
307
307
308
308
309 def test_parse_options():
309 def test_parse_options():
310 """Tests for basic options parsing in magics."""
310 """Tests for basic options parsing in magics."""
311 # These are only the most minimal of tests, more should be added later. At
311 # These are only the most minimal of tests, more should be added later. At
312 # the very least we check that basic text/unicode calls work OK.
312 # the very least we check that basic text/unicode calls work OK.
313 m = DummyMagics(_ip)
313 m = DummyMagics(_ip)
314 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
314 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
315 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
315 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
316
316
317
317
318 def test_dirops():
318 def test_dirops():
319 """Test various directory handling operations."""
319 """Test various directory handling operations."""
320 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
320 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
321 curpath = os.getcwdu
321 curpath = os.getcwdu
322 startdir = os.getcwdu()
322 startdir = os.getcwdu()
323 ipdir = os.path.realpath(_ip.ipython_dir)
323 ipdir = os.path.realpath(_ip.ipython_dir)
324 try:
324 try:
325 _ip.magic('cd "%s"' % ipdir)
325 _ip.magic('cd "%s"' % ipdir)
326 nt.assert_equal(curpath(), ipdir)
326 nt.assert_equal(curpath(), ipdir)
327 _ip.magic('cd -')
327 _ip.magic('cd -')
328 nt.assert_equal(curpath(), startdir)
328 nt.assert_equal(curpath(), startdir)
329 _ip.magic('pushd "%s"' % ipdir)
329 _ip.magic('pushd "%s"' % ipdir)
330 nt.assert_equal(curpath(), ipdir)
330 nt.assert_equal(curpath(), ipdir)
331 _ip.magic('popd')
331 _ip.magic('popd')
332 nt.assert_equal(curpath(), startdir)
332 nt.assert_equal(curpath(), startdir)
333 finally:
333 finally:
334 os.chdir(startdir)
334 os.chdir(startdir)
335
335
336
336
337 def test_xmode():
337 def test_xmode():
338 # Calling xmode three times should be a no-op
338 # Calling xmode three times should be a no-op
339 xmode = _ip.InteractiveTB.mode
339 xmode = _ip.InteractiveTB.mode
340 for i in range(3):
340 for i in range(3):
341 _ip.magic("xmode")
341 _ip.magic("xmode")
342 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
342 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
343
343
344 def test_reset_hard():
344 def test_reset_hard():
345 monitor = []
345 monitor = []
346 class A(object):
346 class A(object):
347 def __del__(self):
347 def __del__(self):
348 monitor.append(1)
348 monitor.append(1)
349 def __repr__(self):
349 def __repr__(self):
350 return "<A instance>"
350 return "<A instance>"
351
351
352 _ip.user_ns["a"] = A()
352 _ip.user_ns["a"] = A()
353 _ip.run_cell("a")
353 _ip.run_cell("a")
354
354
355 nt.assert_equal(monitor, [])
355 nt.assert_equal(monitor, [])
356 _ip.magic("reset -f")
356 _ip.magic("reset -f")
357 nt.assert_equal(monitor, [1])
357 nt.assert_equal(monitor, [1])
358
358
359 class TestXdel(tt.TempFileMixin):
359 class TestXdel(tt.TempFileMixin):
360 def test_xdel(self):
360 def test_xdel(self):
361 """Test that references from %run are cleared by xdel."""
361 """Test that references from %run are cleared by xdel."""
362 src = ("class A(object):\n"
362 src = ("class A(object):\n"
363 " monitor = []\n"
363 " monitor = []\n"
364 " def __del__(self):\n"
364 " def __del__(self):\n"
365 " self.monitor.append(1)\n"
365 " self.monitor.append(1)\n"
366 "a = A()\n")
366 "a = A()\n")
367 self.mktmp(src)
367 self.mktmp(src)
368 # %run creates some hidden references...
368 # %run creates some hidden references...
369 _ip.magic("run %s" % self.fname)
369 _ip.magic("run %s" % self.fname)
370 # ... as does the displayhook.
370 # ... as does the displayhook.
371 _ip.run_cell("a")
371 _ip.run_cell("a")
372
372
373 monitor = _ip.user_ns["A"].monitor
373 monitor = _ip.user_ns["A"].monitor
374 nt.assert_equal(monitor, [])
374 nt.assert_equal(monitor, [])
375
375
376 _ip.magic("xdel a")
376 _ip.magic("xdel a")
377
377
378 # Check that a's __del__ method has been called.
378 # Check that a's __del__ method has been called.
379 nt.assert_equal(monitor, [1])
379 nt.assert_equal(monitor, [1])
380
380
381 def doctest_who():
381 def doctest_who():
382 """doctest for %who
382 """doctest for %who
383
383
384 In [1]: %reset -f
384 In [1]: %reset -f
385
385
386 In [2]: alpha = 123
386 In [2]: alpha = 123
387
387
388 In [3]: beta = 'beta'
388 In [3]: beta = 'beta'
389
389
390 In [4]: %who int
390 In [4]: %who int
391 alpha
391 alpha
392
392
393 In [5]: %who str
393 In [5]: %who str
394 beta
394 beta
395
395
396 In [6]: %whos
396 In [6]: %whos
397 Variable Type Data/Info
397 Variable Type Data/Info
398 ----------------------------
398 ----------------------------
399 alpha int 123
399 alpha int 123
400 beta str beta
400 beta str beta
401
401
402 In [7]: %who_ls
402 In [7]: %who_ls
403 Out[7]: ['alpha', 'beta']
403 Out[7]: ['alpha', 'beta']
404 """
404 """
405
405
406 def test_whos():
406 def test_whos():
407 """Check that whos is protected against objects where repr() fails."""
407 """Check that whos is protected against objects where repr() fails."""
408 class A(object):
408 class A(object):
409 def __repr__(self):
409 def __repr__(self):
410 raise Exception()
410 raise Exception()
411 _ip.user_ns['a'] = A()
411 _ip.user_ns['a'] = A()
412 _ip.magic("whos")
412 _ip.magic("whos")
413
413
414 @py3compat.u_format
414 @py3compat.u_format
415 def doctest_precision():
415 def doctest_precision():
416 """doctest for %precision
416 """doctest for %precision
417
417
418 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
418 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
419
419
420 In [2]: %precision 5
420 In [2]: %precision 5
421 Out[2]: {u}'%.5f'
421 Out[2]: {u}'%.5f'
422
422
423 In [3]: f.float_format
423 In [3]: f.float_format
424 Out[3]: {u}'%.5f'
424 Out[3]: {u}'%.5f'
425
425
426 In [4]: %precision %e
426 In [4]: %precision %e
427 Out[4]: {u}'%e'
427 Out[4]: {u}'%e'
428
428
429 In [5]: f(3.1415927)
429 In [5]: f(3.1415927)
430 Out[5]: {u}'3.141593e+00'
430 Out[5]: {u}'3.141593e+00'
431 """
431 """
432
432
433 def test_psearch():
433 def test_psearch():
434 with tt.AssertPrints("dict.fromkeys"):
434 with tt.AssertPrints("dict.fromkeys"):
435 _ip.run_cell("dict.fr*?")
435 _ip.run_cell("dict.fr*?")
436
436
437 def test_timeit_shlex():
437 def test_timeit_shlex():
438 """test shlex issues with timeit (#1109)"""
438 """test shlex issues with timeit (#1109)"""
439 _ip.ex("def f(*a,**kw): pass")
439 _ip.ex("def f(*a,**kw): pass")
440 _ip.magic('timeit -n1 "this is a bug".count(" ")')
440 _ip.magic('timeit -n1 "this is a bug".count(" ")')
441 _ip.magic('timeit -r1 -n1 f(" ", 1)')
441 _ip.magic('timeit -r1 -n1 f(" ", 1)')
442 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
442 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
443 _ip.magic('timeit -r1 -n1 ("a " + "b")')
443 _ip.magic('timeit -r1 -n1 ("a " + "b")')
444 _ip.magic('timeit -r1 -n1 f("a " + "b")')
444 _ip.magic('timeit -r1 -n1 f("a " + "b")')
445 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
445 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
446
446
447
447
448 def test_timeit_arguments():
448 def test_timeit_arguments():
449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
450 _ip.magic("timeit ('#')")
450 _ip.magic("timeit ('#')")
451
451
452
452
453 def test_timeit_special_syntax():
453 def test_timeit_special_syntax():
454 "Test %%timeit with IPython special syntax"
454 "Test %%timeit with IPython special syntax"
455 from IPython.core.magic import register_line_magic
455 from IPython.core.magic import register_line_magic
456
456
457 @register_line_magic
457 @register_line_magic
458 def lmagic(line):
458 def lmagic(line):
459 ip = get_ipython()
459 ip = get_ipython()
460 ip.user_ns['lmagic_out'] = line
460 ip.user_ns['lmagic_out'] = line
461
461
462 # line mode test
462 # line mode test
463 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
463 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
464 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
464 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
465 # cell mode test
465 # cell mode test
466 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
466 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
467 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
467 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
468
468
469
469
470 @dec.skipif(execution.profile is None)
470 @dec.skipif(execution.profile is None)
471 def test_prun_quotes():
471 def test_prun_quotes():
472 "Test that prun does not clobber string escapes (GH #1302)"
472 "Test that prun does not clobber string escapes (GH #1302)"
473 _ip.magic(r"prun -q x = '\t'")
473 _ip.magic(r"prun -q x = '\t'")
474 nt.assert_equal(_ip.user_ns['x'], '\t')
474 nt.assert_equal(_ip.user_ns['x'], '\t')
475
475
476 def test_extension():
476 def test_extension():
477 tmpdir = TemporaryDirectory()
477 tmpdir = TemporaryDirectory()
478 orig_ipython_dir = _ip.ipython_dir
478 orig_ipython_dir = _ip.ipython_dir
479 try:
479 try:
480 _ip.ipython_dir = tmpdir.name
480 _ip.ipython_dir = tmpdir.name
481 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
481 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
482 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
482 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
483 _ip.magic("install_ext %s" % url)
483 _ip.magic("install_ext %s" % url)
484 _ip.user_ns.pop('arq', None)
484 _ip.user_ns.pop('arq', None)
485 invalidate_caches() # Clear import caches
485 invalidate_caches() # Clear import caches
486 _ip.magic("load_ext daft_extension")
486 _ip.magic("load_ext daft_extension")
487 tt.assert_equal(_ip.user_ns['arq'], 185)
487 tt.assert_equal(_ip.user_ns['arq'], 185)
488 _ip.magic("unload_ext daft_extension")
488 _ip.magic("unload_ext daft_extension")
489 assert 'arq' not in _ip.user_ns
489 assert 'arq' not in _ip.user_ns
490 finally:
490 finally:
491 _ip.ipython_dir = orig_ipython_dir
491 _ip.ipython_dir = orig_ipython_dir
492 tmpdir.cleanup()
492 tmpdir.cleanup()
493
493
494 def test_notebook_export_json():
494 def test_notebook_export_json():
495 with TemporaryDirectory() as td:
495 with TemporaryDirectory() as td:
496 outfile = os.path.join(td, "nb.ipynb")
496 outfile = os.path.join(td, "nb.ipynb")
497 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
497 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
498 _ip.magic("notebook -e %s" % outfile)
498 _ip.magic("notebook -e %s" % outfile)
499
499
500 def test_notebook_export_py():
500 def test_notebook_export_py():
501 with TemporaryDirectory() as td:
501 with TemporaryDirectory() as td:
502 outfile = os.path.join(td, "nb.py")
502 outfile = os.path.join(td, "nb.py")
503 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
503 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
504 _ip.magic("notebook -e %s" % outfile)
504 _ip.magic("notebook -e %s" % outfile)
505
505
506 def test_notebook_reformat_py():
506 def test_notebook_reformat_py():
507 with TemporaryDirectory() as td:
507 with TemporaryDirectory() as td:
508 infile = os.path.join(td, "nb.ipynb")
508 infile = os.path.join(td, "nb.ipynb")
509 with io.open(infile, 'w', encoding='utf-8') as f:
509 with io.open(infile, 'w', encoding='utf-8') as f:
510 current.write(nb0, f, 'json')
510 current.write(nb0, f, 'json')
511
511
512 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
512 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
513 _ip.magic("notebook -f py %s" % infile)
513 _ip.magic("notebook -f py %s" % infile)
514
514
515 def test_notebook_reformat_json():
515 def test_notebook_reformat_json():
516 with TemporaryDirectory() as td:
516 with TemporaryDirectory() as td:
517 infile = os.path.join(td, "nb.py")
517 infile = os.path.join(td, "nb.py")
518 with io.open(infile, 'w', encoding='utf-8') as f:
518 with io.open(infile, 'w', encoding='utf-8') as f:
519 current.write(nb0, f, 'py')
519 current.write(nb0, f, 'py')
520
520
521 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
521 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
522 _ip.magic("notebook -f ipynb %s" % infile)
522 _ip.magic("notebook -f ipynb %s" % infile)
523 _ip.magic("notebook -f json %s" % infile)
523 _ip.magic("notebook -f json %s" % infile)
524
524
525 def test_env():
525 def test_env():
526 env = _ip.magic("env")
526 env = _ip.magic("env")
527 assert isinstance(env, dict), type(env)
527 assert isinstance(env, dict), type(env)
528
528
529
529
530 class CellMagicTestCase(TestCase):
530 class CellMagicTestCase(TestCase):
531
531
532 def check_ident(self, magic):
532 def check_ident(self, magic):
533 # Manually called, we get the result
533 # Manually called, we get the result
534 out = _ip.run_cell_magic(magic, 'a', 'b')
534 out = _ip.run_cell_magic(magic, 'a', 'b')
535 nt.assert_equals(out, ('a','b'))
535 nt.assert_equals(out, ('a','b'))
536 # Via run_cell, it goes into the user's namespace via displayhook
536 # Via run_cell, it goes into the user's namespace via displayhook
537 _ip.run_cell('%%' + magic +' c\nd')
537 _ip.run_cell('%%' + magic +' c\nd')
538 nt.assert_equals(_ip.user_ns['_'], ('c','d'))
538 nt.assert_equals(_ip.user_ns['_'], ('c','d'))
539
539
540 def test_cell_magic_func_deco(self):
540 def test_cell_magic_func_deco(self):
541 "Cell magic using simple decorator"
541 "Cell magic using simple decorator"
542 @register_cell_magic
542 @register_cell_magic
543 def cellm(line, cell):
543 def cellm(line, cell):
544 return line, cell
544 return line, cell
545
545
546 self.check_ident('cellm')
546 self.check_ident('cellm')
547
547
548 def test_cell_magic_reg(self):
548 def test_cell_magic_reg(self):
549 "Cell magic manually registered"
549 "Cell magic manually registered"
550 def cellm(line, cell):
550 def cellm(line, cell):
551 return line, cell
551 return line, cell
552
552
553 _ip.register_magic_function(cellm, 'cell', 'cellm2')
553 _ip.register_magic_function(cellm, 'cell', 'cellm2')
554 self.check_ident('cellm2')
554 self.check_ident('cellm2')
555
555
556 def test_cell_magic_class(self):
556 def test_cell_magic_class(self):
557 "Cell magics declared via a class"
557 "Cell magics declared via a class"
558 @magics_class
558 @magics_class
559 class MyMagics(Magics):
559 class MyMagics(Magics):
560
560
561 @cell_magic
561 @cell_magic
562 def cellm3(self, line, cell):
562 def cellm3(self, line, cell):
563 return line, cell
563 return line, cell
564
564
565 _ip.register_magics(MyMagics)
565 _ip.register_magics(MyMagics)
566 self.check_ident('cellm3')
566 self.check_ident('cellm3')
567
567
568 def test_cell_magic_class2(self):
568 def test_cell_magic_class2(self):
569 "Cell magics declared via a class, #2"
569 "Cell magics declared via a class, #2"
570 @magics_class
570 @magics_class
571 class MyMagics2(Magics):
571 class MyMagics2(Magics):
572
572
573 @cell_magic('cellm4')
573 @cell_magic('cellm4')
574 def cellm33(self, line, cell):
574 def cellm33(self, line, cell):
575 return line, cell
575 return line, cell
576
576
577 _ip.register_magics(MyMagics2)
577 _ip.register_magics(MyMagics2)
578 self.check_ident('cellm4')
578 self.check_ident('cellm4')
579 # Check that nothing is registered as 'cellm33'
579 # Check that nothing is registered as 'cellm33'
580 c33 = _ip.find_cell_magic('cellm33')
580 c33 = _ip.find_cell_magic('cellm33')
581 nt.assert_equals(c33, None)
581 nt.assert_equals(c33, None)
582
582
583 def test_file():
583 def test_file():
584 """Basic %%file"""
584 """Basic %%file"""
585 ip = get_ipython()
585 ip = get_ipython()
586 with TemporaryDirectory() as td:
586 with TemporaryDirectory() as td:
587 fname = os.path.join(td, 'file1')
587 fname = os.path.join(td, 'file1')
588 ip.run_cell_magic("file", fname, u'\n'.join([
588 ip.run_cell_magic("file", fname, u'\n'.join([
589 'line1',
589 'line1',
590 'line2',
590 'line2',
591 ]))
591 ]))
592 with open(fname) as f:
592 with open(fname) as f:
593 s = f.read()
593 s = f.read()
594 nt.assert_in('line1\n', s)
594 nt.assert_in('line1\n', s)
595 nt.assert_in('line2', s)
595 nt.assert_in('line2', s)
596
596
597 def test_file_unicode():
597 def test_file_unicode():
598 """%%file with unicode cell"""
598 """%%file with unicode cell"""
599 ip = get_ipython()
599 ip = get_ipython()
600 with TemporaryDirectory() as td:
600 with TemporaryDirectory() as td:
601 fname = os.path.join(td, 'file1')
601 fname = os.path.join(td, 'file1')
602 ip.run_cell_magic("file", fname, u'\n'.join([
602 ip.run_cell_magic("file", fname, u'\n'.join([
603 u'linΓ©1',
603 u'linΓ©1',
604 u'linΓ©2',
604 u'linΓ©2',
605 ]))
605 ]))
606 with io.open(fname, encoding='utf-8') as f:
606 with io.open(fname, encoding='utf-8') as f:
607 s = f.read()
607 s = f.read()
608 nt.assert_in(u'linΓ©1\n', s)
608 nt.assert_in(u'linΓ©1\n', s)
609 nt.assert_in(u'linΓ©2', s)
609 nt.assert_in(u'linΓ©2', s)
610
610
611 def test_file_amend():
611 def test_file_amend():
612 """%%file -a amends files"""
612 """%%file -a amends files"""
613 ip = get_ipython()
613 ip = get_ipython()
614 with TemporaryDirectory() as td:
614 with TemporaryDirectory() as td:
615 fname = os.path.join(td, 'file2')
615 fname = os.path.join(td, 'file2')
616 ip.run_cell_magic("file", fname, u'\n'.join([
616 ip.run_cell_magic("file", fname, u'\n'.join([
617 'line1',
617 'line1',
618 'line2',
618 'line2',
619 ]))
619 ]))
620 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
620 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
621 'line3',
621 'line3',
622 'line4',
622 'line4',
623 ]))
623 ]))
624 with open(fname) as f:
624 with open(fname) as f:
625 s = f.read()
625 s = f.read()
626 nt.assert_in('line1\n', s)
626 nt.assert_in('line1\n', s)
627 nt.assert_in('line3\n', s)
627 nt.assert_in('line3\n', s)
628
628
629
629
630 def test_script_config():
630 def test_script_config():
631 ip = get_ipython()
631 ip = get_ipython()
632 ip.config.ScriptMagics.script_magics = ['whoda']
632 ip.config.ScriptMagics.script_magics = ['whoda']
633 sm = script.ScriptMagics(shell=ip)
633 sm = script.ScriptMagics(shell=ip)
634 nt.assert_in('whoda', sm.magics['cell'])
634 nt.assert_in('whoda', sm.magics['cell'])
635
635
636 @dec.skip_win32
636 @dec.skip_win32
637 def test_script_out():
637 def test_script_out():
638 ip = get_ipython()
638 ip = get_ipython()
639 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
639 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
640 nt.assert_equals(ip.user_ns['output'], 'hi\n')
640 nt.assert_equals(ip.user_ns['output'], 'hi\n')
641
641
642 @dec.skip_win32
642 @dec.skip_win32
643 def test_script_err():
643 def test_script_err():
644 ip = get_ipython()
644 ip = get_ipython()
645 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
645 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
646 nt.assert_equals(ip.user_ns['error'], 'hello\n')
646 nt.assert_equals(ip.user_ns['error'], 'hello\n')
647
647
648 @dec.skip_win32
648 @dec.skip_win32
649 def test_script_out_err():
649 def test_script_out_err():
650 ip = get_ipython()
650 ip = get_ipython()
651 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
651 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
652 nt.assert_equals(ip.user_ns['output'], 'hi\n')
652 nt.assert_equals(ip.user_ns['output'], 'hi\n')
653 nt.assert_equals(ip.user_ns['error'], 'hello\n')
653 nt.assert_equals(ip.user_ns['error'], 'hello\n')
654
654
655 @dec.skip_win32
655 @dec.skip_win32
656 def test_script_bg_out():
656 def test_script_bg_out():
657 ip = get_ipython()
657 ip = get_ipython()
658 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
658 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
659 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
659 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
660
660
661 @dec.skip_win32
661 @dec.skip_win32
662 def test_script_bg_err():
662 def test_script_bg_err():
663 ip = get_ipython()
663 ip = get_ipython()
664 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
664 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
665 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
665 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
666
666
667 @dec.skip_win32
667 @dec.skip_win32
668 def test_script_bg_out_err():
668 def test_script_bg_out_err():
669 ip = get_ipython()
669 ip = get_ipython()
670 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
670 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
671 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
671 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
672 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
672 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
673
673
674 def test_script_defaults():
674 def test_script_defaults():
675 ip = get_ipython()
675 ip = get_ipython()
676 for cmd in ['sh', 'bash', 'perl', 'ruby']:
676 for cmd in ['sh', 'bash', 'perl', 'ruby']:
677 try:
677 try:
678 find_cmd(cmd)
678 find_cmd(cmd)
679 except Exception:
679 except Exception:
680 pass
680 pass
681 else:
681 else:
682 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
682 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
683
683
684
684
685 @magics_class
685 @magics_class
686 class FooFoo(Magics):
686 class FooFoo(Magics):
687 """class with both %foo and %%foo magics"""
687 """class with both %foo and %%foo magics"""
688 @line_magic('foo')
688 @line_magic('foo')
689 def line_foo(self, line):
689 def line_foo(self, line):
690 "I am line foo"
690 "I am line foo"
691 pass
691 pass
692
692
693 @cell_magic("foo")
693 @cell_magic("foo")
694 def cell_foo(self, line, cell):
694 def cell_foo(self, line, cell):
695 "I am cell foo, not line foo"
695 "I am cell foo, not line foo"
696 pass
696 pass
697
697
698 def test_line_cell_info():
698 def test_line_cell_info():
699 """%%foo and %foo magics are distinguishable to inspect"""
699 """%%foo and %foo magics are distinguishable to inspect"""
700 ip = get_ipython()
700 ip = get_ipython()
701 ip.magics_manager.register(FooFoo)
701 ip.magics_manager.register(FooFoo)
702 oinfo = ip.object_inspect('foo')
702 oinfo = ip.object_inspect('foo')
703 nt.assert_true(oinfo['found'])
703 nt.assert_true(oinfo['found'])
704 nt.assert_true(oinfo['ismagic'])
704 nt.assert_true(oinfo['ismagic'])
705
705
706 oinfo = ip.object_inspect('%%foo')
706 oinfo = ip.object_inspect('%%foo')
707 nt.assert_true(oinfo['found'])
707 nt.assert_true(oinfo['found'])
708 nt.assert_true(oinfo['ismagic'])
708 nt.assert_true(oinfo['ismagic'])
709 nt.assert_equals(oinfo['docstring'], FooFoo.cell_foo.__doc__)
709 nt.assert_equals(oinfo['docstring'], FooFoo.cell_foo.__doc__)
710
710
711 oinfo = ip.object_inspect('%foo')
711 oinfo = ip.object_inspect('%foo')
712 nt.assert_true(oinfo['found'])
712 nt.assert_true(oinfo['found'])
713 nt.assert_true(oinfo['ismagic'])
713 nt.assert_true(oinfo['ismagic'])
714 nt.assert_equals(oinfo['docstring'], FooFoo.line_foo.__doc__)
714 nt.assert_equals(oinfo['docstring'], FooFoo.line_foo.__doc__)
715
715
716 def test_multiple_magics():
716 def test_multiple_magics():
717 ip = get_ipython()
717 ip = get_ipython()
718 foo1 = FooFoo(ip)
718 foo1 = FooFoo(ip)
719 foo2 = FooFoo(ip)
719 foo2 = FooFoo(ip)
720 mm = ip.magics_manager
720 mm = ip.magics_manager
721 mm.register(foo1)
721 mm.register(foo1)
722 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
722 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
723 mm.register(foo2)
723 mm.register(foo2)
724 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
724 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
725
725
726 def test_alias_magic():
726 def test_alias_magic():
727 """Test %alias_magic."""
727 """Test %alias_magic."""
728 ip = get_ipython()
728 ip = get_ipython()
729 mm = ip.magics_manager
729 mm = ip.magics_manager
730
730
731 # Basic operation: both cell and line magics are created, if possible.
731 # Basic operation: both cell and line magics are created, if possible.
732 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
732 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
733 nt.assert_true('timeit_alias' in mm.magics['line'])
733 nt.assert_true('timeit_alias' in mm.magics['line'])
734 nt.assert_true('timeit_alias' in mm.magics['cell'])
734 nt.assert_true('timeit_alias' in mm.magics['cell'])
735
735
736 # --cell is specified, line magic not created.
736 # --cell is specified, line magic not created.
737 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
737 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
738 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
738 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
739 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
739 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
740
740
741 # Test that line alias is created successfully.
741 # Test that line alias is created successfully.
742 ip.run_line_magic('alias_magic', '--line env_alias env')
742 ip.run_line_magic('alias_magic', '--line env_alias env')
743 nt.assert_equal(ip.run_line_magic('env', ''),
743 nt.assert_equal(ip.run_line_magic('env', ''),
744 ip.run_line_magic('env_alias', ''))
744 ip.run_line_magic('env_alias', ''))
745
746 def test_save():
747 """Test %save."""
748 ip = get_ipython()
749 ip.history_manager.reset() # Clear any existing history.
750 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
751 for i, cmd in enumerate(cmds, start=1):
752 ip.history_manager.store_inputs(i, cmd)
753 with TemporaryDirectory() as tmpdir:
754 file = os.path.join(tmpdir, "testsave.py")
755 ip.run_line_magic("save", "%s 1-10" % file)
756 with open(file) as f:
757 content = f.read()
758 nt.assert_equal(content.count(cmds[0]), 1)
759 nt.assert_true('coding: utf-8' in content)
760 ip.run_line_magic("save", "-a %s 1-10" % file)
761 with open(file) as f:
762 content = f.read()
763 nt.assert_equal(content.count(cmds[0]), 2)
764 nt.assert_true('coding: utf-8' in content)
General Comments 0
You need to be logged in to leave comments. Login now