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