##// END OF EJS Templates
Merge branch 'kd2718/os_scandir_prep' of github.com:kd2718/ipython into kd2718/os_scandir_prep
kd2718 -
r24686:0e555a81 merge
parent child Browse files
Show More
@@ -1,832 +1,831
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().__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 for pdir in path:
215 for pdir in path:
216 try:
216 try:
217 os.chdir(pdir)
217 os.chdir(pdir)
218 except OSError:
218 except OSError:
219 continue
219 continue
220
220
221 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
221 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
222 dirlist = os.scandir(path=pdir)
222 dirlist = os.scandir(path=pdir)
223 for ff in dirlist:
223 for ff in dirlist:
224 if self.isexec(ff):
224 if self.isexec(ff):
225 fname = ff.name
225 fname = ff.name
226 try:
226 try:
227 # Removes dots from the name since ipython
227 # Removes dots from the name since ipython
228 # will assume names with dots to be python.
228 # will assume names with dots to be python.
229 if not self.shell.alias_manager.is_alias(fname):
229 if not self.shell.alias_manager.is_alias(fname):
230 self.shell.alias_manager.define_alias(
230 self.shell.alias_manager.define_alias(
231 fname.replace('.',''), fname)
231 fname.replace('.',''), fname)
232 except InvalidAliasError:
232 except InvalidAliasError:
233 pass
233 pass
234 else:
234 else:
235 syscmdlist.append(fname)
235 syscmdlist.append(fname)
236 else:
236 else:
237 no_alias = Alias.blacklist
237 no_alias = Alias.blacklist
238 for pdir in path:
238 for pdir in path:
239 try:
239 try:
240 os.chdir(pdir)
240 os.chdir(pdir)
241 except OSError:
241 except OSError:
242 continue
242 continue
243
243
244 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
244 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
245 dirlist = os.scandir(pdir)
245 dirlist = os.scandir(pdir)
246 for ff in dirlist:
246 for ff in dirlist:
247 fname = ff.name
247 fname = ff.name
248 base, ext = os.path.splitext(fname)
248 base, ext = os.path.splitext(fname)
249 if self.isexec(ff) and base.lower() not in no_alias:
249 if self.isexec(ff) and base.lower() not in no_alias:
250 if ext.lower() == '.exe':
250 if ext.lower() == '.exe':
251 fname = base
251 fname = base
252 try:
252 try:
253 # Removes dots from the name since ipython
253 # Removes dots from the name since ipython
254 # will assume names with dots to be python.
254 # will assume names with dots to be python.
255 self.shell.alias_manager.define_alias(
255 self.shell.alias_manager.define_alias(
256 base.lower().replace('.',''), fname)
256 base.lower().replace('.',''), fname)
257 except InvalidAliasError:
257 except InvalidAliasError:
258 pass
258 pass
259 syscmdlist.append(fname)
259 syscmdlist.append(fname)
260
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 = []
524 try:
523 try:
525 args = map(int,parameter_s.split())
524 args = map(int,parameter_s.split())
526 except:
525 except:
527 self.arg_err(self.dhist)
526 self.arg_err(self.dhist)
528 return
527 return
529 if len(args) == 1:
528 if len(args) == 1:
530 ini,fin = max(len(dh)-(args[0]),0),len(dh)
529 ini,fin = max(len(dh)-(args[0]),0),len(dh)
531 elif len(args) == 2:
530 elif len(args) == 2:
532 ini,fin = args
531 ini,fin = args
533 fin = min(fin, len(dh))
532 fin = min(fin, len(dh))
534 else:
533 else:
535 self.arg_err(self.dhist)
534 self.arg_err(self.dhist)
536 return
535 return
537 else:
536 else:
538 ini,fin = 0,len(dh)
537 ini,fin = 0,len(dh)
539 print('Directory history (kept in _dh)')
538 print('Directory history (kept in _dh)')
540 for i in range(ini, fin):
539 for i in range(ini, fin):
541 print("%d: %s" % (i, dh[i]))
540 print("%d: %s" % (i, dh[i]))
542
541
543 @skip_doctest
542 @skip_doctest
544 @line_magic
543 @line_magic
545 def sc(self, parameter_s=''):
544 def sc(self, parameter_s=''):
546 """Shell capture - run shell command and capture output (DEPRECATED use !).
545 """Shell capture - run shell command and capture output (DEPRECATED use !).
547
546
548 DEPRECATED. Suboptimal, retained for backwards compatibility.
547 DEPRECATED. Suboptimal, retained for backwards compatibility.
549
548
550 You should use the form 'var = !command' instead. Example:
549 You should use the form 'var = !command' instead. Example:
551
550
552 "%sc -l myfiles = ls ~" should now be written as
551 "%sc -l myfiles = ls ~" should now be written as
553
552
554 "myfiles = !ls ~"
553 "myfiles = !ls ~"
555
554
556 myfiles.s, myfiles.l and myfiles.n still apply as documented
555 myfiles.s, myfiles.l and myfiles.n still apply as documented
557 below.
556 below.
558
557
559 --
558 --
560 %sc [options] varname=command
559 %sc [options] varname=command
561
560
562 IPython will run the given command using commands.getoutput(), and
561 IPython will run the given command using commands.getoutput(), and
563 will then update the user's interactive namespace with a variable
562 will then update the user's interactive namespace with a variable
564 called varname, containing the value of the call. Your command can
563 called varname, containing the value of the call. Your command can
565 contain shell wildcards, pipes, etc.
564 contain shell wildcards, pipes, etc.
566
565
567 The '=' sign in the syntax is mandatory, and the variable name you
566 The '=' sign in the syntax is mandatory, and the variable name you
568 supply must follow Python's standard conventions for valid names.
567 supply must follow Python's standard conventions for valid names.
569
568
570 (A special format without variable name exists for internal use)
569 (A special format without variable name exists for internal use)
571
570
572 Options:
571 Options:
573
572
574 -l: list output. Split the output on newlines into a list before
573 -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
574 assigning it to the given variable. By default the output is stored
576 as a single string.
575 as a single string.
577
576
578 -v: verbose. Print the contents of the variable.
577 -v: verbose. Print the contents of the variable.
579
578
580 In most cases you should not need to split as a list, because the
579 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
580 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
581 provide its contents either as a list (split on newlines) or as a
583 space-separated string. These are convenient, respectively, either
582 space-separated string. These are convenient, respectively, either
584 for sequential processing or to be passed to a shell command.
583 for sequential processing or to be passed to a shell command.
585
584
586 For example::
585 For example::
587
586
588 # Capture into variable a
587 # Capture into variable a
589 In [1]: sc a=ls *py
588 In [1]: sc a=ls *py
590
589
591 # a is a string with embedded newlines
590 # a is a string with embedded newlines
592 In [2]: a
591 In [2]: a
593 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
592 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
594
593
595 # which can be seen as a list:
594 # which can be seen as a list:
596 In [3]: a.l
595 In [3]: a.l
597 Out[3]: ['setup.py', 'win32_manual_post_install.py']
596 Out[3]: ['setup.py', 'win32_manual_post_install.py']
598
597
599 # or as a whitespace-separated string:
598 # or as a whitespace-separated string:
600 In [4]: a.s
599 In [4]: a.s
601 Out[4]: 'setup.py win32_manual_post_install.py'
600 Out[4]: 'setup.py win32_manual_post_install.py'
602
601
603 # a.s is useful to pass as a single command line:
602 # a.s is useful to pass as a single command line:
604 In [5]: !wc -l $a.s
603 In [5]: !wc -l $a.s
605 146 setup.py
604 146 setup.py
606 130 win32_manual_post_install.py
605 130 win32_manual_post_install.py
607 276 total
606 276 total
608
607
609 # while the list form is useful to loop over:
608 # while the list form is useful to loop over:
610 In [6]: for f in a.l:
609 In [6]: for f in a.l:
611 ...: !wc -l $f
610 ...: !wc -l $f
612 ...:
611 ...:
613 146 setup.py
612 146 setup.py
614 130 win32_manual_post_install.py
613 130 win32_manual_post_install.py
615
614
616 Similarly, the lists returned by the -l option are also special, in
615 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
616 the sense that you can equally invoke the .s attribute on them to
618 automatically get a whitespace-separated string from their contents::
617 automatically get a whitespace-separated string from their contents::
619
618
620 In [7]: sc -l b=ls *py
619 In [7]: sc -l b=ls *py
621
620
622 In [8]: b
621 In [8]: b
623 Out[8]: ['setup.py', 'win32_manual_post_install.py']
622 Out[8]: ['setup.py', 'win32_manual_post_install.py']
624
623
625 In [9]: b.s
624 In [9]: b.s
626 Out[9]: 'setup.py win32_manual_post_install.py'
625 Out[9]: 'setup.py win32_manual_post_install.py'
627
626
628 In summary, both the lists and strings used for output capture have
627 In summary, both the lists and strings used for output capture have
629 the following special attributes::
628 the following special attributes::
630
629
631 .l (or .list) : value as list.
630 .l (or .list) : value as list.
632 .n (or .nlstr): value as newline-separated string.
631 .n (or .nlstr): value as newline-separated string.
633 .s (or .spstr): value as space-separated string.
632 .s (or .spstr): value as space-separated string.
634 """
633 """
635
634
636 opts,args = self.parse_options(parameter_s, 'lv')
635 opts,args = self.parse_options(parameter_s, 'lv')
637 # Try to get a variable name and command to run
636 # Try to get a variable name and command to run
638 try:
637 try:
639 # the variable name must be obtained from the parse_options
638 # the variable name must be obtained from the parse_options
640 # output, which uses shlex.split to strip options out.
639 # output, which uses shlex.split to strip options out.
641 var,_ = args.split('=', 1)
640 var,_ = args.split('=', 1)
642 var = var.strip()
641 var = var.strip()
643 # But the command has to be extracted from the original input
642 # But the command has to be extracted from the original input
644 # parameter_s, not on what parse_options returns, to avoid the
643 # parameter_s, not on what parse_options returns, to avoid the
645 # quote stripping which shlex.split performs on it.
644 # quote stripping which shlex.split performs on it.
646 _,cmd = parameter_s.split('=', 1)
645 _,cmd = parameter_s.split('=', 1)
647 except ValueError:
646 except ValueError:
648 var,cmd = '',''
647 var,cmd = '',''
649 # If all looks ok, proceed
648 # If all looks ok, proceed
650 split = 'l' in opts
649 split = 'l' in opts
651 out = self.shell.getoutput(cmd, split=split)
650 out = self.shell.getoutput(cmd, split=split)
652 if 'v' in opts:
651 if 'v' in opts:
653 print('%s ==\n%s' % (var, pformat(out)))
652 print('%s ==\n%s' % (var, pformat(out)))
654 if var:
653 if var:
655 self.shell.user_ns.update({var:out})
654 self.shell.user_ns.update({var:out})
656 else:
655 else:
657 return out
656 return out
658
657
659 @line_cell_magic
658 @line_cell_magic
660 def sx(self, line='', cell=None):
659 def sx(self, line='', cell=None):
661 """Shell execute - run shell command and capture output (!! is short-hand).
660 """Shell execute - run shell command and capture output (!! is short-hand).
662
661
663 %sx command
662 %sx command
664
663
665 IPython will run the given command using commands.getoutput(), and
664 IPython will run the given command using commands.getoutput(), and
666 return the result formatted as a list (split on '\\n'). Since the
665 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
666 output is _returned_, it will be stored in ipython's regular output
668 cache Out[N] and in the '_N' automatic variables.
667 cache Out[N] and in the '_N' automatic variables.
669
668
670 Notes:
669 Notes:
671
670
672 1) If an input line begins with '!!', then %sx is automatically
671 1) If an input line begins with '!!', then %sx is automatically
673 invoked. That is, while::
672 invoked. That is, while::
674
673
675 !ls
674 !ls
676
675
677 causes ipython to simply issue system('ls'), typing::
676 causes ipython to simply issue system('ls'), typing::
678
677
679 !!ls
678 !!ls
680
679
681 is a shorthand equivalent to::
680 is a shorthand equivalent to::
682
681
683 %sx ls
682 %sx ls
684
683
685 2) %sx differs from %sc in that %sx automatically splits into a list,
684 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
685 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.
686 to process line-oriented shell output via further python commands.
688 %sc is meant to provide much finer control, but requires more
687 %sc is meant to provide much finer control, but requires more
689 typing.
688 typing.
690
689
691 3) Just like %sc -l, this is a list with special attributes:
690 3) Just like %sc -l, this is a list with special attributes:
692 ::
691 ::
693
692
694 .l (or .list) : value as list.
693 .l (or .list) : value as list.
695 .n (or .nlstr): value as newline-separated string.
694 .n (or .nlstr): value as newline-separated string.
696 .s (or .spstr): value as whitespace-separated string.
695 .s (or .spstr): value as whitespace-separated string.
697
696
698 This is very useful when trying to use such lists as arguments to
697 This is very useful when trying to use such lists as arguments to
699 system commands."""
698 system commands."""
700
699
701 if cell is None:
700 if cell is None:
702 # line magic
701 # line magic
703 return self.shell.getoutput(line)
702 return self.shell.getoutput(line)
704 else:
703 else:
705 opts,args = self.parse_options(line, '', 'out=')
704 opts,args = self.parse_options(line, '', 'out=')
706 output = self.shell.getoutput(cell)
705 output = self.shell.getoutput(cell)
707 out_name = opts.get('out', opts.get('o'))
706 out_name = opts.get('out', opts.get('o'))
708 if out_name:
707 if out_name:
709 self.shell.user_ns[out_name] = output
708 self.shell.user_ns[out_name] = output
710 else:
709 else:
711 return output
710 return output
712
711
713 system = line_cell_magic('system')(sx)
712 system = line_cell_magic('system')(sx)
714 bang = cell_magic('!')(sx)
713 bang = cell_magic('!')(sx)
715
714
716 @line_magic
715 @line_magic
717 def bookmark(self, parameter_s=''):
716 def bookmark(self, parameter_s=''):
718 """Manage IPython's bookmark system.
717 """Manage IPython's bookmark system.
719
718
720 %bookmark <name> - set bookmark to current dir
719 %bookmark <name> - set bookmark to current dir
721 %bookmark <name> <dir> - set bookmark to <dir>
720 %bookmark <name> <dir> - set bookmark to <dir>
722 %bookmark -l - list all bookmarks
721 %bookmark -l - list all bookmarks
723 %bookmark -d <name> - remove bookmark
722 %bookmark -d <name> - remove bookmark
724 %bookmark -r - remove all bookmarks
723 %bookmark -r - remove all bookmarks
725
724
726 You can later on access a bookmarked folder with::
725 You can later on access a bookmarked folder with::
727
726
728 %cd -b <name>
727 %cd -b <name>
729
728
730 or simply '%cd <name>' if there is no directory called <name> AND
729 or simply '%cd <name>' if there is no directory called <name> AND
731 there is such a bookmark defined.
730 there is such a bookmark defined.
732
731
733 Your bookmarks persist through IPython sessions, but they are
732 Your bookmarks persist through IPython sessions, but they are
734 associated with each profile."""
733 associated with each profile."""
735
734
736 opts,args = self.parse_options(parameter_s,'drl',mode='list')
735 opts,args = self.parse_options(parameter_s,'drl',mode='list')
737 if len(args) > 2:
736 if len(args) > 2:
738 raise UsageError("%bookmark: too many arguments")
737 raise UsageError("%bookmark: too many arguments")
739
738
740 bkms = self.shell.db.get('bookmarks',{})
739 bkms = self.shell.db.get('bookmarks',{})
741
740
742 if 'd' in opts:
741 if 'd' in opts:
743 try:
742 try:
744 todel = args[0]
743 todel = args[0]
745 except IndexError:
744 except IndexError:
746 raise UsageError(
745 raise UsageError(
747 "%bookmark -d: must provide a bookmark to delete")
746 "%bookmark -d: must provide a bookmark to delete")
748 else:
747 else:
749 try:
748 try:
750 del bkms[todel]
749 del bkms[todel]
751 except KeyError:
750 except KeyError:
752 raise UsageError(
751 raise UsageError(
753 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
752 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
754
753
755 elif 'r' in opts:
754 elif 'r' in opts:
756 bkms = {}
755 bkms = {}
757 elif 'l' in opts:
756 elif 'l' in opts:
758 bks = sorted(bkms)
757 bks = sorted(bkms)
759 if bks:
758 if bks:
760 size = max(map(len, bks))
759 size = max(map(len, bks))
761 else:
760 else:
762 size = 0
761 size = 0
763 fmt = '%-'+str(size)+'s -> %s'
762 fmt = '%-'+str(size)+'s -> %s'
764 print('Current bookmarks:')
763 print('Current bookmarks:')
765 for bk in bks:
764 for bk in bks:
766 print(fmt % (bk, bkms[bk]))
765 print(fmt % (bk, bkms[bk]))
767 else:
766 else:
768 if not args:
767 if not args:
769 raise UsageError("%bookmark: You must specify the bookmark name")
768 raise UsageError("%bookmark: You must specify the bookmark name")
770 elif len(args)==1:
769 elif len(args)==1:
771 bkms[args[0]] = os.getcwd()
770 bkms[args[0]] = os.getcwd()
772 elif len(args)==2:
771 elif len(args)==2:
773 bkms[args[0]] = args[1]
772 bkms[args[0]] = args[1]
774 self.shell.db['bookmarks'] = bkms
773 self.shell.db['bookmarks'] = bkms
775
774
776 @line_magic
775 @line_magic
777 def pycat(self, parameter_s=''):
776 def pycat(self, parameter_s=''):
778 """Show a syntax-highlighted file through a pager.
777 """Show a syntax-highlighted file through a pager.
779
778
780 This magic is similar to the cat utility, but it will assume the file
779 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.
780 to be Python source and will show it with syntax highlighting.
782
781
783 This magic command can either take a local filename, an url,
782 This magic command can either take a local filename, an url,
784 an history range (see %history) or a macro as argument ::
783 an history range (see %history) or a macro as argument ::
785
784
786 %pycat myscript.py
785 %pycat myscript.py
787 %pycat 7-27
786 %pycat 7-27
788 %pycat myMacro
787 %pycat myMacro
789 %pycat http://www.example.com/myscript.py
788 %pycat http://www.example.com/myscript.py
790 """
789 """
791 if not parameter_s:
790 if not parameter_s:
792 raise UsageError('Missing filename, URL, input history range, '
791 raise UsageError('Missing filename, URL, input history range, '
793 'or macro.')
792 'or macro.')
794
793
795 try :
794 try :
796 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
795 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
797 except (ValueError, IOError):
796 except (ValueError, IOError):
798 print("Error: no such file, variable, URL, history range or macro")
797 print("Error: no such file, variable, URL, history range or macro")
799 return
798 return
800
799
801 page.page(self.shell.pycolorize(source_to_unicode(cont)))
800 page.page(self.shell.pycolorize(source_to_unicode(cont)))
802
801
803 @magic_arguments.magic_arguments()
802 @magic_arguments.magic_arguments()
804 @magic_arguments.argument(
803 @magic_arguments.argument(
805 '-a', '--append', action='store_true', default=False,
804 '-a', '--append', action='store_true', default=False,
806 help='Append contents of the cell to an existing file. '
805 help='Append contents of the cell to an existing file. '
807 'The file will be created if it does not exist.'
806 'The file will be created if it does not exist.'
808 )
807 )
809 @magic_arguments.argument(
808 @magic_arguments.argument(
810 'filename', type=str,
809 'filename', type=str,
811 help='file to write'
810 help='file to write'
812 )
811 )
813 @cell_magic
812 @cell_magic
814 def writefile(self, line, cell):
813 def writefile(self, line, cell):
815 """Write the contents of the cell to a file.
814 """Write the contents of the cell to a file.
816
815
817 The file will be overwritten unless the -a (--append) flag is specified.
816 The file will be overwritten unless the -a (--append) flag is specified.
818 """
817 """
819 args = magic_arguments.parse_argstring(self.writefile, line)
818 args = magic_arguments.parse_argstring(self.writefile, line)
820 filename = os.path.expanduser(args.filename)
819 filename = os.path.expanduser(args.filename)
821
820
822 if os.path.exists(filename):
821 if os.path.exists(filename):
823 if args.append:
822 if args.append:
824 print("Appending to %s" % filename)
823 print("Appending to %s" % filename)
825 else:
824 else:
826 print("Overwriting %s" % filename)
825 print("Overwriting %s" % filename)
827 else:
826 else:
828 print("Writing %s" % filename)
827 print("Writing %s" % filename)
829
828
830 mode = 'a' if args.append else 'w'
829 mode = 'a' if args.append else 'w'
831 with io.open(filename, mode, encoding='utf-8') as f:
830 with io.open(filename, mode, encoding='utf-8') as f:
832 f.write(cell)
831 f.write(cell)
General Comments 0
You need to be logged in to leave comments. Login now