##// END OF EJS Templates
Merge pull request #4295 from mgaitan/1093_boundary_load_magic...
Min RK -
r12838:9bfd8553 merge
parent child Browse files
Show More
@@ -1,559 +1,614 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 os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 from itertools import chain
21
22
22 # Our own packages
23 # Our own packages
23 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
24 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
24 from IPython.core.macro import Macro
25 from IPython.core.macro import Macro
25 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.oinspect import find_file, find_source_lines
27 from IPython.core.oinspect import find_file, find_source_lines
27 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.utils import py3compat
29 from IPython.utils import py3compat
29 from IPython.utils.contexts import preserve_keys
30 from IPython.utils.contexts import preserve_keys
30 from IPython.utils.path import get_py_filename, unquote_filename
31 from IPython.utils.path import get_py_filename, unquote_filename
31 from IPython.utils.warn import warn
32 from IPython.utils.warn import warn
32
33
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34 # Magic implementation classes
35 # Magic implementation classes
35 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
36
37
37 # Used for exception handling in magic_edit
38 # Used for exception handling in magic_edit
38 class MacroToEdit(ValueError): pass
39 class MacroToEdit(ValueError): pass
39
40
40 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
41 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
41
42
43 # To match, e.g. 8-10 1:5 :10 3-
44 range_re = re.compile(r"""
45 (?P<start>\d+)?
46 ((?P<sep>[\-:])
47 (?P<end>\d+)?)?
48 $""", re.VERBOSE)
49
50
51 def extract_code_ranges(ranges_str):
52 """Turn a string of range for %%load into 2-tuples of (start, stop)
53 ready to use as a slice of the content splitted by lines.
54
55 Examples
56 --------
57 list(extract_input_ranges("5-10 2"))
58 [(4, 10), (1, 2)]
59 """
60 for range_str in ranges_str.split():
61 rmatch = range_re.match(range_str)
62 if not rmatch:
63 continue
64 sep = rmatch.group("sep")
65 start = rmatch.group("start")
66 end = rmatch.group("end")
67
68 if sep == '-':
69 start = int(start) - 1 if start else None
70 end = int(end) if end else None
71 elif sep == ':':
72 start = int(start) - 1 if start else None
73 end = int(end) - 1 if end else None
74 else:
75 end = int(start)
76 start = int(start) - 1
77 yield (start, end)
78
79
42 class InteractivelyDefined(Exception):
80 class InteractivelyDefined(Exception):
43 """Exception for interactively defined variable in magic_edit"""
81 """Exception for interactively defined variable in magic_edit"""
44 def __init__(self, index):
82 def __init__(self, index):
45 self.index = index
83 self.index = index
46
84
47
85
48 @magics_class
86 @magics_class
49 class CodeMagics(Magics):
87 class CodeMagics(Magics):
50 """Magics related to code management (loading, saving, editing, ...)."""
88 """Magics related to code management (loading, saving, editing, ...)."""
51
89
52 @line_magic
90 @line_magic
53 def save(self, parameter_s=''):
91 def save(self, parameter_s=''):
54 """Save a set of lines or a macro to a given filename.
92 """Save a set of lines or a macro to a given filename.
55
93
56 Usage:\\
94 Usage:\\
57 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
95 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
58
96
59 Options:
97 Options:
60
98
61 -r: use 'raw' input. By default, the 'processed' history is used,
99 -r: use 'raw' input. By default, the 'processed' history is used,
62 so that magics are loaded in their transformed version to valid
100 so that magics are loaded in their transformed version to valid
63 Python. If this option is given, the raw input as typed as the
101 Python. If this option is given, the raw input as typed as the
64 command line is used instead.
102 command line is used instead.
65
103
66 -f: force overwrite. If file exists, %save will prompt for overwrite
104 -f: force overwrite. If file exists, %save will prompt for overwrite
67 unless -f is given.
105 unless -f is given.
68
106
69 -a: append to the file instead of overwriting it.
107 -a: append to the file instead of overwriting it.
70
108
71 This function uses the same syntax as %history for input ranges,
109 This function uses the same syntax as %history for input ranges,
72 then saves the lines to the filename you specify.
110 then saves the lines to the filename you specify.
73
111
74 It adds a '.py' extension to the file if you don't do so yourself, and
112 It adds a '.py' extension to the file if you don't do so yourself, and
75 it asks for confirmation before overwriting existing files.
113 it asks for confirmation before overwriting existing files.
76
114
77 If `-r` option is used, the default extension is `.ipy`.
115 If `-r` option is used, the default extension is `.ipy`.
78 """
116 """
79
117
80 opts,args = self.parse_options(parameter_s,'fra',mode='list')
118 opts,args = self.parse_options(parameter_s,'fra',mode='list')
81 if not args:
119 if not args:
82 raise UsageError('Missing filename.')
120 raise UsageError('Missing filename.')
83 raw = 'r' in opts
121 raw = 'r' in opts
84 force = 'f' in opts
122 force = 'f' in opts
85 append = 'a' in opts
123 append = 'a' in opts
86 mode = 'a' if append else 'w'
124 mode = 'a' if append else 'w'
87 ext = u'.ipy' if raw else u'.py'
125 ext = u'.ipy' if raw else u'.py'
88 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
126 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
89 if not fname.endswith((u'.py',u'.ipy')):
127 if not fname.endswith((u'.py',u'.ipy')):
90 fname += ext
128 fname += ext
91 file_exists = os.path.isfile(fname)
129 file_exists = os.path.isfile(fname)
92 if file_exists and not force and not append:
130 if file_exists and not force and not append:
93 try:
131 try:
94 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
132 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
95 except StdinNotImplementedError:
133 except StdinNotImplementedError:
96 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
134 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
97 return
135 return
98 if not overwrite :
136 if not overwrite :
99 print 'Operation cancelled.'
137 print 'Operation cancelled.'
100 return
138 return
101 try:
139 try:
102 cmds = self.shell.find_user_code(codefrom,raw)
140 cmds = self.shell.find_user_code(codefrom,raw)
103 except (TypeError, ValueError) as e:
141 except (TypeError, ValueError) as e:
104 print e.args[0]
142 print e.args[0]
105 return
143 return
106 out = py3compat.cast_unicode(cmds)
144 out = py3compat.cast_unicode(cmds)
107 with io.open(fname, mode, encoding="utf-8") as f:
145 with io.open(fname, mode, encoding="utf-8") as f:
108 if not file_exists or not append:
146 if not file_exists or not append:
109 f.write(u"# coding: utf-8\n")
147 f.write(u"# coding: utf-8\n")
110 f.write(out)
148 f.write(out)
111 # make sure we end on a newline
149 # make sure we end on a newline
112 if not out.endswith(u'\n'):
150 if not out.endswith(u'\n'):
113 f.write(u'\n')
151 f.write(u'\n')
114 print 'The following commands were written to file `%s`:' % fname
152 print 'The following commands were written to file `%s`:' % fname
115 print cmds
153 print cmds
116
154
117 @line_magic
155 @line_magic
118 def pastebin(self, parameter_s=''):
156 def pastebin(self, parameter_s=''):
119 """Upload code to Github's Gist paste bin, returning the URL.
157 """Upload code to Github's Gist paste bin, returning the URL.
120
158
121 Usage:\\
159 Usage:\\
122 %pastebin [-d "Custom description"] 1-7
160 %pastebin [-d "Custom description"] 1-7
123
161
124 The argument can be an input history range, a filename, or the name of a
162 The argument can be an input history range, a filename, or the name of a
125 string or macro.
163 string or macro.
126
164
127 Options:
165 Options:
128
166
129 -d: Pass a custom description for the gist. The default will say
167 -d: Pass a custom description for the gist. The default will say
130 "Pasted from IPython".
168 "Pasted from IPython".
131 """
169 """
132 opts, args = self.parse_options(parameter_s, 'd:')
170 opts, args = self.parse_options(parameter_s, 'd:')
133
171
134 try:
172 try:
135 code = self.shell.find_user_code(args)
173 code = self.shell.find_user_code(args)
136 except (ValueError, TypeError) as e:
174 except (ValueError, TypeError) as e:
137 print e.args[0]
175 print e.args[0]
138 return
176 return
139
177
140 from urllib2 import urlopen # Deferred import
178 from urllib2 import urlopen # Deferred import
141 import json
179 import json
142 post_data = json.dumps({
180 post_data = json.dumps({
143 "description": opts.get('d', "Pasted from IPython"),
181 "description": opts.get('d', "Pasted from IPython"),
144 "public": True,
182 "public": True,
145 "files": {
183 "files": {
146 "file1.py": {
184 "file1.py": {
147 "content": code
185 "content": code
148 }
186 }
149 }
187 }
150 }).encode('utf-8')
188 }).encode('utf-8')
151
189
152 response = urlopen("https://api.github.com/gists", post_data)
190 response = urlopen("https://api.github.com/gists", post_data)
153 response_data = json.loads(response.read().decode('utf-8'))
191 response_data = json.loads(response.read().decode('utf-8'))
154 return response_data['html_url']
192 return response_data['html_url']
155
193
156 @line_magic
194 @line_magic
157 def loadpy(self, arg_s):
195 def loadpy(self, arg_s):
158 """Alias of `%load`
196 """Alias of `%load`
159
197
160 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
198 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
161 extension. So it has been renamed simply into %load. You can look at
199 extension. So it has been renamed simply into %load. You can look at
162 `%load`'s docstring for more info.
200 `%load`'s docstring for more info.
163 """
201 """
164 self.load(arg_s)
202 self.load(arg_s)
165
203
166 @line_magic
204 @line_magic
167 def load(self, arg_s):
205 def load(self, arg_s):
168 """Load code into the current frontend.
206 """Load code into the current frontend.
169
207
170 Usage:\\
208 Usage:\\
171 %load [options] source
209 %load [options] source
172
210
173 where source can be a filename, URL, input history range or macro
211 where source can be a filename, URL, input history range or macro
174
212
175 Options:
213 Options:
176 --------
214 --------
215 -r <lines>: Specify lines or ranges of lines to load from the source.
216 Ranges could be specified as x-y (x..y) or in python-style x:y
217 (x..(y-1)). Both limits x and y can be left blank (meaning the
218 beginning and end of the file, respectively).
219
177 -y : Don't ask confirmation for loading source above 200 000 characters.
220 -y : Don't ask confirmation for loading source above 200 000 characters.
178
221
179 This magic command can either take a local filename, a URL, an history
222 This magic command can either take a local filename, a URL, an history
180 range (see %history) or a macro as argument, it will prompt for
223 range (see %history) or a macro as argument, it will prompt for
181 confirmation before loading source with more than 200 000 characters, unless
224 confirmation before loading source with more than 200 000 characters, unless
182 -y flag is passed or if the frontend does not support raw_input::
225 -y flag is passed or if the frontend does not support raw_input::
183
226
184 %load myscript.py
227 %load myscript.py
185 %load 7-27
228 %load 7-27
186 %load myMacro
229 %load myMacro
187 %load http://www.example.com/myscript.py
230 %load http://www.example.com/myscript.py
231 %load -r 5-10 myscript.py
232 %load -r 10-20,30,40: foo.py
188 """
233 """
189 opts,args = self.parse_options(arg_s,'y')
234 opts,args = self.parse_options(arg_s,'yr:')
235
190 if not args:
236 if not args:
191 raise UsageError('Missing filename, URL, input history range, '
237 raise UsageError('Missing filename, URL, input history range, '
192 'or macro.')
238 'or macro.')
193
239
194 contents = self.shell.find_user_code(args)
240 contents = self.shell.find_user_code(args)
241
242 if 'r' in opts:
243 ranges = opts['r'].replace(',', ' ')
244 lines = contents.split('\n')
245 slices = extract_code_ranges(ranges)
246 contents = [lines[slice(*slc)] for slc in slices]
247 contents = '\n'.join(chain.from_iterable(contents))
248
195 l = len(contents)
249 l = len(contents)
196
250
251
197 # 200 000 is ~ 2500 full 80 caracter lines
252 # 200 000 is ~ 2500 full 80 caracter lines
198 # so in average, more than 5000 lines
253 # so in average, more than 5000 lines
199 if l > 200000 and 'y' not in opts:
254 if l > 200000 and 'y' not in opts:
200 try:
255 try:
201 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
256 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
202 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
257 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
203 except StdinNotImplementedError:
258 except StdinNotImplementedError:
204 #asume yes if raw input not implemented
259 #asume yes if raw input not implemented
205 ans = True
260 ans = True
206
261
207 if ans is False :
262 if ans is False :
208 print 'Operation cancelled.'
263 print 'Operation cancelled.'
209 return
264 return
210
265
211 self.shell.set_next_input(contents)
266 self.shell.set_next_input(contents)
212
267
213 @staticmethod
268 @staticmethod
214 def _find_edit_target(shell, args, opts, last_call):
269 def _find_edit_target(shell, args, opts, last_call):
215 """Utility method used by magic_edit to find what to edit."""
270 """Utility method used by magic_edit to find what to edit."""
216
271
217 def make_filename(arg):
272 def make_filename(arg):
218 "Make a filename from the given args"
273 "Make a filename from the given args"
219 arg = unquote_filename(arg)
274 arg = unquote_filename(arg)
220 try:
275 try:
221 filename = get_py_filename(arg)
276 filename = get_py_filename(arg)
222 except IOError:
277 except IOError:
223 # If it ends with .py but doesn't already exist, assume we want
278 # If it ends with .py but doesn't already exist, assume we want
224 # a new file.
279 # a new file.
225 if arg.endswith('.py'):
280 if arg.endswith('.py'):
226 filename = arg
281 filename = arg
227 else:
282 else:
228 filename = None
283 filename = None
229 return filename
284 return filename
230
285
231 # Set a few locals from the options for convenience:
286 # Set a few locals from the options for convenience:
232 opts_prev = 'p' in opts
287 opts_prev = 'p' in opts
233 opts_raw = 'r' in opts
288 opts_raw = 'r' in opts
234
289
235 # custom exceptions
290 # custom exceptions
236 class DataIsObject(Exception): pass
291 class DataIsObject(Exception): pass
237
292
238 # Default line number value
293 # Default line number value
239 lineno = opts.get('n',None)
294 lineno = opts.get('n',None)
240
295
241 if opts_prev:
296 if opts_prev:
242 args = '_%s' % last_call[0]
297 args = '_%s' % last_call[0]
243 if args not in shell.user_ns:
298 if args not in shell.user_ns:
244 args = last_call[1]
299 args = last_call[1]
245
300
246 # by default this is done with temp files, except when the given
301 # by default this is done with temp files, except when the given
247 # arg is a filename
302 # arg is a filename
248 use_temp = True
303 use_temp = True
249
304
250 data = ''
305 data = ''
251
306
252 # First, see if the arguments should be a filename.
307 # First, see if the arguments should be a filename.
253 filename = make_filename(args)
308 filename = make_filename(args)
254 if filename:
309 if filename:
255 use_temp = False
310 use_temp = False
256 elif args:
311 elif args:
257 # Mode where user specifies ranges of lines, like in %macro.
312 # Mode where user specifies ranges of lines, like in %macro.
258 data = shell.extract_input_lines(args, opts_raw)
313 data = shell.extract_input_lines(args, opts_raw)
259 if not data:
314 if not data:
260 try:
315 try:
261 # Load the parameter given as a variable. If not a string,
316 # Load the parameter given as a variable. If not a string,
262 # process it as an object instead (below)
317 # process it as an object instead (below)
263
318
264 #print '*** args',args,'type',type(args) # dbg
319 #print '*** args',args,'type',type(args) # dbg
265 data = eval(args, shell.user_ns)
320 data = eval(args, shell.user_ns)
266 if not isinstance(data, basestring):
321 if not isinstance(data, basestring):
267 raise DataIsObject
322 raise DataIsObject
268
323
269 except (NameError,SyntaxError):
324 except (NameError,SyntaxError):
270 # given argument is not a variable, try as a filename
325 # given argument is not a variable, try as a filename
271 filename = make_filename(args)
326 filename = make_filename(args)
272 if filename is None:
327 if filename is None:
273 warn("Argument given (%s) can't be found as a variable "
328 warn("Argument given (%s) can't be found as a variable "
274 "or as a filename." % args)
329 "or as a filename." % args)
275 return (None, None, None)
330 return (None, None, None)
276 use_temp = False
331 use_temp = False
277
332
278 except DataIsObject:
333 except DataIsObject:
279 # macros have a special edit function
334 # macros have a special edit function
280 if isinstance(data, Macro):
335 if isinstance(data, Macro):
281 raise MacroToEdit(data)
336 raise MacroToEdit(data)
282
337
283 # For objects, try to edit the file where they are defined
338 # For objects, try to edit the file where they are defined
284 filename = find_file(data)
339 filename = find_file(data)
285 if filename:
340 if filename:
286 if 'fakemodule' in filename.lower() and \
341 if 'fakemodule' in filename.lower() and \
287 inspect.isclass(data):
342 inspect.isclass(data):
288 # class created by %edit? Try to find source
343 # class created by %edit? Try to find source
289 # by looking for method definitions instead, the
344 # by looking for method definitions instead, the
290 # __module__ in those classes is FakeModule.
345 # __module__ in those classes is FakeModule.
291 attrs = [getattr(data, aname) for aname in dir(data)]
346 attrs = [getattr(data, aname) for aname in dir(data)]
292 for attr in attrs:
347 for attr in attrs:
293 if not inspect.ismethod(attr):
348 if not inspect.ismethod(attr):
294 continue
349 continue
295 filename = find_file(attr)
350 filename = find_file(attr)
296 if filename and \
351 if filename and \
297 'fakemodule' not in filename.lower():
352 'fakemodule' not in filename.lower():
298 # change the attribute to be the edit
353 # change the attribute to be the edit
299 # target instead
354 # target instead
300 data = attr
355 data = attr
301 break
356 break
302
357
303 m = ipython_input_pat.match(os.path.basename(filename))
358 m = ipython_input_pat.match(os.path.basename(filename))
304 if m:
359 if m:
305 raise InteractivelyDefined(int(m.groups()[0]))
360 raise InteractivelyDefined(int(m.groups()[0]))
306
361
307 datafile = 1
362 datafile = 1
308 if filename is None:
363 if filename is None:
309 filename = make_filename(args)
364 filename = make_filename(args)
310 datafile = 1
365 datafile = 1
311 if filename is not None:
366 if filename is not None:
312 # only warn about this if we get a real name
367 # only warn about this if we get a real name
313 warn('Could not find file where `%s` is defined.\n'
368 warn('Could not find file where `%s` is defined.\n'
314 'Opening a file named `%s`' % (args, filename))
369 'Opening a file named `%s`' % (args, filename))
315 # Now, make sure we can actually read the source (if it was
370 # Now, make sure we can actually read the source (if it was
316 # in a temp file it's gone by now).
371 # in a temp file it's gone by now).
317 if datafile:
372 if datafile:
318 if lineno is None:
373 if lineno is None:
319 lineno = find_source_lines(data)
374 lineno = find_source_lines(data)
320 if lineno is None:
375 if lineno is None:
321 filename = make_filename(args)
376 filename = make_filename(args)
322 if filename is None:
377 if filename is None:
323 warn('The file where `%s` was defined '
378 warn('The file where `%s` was defined '
324 'cannot be read or found.' % data)
379 'cannot be read or found.' % data)
325 return (None, None, None)
380 return (None, None, None)
326 use_temp = False
381 use_temp = False
327
382
328 if use_temp:
383 if use_temp:
329 filename = shell.mktempfile(data)
384 filename = shell.mktempfile(data)
330 print 'IPython will make a temporary file named:',filename
385 print 'IPython will make a temporary file named:',filename
331
386
332 # use last_call to remember the state of the previous call, but don't
387 # use last_call to remember the state of the previous call, but don't
333 # let it be clobbered by successive '-p' calls.
388 # let it be clobbered by successive '-p' calls.
334 try:
389 try:
335 last_call[0] = shell.displayhook.prompt_count
390 last_call[0] = shell.displayhook.prompt_count
336 if not opts_prev:
391 if not opts_prev:
337 last_call[1] = args
392 last_call[1] = args
338 except:
393 except:
339 pass
394 pass
340
395
341
396
342 return filename, lineno, use_temp
397 return filename, lineno, use_temp
343
398
344 def _edit_macro(self,mname,macro):
399 def _edit_macro(self,mname,macro):
345 """open an editor with the macro data in a file"""
400 """open an editor with the macro data in a file"""
346 filename = self.shell.mktempfile(macro.value)
401 filename = self.shell.mktempfile(macro.value)
347 self.shell.hooks.editor(filename)
402 self.shell.hooks.editor(filename)
348
403
349 # and make a new macro object, to replace the old one
404 # and make a new macro object, to replace the old one
350 mfile = open(filename)
405 mfile = open(filename)
351 mvalue = mfile.read()
406 mvalue = mfile.read()
352 mfile.close()
407 mfile.close()
353 self.shell.user_ns[mname] = Macro(mvalue)
408 self.shell.user_ns[mname] = Macro(mvalue)
354
409
355 @skip_doctest
410 @skip_doctest
356 @line_magic
411 @line_magic
357 def edit(self, parameter_s='',last_call=['','']):
412 def edit(self, parameter_s='',last_call=['','']):
358 """Bring up an editor and execute the resulting code.
413 """Bring up an editor and execute the resulting code.
359
414
360 Usage:
415 Usage:
361 %edit [options] [args]
416 %edit [options] [args]
362
417
363 %edit runs IPython's editor hook. The default version of this hook is
418 %edit runs IPython's editor hook. The default version of this hook is
364 set to call the editor specified by your $EDITOR environment variable.
419 set to call the editor specified by your $EDITOR environment variable.
365 If this isn't found, it will default to vi under Linux/Unix and to
420 If this isn't found, it will default to vi under Linux/Unix and to
366 notepad under Windows. See the end of this docstring for how to change
421 notepad under Windows. See the end of this docstring for how to change
367 the editor hook.
422 the editor hook.
368
423
369 You can also set the value of this editor via the
424 You can also set the value of this editor via the
370 ``TerminalInteractiveShell.editor`` option in your configuration file.
425 ``TerminalInteractiveShell.editor`` option in your configuration file.
371 This is useful if you wish to use a different editor from your typical
426 This is useful if you wish to use a different editor from your typical
372 default with IPython (and for Windows users who typically don't set
427 default with IPython (and for Windows users who typically don't set
373 environment variables).
428 environment variables).
374
429
375 This command allows you to conveniently edit multi-line code right in
430 This command allows you to conveniently edit multi-line code right in
376 your IPython session.
431 your IPython session.
377
432
378 If called without arguments, %edit opens up an empty editor with a
433 If called without arguments, %edit opens up an empty editor with a
379 temporary file and will execute the contents of this file when you
434 temporary file and will execute the contents of this file when you
380 close it (don't forget to save it!).
435 close it (don't forget to save it!).
381
436
382
437
383 Options:
438 Options:
384
439
385 -n <number>: open the editor at a specified line number. By default,
440 -n <number>: open the editor at a specified line number. By default,
386 the IPython editor hook uses the unix syntax 'editor +N filename', but
441 the IPython editor hook uses the unix syntax 'editor +N filename', but
387 you can configure this by providing your own modified hook if your
442 you can configure this by providing your own modified hook if your
388 favorite editor supports line-number specifications with a different
443 favorite editor supports line-number specifications with a different
389 syntax.
444 syntax.
390
445
391 -p: this will call the editor with the same data as the previous time
446 -p: this will call the editor with the same data as the previous time
392 it was used, regardless of how long ago (in your current session) it
447 it was used, regardless of how long ago (in your current session) it
393 was.
448 was.
394
449
395 -r: use 'raw' input. This option only applies to input taken from the
450 -r: use 'raw' input. This option only applies to input taken from the
396 user's history. By default, the 'processed' history is used, so that
451 user's history. By default, the 'processed' history is used, so that
397 magics are loaded in their transformed version to valid Python. If
452 magics are loaded in their transformed version to valid Python. If
398 this option is given, the raw input as typed as the command line is
453 this option is given, the raw input as typed as the command line is
399 used instead. When you exit the editor, it will be executed by
454 used instead. When you exit the editor, it will be executed by
400 IPython's own processor.
455 IPython's own processor.
401
456
402 -x: do not execute the edited code immediately upon exit. This is
457 -x: do not execute the edited code immediately upon exit. This is
403 mainly useful if you are editing programs which need to be called with
458 mainly useful if you are editing programs which need to be called with
404 command line arguments, which you can then do using %run.
459 command line arguments, which you can then do using %run.
405
460
406
461
407 Arguments:
462 Arguments:
408
463
409 If arguments are given, the following possibilities exist:
464 If arguments are given, the following possibilities exist:
410
465
411 - If the argument is a filename, IPython will load that into the
466 - If the argument is a filename, IPython will load that into the
412 editor. It will execute its contents with execfile() when you exit,
467 editor. It will execute its contents with execfile() when you exit,
413 loading any code in the file into your interactive namespace.
468 loading any code in the file into your interactive namespace.
414
469
415 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
470 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
416 The syntax is the same as in the %history magic.
471 The syntax is the same as in the %history magic.
417
472
418 - If the argument is a string variable, its contents are loaded
473 - If the argument is a string variable, its contents are loaded
419 into the editor. You can thus edit any string which contains
474 into the editor. You can thus edit any string which contains
420 python code (including the result of previous edits).
475 python code (including the result of previous edits).
421
476
422 - If the argument is the name of an object (other than a string),
477 - If the argument is the name of an object (other than a string),
423 IPython will try to locate the file where it was defined and open the
478 IPython will try to locate the file where it was defined and open the
424 editor at the point where it is defined. You can use `%edit function`
479 editor at the point where it is defined. You can use `%edit function`
425 to load an editor exactly at the point where 'function' is defined,
480 to load an editor exactly at the point where 'function' is defined,
426 edit it and have the file be executed automatically.
481 edit it and have the file be executed automatically.
427
482
428 - If the object is a macro (see %macro for details), this opens up your
483 - If the object is a macro (see %macro for details), this opens up your
429 specified editor with a temporary file containing the macro's data.
484 specified editor with a temporary file containing the macro's data.
430 Upon exit, the macro is reloaded with the contents of the file.
485 Upon exit, the macro is reloaded with the contents of the file.
431
486
432 Note: opening at an exact line is only supported under Unix, and some
487 Note: opening at an exact line is only supported under Unix, and some
433 editors (like kedit and gedit up to Gnome 2.8) do not understand the
488 editors (like kedit and gedit up to Gnome 2.8) do not understand the
434 '+NUMBER' parameter necessary for this feature. Good editors like
489 '+NUMBER' parameter necessary for this feature. Good editors like
435 (X)Emacs, vi, jed, pico and joe all do.
490 (X)Emacs, vi, jed, pico and joe all do.
436
491
437 After executing your code, %edit will return as output the code you
492 After executing your code, %edit will return as output the code you
438 typed in the editor (except when it was an existing file). This way
493 typed in the editor (except when it was an existing file). This way
439 you can reload the code in further invocations of %edit as a variable,
494 you can reload the code in further invocations of %edit as a variable,
440 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
495 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
441 the output.
496 the output.
442
497
443 Note that %edit is also available through the alias %ed.
498 Note that %edit is also available through the alias %ed.
444
499
445 This is an example of creating a simple function inside the editor and
500 This is an example of creating a simple function inside the editor and
446 then modifying it. First, start up the editor::
501 then modifying it. First, start up the editor::
447
502
448 In [1]: edit
503 In [1]: edit
449 Editing... done. Executing edited code...
504 Editing... done. Executing edited code...
450 Out[1]: 'def foo():\\n print "foo() was defined in an editing
505 Out[1]: 'def foo():\\n print "foo() was defined in an editing
451 session"\\n'
506 session"\\n'
452
507
453 We can then call the function foo()::
508 We can then call the function foo()::
454
509
455 In [2]: foo()
510 In [2]: foo()
456 foo() was defined in an editing session
511 foo() was defined in an editing session
457
512
458 Now we edit foo. IPython automatically loads the editor with the
513 Now we edit foo. IPython automatically loads the editor with the
459 (temporary) file where foo() was previously defined::
514 (temporary) file where foo() was previously defined::
460
515
461 In [3]: edit foo
516 In [3]: edit foo
462 Editing... done. Executing edited code...
517 Editing... done. Executing edited code...
463
518
464 And if we call foo() again we get the modified version::
519 And if we call foo() again we get the modified version::
465
520
466 In [4]: foo()
521 In [4]: foo()
467 foo() has now been changed!
522 foo() has now been changed!
468
523
469 Here is an example of how to edit a code snippet successive
524 Here is an example of how to edit a code snippet successive
470 times. First we call the editor::
525 times. First we call the editor::
471
526
472 In [5]: edit
527 In [5]: edit
473 Editing... done. Executing edited code...
528 Editing... done. Executing edited code...
474 hello
529 hello
475 Out[5]: "print 'hello'\\n"
530 Out[5]: "print 'hello'\\n"
476
531
477 Now we call it again with the previous output (stored in _)::
532 Now we call it again with the previous output (stored in _)::
478
533
479 In [6]: edit _
534 In [6]: edit _
480 Editing... done. Executing edited code...
535 Editing... done. Executing edited code...
481 hello world
536 hello world
482 Out[6]: "print 'hello world'\\n"
537 Out[6]: "print 'hello world'\\n"
483
538
484 Now we call it with the output #8 (stored in _8, also as Out[8])::
539 Now we call it with the output #8 (stored in _8, also as Out[8])::
485
540
486 In [7]: edit _8
541 In [7]: edit _8
487 Editing... done. Executing edited code...
542 Editing... done. Executing edited code...
488 hello again
543 hello again
489 Out[7]: "print 'hello again'\\n"
544 Out[7]: "print 'hello again'\\n"
490
545
491
546
492 Changing the default editor hook:
547 Changing the default editor hook:
493
548
494 If you wish to write your own editor hook, you can put it in a
549 If you wish to write your own editor hook, you can put it in a
495 configuration file which you load at startup time. The default hook
550 configuration file which you load at startup time. The default hook
496 is defined in the IPython.core.hooks module, and you can use that as a
551 is defined in the IPython.core.hooks module, and you can use that as a
497 starting example for further modifications. That file also has
552 starting example for further modifications. That file also has
498 general instructions on how to set a new hook for use once you've
553 general instructions on how to set a new hook for use once you've
499 defined it."""
554 defined it."""
500 opts,args = self.parse_options(parameter_s,'prxn:')
555 opts,args = self.parse_options(parameter_s,'prxn:')
501
556
502 try:
557 try:
503 filename, lineno, is_temp = self._find_edit_target(self.shell,
558 filename, lineno, is_temp = self._find_edit_target(self.shell,
504 args, opts, last_call)
559 args, opts, last_call)
505 except MacroToEdit as e:
560 except MacroToEdit as e:
506 self._edit_macro(args, e.args[0])
561 self._edit_macro(args, e.args[0])
507 return
562 return
508 except InteractivelyDefined as e:
563 except InteractivelyDefined as e:
509 print "Editing In[%i]" % e.index
564 print "Editing In[%i]" % e.index
510 args = str(e.index)
565 args = str(e.index)
511 filename, lineno, is_temp = self._find_edit_target(self.shell,
566 filename, lineno, is_temp = self._find_edit_target(self.shell,
512 args, opts, last_call)
567 args, opts, last_call)
513 if filename is None:
568 if filename is None:
514 # nothing was found, warnings have already been issued,
569 # nothing was found, warnings have already been issued,
515 # just give up.
570 # just give up.
516 return
571 return
517
572
518 # do actual editing here
573 # do actual editing here
519 print 'Editing...',
574 print 'Editing...',
520 sys.stdout.flush()
575 sys.stdout.flush()
521 try:
576 try:
522 # Quote filenames that may have spaces in them
577 # Quote filenames that may have spaces in them
523 if ' ' in filename:
578 if ' ' in filename:
524 filename = "'%s'" % filename
579 filename = "'%s'" % filename
525 self.shell.hooks.editor(filename,lineno)
580 self.shell.hooks.editor(filename,lineno)
526 except TryNext:
581 except TryNext:
527 warn('Could not open editor')
582 warn('Could not open editor')
528 return
583 return
529
584
530 # XXX TODO: should this be generalized for all string vars?
585 # XXX TODO: should this be generalized for all string vars?
531 # For now, this is special-cased to blocks created by cpaste
586 # For now, this is special-cased to blocks created by cpaste
532 if args.strip() == 'pasted_block':
587 if args.strip() == 'pasted_block':
533 with open(filename, 'r') as f:
588 with open(filename, 'r') as f:
534 self.shell.user_ns['pasted_block'] = f.read()
589 self.shell.user_ns['pasted_block'] = f.read()
535
590
536 if 'x' in opts: # -x prevents actual execution
591 if 'x' in opts: # -x prevents actual execution
537 print
592 print
538 else:
593 else:
539 print 'done. Executing edited code...'
594 print 'done. Executing edited code...'
540 with preserve_keys(self.shell.user_ns, '__file__'):
595 with preserve_keys(self.shell.user_ns, '__file__'):
541 if not is_temp:
596 if not is_temp:
542 self.shell.user_ns['__file__'] = filename
597 self.shell.user_ns['__file__'] = filename
543 if 'r' in opts: # Untranslated IPython code
598 if 'r' in opts: # Untranslated IPython code
544 with open(filename, 'r') as f:
599 with open(filename, 'r') as f:
545 source = f.read()
600 source = f.read()
546 self.shell.run_cell(source, store_history=False)
601 self.shell.run_cell(source, store_history=False)
547 else:
602 else:
548 self.shell.safe_execfile(filename, self.shell.user_ns,
603 self.shell.safe_execfile(filename, self.shell.user_ns,
549 self.shell.user_ns)
604 self.shell.user_ns)
550
605
551 if is_temp:
606 if is_temp:
552 try:
607 try:
553 return open(filename).read()
608 return open(filename).read()
554 except IOError as msg:
609 except IOError as msg:
555 if msg.filename == filename:
610 if msg.filename == filename:
556 warn('File not found. Did you forget to save?')
611 warn('File not found. Did you forget to save?')
557 return
612 return
558 else:
613 else:
559 self.shell.showtraceback()
614 self.shell.showtraceback()
@@ -1,895 +1,910 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, code
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.io import capture_output
37 from IPython.utils.io import capture_output
38 from IPython.utils.tempdir import TemporaryDirectory
38 from IPython.utils.tempdir import TemporaryDirectory
39 from IPython.utils.process import find_cmd
39 from IPython.utils.process import find_cmd
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Test functions begin
42 # Test functions begin
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 @magic.magics_class
45 @magic.magics_class
46 class DummyMagics(magic.Magics): pass
46 class DummyMagics(magic.Magics): pass
47
47
48 def test_extract_code_ranges():
49 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
50 expected = [(0, 1),
51 (2, 3),
52 (4, 6),
53 (6, 9),
54 (9, 14),
55 (16, None),
56 (None, 9),
57 (9, None),
58 (None, 13),
59 (None, None)]
60 actual = list(code.extract_code_ranges(instr))
61 nt.assert_equal(actual, expected)
62
48 def test_rehashx():
63 def test_rehashx():
49 # clear up everything
64 # clear up everything
50 _ip = get_ipython()
65 _ip = get_ipython()
51 _ip.alias_manager.clear_aliases()
66 _ip.alias_manager.clear_aliases()
52 del _ip.db['syscmdlist']
67 del _ip.db['syscmdlist']
53
68
54 _ip.magic('rehashx')
69 _ip.magic('rehashx')
55 # Practically ALL ipython development systems will have more than 10 aliases
70 # Practically ALL ipython development systems will have more than 10 aliases
56
71
57 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
72 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
58 for name, cmd in _ip.alias_manager.aliases:
73 for name, cmd in _ip.alias_manager.aliases:
59 # we must strip dots from alias names
74 # we must strip dots from alias names
60 nt.assert_not_in('.', name)
75 nt.assert_not_in('.', name)
61
76
62 # rehashx must fill up syscmdlist
77 # rehashx must fill up syscmdlist
63 scoms = _ip.db['syscmdlist']
78 scoms = _ip.db['syscmdlist']
64 nt.assert_true(len(scoms) > 10)
79 nt.assert_true(len(scoms) > 10)
65
80
66
81
67 def test_magic_parse_options():
82 def test_magic_parse_options():
68 """Test that we don't mangle paths when parsing magic options."""
83 """Test that we don't mangle paths when parsing magic options."""
69 ip = get_ipython()
84 ip = get_ipython()
70 path = 'c:\\x'
85 path = 'c:\\x'
71 m = DummyMagics(ip)
86 m = DummyMagics(ip)
72 opts = m.parse_options('-f %s' % path,'f:')[0]
87 opts = m.parse_options('-f %s' % path,'f:')[0]
73 # argv splitting is os-dependent
88 # argv splitting is os-dependent
74 if os.name == 'posix':
89 if os.name == 'posix':
75 expected = 'c:x'
90 expected = 'c:x'
76 else:
91 else:
77 expected = path
92 expected = path
78 nt.assert_equal(opts['f'], expected)
93 nt.assert_equal(opts['f'], expected)
79
94
80 def test_magic_parse_long_options():
95 def test_magic_parse_long_options():
81 """Magic.parse_options can handle --foo=bar long options"""
96 """Magic.parse_options can handle --foo=bar long options"""
82 ip = get_ipython()
97 ip = get_ipython()
83 m = DummyMagics(ip)
98 m = DummyMagics(ip)
84 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
99 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
85 nt.assert_in('foo', opts)
100 nt.assert_in('foo', opts)
86 nt.assert_in('bar', opts)
101 nt.assert_in('bar', opts)
87 nt.assert_equal(opts['bar'], "bubble")
102 nt.assert_equal(opts['bar'], "bubble")
88
103
89
104
90 @dec.skip_without('sqlite3')
105 @dec.skip_without('sqlite3')
91 def doctest_hist_f():
106 def doctest_hist_f():
92 """Test %hist -f with temporary filename.
107 """Test %hist -f with temporary filename.
93
108
94 In [9]: import tempfile
109 In [9]: import tempfile
95
110
96 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
111 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
97
112
98 In [11]: %hist -nl -f $tfile 3
113 In [11]: %hist -nl -f $tfile 3
99
114
100 In [13]: import os; os.unlink(tfile)
115 In [13]: import os; os.unlink(tfile)
101 """
116 """
102
117
103
118
104 @dec.skip_without('sqlite3')
119 @dec.skip_without('sqlite3')
105 def doctest_hist_r():
120 def doctest_hist_r():
106 """Test %hist -r
121 """Test %hist -r
107
122
108 XXX - This test is not recording the output correctly. For some reason, in
123 XXX - This test is not recording the output correctly. For some reason, in
109 testing mode the raw history isn't getting populated. No idea why.
124 testing mode the raw history isn't getting populated. No idea why.
110 Disabling the output checking for now, though at least we do run it.
125 Disabling the output checking for now, though at least we do run it.
111
126
112 In [1]: 'hist' in _ip.lsmagic()
127 In [1]: 'hist' in _ip.lsmagic()
113 Out[1]: True
128 Out[1]: True
114
129
115 In [2]: x=1
130 In [2]: x=1
116
131
117 In [3]: %hist -rl 2
132 In [3]: %hist -rl 2
118 x=1 # random
133 x=1 # random
119 %hist -r 2
134 %hist -r 2
120 """
135 """
121
136
122
137
123 @dec.skip_without('sqlite3')
138 @dec.skip_without('sqlite3')
124 def doctest_hist_op():
139 def doctest_hist_op():
125 """Test %hist -op
140 """Test %hist -op
126
141
127 In [1]: class b(float):
142 In [1]: class b(float):
128 ...: pass
143 ...: pass
129 ...:
144 ...:
130
145
131 In [2]: class s(object):
146 In [2]: class s(object):
132 ...: def __str__(self):
147 ...: def __str__(self):
133 ...: return 's'
148 ...: return 's'
134 ...:
149 ...:
135
150
136 In [3]:
151 In [3]:
137
152
138 In [4]: class r(b):
153 In [4]: class r(b):
139 ...: def __repr__(self):
154 ...: def __repr__(self):
140 ...: return 'r'
155 ...: return 'r'
141 ...:
156 ...:
142
157
143 In [5]: class sr(s,r): pass
158 In [5]: class sr(s,r): pass
144 ...:
159 ...:
145
160
146 In [6]:
161 In [6]:
147
162
148 In [7]: bb=b()
163 In [7]: bb=b()
149
164
150 In [8]: ss=s()
165 In [8]: ss=s()
151
166
152 In [9]: rr=r()
167 In [9]: rr=r()
153
168
154 In [10]: ssrr=sr()
169 In [10]: ssrr=sr()
155
170
156 In [11]: 4.5
171 In [11]: 4.5
157 Out[11]: 4.5
172 Out[11]: 4.5
158
173
159 In [12]: str(ss)
174 In [12]: str(ss)
160 Out[12]: 's'
175 Out[12]: 's'
161
176
162 In [13]:
177 In [13]:
163
178
164 In [14]: %hist -op
179 In [14]: %hist -op
165 >>> class b:
180 >>> class b:
166 ... pass
181 ... pass
167 ...
182 ...
168 >>> class s(b):
183 >>> class s(b):
169 ... def __str__(self):
184 ... def __str__(self):
170 ... return 's'
185 ... return 's'
171 ...
186 ...
172 >>>
187 >>>
173 >>> class r(b):
188 >>> class r(b):
174 ... def __repr__(self):
189 ... def __repr__(self):
175 ... return 'r'
190 ... return 'r'
176 ...
191 ...
177 >>> class sr(s,r): pass
192 >>> class sr(s,r): pass
178 >>>
193 >>>
179 >>> bb=b()
194 >>> bb=b()
180 >>> ss=s()
195 >>> ss=s()
181 >>> rr=r()
196 >>> rr=r()
182 >>> ssrr=sr()
197 >>> ssrr=sr()
183 >>> 4.5
198 >>> 4.5
184 4.5
199 4.5
185 >>> str(ss)
200 >>> str(ss)
186 's'
201 's'
187 >>>
202 >>>
188 """
203 """
189
204
190
205
191 @dec.skip_without('sqlite3')
206 @dec.skip_without('sqlite3')
192 def test_macro():
207 def test_macro():
193 ip = get_ipython()
208 ip = get_ipython()
194 ip.history_manager.reset() # Clear any existing history.
209 ip.history_manager.reset() # Clear any existing history.
195 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
210 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
196 for i, cmd in enumerate(cmds, start=1):
211 for i, cmd in enumerate(cmds, start=1):
197 ip.history_manager.store_inputs(i, cmd)
212 ip.history_manager.store_inputs(i, cmd)
198 ip.magic("macro test 1-3")
213 ip.magic("macro test 1-3")
199 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
214 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
200
215
201 # List macros
216 # List macros
202 nt.assert_in("test", ip.magic("macro"))
217 nt.assert_in("test", ip.magic("macro"))
203
218
204
219
205 @dec.skip_without('sqlite3')
220 @dec.skip_without('sqlite3')
206 def test_macro_run():
221 def test_macro_run():
207 """Test that we can run a multi-line macro successfully."""
222 """Test that we can run a multi-line macro successfully."""
208 ip = get_ipython()
223 ip = get_ipython()
209 ip.history_manager.reset()
224 ip.history_manager.reset()
210 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
225 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
211 "%macro test 2-3"]
226 "%macro test 2-3"]
212 for cmd in cmds:
227 for cmd in cmds:
213 ip.run_cell(cmd, store_history=True)
228 ip.run_cell(cmd, store_history=True)
214 nt.assert_equal(ip.user_ns["test"].value,
229 nt.assert_equal(ip.user_ns["test"].value,
215 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
230 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
216 with tt.AssertPrints("12"):
231 with tt.AssertPrints("12"):
217 ip.run_cell("test")
232 ip.run_cell("test")
218 with tt.AssertPrints("13"):
233 with tt.AssertPrints("13"):
219 ip.run_cell("test")
234 ip.run_cell("test")
220
235
221
236
222 def test_magic_magic():
237 def test_magic_magic():
223 """Test %magic"""
238 """Test %magic"""
224 ip = get_ipython()
239 ip = get_ipython()
225 with capture_output() as captured:
240 with capture_output() as captured:
226 ip.magic("magic")
241 ip.magic("magic")
227
242
228 stdout = captured.stdout
243 stdout = captured.stdout
229 nt.assert_in('%magic', stdout)
244 nt.assert_in('%magic', stdout)
230 nt.assert_in('IPython', stdout)
245 nt.assert_in('IPython', stdout)
231 nt.assert_in('Available', stdout)
246 nt.assert_in('Available', stdout)
232
247
233
248
234 @dec.skipif_not_numpy
249 @dec.skipif_not_numpy
235 def test_numpy_reset_array_undec():
250 def test_numpy_reset_array_undec():
236 "Test '%reset array' functionality"
251 "Test '%reset array' functionality"
237 _ip.ex('import numpy as np')
252 _ip.ex('import numpy as np')
238 _ip.ex('a = np.empty(2)')
253 _ip.ex('a = np.empty(2)')
239 nt.assert_in('a', _ip.user_ns)
254 nt.assert_in('a', _ip.user_ns)
240 _ip.magic('reset -f array')
255 _ip.magic('reset -f array')
241 nt.assert_not_in('a', _ip.user_ns)
256 nt.assert_not_in('a', _ip.user_ns)
242
257
243 def test_reset_out():
258 def test_reset_out():
244 "Test '%reset out' magic"
259 "Test '%reset out' magic"
245 _ip.run_cell("parrot = 'dead'", store_history=True)
260 _ip.run_cell("parrot = 'dead'", store_history=True)
246 # test '%reset -f out', make an Out prompt
261 # test '%reset -f out', make an Out prompt
247 _ip.run_cell("parrot", store_history=True)
262 _ip.run_cell("parrot", store_history=True)
248 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
263 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
249 _ip.magic('reset -f out')
264 _ip.magic('reset -f out')
250 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
265 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
251 nt.assert_equal(len(_ip.user_ns['Out']), 0)
266 nt.assert_equal(len(_ip.user_ns['Out']), 0)
252
267
253 def test_reset_in():
268 def test_reset_in():
254 "Test '%reset in' magic"
269 "Test '%reset in' magic"
255 # test '%reset -f in'
270 # test '%reset -f in'
256 _ip.run_cell("parrot", store_history=True)
271 _ip.run_cell("parrot", store_history=True)
257 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
272 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
258 _ip.magic('%reset -f in')
273 _ip.magic('%reset -f in')
259 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
274 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
260 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
275 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
261
276
262 def test_reset_dhist():
277 def test_reset_dhist():
263 "Test '%reset dhist' magic"
278 "Test '%reset dhist' magic"
264 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
279 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
265 _ip.magic('cd ' + os.path.dirname(nt.__file__))
280 _ip.magic('cd ' + os.path.dirname(nt.__file__))
266 _ip.magic('cd -')
281 _ip.magic('cd -')
267 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
282 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
268 _ip.magic('reset -f dhist')
283 _ip.magic('reset -f dhist')
269 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
284 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
270 _ip.run_cell("_dh = [d for d in tmp]") #restore
285 _ip.run_cell("_dh = [d for d in tmp]") #restore
271
286
272 def test_reset_in_length():
287 def test_reset_in_length():
273 "Test that '%reset in' preserves In[] length"
288 "Test that '%reset in' preserves In[] length"
274 _ip.run_cell("print 'foo'")
289 _ip.run_cell("print 'foo'")
275 _ip.run_cell("reset -f in")
290 _ip.run_cell("reset -f in")
276 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
291 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
277
292
278 def test_tb_syntaxerror():
293 def test_tb_syntaxerror():
279 """test %tb after a SyntaxError"""
294 """test %tb after a SyntaxError"""
280 ip = get_ipython()
295 ip = get_ipython()
281 ip.run_cell("for")
296 ip.run_cell("for")
282
297
283 # trap and validate stdout
298 # trap and validate stdout
284 save_stdout = sys.stdout
299 save_stdout = sys.stdout
285 try:
300 try:
286 sys.stdout = StringIO()
301 sys.stdout = StringIO()
287 ip.run_cell("%tb")
302 ip.run_cell("%tb")
288 out = sys.stdout.getvalue()
303 out = sys.stdout.getvalue()
289 finally:
304 finally:
290 sys.stdout = save_stdout
305 sys.stdout = save_stdout
291 # trim output, and only check the last line
306 # trim output, and only check the last line
292 last_line = out.rstrip().splitlines()[-1].strip()
307 last_line = out.rstrip().splitlines()[-1].strip()
293 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
308 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
294
309
295
310
296 def test_time():
311 def test_time():
297 ip = get_ipython()
312 ip = get_ipython()
298
313
299 with tt.AssertPrints("Wall time: "):
314 with tt.AssertPrints("Wall time: "):
300 ip.run_cell("%time None")
315 ip.run_cell("%time None")
301
316
302 ip.run_cell("def f(kmjy):\n"
317 ip.run_cell("def f(kmjy):\n"
303 " %time print (2*kmjy)")
318 " %time print (2*kmjy)")
304
319
305 with tt.AssertPrints("Wall time: "):
320 with tt.AssertPrints("Wall time: "):
306 with tt.AssertPrints("hihi", suppress=False):
321 with tt.AssertPrints("hihi", suppress=False):
307 ip.run_cell("f('hi')")
322 ip.run_cell("f('hi')")
308
323
309
324
310 @dec.skip_win32
325 @dec.skip_win32
311 def test_time2():
326 def test_time2():
312 ip = get_ipython()
327 ip = get_ipython()
313
328
314 with tt.AssertPrints("CPU times: user "):
329 with tt.AssertPrints("CPU times: user "):
315 ip.run_cell("%time None")
330 ip.run_cell("%time None")
316
331
317 def test_time3():
332 def test_time3():
318 """Erroneous magic function calls, issue gh-3334"""
333 """Erroneous magic function calls, issue gh-3334"""
319 ip = get_ipython()
334 ip = get_ipython()
320 ip.user_ns.pop('run', None)
335 ip.user_ns.pop('run', None)
321
336
322 with tt.AssertNotPrints("not found", channel='stderr'):
337 with tt.AssertNotPrints("not found", channel='stderr'):
323 ip.run_cell("%%time\n"
338 ip.run_cell("%%time\n"
324 "run = 0\n"
339 "run = 0\n"
325 "run += 1")
340 "run += 1")
326
341
327 def test_doctest_mode():
342 def test_doctest_mode():
328 "Toggle doctest_mode twice, it should be a no-op and run without error"
343 "Toggle doctest_mode twice, it should be a no-op and run without error"
329 _ip.magic('doctest_mode')
344 _ip.magic('doctest_mode')
330 _ip.magic('doctest_mode')
345 _ip.magic('doctest_mode')
331
346
332
347
333 def test_parse_options():
348 def test_parse_options():
334 """Tests for basic options parsing in magics."""
349 """Tests for basic options parsing in magics."""
335 # These are only the most minimal of tests, more should be added later. At
350 # These are only the most minimal of tests, more should be added later. At
336 # the very least we check that basic text/unicode calls work OK.
351 # the very least we check that basic text/unicode calls work OK.
337 m = DummyMagics(_ip)
352 m = DummyMagics(_ip)
338 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
353 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
339 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
354 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
340
355
341
356
342 def test_dirops():
357 def test_dirops():
343 """Test various directory handling operations."""
358 """Test various directory handling operations."""
344 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
359 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
345 curpath = os.getcwdu
360 curpath = os.getcwdu
346 startdir = os.getcwdu()
361 startdir = os.getcwdu()
347 ipdir = os.path.realpath(_ip.ipython_dir)
362 ipdir = os.path.realpath(_ip.ipython_dir)
348 try:
363 try:
349 _ip.magic('cd "%s"' % ipdir)
364 _ip.magic('cd "%s"' % ipdir)
350 nt.assert_equal(curpath(), ipdir)
365 nt.assert_equal(curpath(), ipdir)
351 _ip.magic('cd -')
366 _ip.magic('cd -')
352 nt.assert_equal(curpath(), startdir)
367 nt.assert_equal(curpath(), startdir)
353 _ip.magic('pushd "%s"' % ipdir)
368 _ip.magic('pushd "%s"' % ipdir)
354 nt.assert_equal(curpath(), ipdir)
369 nt.assert_equal(curpath(), ipdir)
355 _ip.magic('popd')
370 _ip.magic('popd')
356 nt.assert_equal(curpath(), startdir)
371 nt.assert_equal(curpath(), startdir)
357 finally:
372 finally:
358 os.chdir(startdir)
373 os.chdir(startdir)
359
374
360
375
361 def test_xmode():
376 def test_xmode():
362 # Calling xmode three times should be a no-op
377 # Calling xmode three times should be a no-op
363 xmode = _ip.InteractiveTB.mode
378 xmode = _ip.InteractiveTB.mode
364 for i in range(3):
379 for i in range(3):
365 _ip.magic("xmode")
380 _ip.magic("xmode")
366 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
381 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
367
382
368 def test_reset_hard():
383 def test_reset_hard():
369 monitor = []
384 monitor = []
370 class A(object):
385 class A(object):
371 def __del__(self):
386 def __del__(self):
372 monitor.append(1)
387 monitor.append(1)
373 def __repr__(self):
388 def __repr__(self):
374 return "<A instance>"
389 return "<A instance>"
375
390
376 _ip.user_ns["a"] = A()
391 _ip.user_ns["a"] = A()
377 _ip.run_cell("a")
392 _ip.run_cell("a")
378
393
379 nt.assert_equal(monitor, [])
394 nt.assert_equal(monitor, [])
380 _ip.magic("reset -f")
395 _ip.magic("reset -f")
381 nt.assert_equal(monitor, [1])
396 nt.assert_equal(monitor, [1])
382
397
383 class TestXdel(tt.TempFileMixin):
398 class TestXdel(tt.TempFileMixin):
384 def test_xdel(self):
399 def test_xdel(self):
385 """Test that references from %run are cleared by xdel."""
400 """Test that references from %run are cleared by xdel."""
386 src = ("class A(object):\n"
401 src = ("class A(object):\n"
387 " monitor = []\n"
402 " monitor = []\n"
388 " def __del__(self):\n"
403 " def __del__(self):\n"
389 " self.monitor.append(1)\n"
404 " self.monitor.append(1)\n"
390 "a = A()\n")
405 "a = A()\n")
391 self.mktmp(src)
406 self.mktmp(src)
392 # %run creates some hidden references...
407 # %run creates some hidden references...
393 _ip.magic("run %s" % self.fname)
408 _ip.magic("run %s" % self.fname)
394 # ... as does the displayhook.
409 # ... as does the displayhook.
395 _ip.run_cell("a")
410 _ip.run_cell("a")
396
411
397 monitor = _ip.user_ns["A"].monitor
412 monitor = _ip.user_ns["A"].monitor
398 nt.assert_equal(monitor, [])
413 nt.assert_equal(monitor, [])
399
414
400 _ip.magic("xdel a")
415 _ip.magic("xdel a")
401
416
402 # Check that a's __del__ method has been called.
417 # Check that a's __del__ method has been called.
403 nt.assert_equal(monitor, [1])
418 nt.assert_equal(monitor, [1])
404
419
405 def doctest_who():
420 def doctest_who():
406 """doctest for %who
421 """doctest for %who
407
422
408 In [1]: %reset -f
423 In [1]: %reset -f
409
424
410 In [2]: alpha = 123
425 In [2]: alpha = 123
411
426
412 In [3]: beta = 'beta'
427 In [3]: beta = 'beta'
413
428
414 In [4]: %who int
429 In [4]: %who int
415 alpha
430 alpha
416
431
417 In [5]: %who str
432 In [5]: %who str
418 beta
433 beta
419
434
420 In [6]: %whos
435 In [6]: %whos
421 Variable Type Data/Info
436 Variable Type Data/Info
422 ----------------------------
437 ----------------------------
423 alpha int 123
438 alpha int 123
424 beta str beta
439 beta str beta
425
440
426 In [7]: %who_ls
441 In [7]: %who_ls
427 Out[7]: ['alpha', 'beta']
442 Out[7]: ['alpha', 'beta']
428 """
443 """
429
444
430 def test_whos():
445 def test_whos():
431 """Check that whos is protected against objects where repr() fails."""
446 """Check that whos is protected against objects where repr() fails."""
432 class A(object):
447 class A(object):
433 def __repr__(self):
448 def __repr__(self):
434 raise Exception()
449 raise Exception()
435 _ip.user_ns['a'] = A()
450 _ip.user_ns['a'] = A()
436 _ip.magic("whos")
451 _ip.magic("whos")
437
452
438 @py3compat.u_format
453 @py3compat.u_format
439 def doctest_precision():
454 def doctest_precision():
440 """doctest for %precision
455 """doctest for %precision
441
456
442 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
457 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
443
458
444 In [2]: %precision 5
459 In [2]: %precision 5
445 Out[2]: {u}'%.5f'
460 Out[2]: {u}'%.5f'
446
461
447 In [3]: f.float_format
462 In [3]: f.float_format
448 Out[3]: {u}'%.5f'
463 Out[3]: {u}'%.5f'
449
464
450 In [4]: %precision %e
465 In [4]: %precision %e
451 Out[4]: {u}'%e'
466 Out[4]: {u}'%e'
452
467
453 In [5]: f(3.1415927)
468 In [5]: f(3.1415927)
454 Out[5]: {u}'3.141593e+00'
469 Out[5]: {u}'3.141593e+00'
455 """
470 """
456
471
457 def test_psearch():
472 def test_psearch():
458 with tt.AssertPrints("dict.fromkeys"):
473 with tt.AssertPrints("dict.fromkeys"):
459 _ip.run_cell("dict.fr*?")
474 _ip.run_cell("dict.fr*?")
460
475
461 def test_timeit_shlex():
476 def test_timeit_shlex():
462 """test shlex issues with timeit (#1109)"""
477 """test shlex issues with timeit (#1109)"""
463 _ip.ex("def f(*a,**kw): pass")
478 _ip.ex("def f(*a,**kw): pass")
464 _ip.magic('timeit -n1 "this is a bug".count(" ")')
479 _ip.magic('timeit -n1 "this is a bug".count(" ")')
465 _ip.magic('timeit -r1 -n1 f(" ", 1)')
480 _ip.magic('timeit -r1 -n1 f(" ", 1)')
466 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
481 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
467 _ip.magic('timeit -r1 -n1 ("a " + "b")')
482 _ip.magic('timeit -r1 -n1 ("a " + "b")')
468 _ip.magic('timeit -r1 -n1 f("a " + "b")')
483 _ip.magic('timeit -r1 -n1 f("a " + "b")')
469 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
484 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
470
485
471
486
472 def test_timeit_arguments():
487 def test_timeit_arguments():
473 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
488 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
474 _ip.magic("timeit ('#')")
489 _ip.magic("timeit ('#')")
475
490
476
491
477 def test_timeit_special_syntax():
492 def test_timeit_special_syntax():
478 "Test %%timeit with IPython special syntax"
493 "Test %%timeit with IPython special syntax"
479 @register_line_magic
494 @register_line_magic
480 def lmagic(line):
495 def lmagic(line):
481 ip = get_ipython()
496 ip = get_ipython()
482 ip.user_ns['lmagic_out'] = line
497 ip.user_ns['lmagic_out'] = line
483
498
484 # line mode test
499 # line mode test
485 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
500 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
486 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
501 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
487 # cell mode test
502 # cell mode test
488 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
503 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
489 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
504 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
490
505
491 def test_timeit_return():
506 def test_timeit_return():
492 """
507 """
493 test wether timeit -o return object
508 test wether timeit -o return object
494 """
509 """
495
510
496 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
511 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
497 assert(res is not None)
512 assert(res is not None)
498
513
499 def test_timeit_quiet():
514 def test_timeit_quiet():
500 """
515 """
501 test quiet option of timeit magic
516 test quiet option of timeit magic
502 """
517 """
503 with tt.AssertNotPrints("loops"):
518 with tt.AssertNotPrints("loops"):
504 _ip.run_cell("%timeit -n1 -r1 -q 1")
519 _ip.run_cell("%timeit -n1 -r1 -q 1")
505
520
506 @dec.skipif(execution.profile is None)
521 @dec.skipif(execution.profile is None)
507 def test_prun_special_syntax():
522 def test_prun_special_syntax():
508 "Test %%prun with IPython special syntax"
523 "Test %%prun with IPython special syntax"
509 @register_line_magic
524 @register_line_magic
510 def lmagic(line):
525 def lmagic(line):
511 ip = get_ipython()
526 ip = get_ipython()
512 ip.user_ns['lmagic_out'] = line
527 ip.user_ns['lmagic_out'] = line
513
528
514 # line mode test
529 # line mode test
515 _ip.run_line_magic('prun', '-q %lmagic my line')
530 _ip.run_line_magic('prun', '-q %lmagic my line')
516 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
531 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
517 # cell mode test
532 # cell mode test
518 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
533 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
519 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
534 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
520
535
521 @dec.skipif(execution.profile is None)
536 @dec.skipif(execution.profile is None)
522 def test_prun_quotes():
537 def test_prun_quotes():
523 "Test that prun does not clobber string escapes (GH #1302)"
538 "Test that prun does not clobber string escapes (GH #1302)"
524 _ip.magic(r"prun -q x = '\t'")
539 _ip.magic(r"prun -q x = '\t'")
525 nt.assert_equal(_ip.user_ns['x'], '\t')
540 nt.assert_equal(_ip.user_ns['x'], '\t')
526
541
527 def test_extension():
542 def test_extension():
528 tmpdir = TemporaryDirectory()
543 tmpdir = TemporaryDirectory()
529 orig_ipython_dir = _ip.ipython_dir
544 orig_ipython_dir = _ip.ipython_dir
530 try:
545 try:
531 _ip.ipython_dir = tmpdir.name
546 _ip.ipython_dir = tmpdir.name
532 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
547 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
533 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
548 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
534 _ip.magic("install_ext %s" % url)
549 _ip.magic("install_ext %s" % url)
535 _ip.user_ns.pop('arq', None)
550 _ip.user_ns.pop('arq', None)
536 invalidate_caches() # Clear import caches
551 invalidate_caches() # Clear import caches
537 _ip.magic("load_ext daft_extension")
552 _ip.magic("load_ext daft_extension")
538 nt.assert_equal(_ip.user_ns['arq'], 185)
553 nt.assert_equal(_ip.user_ns['arq'], 185)
539 _ip.magic("unload_ext daft_extension")
554 _ip.magic("unload_ext daft_extension")
540 assert 'arq' not in _ip.user_ns
555 assert 'arq' not in _ip.user_ns
541 finally:
556 finally:
542 _ip.ipython_dir = orig_ipython_dir
557 _ip.ipython_dir = orig_ipython_dir
543 tmpdir.cleanup()
558 tmpdir.cleanup()
544
559
545 def test_notebook_export_json():
560 def test_notebook_export_json():
546 with TemporaryDirectory() as td:
561 with TemporaryDirectory() as td:
547 outfile = os.path.join(td, "nb.ipynb")
562 outfile = os.path.join(td, "nb.ipynb")
548 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
563 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
549 _ip.magic("notebook -e %s" % outfile)
564 _ip.magic("notebook -e %s" % outfile)
550
565
551 def test_notebook_export_py():
566 def test_notebook_export_py():
552 with TemporaryDirectory() as td:
567 with TemporaryDirectory() as td:
553 outfile = os.path.join(td, "nb.py")
568 outfile = os.path.join(td, "nb.py")
554 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
569 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
555 _ip.magic("notebook -e %s" % outfile)
570 _ip.magic("notebook -e %s" % outfile)
556
571
557 def test_notebook_reformat_py():
572 def test_notebook_reformat_py():
558 with TemporaryDirectory() as td:
573 with TemporaryDirectory() as td:
559 infile = os.path.join(td, "nb.ipynb")
574 infile = os.path.join(td, "nb.ipynb")
560 with io.open(infile, 'w', encoding='utf-8') as f:
575 with io.open(infile, 'w', encoding='utf-8') as f:
561 current.write(nb0, f, 'json')
576 current.write(nb0, f, 'json')
562
577
563 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
578 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
564 _ip.magic("notebook -f py %s" % infile)
579 _ip.magic("notebook -f py %s" % infile)
565
580
566 def test_notebook_reformat_json():
581 def test_notebook_reformat_json():
567 with TemporaryDirectory() as td:
582 with TemporaryDirectory() as td:
568 infile = os.path.join(td, "nb.py")
583 infile = os.path.join(td, "nb.py")
569 with io.open(infile, 'w', encoding='utf-8') as f:
584 with io.open(infile, 'w', encoding='utf-8') as f:
570 current.write(nb0, f, 'py')
585 current.write(nb0, f, 'py')
571
586
572 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
587 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
573 _ip.magic("notebook -f ipynb %s" % infile)
588 _ip.magic("notebook -f ipynb %s" % infile)
574 _ip.magic("notebook -f json %s" % infile)
589 _ip.magic("notebook -f json %s" % infile)
575
590
576 def test_env():
591 def test_env():
577 env = _ip.magic("env")
592 env = _ip.magic("env")
578 assert isinstance(env, dict), type(env)
593 assert isinstance(env, dict), type(env)
579
594
580
595
581 class CellMagicTestCase(TestCase):
596 class CellMagicTestCase(TestCase):
582
597
583 def check_ident(self, magic):
598 def check_ident(self, magic):
584 # Manually called, we get the result
599 # Manually called, we get the result
585 out = _ip.run_cell_magic(magic, 'a', 'b')
600 out = _ip.run_cell_magic(magic, 'a', 'b')
586 nt.assert_equal(out, ('a','b'))
601 nt.assert_equal(out, ('a','b'))
587 # Via run_cell, it goes into the user's namespace via displayhook
602 # Via run_cell, it goes into the user's namespace via displayhook
588 _ip.run_cell('%%' + magic +' c\nd')
603 _ip.run_cell('%%' + magic +' c\nd')
589 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
604 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
590
605
591 def test_cell_magic_func_deco(self):
606 def test_cell_magic_func_deco(self):
592 "Cell magic using simple decorator"
607 "Cell magic using simple decorator"
593 @register_cell_magic
608 @register_cell_magic
594 def cellm(line, cell):
609 def cellm(line, cell):
595 return line, cell
610 return line, cell
596
611
597 self.check_ident('cellm')
612 self.check_ident('cellm')
598
613
599 def test_cell_magic_reg(self):
614 def test_cell_magic_reg(self):
600 "Cell magic manually registered"
615 "Cell magic manually registered"
601 def cellm(line, cell):
616 def cellm(line, cell):
602 return line, cell
617 return line, cell
603
618
604 _ip.register_magic_function(cellm, 'cell', 'cellm2')
619 _ip.register_magic_function(cellm, 'cell', 'cellm2')
605 self.check_ident('cellm2')
620 self.check_ident('cellm2')
606
621
607 def test_cell_magic_class(self):
622 def test_cell_magic_class(self):
608 "Cell magics declared via a class"
623 "Cell magics declared via a class"
609 @magics_class
624 @magics_class
610 class MyMagics(Magics):
625 class MyMagics(Magics):
611
626
612 @cell_magic
627 @cell_magic
613 def cellm3(self, line, cell):
628 def cellm3(self, line, cell):
614 return line, cell
629 return line, cell
615
630
616 _ip.register_magics(MyMagics)
631 _ip.register_magics(MyMagics)
617 self.check_ident('cellm3')
632 self.check_ident('cellm3')
618
633
619 def test_cell_magic_class2(self):
634 def test_cell_magic_class2(self):
620 "Cell magics declared via a class, #2"
635 "Cell magics declared via a class, #2"
621 @magics_class
636 @magics_class
622 class MyMagics2(Magics):
637 class MyMagics2(Magics):
623
638
624 @cell_magic('cellm4')
639 @cell_magic('cellm4')
625 def cellm33(self, line, cell):
640 def cellm33(self, line, cell):
626 return line, cell
641 return line, cell
627
642
628 _ip.register_magics(MyMagics2)
643 _ip.register_magics(MyMagics2)
629 self.check_ident('cellm4')
644 self.check_ident('cellm4')
630 # Check that nothing is registered as 'cellm33'
645 # Check that nothing is registered as 'cellm33'
631 c33 = _ip.find_cell_magic('cellm33')
646 c33 = _ip.find_cell_magic('cellm33')
632 nt.assert_equal(c33, None)
647 nt.assert_equal(c33, None)
633
648
634 def test_file():
649 def test_file():
635 """Basic %%file"""
650 """Basic %%file"""
636 ip = get_ipython()
651 ip = get_ipython()
637 with TemporaryDirectory() as td:
652 with TemporaryDirectory() as td:
638 fname = os.path.join(td, 'file1')
653 fname = os.path.join(td, 'file1')
639 ip.run_cell_magic("file", fname, u'\n'.join([
654 ip.run_cell_magic("file", fname, u'\n'.join([
640 'line1',
655 'line1',
641 'line2',
656 'line2',
642 ]))
657 ]))
643 with open(fname) as f:
658 with open(fname) as f:
644 s = f.read()
659 s = f.read()
645 nt.assert_in('line1\n', s)
660 nt.assert_in('line1\n', s)
646 nt.assert_in('line2', s)
661 nt.assert_in('line2', s)
647
662
648 def test_file_var_expand():
663 def test_file_var_expand():
649 """%%file $filename"""
664 """%%file $filename"""
650 ip = get_ipython()
665 ip = get_ipython()
651 with TemporaryDirectory() as td:
666 with TemporaryDirectory() as td:
652 fname = os.path.join(td, 'file1')
667 fname = os.path.join(td, 'file1')
653 ip.user_ns['filename'] = fname
668 ip.user_ns['filename'] = fname
654 ip.run_cell_magic("file", '$filename', u'\n'.join([
669 ip.run_cell_magic("file", '$filename', u'\n'.join([
655 'line1',
670 'line1',
656 'line2',
671 'line2',
657 ]))
672 ]))
658 with open(fname) as f:
673 with open(fname) as f:
659 s = f.read()
674 s = f.read()
660 nt.assert_in('line1\n', s)
675 nt.assert_in('line1\n', s)
661 nt.assert_in('line2', s)
676 nt.assert_in('line2', s)
662
677
663 def test_file_unicode():
678 def test_file_unicode():
664 """%%file with unicode cell"""
679 """%%file with unicode cell"""
665 ip = get_ipython()
680 ip = get_ipython()
666 with TemporaryDirectory() as td:
681 with TemporaryDirectory() as td:
667 fname = os.path.join(td, 'file1')
682 fname = os.path.join(td, 'file1')
668 ip.run_cell_magic("file", fname, u'\n'.join([
683 ip.run_cell_magic("file", fname, u'\n'.join([
669 u'linΓ©1',
684 u'linΓ©1',
670 u'linΓ©2',
685 u'linΓ©2',
671 ]))
686 ]))
672 with io.open(fname, encoding='utf-8') as f:
687 with io.open(fname, encoding='utf-8') as f:
673 s = f.read()
688 s = f.read()
674 nt.assert_in(u'linΓ©1\n', s)
689 nt.assert_in(u'linΓ©1\n', s)
675 nt.assert_in(u'linΓ©2', s)
690 nt.assert_in(u'linΓ©2', s)
676
691
677 def test_file_amend():
692 def test_file_amend():
678 """%%file -a amends files"""
693 """%%file -a amends files"""
679 ip = get_ipython()
694 ip = get_ipython()
680 with TemporaryDirectory() as td:
695 with TemporaryDirectory() as td:
681 fname = os.path.join(td, 'file2')
696 fname = os.path.join(td, 'file2')
682 ip.run_cell_magic("file", fname, u'\n'.join([
697 ip.run_cell_magic("file", fname, u'\n'.join([
683 'line1',
698 'line1',
684 'line2',
699 'line2',
685 ]))
700 ]))
686 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
701 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
687 'line3',
702 'line3',
688 'line4',
703 'line4',
689 ]))
704 ]))
690 with open(fname) as f:
705 with open(fname) as f:
691 s = f.read()
706 s = f.read()
692 nt.assert_in('line1\n', s)
707 nt.assert_in('line1\n', s)
693 nt.assert_in('line3\n', s)
708 nt.assert_in('line3\n', s)
694
709
695
710
696 def test_script_config():
711 def test_script_config():
697 ip = get_ipython()
712 ip = get_ipython()
698 ip.config.ScriptMagics.script_magics = ['whoda']
713 ip.config.ScriptMagics.script_magics = ['whoda']
699 sm = script.ScriptMagics(shell=ip)
714 sm = script.ScriptMagics(shell=ip)
700 nt.assert_in('whoda', sm.magics['cell'])
715 nt.assert_in('whoda', sm.magics['cell'])
701
716
702 @dec.skip_win32
717 @dec.skip_win32
703 def test_script_out():
718 def test_script_out():
704 ip = get_ipython()
719 ip = get_ipython()
705 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
720 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
706 nt.assert_equal(ip.user_ns['output'], 'hi\n')
721 nt.assert_equal(ip.user_ns['output'], 'hi\n')
707
722
708 @dec.skip_win32
723 @dec.skip_win32
709 def test_script_err():
724 def test_script_err():
710 ip = get_ipython()
725 ip = get_ipython()
711 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
726 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
712 nt.assert_equal(ip.user_ns['error'], 'hello\n')
727 nt.assert_equal(ip.user_ns['error'], 'hello\n')
713
728
714 @dec.skip_win32
729 @dec.skip_win32
715 def test_script_out_err():
730 def test_script_out_err():
716 ip = get_ipython()
731 ip = get_ipython()
717 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
732 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
718 nt.assert_equal(ip.user_ns['output'], 'hi\n')
733 nt.assert_equal(ip.user_ns['output'], 'hi\n')
719 nt.assert_equal(ip.user_ns['error'], 'hello\n')
734 nt.assert_equal(ip.user_ns['error'], 'hello\n')
720
735
721 @dec.skip_win32
736 @dec.skip_win32
722 def test_script_bg_out():
737 def test_script_bg_out():
723 ip = get_ipython()
738 ip = get_ipython()
724 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
739 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
725 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
740 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
726
741
727 @dec.skip_win32
742 @dec.skip_win32
728 def test_script_bg_err():
743 def test_script_bg_err():
729 ip = get_ipython()
744 ip = get_ipython()
730 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
745 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
731 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
746 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
732
747
733 @dec.skip_win32
748 @dec.skip_win32
734 def test_script_bg_out_err():
749 def test_script_bg_out_err():
735 ip = get_ipython()
750 ip = get_ipython()
736 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
751 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
737 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
752 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
738 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
753 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
739
754
740 def test_script_defaults():
755 def test_script_defaults():
741 ip = get_ipython()
756 ip = get_ipython()
742 for cmd in ['sh', 'bash', 'perl', 'ruby']:
757 for cmd in ['sh', 'bash', 'perl', 'ruby']:
743 try:
758 try:
744 find_cmd(cmd)
759 find_cmd(cmd)
745 except Exception:
760 except Exception:
746 pass
761 pass
747 else:
762 else:
748 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
763 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
749
764
750
765
751 @magics_class
766 @magics_class
752 class FooFoo(Magics):
767 class FooFoo(Magics):
753 """class with both %foo and %%foo magics"""
768 """class with both %foo and %%foo magics"""
754 @line_magic('foo')
769 @line_magic('foo')
755 def line_foo(self, line):
770 def line_foo(self, line):
756 "I am line foo"
771 "I am line foo"
757 pass
772 pass
758
773
759 @cell_magic("foo")
774 @cell_magic("foo")
760 def cell_foo(self, line, cell):
775 def cell_foo(self, line, cell):
761 "I am cell foo, not line foo"
776 "I am cell foo, not line foo"
762 pass
777 pass
763
778
764 def test_line_cell_info():
779 def test_line_cell_info():
765 """%%foo and %foo magics are distinguishable to inspect"""
780 """%%foo and %foo magics are distinguishable to inspect"""
766 ip = get_ipython()
781 ip = get_ipython()
767 ip.magics_manager.register(FooFoo)
782 ip.magics_manager.register(FooFoo)
768 oinfo = ip.object_inspect('foo')
783 oinfo = ip.object_inspect('foo')
769 nt.assert_true(oinfo['found'])
784 nt.assert_true(oinfo['found'])
770 nt.assert_true(oinfo['ismagic'])
785 nt.assert_true(oinfo['ismagic'])
771
786
772 oinfo = ip.object_inspect('%%foo')
787 oinfo = ip.object_inspect('%%foo')
773 nt.assert_true(oinfo['found'])
788 nt.assert_true(oinfo['found'])
774 nt.assert_true(oinfo['ismagic'])
789 nt.assert_true(oinfo['ismagic'])
775 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
790 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
776
791
777 oinfo = ip.object_inspect('%foo')
792 oinfo = ip.object_inspect('%foo')
778 nt.assert_true(oinfo['found'])
793 nt.assert_true(oinfo['found'])
779 nt.assert_true(oinfo['ismagic'])
794 nt.assert_true(oinfo['ismagic'])
780 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
795 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
781
796
782 def test_multiple_magics():
797 def test_multiple_magics():
783 ip = get_ipython()
798 ip = get_ipython()
784 foo1 = FooFoo(ip)
799 foo1 = FooFoo(ip)
785 foo2 = FooFoo(ip)
800 foo2 = FooFoo(ip)
786 mm = ip.magics_manager
801 mm = ip.magics_manager
787 mm.register(foo1)
802 mm.register(foo1)
788 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
803 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
789 mm.register(foo2)
804 mm.register(foo2)
790 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
805 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
791
806
792 def test_alias_magic():
807 def test_alias_magic():
793 """Test %alias_magic."""
808 """Test %alias_magic."""
794 ip = get_ipython()
809 ip = get_ipython()
795 mm = ip.magics_manager
810 mm = ip.magics_manager
796
811
797 # Basic operation: both cell and line magics are created, if possible.
812 # Basic operation: both cell and line magics are created, if possible.
798 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
813 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
799 nt.assert_in('timeit_alias', mm.magics['line'])
814 nt.assert_in('timeit_alias', mm.magics['line'])
800 nt.assert_in('timeit_alias', mm.magics['cell'])
815 nt.assert_in('timeit_alias', mm.magics['cell'])
801
816
802 # --cell is specified, line magic not created.
817 # --cell is specified, line magic not created.
803 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
818 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
804 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
819 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
805 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
820 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
806
821
807 # Test that line alias is created successfully.
822 # Test that line alias is created successfully.
808 ip.run_line_magic('alias_magic', '--line env_alias env')
823 ip.run_line_magic('alias_magic', '--line env_alias env')
809 nt.assert_equal(ip.run_line_magic('env', ''),
824 nt.assert_equal(ip.run_line_magic('env', ''),
810 ip.run_line_magic('env_alias', ''))
825 ip.run_line_magic('env_alias', ''))
811
826
812 def test_save():
827 def test_save():
813 """Test %save."""
828 """Test %save."""
814 ip = get_ipython()
829 ip = get_ipython()
815 ip.history_manager.reset() # Clear any existing history.
830 ip.history_manager.reset() # Clear any existing history.
816 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
831 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
817 for i, cmd in enumerate(cmds, start=1):
832 for i, cmd in enumerate(cmds, start=1):
818 ip.history_manager.store_inputs(i, cmd)
833 ip.history_manager.store_inputs(i, cmd)
819 with TemporaryDirectory() as tmpdir:
834 with TemporaryDirectory() as tmpdir:
820 file = os.path.join(tmpdir, "testsave.py")
835 file = os.path.join(tmpdir, "testsave.py")
821 ip.run_line_magic("save", "%s 1-10" % file)
836 ip.run_line_magic("save", "%s 1-10" % file)
822 with open(file) as f:
837 with open(file) as f:
823 content = f.read()
838 content = f.read()
824 nt.assert_equal(content.count(cmds[0]), 1)
839 nt.assert_equal(content.count(cmds[0]), 1)
825 nt.assert_in('coding: utf-8', content)
840 nt.assert_in('coding: utf-8', content)
826 ip.run_line_magic("save", "-a %s 1-10" % file)
841 ip.run_line_magic("save", "-a %s 1-10" % file)
827 with open(file) as f:
842 with open(file) as f:
828 content = f.read()
843 content = f.read()
829 nt.assert_equal(content.count(cmds[0]), 2)
844 nt.assert_equal(content.count(cmds[0]), 2)
830 nt.assert_in('coding: utf-8', content)
845 nt.assert_in('coding: utf-8', content)
831
846
832
847
833 def test_store():
848 def test_store():
834 """Test %store."""
849 """Test %store."""
835 ip = get_ipython()
850 ip = get_ipython()
836 ip.run_line_magic('load_ext', 'storemagic')
851 ip.run_line_magic('load_ext', 'storemagic')
837
852
838 # make sure the storage is empty
853 # make sure the storage is empty
839 ip.run_line_magic('store', '-z')
854 ip.run_line_magic('store', '-z')
840 ip.user_ns['var'] = 42
855 ip.user_ns['var'] = 42
841 ip.run_line_magic('store', 'var')
856 ip.run_line_magic('store', 'var')
842 ip.user_ns['var'] = 39
857 ip.user_ns['var'] = 39
843 ip.run_line_magic('store', '-r')
858 ip.run_line_magic('store', '-r')
844 nt.assert_equal(ip.user_ns['var'], 42)
859 nt.assert_equal(ip.user_ns['var'], 42)
845
860
846 ip.run_line_magic('store', '-d var')
861 ip.run_line_magic('store', '-d var')
847 ip.user_ns['var'] = 39
862 ip.user_ns['var'] = 39
848 ip.run_line_magic('store' , '-r')
863 ip.run_line_magic('store' , '-r')
849 nt.assert_equal(ip.user_ns['var'], 39)
864 nt.assert_equal(ip.user_ns['var'], 39)
850
865
851
866
852 def _run_edit_test(arg_s, exp_filename=None,
867 def _run_edit_test(arg_s, exp_filename=None,
853 exp_lineno=-1,
868 exp_lineno=-1,
854 exp_contents=None,
869 exp_contents=None,
855 exp_is_temp=None):
870 exp_is_temp=None):
856 ip = get_ipython()
871 ip = get_ipython()
857 M = code.CodeMagics(ip)
872 M = code.CodeMagics(ip)
858 last_call = ['','']
873 last_call = ['','']
859 opts,args = M.parse_options(arg_s,'prxn:')
874 opts,args = M.parse_options(arg_s,'prxn:')
860 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
875 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
861
876
862 if exp_filename is not None:
877 if exp_filename is not None:
863 nt.assert_equal(exp_filename, filename)
878 nt.assert_equal(exp_filename, filename)
864 if exp_contents is not None:
879 if exp_contents is not None:
865 with io.open(filename, 'r') as f:
880 with io.open(filename, 'r') as f:
866 contents = f.read()
881 contents = f.read()
867 nt.assert_equal(exp_contents, contents)
882 nt.assert_equal(exp_contents, contents)
868 if exp_lineno != -1:
883 if exp_lineno != -1:
869 nt.assert_equal(exp_lineno, lineno)
884 nt.assert_equal(exp_lineno, lineno)
870 if exp_is_temp is not None:
885 if exp_is_temp is not None:
871 nt.assert_equal(exp_is_temp, is_temp)
886 nt.assert_equal(exp_is_temp, is_temp)
872
887
873
888
874 def test_edit_interactive():
889 def test_edit_interactive():
875 """%edit on interactively defined objects"""
890 """%edit on interactively defined objects"""
876 ip = get_ipython()
891 ip = get_ipython()
877 n = ip.execution_count
892 n = ip.execution_count
878 ip.run_cell(u"def foo(): return 1", store_history=True)
893 ip.run_cell(u"def foo(): return 1", store_history=True)
879
894
880 try:
895 try:
881 _run_edit_test("foo")
896 _run_edit_test("foo")
882 except code.InteractivelyDefined as e:
897 except code.InteractivelyDefined as e:
883 nt.assert_equal(e.index, n)
898 nt.assert_equal(e.index, n)
884 else:
899 else:
885 raise AssertionError("Should have raised InteractivelyDefined")
900 raise AssertionError("Should have raised InteractivelyDefined")
886
901
887
902
888 def test_edit_cell():
903 def test_edit_cell():
889 """%edit [cell id]"""
904 """%edit [cell id]"""
890 ip = get_ipython()
905 ip = get_ipython()
891
906
892 ip.run_cell(u"def foo(): return 1", store_history=True)
907 ip.run_cell(u"def foo(): return 1", store_history=True)
893
908
894 # test
909 # test
895 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
910 _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