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