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