##// END OF EJS Templates
Merge pull request #11930 from gokceneraslan/master...
Matthias Bussonnier -
r25234:61c70483 merge
parent child Browse files
Show More
@@ -1,226 +1,233 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.StoreMagics.autorestore = True
11 11 """
12 12
13 13 # Copyright (c) IPython Development Team.
14 14 # Distributed under the terms of the Modified BSD License.
15 15
16 16 import inspect, os, sys, textwrap
17 17
18 18 from IPython.core.error import UsageError
19 19 from IPython.core.magic import Magics, magics_class, line_magic
20 20 from traitlets import Bool
21 21
22 22
23 def restore_aliases(ip):
23 def restore_aliases(ip, alias=None):
24 24 staliases = ip.db.get('stored_aliases', {})
25 for k,v in staliases.items():
26 #print "restore alias",k,v # dbg
27 #self.alias_table[k] = v
28 ip.alias_manager.define_alias(k,v)
25 if alias is None:
26 for k,v in staliases.items():
27 #print "restore alias",k,v # dbg
28 #self.alias_table[k] = v
29 ip.alias_manager.define_alias(k,v)
30 else:
31 ip.alias_manager.define_alias(alias, staliases[alias])
29 32
30 33
31 34 def refresh_variables(ip):
32 35 db = ip.db
33 36 for key in db.keys('autorestore/*'):
34 37 # strip autorestore
35 38 justkey = os.path.basename(key)
36 39 try:
37 40 obj = db[key]
38 41 except KeyError:
39 42 print("Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey)
40 43 print("The error was:", sys.exc_info()[0])
41 44 else:
42 45 #print "restored",justkey,"=",obj #dbg
43 46 ip.user_ns[justkey] = obj
44 47
45 48
46 49 def restore_dhist(ip):
47 50 ip.user_ns['_dh'] = ip.db.get('dhist',[])
48 51
49 52
50 53 def restore_data(ip):
51 54 refresh_variables(ip)
52 55 restore_aliases(ip)
53 56 restore_dhist(ip)
54 57
55 58
56 59 @magics_class
57 60 class StoreMagics(Magics):
58 61 """Lightweight persistence for python variables.
59 62
60 63 Provides the %store magic."""
61
64
62 65 autorestore = Bool(False, help=
63 66 """If True, any %store-d variables will be automatically restored
64 67 when IPython starts.
65 68 """
66 69 ).tag(config=True)
67
70
68 71 def __init__(self, shell):
69 72 super(StoreMagics, self).__init__(shell=shell)
70 73 self.shell.configurables.append(self)
71 74 if self.autorestore:
72 75 restore_data(self.shell)
73 76
74 77 @line_magic
75 78 def store(self, parameter_s=''):
76 79 """Lightweight persistence for python variables.
77 80
78 81 Example::
79 82
80 83 In [1]: l = ['hello',10,'world']
81 84 In [2]: %store l
82 85 In [3]: exit
83 86
84 87 (IPython session is closed and started again...)
85 88
86 89 ville@badger:~$ ipython
87 90 In [1]: l
88 91 NameError: name 'l' is not defined
89 92 In [2]: %store -r
90 93 In [3]: l
91 94 Out[3]: ['hello', 10, 'world']
92 95
93 96 Usage:
94 97
95 98 * ``%store`` - Show list of all variables and their current
96 99 values
97 * ``%store spam`` - Store the *current* value of the variable spam
98 to disk
100 * ``%store spam bar`` - Store the *current* value of the variables spam
101 and bar to disk
99 102 * ``%store -d spam`` - Remove the variable and its value from storage
100 103 * ``%store -z`` - Remove all variables from storage
101 * ``%store -r`` - Refresh all variables from store (overwrite
102 current vals)
103 * ``%store -r spam bar`` - Refresh specified variables from store
104 * ``%store -r`` - Refresh all variables, aliases and directory history
105 from store (overwrite current vals)
106 * ``%store -r spam bar`` - Refresh specified variables and aliases from store
104 107 (delete current val)
105 108 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
106 109 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
107 110
108 111 It should be noted that if you change the value of a variable, you
109 112 need to %store it again if you want to persist the new value.
110 113
111 114 Note also that the variables will need to be pickleable; most basic
112 115 python types can be safely %store'd.
113 116
114 117 Also aliases can be %store'd across sessions.
115 118 To remove an alias from the storage, use the %unalias magic.
116 119 """
117 120
118 121 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
119 args = argsl.split(None,1)
122 args = argsl.split()
120 123 ip = self.shell
121 124 db = ip.db
122 125 # delete
123 126 if 'd' in opts:
124 127 try:
125 128 todel = args[0]
126 129 except IndexError:
127 130 raise UsageError('You must provide the variable to forget')
128 131 else:
129 132 try:
130 133 del db['autorestore/' + todel]
131 134 except:
132 135 raise UsageError("Can't delete variable '%s'" % todel)
133 136 # reset
134 137 elif 'z' in opts:
135 138 for k in db.keys('autorestore/*'):
136 139 del db[k]
137 140
138 141 elif 'r' in opts:
139 142 if args:
140 143 for arg in args:
141 144 try:
142 145 obj = db['autorestore/' + arg]
143 146 except KeyError:
144 print("no stored variable %s" % arg)
147 try:
148 restore_aliases(ip, alias=arg)
149 except KeyError:
150 print("no stored variable or alias %s" % arg)
145 151 else:
146 152 ip.user_ns[arg] = obj
147 153 else:
148 154 restore_data(ip)
149 155
150 156 # run without arguments -> list variables & values
151 157 elif not args:
152 158 vars = db.keys('autorestore/*')
153 159 vars.sort()
154 160 if vars:
155 161 size = max(map(len, vars))
156 162 else:
157 163 size = 0
158 164
159 165 print('Stored variables and their in-db values:')
160 166 fmt = '%-'+str(size)+'s -> %s'
161 167 get = db.get
162 168 for var in vars:
163 169 justkey = os.path.basename(var)
164 170 # print 30 first characters from every var
165 171 print(fmt % (justkey, repr(get(var, '<unavailable>'))[:50]))
166 172
167 173 # default action - store the variable
168 174 else:
169 175 # %store foo >file.txt or >>file.txt
170 176 if len(args) > 1 and args[1].startswith('>'):
171 177 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
172 178 if args[1].startswith('>>'):
173 179 fil = open(fnam, 'a')
174 180 else:
175 181 fil = open(fnam, 'w')
176 182 with fil:
177 183 obj = ip.ev(args[0])
178 184 print("Writing '%s' (%s) to file '%s'." % (args[0],
179 185 obj.__class__.__name__, fnam))
180 186
181 187 if not isinstance (obj, str):
182 188 from pprint import pprint
183 189 pprint(obj, fil)
184 190 else:
185 191 fil.write(obj)
186 192 if not obj.endswith('\n'):
187 193 fil.write('\n')
188 194
189 195 return
190 196
191 197 # %store foo
192 try:
193 obj = ip.user_ns[args[0]]
194 except KeyError:
195 # it might be an alias
196 name = args[0]
198 for arg in args:
197 199 try:
198 cmd = ip.alias_manager.retrieve_alias(name)
199 except ValueError:
200 raise UsageError("Unknown variable '%s'" % name)
201
202 staliases = db.get('stored_aliases',{})
203 staliases[name] = cmd
204 db['stored_aliases'] = staliases
205 print("Alias stored: %s (%s)" % (name, cmd))
206 return
207
208 else:
209 modname = getattr(inspect.getmodule(obj), '__name__', '')
210 if modname == '__main__':
211 print(textwrap.dedent("""\
212 Warning:%s is %s
213 Proper storage of interactively declared classes (or instances
214 of those classes) is not possible! Only instances
215 of classes in real modules on file system can be %%store'd.
216 """ % (args[0], obj) ))
200 obj = ip.user_ns[arg]
201 except KeyError:
202 # it might be an alias
203 name = arg
204 try:
205 cmd = ip.alias_manager.retrieve_alias(name)
206 except ValueError:
207 raise UsageError("Unknown variable '%s'" % name)
208
209 staliases = db.get('stored_aliases',{})
210 staliases[name] = cmd
211 db['stored_aliases'] = staliases
212 print("Alias stored: %s (%s)" % (name, cmd))
217 213 return
218 #pickled = pickle.dumps(obj)
219 db[ 'autorestore/' + args[0] ] = obj
220 print("Stored '%s' (%s)" % (args[0], obj.__class__.__name__))
214
215 else:
216 modname = getattr(inspect.getmodule(obj), '__name__', '')
217 if modname == '__main__':
218 print(textwrap.dedent("""\
219 Warning:%s is %s
220 Proper storage of interactively declared classes (or instances
221 of those classes) is not possible! Only instances
222 of classes in real modules on file system can be %%store'd.
223 """ % (arg, obj) ))
224 return
225 #pickled = pickle.dumps(obj)
226 db[ 'autorestore/' + arg ] = obj
227 print("Stored '%s' (%s)" % (arg, obj.__class__.__name__))
221 228
222 229
223 230 def load_ipython_extension(ip):
224 231 """Load the extension in IPython."""
225 232 ip.register_magics(StoreMagics)
226
233
@@ -1,53 +1,66 b''
1 1 import tempfile, os
2 2
3 3 from traitlets.config.loader import Config
4 4 import nose.tools as nt
5 5
6 6
7 7 def setup_module():
8 8 ip.magic('load_ext storemagic')
9 9
10 10 def test_store_restore():
11 11 assert 'bar' not in ip.user_ns, "Error: some other test leaked `bar` in user_ns"
12 12 assert 'foo' not in ip.user_ns, "Error: some other test leaked `foo` in user_ns"
13 assert 'foobar' not in ip.user_ns, "Error: some other test leaked `foobar` in user_ns"
14 assert 'foobaz' not in ip.user_ns, "Error: some other test leaked `foobaz` in user_ns"
13 15 ip.user_ns['foo'] = 78
14 16 ip.magic('alias bar echo "hello"')
17 ip.user_ns['foobar'] = 79
18 ip.user_ns['foobaz'] = '80'
15 19 tmpd = tempfile.mkdtemp()
16 20 ip.magic('cd ' + tmpd)
17 21 ip.magic('store foo')
18 22 ip.magic('store bar')
19
23 ip.magic('store foobar foobaz')
24
20 25 # Check storing
21 26 nt.assert_equal(ip.db['autorestore/foo'], 78)
22 27 nt.assert_in('bar', ip.db['stored_aliases'])
23
28 nt.assert_equal(ip.db['autorestore/foobar'], 79)
29 nt.assert_equal(ip.db['autorestore/foobaz'], '80')
30
24 31 # Remove those items
25 32 ip.user_ns.pop('foo', None)
33 ip.user_ns.pop('foobar', None)
34 ip.user_ns.pop('foobaz', None)
26 35 ip.alias_manager.undefine_alias('bar')
27 36 ip.magic('cd -')
28 37 ip.user_ns['_dh'][:] = []
29
38
30 39 # Check restoring
31 ip.magic('store -r')
40 ip.magic('store -r foo bar foobar foobaz')
32 41 nt.assert_equal(ip.user_ns['foo'], 78)
33 42 assert ip.alias_manager.is_alias('bar')
43 nt.assert_equal(ip.user_ns['foobar'], 79)
44 nt.assert_equal(ip.user_ns['foobaz'], '80')
45
46 ip.magic('store -r') # restores _dh too
34 47 nt.assert_in(os.path.realpath(tmpd), ip.user_ns['_dh'])
35
48
36 49 os.rmdir(tmpd)
37 50
38 51 def test_autorestore():
39 52 ip.user_ns['foo'] = 95
40 53 ip.magic('store foo')
41 54 del ip.user_ns['foo']
42 55 c = Config()
43 56 c.StoreMagics.autorestore = False
44 57 orig_config = ip.config
45 58 try:
46 59 ip.config = c
47 60 ip.extension_manager.reload_extension('storemagic')
48 61 nt.assert_not_in('foo', ip.user_ns)
49 62 c.StoreMagics.autorestore = True
50 63 ip.extension_manager.reload_extension('storemagic')
51 64 nt.assert_equal(ip.user_ns['foo'], 95)
52 65 finally:
53 66 ip.config = orig_config
General Comments 0
You need to be logged in to leave comments. Login now