##// END OF EJS Templates
bugfix. parse of non python code returns a tuple as expected
Martín Gaitán -
Show More
@@ -1,686 +1,687 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 from IPython.utils.text import get_text_list
34 from IPython.utils.text import get_text_list
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Magic implementation classes
37 # Magic implementation classes
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # Used for exception handling in magic_edit
40 # Used for exception handling in magic_edit
41 class MacroToEdit(ValueError): pass
41 class MacroToEdit(ValueError): pass
42
42
43 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
43 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
44
44
45 # To match, e.g. 8-10 1:5 :10 3-
45 # To match, e.g. 8-10 1:5 :10 3-
46 range_re = re.compile(r"""
46 range_re = re.compile(r"""
47 (?P<start>\d+)?
47 (?P<start>\d+)?
48 ((?P<sep>[\-:])
48 ((?P<sep>[\-:])
49 (?P<end>\d+)?)?
49 (?P<end>\d+)?)?
50 $""", re.VERBOSE)
50 $""", re.VERBOSE)
51
51
52
52
53 def extract_code_ranges(ranges_str):
53 def extract_code_ranges(ranges_str):
54 """Turn a string of range for %%load into 2-tuples of (start, stop)
54 """Turn a string of range for %%load into 2-tuples of (start, stop)
55 ready to use as a slice of the content splitted by lines.
55 ready to use as a slice of the content splitted by lines.
56
56
57 Examples
57 Examples
58 --------
58 --------
59 list(extract_input_ranges("5-10 2"))
59 list(extract_input_ranges("5-10 2"))
60 [(4, 10), (1, 2)]
60 [(4, 10), (1, 2)]
61 """
61 """
62 for range_str in ranges_str.split():
62 for range_str in ranges_str.split():
63 rmatch = range_re.match(range_str)
63 rmatch = range_re.match(range_str)
64 if not rmatch:
64 if not rmatch:
65 continue
65 continue
66 sep = rmatch.group("sep")
66 sep = rmatch.group("sep")
67 start = rmatch.group("start")
67 start = rmatch.group("start")
68 end = rmatch.group("end")
68 end = rmatch.group("end")
69
69
70 if sep == '-':
70 if sep == '-':
71 start = int(start) - 1 if start else None
71 start = int(start) - 1 if start else None
72 end = int(end) if end else None
72 end = int(end) if end else None
73 elif sep == ':':
73 elif sep == ':':
74 start = int(start) - 1 if start else None
74 start = int(start) - 1 if start else None
75 end = int(end) - 1 if end else None
75 end = int(end) - 1 if end else None
76 else:
76 else:
77 end = int(start)
77 end = int(start)
78 start = int(start) - 1
78 start = int(start) - 1
79 yield (start, end)
79 yield (start, end)
80
80
81
81
82 @skip_doctest
82 @skip_doctest
83 def extract_symbols(code, symbols):
83 def extract_symbols(code, symbols):
84 """
84 """
85 Return a tuple (blocks, not_found)
85 Return a tuple (blocks, not_found)
86 where ``blocks`` is a list of code fragments
86 where ``blocks`` is a list of code fragments
87 for each symbol parsed from code, and ``not_found`` are
87 for each symbol parsed from code, and ``not_found`` are
88 symbols not found in the code.
88 symbols not found in the code.
89
89
90 For example::
90 For example::
91
91
92 >>> code = '''a = 10
92 >>> code = '''a = 10
93
93
94 def b(): return 42
94 def b(): return 42
95
95
96 class A: pass'''
96 class A: pass'''
97
97
98 >>> extract_symbols(code, 'A,b,z')
98 >>> extract_symbols(code, 'A,b,z')
99 (["class A: pass", "def b(): return 42"], ['z'])
99 (["class A: pass", "def b(): return 42"], ['z'])
100 """
100 """
101 symbols = symbols.split(',')
101 try:
102 try:
102 py_code = ast.parse(code)
103 py_code = ast.parse(code)
103 except SyntaxError:
104 except SyntaxError:
104 # ignores non python code
105 # ignores non python code
105 return []
106 return [], symbols
106
107
107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
108 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
108 code = code.split('\n')
109 code = code.split('\n')
109
110
110 symbols_lines = {}
111 symbols_lines = {}
111
112
112 # we already know the start_lineno of each symbol (marks).
113 # we already know the start_lineno of each symbol (marks).
113 # To find each end_lineno, we traverse in reverse order until each
114 # To find each end_lineno, we traverse in reverse order until each
114 # non-blank line
115 # non-blank line
115 end = len(code)
116 end = len(code)
116 for name, start in reversed(marks):
117 for name, start in reversed(marks):
117 while not code[end - 1].strip():
118 while not code[end - 1].strip():
118 end -= 1
119 end -= 1
119 if name:
120 if name:
120 symbols_lines[name] = (start - 1, end)
121 symbols_lines[name] = (start - 1, end)
121 end = start - 1
122 end = start - 1
122
123
123 # Now symbols_lines is a map
124 # Now symbols_lines is a map
124 # {'symbol_name': (start_lineno, end_lineno), ...}
125 # {'symbol_name': (start_lineno, end_lineno), ...}
125
126
126 # fill a list with chunks of codes for each requested symbol
127 # fill a list with chunks of codes for each requested symbol
127 blocks = []
128 blocks = []
128 not_found = []
129 not_found = []
129 for symbol in symbols.split(','):
130 for symbol in symbols:
130 if symbol in symbols_lines:
131 if symbol in symbols_lines:
131 start, end = symbols_lines[symbol]
132 start, end = symbols_lines[symbol]
132 blocks.append('\n'.join(code[start:end]) + '\n')
133 blocks.append('\n'.join(code[start:end]) + '\n')
133 else:
134 else:
134 not_found.append(symbol)
135 not_found.append(symbol)
135
136
136 return blocks, not_found
137 return blocks, not_found
137
138
138
139
139 class InteractivelyDefined(Exception):
140 class InteractivelyDefined(Exception):
140 """Exception for interactively defined variable in magic_edit"""
141 """Exception for interactively defined variable in magic_edit"""
141 def __init__(self, index):
142 def __init__(self, index):
142 self.index = index
143 self.index = index
143
144
144
145
145 @magics_class
146 @magics_class
146 class CodeMagics(Magics):
147 class CodeMagics(Magics):
147 """Magics related to code management (loading, saving, editing, ...)."""
148 """Magics related to code management (loading, saving, editing, ...)."""
148
149
149 @line_magic
150 @line_magic
150 def save(self, parameter_s=''):
151 def save(self, parameter_s=''):
151 """Save a set of lines or a macro to a given filename.
152 """Save a set of lines or a macro to a given filename.
152
153
153 Usage:\\
154 Usage:\\
154 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
155 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
155
156
156 Options:
157 Options:
157
158
158 -r: use 'raw' input. By default, the 'processed' history is used,
159 -r: use 'raw' input. By default, the 'processed' history is used,
159 so that magics are loaded in their transformed version to valid
160 so that magics are loaded in their transformed version to valid
160 Python. If this option is given, the raw input as typed as the
161 Python. If this option is given, the raw input as typed as the
161 command line is used instead.
162 command line is used instead.
162
163
163 -f: force overwrite. If file exists, %save will prompt for overwrite
164 -f: force overwrite. If file exists, %save will prompt for overwrite
164 unless -f is given.
165 unless -f is given.
165
166
166 -a: append to the file instead of overwriting it.
167 -a: append to the file instead of overwriting it.
167
168
168 This function uses the same syntax as %history for input ranges,
169 This function uses the same syntax as %history for input ranges,
169 then saves the lines to the filename you specify.
170 then saves the lines to the filename you specify.
170
171
171 It adds a '.py' extension to the file if you don't do so yourself, and
172 It adds a '.py' extension to the file if you don't do so yourself, and
172 it asks for confirmation before overwriting existing files.
173 it asks for confirmation before overwriting existing files.
173
174
174 If `-r` option is used, the default extension is `.ipy`.
175 If `-r` option is used, the default extension is `.ipy`.
175 """
176 """
176
177
177 opts,args = self.parse_options(parameter_s,'fra',mode='list')
178 opts,args = self.parse_options(parameter_s,'fra',mode='list')
178 if not args:
179 if not args:
179 raise UsageError('Missing filename.')
180 raise UsageError('Missing filename.')
180 raw = 'r' in opts
181 raw = 'r' in opts
181 force = 'f' in opts
182 force = 'f' in opts
182 append = 'a' in opts
183 append = 'a' in opts
183 mode = 'a' if append else 'w'
184 mode = 'a' if append else 'w'
184 ext = u'.ipy' if raw else u'.py'
185 ext = u'.ipy' if raw else u'.py'
185 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
186 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
186 if not fname.endswith((u'.py',u'.ipy')):
187 if not fname.endswith((u'.py',u'.ipy')):
187 fname += ext
188 fname += ext
188 file_exists = os.path.isfile(fname)
189 file_exists = os.path.isfile(fname)
189 if file_exists and not force and not append:
190 if file_exists and not force and not append:
190 try:
191 try:
191 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
192 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
192 except StdinNotImplementedError:
193 except StdinNotImplementedError:
193 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
194 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
194 return
195 return
195 if not overwrite :
196 if not overwrite :
196 print 'Operation cancelled.'
197 print 'Operation cancelled.'
197 return
198 return
198 try:
199 try:
199 cmds = self.shell.find_user_code(codefrom,raw)
200 cmds = self.shell.find_user_code(codefrom,raw)
200 except (TypeError, ValueError) as e:
201 except (TypeError, ValueError) as e:
201 print e.args[0]
202 print e.args[0]
202 return
203 return
203 out = py3compat.cast_unicode(cmds)
204 out = py3compat.cast_unicode(cmds)
204 with io.open(fname, mode, encoding="utf-8") as f:
205 with io.open(fname, mode, encoding="utf-8") as f:
205 if not file_exists or not append:
206 if not file_exists or not append:
206 f.write(u"# coding: utf-8\n")
207 f.write(u"# coding: utf-8\n")
207 f.write(out)
208 f.write(out)
208 # make sure we end on a newline
209 # make sure we end on a newline
209 if not out.endswith(u'\n'):
210 if not out.endswith(u'\n'):
210 f.write(u'\n')
211 f.write(u'\n')
211 print 'The following commands were written to file `%s`:' % fname
212 print 'The following commands were written to file `%s`:' % fname
212 print cmds
213 print cmds
213
214
214 @line_magic
215 @line_magic
215 def pastebin(self, parameter_s=''):
216 def pastebin(self, parameter_s=''):
216 """Upload code to Github's Gist paste bin, returning the URL.
217 """Upload code to Github's Gist paste bin, returning the URL.
217
218
218 Usage:\\
219 Usage:\\
219 %pastebin [-d "Custom description"] 1-7
220 %pastebin [-d "Custom description"] 1-7
220
221
221 The argument can be an input history range, a filename, or the name of a
222 The argument can be an input history range, a filename, or the name of a
222 string or macro.
223 string or macro.
223
224
224 Options:
225 Options:
225
226
226 -d: Pass a custom description for the gist. The default will say
227 -d: Pass a custom description for the gist. The default will say
227 "Pasted from IPython".
228 "Pasted from IPython".
228 """
229 """
229 opts, args = self.parse_options(parameter_s, 'd:')
230 opts, args = self.parse_options(parameter_s, 'd:')
230
231
231 try:
232 try:
232 code = self.shell.find_user_code(args)
233 code = self.shell.find_user_code(args)
233 except (ValueError, TypeError) as e:
234 except (ValueError, TypeError) as e:
234 print e.args[0]
235 print e.args[0]
235 return
236 return
236
237
237 from urllib2 import urlopen # Deferred import
238 from urllib2 import urlopen # Deferred import
238 import json
239 import json
239 post_data = json.dumps({
240 post_data = json.dumps({
240 "description": opts.get('d', "Pasted from IPython"),
241 "description": opts.get('d', "Pasted from IPython"),
241 "public": True,
242 "public": True,
242 "files": {
243 "files": {
243 "file1.py": {
244 "file1.py": {
244 "content": code
245 "content": code
245 }
246 }
246 }
247 }
247 }).encode('utf-8')
248 }).encode('utf-8')
248
249
249 response = urlopen("https://api.github.com/gists", post_data)
250 response = urlopen("https://api.github.com/gists", post_data)
250 response_data = json.loads(response.read().decode('utf-8'))
251 response_data = json.loads(response.read().decode('utf-8'))
251 return response_data['html_url']
252 return response_data['html_url']
252
253
253 @line_magic
254 @line_magic
254 def loadpy(self, arg_s):
255 def loadpy(self, arg_s):
255 """Alias of `%load`
256 """Alias of `%load`
256
257
257 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
258 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
258 extension. So it has been renamed simply into %load. You can look at
259 extension. So it has been renamed simply into %load. You can look at
259 `%load`'s docstring for more info.
260 `%load`'s docstring for more info.
260 """
261 """
261 self.load(arg_s)
262 self.load(arg_s)
262
263
263 @line_magic
264 @line_magic
264 def load(self, arg_s):
265 def load(self, arg_s):
265 """Load code into the current frontend.
266 """Load code into the current frontend.
266
267
267 Usage:\\
268 Usage:\\
268 %load [options] source
269 %load [options] source
269
270
270 where source can be a filename, URL, input history range or macro
271 where source can be a filename, URL, input history range or macro
271
272
272 Options:
273 Options:
273 --------
274 --------
274 -r <lines>: Specify lines or ranges of lines to load from the source.
275 -r <lines>: Specify lines or ranges of lines to load from the source.
275 Ranges could be specified as x-y (x..y) or in python-style x:y
276 Ranges could be specified as x-y (x..y) or in python-style x:y
276 (x..(y-1)). Both limits x and y can be left blank (meaning the
277 (x..(y-1)). Both limits x and y can be left blank (meaning the
277 beginning and end of the file, respectively).
278 beginning and end of the file, respectively).
278
279
279 -s <symbols>: Specify function or classes to load from python source.
280 -s <symbols>: Specify function or classes to load from python source.
280
281
281 -y : Don't ask confirmation for loading source above 200 000 characters.
282 -y : Don't ask confirmation for loading source above 200 000 characters.
282
283
283 This magic command can either take a local filename, a URL, an history
284 This magic command can either take a local filename, a URL, an history
284 range (see %history) or a macro as argument, it will prompt for
285 range (see %history) or a macro as argument, it will prompt for
285 confirmation before loading source with more than 200 000 characters, unless
286 confirmation before loading source with more than 200 000 characters, unless
286 -y flag is passed or if the frontend does not support raw_input::
287 -y flag is passed or if the frontend does not support raw_input::
287
288
288 %load myscript.py
289 %load myscript.py
289 %load 7-27
290 %load 7-27
290 %load myMacro
291 %load myMacro
291 %load http://www.example.com/myscript.py
292 %load http://www.example.com/myscript.py
292 %load -r 5-10 myscript.py
293 %load -r 5-10 myscript.py
293 %load -r 10-20,30,40: foo.py
294 %load -r 10-20,30,40: foo.py
294 %load -s MyClass,wonder_function myscript.py
295 %load -s MyClass,wonder_function myscript.py
295 """
296 """
296 opts,args = self.parse_options(arg_s,'ys:r:')
297 opts,args = self.parse_options(arg_s,'ys:r:')
297
298
298 if not args:
299 if not args:
299 raise UsageError('Missing filename, URL, input history range, '
300 raise UsageError('Missing filename, URL, input history range, '
300 'or macro.')
301 'or macro.')
301
302
302 contents = self.shell.find_user_code(args)
303 contents = self.shell.find_user_code(args)
303
304
304 if 's' in opts:
305 if 's' in opts:
305 blocks, not_found = extract_symbols(contents, opts['s'])
306 blocks, not_found = extract_symbols(contents, opts['s'])
306 if len(not_found) == 1:
307 if len(not_found) == 1:
307 warn('The symbol `%s` was not found' % not_found[0])
308 warn('The symbol `%s` was not found' % not_found[0])
308 elif len(not_found) > 1:
309 elif len(not_found) > 1:
309 warn('The symbols %s were not found' % get_text_list(not_found,
310 warn('The symbols %s were not found' % get_text_list(not_found,
310 wrap_item_with='`')
311 wrap_item_with='`')
311 )
312 )
312
313
313 contents = '\n'.join(blocks)
314 contents = '\n'.join(blocks)
314
315
315 if 'r' in opts:
316 if 'r' in opts:
316 ranges = opts['r'].replace(',', ' ')
317 ranges = opts['r'].replace(',', ' ')
317 lines = contents.split('\n')
318 lines = contents.split('\n')
318 slices = extract_code_ranges(ranges)
319 slices = extract_code_ranges(ranges)
319 contents = [lines[slice(*slc)] for slc in slices]
320 contents = [lines[slice(*slc)] for slc in slices]
320 contents = '\n'.join(chain.from_iterable(contents))
321 contents = '\n'.join(chain.from_iterable(contents))
321
322
322 l = len(contents)
323 l = len(contents)
323
324
324 # 200 000 is ~ 2500 full 80 caracter lines
325 # 200 000 is ~ 2500 full 80 caracter lines
325 # so in average, more than 5000 lines
326 # so in average, more than 5000 lines
326 if l > 200000 and 'y' not in opts:
327 if l > 200000 and 'y' not in opts:
327 try:
328 try:
328 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
329 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
329 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
330 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
330 except StdinNotImplementedError:
331 except StdinNotImplementedError:
331 #asume yes if raw input not implemented
332 #asume yes if raw input not implemented
332 ans = True
333 ans = True
333
334
334 if ans is False :
335 if ans is False :
335 print 'Operation cancelled.'
336 print 'Operation cancelled.'
336 return
337 return
337
338
338 self.shell.set_next_input(contents)
339 self.shell.set_next_input(contents)
339
340
340 @staticmethod
341 @staticmethod
341 def _find_edit_target(shell, args, opts, last_call):
342 def _find_edit_target(shell, args, opts, last_call):
342 """Utility method used by magic_edit to find what to edit."""
343 """Utility method used by magic_edit to find what to edit."""
343
344
344 def make_filename(arg):
345 def make_filename(arg):
345 "Make a filename from the given args"
346 "Make a filename from the given args"
346 arg = unquote_filename(arg)
347 arg = unquote_filename(arg)
347 try:
348 try:
348 filename = get_py_filename(arg)
349 filename = get_py_filename(arg)
349 except IOError:
350 except IOError:
350 # If it ends with .py but doesn't already exist, assume we want
351 # If it ends with .py but doesn't already exist, assume we want
351 # a new file.
352 # a new file.
352 if arg.endswith('.py'):
353 if arg.endswith('.py'):
353 filename = arg
354 filename = arg
354 else:
355 else:
355 filename = None
356 filename = None
356 return filename
357 return filename
357
358
358 # Set a few locals from the options for convenience:
359 # Set a few locals from the options for convenience:
359 opts_prev = 'p' in opts
360 opts_prev = 'p' in opts
360 opts_raw = 'r' in opts
361 opts_raw = 'r' in opts
361
362
362 # custom exceptions
363 # custom exceptions
363 class DataIsObject(Exception): pass
364 class DataIsObject(Exception): pass
364
365
365 # Default line number value
366 # Default line number value
366 lineno = opts.get('n',None)
367 lineno = opts.get('n',None)
367
368
368 if opts_prev:
369 if opts_prev:
369 args = '_%s' % last_call[0]
370 args = '_%s' % last_call[0]
370 if args not in shell.user_ns:
371 if args not in shell.user_ns:
371 args = last_call[1]
372 args = last_call[1]
372
373
373 # by default this is done with temp files, except when the given
374 # by default this is done with temp files, except when the given
374 # arg is a filename
375 # arg is a filename
375 use_temp = True
376 use_temp = True
376
377
377 data = ''
378 data = ''
378
379
379 # First, see if the arguments should be a filename.
380 # First, see if the arguments should be a filename.
380 filename = make_filename(args)
381 filename = make_filename(args)
381 if filename:
382 if filename:
382 use_temp = False
383 use_temp = False
383 elif args:
384 elif args:
384 # Mode where user specifies ranges of lines, like in %macro.
385 # Mode where user specifies ranges of lines, like in %macro.
385 data = shell.extract_input_lines(args, opts_raw)
386 data = shell.extract_input_lines(args, opts_raw)
386 if not data:
387 if not data:
387 try:
388 try:
388 # Load the parameter given as a variable. If not a string,
389 # Load the parameter given as a variable. If not a string,
389 # process it as an object instead (below)
390 # process it as an object instead (below)
390
391
391 #print '*** args',args,'type',type(args) # dbg
392 #print '*** args',args,'type',type(args) # dbg
392 data = eval(args, shell.user_ns)
393 data = eval(args, shell.user_ns)
393 if not isinstance(data, basestring):
394 if not isinstance(data, basestring):
394 raise DataIsObject
395 raise DataIsObject
395
396
396 except (NameError,SyntaxError):
397 except (NameError,SyntaxError):
397 # given argument is not a variable, try as a filename
398 # given argument is not a variable, try as a filename
398 filename = make_filename(args)
399 filename = make_filename(args)
399 if filename is None:
400 if filename is None:
400 warn("Argument given (%s) can't be found as a variable "
401 warn("Argument given (%s) can't be found as a variable "
401 "or as a filename." % args)
402 "or as a filename." % args)
402 return (None, None, None)
403 return (None, None, None)
403 use_temp = False
404 use_temp = False
404
405
405 except DataIsObject:
406 except DataIsObject:
406 # macros have a special edit function
407 # macros have a special edit function
407 if isinstance(data, Macro):
408 if isinstance(data, Macro):
408 raise MacroToEdit(data)
409 raise MacroToEdit(data)
409
410
410 # For objects, try to edit the file where they are defined
411 # For objects, try to edit the file where they are defined
411 filename = find_file(data)
412 filename = find_file(data)
412 if filename:
413 if filename:
413 if 'fakemodule' in filename.lower() and \
414 if 'fakemodule' in filename.lower() and \
414 inspect.isclass(data):
415 inspect.isclass(data):
415 # class created by %edit? Try to find source
416 # class created by %edit? Try to find source
416 # by looking for method definitions instead, the
417 # by looking for method definitions instead, the
417 # __module__ in those classes is FakeModule.
418 # __module__ in those classes is FakeModule.
418 attrs = [getattr(data, aname) for aname in dir(data)]
419 attrs = [getattr(data, aname) for aname in dir(data)]
419 for attr in attrs:
420 for attr in attrs:
420 if not inspect.ismethod(attr):
421 if not inspect.ismethod(attr):
421 continue
422 continue
422 filename = find_file(attr)
423 filename = find_file(attr)
423 if filename and \
424 if filename and \
424 'fakemodule' not in filename.lower():
425 'fakemodule' not in filename.lower():
425 # change the attribute to be the edit
426 # change the attribute to be the edit
426 # target instead
427 # target instead
427 data = attr
428 data = attr
428 break
429 break
429
430
430 m = ipython_input_pat.match(os.path.basename(filename))
431 m = ipython_input_pat.match(os.path.basename(filename))
431 if m:
432 if m:
432 raise InteractivelyDefined(int(m.groups()[0]))
433 raise InteractivelyDefined(int(m.groups()[0]))
433
434
434 datafile = 1
435 datafile = 1
435 if filename is None:
436 if filename is None:
436 filename = make_filename(args)
437 filename = make_filename(args)
437 datafile = 1
438 datafile = 1
438 if filename is not None:
439 if filename is not None:
439 # only warn about this if we get a real name
440 # only warn about this if we get a real name
440 warn('Could not find file where `%s` is defined.\n'
441 warn('Could not find file where `%s` is defined.\n'
441 'Opening a file named `%s`' % (args, filename))
442 'Opening a file named `%s`' % (args, filename))
442 # Now, make sure we can actually read the source (if it was
443 # Now, make sure we can actually read the source (if it was
443 # in a temp file it's gone by now).
444 # in a temp file it's gone by now).
444 if datafile:
445 if datafile:
445 if lineno is None:
446 if lineno is None:
446 lineno = find_source_lines(data)
447 lineno = find_source_lines(data)
447 if lineno is None:
448 if lineno is None:
448 filename = make_filename(args)
449 filename = make_filename(args)
449 if filename is None:
450 if filename is None:
450 warn('The file where `%s` was defined '
451 warn('The file where `%s` was defined '
451 'cannot be read or found.' % data)
452 'cannot be read or found.' % data)
452 return (None, None, None)
453 return (None, None, None)
453 use_temp = False
454 use_temp = False
454
455
455 if use_temp:
456 if use_temp:
456 filename = shell.mktempfile(data)
457 filename = shell.mktempfile(data)
457 print 'IPython will make a temporary file named:',filename
458 print 'IPython will make a temporary file named:',filename
458
459
459 # use last_call to remember the state of the previous call, but don't
460 # use last_call to remember the state of the previous call, but don't
460 # let it be clobbered by successive '-p' calls.
461 # let it be clobbered by successive '-p' calls.
461 try:
462 try:
462 last_call[0] = shell.displayhook.prompt_count
463 last_call[0] = shell.displayhook.prompt_count
463 if not opts_prev:
464 if not opts_prev:
464 last_call[1] = args
465 last_call[1] = args
465 except:
466 except:
466 pass
467 pass
467
468
468
469
469 return filename, lineno, use_temp
470 return filename, lineno, use_temp
470
471
471 def _edit_macro(self,mname,macro):
472 def _edit_macro(self,mname,macro):
472 """open an editor with the macro data in a file"""
473 """open an editor with the macro data in a file"""
473 filename = self.shell.mktempfile(macro.value)
474 filename = self.shell.mktempfile(macro.value)
474 self.shell.hooks.editor(filename)
475 self.shell.hooks.editor(filename)
475
476
476 # and make a new macro object, to replace the old one
477 # and make a new macro object, to replace the old one
477 mfile = open(filename)
478 mfile = open(filename)
478 mvalue = mfile.read()
479 mvalue = mfile.read()
479 mfile.close()
480 mfile.close()
480 self.shell.user_ns[mname] = Macro(mvalue)
481 self.shell.user_ns[mname] = Macro(mvalue)
481
482
482 @skip_doctest
483 @skip_doctest
483 @line_magic
484 @line_magic
484 def edit(self, parameter_s='',last_call=['','']):
485 def edit(self, parameter_s='',last_call=['','']):
485 """Bring up an editor and execute the resulting code.
486 """Bring up an editor and execute the resulting code.
486
487
487 Usage:
488 Usage:
488 %edit [options] [args]
489 %edit [options] [args]
489
490
490 %edit runs IPython's editor hook. The default version of this hook is
491 %edit runs IPython's editor hook. The default version of this hook is
491 set to call the editor specified by your $EDITOR environment variable.
492 set to call the editor specified by your $EDITOR environment variable.
492 If this isn't found, it will default to vi under Linux/Unix and to
493 If this isn't found, it will default to vi under Linux/Unix and to
493 notepad under Windows. See the end of this docstring for how to change
494 notepad under Windows. See the end of this docstring for how to change
494 the editor hook.
495 the editor hook.
495
496
496 You can also set the value of this editor via the
497 You can also set the value of this editor via the
497 ``TerminalInteractiveShell.editor`` option in your configuration file.
498 ``TerminalInteractiveShell.editor`` option in your configuration file.
498 This is useful if you wish to use a different editor from your typical
499 This is useful if you wish to use a different editor from your typical
499 default with IPython (and for Windows users who typically don't set
500 default with IPython (and for Windows users who typically don't set
500 environment variables).
501 environment variables).
501
502
502 This command allows you to conveniently edit multi-line code right in
503 This command allows you to conveniently edit multi-line code right in
503 your IPython session.
504 your IPython session.
504
505
505 If called without arguments, %edit opens up an empty editor with a
506 If called without arguments, %edit opens up an empty editor with a
506 temporary file and will execute the contents of this file when you
507 temporary file and will execute the contents of this file when you
507 close it (don't forget to save it!).
508 close it (don't forget to save it!).
508
509
509
510
510 Options:
511 Options:
511
512
512 -n <number>: open the editor at a specified line number. By default,
513 -n <number>: open the editor at a specified line number. By default,
513 the IPython editor hook uses the unix syntax 'editor +N filename', but
514 the IPython editor hook uses the unix syntax 'editor +N filename', but
514 you can configure this by providing your own modified hook if your
515 you can configure this by providing your own modified hook if your
515 favorite editor supports line-number specifications with a different
516 favorite editor supports line-number specifications with a different
516 syntax.
517 syntax.
517
518
518 -p: this will call the editor with the same data as the previous time
519 -p: this will call the editor with the same data as the previous time
519 it was used, regardless of how long ago (in your current session) it
520 it was used, regardless of how long ago (in your current session) it
520 was.
521 was.
521
522
522 -r: use 'raw' input. This option only applies to input taken from the
523 -r: use 'raw' input. This option only applies to input taken from the
523 user's history. By default, the 'processed' history is used, so that
524 user's history. By default, the 'processed' history is used, so that
524 magics are loaded in their transformed version to valid Python. If
525 magics are loaded in their transformed version to valid Python. If
525 this option is given, the raw input as typed as the command line is
526 this option is given, the raw input as typed as the command line is
526 used instead. When you exit the editor, it will be executed by
527 used instead. When you exit the editor, it will be executed by
527 IPython's own processor.
528 IPython's own processor.
528
529
529 -x: do not execute the edited code immediately upon exit. This is
530 -x: do not execute the edited code immediately upon exit. This is
530 mainly useful if you are editing programs which need to be called with
531 mainly useful if you are editing programs which need to be called with
531 command line arguments, which you can then do using %run.
532 command line arguments, which you can then do using %run.
532
533
533
534
534 Arguments:
535 Arguments:
535
536
536 If arguments are given, the following possibilities exist:
537 If arguments are given, the following possibilities exist:
537
538
538 - If the argument is a filename, IPython will load that into the
539 - If the argument is a filename, IPython will load that into the
539 editor. It will execute its contents with execfile() when you exit,
540 editor. It will execute its contents with execfile() when you exit,
540 loading any code in the file into your interactive namespace.
541 loading any code in the file into your interactive namespace.
541
542
542 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
543 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
543 The syntax is the same as in the %history magic.
544 The syntax is the same as in the %history magic.
544
545
545 - If the argument is a string variable, its contents are loaded
546 - If the argument is a string variable, its contents are loaded
546 into the editor. You can thus edit any string which contains
547 into the editor. You can thus edit any string which contains
547 python code (including the result of previous edits).
548 python code (including the result of previous edits).
548
549
549 - If the argument is the name of an object (other than a string),
550 - If the argument is the name of an object (other than a string),
550 IPython will try to locate the file where it was defined and open the
551 IPython will try to locate the file where it was defined and open the
551 editor at the point where it is defined. You can use `%edit function`
552 editor at the point where it is defined. You can use `%edit function`
552 to load an editor exactly at the point where 'function' is defined,
553 to load an editor exactly at the point where 'function' is defined,
553 edit it and have the file be executed automatically.
554 edit it and have the file be executed automatically.
554
555
555 - If the object is a macro (see %macro for details), this opens up your
556 - If the object is a macro (see %macro for details), this opens up your
556 specified editor with a temporary file containing the macro's data.
557 specified editor with a temporary file containing the macro's data.
557 Upon exit, the macro is reloaded with the contents of the file.
558 Upon exit, the macro is reloaded with the contents of the file.
558
559
559 Note: opening at an exact line is only supported under Unix, and some
560 Note: opening at an exact line is only supported under Unix, and some
560 editors (like kedit and gedit up to Gnome 2.8) do not understand the
561 editors (like kedit and gedit up to Gnome 2.8) do not understand the
561 '+NUMBER' parameter necessary for this feature. Good editors like
562 '+NUMBER' parameter necessary for this feature. Good editors like
562 (X)Emacs, vi, jed, pico and joe all do.
563 (X)Emacs, vi, jed, pico and joe all do.
563
564
564 After executing your code, %edit will return as output the code you
565 After executing your code, %edit will return as output the code you
565 typed in the editor (except when it was an existing file). This way
566 typed in the editor (except when it was an existing file). This way
566 you can reload the code in further invocations of %edit as a variable,
567 you can reload the code in further invocations of %edit as a variable,
567 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
568 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
568 the output.
569 the output.
569
570
570 Note that %edit is also available through the alias %ed.
571 Note that %edit is also available through the alias %ed.
571
572
572 This is an example of creating a simple function inside the editor and
573 This is an example of creating a simple function inside the editor and
573 then modifying it. First, start up the editor::
574 then modifying it. First, start up the editor::
574
575
575 In [1]: edit
576 In [1]: edit
576 Editing... done. Executing edited code...
577 Editing... done. Executing edited code...
577 Out[1]: 'def foo():\\n print "foo() was defined in an editing
578 Out[1]: 'def foo():\\n print "foo() was defined in an editing
578 session"\\n'
579 session"\\n'
579
580
580 We can then call the function foo()::
581 We can then call the function foo()::
581
582
582 In [2]: foo()
583 In [2]: foo()
583 foo() was defined in an editing session
584 foo() was defined in an editing session
584
585
585 Now we edit foo. IPython automatically loads the editor with the
586 Now we edit foo. IPython automatically loads the editor with the
586 (temporary) file where foo() was previously defined::
587 (temporary) file where foo() was previously defined::
587
588
588 In [3]: edit foo
589 In [3]: edit foo
589 Editing... done. Executing edited code...
590 Editing... done. Executing edited code...
590
591
591 And if we call foo() again we get the modified version::
592 And if we call foo() again we get the modified version::
592
593
593 In [4]: foo()
594 In [4]: foo()
594 foo() has now been changed!
595 foo() has now been changed!
595
596
596 Here is an example of how to edit a code snippet successive
597 Here is an example of how to edit a code snippet successive
597 times. First we call the editor::
598 times. First we call the editor::
598
599
599 In [5]: edit
600 In [5]: edit
600 Editing... done. Executing edited code...
601 Editing... done. Executing edited code...
601 hello
602 hello
602 Out[5]: "print 'hello'\\n"
603 Out[5]: "print 'hello'\\n"
603
604
604 Now we call it again with the previous output (stored in _)::
605 Now we call it again with the previous output (stored in _)::
605
606
606 In [6]: edit _
607 In [6]: edit _
607 Editing... done. Executing edited code...
608 Editing... done. Executing edited code...
608 hello world
609 hello world
609 Out[6]: "print 'hello world'\\n"
610 Out[6]: "print 'hello world'\\n"
610
611
611 Now we call it with the output #8 (stored in _8, also as Out[8])::
612 Now we call it with the output #8 (stored in _8, also as Out[8])::
612
613
613 In [7]: edit _8
614 In [7]: edit _8
614 Editing... done. Executing edited code...
615 Editing... done. Executing edited code...
615 hello again
616 hello again
616 Out[7]: "print 'hello again'\\n"
617 Out[7]: "print 'hello again'\\n"
617
618
618
619
619 Changing the default editor hook:
620 Changing the default editor hook:
620
621
621 If you wish to write your own editor hook, you can put it in a
622 If you wish to write your own editor hook, you can put it in a
622 configuration file which you load at startup time. The default hook
623 configuration file which you load at startup time. The default hook
623 is defined in the IPython.core.hooks module, and you can use that as a
624 is defined in the IPython.core.hooks module, and you can use that as a
624 starting example for further modifications. That file also has
625 starting example for further modifications. That file also has
625 general instructions on how to set a new hook for use once you've
626 general instructions on how to set a new hook for use once you've
626 defined it."""
627 defined it."""
627 opts,args = self.parse_options(parameter_s,'prxn:')
628 opts,args = self.parse_options(parameter_s,'prxn:')
628
629
629 try:
630 try:
630 filename, lineno, is_temp = self._find_edit_target(self.shell,
631 filename, lineno, is_temp = self._find_edit_target(self.shell,
631 args, opts, last_call)
632 args, opts, last_call)
632 except MacroToEdit as e:
633 except MacroToEdit as e:
633 self._edit_macro(args, e.args[0])
634 self._edit_macro(args, e.args[0])
634 return
635 return
635 except InteractivelyDefined as e:
636 except InteractivelyDefined as e:
636 print "Editing In[%i]" % e.index
637 print "Editing In[%i]" % e.index
637 args = str(e.index)
638 args = str(e.index)
638 filename, lineno, is_temp = self._find_edit_target(self.shell,
639 filename, lineno, is_temp = self._find_edit_target(self.shell,
639 args, opts, last_call)
640 args, opts, last_call)
640 if filename is None:
641 if filename is None:
641 # nothing was found, warnings have already been issued,
642 # nothing was found, warnings have already been issued,
642 # just give up.
643 # just give up.
643 return
644 return
644
645
645 # do actual editing here
646 # do actual editing here
646 print 'Editing...',
647 print 'Editing...',
647 sys.stdout.flush()
648 sys.stdout.flush()
648 try:
649 try:
649 # Quote filenames that may have spaces in them
650 # Quote filenames that may have spaces in them
650 if ' ' in filename:
651 if ' ' in filename:
651 filename = "'%s'" % filename
652 filename = "'%s'" % filename
652 self.shell.hooks.editor(filename,lineno)
653 self.shell.hooks.editor(filename,lineno)
653 except TryNext:
654 except TryNext:
654 warn('Could not open editor')
655 warn('Could not open editor')
655 return
656 return
656
657
657 # XXX TODO: should this be generalized for all string vars?
658 # XXX TODO: should this be generalized for all string vars?
658 # For now, this is special-cased to blocks created by cpaste
659 # For now, this is special-cased to blocks created by cpaste
659 if args.strip() == 'pasted_block':
660 if args.strip() == 'pasted_block':
660 with open(filename, 'r') as f:
661 with open(filename, 'r') as f:
661 self.shell.user_ns['pasted_block'] = f.read()
662 self.shell.user_ns['pasted_block'] = f.read()
662
663
663 if 'x' in opts: # -x prevents actual execution
664 if 'x' in opts: # -x prevents actual execution
664 print
665 print
665 else:
666 else:
666 print 'done. Executing edited code...'
667 print 'done. Executing edited code...'
667 with preserve_keys(self.shell.user_ns, '__file__'):
668 with preserve_keys(self.shell.user_ns, '__file__'):
668 if not is_temp:
669 if not is_temp:
669 self.shell.user_ns['__file__'] = filename
670 self.shell.user_ns['__file__'] = filename
670 if 'r' in opts: # Untranslated IPython code
671 if 'r' in opts: # Untranslated IPython code
671 with open(filename, 'r') as f:
672 with open(filename, 'r') as f:
672 source = f.read()
673 source = f.read()
673 self.shell.run_cell(source, store_history=False)
674 self.shell.run_cell(source, store_history=False)
674 else:
675 else:
675 self.shell.safe_execfile(filename, self.shell.user_ns,
676 self.shell.safe_execfile(filename, self.shell.user_ns,
676 self.shell.user_ns)
677 self.shell.user_ns)
677
678
678 if is_temp:
679 if is_temp:
679 try:
680 try:
680 return open(filename).read()
681 return open(filename).read()
681 except IOError as msg:
682 except IOError as msg:
682 if msg.filename == filename:
683 if msg.filename == filename:
683 warn('File not found. Did you forget to save?')
684 warn('File not found. Did you forget to save?')
684 return
685 return
685 else:
686 else:
686 self.shell.showtraceback()
687 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\n\n\nclass A: pass\n\n\n"""
65 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\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 = [([], ['a']),
67 expected = [([], ['a']),
68 (["def b():\n return 42\n"], []),
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\n"], []),
70 (["class A: pass\n", "def b():\n return 42\n"], []),
71 (["class A: pass\n"], ['a']),
71 (["class A: pass\n"], ['a']),
72 ([], ['z'])]
72 ([], ['z'])]
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"), ([], ['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