##// END OF EJS Templates
updated comments. removed debug print statement
kd2718 -
Show More
@@ -1,832 +1,832
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 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import io
9 import io
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13 from pprint import pformat
13 from pprint import pformat
14
14
15 from IPython.core import magic_arguments
15 from IPython.core import magic_arguments
16 from IPython.core import oinspect
16 from IPython.core import oinspect
17 from IPython.core import page
17 from IPython.core import page
18 from IPython.core.alias import AliasError, Alias
18 from IPython.core.alias import AliasError, Alias
19 from IPython.core.error import UsageError
19 from IPython.core.error import UsageError
20 from IPython.core.magic import (
20 from IPython.core.magic import (
21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
22 )
22 )
23 from IPython.testing.skipdoctest import skip_doctest
23 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.utils.openpy import source_to_unicode
24 from IPython.utils.openpy import source_to_unicode
25 from IPython.utils.process import abbrev_cwd
25 from IPython.utils.process import abbrev_cwd
26 from IPython.utils.terminal import set_term_title
26 from IPython.utils.terminal import set_term_title
27
27
28
28
29 @magics_class
29 @magics_class
30 class OSMagics(Magics):
30 class OSMagics(Magics):
31 """Magics to interact with the underlying OS (shell-type functionality).
31 """Magics to interact with the underlying OS (shell-type functionality).
32 """
32 """
33
33
34 def __init__(self, shell=None, **kwargs):
34 def __init__(self, shell=None, **kwargs):
35
35
36 # Now define isexec in a cross platform manner.
36 # Now define isexec in a cross platform manner.
37 self.is_posix = False
37 self.is_posix = False
38 self.execre = None
38 self.execre = None
39 if os.name == 'posix':
39 if os.name == 'posix':
40 self.is_posix = True
40 self.is_posix = True
41 else:
41 else:
42 try:
42 try:
43 winext = os.environ['pathext'].replace(';','|').replace('.','')
43 winext = os.environ['pathext'].replace(';','|').replace('.','')
44 except KeyError:
44 except KeyError:
45 winext = 'exe|com|bat|py'
45 winext = 'exe|com|bat|py'
46
46
47 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
47 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
48
48
49 # call up the chain
49 # call up the chain
50 super(OSMagics, self).__init__(shell=shell, **kwargs)
50 super(OSMagics, self).__init__(shell=shell, **kwargs)
51
51
52
52
53 @skip_doctest
53 @skip_doctest
54 def _isexec_POSIX(self, file):
54 def _isexec_POSIX(self, file):
55 """
55 """
56 Test for executible on a POSIX system
56 Test for executible on a POSIX system
57 """
57 """
58 return file.is_file() and os.access(file.path, os.X_OK)
58 return file.is_file() and os.access(file.path, os.X_OK)
59
59
60
60
61 @skip_doctest
61 @skip_doctest
62 def _isexec_WIN(self, file):
62 def _isexec_WIN(self, file):
63 """
63 """
64 Test for executible file on non POSIX system
64 Test for executible file on non POSIX system
65 """
65 """
66 return file.is_file() and self.execre.match(file.name) is not None
66 return file.is_file() and self.execre.match(file.name) is not None
67
67
68 @skip_doctest
68 @skip_doctest
69 def isexec(self, file):
69 def isexec(self, file):
70 """
70 """
71 Test for executible file on non POSIX system
71 Test for executible file on non POSIX system
72 """
72 """
73 if self.is_posix:
73 if self.is_posix:
74 return self._isexec_POSIX(file)
74 return self._isexec_POSIX(file)
75 else:
75 else:
76 return self._isexec_WIN(file)
76 return self._isexec_WIN(file)
77
77
78
78
79 @skip_doctest
79 @skip_doctest
80 @line_magic
80 @line_magic
81 def alias(self, parameter_s=''):
81 def alias(self, parameter_s=''):
82 """Define an alias for a system command.
82 """Define an alias for a system command.
83
83
84 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
84 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
85
85
86 Then, typing 'alias_name params' will execute the system command 'cmd
86 Then, typing 'alias_name params' will execute the system command 'cmd
87 params' (from your underlying operating system).
87 params' (from your underlying operating system).
88
88
89 Aliases have lower precedence than magic functions and Python normal
89 Aliases have lower precedence than magic functions and Python normal
90 variables, so if 'foo' is both a Python variable and an alias, the
90 variables, so if 'foo' is both a Python variable and an alias, the
91 alias can not be executed until 'del foo' removes the Python variable.
91 alias can not be executed until 'del foo' removes the Python variable.
92
92
93 You can use the %l specifier in an alias definition to represent the
93 You can use the %l specifier in an alias definition to represent the
94 whole line when the alias is called. For example::
94 whole line when the alias is called. For example::
95
95
96 In [2]: alias bracket echo "Input in brackets: <%l>"
96 In [2]: alias bracket echo "Input in brackets: <%l>"
97 In [3]: bracket hello world
97 In [3]: bracket hello world
98 Input in brackets: <hello world>
98 Input in brackets: <hello world>
99
99
100 You can also define aliases with parameters using %s specifiers (one
100 You can also define aliases with parameters using %s specifiers (one
101 per parameter)::
101 per parameter)::
102
102
103 In [1]: alias parts echo first %s second %s
103 In [1]: alias parts echo first %s second %s
104 In [2]: %parts A B
104 In [2]: %parts A B
105 first A second B
105 first A second B
106 In [3]: %parts A
106 In [3]: %parts A
107 Incorrect number of arguments: 2 expected.
107 Incorrect number of arguments: 2 expected.
108 parts is an alias to: 'echo first %s second %s'
108 parts is an alias to: 'echo first %s second %s'
109
109
110 Note that %l and %s are mutually exclusive. You can only use one or
110 Note that %l and %s are mutually exclusive. You can only use one or
111 the other in your aliases.
111 the other in your aliases.
112
112
113 Aliases expand Python variables just like system calls using ! or !!
113 Aliases expand Python variables just like system calls using ! or !!
114 do: all expressions prefixed with '$' get expanded. For details of
114 do: all expressions prefixed with '$' get expanded. For details of
115 the semantic rules, see PEP-215:
115 the semantic rules, see PEP-215:
116 http://www.python.org/peps/pep-0215.html. This is the library used by
116 http://www.python.org/peps/pep-0215.html. This is the library used by
117 IPython for variable expansion. If you want to access a true shell
117 IPython for variable expansion. If you want to access a true shell
118 variable, an extra $ is necessary to prevent its expansion by
118 variable, an extra $ is necessary to prevent its expansion by
119 IPython::
119 IPython::
120
120
121 In [6]: alias show echo
121 In [6]: alias show echo
122 In [7]: PATH='A Python string'
122 In [7]: PATH='A Python string'
123 In [8]: show $PATH
123 In [8]: show $PATH
124 A Python string
124 A Python string
125 In [9]: show $$PATH
125 In [9]: show $$PATH
126 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
126 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
127
127
128 You can use the alias facility to access all of $PATH. See the %rehashx
128 You can use the alias facility to access all of $PATH. See the %rehashx
129 function, which automatically creates aliases for the contents of your
129 function, which automatically creates aliases for the contents of your
130 $PATH.
130 $PATH.
131
131
132 If called with no parameters, %alias prints the current alias table
132 If called with no parameters, %alias prints the current alias table
133 for your system. For posix systems, the default aliases are 'cat',
133 for your system. For posix systems, the default aliases are 'cat',
134 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
134 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
135 aliases are added. For windows-based systems, the default aliases are
135 aliases are added. For windows-based systems, the default aliases are
136 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
136 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
137
137
138 You can see the definition of alias by adding a question mark in the
138 You can see the definition of alias by adding a question mark in the
139 end::
139 end::
140
140
141 In [1]: cat?
141 In [1]: cat?
142 Repr: <alias cat for 'cat'>"""
142 Repr: <alias cat for 'cat'>"""
143
143
144 par = parameter_s.strip()
144 par = parameter_s.strip()
145 if not par:
145 if not par:
146 aliases = sorted(self.shell.alias_manager.aliases)
146 aliases = sorted(self.shell.alias_manager.aliases)
147 # stored = self.shell.db.get('stored_aliases', {} )
147 # stored = self.shell.db.get('stored_aliases', {} )
148 # for k, v in stored:
148 # for k, v in stored:
149 # atab.append(k, v[0])
149 # atab.append(k, v[0])
150
150
151 print("Total number of aliases:", len(aliases))
151 print("Total number of aliases:", len(aliases))
152 sys.stdout.flush()
152 sys.stdout.flush()
153 return aliases
153 return aliases
154
154
155 # Now try to define a new one
155 # Now try to define a new one
156 try:
156 try:
157 alias,cmd = par.split(None, 1)
157 alias,cmd = par.split(None, 1)
158 except TypeError:
158 except TypeError:
159 print(oinspect.getdoc(self.alias))
159 print(oinspect.getdoc(self.alias))
160 return
160 return
161
161
162 try:
162 try:
163 self.shell.alias_manager.define_alias(alias, cmd)
163 self.shell.alias_manager.define_alias(alias, cmd)
164 except AliasError as e:
164 except AliasError as e:
165 print(e)
165 print(e)
166 # end magic_alias
166 # end magic_alias
167
167
168 @line_magic
168 @line_magic
169 def unalias(self, parameter_s=''):
169 def unalias(self, parameter_s=''):
170 """Remove an alias"""
170 """Remove an alias"""
171
171
172 aname = parameter_s.strip()
172 aname = parameter_s.strip()
173 try:
173 try:
174 self.shell.alias_manager.undefine_alias(aname)
174 self.shell.alias_manager.undefine_alias(aname)
175 except ValueError as e:
175 except ValueError as e:
176 print(e)
176 print(e)
177 return
177 return
178
178
179 stored = self.shell.db.get('stored_aliases', {} )
179 stored = self.shell.db.get('stored_aliases', {} )
180 if aname in stored:
180 if aname in stored:
181 print("Removing %stored alias",aname)
181 print("Removing %stored alias",aname)
182 del stored[aname]
182 del stored[aname]
183 self.shell.db['stored_aliases'] = stored
183 self.shell.db['stored_aliases'] = stored
184
184
185 @line_magic
185 @line_magic
186 def rehashx(self, parameter_s=''):
186 def rehashx(self, parameter_s=''):
187 """Update the alias table with all executable files in $PATH.
187 """Update the alias table with all executable files in $PATH.
188
188
189 rehashx explicitly checks that every entry in $PATH is a file
189 rehashx explicitly checks that every entry in $PATH is a file
190 with execute access (os.X_OK).
190 with execute access (os.X_OK).
191
191
192 Under Windows, it checks executability as a match against a
192 Under Windows, it checks executability as a match against a
193 '|'-separated string of extensions, stored in the IPython config
193 '|'-separated string of extensions, stored in the IPython config
194 variable win_exec_ext. This defaults to 'exe|com|bat'.
194 variable win_exec_ext. This defaults to 'exe|com|bat'.
195
195
196 This function also resets the root module cache of module completer,
196 This function also resets the root module cache of module completer,
197 used on slow filesystems.
197 used on slow filesystems.
198 """
198 """
199 from IPython.core.alias import InvalidAliasError
199 from IPython.core.alias import InvalidAliasError
200
200
201 # for the benefit of module completer in ipy_completers.py
201 # for the benefit of module completer in ipy_completers.py
202 del self.shell.db['rootmodules_cache']
202 del self.shell.db['rootmodules_cache']
203
203
204 path = [os.path.abspath(os.path.expanduser(p)) for p in
204 path = [os.path.abspath(os.path.expanduser(p)) for p in
205 os.environ.get('PATH','').split(os.pathsep)]
205 os.environ.get('PATH','').split(os.pathsep)]
206
206
207 syscmdlist = []
207 syscmdlist = []
208 savedir = os.getcwd()
208 savedir = os.getcwd()
209
209
210 # Now walk the paths looking for executables to alias.
210 # Now walk the paths looking for executables to alias.
211 try:
211 try:
212 # write the whole loop for posix/Windows so we don't have an if in
212 # write the whole loop for posix/Windows so we don't have an if in
213 # the innermost part
213 # the innermost part
214 if self.is_posix:
214 if self.is_posix:
215 print(path)
216 for pdir in path:
215 for pdir in path:
217 try:
216 try:
218 os.chdir(pdir)
217 os.chdir(pdir)
219 except OSError:
218 except OSError:
220 continue
219 continue
221
220
222 # use with notation for python 3.6 onward
221 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
223 dirlist = os.scandir(path=pdir)
222 dirlist = os.scandir(path=pdir)
224 for ff in dirlist:
223 for ff in dirlist:
225 if self.isexec(ff):
224 if self.isexec(ff):
226 fname = ff.name
225 fname = ff.name
227 try:
226 try:
228 # Removes dots from the name since ipython
227 # Removes dots from the name since ipython
229 # will assume names with dots to be python.
228 # will assume names with dots to be python.
230 if not self.shell.alias_manager.is_alias(fname):
229 if not self.shell.alias_manager.is_alias(fname):
231 self.shell.alias_manager.define_alias(
230 self.shell.alias_manager.define_alias(
232 fname.replace('.',''), fname)
231 fname.replace('.',''), fname)
233 except InvalidAliasError:
232 except InvalidAliasError:
234 pass
233 pass
235 else:
234 else:
236 syscmdlist.append(fname)
235 syscmdlist.append(fname)
237 else:
236 else:
238 no_alias = Alias.blacklist
237 no_alias = Alias.blacklist
239 for pdir in path:
238 for pdir in path:
240 try:
239 try:
241 os.chdir(pdir)
240 os.chdir(pdir)
242 except OSError:
241 except OSError:
243 continue
242 continue
244
243
245 # use with notation for python 3.6 onward
244 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
246 dirlist = os.scandir(pdir)
245 dirlist = os.scandir(pdir)
247 for ff in dirlist:
246 for ff in dirlist:
248 fname = ff.name
247 fname = ff.name
249 base, ext = os.path.splitext(fname)
248 base, ext = os.path.splitext(fname)
250 if self.isexec(ff) and base.lower() not in no_alias:
249 if self.isexec(ff) and base.lower() not in no_alias:
251 if ext.lower() == '.exe':
250 if ext.lower() == '.exe':
252 fname = base
251 fname = base
253 try:
252 try:
254 # Removes dots from the name since ipython
253 # Removes dots from the name since ipython
255 # will assume names with dots to be python.
254 # will assume names with dots to be python.
256 self.shell.alias_manager.define_alias(
255 self.shell.alias_manager.define_alias(
257 base.lower().replace('.',''), fname)
256 base.lower().replace('.',''), fname)
258 except InvalidAliasError:
257 except InvalidAliasError:
259 pass
258 pass
260 syscmdlist.append(fname)
259 syscmdlist.append(fname)
260
261 self.shell.db['syscmdlist'] = syscmdlist
261 self.shell.db['syscmdlist'] = syscmdlist
262 finally:
262 finally:
263 os.chdir(savedir)
263 os.chdir(savedir)
264
264
265 @skip_doctest
265 @skip_doctest
266 @line_magic
266 @line_magic
267 def pwd(self, parameter_s=''):
267 def pwd(self, parameter_s=''):
268 """Return the current working directory path.
268 """Return the current working directory path.
269
269
270 Examples
270 Examples
271 --------
271 --------
272 ::
272 ::
273
273
274 In [9]: pwd
274 In [9]: pwd
275 Out[9]: '/home/tsuser/sprint/ipython'
275 Out[9]: '/home/tsuser/sprint/ipython'
276 """
276 """
277 try:
277 try:
278 return os.getcwd()
278 return os.getcwd()
279 except FileNotFoundError:
279 except FileNotFoundError:
280 raise UsageError("CWD no longer exists - please use %cd to change directory.")
280 raise UsageError("CWD no longer exists - please use %cd to change directory.")
281
281
282 @skip_doctest
282 @skip_doctest
283 @line_magic
283 @line_magic
284 def cd(self, parameter_s=''):
284 def cd(self, parameter_s=''):
285 """Change the current working directory.
285 """Change the current working directory.
286
286
287 This command automatically maintains an internal list of directories
287 This command automatically maintains an internal list of directories
288 you visit during your IPython session, in the variable _dh. The
288 you visit during your IPython session, in the variable _dh. The
289 command %dhist shows this history nicely formatted. You can also
289 command %dhist shows this history nicely formatted. You can also
290 do 'cd -<tab>' to see directory history conveniently.
290 do 'cd -<tab>' to see directory history conveniently.
291
291
292 Usage:
292 Usage:
293
293
294 cd 'dir': changes to directory 'dir'.
294 cd 'dir': changes to directory 'dir'.
295
295
296 cd -: changes to the last visited directory.
296 cd -: changes to the last visited directory.
297
297
298 cd -<n>: changes to the n-th directory in the directory history.
298 cd -<n>: changes to the n-th directory in the directory history.
299
299
300 cd --foo: change to directory that matches 'foo' in history
300 cd --foo: change to directory that matches 'foo' in history
301
301
302 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
302 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
303 (note: cd <bookmark_name> is enough if there is no
303 (note: cd <bookmark_name> is enough if there is no
304 directory <bookmark_name>, but a bookmark with the name exists.)
304 directory <bookmark_name>, but a bookmark with the name exists.)
305 'cd -b <tab>' allows you to tab-complete bookmark names.
305 'cd -b <tab>' allows you to tab-complete bookmark names.
306
306
307 Options:
307 Options:
308
308
309 -q: quiet. Do not print the working directory after the cd command is
309 -q: quiet. Do not print the working directory after the cd command is
310 executed. By default IPython's cd command does print this directory,
310 executed. By default IPython's cd command does print this directory,
311 since the default prompts do not display path information.
311 since the default prompts do not display path information.
312
312
313 Note that !cd doesn't work for this purpose because the shell where
313 Note that !cd doesn't work for this purpose because the shell where
314 !command runs is immediately discarded after executing 'command'.
314 !command runs is immediately discarded after executing 'command'.
315
315
316 Examples
316 Examples
317 --------
317 --------
318 ::
318 ::
319
319
320 In [10]: cd parent/child
320 In [10]: cd parent/child
321 /home/tsuser/parent/child
321 /home/tsuser/parent/child
322 """
322 """
323
323
324 try:
324 try:
325 oldcwd = os.getcwd()
325 oldcwd = os.getcwd()
326 except FileNotFoundError:
326 except FileNotFoundError:
327 # Happens if the CWD has been deleted.
327 # Happens if the CWD has been deleted.
328 oldcwd = None
328 oldcwd = None
329
329
330 numcd = re.match(r'(-)(\d+)$',parameter_s)
330 numcd = re.match(r'(-)(\d+)$',parameter_s)
331 # jump in directory history by number
331 # jump in directory history by number
332 if numcd:
332 if numcd:
333 nn = int(numcd.group(2))
333 nn = int(numcd.group(2))
334 try:
334 try:
335 ps = self.shell.user_ns['_dh'][nn]
335 ps = self.shell.user_ns['_dh'][nn]
336 except IndexError:
336 except IndexError:
337 print('The requested directory does not exist in history.')
337 print('The requested directory does not exist in history.')
338 return
338 return
339 else:
339 else:
340 opts = {}
340 opts = {}
341 elif parameter_s.startswith('--'):
341 elif parameter_s.startswith('--'):
342 ps = None
342 ps = None
343 fallback = None
343 fallback = None
344 pat = parameter_s[2:]
344 pat = parameter_s[2:]
345 dh = self.shell.user_ns['_dh']
345 dh = self.shell.user_ns['_dh']
346 # first search only by basename (last component)
346 # first search only by basename (last component)
347 for ent in reversed(dh):
347 for ent in reversed(dh):
348 if pat in os.path.basename(ent) and os.path.isdir(ent):
348 if pat in os.path.basename(ent) and os.path.isdir(ent):
349 ps = ent
349 ps = ent
350 break
350 break
351
351
352 if fallback is None and pat in ent and os.path.isdir(ent):
352 if fallback is None and pat in ent and os.path.isdir(ent):
353 fallback = ent
353 fallback = ent
354
354
355 # if we have no last part match, pick the first full path match
355 # if we have no last part match, pick the first full path match
356 if ps is None:
356 if ps is None:
357 ps = fallback
357 ps = fallback
358
358
359 if ps is None:
359 if ps is None:
360 print("No matching entry in directory history")
360 print("No matching entry in directory history")
361 return
361 return
362 else:
362 else:
363 opts = {}
363 opts = {}
364
364
365
365
366 else:
366 else:
367 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
367 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
368 # jump to previous
368 # jump to previous
369 if ps == '-':
369 if ps == '-':
370 try:
370 try:
371 ps = self.shell.user_ns['_dh'][-2]
371 ps = self.shell.user_ns['_dh'][-2]
372 except IndexError:
372 except IndexError:
373 raise UsageError('%cd -: No previous directory to change to.')
373 raise UsageError('%cd -: No previous directory to change to.')
374 # jump to bookmark if needed
374 # jump to bookmark if needed
375 else:
375 else:
376 if not os.path.isdir(ps) or 'b' in opts:
376 if not os.path.isdir(ps) or 'b' in opts:
377 bkms = self.shell.db.get('bookmarks', {})
377 bkms = self.shell.db.get('bookmarks', {})
378
378
379 if ps in bkms:
379 if ps in bkms:
380 target = bkms[ps]
380 target = bkms[ps]
381 print('(bookmark:%s) -> %s' % (ps, target))
381 print('(bookmark:%s) -> %s' % (ps, target))
382 ps = target
382 ps = target
383 else:
383 else:
384 if 'b' in opts:
384 if 'b' in opts:
385 raise UsageError("Bookmark '%s' not found. "
385 raise UsageError("Bookmark '%s' not found. "
386 "Use '%%bookmark -l' to see your bookmarks." % ps)
386 "Use '%%bookmark -l' to see your bookmarks." % ps)
387
387
388 # at this point ps should point to the target dir
388 # at this point ps should point to the target dir
389 if ps:
389 if ps:
390 try:
390 try:
391 os.chdir(os.path.expanduser(ps))
391 os.chdir(os.path.expanduser(ps))
392 if hasattr(self.shell, 'term_title') and self.shell.term_title:
392 if hasattr(self.shell, 'term_title') and self.shell.term_title:
393 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
393 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
394 except OSError:
394 except OSError:
395 print(sys.exc_info()[1])
395 print(sys.exc_info()[1])
396 else:
396 else:
397 cwd = os.getcwd()
397 cwd = os.getcwd()
398 dhist = self.shell.user_ns['_dh']
398 dhist = self.shell.user_ns['_dh']
399 if oldcwd != cwd:
399 if oldcwd != cwd:
400 dhist.append(cwd)
400 dhist.append(cwd)
401 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
401 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
402
402
403 else:
403 else:
404 os.chdir(self.shell.home_dir)
404 os.chdir(self.shell.home_dir)
405 if hasattr(self.shell, 'term_title') and self.shell.term_title:
405 if hasattr(self.shell, 'term_title') and self.shell.term_title:
406 set_term_title(self.shell.term_title_format.format(cwd="~"))
406 set_term_title(self.shell.term_title_format.format(cwd="~"))
407 cwd = os.getcwd()
407 cwd = os.getcwd()
408 dhist = self.shell.user_ns['_dh']
408 dhist = self.shell.user_ns['_dh']
409
409
410 if oldcwd != cwd:
410 if oldcwd != cwd:
411 dhist.append(cwd)
411 dhist.append(cwd)
412 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
412 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
413 if not 'q' in opts and self.shell.user_ns['_dh']:
413 if not 'q' in opts and self.shell.user_ns['_dh']:
414 print(self.shell.user_ns['_dh'][-1])
414 print(self.shell.user_ns['_dh'][-1])
415
415
416 @line_magic
416 @line_magic
417 def env(self, parameter_s=''):
417 def env(self, parameter_s=''):
418 """Get, set, or list environment variables.
418 """Get, set, or list environment variables.
419
419
420 Usage:\\
420 Usage:\\
421
421
422 %env: lists all environment variables/values
422 %env: lists all environment variables/values
423 %env var: get value for var
423 %env var: get value for var
424 %env var val: set value for var
424 %env var val: set value for var
425 %env var=val: set value for var
425 %env var=val: set value for var
426 %env var=$val: set value for var, using python expansion if possible
426 %env var=$val: set value for var, using python expansion if possible
427 """
427 """
428 if parameter_s.strip():
428 if parameter_s.strip():
429 split = '=' if '=' in parameter_s else ' '
429 split = '=' if '=' in parameter_s else ' '
430 bits = parameter_s.split(split)
430 bits = parameter_s.split(split)
431 if len(bits) == 1:
431 if len(bits) == 1:
432 key = parameter_s.strip()
432 key = parameter_s.strip()
433 if key in os.environ:
433 if key in os.environ:
434 return os.environ[key]
434 return os.environ[key]
435 else:
435 else:
436 err = "Environment does not have key: {0}".format(key)
436 err = "Environment does not have key: {0}".format(key)
437 raise UsageError(err)
437 raise UsageError(err)
438 if len(bits) > 1:
438 if len(bits) > 1:
439 return self.set_env(parameter_s)
439 return self.set_env(parameter_s)
440 return dict(os.environ)
440 return dict(os.environ)
441
441
442 @line_magic
442 @line_magic
443 def set_env(self, parameter_s):
443 def set_env(self, parameter_s):
444 """Set environment variables. Assumptions are that either "val" is a
444 """Set environment variables. Assumptions are that either "val" is a
445 name in the user namespace, or val is something that evaluates to a
445 name in the user namespace, or val is something that evaluates to a
446 string.
446 string.
447
447
448 Usage:\\
448 Usage:\\
449 %set_env var val: set value for var
449 %set_env var val: set value for var
450 %set_env var=val: set value for var
450 %set_env var=val: set value for var
451 %set_env var=$val: set value for var, using python expansion if possible
451 %set_env var=$val: set value for var, using python expansion if possible
452 """
452 """
453 split = '=' if '=' in parameter_s else ' '
453 split = '=' if '=' in parameter_s else ' '
454 bits = parameter_s.split(split, 1)
454 bits = parameter_s.split(split, 1)
455 if not parameter_s.strip() or len(bits)<2:
455 if not parameter_s.strip() or len(bits)<2:
456 raise UsageError("usage is 'set_env var=val'")
456 raise UsageError("usage is 'set_env var=val'")
457 var = bits[0].strip()
457 var = bits[0].strip()
458 val = bits[1].strip()
458 val = bits[1].strip()
459 if re.match(r'.*\s.*', var):
459 if re.match(r'.*\s.*', var):
460 # an environment variable with whitespace is almost certainly
460 # an environment variable with whitespace is almost certainly
461 # not what the user intended. what's more likely is the wrong
461 # not what the user intended. what's more likely is the wrong
462 # split was chosen, ie for "set_env cmd_args A=B", we chose
462 # split was chosen, ie for "set_env cmd_args A=B", we chose
463 # '=' for the split and should have chosen ' '. to get around
463 # '=' for the split and should have chosen ' '. to get around
464 # this, users should just assign directly to os.environ or use
464 # this, users should just assign directly to os.environ or use
465 # standard magic {var} expansion.
465 # standard magic {var} expansion.
466 err = "refusing to set env var with whitespace: '{0}'"
466 err = "refusing to set env var with whitespace: '{0}'"
467 err = err.format(val)
467 err = err.format(val)
468 raise UsageError(err)
468 raise UsageError(err)
469 os.environ[var] = val
469 os.environ[var] = val
470 print('env: {0}={1}'.format(var,val))
470 print('env: {0}={1}'.format(var,val))
471
471
472 @line_magic
472 @line_magic
473 def pushd(self, parameter_s=''):
473 def pushd(self, parameter_s=''):
474 """Place the current dir on stack and change directory.
474 """Place the current dir on stack and change directory.
475
475
476 Usage:\\
476 Usage:\\
477 %pushd ['dirname']
477 %pushd ['dirname']
478 """
478 """
479
479
480 dir_s = self.shell.dir_stack
480 dir_s = self.shell.dir_stack
481 tgt = os.path.expanduser(parameter_s)
481 tgt = os.path.expanduser(parameter_s)
482 cwd = os.getcwd().replace(self.shell.home_dir,'~')
482 cwd = os.getcwd().replace(self.shell.home_dir,'~')
483 if tgt:
483 if tgt:
484 self.cd(parameter_s)
484 self.cd(parameter_s)
485 dir_s.insert(0,cwd)
485 dir_s.insert(0,cwd)
486 return self.shell.magic('dirs')
486 return self.shell.magic('dirs')
487
487
488 @line_magic
488 @line_magic
489 def popd(self, parameter_s=''):
489 def popd(self, parameter_s=''):
490 """Change to directory popped off the top of the stack.
490 """Change to directory popped off the top of the stack.
491 """
491 """
492 if not self.shell.dir_stack:
492 if not self.shell.dir_stack:
493 raise UsageError("%popd on empty stack")
493 raise UsageError("%popd on empty stack")
494 top = self.shell.dir_stack.pop(0)
494 top = self.shell.dir_stack.pop(0)
495 self.cd(top)
495 self.cd(top)
496 print("popd ->",top)
496 print("popd ->",top)
497
497
498 @line_magic
498 @line_magic
499 def dirs(self, parameter_s=''):
499 def dirs(self, parameter_s=''):
500 """Return the current directory stack."""
500 """Return the current directory stack."""
501
501
502 return self.shell.dir_stack
502 return self.shell.dir_stack
503
503
504 @line_magic
504 @line_magic
505 def dhist(self, parameter_s=''):
505 def dhist(self, parameter_s=''):
506 """Print your history of visited directories.
506 """Print your history of visited directories.
507
507
508 %dhist -> print full history\\
508 %dhist -> print full history\\
509 %dhist n -> print last n entries only\\
509 %dhist n -> print last n entries only\\
510 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
510 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
511
511
512 This history is automatically maintained by the %cd command, and
512 This history is automatically maintained by the %cd command, and
513 always available as the global list variable _dh. You can use %cd -<n>
513 always available as the global list variable _dh. You can use %cd -<n>
514 to go to directory number <n>.
514 to go to directory number <n>.
515
515
516 Note that most of time, you should view directory history by entering
516 Note that most of time, you should view directory history by entering
517 cd -<TAB>.
517 cd -<TAB>.
518
518
519 """
519 """
520
520
521 dh = self.shell.user_ns['_dh']
521 dh = self.shell.user_ns['_dh']
522 if parameter_s:
522 if parameter_s:
523 args = []
523 args = []
524 try:
524 try:
525 args = map(int,parameter_s.split())
525 args = map(int,parameter_s.split())
526 except:
526 except:
527 self.arg_err(self.dhist)
527 self.arg_err(self.dhist)
528 return
528 return
529 if len(args) == 1:
529 if len(args) == 1:
530 ini,fin = max(len(dh)-(args[0]),0),len(dh)
530 ini,fin = max(len(dh)-(args[0]),0),len(dh)
531 elif len(args) == 2:
531 elif len(args) == 2:
532 ini,fin = args
532 ini,fin = args
533 fin = min(fin, len(dh))
533 fin = min(fin, len(dh))
534 else:
534 else:
535 self.arg_err(self.dhist)
535 self.arg_err(self.dhist)
536 return
536 return
537 else:
537 else:
538 ini,fin = 0,len(dh)
538 ini,fin = 0,len(dh)
539 print('Directory history (kept in _dh)')
539 print('Directory history (kept in _dh)')
540 for i in range(ini, fin):
540 for i in range(ini, fin):
541 print("%d: %s" % (i, dh[i]))
541 print("%d: %s" % (i, dh[i]))
542
542
543 @skip_doctest
543 @skip_doctest
544 @line_magic
544 @line_magic
545 def sc(self, parameter_s=''):
545 def sc(self, parameter_s=''):
546 """Shell capture - run shell command and capture output (DEPRECATED use !).
546 """Shell capture - run shell command and capture output (DEPRECATED use !).
547
547
548 DEPRECATED. Suboptimal, retained for backwards compatibility.
548 DEPRECATED. Suboptimal, retained for backwards compatibility.
549
549
550 You should use the form 'var = !command' instead. Example:
550 You should use the form 'var = !command' instead. Example:
551
551
552 "%sc -l myfiles = ls ~" should now be written as
552 "%sc -l myfiles = ls ~" should now be written as
553
553
554 "myfiles = !ls ~"
554 "myfiles = !ls ~"
555
555
556 myfiles.s, myfiles.l and myfiles.n still apply as documented
556 myfiles.s, myfiles.l and myfiles.n still apply as documented
557 below.
557 below.
558
558
559 --
559 --
560 %sc [options] varname=command
560 %sc [options] varname=command
561
561
562 IPython will run the given command using commands.getoutput(), and
562 IPython will run the given command using commands.getoutput(), and
563 will then update the user's interactive namespace with a variable
563 will then update the user's interactive namespace with a variable
564 called varname, containing the value of the call. Your command can
564 called varname, containing the value of the call. Your command can
565 contain shell wildcards, pipes, etc.
565 contain shell wildcards, pipes, etc.
566
566
567 The '=' sign in the syntax is mandatory, and the variable name you
567 The '=' sign in the syntax is mandatory, and the variable name you
568 supply must follow Python's standard conventions for valid names.
568 supply must follow Python's standard conventions for valid names.
569
569
570 (A special format without variable name exists for internal use)
570 (A special format without variable name exists for internal use)
571
571
572 Options:
572 Options:
573
573
574 -l: list output. Split the output on newlines into a list before
574 -l: list output. Split the output on newlines into a list before
575 assigning it to the given variable. By default the output is stored
575 assigning it to the given variable. By default the output is stored
576 as a single string.
576 as a single string.
577
577
578 -v: verbose. Print the contents of the variable.
578 -v: verbose. Print the contents of the variable.
579
579
580 In most cases you should not need to split as a list, because the
580 In most cases you should not need to split as a list, because the
581 returned value is a special type of string which can automatically
581 returned value is a special type of string which can automatically
582 provide its contents either as a list (split on newlines) or as a
582 provide its contents either as a list (split on newlines) or as a
583 space-separated string. These are convenient, respectively, either
583 space-separated string. These are convenient, respectively, either
584 for sequential processing or to be passed to a shell command.
584 for sequential processing or to be passed to a shell command.
585
585
586 For example::
586 For example::
587
587
588 # Capture into variable a
588 # Capture into variable a
589 In [1]: sc a=ls *py
589 In [1]: sc a=ls *py
590
590
591 # a is a string with embedded newlines
591 # a is a string with embedded newlines
592 In [2]: a
592 In [2]: a
593 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
593 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
594
594
595 # which can be seen as a list:
595 # which can be seen as a list:
596 In [3]: a.l
596 In [3]: a.l
597 Out[3]: ['setup.py', 'win32_manual_post_install.py']
597 Out[3]: ['setup.py', 'win32_manual_post_install.py']
598
598
599 # or as a whitespace-separated string:
599 # or as a whitespace-separated string:
600 In [4]: a.s
600 In [4]: a.s
601 Out[4]: 'setup.py win32_manual_post_install.py'
601 Out[4]: 'setup.py win32_manual_post_install.py'
602
602
603 # a.s is useful to pass as a single command line:
603 # a.s is useful to pass as a single command line:
604 In [5]: !wc -l $a.s
604 In [5]: !wc -l $a.s
605 146 setup.py
605 146 setup.py
606 130 win32_manual_post_install.py
606 130 win32_manual_post_install.py
607 276 total
607 276 total
608
608
609 # while the list form is useful to loop over:
609 # while the list form is useful to loop over:
610 In [6]: for f in a.l:
610 In [6]: for f in a.l:
611 ...: !wc -l $f
611 ...: !wc -l $f
612 ...:
612 ...:
613 146 setup.py
613 146 setup.py
614 130 win32_manual_post_install.py
614 130 win32_manual_post_install.py
615
615
616 Similarly, the lists returned by the -l option are also special, in
616 Similarly, the lists returned by the -l option are also special, in
617 the sense that you can equally invoke the .s attribute on them to
617 the sense that you can equally invoke the .s attribute on them to
618 automatically get a whitespace-separated string from their contents::
618 automatically get a whitespace-separated string from their contents::
619
619
620 In [7]: sc -l b=ls *py
620 In [7]: sc -l b=ls *py
621
621
622 In [8]: b
622 In [8]: b
623 Out[8]: ['setup.py', 'win32_manual_post_install.py']
623 Out[8]: ['setup.py', 'win32_manual_post_install.py']
624
624
625 In [9]: b.s
625 In [9]: b.s
626 Out[9]: 'setup.py win32_manual_post_install.py'
626 Out[9]: 'setup.py win32_manual_post_install.py'
627
627
628 In summary, both the lists and strings used for output capture have
628 In summary, both the lists and strings used for output capture have
629 the following special attributes::
629 the following special attributes::
630
630
631 .l (or .list) : value as list.
631 .l (or .list) : value as list.
632 .n (or .nlstr): value as newline-separated string.
632 .n (or .nlstr): value as newline-separated string.
633 .s (or .spstr): value as space-separated string.
633 .s (or .spstr): value as space-separated string.
634 """
634 """
635
635
636 opts,args = self.parse_options(parameter_s, 'lv')
636 opts,args = self.parse_options(parameter_s, 'lv')
637 # Try to get a variable name and command to run
637 # Try to get a variable name and command to run
638 try:
638 try:
639 # the variable name must be obtained from the parse_options
639 # the variable name must be obtained from the parse_options
640 # output, which uses shlex.split to strip options out.
640 # output, which uses shlex.split to strip options out.
641 var,_ = args.split('=', 1)
641 var,_ = args.split('=', 1)
642 var = var.strip()
642 var = var.strip()
643 # But the command has to be extracted from the original input
643 # But the command has to be extracted from the original input
644 # parameter_s, not on what parse_options returns, to avoid the
644 # parameter_s, not on what parse_options returns, to avoid the
645 # quote stripping which shlex.split performs on it.
645 # quote stripping which shlex.split performs on it.
646 _,cmd = parameter_s.split('=', 1)
646 _,cmd = parameter_s.split('=', 1)
647 except ValueError:
647 except ValueError:
648 var,cmd = '',''
648 var,cmd = '',''
649 # If all looks ok, proceed
649 # If all looks ok, proceed
650 split = 'l' in opts
650 split = 'l' in opts
651 out = self.shell.getoutput(cmd, split=split)
651 out = self.shell.getoutput(cmd, split=split)
652 if 'v' in opts:
652 if 'v' in opts:
653 print('%s ==\n%s' % (var, pformat(out)))
653 print('%s ==\n%s' % (var, pformat(out)))
654 if var:
654 if var:
655 self.shell.user_ns.update({var:out})
655 self.shell.user_ns.update({var:out})
656 else:
656 else:
657 return out
657 return out
658
658
659 @line_cell_magic
659 @line_cell_magic
660 def sx(self, line='', cell=None):
660 def sx(self, line='', cell=None):
661 """Shell execute - run shell command and capture output (!! is short-hand).
661 """Shell execute - run shell command and capture output (!! is short-hand).
662
662
663 %sx command
663 %sx command
664
664
665 IPython will run the given command using commands.getoutput(), and
665 IPython will run the given command using commands.getoutput(), and
666 return the result formatted as a list (split on '\\n'). Since the
666 return the result formatted as a list (split on '\\n'). Since the
667 output is _returned_, it will be stored in ipython's regular output
667 output is _returned_, it will be stored in ipython's regular output
668 cache Out[N] and in the '_N' automatic variables.
668 cache Out[N] and in the '_N' automatic variables.
669
669
670 Notes:
670 Notes:
671
671
672 1) If an input line begins with '!!', then %sx is automatically
672 1) If an input line begins with '!!', then %sx is automatically
673 invoked. That is, while::
673 invoked. That is, while::
674
674
675 !ls
675 !ls
676
676
677 causes ipython to simply issue system('ls'), typing::
677 causes ipython to simply issue system('ls'), typing::
678
678
679 !!ls
679 !!ls
680
680
681 is a shorthand equivalent to::
681 is a shorthand equivalent to::
682
682
683 %sx ls
683 %sx ls
684
684
685 2) %sx differs from %sc in that %sx automatically splits into a list,
685 2) %sx differs from %sc in that %sx automatically splits into a list,
686 like '%sc -l'. The reason for this is to make it as easy as possible
686 like '%sc -l'. The reason for this is to make it as easy as possible
687 to process line-oriented shell output via further python commands.
687 to process line-oriented shell output via further python commands.
688 %sc is meant to provide much finer control, but requires more
688 %sc is meant to provide much finer control, but requires more
689 typing.
689 typing.
690
690
691 3) Just like %sc -l, this is a list with special attributes:
691 3) Just like %sc -l, this is a list with special attributes:
692 ::
692 ::
693
693
694 .l (or .list) : value as list.
694 .l (or .list) : value as list.
695 .n (or .nlstr): value as newline-separated string.
695 .n (or .nlstr): value as newline-separated string.
696 .s (or .spstr): value as whitespace-separated string.
696 .s (or .spstr): value as whitespace-separated string.
697
697
698 This is very useful when trying to use such lists as arguments to
698 This is very useful when trying to use such lists as arguments to
699 system commands."""
699 system commands."""
700
700
701 if cell is None:
701 if cell is None:
702 # line magic
702 # line magic
703 return self.shell.getoutput(line)
703 return self.shell.getoutput(line)
704 else:
704 else:
705 opts,args = self.parse_options(line, '', 'out=')
705 opts,args = self.parse_options(line, '', 'out=')
706 output = self.shell.getoutput(cell)
706 output = self.shell.getoutput(cell)
707 out_name = opts.get('out', opts.get('o'))
707 out_name = opts.get('out', opts.get('o'))
708 if out_name:
708 if out_name:
709 self.shell.user_ns[out_name] = output
709 self.shell.user_ns[out_name] = output
710 else:
710 else:
711 return output
711 return output
712
712
713 system = line_cell_magic('system')(sx)
713 system = line_cell_magic('system')(sx)
714 bang = cell_magic('!')(sx)
714 bang = cell_magic('!')(sx)
715
715
716 @line_magic
716 @line_magic
717 def bookmark(self, parameter_s=''):
717 def bookmark(self, parameter_s=''):
718 """Manage IPython's bookmark system.
718 """Manage IPython's bookmark system.
719
719
720 %bookmark <name> - set bookmark to current dir
720 %bookmark <name> - set bookmark to current dir
721 %bookmark <name> <dir> - set bookmark to <dir>
721 %bookmark <name> <dir> - set bookmark to <dir>
722 %bookmark -l - list all bookmarks
722 %bookmark -l - list all bookmarks
723 %bookmark -d <name> - remove bookmark
723 %bookmark -d <name> - remove bookmark
724 %bookmark -r - remove all bookmarks
724 %bookmark -r - remove all bookmarks
725
725
726 You can later on access a bookmarked folder with::
726 You can later on access a bookmarked folder with::
727
727
728 %cd -b <name>
728 %cd -b <name>
729
729
730 or simply '%cd <name>' if there is no directory called <name> AND
730 or simply '%cd <name>' if there is no directory called <name> AND
731 there is such a bookmark defined.
731 there is such a bookmark defined.
732
732
733 Your bookmarks persist through IPython sessions, but they are
733 Your bookmarks persist through IPython sessions, but they are
734 associated with each profile."""
734 associated with each profile."""
735
735
736 opts,args = self.parse_options(parameter_s,'drl',mode='list')
736 opts,args = self.parse_options(parameter_s,'drl',mode='list')
737 if len(args) > 2:
737 if len(args) > 2:
738 raise UsageError("%bookmark: too many arguments")
738 raise UsageError("%bookmark: too many arguments")
739
739
740 bkms = self.shell.db.get('bookmarks',{})
740 bkms = self.shell.db.get('bookmarks',{})
741
741
742 if 'd' in opts:
742 if 'd' in opts:
743 try:
743 try:
744 todel = args[0]
744 todel = args[0]
745 except IndexError:
745 except IndexError:
746 raise UsageError(
746 raise UsageError(
747 "%bookmark -d: must provide a bookmark to delete")
747 "%bookmark -d: must provide a bookmark to delete")
748 else:
748 else:
749 try:
749 try:
750 del bkms[todel]
750 del bkms[todel]
751 except KeyError:
751 except KeyError:
752 raise UsageError(
752 raise UsageError(
753 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
753 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
754
754
755 elif 'r' in opts:
755 elif 'r' in opts:
756 bkms = {}
756 bkms = {}
757 elif 'l' in opts:
757 elif 'l' in opts:
758 bks = sorted(bkms)
758 bks = sorted(bkms)
759 if bks:
759 if bks:
760 size = max(map(len, bks))
760 size = max(map(len, bks))
761 else:
761 else:
762 size = 0
762 size = 0
763 fmt = '%-'+str(size)+'s -> %s'
763 fmt = '%-'+str(size)+'s -> %s'
764 print('Current bookmarks:')
764 print('Current bookmarks:')
765 for bk in bks:
765 for bk in bks:
766 print(fmt % (bk, bkms[bk]))
766 print(fmt % (bk, bkms[bk]))
767 else:
767 else:
768 if not args:
768 if not args:
769 raise UsageError("%bookmark: You must specify the bookmark name")
769 raise UsageError("%bookmark: You must specify the bookmark name")
770 elif len(args)==1:
770 elif len(args)==1:
771 bkms[args[0]] = os.getcwd()
771 bkms[args[0]] = os.getcwd()
772 elif len(args)==2:
772 elif len(args)==2:
773 bkms[args[0]] = args[1]
773 bkms[args[0]] = args[1]
774 self.shell.db['bookmarks'] = bkms
774 self.shell.db['bookmarks'] = bkms
775
775
776 @line_magic
776 @line_magic
777 def pycat(self, parameter_s=''):
777 def pycat(self, parameter_s=''):
778 """Show a syntax-highlighted file through a pager.
778 """Show a syntax-highlighted file through a pager.
779
779
780 This magic is similar to the cat utility, but it will assume the file
780 This magic is similar to the cat utility, but it will assume the file
781 to be Python source and will show it with syntax highlighting.
781 to be Python source and will show it with syntax highlighting.
782
782
783 This magic command can either take a local filename, an url,
783 This magic command can either take a local filename, an url,
784 an history range (see %history) or a macro as argument ::
784 an history range (see %history) or a macro as argument ::
785
785
786 %pycat myscript.py
786 %pycat myscript.py
787 %pycat 7-27
787 %pycat 7-27
788 %pycat myMacro
788 %pycat myMacro
789 %pycat http://www.example.com/myscript.py
789 %pycat http://www.example.com/myscript.py
790 """
790 """
791 if not parameter_s:
791 if not parameter_s:
792 raise UsageError('Missing filename, URL, input history range, '
792 raise UsageError('Missing filename, URL, input history range, '
793 'or macro.')
793 'or macro.')
794
794
795 try :
795 try :
796 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
796 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
797 except (ValueError, IOError):
797 except (ValueError, IOError):
798 print("Error: no such file, variable, URL, history range or macro")
798 print("Error: no such file, variable, URL, history range or macro")
799 return
799 return
800
800
801 page.page(self.shell.pycolorize(source_to_unicode(cont)))
801 page.page(self.shell.pycolorize(source_to_unicode(cont)))
802
802
803 @magic_arguments.magic_arguments()
803 @magic_arguments.magic_arguments()
804 @magic_arguments.argument(
804 @magic_arguments.argument(
805 '-a', '--append', action='store_true', default=False,
805 '-a', '--append', action='store_true', default=False,
806 help='Append contents of the cell to an existing file. '
806 help='Append contents of the cell to an existing file. '
807 'The file will be created if it does not exist.'
807 'The file will be created if it does not exist.'
808 )
808 )
809 @magic_arguments.argument(
809 @magic_arguments.argument(
810 'filename', type=str,
810 'filename', type=str,
811 help='file to write'
811 help='file to write'
812 )
812 )
813 @cell_magic
813 @cell_magic
814 def writefile(self, line, cell):
814 def writefile(self, line, cell):
815 """Write the contents of the cell to a file.
815 """Write the contents of the cell to a file.
816
816
817 The file will be overwritten unless the -a (--append) flag is specified.
817 The file will be overwritten unless the -a (--append) flag is specified.
818 """
818 """
819 args = magic_arguments.parse_argstring(self.writefile, line)
819 args = magic_arguments.parse_argstring(self.writefile, line)
820 filename = os.path.expanduser(args.filename)
820 filename = os.path.expanduser(args.filename)
821
821
822 if os.path.exists(filename):
822 if os.path.exists(filename):
823 if args.append:
823 if args.append:
824 print("Appending to %s" % filename)
824 print("Appending to %s" % filename)
825 else:
825 else:
826 print("Overwriting %s" % filename)
826 print("Overwriting %s" % filename)
827 else:
827 else:
828 print("Writing %s" % filename)
828 print("Writing %s" % filename)
829
829
830 mode = 'a' if args.append else 'w'
830 mode = 'a' if args.append else 'w'
831 with io.open(filename, mode, encoding='utf-8') as f:
831 with io.open(filename, mode, encoding='utf-8') as f:
832 f.write(cell)
832 f.write(cell)
@@ -1,311 +1,311
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for managing IPython profiles.
3 An application for managing IPython profiles.
4
4
5 To be invoked as the `ipython profile` subcommand.
5 To be invoked as the `ipython profile` subcommand.
6
6
7 Authors:
7 Authors:
8
8
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import os
24 import os
25
25
26 from traitlets.config.application import Application
26 from traitlets.config.application import Application
27 from IPython.core.application import (
27 from IPython.core.application import (
28 BaseIPythonApplication, base_flags
28 BaseIPythonApplication, base_flags
29 )
29 )
30 from IPython.core.profiledir import ProfileDir
30 from IPython.core.profiledir import ProfileDir
31 from IPython.utils.importstring import import_item
31 from IPython.utils.importstring import import_item
32 from IPython.paths import get_ipython_dir, get_ipython_package_dir
32 from IPython.paths import get_ipython_dir, get_ipython_package_dir
33 from traitlets import Unicode, Bool, Dict, observe
33 from traitlets import Unicode, Bool, Dict, observe
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Constants
36 # Constants
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 create_help = """Create an IPython profile by name
39 create_help = """Create an IPython profile by name
40
40
41 Create an ipython profile directory by its name or
41 Create an ipython profile directory by its name or
42 profile directory path. Profile directories contain
42 profile directory path. Profile directories contain
43 configuration, log and security related files and are named
43 configuration, log and security related files and are named
44 using the convention 'profile_<name>'. By default they are
44 using the convention 'profile_<name>'. By default they are
45 located in your ipython directory. Once created, you will
45 located in your ipython directory. Once created, you will
46 can edit the configuration files in the profile
46 can edit the configuration files in the profile
47 directory to configure IPython. Most users will create a
47 directory to configure IPython. Most users will create a
48 profile directory by name,
48 profile directory by name,
49 `ipython profile create myprofile`, which will put the directory
49 `ipython profile create myprofile`, which will put the directory
50 in `<ipython_dir>/profile_myprofile`.
50 in `<ipython_dir>/profile_myprofile`.
51 """
51 """
52 list_help = """List available IPython profiles
52 list_help = """List available IPython profiles
53
53
54 List all available profiles, by profile location, that can
54 List all available profiles, by profile location, that can
55 be found in the current working directly or in the ipython
55 be found in the current working directly or in the ipython
56 directory. Profile directories are named using the convention
56 directory. Profile directories are named using the convention
57 'profile_<profile>'.
57 'profile_<profile>'.
58 """
58 """
59 profile_help = """Manage IPython profiles
59 profile_help = """Manage IPython profiles
60
60
61 Profile directories contain
61 Profile directories contain
62 configuration, log and security related files and are named
62 configuration, log and security related files and are named
63 using the convention 'profile_<name>'. By default they are
63 using the convention 'profile_<name>'. By default they are
64 located in your ipython directory. You can create profiles
64 located in your ipython directory. You can create profiles
65 with `ipython profile create <name>`, or see the profiles you
65 with `ipython profile create <name>`, or see the profiles you
66 already have with `ipython profile list`
66 already have with `ipython profile list`
67
67
68 To get started configuring IPython, simply do:
68 To get started configuring IPython, simply do:
69
69
70 $> ipython profile create
70 $> ipython profile create
71
71
72 and IPython will create the default profile in <ipython_dir>/profile_default,
72 and IPython will create the default profile in <ipython_dir>/profile_default,
73 where you can edit ipython_config.py to start configuring IPython.
73 where you can edit ipython_config.py to start configuring IPython.
74
74
75 """
75 """
76
76
77 _list_examples = "ipython profile list # list all profiles"
77 _list_examples = "ipython profile list # list all profiles"
78
78
79 _create_examples = """
79 _create_examples = """
80 ipython profile create foo # create profile foo w/ default config files
80 ipython profile create foo # create profile foo w/ default config files
81 ipython profile create foo --reset # restage default config files over current
81 ipython profile create foo --reset # restage default config files over current
82 ipython profile create foo --parallel # also stage parallel config files
82 ipython profile create foo --parallel # also stage parallel config files
83 """
83 """
84
84
85 _main_examples = """
85 _main_examples = """
86 ipython profile create -h # show the help string for the create subcommand
86 ipython profile create -h # show the help string for the create subcommand
87 ipython profile list -h # show the help string for the list subcommand
87 ipython profile list -h # show the help string for the list subcommand
88
88
89 ipython locate profile foo # print the path to the directory for profile 'foo'
89 ipython locate profile foo # print the path to the directory for profile 'foo'
90 """
90 """
91
91
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93 # Profile Application Class (for `ipython profile` subcommand)
93 # Profile Application Class (for `ipython profile` subcommand)
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95
95
96
96
97 def list_profiles_in(path):
97 def list_profiles_in(path):
98 """list profiles in a given root directory"""
98 """list profiles in a given root directory"""
99 profiles = []
99 profiles = []
100
100
101 # use with notation for python 3.6 onward
101 # for python 3.6+ rewrite to: with os.scandir(path) as dirlist:
102 files = os.scandir(path)
102 files = os.scandir(path)
103 for f in files:
103 for f in files:
104 if f.is_dir() and f.name.startswith('profile_'):
104 if f.is_dir() and f.name.startswith('profile_'):
105 profiles.append(f.name.split('_', 1)[-1])
105 profiles.append(f.name.split('_', 1)[-1])
106 return profiles
106 return profiles
107
107
108
108
109 def list_bundled_profiles():
109 def list_bundled_profiles():
110 """list profiles that are bundled with IPython."""
110 """list profiles that are bundled with IPython."""
111 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
111 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
112 profiles = []
112 profiles = []
113
113
114 # use with notation for python 3.6 onward
114 # for python 3.6+ rewrite to: with os.scandir(path) as dirlist:
115 files = os.scandir(path)
115 files = os.scandir(path)
116 for profile in files:
116 for profile in files:
117 if profile.is_dir() and profile.name != "__pycache__":
117 if profile.is_dir() and profile.name != "__pycache__":
118 profiles.append(profile.name)
118 profiles.append(profile.name)
119 return profiles
119 return profiles
120
120
121
121
122 class ProfileLocate(BaseIPythonApplication):
122 class ProfileLocate(BaseIPythonApplication):
123 description = """print the path to an IPython profile dir"""
123 description = """print the path to an IPython profile dir"""
124
124
125 def parse_command_line(self, argv=None):
125 def parse_command_line(self, argv=None):
126 super(ProfileLocate, self).parse_command_line(argv)
126 super(ProfileLocate, self).parse_command_line(argv)
127 if self.extra_args:
127 if self.extra_args:
128 self.profile = self.extra_args[0]
128 self.profile = self.extra_args[0]
129
129
130 def start(self):
130 def start(self):
131 print(self.profile_dir.location)
131 print(self.profile_dir.location)
132
132
133
133
134 class ProfileList(Application):
134 class ProfileList(Application):
135 name = u'ipython-profile'
135 name = u'ipython-profile'
136 description = list_help
136 description = list_help
137 examples = _list_examples
137 examples = _list_examples
138
138
139 aliases = Dict({
139 aliases = Dict({
140 'ipython-dir' : 'ProfileList.ipython_dir',
140 'ipython-dir' : 'ProfileList.ipython_dir',
141 'log-level' : 'Application.log_level',
141 'log-level' : 'Application.log_level',
142 })
142 })
143 flags = Dict(dict(
143 flags = Dict(dict(
144 debug = ({'Application' : {'log_level' : 0}},
144 debug = ({'Application' : {'log_level' : 0}},
145 "Set Application.log_level to 0, maximizing log output."
145 "Set Application.log_level to 0, maximizing log output."
146 )
146 )
147 ))
147 ))
148
148
149 ipython_dir = Unicode(get_ipython_dir(),
149 ipython_dir = Unicode(get_ipython_dir(),
150 help="""
150 help="""
151 The name of the IPython directory. This directory is used for logging
151 The name of the IPython directory. This directory is used for logging
152 configuration (through profiles), history storage, etc. The default
152 configuration (through profiles), history storage, etc. The default
153 is usually $HOME/.ipython. This options can also be specified through
153 is usually $HOME/.ipython. This options can also be specified through
154 the environment variable IPYTHONDIR.
154 the environment variable IPYTHONDIR.
155 """
155 """
156 ).tag(config=True)
156 ).tag(config=True)
157
157
158
158
159 def _print_profiles(self, profiles):
159 def _print_profiles(self, profiles):
160 """print list of profiles, indented."""
160 """print list of profiles, indented."""
161 for profile in profiles:
161 for profile in profiles:
162 print(' %s' % profile)
162 print(' %s' % profile)
163
163
164 def list_profile_dirs(self):
164 def list_profile_dirs(self):
165 profiles = list_bundled_profiles()
165 profiles = list_bundled_profiles()
166 if profiles:
166 if profiles:
167 print()
167 print()
168 print("Available profiles in IPython:")
168 print("Available profiles in IPython:")
169 self._print_profiles(profiles)
169 self._print_profiles(profiles)
170 print()
170 print()
171 print(" The first request for a bundled profile will copy it")
171 print(" The first request for a bundled profile will copy it")
172 print(" into your IPython directory (%s)," % self.ipython_dir)
172 print(" into your IPython directory (%s)," % self.ipython_dir)
173 print(" where you can customize it.")
173 print(" where you can customize it.")
174
174
175 profiles = list_profiles_in(self.ipython_dir)
175 profiles = list_profiles_in(self.ipython_dir)
176 if profiles:
176 if profiles:
177 print()
177 print()
178 print("Available profiles in %s:" % self.ipython_dir)
178 print("Available profiles in %s:" % self.ipython_dir)
179 self._print_profiles(profiles)
179 self._print_profiles(profiles)
180
180
181 profiles = list_profiles_in(os.getcwd())
181 profiles = list_profiles_in(os.getcwd())
182 if profiles:
182 if profiles:
183 print()
183 print()
184 print("Available profiles in current directory (%s):" % os.getcwd())
184 print("Available profiles in current directory (%s):" % os.getcwd())
185 self._print_profiles(profiles)
185 self._print_profiles(profiles)
186
186
187 print()
187 print()
188 print("To use any of the above profiles, start IPython with:")
188 print("To use any of the above profiles, start IPython with:")
189 print(" ipython --profile=<name>")
189 print(" ipython --profile=<name>")
190 print()
190 print()
191
191
192 def start(self):
192 def start(self):
193 self.list_profile_dirs()
193 self.list_profile_dirs()
194
194
195
195
196 create_flags = {}
196 create_flags = {}
197 create_flags.update(base_flags)
197 create_flags.update(base_flags)
198 # don't include '--init' flag, which implies running profile create in other apps
198 # don't include '--init' flag, which implies running profile create in other apps
199 create_flags.pop('init')
199 create_flags.pop('init')
200 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
200 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
201 "reset config files in this profile to the defaults.")
201 "reset config files in this profile to the defaults.")
202 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
202 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
203 "Include the config files for parallel "
203 "Include the config files for parallel "
204 "computing apps (ipengine, ipcontroller, etc.)")
204 "computing apps (ipengine, ipcontroller, etc.)")
205
205
206
206
207 class ProfileCreate(BaseIPythonApplication):
207 class ProfileCreate(BaseIPythonApplication):
208 name = u'ipython-profile'
208 name = u'ipython-profile'
209 description = create_help
209 description = create_help
210 examples = _create_examples
210 examples = _create_examples
211 auto_create = Bool(True)
211 auto_create = Bool(True)
212 def _log_format_default(self):
212 def _log_format_default(self):
213 return "[%(name)s] %(message)s"
213 return "[%(name)s] %(message)s"
214
214
215 def _copy_config_files_default(self):
215 def _copy_config_files_default(self):
216 return True
216 return True
217
217
218 parallel = Bool(False,
218 parallel = Bool(False,
219 help="whether to include parallel computing config files"
219 help="whether to include parallel computing config files"
220 ).tag(config=True)
220 ).tag(config=True)
221
221
222 @observe('parallel')
222 @observe('parallel')
223 def _parallel_changed(self, change):
223 def _parallel_changed(self, change):
224 parallel_files = [ 'ipcontroller_config.py',
224 parallel_files = [ 'ipcontroller_config.py',
225 'ipengine_config.py',
225 'ipengine_config.py',
226 'ipcluster_config.py'
226 'ipcluster_config.py'
227 ]
227 ]
228 if change['new']:
228 if change['new']:
229 for cf in parallel_files:
229 for cf in parallel_files:
230 self.config_files.append(cf)
230 self.config_files.append(cf)
231 else:
231 else:
232 for cf in parallel_files:
232 for cf in parallel_files:
233 if cf in self.config_files:
233 if cf in self.config_files:
234 self.config_files.remove(cf)
234 self.config_files.remove(cf)
235
235
236 def parse_command_line(self, argv):
236 def parse_command_line(self, argv):
237 super(ProfileCreate, self).parse_command_line(argv)
237 super(ProfileCreate, self).parse_command_line(argv)
238 # accept positional arg as profile name
238 # accept positional arg as profile name
239 if self.extra_args:
239 if self.extra_args:
240 self.profile = self.extra_args[0]
240 self.profile = self.extra_args[0]
241
241
242 flags = Dict(create_flags)
242 flags = Dict(create_flags)
243
243
244 classes = [ProfileDir]
244 classes = [ProfileDir]
245
245
246 def _import_app(self, app_path):
246 def _import_app(self, app_path):
247 """import an app class"""
247 """import an app class"""
248 app = None
248 app = None
249 name = app_path.rsplit('.', 1)[-1]
249 name = app_path.rsplit('.', 1)[-1]
250 try:
250 try:
251 app = import_item(app_path)
251 app = import_item(app_path)
252 except ImportError:
252 except ImportError:
253 self.log.info("Couldn't import %s, config file will be excluded", name)
253 self.log.info("Couldn't import %s, config file will be excluded", name)
254 except Exception:
254 except Exception:
255 self.log.warning('Unexpected error importing %s', name, exc_info=True)
255 self.log.warning('Unexpected error importing %s', name, exc_info=True)
256 return app
256 return app
257
257
258 def init_config_files(self):
258 def init_config_files(self):
259 super(ProfileCreate, self).init_config_files()
259 super(ProfileCreate, self).init_config_files()
260 # use local imports, since these classes may import from here
260 # use local imports, since these classes may import from here
261 from IPython.terminal.ipapp import TerminalIPythonApp
261 from IPython.terminal.ipapp import TerminalIPythonApp
262 apps = [TerminalIPythonApp]
262 apps = [TerminalIPythonApp]
263 for app_path in (
263 for app_path in (
264 'ipykernel.kernelapp.IPKernelApp',
264 'ipykernel.kernelapp.IPKernelApp',
265 ):
265 ):
266 app = self._import_app(app_path)
266 app = self._import_app(app_path)
267 if app is not None:
267 if app is not None:
268 apps.append(app)
268 apps.append(app)
269 if self.parallel:
269 if self.parallel:
270 from ipyparallel.apps.ipcontrollerapp import IPControllerApp
270 from ipyparallel.apps.ipcontrollerapp import IPControllerApp
271 from ipyparallel.apps.ipengineapp import IPEngineApp
271 from ipyparallel.apps.ipengineapp import IPEngineApp
272 from ipyparallel.apps.ipclusterapp import IPClusterStart
272 from ipyparallel.apps.ipclusterapp import IPClusterStart
273 apps.extend([
273 apps.extend([
274 IPControllerApp,
274 IPControllerApp,
275 IPEngineApp,
275 IPEngineApp,
276 IPClusterStart,
276 IPClusterStart,
277 ])
277 ])
278 for App in apps:
278 for App in apps:
279 app = App()
279 app = App()
280 app.config.update(self.config)
280 app.config.update(self.config)
281 app.log = self.log
281 app.log = self.log
282 app.overwrite = self.overwrite
282 app.overwrite = self.overwrite
283 app.copy_config_files=True
283 app.copy_config_files=True
284 app.ipython_dir=self.ipython_dir
284 app.ipython_dir=self.ipython_dir
285 app.profile_dir=self.profile_dir
285 app.profile_dir=self.profile_dir
286 app.init_config_files()
286 app.init_config_files()
287
287
288 def stage_default_config_file(self):
288 def stage_default_config_file(self):
289 pass
289 pass
290
290
291
291
292 class ProfileApp(Application):
292 class ProfileApp(Application):
293 name = u'ipython profile'
293 name = u'ipython profile'
294 description = profile_help
294 description = profile_help
295 examples = _main_examples
295 examples = _main_examples
296
296
297 subcommands = Dict(dict(
297 subcommands = Dict(dict(
298 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
298 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
299 list = (ProfileList, ProfileList.description.splitlines()[0]),
299 list = (ProfileList, ProfileList.description.splitlines()[0]),
300 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
300 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
301 ))
301 ))
302
302
303 def start(self):
303 def start(self):
304 if self.subapp is None:
304 if self.subapp is None:
305 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
305 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
306 print()
306 print()
307 self.print_description()
307 self.print_description()
308 self.print_subcommands()
308 self.print_subcommands()
309 self.exit(1)
309 self.exit(1)
310 else:
310 else:
311 return self.subapp.start()
311 return self.subapp.start()
General Comments 0
You need to be logged in to leave comments. Login now