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