##// END OF EJS Templates
Restore pspersistence, including %store magic, as an extension.
Thomas Kluyver -
Show More
@@ -1,263 +1,263 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-2010 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 23 import __builtin__
24 24 import keyword
25 25 import os
26 26 import re
27 27 import sys
28 28
29 29 from IPython.config.configurable import Configurable
30 30 from IPython.core.splitinput import split_user_input
31 31
32 32 from IPython.utils.traitlets import List, Instance
33 33 from IPython.utils.autoattr import auto_attr
34 34 from IPython.utils.warn import warn, error
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Utilities
38 38 #-----------------------------------------------------------------------------
39 39
40 40 # This is used as the pattern for calls to split_user_input.
41 41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42 42
43 43 def default_aliases():
44 44 """Return list of shell aliases to auto-define.
45 45 """
46 46 # Note: the aliases defined here should be safe to use on a kernel
47 47 # regardless of what frontend it is attached to. Frontends that use a
48 48 # kernel in-process can define additional aliases that will only work in
49 49 # their case. For example, things like 'less' or 'clear' that manipulate
50 50 # the terminal should NOT be declared here, as they will only work if the
51 51 # kernel is running inside a true terminal, and not over the network.
52 52
53 53 if os.name == 'posix':
54 54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
56 56 ('cat', 'cat'),
57 57 ]
58 58 # Useful set of ls aliases. The GNU and BSD options are a little
59 59 # different, so we make aliases that provide as similar as possible
60 60 # behavior in ipython, by passing the right flags for each platform
61 61 if sys.platform.startswith('linux'):
62 62 ls_aliases = [('ls', 'ls -F --color'),
63 63 # long ls
64 64 ('ll', 'ls -F -o --color'),
65 65 # ls normal files only
66 66 ('lf', 'ls -F -o --color %l | grep ^-'),
67 67 # ls symbolic links
68 68 ('lk', 'ls -F -o --color %l | grep ^l'),
69 69 # directories or links to directories,
70 70 ('ldir', 'ls -F -o --color %l | grep /$'),
71 71 # things which are executable
72 72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
73 73 ]
74 74 else:
75 75 # BSD, OSX, etc.
76 76 ls_aliases = [('ls', 'ls -F'),
77 77 # long ls
78 78 ('ll', 'ls -F -l'),
79 79 # ls normal files only
80 80 ('lf', 'ls -F -l %l | grep ^-'),
81 81 # ls symbolic links
82 82 ('lk', 'ls -F -l %l | grep ^l'),
83 83 # directories or links to directories,
84 84 ('ldir', 'ls -F -l %l | grep /$'),
85 85 # things which are executable
86 86 ('lx', 'ls -F -l %l | grep ^-..x'),
87 87 ]
88 88 default_aliases = default_aliases + ls_aliases
89 89 elif os.name in ['nt', 'dos']:
90 90 default_aliases = [('ls', 'dir /on'),
91 91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
92 92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
93 93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
94 94 ]
95 95 else:
96 96 default_aliases = []
97 97
98 98 return default_aliases
99 99
100 100
101 101 class AliasError(Exception):
102 102 pass
103 103
104 104
105 105 class InvalidAliasError(AliasError):
106 106 pass
107 107
108 108 #-----------------------------------------------------------------------------
109 109 # Main AliasManager class
110 110 #-----------------------------------------------------------------------------
111 111
112 112 class AliasManager(Configurable):
113 113
114 114 default_aliases = List(default_aliases(), config=True)
115 115 user_aliases = List(default_value=[], config=True)
116 116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
117 117
118 118 def __init__(self, shell=None, config=None):
119 119 super(AliasManager, self).__init__(shell=shell, config=config)
120 120 self.alias_table = {}
121 121 self.exclude_aliases()
122 122 self.init_aliases()
123 123
124 124 def __contains__(self, name):
125 125 return name in self.alias_table
126 126
127 127 @property
128 128 def aliases(self):
129 129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
130 130
131 131 def exclude_aliases(self):
132 132 # set of things NOT to alias (keywords, builtins and some magics)
133 133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
134 134 no_alias.update(set(keyword.kwlist))
135 135 no_alias.update(set(__builtin__.__dict__.keys()))
136 136 self.no_alias = no_alias
137 137
138 138 def init_aliases(self):
139 139 # Load default aliases
140 140 for name, cmd in self.default_aliases:
141 141 self.soft_define_alias(name, cmd)
142 142
143 143 # Load user aliases
144 144 for name, cmd in self.user_aliases:
145 145 self.soft_define_alias(name, cmd)
146 146
147 147 def clear_aliases(self):
148 148 self.alias_table.clear()
149 149
150 150 def soft_define_alias(self, name, cmd):
151 151 """Define an alias, but don't raise on an AliasError."""
152 152 try:
153 153 self.define_alias(name, cmd)
154 154 except AliasError, e:
155 155 error("Invalid alias: %s" % e)
156 156
157 157 def define_alias(self, name, cmd):
158 158 """Define a new alias after validating it.
159 159
160 160 This will raise an :exc:`AliasError` if there are validation
161 161 problems.
162 162 """
163 163 nargs = self.validate_alias(name, cmd)
164 164 self.alias_table[name] = (nargs, cmd)
165 165
166 166 def undefine_alias(self, name):
167 167 if self.alias_table.has_key(name):
168 168 del self.alias_table[name]
169 169
170 170 def validate_alias(self, name, cmd):
171 171 """Validate an alias and return the its number of arguments."""
172 172 if name in self.no_alias:
173 173 raise InvalidAliasError("The name %s can't be aliased "
174 174 "because it is a keyword or builtin." % name)
175 175 if not (isinstance(cmd, basestring)):
176 176 raise InvalidAliasError("An alias command must be a string, "
177 "got: %r" % name)
177 "got: %r" % cmd)
178 178 nargs = cmd.count('%s')
179 179 if nargs>0 and cmd.find('%l')>=0:
180 180 raise InvalidAliasError('The %s and %l specifiers are mutually '
181 181 'exclusive in alias definitions.')
182 182 return nargs
183 183
184 184 def call_alias(self, alias, rest=''):
185 185 """Call an alias given its name and the rest of the line."""
186 186 cmd = self.transform_alias(alias, rest)
187 187 try:
188 188 self.shell.system(cmd)
189 189 except:
190 190 self.shell.showtraceback()
191 191
192 192 def transform_alias(self, alias,rest=''):
193 193 """Transform alias to system command string."""
194 194 nargs, cmd = self.alias_table[alias]
195 195
196 196 if ' ' in cmd and os.path.isfile(cmd):
197 197 cmd = '"%s"' % cmd
198 198
199 199 # Expand the %l special to be the user's input line
200 200 if cmd.find('%l') >= 0:
201 201 cmd = cmd.replace('%l', rest)
202 202 rest = ''
203 203 if nargs==0:
204 204 # Simple, argument-less aliases
205 205 cmd = '%s %s' % (cmd, rest)
206 206 else:
207 207 # Handle aliases with positional arguments
208 208 args = rest.split(None, nargs)
209 209 if len(args) < nargs:
210 210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
211 211 (alias, nargs, len(args)))
212 212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
213 213 return cmd
214 214
215 215 def expand_alias(self, line):
216 216 """ Expand an alias in the command line
217 217
218 218 Returns the provided command line, possibly with the first word
219 219 (command) translated according to alias expansion rules.
220 220
221 221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
222 222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
223 223 """
224 224
225 225 pre,_,fn,rest = split_user_input(line)
226 226 res = pre + self.expand_aliases(fn, rest)
227 227 return res
228 228
229 229 def expand_aliases(self, fn, rest):
230 230 """Expand multiple levels of aliases:
231 231
232 232 if:
233 233
234 234 alias foo bar /tmp
235 235 alias baz foo
236 236
237 237 then:
238 238
239 239 baz huhhahhei -> bar /tmp huhhahhei
240 240 """
241 241 line = fn + " " + rest
242 242
243 243 done = set()
244 244 while 1:
245 245 pre,_,fn,rest = split_user_input(line, shell_line_split)
246 246 if fn in self.alias_table:
247 247 if fn in done:
248 248 warn("Cyclic alias definition, repeated '%s'" % fn)
249 249 return ""
250 250 done.add(fn)
251 251
252 252 l2 = self.transform_alias(fn, rest)
253 253 if l2 == line:
254 254 break
255 255 # ls -> ls -F should not recurse forever
256 256 if l2.split(None,1)[0] == line.split(None,1)[0]:
257 257 line = l2
258 258 break
259 259 line=l2
260 260 else:
261 261 break
262 262
263 263 return line
@@ -1,183 +1,178 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 %store magic for lightweight persistence.
4 4
5 5 Stores variables, aliases etc. in PickleShare database.
6 6 """
7 7
8 from IPython.core import ipapi
9 8 from IPython.core.error import TryNext, UsageError
10 ip = ipapi.get()
11
12 import pickleshare
9 from IPython.utils import pickleshare
13 10
14 11 import inspect,pickle,os,sys,textwrap
15 12 from IPython.core.fakemodule import FakeModule
16 13
17 def restore_aliases(self):
18 ip = self.getapi()
14 def restore_aliases(ip):
19 15 staliases = ip.db.get('stored_aliases', {})
20 16 for k,v in staliases.items():
21 17 #print "restore alias",k,v # dbg
22 18 #self.alias_table[k] = v
23 ip.define_alias(k,v)
19 ip.alias_manager.define_alias(k,v)
24 20
25 21
26 22 def refresh_variables(ip):
27 23 db = ip.db
28 24 for key in db.keys('autorestore/*'):
29 25 # strip autorestore
30 26 justkey = os.path.basename(key)
31 27 try:
32 28 obj = db[key]
33 29 except KeyError:
34 30 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
35 31 print "The error was:",sys.exc_info()[0]
36 32 else:
37 33 #print "restored",justkey,"=",obj #dbg
38 34 ip.user_ns[justkey] = obj
39 35
40 36
41 37 def restore_dhist(ip):
42 db = ip.db
43 ip.user_ns['_dh'] = db.get('dhist',[])
38 ip.user_ns['_dh'] = ip.db.get('dhist',[])
44 39
45 def restore_data(self):
46 ip = self.getapi()
40 def restore_data(ip):
47 41 refresh_variables(ip)
48 restore_aliases(self)
49 restore_dhist(self)
50 raise TryNext
51
52 ip.set_hook('late_startup_hook', restore_data)
42 restore_aliases(ip)
43 restore_dhist(ip)
53 44
54 45 def magic_store(self, parameter_s=''):
55 46 """Lightweight persistence for python variables.
56 47
57 48 Example:
58 49
59 50 ville@badger[~]|1> A = ['hello',10,'world']\\
60 51 ville@badger[~]|2> %store A\\
61 52 ville@badger[~]|3> Exit
62 53
63 54 (IPython session is closed and started again...)
64 55
65 56 ville@badger:~$ ipython -p pysh\\
66 57 ville@badger[~]|1> print A
67 58
68 59 ['hello', 10, 'world']
69 60
70 61 Usage:
71 62
72 63 %store - Show list of all variables and their current values\\
73 64 %store <var> - Store the *current* value of the variable to disk\\
74 65 %store -d <var> - Remove the variable and its value from storage\\
75 66 %store -z - Remove all variables from storage\\
76 67 %store -r - Refresh all variables from store (delete current vals)\\
77 68 %store foo >a.txt - Store value of foo to new file a.txt\\
78 69 %store foo >>a.txt - Append value of foo to file a.txt\\
79 70
80 71 It should be noted that if you change the value of a variable, you
81 72 need to %store it again if you want to persist the new value.
82 73
83 74 Note also that the variables will need to be pickleable; most basic
84 75 python types can be safely %stored.
85 76
86 77 Also aliases can be %store'd across sessions.
87 78 """
88 79
89 80 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
90 81 args = argsl.split(None,1)
91 ip = self.getapi()
82 ip = self.shell
92 83 db = ip.db
93 84 # delete
94 85 if opts.has_key('d'):
95 86 try:
96 87 todel = args[0]
97 88 except IndexError:
98 89 raise UsageError('You must provide the variable to forget')
99 90 else:
100 91 try:
101 92 del db['autorestore/' + todel]
102 93 except:
103 94 raise UsageError("Can't delete variable '%s'" % todel)
104 95 # reset
105 96 elif opts.has_key('z'):
106 97 for k in db.keys('autorestore/*'):
107 98 del db[k]
108 99
109 100 elif opts.has_key('r'):
110 101 refresh_variables(ip)
111 102
112 103
113 104 # run without arguments -> list variables & values
114 105 elif not args:
115 106 vars = self.db.keys('autorestore/*')
116 107 vars.sort()
117 108 if vars:
118 109 size = max(map(len,vars))
119 110 else:
120 111 size = 0
121 112
122 113 print 'Stored variables and their in-db values:'
123 114 fmt = '%-'+str(size)+'s -> %s'
124 115 get = db.get
125 116 for var in vars:
126 117 justkey = os.path.basename(var)
127 118 # print 30 first characters from every var
128 119 print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
129 120
130 121 # default action - store the variable
131 122 else:
132 123 # %store foo >file.txt or >>file.txt
133 124 if len(args) > 1 and args[1].startswith('>'):
134 125 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
135 126 if args[1].startswith('>>'):
136 127 fil = open(fnam,'a')
137 128 else:
138 129 fil = open(fnam,'w')
139 130 obj = ip.ev(args[0])
140 131 print "Writing '%s' (%s) to file '%s'." % (args[0],
141 132 obj.__class__.__name__, fnam)
142 133
143 134
144 135 if not isinstance (obj,basestring):
145 136 from pprint import pprint
146 137 pprint(obj,fil)
147 138 else:
148 139 fil.write(obj)
149 140 if not obj.endswith('\n'):
150 141 fil.write('\n')
151 142
152 143 fil.close()
153 144 return
154 145
155 146 # %store foo
156 147 try:
157 148 obj = ip.user_ns[args[0]]
158 149 except KeyError:
159 150 # it might be an alias
160 151 # This needs to be refactored to use the new AliasManager stuff.
161 if args[0] in self.alias_table:
152 if args[0] in self.alias_manager:
153 name = args[0]
154 nargs, cmd = self.alias_manager.alias_table[ name ]
162 155 staliases = db.get('stored_aliases',{})
163 staliases[ args[0] ] = self.alias_table[ args[0] ]
156 staliases[ name ] = cmd
164 157 db['stored_aliases'] = staliases
165 print "Alias stored:", args[0], self.alias_table[ args[0] ]
158 print "Alias stored: %s (%s)" % (name, cmd)
166 159 return
167 160 else:
168 161 raise UsageError("Unknown variable '%s'" % args[0])
169 162
170 163 else:
171 164 if isinstance(inspect.getmodule(obj), FakeModule):
172 165 print textwrap.dedent("""\
173 166 Warning:%s is %s
174 167 Proper storage of interactively declared classes (or instances
175 168 of those classes) is not possible! Only instances
176 169 of classes in real modules on file system can be %%store'd.
177 170 """ % (args[0], obj) )
178 171 return
179 172 #pickled = pickle.dumps(obj)
180 173 self.db[ 'autorestore/' + args[0] ] = obj
181 174 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
182 175
176 def load_ipython_extension(ip):
183 177 ip.define_magic('store',magic_store)
178 restore_data(ip)
General Comments 0
You need to be logged in to leave comments. Login now