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