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