##// END OF EJS Templates
Changes to Alias API after discussion with Fernando
Thomas Kluyver -
Show More
@@ -1,237 +1,237 b''
1 1 # encoding: utf-8
2 2 """
3 3 System command aliases.
4 4
5 5 Authors:
6 6
7 7 * Fernando Perez
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License.
15 15 #
16 16 # The full license is in the file COPYING.txt, distributed with this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 import __builtin__
24 import keyword
25 23 import os
26 24 import re
27 25 import sys
28 26
29 27 from IPython.config.configurable import Configurable
30 28 from IPython.core.error import UsageError
31 from IPython.core.splitinput import split_user_input
32 29
33 30 from IPython.utils.traitlets import List, Instance
34 from IPython.utils.warn import warn, error
31 from IPython.utils.warn import error
35 32
36 33 #-----------------------------------------------------------------------------
37 34 # Utilities
38 35 #-----------------------------------------------------------------------------
39 36
40 37 # This is used as the pattern for calls to split_user_input.
41 38 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42 39
43 40 def default_aliases():
44 41 """Return list of shell aliases to auto-define.
45 42 """
46 43 # Note: the aliases defined here should be safe to use on a kernel
47 44 # regardless of what frontend it is attached to. Frontends that use a
48 45 # kernel in-process can define additional aliases that will only work in
49 46 # their case. For example, things like 'less' or 'clear' that manipulate
50 47 # the terminal should NOT be declared here, as they will only work if the
51 48 # kernel is running inside a true terminal, and not over the network.
52 49
53 50 if os.name == 'posix':
54 51 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 52 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
56 53 ('cat', 'cat'),
57 54 ]
58 55 # Useful set of ls aliases. The GNU and BSD options are a little
59 56 # different, so we make aliases that provide as similar as possible
60 57 # behavior in ipython, by passing the right flags for each platform
61 58 if sys.platform.startswith('linux'):
62 59 ls_aliases = [('ls', 'ls -F --color'),
63 60 # long ls
64 61 ('ll', 'ls -F -o --color'),
65 62 # ls normal files only
66 63 ('lf', 'ls -F -o --color %l | grep ^-'),
67 64 # ls symbolic links
68 65 ('lk', 'ls -F -o --color %l | grep ^l'),
69 66 # directories or links to directories,
70 67 ('ldir', 'ls -F -o --color %l | grep /$'),
71 68 # things which are executable
72 69 ('lx', 'ls -F -o --color %l | grep ^-..x'),
73 70 ]
74 71 else:
75 72 # BSD, OSX, etc.
76 73 ls_aliases = [('ls', 'ls -F -G'),
77 74 # long ls
78 75 ('ll', 'ls -F -l -G'),
79 76 # ls normal files only
80 77 ('lf', 'ls -F -l -G %l | grep ^-'),
81 78 # ls symbolic links
82 79 ('lk', 'ls -F -l -G %l | grep ^l'),
83 80 # directories or links to directories,
84 81 ('ldir', 'ls -F -G -l %l | grep /$'),
85 82 # things which are executable
86 83 ('lx', 'ls -F -l -G %l | grep ^-..x'),
87 84 ]
88 85 default_aliases = default_aliases + ls_aliases
89 86 elif os.name in ['nt', 'dos']:
90 87 default_aliases = [('ls', 'dir /on'),
91 88 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
92 89 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
93 90 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
94 91 ]
95 92 else:
96 93 default_aliases = []
97 94
98 95 return default_aliases
99 96
100 97
101 98 class AliasError(Exception):
102 99 pass
103 100
104 101
105 102 class InvalidAliasError(AliasError):
106 103 pass
107 104
108 class AliasCaller(object):
105 class Alias(object):
106 """Callable object storing the details of one alias.
107
108 Instances are registered as magic functions to allow use of aliases.
109 """
110
111 # Prepare blacklist
112 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
113
109 114 def __init__(self, shell, name, cmd):
110 115 self.shell = shell
111 116 self.name = name
112 117 self.cmd = cmd
113 self.nargs = cmd.count('%s')
114 if (self.nargs > 0) and (cmd.find('%l') >= 0):
118 self.nargs = self.validate()
119
120 def validate(self):
121 """Validate the alias, and return the number of arguments."""
122 if self.name in self.blacklist:
123 raise InvalidAliasError("The name %s can't be aliased "
124 "because it is a keyword or builtin." % self.name)
125 try:
126 caller = self.shell.magics_manager.magics['line'][self.name]
127 except KeyError:
128 pass
129 else:
130 if not isinstance(caller, Alias):
131 raise InvalidAliasError("The name %s can't be aliased "
132 "because it is another magic command." % self.name)
133
134 if not (isinstance(self.cmd, basestring)):
135 raise InvalidAliasError("An alias command must be a string, "
136 "got: %r" % self.cmd)
137
138 nargs = self.cmd.count('%s')
139
140 if (nargs > 0) and (self.cmd.find('%l') >= 0):
115 141 raise InvalidAliasError('The %s and %l specifiers are mutually '
116 142 'exclusive in alias definitions.')
117 143
144 return nargs
145
118 146 def __repr__(self):
119 147 return "<alias {} for {!r}>".format(self.name, self.cmd)
120 148
121 149 def __call__(self, rest=''):
122 150 cmd = self.cmd
123 151 nargs = self.nargs
124 152 # Expand the %l special to be the user's input line
125 153 if cmd.find('%l') >= 0:
126 154 cmd = cmd.replace('%l', rest)
127 155 rest = ''
128 156 if nargs==0:
129 157 # Simple, argument-less aliases
130 158 cmd = '%s %s' % (cmd, rest)
131 159 else:
132 160 # Handle aliases with positional arguments
133 161 args = rest.split(None, nargs)
134 162 if len(args) < nargs:
135 163 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
136 164 (self.name, nargs, len(args)))
137 165 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
138 166
139 167 self.shell.system(cmd)
140 168
141 169 #-----------------------------------------------------------------------------
142 170 # Main AliasManager class
143 171 #-----------------------------------------------------------------------------
144 172
145 173 class AliasManager(Configurable):
146 174
147 175 default_aliases = List(default_aliases(), config=True)
148 176 user_aliases = List(default_value=[], config=True)
149 177 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
150 178
151 179 def __init__(self, shell=None, **kwargs):
152 180 super(AliasManager, self).__init__(shell=shell, **kwargs)
153 self.init_exclusions()
181 # For convenient access
182 self.linemagics = self.shell.magics_manager.magics['line']
154 183 self.init_aliases()
155 184
156 @property
157 def aliases(self):
158 linemagics = self.shell.magics_manager.magics['line']
159 return [(n, func.cmd) for (n, func) in linemagics.items()
160 if isinstance(func, AliasCaller)]
161
162 def init_exclusions(self):
163 # set of things NOT to alias (keywords, builtins and some magics)
164 no_alias = {'cd','popd','pushd','dhist','alias','unalias'}
165 no_alias.update(set(keyword.kwlist))
166 no_alias.update(set(__builtin__.__dict__.keys()))
167 self.no_alias = no_alias
168
169 185 def init_aliases(self):
170 # Load default aliases
171 for name, cmd in self.default_aliases:
172 self.soft_define_alias(name, cmd)
173
174 # Load user aliases
175 for name, cmd in self.user_aliases:
186 # Load default & user aliases
187 for name, cmd in self.default_aliases + self.user_aliases:
176 188 self.soft_define_alias(name, cmd)
177 189
178 def clear_aliases(self):
179 for name, cmd in self.aliases:
180 self.undefine_alias(name)
190 @property
191 def aliases(self):
192 return [(n, func.cmd) for (n, func) in self.linemagics.items()
193 if isinstance(func, Alias)]
181 194
182 195 def soft_define_alias(self, name, cmd):
183 196 """Define an alias, but don't raise on an AliasError."""
184 197 try:
185 198 self.define_alias(name, cmd)
186 199 except AliasError as e:
187 200 error("Invalid alias: %s" % e)
188 201
189 202 def define_alias(self, name, cmd):
190 203 """Define a new alias after validating it.
191 204
192 205 This will raise an :exc:`AliasError` if there are validation
193 206 problems.
194 207 """
195 self.validate_alias(name, cmd)
196 caller = AliasCaller(shell=self.shell, name=name, cmd=cmd)
208 caller = Alias(shell=self.shell, name=name, cmd=cmd)
197 209 self.shell.magics_manager.register_function(caller, magic_kind='line',
198 210 magic_name=name)
199 211
212 def get_alias(self, name):
213 """Return an alias, or None if no alias by that name exists."""
214 aname = self.linemagics.get(name, None)
215 return aname if isinstance(aname, Alias) else None
216
217 def is_alias(self, name):
218 """Return whether or not a given name has been defined as an alias"""
219 return self.get_alias(name) is not None
220
200 221 def undefine_alias(self, name):
201 linemagics = self.shell.magics_manager.magics['line']
202 caller = linemagics.get(name, None)
203 if isinstance(caller, AliasCaller):
204 del linemagics[name]
222 if self.is_alias(name):
223 del self.linemagics[name]
205 224 else:
206 225 raise ValueError('%s is not an alias' % name)
207 226
208 def validate_alias(self, name, cmd):
209 """Validate an alias and return the its number of arguments."""
210 if name in self.no_alias:
211 raise InvalidAliasError("The name %s can't be aliased "
212 "because it is a keyword or builtin." % name)
213 try:
214 caller = self.shell.magics_manager.magics['line'][name]
215 except KeyError:
216 pass
217 else:
218 if not isinstance(caller, AliasCaller):
219 raise InvalidAliasError("The name %s can't be aliased "
220 "because it is another magic command." % name)
221 if not (isinstance(cmd, basestring)):
222 raise InvalidAliasError("An alias command must be a string, "
223 "got: %r" % cmd)
224 return True
227 def clear_aliases(self):
228 for name, cmd in self.aliases:
229 self.undefine_alias(name)
225 230
226 231 def retrieve_alias(self, name):
227 232 """Retrieve the command to which an alias expands."""
228 caller = self.shell.magics_manager.magics['line'].get(name, None)
229 if isinstance(caller, AliasCaller):
233 caller = self.get_alias(name)
234 if caller:
230 235 return caller.cmd
231 236 else:
232 237 raise ValueError('%s is not an alias' % name)
233
234 def is_alias(self, name):
235 """Return whether or not a given name has been defined as an alias"""
236 caller = self.shell.magics_manager.magics['line'].get(name, None)
237 return isinstance(caller, AliasCaller)
@@ -1,738 +1,738 b''
1 1 """Implementation of magic functions for interaction with the OS.
2 2
3 3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 4 builtin.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012 The IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Stdlib
19 19 import io
20 20 import os
21 21 import re
22 22 import sys
23 23 from pprint import pformat
24 24
25 25 # Our own packages
26 26 from IPython.core import magic_arguments
27 27 from IPython.core import oinspect
28 28 from IPython.core import page
29 from IPython.core.alias import AliasError
29 from IPython.core.alias import AliasError, Alias
30 30 from IPython.core.error import UsageError
31 31 from IPython.core.magic import (
32 32 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
33 33 )
34 34 from IPython.testing.skipdoctest import skip_doctest
35 35 from IPython.utils.openpy import source_to_unicode
36 36 from IPython.utils.path import unquote_filename
37 37 from IPython.utils.process import abbrev_cwd
38 38 from IPython.utils.terminal import set_term_title
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Magic implementation classes
42 42 #-----------------------------------------------------------------------------
43 43 @magics_class
44 44 class OSMagics(Magics):
45 45 """Magics to interact with the underlying OS (shell-type functionality).
46 46 """
47 47
48 48 @skip_doctest
49 49 @line_magic
50 50 def alias(self, parameter_s=''):
51 51 """Define an alias for a system command.
52 52
53 53 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
54 54
55 55 Then, typing 'alias_name params' will execute the system command 'cmd
56 56 params' (from your underlying operating system).
57 57
58 58 Aliases have lower precedence than magic functions and Python normal
59 59 variables, so if 'foo' is both a Python variable and an alias, the
60 60 alias can not be executed until 'del foo' removes the Python variable.
61 61
62 62 You can use the %l specifier in an alias definition to represent the
63 63 whole line when the alias is called. For example::
64 64
65 65 In [2]: alias bracket echo "Input in brackets: <%l>"
66 66 In [3]: bracket hello world
67 67 Input in brackets: <hello world>
68 68
69 69 You can also define aliases with parameters using %s specifiers (one
70 70 per parameter)::
71 71
72 72 In [1]: alias parts echo first %s second %s
73 73 In [2]: %parts A B
74 74 first A second B
75 75 In [3]: %parts A
76 76 Incorrect number of arguments: 2 expected.
77 77 parts is an alias to: 'echo first %s second %s'
78 78
79 79 Note that %l and %s are mutually exclusive. You can only use one or
80 80 the other in your aliases.
81 81
82 82 Aliases expand Python variables just like system calls using ! or !!
83 83 do: all expressions prefixed with '$' get expanded. For details of
84 84 the semantic rules, see PEP-215:
85 85 http://www.python.org/peps/pep-0215.html. This is the library used by
86 86 IPython for variable expansion. If you want to access a true shell
87 87 variable, an extra $ is necessary to prevent its expansion by
88 88 IPython::
89 89
90 90 In [6]: alias show echo
91 91 In [7]: PATH='A Python string'
92 92 In [8]: show $PATH
93 93 A Python string
94 94 In [9]: show $$PATH
95 95 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
96 96
97 97 You can use the alias facility to acess all of $PATH. See the %rehash
98 98 and %rehashx functions, which automatically create aliases for the
99 99 contents of your $PATH.
100 100
101 101 If called with no parameters, %alias prints the current alias table."""
102 102
103 103 par = parameter_s.strip()
104 104 if not par:
105 105 aliases = sorted(self.shell.alias_manager.aliases)
106 106 # stored = self.shell.db.get('stored_aliases', {} )
107 107 # for k, v in stored:
108 108 # atab.append(k, v[0])
109 109
110 110 print "Total number of aliases:", len(aliases)
111 111 sys.stdout.flush()
112 112 return aliases
113 113
114 114 # Now try to define a new one
115 115 try:
116 116 alias,cmd = par.split(None, 1)
117 117 except TypeError:
118 118 print(oinspect.getdoc(self.alias))
119 119 return
120 120
121 121 try:
122 122 self.shell.alias_manager.define_alias(alias, cmd)
123 123 except AliasError as e:
124 124 print(e)
125 125 # end magic_alias
126 126
127 127 @line_magic
128 128 def unalias(self, parameter_s=''):
129 129 """Remove an alias"""
130 130
131 131 aname = parameter_s.strip()
132 132 try:
133 133 self.shell.alias_manager.undefine_alias(aname)
134 134 except ValueError as e:
135 135 print(e)
136 136 return
137 137
138 138 stored = self.shell.db.get('stored_aliases', {} )
139 139 if aname in stored:
140 140 print "Removing %stored alias",aname
141 141 del stored[aname]
142 142 self.shell.db['stored_aliases'] = stored
143 143
144 144 @line_magic
145 145 def rehashx(self, parameter_s=''):
146 146 """Update the alias table with all executable files in $PATH.
147 147
148 148 This version explicitly checks that every entry in $PATH is a file
149 149 with execute access (os.X_OK), so it is much slower than %rehash.
150 150
151 151 Under Windows, it checks executability as a match against a
152 152 '|'-separated string of extensions, stored in the IPython config
153 153 variable win_exec_ext. This defaults to 'exe|com|bat'.
154 154
155 155 This function also resets the root module cache of module completer,
156 156 used on slow filesystems.
157 157 """
158 158 from IPython.core.alias import InvalidAliasError
159 159
160 160 # for the benefit of module completer in ipy_completers.py
161 161 del self.shell.db['rootmodules_cache']
162 162
163 163 path = [os.path.abspath(os.path.expanduser(p)) for p in
164 164 os.environ.get('PATH','').split(os.pathsep)]
165 165 path = filter(os.path.isdir,path)
166 166
167 167 syscmdlist = []
168 168 # Now define isexec in a cross platform manner.
169 169 if os.name == 'posix':
170 170 isexec = lambda fname:os.path.isfile(fname) and \
171 171 os.access(fname,os.X_OK)
172 172 else:
173 173 try:
174 174 winext = os.environ['pathext'].replace(';','|').replace('.','')
175 175 except KeyError:
176 176 winext = 'exe|com|bat|py'
177 177 if 'py' not in winext:
178 178 winext += '|py'
179 179 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
180 180 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
181 181 savedir = os.getcwdu()
182 182
183 183 # Now walk the paths looking for executables to alias.
184 184 try:
185 185 # write the whole loop for posix/Windows so we don't have an if in
186 186 # the innermost part
187 187 if os.name == 'posix':
188 188 for pdir in path:
189 189 os.chdir(pdir)
190 190 for ff in os.listdir(pdir):
191 191 if isexec(ff):
192 192 try:
193 193 # Removes dots from the name since ipython
194 194 # will assume names with dots to be python.
195 195 if not self.shell.alias_manager.is_alias(ff):
196 196 self.shell.alias_manager.define_alias(
197 197 ff.replace('.',''), ff)
198 198 except InvalidAliasError:
199 199 pass
200 200 else:
201 201 syscmdlist.append(ff)
202 202 else:
203 no_alias = self.shell.alias_manager.no_alias
203 no_alias = Alias.blacklist
204 204 for pdir in path:
205 205 os.chdir(pdir)
206 206 for ff in os.listdir(pdir):
207 207 base, ext = os.path.splitext(ff)
208 208 if isexec(ff) and base.lower() not in no_alias:
209 209 if ext.lower() == '.exe':
210 210 ff = base
211 211 try:
212 212 # Removes dots from the name since ipython
213 213 # will assume names with dots to be python.
214 214 self.shell.alias_manager.define_alias(
215 215 base.lower().replace('.',''), ff)
216 216 except InvalidAliasError:
217 217 pass
218 218 syscmdlist.append(ff)
219 219 self.shell.db['syscmdlist'] = syscmdlist
220 220 finally:
221 221 os.chdir(savedir)
222 222
223 223 @skip_doctest
224 224 @line_magic
225 225 def pwd(self, parameter_s=''):
226 226 """Return the current working directory path.
227 227
228 228 Examples
229 229 --------
230 230 ::
231 231
232 232 In [9]: pwd
233 233 Out[9]: '/home/tsuser/sprint/ipython'
234 234 """
235 235 return os.getcwdu()
236 236
237 237 @skip_doctest
238 238 @line_magic
239 239 def cd(self, parameter_s=''):
240 240 """Change the current working directory.
241 241
242 242 This command automatically maintains an internal list of directories
243 243 you visit during your IPython session, in the variable _dh. The
244 244 command %dhist shows this history nicely formatted. You can also
245 245 do 'cd -<tab>' to see directory history conveniently.
246 246
247 247 Usage:
248 248
249 249 cd 'dir': changes to directory 'dir'.
250 250
251 251 cd -: changes to the last visited directory.
252 252
253 253 cd -<n>: changes to the n-th directory in the directory history.
254 254
255 255 cd --foo: change to directory that matches 'foo' in history
256 256
257 257 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
258 258 (note: cd <bookmark_name> is enough if there is no
259 259 directory <bookmark_name>, but a bookmark with the name exists.)
260 260 'cd -b <tab>' allows you to tab-complete bookmark names.
261 261
262 262 Options:
263 263
264 264 -q: quiet. Do not print the working directory after the cd command is
265 265 executed. By default IPython's cd command does print this directory,
266 266 since the default prompts do not display path information.
267 267
268 268 Note that !cd doesn't work for this purpose because the shell where
269 269 !command runs is immediately discarded after executing 'command'.
270 270
271 271 Examples
272 272 --------
273 273 ::
274 274
275 275 In [10]: cd parent/child
276 276 /home/tsuser/parent/child
277 277 """
278 278
279 279 oldcwd = os.getcwdu()
280 280 numcd = re.match(r'(-)(\d+)$',parameter_s)
281 281 # jump in directory history by number
282 282 if numcd:
283 283 nn = int(numcd.group(2))
284 284 try:
285 285 ps = self.shell.user_ns['_dh'][nn]
286 286 except IndexError:
287 287 print 'The requested directory does not exist in history.'
288 288 return
289 289 else:
290 290 opts = {}
291 291 elif parameter_s.startswith('--'):
292 292 ps = None
293 293 fallback = None
294 294 pat = parameter_s[2:]
295 295 dh = self.shell.user_ns['_dh']
296 296 # first search only by basename (last component)
297 297 for ent in reversed(dh):
298 298 if pat in os.path.basename(ent) and os.path.isdir(ent):
299 299 ps = ent
300 300 break
301 301
302 302 if fallback is None and pat in ent and os.path.isdir(ent):
303 303 fallback = ent
304 304
305 305 # if we have no last part match, pick the first full path match
306 306 if ps is None:
307 307 ps = fallback
308 308
309 309 if ps is None:
310 310 print "No matching entry in directory history"
311 311 return
312 312 else:
313 313 opts = {}
314 314
315 315
316 316 else:
317 317 #turn all non-space-escaping backslashes to slashes,
318 318 # for c:\windows\directory\names\
319 319 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
320 320 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
321 321 # jump to previous
322 322 if ps == '-':
323 323 try:
324 324 ps = self.shell.user_ns['_dh'][-2]
325 325 except IndexError:
326 326 raise UsageError('%cd -: No previous directory to change to.')
327 327 # jump to bookmark if needed
328 328 else:
329 329 if not os.path.isdir(ps) or 'b' in opts:
330 330 bkms = self.shell.db.get('bookmarks', {})
331 331
332 332 if ps in bkms:
333 333 target = bkms[ps]
334 334 print '(bookmark:%s) -> %s' % (ps, target)
335 335 ps = target
336 336 else:
337 337 if 'b' in opts:
338 338 raise UsageError("Bookmark '%s' not found. "
339 339 "Use '%%bookmark -l' to see your bookmarks." % ps)
340 340
341 341 # strip extra quotes on Windows, because os.chdir doesn't like them
342 342 ps = unquote_filename(ps)
343 343 # at this point ps should point to the target dir
344 344 if ps:
345 345 try:
346 346 os.chdir(os.path.expanduser(ps))
347 347 if hasattr(self.shell, 'term_title') and self.shell.term_title:
348 348 set_term_title('IPython: ' + abbrev_cwd())
349 349 except OSError:
350 350 print sys.exc_info()[1]
351 351 else:
352 352 cwd = os.getcwdu()
353 353 dhist = self.shell.user_ns['_dh']
354 354 if oldcwd != cwd:
355 355 dhist.append(cwd)
356 356 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
357 357
358 358 else:
359 359 os.chdir(self.shell.home_dir)
360 360 if hasattr(self.shell, 'term_title') and self.shell.term_title:
361 361 set_term_title('IPython: ' + '~')
362 362 cwd = os.getcwdu()
363 363 dhist = self.shell.user_ns['_dh']
364 364
365 365 if oldcwd != cwd:
366 366 dhist.append(cwd)
367 367 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
368 368 if not 'q' in opts and self.shell.user_ns['_dh']:
369 369 print self.shell.user_ns['_dh'][-1]
370 370
371 371
372 372 @line_magic
373 373 def env(self, parameter_s=''):
374 374 """List environment variables."""
375 375
376 376 return dict(os.environ)
377 377
378 378 @line_magic
379 379 def pushd(self, parameter_s=''):
380 380 """Place the current dir on stack and change directory.
381 381
382 382 Usage:\\
383 383 %pushd ['dirname']
384 384 """
385 385
386 386 dir_s = self.shell.dir_stack
387 387 tgt = os.path.expanduser(unquote_filename(parameter_s))
388 388 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
389 389 if tgt:
390 390 self.cd(parameter_s)
391 391 dir_s.insert(0,cwd)
392 392 return self.shell.magic('dirs')
393 393
394 394 @line_magic
395 395 def popd(self, parameter_s=''):
396 396 """Change to directory popped off the top of the stack.
397 397 """
398 398 if not self.shell.dir_stack:
399 399 raise UsageError("%popd on empty stack")
400 400 top = self.shell.dir_stack.pop(0)
401 401 self.cd(top)
402 402 print "popd ->",top
403 403
404 404 @line_magic
405 405 def dirs(self, parameter_s=''):
406 406 """Return the current directory stack."""
407 407
408 408 return self.shell.dir_stack
409 409
410 410 @line_magic
411 411 def dhist(self, parameter_s=''):
412 412 """Print your history of visited directories.
413 413
414 414 %dhist -> print full history\\
415 415 %dhist n -> print last n entries only\\
416 416 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
417 417
418 418 This history is automatically maintained by the %cd command, and
419 419 always available as the global list variable _dh. You can use %cd -<n>
420 420 to go to directory number <n>.
421 421
422 422 Note that most of time, you should view directory history by entering
423 423 cd -<TAB>.
424 424
425 425 """
426 426
427 427 dh = self.shell.user_ns['_dh']
428 428 if parameter_s:
429 429 try:
430 430 args = map(int,parameter_s.split())
431 431 except:
432 432 self.arg_err(self.dhist)
433 433 return
434 434 if len(args) == 1:
435 435 ini,fin = max(len(dh)-(args[0]),0),len(dh)
436 436 elif len(args) == 2:
437 437 ini,fin = args
438 438 fin = min(fin, len(dh))
439 439 else:
440 440 self.arg_err(self.dhist)
441 441 return
442 442 else:
443 443 ini,fin = 0,len(dh)
444 444 print 'Directory history (kept in _dh)'
445 445 for i in range(ini, fin):
446 446 print "%d: %s" % (i, dh[i])
447 447
448 448 @skip_doctest
449 449 @line_magic
450 450 def sc(self, parameter_s=''):
451 451 """Shell capture - run shell command and capture output (DEPRECATED use !).
452 452
453 453 DEPRECATED. Suboptimal, retained for backwards compatibility.
454 454
455 455 You should use the form 'var = !command' instead. Example:
456 456
457 457 "%sc -l myfiles = ls ~" should now be written as
458 458
459 459 "myfiles = !ls ~"
460 460
461 461 myfiles.s, myfiles.l and myfiles.n still apply as documented
462 462 below.
463 463
464 464 --
465 465 %sc [options] varname=command
466 466
467 467 IPython will run the given command using commands.getoutput(), and
468 468 will then update the user's interactive namespace with a variable
469 469 called varname, containing the value of the call. Your command can
470 470 contain shell wildcards, pipes, etc.
471 471
472 472 The '=' sign in the syntax is mandatory, and the variable name you
473 473 supply must follow Python's standard conventions for valid names.
474 474
475 475 (A special format without variable name exists for internal use)
476 476
477 477 Options:
478 478
479 479 -l: list output. Split the output on newlines into a list before
480 480 assigning it to the given variable. By default the output is stored
481 481 as a single string.
482 482
483 483 -v: verbose. Print the contents of the variable.
484 484
485 485 In most cases you should not need to split as a list, because the
486 486 returned value is a special type of string which can automatically
487 487 provide its contents either as a list (split on newlines) or as a
488 488 space-separated string. These are convenient, respectively, either
489 489 for sequential processing or to be passed to a shell command.
490 490
491 491 For example::
492 492
493 493 # Capture into variable a
494 494 In [1]: sc a=ls *py
495 495
496 496 # a is a string with embedded newlines
497 497 In [2]: a
498 498 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
499 499
500 500 # which can be seen as a list:
501 501 In [3]: a.l
502 502 Out[3]: ['setup.py', 'win32_manual_post_install.py']
503 503
504 504 # or as a whitespace-separated string:
505 505 In [4]: a.s
506 506 Out[4]: 'setup.py win32_manual_post_install.py'
507 507
508 508 # a.s is useful to pass as a single command line:
509 509 In [5]: !wc -l $a.s
510 510 146 setup.py
511 511 130 win32_manual_post_install.py
512 512 276 total
513 513
514 514 # while the list form is useful to loop over:
515 515 In [6]: for f in a.l:
516 516 ...: !wc -l $f
517 517 ...:
518 518 146 setup.py
519 519 130 win32_manual_post_install.py
520 520
521 521 Similarly, the lists returned by the -l option are also special, in
522 522 the sense that you can equally invoke the .s attribute on them to
523 523 automatically get a whitespace-separated string from their contents::
524 524
525 525 In [7]: sc -l b=ls *py
526 526
527 527 In [8]: b
528 528 Out[8]: ['setup.py', 'win32_manual_post_install.py']
529 529
530 530 In [9]: b.s
531 531 Out[9]: 'setup.py win32_manual_post_install.py'
532 532
533 533 In summary, both the lists and strings used for output capture have
534 534 the following special attributes::
535 535
536 536 .l (or .list) : value as list.
537 537 .n (or .nlstr): value as newline-separated string.
538 538 .s (or .spstr): value as space-separated string.
539 539 """
540 540
541 541 opts,args = self.parse_options(parameter_s, 'lv')
542 542 # Try to get a variable name and command to run
543 543 try:
544 544 # the variable name must be obtained from the parse_options
545 545 # output, which uses shlex.split to strip options out.
546 546 var,_ = args.split('=', 1)
547 547 var = var.strip()
548 548 # But the command has to be extracted from the original input
549 549 # parameter_s, not on what parse_options returns, to avoid the
550 550 # quote stripping which shlex.split performs on it.
551 551 _,cmd = parameter_s.split('=', 1)
552 552 except ValueError:
553 553 var,cmd = '',''
554 554 # If all looks ok, proceed
555 555 split = 'l' in opts
556 556 out = self.shell.getoutput(cmd, split=split)
557 557 if 'v' in opts:
558 558 print '%s ==\n%s' % (var, pformat(out))
559 559 if var:
560 560 self.shell.user_ns.update({var:out})
561 561 else:
562 562 return out
563 563
564 564 @line_cell_magic
565 565 def sx(self, line='', cell=None):
566 566 """Shell execute - run shell command and capture output (!! is short-hand).
567 567
568 568 %sx command
569 569
570 570 IPython will run the given command using commands.getoutput(), and
571 571 return the result formatted as a list (split on '\\n'). Since the
572 572 output is _returned_, it will be stored in ipython's regular output
573 573 cache Out[N] and in the '_N' automatic variables.
574 574
575 575 Notes:
576 576
577 577 1) If an input line begins with '!!', then %sx is automatically
578 578 invoked. That is, while::
579 579
580 580 !ls
581 581
582 582 causes ipython to simply issue system('ls'), typing::
583 583
584 584 !!ls
585 585
586 586 is a shorthand equivalent to::
587 587
588 588 %sx ls
589 589
590 590 2) %sx differs from %sc in that %sx automatically splits into a list,
591 591 like '%sc -l'. The reason for this is to make it as easy as possible
592 592 to process line-oriented shell output via further python commands.
593 593 %sc is meant to provide much finer control, but requires more
594 594 typing.
595 595
596 596 3) Just like %sc -l, this is a list with special attributes:
597 597 ::
598 598
599 599 .l (or .list) : value as list.
600 600 .n (or .nlstr): value as newline-separated string.
601 601 .s (or .spstr): value as whitespace-separated string.
602 602
603 603 This is very useful when trying to use such lists as arguments to
604 604 system commands."""
605 605
606 606 if cell is None:
607 607 # line magic
608 608 return self.shell.getoutput(line)
609 609 else:
610 610 opts,args = self.parse_options(line, '', 'out=')
611 611 output = self.shell.getoutput(cell)
612 612 out_name = opts.get('out', opts.get('o'))
613 613 if out_name:
614 614 self.shell.user_ns[out_name] = output
615 615 else:
616 616 return output
617 617
618 618 system = line_cell_magic('system')(sx)
619 619 bang = cell_magic('!')(sx)
620 620
621 621 @line_magic
622 622 def bookmark(self, parameter_s=''):
623 623 """Manage IPython's bookmark system.
624 624
625 625 %bookmark <name> - set bookmark to current dir
626 626 %bookmark <name> <dir> - set bookmark to <dir>
627 627 %bookmark -l - list all bookmarks
628 628 %bookmark -d <name> - remove bookmark
629 629 %bookmark -r - remove all bookmarks
630 630
631 631 You can later on access a bookmarked folder with::
632 632
633 633 %cd -b <name>
634 634
635 635 or simply '%cd <name>' if there is no directory called <name> AND
636 636 there is such a bookmark defined.
637 637
638 638 Your bookmarks persist through IPython sessions, but they are
639 639 associated with each profile."""
640 640
641 641 opts,args = self.parse_options(parameter_s,'drl',mode='list')
642 642 if len(args) > 2:
643 643 raise UsageError("%bookmark: too many arguments")
644 644
645 645 bkms = self.shell.db.get('bookmarks',{})
646 646
647 647 if 'd' in opts:
648 648 try:
649 649 todel = args[0]
650 650 except IndexError:
651 651 raise UsageError(
652 652 "%bookmark -d: must provide a bookmark to delete")
653 653 else:
654 654 try:
655 655 del bkms[todel]
656 656 except KeyError:
657 657 raise UsageError(
658 658 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
659 659
660 660 elif 'r' in opts:
661 661 bkms = {}
662 662 elif 'l' in opts:
663 663 bks = bkms.keys()
664 664 bks.sort()
665 665 if bks:
666 666 size = max(map(len, bks))
667 667 else:
668 668 size = 0
669 669 fmt = '%-'+str(size)+'s -> %s'
670 670 print 'Current bookmarks:'
671 671 for bk in bks:
672 672 print fmt % (bk, bkms[bk])
673 673 else:
674 674 if not args:
675 675 raise UsageError("%bookmark: You must specify the bookmark name")
676 676 elif len(args)==1:
677 677 bkms[args[0]] = os.getcwdu()
678 678 elif len(args)==2:
679 679 bkms[args[0]] = args[1]
680 680 self.shell.db['bookmarks'] = bkms
681 681
682 682 @line_magic
683 683 def pycat(self, parameter_s=''):
684 684 """Show a syntax-highlighted file through a pager.
685 685
686 686 This magic is similar to the cat utility, but it will assume the file
687 687 to be Python source and will show it with syntax highlighting.
688 688
689 689 This magic command can either take a local filename, an url,
690 690 an history range (see %history) or a macro as argument ::
691 691
692 692 %pycat myscript.py
693 693 %pycat 7-27
694 694 %pycat myMacro
695 695 %pycat http://www.example.com/myscript.py
696 696 """
697 697 if not parameter_s:
698 698 raise UsageError('Missing filename, URL, input history range, '
699 699 'or macro.')
700 700
701 701 try :
702 702 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
703 703 except (ValueError, IOError):
704 704 print "Error: no such file, variable, URL, history range or macro"
705 705 return
706 706
707 707 page.page(self.shell.pycolorize(source_to_unicode(cont)))
708 708
709 709 @magic_arguments.magic_arguments()
710 710 @magic_arguments.argument(
711 711 '-a', '--append', action='store_true', default=False,
712 712 help='Append contents of the cell to an existing file. '
713 713 'The file will be created if it does not exist.'
714 714 )
715 715 @magic_arguments.argument(
716 716 'filename', type=unicode,
717 717 help='file to write'
718 718 )
719 719 @cell_magic
720 720 def writefile(self, line, cell):
721 721 """Write the contents of the cell to a file.
722 722
723 723 The file will be overwritten unless the -a (--append) flag is specified.
724 724 """
725 725 args = magic_arguments.parse_argstring(self.writefile, line)
726 726 filename = os.path.expanduser(unquote_filename(args.filename))
727 727
728 728 if os.path.exists(filename):
729 729 if args.append:
730 730 print "Appending to %s" % filename
731 731 else:
732 732 print "Overwriting %s" % filename
733 733 else:
734 734 print "Writing %s" % filename
735 735
736 736 mode = 'a' if args.append else 'w'
737 737 with io.open(filename, mode, encoding='utf-8') as f:
738 738 f.write(cell)
@@ -1,244 +1,243 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 %store magic for lightweight persistence.
4 4
5 5 Stores variables, aliases and macros in IPython's database.
6 6
7 7 To automatically restore stored variables at startup, add this to your
8 8 :file:`ipython_config.py` file::
9 9
10 10 c.StoreMagic.autorestore = True
11 11 """
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (c) 2012, The IPython Development Team.
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.txt, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 # Stdlib
25 25 import inspect, os, sys, textwrap
26 26
27 27 # Our own
28 28 from IPython.config.configurable import Configurable
29 29 from IPython.core.error import UsageError
30 30 from IPython.core.magic import Magics, magics_class, line_magic
31 31 from IPython.testing.skipdoctest import skip_doctest
32 32 from IPython.utils.traitlets import Bool
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Functions and classes
36 36 #-----------------------------------------------------------------------------
37 37
38 38 def restore_aliases(ip):
39 39 staliases = ip.db.get('stored_aliases', {})
40 40 for k,v in staliases.items():
41 41 #print "restore alias",k,v # dbg
42 42 #self.alias_table[k] = v
43 43 ip.alias_manager.define_alias(k,v)
44 44
45 45
46 46 def refresh_variables(ip):
47 47 db = ip.db
48 48 for key in db.keys('autorestore/*'):
49 49 # strip autorestore
50 50 justkey = os.path.basename(key)
51 51 try:
52 52 obj = db[key]
53 53 except KeyError:
54 54 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
55 55 print "The error was:", sys.exc_info()[0]
56 56 else:
57 57 #print "restored",justkey,"=",obj #dbg
58 58 ip.user_ns[justkey] = obj
59 59
60 60
61 61 def restore_dhist(ip):
62 62 ip.user_ns['_dh'] = ip.db.get('dhist',[])
63 63
64 64
65 65 def restore_data(ip):
66 66 refresh_variables(ip)
67 67 restore_aliases(ip)
68 68 restore_dhist(ip)
69 69
70 70
71 71 @magics_class
72 72 class StoreMagics(Magics, Configurable):
73 73 """Lightweight persistence for python variables.
74 74
75 75 Provides the %store magic."""
76 76
77 77 autorestore = Bool(False, config=True, help=
78 78 """If True, any %store-d variables will be automatically restored
79 79 when IPython starts.
80 80 """
81 81 )
82 82
83 83 def __init__(self, shell):
84 84 Configurable.__init__(self, config=shell.config)
85 85 Magics.__init__(self, shell=shell)
86 86 self.shell.configurables.append(self)
87 87 if self.autorestore:
88 88 restore_data(self.shell)
89 89
90 90 @skip_doctest
91 91 @line_magic
92 92 def store(self, parameter_s=''):
93 93 """Lightweight persistence for python variables.
94 94
95 95 Example::
96 96
97 97 In [1]: l = ['hello',10,'world']
98 98 In [2]: %store l
99 99 In [3]: exit
100 100
101 101 (IPython session is closed and started again...)
102 102
103 103 ville@badger:~$ ipython
104 104 In [1]: l
105 105 NameError: name 'l' is not defined
106 106 In [2]: %store -r
107 107 In [3]: l
108 108 Out[3]: ['hello', 10, 'world']
109 109
110 110 Usage:
111 111
112 112 * ``%store`` - Show list of all variables and their current
113 113 values
114 114 * ``%store spam`` - Store the *current* value of the variable spam
115 115 to disk
116 116 * ``%store -d spam`` - Remove the variable and its value from storage
117 117 * ``%store -z`` - Remove all variables from storage
118 118 * ``%store -r`` - Refresh all variables from store (overwrite
119 119 current vals)
120 120 * ``%store -r spam bar`` - Refresh specified variables from store
121 121 (delete current val)
122 122 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
123 123 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
124 124
125 125 It should be noted that if you change the value of a variable, you
126 126 need to %store it again if you want to persist the new value.
127 127
128 128 Note also that the variables will need to be pickleable; most basic
129 129 python types can be safely %store'd.
130 130
131 131 Also aliases can be %store'd across sessions.
132 132 """
133 133
134 134 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
135 135 args = argsl.split(None,1)
136 136 ip = self.shell
137 137 db = ip.db
138 138 # delete
139 139 if 'd' in opts:
140 140 try:
141 141 todel = args[0]
142 142 except IndexError:
143 143 raise UsageError('You must provide the variable to forget')
144 144 else:
145 145 try:
146 146 del db['autorestore/' + todel]
147 147 except:
148 148 raise UsageError("Can't delete variable '%s'" % todel)
149 149 # reset
150 150 elif 'z' in opts:
151 151 for k in db.keys('autorestore/*'):
152 152 del db[k]
153 153
154 154 elif 'r' in opts:
155 155 if args:
156 156 for arg in args:
157 157 try:
158 158 obj = db['autorestore/' + arg]
159 159 except KeyError:
160 160 print "no stored variable %s" % arg
161 161 else:
162 162 ip.user_ns[arg] = obj
163 163 else:
164 164 restore_data(ip)
165 165
166 166 # run without arguments -> list variables & values
167 167 elif not args:
168 168 vars = db.keys('autorestore/*')
169 169 vars.sort()
170 170 if vars:
171 171 size = max(map(len, vars))
172 172 else:
173 173 size = 0
174 174
175 175 print 'Stored variables and their in-db values:'
176 176 fmt = '%-'+str(size)+'s -> %s'
177 177 get = db.get
178 178 for var in vars:
179 179 justkey = os.path.basename(var)
180 180 # print 30 first characters from every var
181 181 print fmt % (justkey, repr(get(var, '<unavailable>'))[:50])
182 182
183 183 # default action - store the variable
184 184 else:
185 185 # %store foo >file.txt or >>file.txt
186 186 if len(args) > 1 and args[1].startswith('>'):
187 187 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
188 188 if args[1].startswith('>>'):
189 189 fil = open(fnam, 'a')
190 190 else:
191 191 fil = open(fnam, 'w')
192 192 obj = ip.ev(args[0])
193 193 print "Writing '%s' (%s) to file '%s'." % (args[0],
194 194 obj.__class__.__name__, fnam)
195 195
196 196
197 197 if not isinstance (obj, basestring):
198 198 from pprint import pprint
199 199 pprint(obj, fil)
200 200 else:
201 201 fil.write(obj)
202 202 if not obj.endswith('\n'):
203 203 fil.write('\n')
204 204
205 205 fil.close()
206 206 return
207 207
208 208 # %store foo
209 209 try:
210 210 obj = ip.user_ns[args[0]]
211 211 except KeyError:
212 212 # it might be an alias
213 # This needs to be refactored to use the new AliasManager stuff.
214 213 name = args[0]
215 214 try:
216 215 cmd = ip.alias_manager.retrieve_alias(name)
217 216 except ValueError:
218 217 raise UsageError("Unknown variable '%s'" % name)
219 218
220 219 staliases = db.get('stored_aliases',{})
221 220 staliases[name] = cmd
222 221 db['stored_aliases'] = staliases
223 222 print "Alias stored: %s (%s)" % (name, cmd)
224 223 return
225 224
226 225 else:
227 226 modname = getattr(inspect.getmodule(obj), '__name__', '')
228 227 if modname == '__main__':
229 228 print textwrap.dedent("""\
230 229 Warning:%s is %s
231 230 Proper storage of interactively declared classes (or instances
232 231 of those classes) is not possible! Only instances
233 232 of classes in real modules on file system can be %%store'd.
234 233 """ % (args[0], obj) )
235 234 return
236 235 #pickled = pickle.dumps(obj)
237 236 db[ 'autorestore/' + args[0] ] = obj
238 237 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
239 238
240 239
241 240 def load_ipython_extension(ip):
242 241 """Load the extension in IPython."""
243 242 ip.register_magics(StoreMagics)
244 243
General Comments 0
You need to be logged in to leave comments. Login now