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