##// END OF EJS Templates
Merge pull request #5677 from takluyver/i5676...
Min RK -
r16372:a4f99e0e merge
parent child Browse files
Show More
@@ -1,741 +1,740 b''
1 """Implementation of magic functions for interaction with the OS.
1 """Implementation of magic functions for interaction with the OS.
2
2
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 builtin.
4 builtin.
5 """
5 """
6 from __future__ import print_function
6 from __future__ import print_function
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2012 The IPython Development Team.
8 # Copyright (c) 2012 The IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Stdlib
19 # Stdlib
20 import io
20 import io
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 from pprint import pformat
24 from pprint import pformat
25
25
26 # Our own packages
26 # Our own packages
27 from IPython.core import magic_arguments
27 from IPython.core import magic_arguments
28 from IPython.core import oinspect
28 from IPython.core import oinspect
29 from IPython.core import page
29 from IPython.core import page
30 from IPython.core.alias import AliasError, Alias
30 from IPython.core.alias import AliasError, Alias
31 from IPython.core.error import UsageError
31 from IPython.core.error import UsageError
32 from IPython.core.magic import (
32 from IPython.core.magic import (
33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
34 )
34 )
35 from IPython.testing.skipdoctest import skip_doctest
35 from IPython.testing.skipdoctest import skip_doctest
36 from IPython.utils.openpy import source_to_unicode
36 from IPython.utils.openpy import source_to_unicode
37 from IPython.utils.path import unquote_filename
37 from IPython.utils.path import unquote_filename
38 from IPython.utils.process import abbrev_cwd
38 from IPython.utils.process import abbrev_cwd
39 from IPython.utils import py3compat
39 from IPython.utils import py3compat
40 from IPython.utils.py3compat import unicode_type
40 from IPython.utils.py3compat import unicode_type
41 from IPython.utils.terminal import set_term_title
41 from IPython.utils.terminal import set_term_title
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Magic implementation classes
44 # Magic implementation classes
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 @magics_class
46 @magics_class
47 class OSMagics(Magics):
47 class OSMagics(Magics):
48 """Magics to interact with the underlying OS (shell-type functionality).
48 """Magics to interact with the underlying OS (shell-type functionality).
49 """
49 """
50
50
51 @skip_doctest
51 @skip_doctest
52 @line_magic
52 @line_magic
53 def alias(self, parameter_s=''):
53 def alias(self, parameter_s=''):
54 """Define an alias for a system command.
54 """Define an alias for a system command.
55
55
56 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
56 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
57
57
58 Then, typing 'alias_name params' will execute the system command 'cmd
58 Then, typing 'alias_name params' will execute the system command 'cmd
59 params' (from your underlying operating system).
59 params' (from your underlying operating system).
60
60
61 Aliases have lower precedence than magic functions and Python normal
61 Aliases have lower precedence than magic functions and Python normal
62 variables, so if 'foo' is both a Python variable and an alias, the
62 variables, so if 'foo' is both a Python variable and an alias, the
63 alias can not be executed until 'del foo' removes the Python variable.
63 alias can not be executed until 'del foo' removes the Python variable.
64
64
65 You can use the %l specifier in an alias definition to represent the
65 You can use the %l specifier in an alias definition to represent the
66 whole line when the alias is called. For example::
66 whole line when the alias is called. For example::
67
67
68 In [2]: alias bracket echo "Input in brackets: <%l>"
68 In [2]: alias bracket echo "Input in brackets: <%l>"
69 In [3]: bracket hello world
69 In [3]: bracket hello world
70 Input in brackets: <hello world>
70 Input in brackets: <hello world>
71
71
72 You can also define aliases with parameters using %s specifiers (one
72 You can also define aliases with parameters using %s specifiers (one
73 per parameter)::
73 per parameter)::
74
74
75 In [1]: alias parts echo first %s second %s
75 In [1]: alias parts echo first %s second %s
76 In [2]: %parts A B
76 In [2]: %parts A B
77 first A second B
77 first A second B
78 In [3]: %parts A
78 In [3]: %parts A
79 Incorrect number of arguments: 2 expected.
79 Incorrect number of arguments: 2 expected.
80 parts is an alias to: 'echo first %s second %s'
80 parts is an alias to: 'echo first %s second %s'
81
81
82 Note that %l and %s are mutually exclusive. You can only use one or
82 Note that %l and %s are mutually exclusive. You can only use one or
83 the other in your aliases.
83 the other in your aliases.
84
84
85 Aliases expand Python variables just like system calls using ! or !!
85 Aliases expand Python variables just like system calls using ! or !!
86 do: all expressions prefixed with '$' get expanded. For details of
86 do: all expressions prefixed with '$' get expanded. For details of
87 the semantic rules, see PEP-215:
87 the semantic rules, see PEP-215:
88 http://www.python.org/peps/pep-0215.html. This is the library used by
88 http://www.python.org/peps/pep-0215.html. This is the library used by
89 IPython for variable expansion. If you want to access a true shell
89 IPython for variable expansion. If you want to access a true shell
90 variable, an extra $ is necessary to prevent its expansion by
90 variable, an extra $ is necessary to prevent its expansion by
91 IPython::
91 IPython::
92
92
93 In [6]: alias show echo
93 In [6]: alias show echo
94 In [7]: PATH='A Python string'
94 In [7]: PATH='A Python string'
95 In [8]: show $PATH
95 In [8]: show $PATH
96 A Python string
96 A Python string
97 In [9]: show $$PATH
97 In [9]: show $$PATH
98 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
98 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
99
99
100 You can use the alias facility to acess all of $PATH. See the %rehash
100 You can use the alias facility to acess all of $PATH. See the %rehash
101 and %rehashx functions, which automatically create aliases for the
101 and %rehashx functions, which automatically create aliases for the
102 contents of your $PATH.
102 contents of your $PATH.
103
103
104 If called with no parameters, %alias prints the current alias table."""
104 If called with no parameters, %alias prints the current alias table."""
105
105
106 par = parameter_s.strip()
106 par = parameter_s.strip()
107 if not par:
107 if not par:
108 aliases = sorted(self.shell.alias_manager.aliases)
108 aliases = sorted(self.shell.alias_manager.aliases)
109 # stored = self.shell.db.get('stored_aliases', {} )
109 # stored = self.shell.db.get('stored_aliases', {} )
110 # for k, v in stored:
110 # for k, v in stored:
111 # atab.append(k, v[0])
111 # atab.append(k, v[0])
112
112
113 print("Total number of aliases:", len(aliases))
113 print("Total number of aliases:", len(aliases))
114 sys.stdout.flush()
114 sys.stdout.flush()
115 return aliases
115 return aliases
116
116
117 # Now try to define a new one
117 # Now try to define a new one
118 try:
118 try:
119 alias,cmd = par.split(None, 1)
119 alias,cmd = par.split(None, 1)
120 except TypeError:
120 except TypeError:
121 print(oinspect.getdoc(self.alias))
121 print(oinspect.getdoc(self.alias))
122 return
122 return
123
123
124 try:
124 try:
125 self.shell.alias_manager.define_alias(alias, cmd)
125 self.shell.alias_manager.define_alias(alias, cmd)
126 except AliasError as e:
126 except AliasError as e:
127 print(e)
127 print(e)
128 # end magic_alias
128 # end magic_alias
129
129
130 @line_magic
130 @line_magic
131 def unalias(self, parameter_s=''):
131 def unalias(self, parameter_s=''):
132 """Remove an alias"""
132 """Remove an alias"""
133
133
134 aname = parameter_s.strip()
134 aname = parameter_s.strip()
135 try:
135 try:
136 self.shell.alias_manager.undefine_alias(aname)
136 self.shell.alias_manager.undefine_alias(aname)
137 except ValueError as e:
137 except ValueError as e:
138 print(e)
138 print(e)
139 return
139 return
140
140
141 stored = self.shell.db.get('stored_aliases', {} )
141 stored = self.shell.db.get('stored_aliases', {} )
142 if aname in stored:
142 if aname in stored:
143 print("Removing %stored alias",aname)
143 print("Removing %stored alias",aname)
144 del stored[aname]
144 del stored[aname]
145 self.shell.db['stored_aliases'] = stored
145 self.shell.db['stored_aliases'] = stored
146
146
147 @line_magic
147 @line_magic
148 def rehashx(self, parameter_s=''):
148 def rehashx(self, parameter_s=''):
149 """Update the alias table with all executable files in $PATH.
149 """Update the alias table with all executable files in $PATH.
150
150
151 This version explicitly checks that every entry in $PATH is a file
151 This version explicitly checks that every entry in $PATH is a file
152 with execute access (os.X_OK), so it is much slower than %rehash.
152 with execute access (os.X_OK), so it is much slower than %rehash.
153
153
154 Under Windows, it checks executability as a match against a
154 Under Windows, it checks executability as a match against a
155 '|'-separated string of extensions, stored in the IPython config
155 '|'-separated string of extensions, stored in the IPython config
156 variable win_exec_ext. This defaults to 'exe|com|bat'.
156 variable win_exec_ext. This defaults to 'exe|com|bat'.
157
157
158 This function also resets the root module cache of module completer,
158 This function also resets the root module cache of module completer,
159 used on slow filesystems.
159 used on slow filesystems.
160 """
160 """
161 from IPython.core.alias import InvalidAliasError
161 from IPython.core.alias import InvalidAliasError
162
162
163 # for the benefit of module completer in ipy_completers.py
163 # for the benefit of module completer in ipy_completers.py
164 del self.shell.db['rootmodules_cache']
164 del self.shell.db['rootmodules_cache']
165
165
166 path = [os.path.abspath(os.path.expanduser(p)) for p in
166 path = [os.path.abspath(os.path.expanduser(p)) for p in
167 os.environ.get('PATH','').split(os.pathsep)]
167 os.environ.get('PATH','').split(os.pathsep)]
168 path = filter(os.path.isdir,path)
168 path = filter(os.path.isdir,path)
169
169
170 syscmdlist = []
170 syscmdlist = []
171 # Now define isexec in a cross platform manner.
171 # Now define isexec in a cross platform manner.
172 if os.name == 'posix':
172 if os.name == 'posix':
173 isexec = lambda fname:os.path.isfile(fname) and \
173 isexec = lambda fname:os.path.isfile(fname) and \
174 os.access(fname,os.X_OK)
174 os.access(fname,os.X_OK)
175 else:
175 else:
176 try:
176 try:
177 winext = os.environ['pathext'].replace(';','|').replace('.','')
177 winext = os.environ['pathext'].replace(';','|').replace('.','')
178 except KeyError:
178 except KeyError:
179 winext = 'exe|com|bat|py'
179 winext = 'exe|com|bat|py'
180 if 'py' not in winext:
180 if 'py' not in winext:
181 winext += '|py'
181 winext += '|py'
182 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
182 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
183 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
183 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
184 savedir = py3compat.getcwd()
184 savedir = py3compat.getcwd()
185
185
186 # Now walk the paths looking for executables to alias.
186 # Now walk the paths looking for executables to alias.
187 try:
187 try:
188 # write the whole loop for posix/Windows so we don't have an if in
188 # write the whole loop for posix/Windows so we don't have an if in
189 # the innermost part
189 # the innermost part
190 if os.name == 'posix':
190 if os.name == 'posix':
191 for pdir in path:
191 for pdir in path:
192 os.chdir(pdir)
192 os.chdir(pdir)
193 for ff in os.listdir(pdir):
193 for ff in os.listdir(pdir):
194 if isexec(ff):
194 if isexec(ff):
195 try:
195 try:
196 # Removes dots from the name since ipython
196 # Removes dots from the name since ipython
197 # will assume names with dots to be python.
197 # will assume names with dots to be python.
198 if not self.shell.alias_manager.is_alias(ff):
198 if not self.shell.alias_manager.is_alias(ff):
199 self.shell.alias_manager.define_alias(
199 self.shell.alias_manager.define_alias(
200 ff.replace('.',''), ff)
200 ff.replace('.',''), ff)
201 except InvalidAliasError:
201 except InvalidAliasError:
202 pass
202 pass
203 else:
203 else:
204 syscmdlist.append(ff)
204 syscmdlist.append(ff)
205 else:
205 else:
206 no_alias = Alias.blacklist
206 no_alias = Alias.blacklist
207 for pdir in path:
207 for pdir in path:
208 os.chdir(pdir)
208 os.chdir(pdir)
209 for ff in os.listdir(pdir):
209 for ff in os.listdir(pdir):
210 base, ext = os.path.splitext(ff)
210 base, ext = os.path.splitext(ff)
211 if isexec(ff) and base.lower() not in no_alias:
211 if isexec(ff) and base.lower() not in no_alias:
212 if ext.lower() == '.exe':
212 if ext.lower() == '.exe':
213 ff = base
213 ff = base
214 try:
214 try:
215 # Removes dots from the name since ipython
215 # Removes dots from the name since ipython
216 # will assume names with dots to be python.
216 # will assume names with dots to be python.
217 self.shell.alias_manager.define_alias(
217 self.shell.alias_manager.define_alias(
218 base.lower().replace('.',''), ff)
218 base.lower().replace('.',''), ff)
219 except InvalidAliasError:
219 except InvalidAliasError:
220 pass
220 pass
221 syscmdlist.append(ff)
221 syscmdlist.append(ff)
222 self.shell.db['syscmdlist'] = syscmdlist
222 self.shell.db['syscmdlist'] = syscmdlist
223 finally:
223 finally:
224 os.chdir(savedir)
224 os.chdir(savedir)
225
225
226 @skip_doctest
226 @skip_doctest
227 @line_magic
227 @line_magic
228 def pwd(self, parameter_s=''):
228 def pwd(self, parameter_s=''):
229 """Return the current working directory path.
229 """Return the current working directory path.
230
230
231 Examples
231 Examples
232 --------
232 --------
233 ::
233 ::
234
234
235 In [9]: pwd
235 In [9]: pwd
236 Out[9]: '/home/tsuser/sprint/ipython'
236 Out[9]: '/home/tsuser/sprint/ipython'
237 """
237 """
238 return py3compat.getcwd()
238 return py3compat.getcwd()
239
239
240 @skip_doctest
240 @skip_doctest
241 @line_magic
241 @line_magic
242 def cd(self, parameter_s=''):
242 def cd(self, parameter_s=''):
243 """Change the current working directory.
243 """Change the current working directory.
244
244
245 This command automatically maintains an internal list of directories
245 This command automatically maintains an internal list of directories
246 you visit during your IPython session, in the variable _dh. The
246 you visit during your IPython session, in the variable _dh. The
247 command %dhist shows this history nicely formatted. You can also
247 command %dhist shows this history nicely formatted. You can also
248 do 'cd -<tab>' to see directory history conveniently.
248 do 'cd -<tab>' to see directory history conveniently.
249
249
250 Usage:
250 Usage:
251
251
252 cd 'dir': changes to directory 'dir'.
252 cd 'dir': changes to directory 'dir'.
253
253
254 cd -: changes to the last visited directory.
254 cd -: changes to the last visited directory.
255
255
256 cd -<n>: changes to the n-th directory in the directory history.
256 cd -<n>: changes to the n-th directory in the directory history.
257
257
258 cd --foo: change to directory that matches 'foo' in history
258 cd --foo: change to directory that matches 'foo' in history
259
259
260 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
260 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
261 (note: cd <bookmark_name> is enough if there is no
261 (note: cd <bookmark_name> is enough if there is no
262 directory <bookmark_name>, but a bookmark with the name exists.)
262 directory <bookmark_name>, but a bookmark with the name exists.)
263 'cd -b <tab>' allows you to tab-complete bookmark names.
263 'cd -b <tab>' allows you to tab-complete bookmark names.
264
264
265 Options:
265 Options:
266
266
267 -q: quiet. Do not print the working directory after the cd command is
267 -q: quiet. Do not print the working directory after the cd command is
268 executed. By default IPython's cd command does print this directory,
268 executed. By default IPython's cd command does print this directory,
269 since the default prompts do not display path information.
269 since the default prompts do not display path information.
270
270
271 Note that !cd doesn't work for this purpose because the shell where
271 Note that !cd doesn't work for this purpose because the shell where
272 !command runs is immediately discarded after executing 'command'.
272 !command runs is immediately discarded after executing 'command'.
273
273
274 Examples
274 Examples
275 --------
275 --------
276 ::
276 ::
277
277
278 In [10]: cd parent/child
278 In [10]: cd parent/child
279 /home/tsuser/parent/child
279 /home/tsuser/parent/child
280 """
280 """
281
281
282 oldcwd = py3compat.getcwd()
282 oldcwd = py3compat.getcwd()
283 numcd = re.match(r'(-)(\d+)$',parameter_s)
283 numcd = re.match(r'(-)(\d+)$',parameter_s)
284 # jump in directory history by number
284 # jump in directory history by number
285 if numcd:
285 if numcd:
286 nn = int(numcd.group(2))
286 nn = int(numcd.group(2))
287 try:
287 try:
288 ps = self.shell.user_ns['_dh'][nn]
288 ps = self.shell.user_ns['_dh'][nn]
289 except IndexError:
289 except IndexError:
290 print('The requested directory does not exist in history.')
290 print('The requested directory does not exist in history.')
291 return
291 return
292 else:
292 else:
293 opts = {}
293 opts = {}
294 elif parameter_s.startswith('--'):
294 elif parameter_s.startswith('--'):
295 ps = None
295 ps = None
296 fallback = None
296 fallback = None
297 pat = parameter_s[2:]
297 pat = parameter_s[2:]
298 dh = self.shell.user_ns['_dh']
298 dh = self.shell.user_ns['_dh']
299 # first search only by basename (last component)
299 # first search only by basename (last component)
300 for ent in reversed(dh):
300 for ent in reversed(dh):
301 if pat in os.path.basename(ent) and os.path.isdir(ent):
301 if pat in os.path.basename(ent) and os.path.isdir(ent):
302 ps = ent
302 ps = ent
303 break
303 break
304
304
305 if fallback is None and pat in ent and os.path.isdir(ent):
305 if fallback is None and pat in ent and os.path.isdir(ent):
306 fallback = ent
306 fallback = ent
307
307
308 # if we have no last part match, pick the first full path match
308 # if we have no last part match, pick the first full path match
309 if ps is None:
309 if ps is None:
310 ps = fallback
310 ps = fallback
311
311
312 if ps is None:
312 if ps is None:
313 print("No matching entry in directory history")
313 print("No matching entry in directory history")
314 return
314 return
315 else:
315 else:
316 opts = {}
316 opts = {}
317
317
318
318
319 else:
319 else:
320 #turn all non-space-escaping backslashes to slashes,
320 #turn all non-space-escaping backslashes to slashes,
321 # for c:\windows\directory\names\
321 # for c:\windows\directory\names\
322 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
322 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
323 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
323 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
324 # jump to previous
324 # jump to previous
325 if ps == '-':
325 if ps == '-':
326 try:
326 try:
327 ps = self.shell.user_ns['_dh'][-2]
327 ps = self.shell.user_ns['_dh'][-2]
328 except IndexError:
328 except IndexError:
329 raise UsageError('%cd -: No previous directory to change to.')
329 raise UsageError('%cd -: No previous directory to change to.')
330 # jump to bookmark if needed
330 # jump to bookmark if needed
331 else:
331 else:
332 if not os.path.isdir(ps) or 'b' in opts:
332 if not os.path.isdir(ps) or 'b' in opts:
333 bkms = self.shell.db.get('bookmarks', {})
333 bkms = self.shell.db.get('bookmarks', {})
334
334
335 if ps in bkms:
335 if ps in bkms:
336 target = bkms[ps]
336 target = bkms[ps]
337 print('(bookmark:%s) -> %s' % (ps, target))
337 print('(bookmark:%s) -> %s' % (ps, target))
338 ps = target
338 ps = target
339 else:
339 else:
340 if 'b' in opts:
340 if 'b' in opts:
341 raise UsageError("Bookmark '%s' not found. "
341 raise UsageError("Bookmark '%s' not found. "
342 "Use '%%bookmark -l' to see your bookmarks." % ps)
342 "Use '%%bookmark -l' to see your bookmarks." % ps)
343
343
344 # strip extra quotes on Windows, because os.chdir doesn't like them
344 # strip extra quotes on Windows, because os.chdir doesn't like them
345 ps = unquote_filename(ps)
345 ps = unquote_filename(ps)
346 # at this point ps should point to the target dir
346 # at this point ps should point to the target dir
347 if ps:
347 if ps:
348 try:
348 try:
349 os.chdir(os.path.expanduser(ps))
349 os.chdir(os.path.expanduser(ps))
350 if hasattr(self.shell, 'term_title') and self.shell.term_title:
350 if hasattr(self.shell, 'term_title') and self.shell.term_title:
351 set_term_title('IPython: ' + abbrev_cwd())
351 set_term_title('IPython: ' + abbrev_cwd())
352 except OSError:
352 except OSError:
353 print(sys.exc_info()[1])
353 print(sys.exc_info()[1])
354 else:
354 else:
355 cwd = py3compat.getcwd()
355 cwd = py3compat.getcwd()
356 dhist = self.shell.user_ns['_dh']
356 dhist = self.shell.user_ns['_dh']
357 if oldcwd != cwd:
357 if oldcwd != cwd:
358 dhist.append(cwd)
358 dhist.append(cwd)
359 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
359 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
360
360
361 else:
361 else:
362 os.chdir(self.shell.home_dir)
362 os.chdir(self.shell.home_dir)
363 if hasattr(self.shell, 'term_title') and self.shell.term_title:
363 if hasattr(self.shell, 'term_title') and self.shell.term_title:
364 set_term_title('IPython: ' + '~')
364 set_term_title('IPython: ' + '~')
365 cwd = py3compat.getcwd()
365 cwd = py3compat.getcwd()
366 dhist = self.shell.user_ns['_dh']
366 dhist = self.shell.user_ns['_dh']
367
367
368 if oldcwd != cwd:
368 if oldcwd != cwd:
369 dhist.append(cwd)
369 dhist.append(cwd)
370 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
370 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
371 if not 'q' in opts and self.shell.user_ns['_dh']:
371 if not 'q' in opts and self.shell.user_ns['_dh']:
372 print(self.shell.user_ns['_dh'][-1])
372 print(self.shell.user_ns['_dh'][-1])
373
373
374
374
375 @line_magic
375 @line_magic
376 def env(self, parameter_s=''):
376 def env(self, parameter_s=''):
377 """List environment variables."""
377 """List environment variables."""
378
378
379 return dict(os.environ)
379 return dict(os.environ)
380
380
381 @line_magic
381 @line_magic
382 def pushd(self, parameter_s=''):
382 def pushd(self, parameter_s=''):
383 """Place the current dir on stack and change directory.
383 """Place the current dir on stack and change directory.
384
384
385 Usage:\\
385 Usage:\\
386 %pushd ['dirname']
386 %pushd ['dirname']
387 """
387 """
388
388
389 dir_s = self.shell.dir_stack
389 dir_s = self.shell.dir_stack
390 tgt = os.path.expanduser(unquote_filename(parameter_s))
390 tgt = os.path.expanduser(unquote_filename(parameter_s))
391 cwd = py3compat.getcwd().replace(self.shell.home_dir,'~')
391 cwd = py3compat.getcwd().replace(self.shell.home_dir,'~')
392 if tgt:
392 if tgt:
393 self.cd(parameter_s)
393 self.cd(parameter_s)
394 dir_s.insert(0,cwd)
394 dir_s.insert(0,cwd)
395 return self.shell.magic('dirs')
395 return self.shell.magic('dirs')
396
396
397 @line_magic
397 @line_magic
398 def popd(self, parameter_s=''):
398 def popd(self, parameter_s=''):
399 """Change to directory popped off the top of the stack.
399 """Change to directory popped off the top of the stack.
400 """
400 """
401 if not self.shell.dir_stack:
401 if not self.shell.dir_stack:
402 raise UsageError("%popd on empty stack")
402 raise UsageError("%popd on empty stack")
403 top = self.shell.dir_stack.pop(0)
403 top = self.shell.dir_stack.pop(0)
404 self.cd(top)
404 self.cd(top)
405 print("popd ->",top)
405 print("popd ->",top)
406
406
407 @line_magic
407 @line_magic
408 def dirs(self, parameter_s=''):
408 def dirs(self, parameter_s=''):
409 """Return the current directory stack."""
409 """Return the current directory stack."""
410
410
411 return self.shell.dir_stack
411 return self.shell.dir_stack
412
412
413 @line_magic
413 @line_magic
414 def dhist(self, parameter_s=''):
414 def dhist(self, parameter_s=''):
415 """Print your history of visited directories.
415 """Print your history of visited directories.
416
416
417 %dhist -> print full history\\
417 %dhist -> print full history\\
418 %dhist n -> print last n entries only\\
418 %dhist n -> print last n entries only\\
419 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
419 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
420
420
421 This history is automatically maintained by the %cd command, and
421 This history is automatically maintained by the %cd command, and
422 always available as the global list variable _dh. You can use %cd -<n>
422 always available as the global list variable _dh. You can use %cd -<n>
423 to go to directory number <n>.
423 to go to directory number <n>.
424
424
425 Note that most of time, you should view directory history by entering
425 Note that most of time, you should view directory history by entering
426 cd -<TAB>.
426 cd -<TAB>.
427
427
428 """
428 """
429
429
430 dh = self.shell.user_ns['_dh']
430 dh = self.shell.user_ns['_dh']
431 if parameter_s:
431 if parameter_s:
432 try:
432 try:
433 args = map(int,parameter_s.split())
433 args = map(int,parameter_s.split())
434 except:
434 except:
435 self.arg_err(self.dhist)
435 self.arg_err(self.dhist)
436 return
436 return
437 if len(args) == 1:
437 if len(args) == 1:
438 ini,fin = max(len(dh)-(args[0]),0),len(dh)
438 ini,fin = max(len(dh)-(args[0]),0),len(dh)
439 elif len(args) == 2:
439 elif len(args) == 2:
440 ini,fin = args
440 ini,fin = args
441 fin = min(fin, len(dh))
441 fin = min(fin, len(dh))
442 else:
442 else:
443 self.arg_err(self.dhist)
443 self.arg_err(self.dhist)
444 return
444 return
445 else:
445 else:
446 ini,fin = 0,len(dh)
446 ini,fin = 0,len(dh)
447 print('Directory history (kept in _dh)')
447 print('Directory history (kept in _dh)')
448 for i in range(ini, fin):
448 for i in range(ini, fin):
449 print("%d: %s" % (i, dh[i]))
449 print("%d: %s" % (i, dh[i]))
450
450
451 @skip_doctest
451 @skip_doctest
452 @line_magic
452 @line_magic
453 def sc(self, parameter_s=''):
453 def sc(self, parameter_s=''):
454 """Shell capture - run shell command and capture output (DEPRECATED use !).
454 """Shell capture - run shell command and capture output (DEPRECATED use !).
455
455
456 DEPRECATED. Suboptimal, retained for backwards compatibility.
456 DEPRECATED. Suboptimal, retained for backwards compatibility.
457
457
458 You should use the form 'var = !command' instead. Example:
458 You should use the form 'var = !command' instead. Example:
459
459
460 "%sc -l myfiles = ls ~" should now be written as
460 "%sc -l myfiles = ls ~" should now be written as
461
461
462 "myfiles = !ls ~"
462 "myfiles = !ls ~"
463
463
464 myfiles.s, myfiles.l and myfiles.n still apply as documented
464 myfiles.s, myfiles.l and myfiles.n still apply as documented
465 below.
465 below.
466
466
467 --
467 --
468 %sc [options] varname=command
468 %sc [options] varname=command
469
469
470 IPython will run the given command using commands.getoutput(), and
470 IPython will run the given command using commands.getoutput(), and
471 will then update the user's interactive namespace with a variable
471 will then update the user's interactive namespace with a variable
472 called varname, containing the value of the call. Your command can
472 called varname, containing the value of the call. Your command can
473 contain shell wildcards, pipes, etc.
473 contain shell wildcards, pipes, etc.
474
474
475 The '=' sign in the syntax is mandatory, and the variable name you
475 The '=' sign in the syntax is mandatory, and the variable name you
476 supply must follow Python's standard conventions for valid names.
476 supply must follow Python's standard conventions for valid names.
477
477
478 (A special format without variable name exists for internal use)
478 (A special format without variable name exists for internal use)
479
479
480 Options:
480 Options:
481
481
482 -l: list output. Split the output on newlines into a list before
482 -l: list output. Split the output on newlines into a list before
483 assigning it to the given variable. By default the output is stored
483 assigning it to the given variable. By default the output is stored
484 as a single string.
484 as a single string.
485
485
486 -v: verbose. Print the contents of the variable.
486 -v: verbose. Print the contents of the variable.
487
487
488 In most cases you should not need to split as a list, because the
488 In most cases you should not need to split as a list, because the
489 returned value is a special type of string which can automatically
489 returned value is a special type of string which can automatically
490 provide its contents either as a list (split on newlines) or as a
490 provide its contents either as a list (split on newlines) or as a
491 space-separated string. These are convenient, respectively, either
491 space-separated string. These are convenient, respectively, either
492 for sequential processing or to be passed to a shell command.
492 for sequential processing or to be passed to a shell command.
493
493
494 For example::
494 For example::
495
495
496 # Capture into variable a
496 # Capture into variable a
497 In [1]: sc a=ls *py
497 In [1]: sc a=ls *py
498
498
499 # a is a string with embedded newlines
499 # a is a string with embedded newlines
500 In [2]: a
500 In [2]: a
501 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
501 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
502
502
503 # which can be seen as a list:
503 # which can be seen as a list:
504 In [3]: a.l
504 In [3]: a.l
505 Out[3]: ['setup.py', 'win32_manual_post_install.py']
505 Out[3]: ['setup.py', 'win32_manual_post_install.py']
506
506
507 # or as a whitespace-separated string:
507 # or as a whitespace-separated string:
508 In [4]: a.s
508 In [4]: a.s
509 Out[4]: 'setup.py win32_manual_post_install.py'
509 Out[4]: 'setup.py win32_manual_post_install.py'
510
510
511 # a.s is useful to pass as a single command line:
511 # a.s is useful to pass as a single command line:
512 In [5]: !wc -l $a.s
512 In [5]: !wc -l $a.s
513 146 setup.py
513 146 setup.py
514 130 win32_manual_post_install.py
514 130 win32_manual_post_install.py
515 276 total
515 276 total
516
516
517 # while the list form is useful to loop over:
517 # while the list form is useful to loop over:
518 In [6]: for f in a.l:
518 In [6]: for f in a.l:
519 ...: !wc -l $f
519 ...: !wc -l $f
520 ...:
520 ...:
521 146 setup.py
521 146 setup.py
522 130 win32_manual_post_install.py
522 130 win32_manual_post_install.py
523
523
524 Similarly, the lists returned by the -l option are also special, in
524 Similarly, the lists returned by the -l option are also special, in
525 the sense that you can equally invoke the .s attribute on them to
525 the sense that you can equally invoke the .s attribute on them to
526 automatically get a whitespace-separated string from their contents::
526 automatically get a whitespace-separated string from their contents::
527
527
528 In [7]: sc -l b=ls *py
528 In [7]: sc -l b=ls *py
529
529
530 In [8]: b
530 In [8]: b
531 Out[8]: ['setup.py', 'win32_manual_post_install.py']
531 Out[8]: ['setup.py', 'win32_manual_post_install.py']
532
532
533 In [9]: b.s
533 In [9]: b.s
534 Out[9]: 'setup.py win32_manual_post_install.py'
534 Out[9]: 'setup.py win32_manual_post_install.py'
535
535
536 In summary, both the lists and strings used for output capture have
536 In summary, both the lists and strings used for output capture have
537 the following special attributes::
537 the following special attributes::
538
538
539 .l (or .list) : value as list.
539 .l (or .list) : value as list.
540 .n (or .nlstr): value as newline-separated string.
540 .n (or .nlstr): value as newline-separated string.
541 .s (or .spstr): value as space-separated string.
541 .s (or .spstr): value as space-separated string.
542 """
542 """
543
543
544 opts,args = self.parse_options(parameter_s, 'lv')
544 opts,args = self.parse_options(parameter_s, 'lv')
545 # Try to get a variable name and command to run
545 # Try to get a variable name and command to run
546 try:
546 try:
547 # the variable name must be obtained from the parse_options
547 # the variable name must be obtained from the parse_options
548 # output, which uses shlex.split to strip options out.
548 # output, which uses shlex.split to strip options out.
549 var,_ = args.split('=', 1)
549 var,_ = args.split('=', 1)
550 var = var.strip()
550 var = var.strip()
551 # But the command has to be extracted from the original input
551 # But the command has to be extracted from the original input
552 # parameter_s, not on what parse_options returns, to avoid the
552 # parameter_s, not on what parse_options returns, to avoid the
553 # quote stripping which shlex.split performs on it.
553 # quote stripping which shlex.split performs on it.
554 _,cmd = parameter_s.split('=', 1)
554 _,cmd = parameter_s.split('=', 1)
555 except ValueError:
555 except ValueError:
556 var,cmd = '',''
556 var,cmd = '',''
557 # If all looks ok, proceed
557 # If all looks ok, proceed
558 split = 'l' in opts
558 split = 'l' in opts
559 out = self.shell.getoutput(cmd, split=split)
559 out = self.shell.getoutput(cmd, split=split)
560 if 'v' in opts:
560 if 'v' in opts:
561 print('%s ==\n%s' % (var, pformat(out)))
561 print('%s ==\n%s' % (var, pformat(out)))
562 if var:
562 if var:
563 self.shell.user_ns.update({var:out})
563 self.shell.user_ns.update({var:out})
564 else:
564 else:
565 return out
565 return out
566
566
567 @line_cell_magic
567 @line_cell_magic
568 def sx(self, line='', cell=None):
568 def sx(self, line='', cell=None):
569 """Shell execute - run shell command and capture output (!! is short-hand).
569 """Shell execute - run shell command and capture output (!! is short-hand).
570
570
571 %sx command
571 %sx command
572
572
573 IPython will run the given command using commands.getoutput(), and
573 IPython will run the given command using commands.getoutput(), and
574 return the result formatted as a list (split on '\\n'). Since the
574 return the result formatted as a list (split on '\\n'). Since the
575 output is _returned_, it will be stored in ipython's regular output
575 output is _returned_, it will be stored in ipython's regular output
576 cache Out[N] and in the '_N' automatic variables.
576 cache Out[N] and in the '_N' automatic variables.
577
577
578 Notes:
578 Notes:
579
579
580 1) If an input line begins with '!!', then %sx is automatically
580 1) If an input line begins with '!!', then %sx is automatically
581 invoked. That is, while::
581 invoked. That is, while::
582
582
583 !ls
583 !ls
584
584
585 causes ipython to simply issue system('ls'), typing::
585 causes ipython to simply issue system('ls'), typing::
586
586
587 !!ls
587 !!ls
588
588
589 is a shorthand equivalent to::
589 is a shorthand equivalent to::
590
590
591 %sx ls
591 %sx ls
592
592
593 2) %sx differs from %sc in that %sx automatically splits into a list,
593 2) %sx differs from %sc in that %sx automatically splits into a list,
594 like '%sc -l'. The reason for this is to make it as easy as possible
594 like '%sc -l'. The reason for this is to make it as easy as possible
595 to process line-oriented shell output via further python commands.
595 to process line-oriented shell output via further python commands.
596 %sc is meant to provide much finer control, but requires more
596 %sc is meant to provide much finer control, but requires more
597 typing.
597 typing.
598
598
599 3) Just like %sc -l, this is a list with special attributes:
599 3) Just like %sc -l, this is a list with special attributes:
600 ::
600 ::
601
601
602 .l (or .list) : value as list.
602 .l (or .list) : value as list.
603 .n (or .nlstr): value as newline-separated string.
603 .n (or .nlstr): value as newline-separated string.
604 .s (or .spstr): value as whitespace-separated string.
604 .s (or .spstr): value as whitespace-separated string.
605
605
606 This is very useful when trying to use such lists as arguments to
606 This is very useful when trying to use such lists as arguments to
607 system commands."""
607 system commands."""
608
608
609 if cell is None:
609 if cell is None:
610 # line magic
610 # line magic
611 return self.shell.getoutput(line)
611 return self.shell.getoutput(line)
612 else:
612 else:
613 opts,args = self.parse_options(line, '', 'out=')
613 opts,args = self.parse_options(line, '', 'out=')
614 output = self.shell.getoutput(cell)
614 output = self.shell.getoutput(cell)
615 out_name = opts.get('out', opts.get('o'))
615 out_name = opts.get('out', opts.get('o'))
616 if out_name:
616 if out_name:
617 self.shell.user_ns[out_name] = output
617 self.shell.user_ns[out_name] = output
618 else:
618 else:
619 return output
619 return output
620
620
621 system = line_cell_magic('system')(sx)
621 system = line_cell_magic('system')(sx)
622 bang = cell_magic('!')(sx)
622 bang = cell_magic('!')(sx)
623
623
624 @line_magic
624 @line_magic
625 def bookmark(self, parameter_s=''):
625 def bookmark(self, parameter_s=''):
626 """Manage IPython's bookmark system.
626 """Manage IPython's bookmark system.
627
627
628 %bookmark <name> - set bookmark to current dir
628 %bookmark <name> - set bookmark to current dir
629 %bookmark <name> <dir> - set bookmark to <dir>
629 %bookmark <name> <dir> - set bookmark to <dir>
630 %bookmark -l - list all bookmarks
630 %bookmark -l - list all bookmarks
631 %bookmark -d <name> - remove bookmark
631 %bookmark -d <name> - remove bookmark
632 %bookmark -r - remove all bookmarks
632 %bookmark -r - remove all bookmarks
633
633
634 You can later on access a bookmarked folder with::
634 You can later on access a bookmarked folder with::
635
635
636 %cd -b <name>
636 %cd -b <name>
637
637
638 or simply '%cd <name>' if there is no directory called <name> AND
638 or simply '%cd <name>' if there is no directory called <name> AND
639 there is such a bookmark defined.
639 there is such a bookmark defined.
640
640
641 Your bookmarks persist through IPython sessions, but they are
641 Your bookmarks persist through IPython sessions, but they are
642 associated with each profile."""
642 associated with each profile."""
643
643
644 opts,args = self.parse_options(parameter_s,'drl',mode='list')
644 opts,args = self.parse_options(parameter_s,'drl',mode='list')
645 if len(args) > 2:
645 if len(args) > 2:
646 raise UsageError("%bookmark: too many arguments")
646 raise UsageError("%bookmark: too many arguments")
647
647
648 bkms = self.shell.db.get('bookmarks',{})
648 bkms = self.shell.db.get('bookmarks',{})
649
649
650 if 'd' in opts:
650 if 'd' in opts:
651 try:
651 try:
652 todel = args[0]
652 todel = args[0]
653 except IndexError:
653 except IndexError:
654 raise UsageError(
654 raise UsageError(
655 "%bookmark -d: must provide a bookmark to delete")
655 "%bookmark -d: must provide a bookmark to delete")
656 else:
656 else:
657 try:
657 try:
658 del bkms[todel]
658 del bkms[todel]
659 except KeyError:
659 except KeyError:
660 raise UsageError(
660 raise UsageError(
661 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
661 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
662
662
663 elif 'r' in opts:
663 elif 'r' in opts:
664 bkms = {}
664 bkms = {}
665 elif 'l' in opts:
665 elif 'l' in opts:
666 bks = bkms.keys()
666 bks = sorted(bkms)
667 bks.sort()
668 if bks:
667 if bks:
669 size = max(map(len, bks))
668 size = max(map(len, bks))
670 else:
669 else:
671 size = 0
670 size = 0
672 fmt = '%-'+str(size)+'s -> %s'
671 fmt = '%-'+str(size)+'s -> %s'
673 print('Current bookmarks:')
672 print('Current bookmarks:')
674 for bk in bks:
673 for bk in bks:
675 print(fmt % (bk, bkms[bk]))
674 print(fmt % (bk, bkms[bk]))
676 else:
675 else:
677 if not args:
676 if not args:
678 raise UsageError("%bookmark: You must specify the bookmark name")
677 raise UsageError("%bookmark: You must specify the bookmark name")
679 elif len(args)==1:
678 elif len(args)==1:
680 bkms[args[0]] = py3compat.getcwd()
679 bkms[args[0]] = py3compat.getcwd()
681 elif len(args)==2:
680 elif len(args)==2:
682 bkms[args[0]] = args[1]
681 bkms[args[0]] = args[1]
683 self.shell.db['bookmarks'] = bkms
682 self.shell.db['bookmarks'] = bkms
684
683
685 @line_magic
684 @line_magic
686 def pycat(self, parameter_s=''):
685 def pycat(self, parameter_s=''):
687 """Show a syntax-highlighted file through a pager.
686 """Show a syntax-highlighted file through a pager.
688
687
689 This magic is similar to the cat utility, but it will assume the file
688 This magic is similar to the cat utility, but it will assume the file
690 to be Python source and will show it with syntax highlighting.
689 to be Python source and will show it with syntax highlighting.
691
690
692 This magic command can either take a local filename, an url,
691 This magic command can either take a local filename, an url,
693 an history range (see %history) or a macro as argument ::
692 an history range (see %history) or a macro as argument ::
694
693
695 %pycat myscript.py
694 %pycat myscript.py
696 %pycat 7-27
695 %pycat 7-27
697 %pycat myMacro
696 %pycat myMacro
698 %pycat http://www.example.com/myscript.py
697 %pycat http://www.example.com/myscript.py
699 """
698 """
700 if not parameter_s:
699 if not parameter_s:
701 raise UsageError('Missing filename, URL, input history range, '
700 raise UsageError('Missing filename, URL, input history range, '
702 'or macro.')
701 'or macro.')
703
702
704 try :
703 try :
705 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
704 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
706 except (ValueError, IOError):
705 except (ValueError, IOError):
707 print("Error: no such file, variable, URL, history range or macro")
706 print("Error: no such file, variable, URL, history range or macro")
708 return
707 return
709
708
710 page.page(self.shell.pycolorize(source_to_unicode(cont)))
709 page.page(self.shell.pycolorize(source_to_unicode(cont)))
711
710
712 @magic_arguments.magic_arguments()
711 @magic_arguments.magic_arguments()
713 @magic_arguments.argument(
712 @magic_arguments.argument(
714 '-a', '--append', action='store_true', default=False,
713 '-a', '--append', action='store_true', default=False,
715 help='Append contents of the cell to an existing file. '
714 help='Append contents of the cell to an existing file. '
716 'The file will be created if it does not exist.'
715 'The file will be created if it does not exist.'
717 )
716 )
718 @magic_arguments.argument(
717 @magic_arguments.argument(
719 'filename', type=unicode_type,
718 'filename', type=unicode_type,
720 help='file to write'
719 help='file to write'
721 )
720 )
722 @cell_magic
721 @cell_magic
723 def writefile(self, line, cell):
722 def writefile(self, line, cell):
724 """Write the contents of the cell to a file.
723 """Write the contents of the cell to a file.
725
724
726 The file will be overwritten unless the -a (--append) flag is specified.
725 The file will be overwritten unless the -a (--append) flag is specified.
727 """
726 """
728 args = magic_arguments.parse_argstring(self.writefile, line)
727 args = magic_arguments.parse_argstring(self.writefile, line)
729 filename = os.path.expanduser(unquote_filename(args.filename))
728 filename = os.path.expanduser(unquote_filename(args.filename))
730
729
731 if os.path.exists(filename):
730 if os.path.exists(filename):
732 if args.append:
731 if args.append:
733 print("Appending to %s" % filename)
732 print("Appending to %s" % filename)
734 else:
733 else:
735 print("Overwriting %s" % filename)
734 print("Overwriting %s" % filename)
736 else:
735 else:
737 print("Writing %s" % filename)
736 print("Writing %s" % filename)
738
737
739 mode = 'a' if args.append else 'w'
738 mode = 'a' if args.append else 'w'
740 with io.open(filename, mode, encoding='utf-8') as f:
739 with io.open(filename, mode, encoding='utf-8') as f:
741 f.write(cell)
740 f.write(cell)
@@ -1,944 +1,951 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from unittest import TestCase
15 from unittest import TestCase
16
16
17 try:
17 try:
18 from importlib import invalidate_caches # Required from Python 3.3
18 from importlib import invalidate_caches # Required from Python 3.3
19 except ImportError:
19 except ImportError:
20 def invalidate_caches():
20 def invalidate_caches():
21 pass
21 pass
22
22
23 import nose.tools as nt
23 import nose.tools as nt
24
24
25 from IPython.core import magic
25 from IPython.core import magic
26 from IPython.core.magic import (Magics, magics_class, line_magic,
26 from IPython.core.magic import (Magics, magics_class, line_magic,
27 cell_magic, line_cell_magic,
27 cell_magic, line_cell_magic,
28 register_line_magic, register_cell_magic,
28 register_line_magic, register_cell_magic,
29 register_line_cell_magic)
29 register_line_cell_magic)
30 from IPython.core.magics import execution, script, code
30 from IPython.core.magics import execution, script, code
31 from IPython.nbformat.v3.tests.nbexamples import nb0
31 from IPython.nbformat.v3.tests.nbexamples import nb0
32 from IPython.nbformat import current
32 from IPython.nbformat import current
33 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
34 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
35 from IPython.utils import py3compat
35 from IPython.utils import py3compat
36 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
37 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
38 from IPython.utils.process import find_cmd
38 from IPython.utils.process import find_cmd
39
39
40 if py3compat.PY3:
40 if py3compat.PY3:
41 from io import StringIO
41 from io import StringIO
42 else:
42 else:
43 from StringIO import StringIO
43 from StringIO import StringIO
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Test functions begin
46 # Test functions begin
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 @magic.magics_class
49 @magic.magics_class
50 class DummyMagics(magic.Magics): pass
50 class DummyMagics(magic.Magics): pass
51
51
52 def test_extract_code_ranges():
52 def test_extract_code_ranges():
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
54 expected = [(0, 1),
54 expected = [(0, 1),
55 (2, 3),
55 (2, 3),
56 (4, 6),
56 (4, 6),
57 (6, 9),
57 (6, 9),
58 (9, 14),
58 (9, 14),
59 (16, None),
59 (16, None),
60 (None, 9),
60 (None, 9),
61 (9, None),
61 (9, None),
62 (None, 13),
62 (None, 13),
63 (None, None)]
63 (None, None)]
64 actual = list(code.extract_code_ranges(instr))
64 actual = list(code.extract_code_ranges(instr))
65 nt.assert_equal(actual, expected)
65 nt.assert_equal(actual, expected)
66
66
67 def test_extract_symbols():
67 def test_extract_symbols():
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
70 expected = [([], ['a']),
70 expected = [([], ['a']),
71 (["def b():\n return 42\n"], []),
71 (["def b():\n return 42\n"], []),
72 (["class A: pass\n"], []),
72 (["class A: pass\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
74 (["class A: pass\n"], ['a']),
74 (["class A: pass\n"], ['a']),
75 ([], ['z'])]
75 ([], ['z'])]
76 for symbols, exp in zip(symbols_args, expected):
76 for symbols, exp in zip(symbols_args, expected):
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
78
78
79
79
80 def test_extract_symbols_raises_exception_with_non_python_code():
80 def test_extract_symbols_raises_exception_with_non_python_code():
81 source = ("=begin A Ruby program :)=end\n"
81 source = ("=begin A Ruby program :)=end\n"
82 "def hello\n"
82 "def hello\n"
83 "puts 'Hello world'\n"
83 "puts 'Hello world'\n"
84 "end")
84 "end")
85 with nt.assert_raises(SyntaxError):
85 with nt.assert_raises(SyntaxError):
86 code.extract_symbols(source, "hello")
86 code.extract_symbols(source, "hello")
87
87
88 def test_config():
88 def test_config():
89 """ test that config magic does not raise
89 """ test that config magic does not raise
90 can happen if Configurable init is moved too early into
90 can happen if Configurable init is moved too early into
91 Magics.__init__ as then a Config object will be registerd as a
91 Magics.__init__ as then a Config object will be registerd as a
92 magic.
92 magic.
93 """
93 """
94 ## should not raise.
94 ## should not raise.
95 _ip.magic('config')
95 _ip.magic('config')
96
96
97 def test_rehashx():
97 def test_rehashx():
98 # clear up everything
98 # clear up everything
99 _ip = get_ipython()
99 _ip = get_ipython()
100 _ip.alias_manager.clear_aliases()
100 _ip.alias_manager.clear_aliases()
101 del _ip.db['syscmdlist']
101 del _ip.db['syscmdlist']
102
102
103 _ip.magic('rehashx')
103 _ip.magic('rehashx')
104 # Practically ALL ipython development systems will have more than 10 aliases
104 # Practically ALL ipython development systems will have more than 10 aliases
105
105
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
107 for name, cmd in _ip.alias_manager.aliases:
107 for name, cmd in _ip.alias_manager.aliases:
108 # we must strip dots from alias names
108 # we must strip dots from alias names
109 nt.assert_not_in('.', name)
109 nt.assert_not_in('.', name)
110
110
111 # rehashx must fill up syscmdlist
111 # rehashx must fill up syscmdlist
112 scoms = _ip.db['syscmdlist']
112 scoms = _ip.db['syscmdlist']
113 nt.assert_true(len(scoms) > 10)
113 nt.assert_true(len(scoms) > 10)
114
114
115
115
116 def test_magic_parse_options():
116 def test_magic_parse_options():
117 """Test that we don't mangle paths when parsing magic options."""
117 """Test that we don't mangle paths when parsing magic options."""
118 ip = get_ipython()
118 ip = get_ipython()
119 path = 'c:\\x'
119 path = 'c:\\x'
120 m = DummyMagics(ip)
120 m = DummyMagics(ip)
121 opts = m.parse_options('-f %s' % path,'f:')[0]
121 opts = m.parse_options('-f %s' % path,'f:')[0]
122 # argv splitting is os-dependent
122 # argv splitting is os-dependent
123 if os.name == 'posix':
123 if os.name == 'posix':
124 expected = 'c:x'
124 expected = 'c:x'
125 else:
125 else:
126 expected = path
126 expected = path
127 nt.assert_equal(opts['f'], expected)
127 nt.assert_equal(opts['f'], expected)
128
128
129 def test_magic_parse_long_options():
129 def test_magic_parse_long_options():
130 """Magic.parse_options can handle --foo=bar long options"""
130 """Magic.parse_options can handle --foo=bar long options"""
131 ip = get_ipython()
131 ip = get_ipython()
132 m = DummyMagics(ip)
132 m = DummyMagics(ip)
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
134 nt.assert_in('foo', opts)
134 nt.assert_in('foo', opts)
135 nt.assert_in('bar', opts)
135 nt.assert_in('bar', opts)
136 nt.assert_equal(opts['bar'], "bubble")
136 nt.assert_equal(opts['bar'], "bubble")
137
137
138
138
139 @dec.skip_without('sqlite3')
139 @dec.skip_without('sqlite3')
140 def doctest_hist_f():
140 def doctest_hist_f():
141 """Test %hist -f with temporary filename.
141 """Test %hist -f with temporary filename.
142
142
143 In [9]: import tempfile
143 In [9]: import tempfile
144
144
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
146
146
147 In [11]: %hist -nl -f $tfile 3
147 In [11]: %hist -nl -f $tfile 3
148
148
149 In [13]: import os; os.unlink(tfile)
149 In [13]: import os; os.unlink(tfile)
150 """
150 """
151
151
152
152
153 @dec.skip_without('sqlite3')
153 @dec.skip_without('sqlite3')
154 def doctest_hist_r():
154 def doctest_hist_r():
155 """Test %hist -r
155 """Test %hist -r
156
156
157 XXX - This test is not recording the output correctly. For some reason, in
157 XXX - This test is not recording the output correctly. For some reason, in
158 testing mode the raw history isn't getting populated. No idea why.
158 testing mode the raw history isn't getting populated. No idea why.
159 Disabling the output checking for now, though at least we do run it.
159 Disabling the output checking for now, though at least we do run it.
160
160
161 In [1]: 'hist' in _ip.lsmagic()
161 In [1]: 'hist' in _ip.lsmagic()
162 Out[1]: True
162 Out[1]: True
163
163
164 In [2]: x=1
164 In [2]: x=1
165
165
166 In [3]: %hist -rl 2
166 In [3]: %hist -rl 2
167 x=1 # random
167 x=1 # random
168 %hist -r 2
168 %hist -r 2
169 """
169 """
170
170
171
171
172 @dec.skip_without('sqlite3')
172 @dec.skip_without('sqlite3')
173 def doctest_hist_op():
173 def doctest_hist_op():
174 """Test %hist -op
174 """Test %hist -op
175
175
176 In [1]: class b(float):
176 In [1]: class b(float):
177 ...: pass
177 ...: pass
178 ...:
178 ...:
179
179
180 In [2]: class s(object):
180 In [2]: class s(object):
181 ...: def __str__(self):
181 ...: def __str__(self):
182 ...: return 's'
182 ...: return 's'
183 ...:
183 ...:
184
184
185 In [3]:
185 In [3]:
186
186
187 In [4]: class r(b):
187 In [4]: class r(b):
188 ...: def __repr__(self):
188 ...: def __repr__(self):
189 ...: return 'r'
189 ...: return 'r'
190 ...:
190 ...:
191
191
192 In [5]: class sr(s,r): pass
192 In [5]: class sr(s,r): pass
193 ...:
193 ...:
194
194
195 In [6]:
195 In [6]:
196
196
197 In [7]: bb=b()
197 In [7]: bb=b()
198
198
199 In [8]: ss=s()
199 In [8]: ss=s()
200
200
201 In [9]: rr=r()
201 In [9]: rr=r()
202
202
203 In [10]: ssrr=sr()
203 In [10]: ssrr=sr()
204
204
205 In [11]: 4.5
205 In [11]: 4.5
206 Out[11]: 4.5
206 Out[11]: 4.5
207
207
208 In [12]: str(ss)
208 In [12]: str(ss)
209 Out[12]: 's'
209 Out[12]: 's'
210
210
211 In [13]:
211 In [13]:
212
212
213 In [14]: %hist -op
213 In [14]: %hist -op
214 >>> class b:
214 >>> class b:
215 ... pass
215 ... pass
216 ...
216 ...
217 >>> class s(b):
217 >>> class s(b):
218 ... def __str__(self):
218 ... def __str__(self):
219 ... return 's'
219 ... return 's'
220 ...
220 ...
221 >>>
221 >>>
222 >>> class r(b):
222 >>> class r(b):
223 ... def __repr__(self):
223 ... def __repr__(self):
224 ... return 'r'
224 ... return 'r'
225 ...
225 ...
226 >>> class sr(s,r): pass
226 >>> class sr(s,r): pass
227 >>>
227 >>>
228 >>> bb=b()
228 >>> bb=b()
229 >>> ss=s()
229 >>> ss=s()
230 >>> rr=r()
230 >>> rr=r()
231 >>> ssrr=sr()
231 >>> ssrr=sr()
232 >>> 4.5
232 >>> 4.5
233 4.5
233 4.5
234 >>> str(ss)
234 >>> str(ss)
235 's'
235 's'
236 >>>
236 >>>
237 """
237 """
238
238
239
239
240 @dec.skip_without('sqlite3')
240 @dec.skip_without('sqlite3')
241 def test_macro():
241 def test_macro():
242 ip = get_ipython()
242 ip = get_ipython()
243 ip.history_manager.reset() # Clear any existing history.
243 ip.history_manager.reset() # Clear any existing history.
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
245 for i, cmd in enumerate(cmds, start=1):
245 for i, cmd in enumerate(cmds, start=1):
246 ip.history_manager.store_inputs(i, cmd)
246 ip.history_manager.store_inputs(i, cmd)
247 ip.magic("macro test 1-3")
247 ip.magic("macro test 1-3")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
249
249
250 # List macros
250 # List macros
251 nt.assert_in("test", ip.magic("macro"))
251 nt.assert_in("test", ip.magic("macro"))
252
252
253
253
254 @dec.skip_without('sqlite3')
254 @dec.skip_without('sqlite3')
255 def test_macro_run():
255 def test_macro_run():
256 """Test that we can run a multi-line macro successfully."""
256 """Test that we can run a multi-line macro successfully."""
257 ip = get_ipython()
257 ip = get_ipython()
258 ip.history_manager.reset()
258 ip.history_manager.reset()
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
260 "%macro test 2-3"]
260 "%macro test 2-3"]
261 for cmd in cmds:
261 for cmd in cmds:
262 ip.run_cell(cmd, store_history=True)
262 ip.run_cell(cmd, store_history=True)
263 nt.assert_equal(ip.user_ns["test"].value,
263 nt.assert_equal(ip.user_ns["test"].value,
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
265 with tt.AssertPrints("12"):
265 with tt.AssertPrints("12"):
266 ip.run_cell("test")
266 ip.run_cell("test")
267 with tt.AssertPrints("13"):
267 with tt.AssertPrints("13"):
268 ip.run_cell("test")
268 ip.run_cell("test")
269
269
270
270
271 def test_magic_magic():
271 def test_magic_magic():
272 """Test %magic"""
272 """Test %magic"""
273 ip = get_ipython()
273 ip = get_ipython()
274 with capture_output() as captured:
274 with capture_output() as captured:
275 ip.magic("magic")
275 ip.magic("magic")
276
276
277 stdout = captured.stdout
277 stdout = captured.stdout
278 nt.assert_in('%magic', stdout)
278 nt.assert_in('%magic', stdout)
279 nt.assert_in('IPython', stdout)
279 nt.assert_in('IPython', stdout)
280 nt.assert_in('Available', stdout)
280 nt.assert_in('Available', stdout)
281
281
282
282
283 @dec.skipif_not_numpy
283 @dec.skipif_not_numpy
284 def test_numpy_reset_array_undec():
284 def test_numpy_reset_array_undec():
285 "Test '%reset array' functionality"
285 "Test '%reset array' functionality"
286 _ip.ex('import numpy as np')
286 _ip.ex('import numpy as np')
287 _ip.ex('a = np.empty(2)')
287 _ip.ex('a = np.empty(2)')
288 nt.assert_in('a', _ip.user_ns)
288 nt.assert_in('a', _ip.user_ns)
289 _ip.magic('reset -f array')
289 _ip.magic('reset -f array')
290 nt.assert_not_in('a', _ip.user_ns)
290 nt.assert_not_in('a', _ip.user_ns)
291
291
292 def test_reset_out():
292 def test_reset_out():
293 "Test '%reset out' magic"
293 "Test '%reset out' magic"
294 _ip.run_cell("parrot = 'dead'", store_history=True)
294 _ip.run_cell("parrot = 'dead'", store_history=True)
295 # test '%reset -f out', make an Out prompt
295 # test '%reset -f out', make an Out prompt
296 _ip.run_cell("parrot", store_history=True)
296 _ip.run_cell("parrot", store_history=True)
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
298 _ip.magic('reset -f out')
298 _ip.magic('reset -f out')
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
301
301
302 def test_reset_in():
302 def test_reset_in():
303 "Test '%reset in' magic"
303 "Test '%reset in' magic"
304 # test '%reset -f in'
304 # test '%reset -f in'
305 _ip.run_cell("parrot", store_history=True)
305 _ip.run_cell("parrot", store_history=True)
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
307 _ip.magic('%reset -f in')
307 _ip.magic('%reset -f in')
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
310
310
311 def test_reset_dhist():
311 def test_reset_dhist():
312 "Test '%reset dhist' magic"
312 "Test '%reset dhist' magic"
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
315 _ip.magic('cd -')
315 _ip.magic('cd -')
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
317 _ip.magic('reset -f dhist')
317 _ip.magic('reset -f dhist')
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
320
320
321 def test_reset_in_length():
321 def test_reset_in_length():
322 "Test that '%reset in' preserves In[] length"
322 "Test that '%reset in' preserves In[] length"
323 _ip.run_cell("print 'foo'")
323 _ip.run_cell("print 'foo'")
324 _ip.run_cell("reset -f in")
324 _ip.run_cell("reset -f in")
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
326
326
327 def test_tb_syntaxerror():
327 def test_tb_syntaxerror():
328 """test %tb after a SyntaxError"""
328 """test %tb after a SyntaxError"""
329 ip = get_ipython()
329 ip = get_ipython()
330 ip.run_cell("for")
330 ip.run_cell("for")
331
331
332 # trap and validate stdout
332 # trap and validate stdout
333 save_stdout = sys.stdout
333 save_stdout = sys.stdout
334 try:
334 try:
335 sys.stdout = StringIO()
335 sys.stdout = StringIO()
336 ip.run_cell("%tb")
336 ip.run_cell("%tb")
337 out = sys.stdout.getvalue()
337 out = sys.stdout.getvalue()
338 finally:
338 finally:
339 sys.stdout = save_stdout
339 sys.stdout = save_stdout
340 # trim output, and only check the last line
340 # trim output, and only check the last line
341 last_line = out.rstrip().splitlines()[-1].strip()
341 last_line = out.rstrip().splitlines()[-1].strip()
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
343
343
344
344
345 def test_time():
345 def test_time():
346 ip = get_ipython()
346 ip = get_ipython()
347
347
348 with tt.AssertPrints("Wall time: "):
348 with tt.AssertPrints("Wall time: "):
349 ip.run_cell("%time None")
349 ip.run_cell("%time None")
350
350
351 ip.run_cell("def f(kmjy):\n"
351 ip.run_cell("def f(kmjy):\n"
352 " %time print (2*kmjy)")
352 " %time print (2*kmjy)")
353
353
354 with tt.AssertPrints("Wall time: "):
354 with tt.AssertPrints("Wall time: "):
355 with tt.AssertPrints("hihi", suppress=False):
355 with tt.AssertPrints("hihi", suppress=False):
356 ip.run_cell("f('hi')")
356 ip.run_cell("f('hi')")
357
357
358
358
359 @dec.skip_win32
359 @dec.skip_win32
360 def test_time2():
360 def test_time2():
361 ip = get_ipython()
361 ip = get_ipython()
362
362
363 with tt.AssertPrints("CPU times: user "):
363 with tt.AssertPrints("CPU times: user "):
364 ip.run_cell("%time None")
364 ip.run_cell("%time None")
365
365
366 def test_time3():
366 def test_time3():
367 """Erroneous magic function calls, issue gh-3334"""
367 """Erroneous magic function calls, issue gh-3334"""
368 ip = get_ipython()
368 ip = get_ipython()
369 ip.user_ns.pop('run', None)
369 ip.user_ns.pop('run', None)
370
370
371 with tt.AssertNotPrints("not found", channel='stderr'):
371 with tt.AssertNotPrints("not found", channel='stderr'):
372 ip.run_cell("%%time\n"
372 ip.run_cell("%%time\n"
373 "run = 0\n"
373 "run = 0\n"
374 "run += 1")
374 "run += 1")
375
375
376 def test_doctest_mode():
376 def test_doctest_mode():
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
378 _ip.magic('doctest_mode')
378 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
380
380
381
381
382 def test_parse_options():
382 def test_parse_options():
383 """Tests for basic options parsing in magics."""
383 """Tests for basic options parsing in magics."""
384 # These are only the most minimal of tests, more should be added later. At
384 # These are only the most minimal of tests, more should be added later. At
385 # the very least we check that basic text/unicode calls work OK.
385 # the very least we check that basic text/unicode calls work OK.
386 m = DummyMagics(_ip)
386 m = DummyMagics(_ip)
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
389
389
390
390
391 def test_dirops():
391 def test_dirops():
392 """Test various directory handling operations."""
392 """Test various directory handling operations."""
393 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
393 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
394 curpath = py3compat.getcwd
394 curpath = py3compat.getcwd
395 startdir = py3compat.getcwd()
395 startdir = py3compat.getcwd()
396 ipdir = os.path.realpath(_ip.ipython_dir)
396 ipdir = os.path.realpath(_ip.ipython_dir)
397 try:
397 try:
398 _ip.magic('cd "%s"' % ipdir)
398 _ip.magic('cd "%s"' % ipdir)
399 nt.assert_equal(curpath(), ipdir)
399 nt.assert_equal(curpath(), ipdir)
400 _ip.magic('cd -')
400 _ip.magic('cd -')
401 nt.assert_equal(curpath(), startdir)
401 nt.assert_equal(curpath(), startdir)
402 _ip.magic('pushd "%s"' % ipdir)
402 _ip.magic('pushd "%s"' % ipdir)
403 nt.assert_equal(curpath(), ipdir)
403 nt.assert_equal(curpath(), ipdir)
404 _ip.magic('popd')
404 _ip.magic('popd')
405 nt.assert_equal(curpath(), startdir)
405 nt.assert_equal(curpath(), startdir)
406 finally:
406 finally:
407 os.chdir(startdir)
407 os.chdir(startdir)
408
408
409
409
410 def test_xmode():
410 def test_xmode():
411 # Calling xmode three times should be a no-op
411 # Calling xmode three times should be a no-op
412 xmode = _ip.InteractiveTB.mode
412 xmode = _ip.InteractiveTB.mode
413 for i in range(3):
413 for i in range(3):
414 _ip.magic("xmode")
414 _ip.magic("xmode")
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
416
416
417 def test_reset_hard():
417 def test_reset_hard():
418 monitor = []
418 monitor = []
419 class A(object):
419 class A(object):
420 def __del__(self):
420 def __del__(self):
421 monitor.append(1)
421 monitor.append(1)
422 def __repr__(self):
422 def __repr__(self):
423 return "<A instance>"
423 return "<A instance>"
424
424
425 _ip.user_ns["a"] = A()
425 _ip.user_ns["a"] = A()
426 _ip.run_cell("a")
426 _ip.run_cell("a")
427
427
428 nt.assert_equal(monitor, [])
428 nt.assert_equal(monitor, [])
429 _ip.magic("reset -f")
429 _ip.magic("reset -f")
430 nt.assert_equal(monitor, [1])
430 nt.assert_equal(monitor, [1])
431
431
432 class TestXdel(tt.TempFileMixin):
432 class TestXdel(tt.TempFileMixin):
433 def test_xdel(self):
433 def test_xdel(self):
434 """Test that references from %run are cleared by xdel."""
434 """Test that references from %run are cleared by xdel."""
435 src = ("class A(object):\n"
435 src = ("class A(object):\n"
436 " monitor = []\n"
436 " monitor = []\n"
437 " def __del__(self):\n"
437 " def __del__(self):\n"
438 " self.monitor.append(1)\n"
438 " self.monitor.append(1)\n"
439 "a = A()\n")
439 "a = A()\n")
440 self.mktmp(src)
440 self.mktmp(src)
441 # %run creates some hidden references...
441 # %run creates some hidden references...
442 _ip.magic("run %s" % self.fname)
442 _ip.magic("run %s" % self.fname)
443 # ... as does the displayhook.
443 # ... as does the displayhook.
444 _ip.run_cell("a")
444 _ip.run_cell("a")
445
445
446 monitor = _ip.user_ns["A"].monitor
446 monitor = _ip.user_ns["A"].monitor
447 nt.assert_equal(monitor, [])
447 nt.assert_equal(monitor, [])
448
448
449 _ip.magic("xdel a")
449 _ip.magic("xdel a")
450
450
451 # Check that a's __del__ method has been called.
451 # Check that a's __del__ method has been called.
452 nt.assert_equal(monitor, [1])
452 nt.assert_equal(monitor, [1])
453
453
454 def doctest_who():
454 def doctest_who():
455 """doctest for %who
455 """doctest for %who
456
456
457 In [1]: %reset -f
457 In [1]: %reset -f
458
458
459 In [2]: alpha = 123
459 In [2]: alpha = 123
460
460
461 In [3]: beta = 'beta'
461 In [3]: beta = 'beta'
462
462
463 In [4]: %who int
463 In [4]: %who int
464 alpha
464 alpha
465
465
466 In [5]: %who str
466 In [5]: %who str
467 beta
467 beta
468
468
469 In [6]: %whos
469 In [6]: %whos
470 Variable Type Data/Info
470 Variable Type Data/Info
471 ----------------------------
471 ----------------------------
472 alpha int 123
472 alpha int 123
473 beta str beta
473 beta str beta
474
474
475 In [7]: %who_ls
475 In [7]: %who_ls
476 Out[7]: ['alpha', 'beta']
476 Out[7]: ['alpha', 'beta']
477 """
477 """
478
478
479 def test_whos():
479 def test_whos():
480 """Check that whos is protected against objects where repr() fails."""
480 """Check that whos is protected against objects where repr() fails."""
481 class A(object):
481 class A(object):
482 def __repr__(self):
482 def __repr__(self):
483 raise Exception()
483 raise Exception()
484 _ip.user_ns['a'] = A()
484 _ip.user_ns['a'] = A()
485 _ip.magic("whos")
485 _ip.magic("whos")
486
486
487 @py3compat.u_format
487 @py3compat.u_format
488 def doctest_precision():
488 def doctest_precision():
489 """doctest for %precision
489 """doctest for %precision
490
490
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
492
492
493 In [2]: %precision 5
493 In [2]: %precision 5
494 Out[2]: {u}'%.5f'
494 Out[2]: {u}'%.5f'
495
495
496 In [3]: f.float_format
496 In [3]: f.float_format
497 Out[3]: {u}'%.5f'
497 Out[3]: {u}'%.5f'
498
498
499 In [4]: %precision %e
499 In [4]: %precision %e
500 Out[4]: {u}'%e'
500 Out[4]: {u}'%e'
501
501
502 In [5]: f(3.1415927)
502 In [5]: f(3.1415927)
503 Out[5]: {u}'3.141593e+00'
503 Out[5]: {u}'3.141593e+00'
504 """
504 """
505
505
506 def test_psearch():
506 def test_psearch():
507 with tt.AssertPrints("dict.fromkeys"):
507 with tt.AssertPrints("dict.fromkeys"):
508 _ip.run_cell("dict.fr*?")
508 _ip.run_cell("dict.fr*?")
509
509
510 def test_timeit_shlex():
510 def test_timeit_shlex():
511 """test shlex issues with timeit (#1109)"""
511 """test shlex issues with timeit (#1109)"""
512 _ip.ex("def f(*a,**kw): pass")
512 _ip.ex("def f(*a,**kw): pass")
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
519
519
520
520
521 def test_timeit_arguments():
521 def test_timeit_arguments():
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
523 _ip.magic("timeit ('#')")
523 _ip.magic("timeit ('#')")
524
524
525
525
526 def test_timeit_special_syntax():
526 def test_timeit_special_syntax():
527 "Test %%timeit with IPython special syntax"
527 "Test %%timeit with IPython special syntax"
528 @register_line_magic
528 @register_line_magic
529 def lmagic(line):
529 def lmagic(line):
530 ip = get_ipython()
530 ip = get_ipython()
531 ip.user_ns['lmagic_out'] = line
531 ip.user_ns['lmagic_out'] = line
532
532
533 # line mode test
533 # line mode test
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
536 # cell mode test
536 # cell mode test
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
539
539
540 def test_timeit_return():
540 def test_timeit_return():
541 """
541 """
542 test wether timeit -o return object
542 test wether timeit -o return object
543 """
543 """
544
544
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
546 assert(res is not None)
546 assert(res is not None)
547
547
548 def test_timeit_quiet():
548 def test_timeit_quiet():
549 """
549 """
550 test quiet option of timeit magic
550 test quiet option of timeit magic
551 """
551 """
552 with tt.AssertNotPrints("loops"):
552 with tt.AssertNotPrints("loops"):
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
554
554
555 @dec.skipif(execution.profile is None)
555 @dec.skipif(execution.profile is None)
556 def test_prun_special_syntax():
556 def test_prun_special_syntax():
557 "Test %%prun with IPython special syntax"
557 "Test %%prun with IPython special syntax"
558 @register_line_magic
558 @register_line_magic
559 def lmagic(line):
559 def lmagic(line):
560 ip = get_ipython()
560 ip = get_ipython()
561 ip.user_ns['lmagic_out'] = line
561 ip.user_ns['lmagic_out'] = line
562
562
563 # line mode test
563 # line mode test
564 _ip.run_line_magic('prun', '-q %lmagic my line')
564 _ip.run_line_magic('prun', '-q %lmagic my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
566 # cell mode test
566 # cell mode test
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
569
569
570 @dec.skipif(execution.profile is None)
570 @dec.skipif(execution.profile is None)
571 def test_prun_quotes():
571 def test_prun_quotes():
572 "Test that prun does not clobber string escapes (GH #1302)"
572 "Test that prun does not clobber string escapes (GH #1302)"
573 _ip.magic(r"prun -q x = '\t'")
573 _ip.magic(r"prun -q x = '\t'")
574 nt.assert_equal(_ip.user_ns['x'], '\t')
574 nt.assert_equal(_ip.user_ns['x'], '\t')
575
575
576 def test_extension():
576 def test_extension():
577 tmpdir = TemporaryDirectory()
577 tmpdir = TemporaryDirectory()
578 orig_ipython_dir = _ip.ipython_dir
578 orig_ipython_dir = _ip.ipython_dir
579 try:
579 try:
580 _ip.ipython_dir = tmpdir.name
580 _ip.ipython_dir = tmpdir.name
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
583 _ip.magic("install_ext %s" % url)
583 _ip.magic("install_ext %s" % url)
584 _ip.user_ns.pop('arq', None)
584 _ip.user_ns.pop('arq', None)
585 invalidate_caches() # Clear import caches
585 invalidate_caches() # Clear import caches
586 _ip.magic("load_ext daft_extension")
586 _ip.magic("load_ext daft_extension")
587 nt.assert_equal(_ip.user_ns['arq'], 185)
587 nt.assert_equal(_ip.user_ns['arq'], 185)
588 _ip.magic("unload_ext daft_extension")
588 _ip.magic("unload_ext daft_extension")
589 assert 'arq' not in _ip.user_ns
589 assert 'arq' not in _ip.user_ns
590 finally:
590 finally:
591 _ip.ipython_dir = orig_ipython_dir
591 _ip.ipython_dir = orig_ipython_dir
592 tmpdir.cleanup()
592 tmpdir.cleanup()
593
593
594 def test_notebook_export_json():
594 def test_notebook_export_json():
595 with TemporaryDirectory() as td:
595 with TemporaryDirectory() as td:
596 outfile = os.path.join(td, "nb.ipynb")
596 outfile = os.path.join(td, "nb.ipynb")
597 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
597 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
598 _ip.magic("notebook -e %s" % outfile)
598 _ip.magic("notebook -e %s" % outfile)
599
599
600 def test_notebook_export_py():
600 def test_notebook_export_py():
601 with TemporaryDirectory() as td:
601 with TemporaryDirectory() as td:
602 outfile = os.path.join(td, "nb.py")
602 outfile = os.path.join(td, "nb.py")
603 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
603 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
604 _ip.magic("notebook -e %s" % outfile)
604 _ip.magic("notebook -e %s" % outfile)
605
605
606 def test_notebook_reformat_py():
606 def test_notebook_reformat_py():
607 with TemporaryDirectory() as td:
607 with TemporaryDirectory() as td:
608 infile = os.path.join(td, "nb.ipynb")
608 infile = os.path.join(td, "nb.ipynb")
609 with io.open(infile, 'w', encoding='utf-8') as f:
609 with io.open(infile, 'w', encoding='utf-8') as f:
610 current.write(nb0, f, 'json')
610 current.write(nb0, f, 'json')
611
611
612 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
612 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
613 _ip.magic("notebook -f py %s" % infile)
613 _ip.magic("notebook -f py %s" % infile)
614
614
615 def test_notebook_reformat_json():
615 def test_notebook_reformat_json():
616 with TemporaryDirectory() as td:
616 with TemporaryDirectory() as td:
617 infile = os.path.join(td, "nb.py")
617 infile = os.path.join(td, "nb.py")
618 with io.open(infile, 'w', encoding='utf-8') as f:
618 with io.open(infile, 'w', encoding='utf-8') as f:
619 current.write(nb0, f, 'py')
619 current.write(nb0, f, 'py')
620
620
621 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
621 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
622 _ip.magic("notebook -f ipynb %s" % infile)
622 _ip.magic("notebook -f ipynb %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
624
624
625 def test_env():
625 def test_env():
626 env = _ip.magic("env")
626 env = _ip.magic("env")
627 assert isinstance(env, dict), type(env)
627 assert isinstance(env, dict), type(env)
628
628
629
629
630 class CellMagicTestCase(TestCase):
630 class CellMagicTestCase(TestCase):
631
631
632 def check_ident(self, magic):
632 def check_ident(self, magic):
633 # Manually called, we get the result
633 # Manually called, we get the result
634 out = _ip.run_cell_magic(magic, 'a', 'b')
634 out = _ip.run_cell_magic(magic, 'a', 'b')
635 nt.assert_equal(out, ('a','b'))
635 nt.assert_equal(out, ('a','b'))
636 # Via run_cell, it goes into the user's namespace via displayhook
636 # Via run_cell, it goes into the user's namespace via displayhook
637 _ip.run_cell('%%' + magic +' c\nd')
637 _ip.run_cell('%%' + magic +' c\nd')
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
639
639
640 def test_cell_magic_func_deco(self):
640 def test_cell_magic_func_deco(self):
641 "Cell magic using simple decorator"
641 "Cell magic using simple decorator"
642 @register_cell_magic
642 @register_cell_magic
643 def cellm(line, cell):
643 def cellm(line, cell):
644 return line, cell
644 return line, cell
645
645
646 self.check_ident('cellm')
646 self.check_ident('cellm')
647
647
648 def test_cell_magic_reg(self):
648 def test_cell_magic_reg(self):
649 "Cell magic manually registered"
649 "Cell magic manually registered"
650 def cellm(line, cell):
650 def cellm(line, cell):
651 return line, cell
651 return line, cell
652
652
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
654 self.check_ident('cellm2')
654 self.check_ident('cellm2')
655
655
656 def test_cell_magic_class(self):
656 def test_cell_magic_class(self):
657 "Cell magics declared via a class"
657 "Cell magics declared via a class"
658 @magics_class
658 @magics_class
659 class MyMagics(Magics):
659 class MyMagics(Magics):
660
660
661 @cell_magic
661 @cell_magic
662 def cellm3(self, line, cell):
662 def cellm3(self, line, cell):
663 return line, cell
663 return line, cell
664
664
665 _ip.register_magics(MyMagics)
665 _ip.register_magics(MyMagics)
666 self.check_ident('cellm3')
666 self.check_ident('cellm3')
667
667
668 def test_cell_magic_class2(self):
668 def test_cell_magic_class2(self):
669 "Cell magics declared via a class, #2"
669 "Cell magics declared via a class, #2"
670 @magics_class
670 @magics_class
671 class MyMagics2(Magics):
671 class MyMagics2(Magics):
672
672
673 @cell_magic('cellm4')
673 @cell_magic('cellm4')
674 def cellm33(self, line, cell):
674 def cellm33(self, line, cell):
675 return line, cell
675 return line, cell
676
676
677 _ip.register_magics(MyMagics2)
677 _ip.register_magics(MyMagics2)
678 self.check_ident('cellm4')
678 self.check_ident('cellm4')
679 # Check that nothing is registered as 'cellm33'
679 # Check that nothing is registered as 'cellm33'
680 c33 = _ip.find_cell_magic('cellm33')
680 c33 = _ip.find_cell_magic('cellm33')
681 nt.assert_equal(c33, None)
681 nt.assert_equal(c33, None)
682
682
683 def test_file():
683 def test_file():
684 """Basic %%file"""
684 """Basic %%file"""
685 ip = get_ipython()
685 ip = get_ipython()
686 with TemporaryDirectory() as td:
686 with TemporaryDirectory() as td:
687 fname = os.path.join(td, 'file1')
687 fname = os.path.join(td, 'file1')
688 ip.run_cell_magic("file", fname, u'\n'.join([
688 ip.run_cell_magic("file", fname, u'\n'.join([
689 'line1',
689 'line1',
690 'line2',
690 'line2',
691 ]))
691 ]))
692 with open(fname) as f:
692 with open(fname) as f:
693 s = f.read()
693 s = f.read()
694 nt.assert_in('line1\n', s)
694 nt.assert_in('line1\n', s)
695 nt.assert_in('line2', s)
695 nt.assert_in('line2', s)
696
696
697 def test_file_var_expand():
697 def test_file_var_expand():
698 """%%file $filename"""
698 """%%file $filename"""
699 ip = get_ipython()
699 ip = get_ipython()
700 with TemporaryDirectory() as td:
700 with TemporaryDirectory() as td:
701 fname = os.path.join(td, 'file1')
701 fname = os.path.join(td, 'file1')
702 ip.user_ns['filename'] = fname
702 ip.user_ns['filename'] = fname
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
704 'line1',
704 'line1',
705 'line2',
705 'line2',
706 ]))
706 ]))
707 with open(fname) as f:
707 with open(fname) as f:
708 s = f.read()
708 s = f.read()
709 nt.assert_in('line1\n', s)
709 nt.assert_in('line1\n', s)
710 nt.assert_in('line2', s)
710 nt.assert_in('line2', s)
711
711
712 def test_file_unicode():
712 def test_file_unicode():
713 """%%file with unicode cell"""
713 """%%file with unicode cell"""
714 ip = get_ipython()
714 ip = get_ipython()
715 with TemporaryDirectory() as td:
715 with TemporaryDirectory() as td:
716 fname = os.path.join(td, 'file1')
716 fname = os.path.join(td, 'file1')
717 ip.run_cell_magic("file", fname, u'\n'.join([
717 ip.run_cell_magic("file", fname, u'\n'.join([
718 u'linΓ©1',
718 u'linΓ©1',
719 u'linΓ©2',
719 u'linΓ©2',
720 ]))
720 ]))
721 with io.open(fname, encoding='utf-8') as f:
721 with io.open(fname, encoding='utf-8') as f:
722 s = f.read()
722 s = f.read()
723 nt.assert_in(u'linΓ©1\n', s)
723 nt.assert_in(u'linΓ©1\n', s)
724 nt.assert_in(u'linΓ©2', s)
724 nt.assert_in(u'linΓ©2', s)
725
725
726 def test_file_amend():
726 def test_file_amend():
727 """%%file -a amends files"""
727 """%%file -a amends files"""
728 ip = get_ipython()
728 ip = get_ipython()
729 with TemporaryDirectory() as td:
729 with TemporaryDirectory() as td:
730 fname = os.path.join(td, 'file2')
730 fname = os.path.join(td, 'file2')
731 ip.run_cell_magic("file", fname, u'\n'.join([
731 ip.run_cell_magic("file", fname, u'\n'.join([
732 'line1',
732 'line1',
733 'line2',
733 'line2',
734 ]))
734 ]))
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
736 'line3',
736 'line3',
737 'line4',
737 'line4',
738 ]))
738 ]))
739 with open(fname) as f:
739 with open(fname) as f:
740 s = f.read()
740 s = f.read()
741 nt.assert_in('line1\n', s)
741 nt.assert_in('line1\n', s)
742 nt.assert_in('line3\n', s)
742 nt.assert_in('line3\n', s)
743
743
744
744
745 def test_script_config():
745 def test_script_config():
746 ip = get_ipython()
746 ip = get_ipython()
747 ip.config.ScriptMagics.script_magics = ['whoda']
747 ip.config.ScriptMagics.script_magics = ['whoda']
748 sm = script.ScriptMagics(shell=ip)
748 sm = script.ScriptMagics(shell=ip)
749 nt.assert_in('whoda', sm.magics['cell'])
749 nt.assert_in('whoda', sm.magics['cell'])
750
750
751 @dec.skip_win32
751 @dec.skip_win32
752 def test_script_out():
752 def test_script_out():
753 ip = get_ipython()
753 ip = get_ipython()
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
756
756
757 @dec.skip_win32
757 @dec.skip_win32
758 def test_script_err():
758 def test_script_err():
759 ip = get_ipython()
759 ip = get_ipython()
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
762
762
763 @dec.skip_win32
763 @dec.skip_win32
764 def test_script_out_err():
764 def test_script_out_err():
765 ip = get_ipython()
765 ip = get_ipython()
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
769
769
770 @dec.skip_win32
770 @dec.skip_win32
771 def test_script_bg_out():
771 def test_script_bg_out():
772 ip = get_ipython()
772 ip = get_ipython()
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
775
775
776 @dec.skip_win32
776 @dec.skip_win32
777 def test_script_bg_err():
777 def test_script_bg_err():
778 ip = get_ipython()
778 ip = get_ipython()
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
781
781
782 @dec.skip_win32
782 @dec.skip_win32
783 def test_script_bg_out_err():
783 def test_script_bg_out_err():
784 ip = get_ipython()
784 ip = get_ipython()
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
788
788
789 def test_script_defaults():
789 def test_script_defaults():
790 ip = get_ipython()
790 ip = get_ipython()
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
792 try:
792 try:
793 find_cmd(cmd)
793 find_cmd(cmd)
794 except Exception:
794 except Exception:
795 pass
795 pass
796 else:
796 else:
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
798
798
799
799
800 @magics_class
800 @magics_class
801 class FooFoo(Magics):
801 class FooFoo(Magics):
802 """class with both %foo and %%foo magics"""
802 """class with both %foo and %%foo magics"""
803 @line_magic('foo')
803 @line_magic('foo')
804 def line_foo(self, line):
804 def line_foo(self, line):
805 "I am line foo"
805 "I am line foo"
806 pass
806 pass
807
807
808 @cell_magic("foo")
808 @cell_magic("foo")
809 def cell_foo(self, line, cell):
809 def cell_foo(self, line, cell):
810 "I am cell foo, not line foo"
810 "I am cell foo, not line foo"
811 pass
811 pass
812
812
813 def test_line_cell_info():
813 def test_line_cell_info():
814 """%%foo and %foo magics are distinguishable to inspect"""
814 """%%foo and %foo magics are distinguishable to inspect"""
815 ip = get_ipython()
815 ip = get_ipython()
816 ip.magics_manager.register(FooFoo)
816 ip.magics_manager.register(FooFoo)
817 oinfo = ip.object_inspect('foo')
817 oinfo = ip.object_inspect('foo')
818 nt.assert_true(oinfo['found'])
818 nt.assert_true(oinfo['found'])
819 nt.assert_true(oinfo['ismagic'])
819 nt.assert_true(oinfo['ismagic'])
820
820
821 oinfo = ip.object_inspect('%%foo')
821 oinfo = ip.object_inspect('%%foo')
822 nt.assert_true(oinfo['found'])
822 nt.assert_true(oinfo['found'])
823 nt.assert_true(oinfo['ismagic'])
823 nt.assert_true(oinfo['ismagic'])
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
825
825
826 oinfo = ip.object_inspect('%foo')
826 oinfo = ip.object_inspect('%foo')
827 nt.assert_true(oinfo['found'])
827 nt.assert_true(oinfo['found'])
828 nt.assert_true(oinfo['ismagic'])
828 nt.assert_true(oinfo['ismagic'])
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
830
830
831 def test_multiple_magics():
831 def test_multiple_magics():
832 ip = get_ipython()
832 ip = get_ipython()
833 foo1 = FooFoo(ip)
833 foo1 = FooFoo(ip)
834 foo2 = FooFoo(ip)
834 foo2 = FooFoo(ip)
835 mm = ip.magics_manager
835 mm = ip.magics_manager
836 mm.register(foo1)
836 mm.register(foo1)
837 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
837 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
838 mm.register(foo2)
838 mm.register(foo2)
839 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
839 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
840
840
841 def test_alias_magic():
841 def test_alias_magic():
842 """Test %alias_magic."""
842 """Test %alias_magic."""
843 ip = get_ipython()
843 ip = get_ipython()
844 mm = ip.magics_manager
844 mm = ip.magics_manager
845
845
846 # Basic operation: both cell and line magics are created, if possible.
846 # Basic operation: both cell and line magics are created, if possible.
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
848 nt.assert_in('timeit_alias', mm.magics['line'])
848 nt.assert_in('timeit_alias', mm.magics['line'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
850
850
851 # --cell is specified, line magic not created.
851 # --cell is specified, line magic not created.
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
855
855
856 # Test that line alias is created successfully.
856 # Test that line alias is created successfully.
857 ip.run_line_magic('alias_magic', '--line env_alias env')
857 ip.run_line_magic('alias_magic', '--line env_alias env')
858 nt.assert_equal(ip.run_line_magic('env', ''),
858 nt.assert_equal(ip.run_line_magic('env', ''),
859 ip.run_line_magic('env_alias', ''))
859 ip.run_line_magic('env_alias', ''))
860
860
861 def test_save():
861 def test_save():
862 """Test %save."""
862 """Test %save."""
863 ip = get_ipython()
863 ip = get_ipython()
864 ip.history_manager.reset() # Clear any existing history.
864 ip.history_manager.reset() # Clear any existing history.
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
866 for i, cmd in enumerate(cmds, start=1):
866 for i, cmd in enumerate(cmds, start=1):
867 ip.history_manager.store_inputs(i, cmd)
867 ip.history_manager.store_inputs(i, cmd)
868 with TemporaryDirectory() as tmpdir:
868 with TemporaryDirectory() as tmpdir:
869 file = os.path.join(tmpdir, "testsave.py")
869 file = os.path.join(tmpdir, "testsave.py")
870 ip.run_line_magic("save", "%s 1-10" % file)
870 ip.run_line_magic("save", "%s 1-10" % file)
871 with open(file) as f:
871 with open(file) as f:
872 content = f.read()
872 content = f.read()
873 nt.assert_equal(content.count(cmds[0]), 1)
873 nt.assert_equal(content.count(cmds[0]), 1)
874 nt.assert_in('coding: utf-8', content)
874 nt.assert_in('coding: utf-8', content)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
876 with open(file) as f:
876 with open(file) as f:
877 content = f.read()
877 content = f.read()
878 nt.assert_equal(content.count(cmds[0]), 2)
878 nt.assert_equal(content.count(cmds[0]), 2)
879 nt.assert_in('coding: utf-8', content)
879 nt.assert_in('coding: utf-8', content)
880
880
881
881
882 def test_store():
882 def test_store():
883 """Test %store."""
883 """Test %store."""
884 ip = get_ipython()
884 ip = get_ipython()
885 ip.run_line_magic('load_ext', 'storemagic')
885 ip.run_line_magic('load_ext', 'storemagic')
886
886
887 # make sure the storage is empty
887 # make sure the storage is empty
888 ip.run_line_magic('store', '-z')
888 ip.run_line_magic('store', '-z')
889 ip.user_ns['var'] = 42
889 ip.user_ns['var'] = 42
890 ip.run_line_magic('store', 'var')
890 ip.run_line_magic('store', 'var')
891 ip.user_ns['var'] = 39
891 ip.user_ns['var'] = 39
892 ip.run_line_magic('store', '-r')
892 ip.run_line_magic('store', '-r')
893 nt.assert_equal(ip.user_ns['var'], 42)
893 nt.assert_equal(ip.user_ns['var'], 42)
894
894
895 ip.run_line_magic('store', '-d var')
895 ip.run_line_magic('store', '-d var')
896 ip.user_ns['var'] = 39
896 ip.user_ns['var'] = 39
897 ip.run_line_magic('store' , '-r')
897 ip.run_line_magic('store' , '-r')
898 nt.assert_equal(ip.user_ns['var'], 39)
898 nt.assert_equal(ip.user_ns['var'], 39)
899
899
900
900
901 def _run_edit_test(arg_s, exp_filename=None,
901 def _run_edit_test(arg_s, exp_filename=None,
902 exp_lineno=-1,
902 exp_lineno=-1,
903 exp_contents=None,
903 exp_contents=None,
904 exp_is_temp=None):
904 exp_is_temp=None):
905 ip = get_ipython()
905 ip = get_ipython()
906 M = code.CodeMagics(ip)
906 M = code.CodeMagics(ip)
907 last_call = ['','']
907 last_call = ['','']
908 opts,args = M.parse_options(arg_s,'prxn:')
908 opts,args = M.parse_options(arg_s,'prxn:')
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
910
910
911 if exp_filename is not None:
911 if exp_filename is not None:
912 nt.assert_equal(exp_filename, filename)
912 nt.assert_equal(exp_filename, filename)
913 if exp_contents is not None:
913 if exp_contents is not None:
914 with io.open(filename, 'r', encoding='utf-8') as f:
914 with io.open(filename, 'r', encoding='utf-8') as f:
915 contents = f.read()
915 contents = f.read()
916 nt.assert_equal(exp_contents, contents)
916 nt.assert_equal(exp_contents, contents)
917 if exp_lineno != -1:
917 if exp_lineno != -1:
918 nt.assert_equal(exp_lineno, lineno)
918 nt.assert_equal(exp_lineno, lineno)
919 if exp_is_temp is not None:
919 if exp_is_temp is not None:
920 nt.assert_equal(exp_is_temp, is_temp)
920 nt.assert_equal(exp_is_temp, is_temp)
921
921
922
922
923 def test_edit_interactive():
923 def test_edit_interactive():
924 """%edit on interactively defined objects"""
924 """%edit on interactively defined objects"""
925 ip = get_ipython()
925 ip = get_ipython()
926 n = ip.execution_count
926 n = ip.execution_count
927 ip.run_cell(u"def foo(): return 1", store_history=True)
927 ip.run_cell(u"def foo(): return 1", store_history=True)
928
928
929 try:
929 try:
930 _run_edit_test("foo")
930 _run_edit_test("foo")
931 except code.InteractivelyDefined as e:
931 except code.InteractivelyDefined as e:
932 nt.assert_equal(e.index, n)
932 nt.assert_equal(e.index, n)
933 else:
933 else:
934 raise AssertionError("Should have raised InteractivelyDefined")
934 raise AssertionError("Should have raised InteractivelyDefined")
935
935
936
936
937 def test_edit_cell():
937 def test_edit_cell():
938 """%edit [cell id]"""
938 """%edit [cell id]"""
939 ip = get_ipython()
939 ip = get_ipython()
940
940
941 ip.run_cell(u"def foo(): return 1", store_history=True)
941 ip.run_cell(u"def foo(): return 1", store_history=True)
942
942
943 # test
943 # test
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
945
946 def test_bookmark():
947 ip = get_ipython()
948 ip.run_line_magic('bookmark', 'bmname')
949 with tt.AssertPrints('bmname'):
950 ip.run_line_magic('bookmark', '-l')
951 ip.run_line_magic('bookmark', '-d bmname')
General Comments 0
You need to be logged in to leave comments. Login now