##// END OF EJS Templates
Grand Persistence Overhaul, featuring PickleShare. startup...
vivainio -
Show More
@@ -0,0 +1,267 b''
1 #!/usr/bin/env python
2
3 """ PickleShare - a small 'shelve' like datastore with concurrency support
4
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
6 shelve, many processes can access the database simultaneously. Changing a
7 value in database is immediately visible to other processes accessing the
8 same database.
9
10 Concurrency is possible because the values are stored in separate files. Hence
11 the "database" is a directory where *all* files are governed by PickleShare.
12
13 Example usage::
14
15 from pickleshare import *
16 db = PickleShareDB('~/testpickleshare')
17 db.clear()
18 print "Should be empty:",db.items()
19 db['hello'] = 15
20 db['aku ankka'] = [1,2,313]
21 db['paths/are/ok/key'] = [1,(5,46)]
22 print db.keys()
23 del db['aku ankka']
24
25 This module is certainly not ZODB, but can be used for low-load
26 (non-mission-critical) situations where tiny code size trumps the
27 advanced features of a "real" object database.
28
29 Installation guide: easy_install pickleshare
30
31 Author: Ville Vainio <vivainio@gmail.com>
32 License: MIT open source license.
33
34 """
35
36 from path import path as Path
37 import os,stat,time
38 import cPickle as pickle
39 import UserDict
40 import warnings
41 import glob
42
43 class PickleShareDB(UserDict.DictMixin):
44 """ The main 'connection' object for PickleShare database """
45 def __init__(self,root):
46 """ Return a db object that will manage the specied directory"""
47 self.root = Path(root).expanduser().abspath()
48 if not self.root.isdir():
49 self.root.makedirs()
50 # cache has { 'key' : (obj, orig_mod_time) }
51 self.cache = {}
52
53 def __getitem__(self,key):
54 """ db['key'] reading """
55 fil = self.root / key
56 try:
57 mtime = (fil.stat()[stat.ST_MTIME])
58 except OSError:
59 raise KeyError(key)
60
61 if fil in self.cache and mtime == self.cache[fil][1]:
62 return self.cache[fil][0]
63 try:
64 # The cached item has expired, need to read
65 obj = pickle.load(fil.open())
66 except:
67 raise KeyError(key)
68
69 self.cache[fil] = (obj,mtime)
70 return obj
71
72 def __setitem__(self,key,value):
73 """ db['key'] = 5 """
74 fil = self.root / key
75 parent = fil.parent
76 if parent and not parent.isdir():
77 parent.makedirs()
78 pickled = pickle.dump(value,fil.open('w'))
79 try:
80 self.cache[fil] = (value,fil.mtime)
81 except OSError,e:
82 if e.errno != 2:
83 raise
84
85 def __delitem__(self,key):
86 """ del db["key"] """
87 fil = self.root / key
88 self.cache.pop(fil,None)
89 try:
90 fil.remove()
91 except OSError:
92 # notfound and permission denied are ok - we
93 # lost, the other process wins the conflict
94 pass
95
96 def _normalized(self, p):
97 """ Make a key suitable for user's eyes """
98 return str(self.root.relpathto(p)).replace('\\','/')
99
100 def keys(self, globpat = None):
101 """ All keys in DB, or all keys matching a glob"""
102
103 if globpat is None:
104 files = self.root.walkfiles()
105 else:
106 files = [Path(p) for p in glob.glob(self.root/globpat)]
107 return [self._normalized(p) for p in files if p.isfile()]
108
109 def uncache(self,*items):
110 """ Removes all, or specified items from cache
111
112 Use this after reading a large amount of large objects
113 to free up memory, when you won't be needing the objects
114 for a while.
115
116 """
117 if not items:
118 self.cache = {}
119 for it in items:
120 self.cache.pop(it,None)
121
122 def waitget(self,key, maxwaittime = 60 ):
123 """ Wait (poll) for a key to get a value
124
125 Will wait for `maxwaittime` seconds before raising a KeyError.
126 The call exits normally if the `key` field in db gets a value
127 within the timeout period.
128
129 Use this for synchronizing different processes or for ensuring
130 that an unfortunately timed "db['key'] = newvalue" operation
131 in another process (which causes all 'get' operation to cause a
132 KeyError for the duration of pickling) won't screw up your program
133 logic.
134 """
135
136 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
137 tries = 0
138 waited = 0
139 while 1:
140 try:
141 val = self[key]
142 return val
143 except KeyError:
144 pass
145
146 if waited > maxwaittime:
147 raise KeyError(key)
148
149 time.sleep(wtimes[tries])
150 waited+=wtimes[tries]
151 if tries < len(wtimes) -1:
152 tries+=1
153
154 def getlink(self,folder):
155 """ Get a convenient link for accessing items """
156 return PickleShareLink(self, folder)
157
158 def __repr__(self):
159 return "PickleShareDB('%s')" % self.root
160
161
162
163 class PickleShareLink:
164 """ A shortdand for accessing nested PickleShare data conveniently.
165
166 Created through PickleShareDB.getlink(), example::
167
168 lnk = db.getlink('myobjects/test')
169 lnk.foo = 2
170 lnk.bar = lnk.foo + 5
171
172 """
173 def __init__(self, db, keydir ):
174 self.__dict__.update(locals())
175
176 def __getattr__(self,key):
177 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
178 def __setattr__(self,key,val):
179 self.db[self.keydir+'/' + key] = val
180 def __repr__(self):
181 db = self.__dict__['db']
182 keys = db.keys( self.__dict__['keydir'] +"/*")
183 return "<PickleShareLink '%s': %s>" % (
184 self.__dict__['keydir'],
185 ";".join([Path(k).basename() for k in keys]))
186
187
188 def test():
189 db = PickleShareDB('~/testpickleshare')
190 db.clear()
191 print "Should be empty:",db.items()
192 db['hello'] = 15
193 db['aku ankka'] = [1,2,313]
194 db['paths/nest/ok/keyname'] = [1,(5,46)]
195 print db.keys()
196 print db.keys('paths/nest/ok/k*')
197 print dict(db) # snapsot of whole db
198 db.uncache() # frees memory, causes re-reads later
199
200 # shorthand for accessing deeply nested files
201 lnk = db.getlink('myobjects/test')
202 lnk.foo = 2
203 lnk.bar = lnk.foo + 5
204 print lnk.bar # 7
205
206 def stress():
207 db = PickleShareDB('~/fsdbtest')
208 import time,sys
209 for i in range(1000):
210 for j in range(300):
211 if i % 15 == 0 and i < 200:
212 if str(j) in db:
213 del db[str(j)]
214 continue
215
216 if j%33 == 0:
217 time.sleep(0.02)
218
219 db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
220 print i,
221 sys.stdout.flush()
222 if i % 10 == 0:
223 db.uncache()
224
225 def main():
226 import textwrap
227 usage = textwrap.dedent("""\
228 pickleshare - manage PickleShare databases
229
230 Usage:
231
232 pickleshare dump /path/to/db > dump.txt
233 pickleshare load /path/to/db < dump.txt
234 pickleshare test /path/to/db
235 """)
236 DB = PickleShareDB
237 import sys
238 if len(sys.argv) < 2:
239 print usage
240 return
241
242 cmd = sys.argv[1]
243 args = sys.argv[2:]
244 if cmd == 'dump':
245 if not args: args= ['.']
246 db = DB(args[0])
247 import pprint
248 pprint.pprint(db.items())
249 elif cmd == 'load':
250 cont = sys.stdin.read()
251 db = DB(args[0])
252 data = eval(cont)
253 db.clear()
254 for k,v in db.items():
255 db[k] = v
256 elif cmd == 'testwait':
257 db = DB(args[0])
258 db.clear()
259 print db.waitget('250')
260 elif cmd == 'test':
261 test()
262 stress()
263
264 if __name__== "__main__":
265 main()
266
267 No newline at end of file
@@ -0,0 +1,149 b''
1 import IPython.ipapi
2 ip = IPython.ipapi.get()
3
4 import pickleshare
5
6 import inspect,pickle,os,textwrap
7 from IPython.FakeModule import FakeModule
8
9 def refresh_variables(ip):
10 db = ip.getdb()
11 for key in db.keys('autorestore/*'):
12 # strip autorestore
13 justkey = os.path.basename(key)
14 try:
15 obj = db[key]
16 except KeyError:
17 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
18 print "The error was:",sys.exc_info()[0]
19 else:
20 #print "restored",justkey,"=",obj #dbg
21 ip.user_ns()[justkey] = obj
22
23
24
25 def restore_data(self):
26 #o = ip.options()
27 #self.db = pickleshare.PickleShareDB(o.ipythondir + "/db")
28 #print "restoring ps data" # dbg
29
30 ip = self.getapi()
31 refresh_variables(ip)
32 raise IPython.ipapi.TryNext
33
34
35 ip.set_hook('late_startup_hook', restore_data)
36
37 def magic_store(self, parameter_s=''):
38 """Lightweight persistence for python variables.
39
40 Example:
41
42 ville@badger[~]|1> A = ['hello',10,'world']\\
43 ville@badger[~]|2> %store A\\
44 ville@badger[~]|3> Exit
45
46 (IPython session is closed and started again...)
47
48 ville@badger:~$ ipython -p pysh\\
49 ville@badger[~]|1> print A
50
51 ['hello', 10, 'world']
52
53 Usage:
54
55 %store - Show list of all variables and their current values\\
56 %store <var> - Store the *current* value of the variable to disk\\
57 %store -d <var> - Remove the variable and its value from storage\\
58 %store -z - Remove all variables from storage\\
59 %store -r - Refresh all variables from store (delete current vals)\\
60 %store foo >a.txt - Store value of foo to new file a.txt\\
61 %store foo >>a.txt - Append value of foo to file a.txt\\
62
63 It should be noted that if you change the value of a variable, you
64 need to %store it again if you want to persist the new value.
65
66 Note also that the variables will need to be pickleable; most basic
67 python types can be safely %stored.
68 """
69
70 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
71 args = argsl.split(None,1)
72 ip = self.getapi()
73 # delete
74 if opts.has_key('d'):
75 try:
76 todel = args[0]
77 except IndexError:
78 error('You must provide the variable to forget')
79 else:
80 try:
81 del self.db['autorestore/' + todel]
82 except:
83 error("Can't delete variable '%s'" % todel)
84 # reset
85 elif opts.has_key('z'):
86 for k in self.db.keys('autorestore/*'):
87 del self.db[k]
88
89 elif opts.has_key('r'):
90 refresh_variables(ip)
91
92
93 # run without arguments -> list variables & values
94 elif not args:
95 vars = self.db.keys('autorestore/*')
96 vars.sort()
97 if vars:
98 size = max(map(len,vars))
99 else:
100 size = 0
101
102 print 'Stored variables and their in-db values:'
103 fmt = '%-'+str(size)+'s -> %s'
104 get = self.db.get
105 for var in vars:
106 justkey = os.path.basename(var)
107 # print 30 first characters from every var
108 print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
109
110 # default action - store the variable
111 else:
112 # %store foo >file.txt or >>file.txt
113 if len(args) > 1 and args[1].startswith('>'):
114 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
115 if args[1].startswith('>>'):
116 fil = open(fnam,'a')
117 else:
118 fil = open(fnam,'w')
119 obj = ip.ev(args[0])
120 print "Writing '%s' (%s) to file '%s'." % (args[0],
121 obj.__class__.__name__, fnam)
122
123
124 if not isinstance (obj,basestring):
125 pprint(obj,fil)
126 else:
127 fil.write(obj)
128 if not obj.endswith('\n'):
129 fil.write('\n')
130
131 fil.close()
132 return
133
134 # %store foo
135 obj = ip.ev(args[0])
136 if isinstance(inspect.getmodule(obj), FakeModule):
137 print textwrap.dedent("""\
138 Warning:%s is %s
139 Proper storage of interactively declared classes (or instances
140 of those classes) is not possible! Only instances
141 of classes in real modules on file system can be %%store'd.
142 """ % (args[0], obj) )
143 return
144 #pickled = pickle.dumps(obj)
145 self.db[ 'autorestore/' + args[0] ] = obj
146 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
147
148 ip.expose_magic('store',magic_store)
149 No newline at end of file
@@ -16,3 +16,4 b' import sys'
16
16
17 import ext_rehashdir # %rehashdir magic
17 import ext_rehashdir # %rehashdir magic
18 import ext_rescapture # var = !ls and var = %magic
18 import ext_rescapture # var = !ls and var = %magic
19 import pspersistence # %store magic No newline at end of file
@@ -1,7 +1,7 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3
3
4 $Id: Magic.py 1099 2006-01-29 21:05:57Z vivainio $"""
4 $Id: Magic.py 1107 2006-01-30 19:02:20Z vivainio $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
@@ -2301,7 +2301,7 b' Defaulting color scheme to \'NoColor\'"""'
2301 !command runs is immediately discarded after executing 'command'."""
2301 !command runs is immediately discarded after executing 'command'."""
2302
2302
2303 parameter_s = parameter_s.strip()
2303 parameter_s = parameter_s.strip()
2304 bkms = self.shell.persist.get("bookmarks",{})
2304 #bkms = self.shell.persist.get("bookmarks",{})
2305
2305
2306 numcd = re.match(r'(-)(\d+)$',parameter_s)
2306 numcd = re.match(r'(-)(\d+)$',parameter_s)
2307 # jump in directory history by number
2307 # jump in directory history by number
@@ -2326,18 +2326,19 b' Defaulting color scheme to \'NoColor\'"""'
2326 except IndexError:
2326 except IndexError:
2327 print 'No previous directory to change to.'
2327 print 'No previous directory to change to.'
2328 return
2328 return
2329 # jump to bookmark
2329 # jump to bookmark if needed
2330 elif opts.has_key('b') or (bkms.has_key(ps) and not os.path.isdir(ps)):
2330 else:
2331 if not os.path.isdir(ps) or opts.has_key('b'):
2332 bkms = self.db.get('bookmarks', {})
2333
2331 if bkms.has_key(ps):
2334 if bkms.has_key(ps):
2332 target = bkms[ps]
2335 target = bkms[ps]
2333 print '(bookmark:%s) -> %s' % (ps,target)
2336 print '(bookmark:%s) -> %s' % (ps,target)
2334 ps = target
2337 ps = target
2335 else:
2338 else:
2336 if bkms:
2339 if opts.has_key('b'):
2337 error("Bookmark '%s' not found. "
2340 error("Bookmark '%s' not found. "
2338 "Use '%%bookmark -l' to see your bookmarks." % ps)
2341 "Use '%%bookmark -l' to see your bookmarks." % ps)
2339 else:
2340 print "Bookmarks not set - use %bookmark <bookmarkname>"
2341 return
2342 return
2342
2343
2343 # at this point ps should point to the target dir
2344 # at this point ps should point to the target dir
@@ -2634,112 +2635,6 b' Defaulting color scheme to \'NoColor\'"""'
2634
2635
2635 self.shell.jobs.new(parameter_s,self.shell.user_ns)
2636 self.shell.jobs.new(parameter_s,self.shell.user_ns)
2636
2637
2637 def magic_store(self, parameter_s=''):
2638 """Lightweight persistence for python variables.
2639
2640 Example:
2641
2642 ville@badger[~]|1> A = ['hello',10,'world']\\
2643 ville@badger[~]|2> %store A\\
2644 ville@badger[~]|3> Exit
2645
2646 (IPython session is closed and started again...)
2647
2648 ville@badger:~$ ipython -p pysh\\
2649 ville@badger[~]|1> print A
2650
2651 ['hello', 10, 'world']
2652
2653 Usage:
2654
2655 %store - Show list of all variables and their current values\\
2656 %store <var> - Store the *current* value of the variable to disk\\
2657 %store -d <var> - Remove the variable and its value from storage\\
2658 %store -r - Remove all variables from storage\\
2659 %store foo >a.txt - Store value of foo to new file a.txt\\
2660 %store foo >>a.txt - Append value of foo to file a.txt\\
2661
2662 It should be noted that if you change the value of a variable, you
2663 need to %store it again if you want to persist the new value.
2664
2665 Note also that the variables will need to be pickleable; most basic
2666 python types can be safely %stored.
2667 """
2668
2669 opts,argsl = self.parse_options(parameter_s,'dr',mode='string')
2670 args = argsl.split(None,1)
2671 ip = self.getapi()
2672 # delete
2673 if opts.has_key('d'):
2674 try:
2675 todel = args[0]
2676 except IndexError:
2677 error('You must provide the variable to forget')
2678 else:
2679 try:
2680 del self.shell.persist['S:' + todel]
2681 except:
2682 error("Can't delete variable '%s'" % todel)
2683 # reset
2684 elif opts.has_key('r'):
2685 for k in self.shell.persist.keys():
2686 if k.startswith('S:'):
2687 del self.shell.persist[k]
2688
2689 # run without arguments -> list variables & values
2690 elif not args:
2691 vars = [v[2:] for v in self.shell.persist.keys()
2692 if v.startswith('S:')]
2693 vars.sort()
2694 if vars:
2695 size = max(map(len,vars))
2696 else:
2697 size = 0
2698
2699 print 'Stored variables and their in-memory values:'
2700 fmt = '%-'+str(size)+'s -> %s'
2701 get = self.shell.user_ns.get
2702 for var in vars:
2703 # print 30 first characters from every var
2704 print fmt % (var,repr(get(var,'<unavailable>'))[:50])
2705
2706 # default action - store the variable
2707 else:
2708 # %store foo >file.txt or >>file.txt
2709 if len(args) > 1 and args[1].startswith('>'):
2710 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
2711 if args[1].startswith('>>'):
2712 fil = open(fnam,'a')
2713 else:
2714 fil = open(fnam,'w')
2715 obj = ip.ev(args[0])
2716 print "Writing '%s' (%s) to file '%s'." % (args[0],
2717 obj.__class__.__name__, fnam)
2718
2719
2720 if not isinstance (obj,basestring):
2721 pprint(obj,fil)
2722 else:
2723 fil.write(obj)
2724 if not obj.endswith('\n'):
2725 fil.write('\n')
2726
2727 fil.close()
2728 return
2729
2730 # %store foo
2731 obj = self.shell.user_ns[args[0] ]
2732 if isinstance(inspect.getmodule(obj), FakeModule):
2733 print textwrap.dedent("""\
2734 Warning:%s is %s
2735 Proper storage of interactively declared classes (or instances
2736 of those classes) is not possible! Only instances
2737 of classes in real modules on file system can be %%store'd.
2738 """ % (args[0], obj) )
2739 return
2740 pickled = pickle.dumps(obj)
2741 self.shell.persist[ 'S:' + args[0] ] = pickled
2742 print "Stored '%s' (%s, %d bytes)" % (args[0], obj.__class__.__name__,len(pickled))
2743
2638
2744 def magic_bookmark(self, parameter_s=''):
2639 def magic_bookmark(self, parameter_s=''):
2745 """Manage IPython's bookmark system.
2640 """Manage IPython's bookmark system.
@@ -2763,7 +2658,7 b' Defaulting color scheme to \'NoColor\'"""'
2763 error('You can only give at most two arguments')
2658 error('You can only give at most two arguments')
2764 return
2659 return
2765
2660
2766 bkms = self.shell.persist.get('bookmarks',{})
2661 bkms = self.db.get('bookmarks',{})
2767
2662
2768 if opts.has_key('d'):
2663 if opts.has_key('d'):
2769 try:
2664 try:
@@ -2795,7 +2690,7 b' Defaulting color scheme to \'NoColor\'"""'
2795 bkms[args[0]] = os.getcwd()
2690 bkms[args[0]] = os.getcwd()
2796 elif len(args)==2:
2691 elif len(args)==2:
2797 bkms[args[0]] = args[1]
2692 bkms[args[0]] = args[1]
2798 self.shell.persist['bookmarks'] = bkms
2693 self.db['bookmarks'] = bkms
2799
2694
2800 def magic_pycat(self, parameter_s=''):
2695 def magic_pycat(self, parameter_s=''):
2801 """Show a syntax-highlighted file through a pager.
2696 """Show a syntax-highlighted file through a pager.
@@ -32,7 +32,7 b" ip.set_hook('editor', calljed)"
32 You can then enable the functionality by doing 'import myiphooks'
32 You can then enable the functionality by doing 'import myiphooks'
33 somewhere in your configuration files or ipython command line.
33 somewhere in your configuration files or ipython command line.
34
34
35 $Id: hooks.py 1095 2006-01-28 19:43:56Z vivainio $"""
35 $Id: hooks.py 1107 2006-01-30 19:02:20Z vivainio $"""
36
36
37 #*****************************************************************************
37 #*****************************************************************************
38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
@@ -54,7 +54,7 b' from pprint import pformat'
54 # List here all the default hooks. For now it's just the editor functions
54 # List here all the default hooks. For now it's just the editor functions
55 # but over time we'll move here all the public API for user-accessible things.
55 # but over time we'll move here all the public API for user-accessible things.
56 __all__ = ['editor', 'fix_error_editor', 'result_display',
56 __all__ = ['editor', 'fix_error_editor', 'result_display',
57 'input_prefilter']
57 'input_prefilter', 'shutdown_hook', 'late_startup_hook']
58
58
59 def editor(self,filename, linenum=None):
59 def editor(self,filename, linenum=None):
60 """Open the default editor at the given filename and linenumber.
60 """Open the default editor at the given filename and linenumber.
@@ -167,3 +167,18 b' def input_prefilter(self,line):'
167 """
167 """
168 #print "attempt to rewrite",line #dbg
168 #print "attempt to rewrite",line #dbg
169 return line
169 return line
170
171 def shutdown_hook(self):
172 """ default shutdown hook
173
174 Typically, shotdown hooks should raise TryNext so all shutdown ops are done
175 """
176
177 #print "default shutdown hook ok" # dbg
178 return
179
180 def late_startup_hook(self):
181 """ Executed after ipython has been constructed and configured
182
183 """
184 #print "default startup hook ok" # dbg No newline at end of file
@@ -149,6 +149,13 b' class IPApi:'
149 """
149 """
150 return self.IP.meta
150 return self.IP.meta
151
151
152 def getdb(self):
153 """ Return a handle to persistent dict-like database
154
155 Return a PickleShareDB object.
156 """
157 return self.IP.db
158
152
159
153 def launch_new_instance(user_ns = None):
160 def launch_new_instance(user_ns = None):
154 """ Create and start a new ipython instance.
161 """ Create and start a new ipython instance.
@@ -6,7 +6,7 b' Requires Python 2.3 or newer.'
6
6
7 This file contains all the classes and helper functions specific to IPython.
7 This file contains all the classes and helper functions specific to IPython.
8
8
9 $Id: iplib.py 1102 2006-01-30 06:08:16Z fperez $
9 $Id: iplib.py 1107 2006-01-30 19:02:20Z vivainio $
10 """
10 """
11
11
12 #*****************************************************************************
12 #*****************************************************************************
@@ -58,6 +58,7 b' import sys'
58 import tempfile
58 import tempfile
59 import traceback
59 import traceback
60 import types
60 import types
61 import pickleshare
61
62
62 from pprint import pprint, pformat
63 from pprint import pprint, pformat
63
64
@@ -191,6 +192,7 b' class InteractiveShell(object,Magic):'
191 user_ns = None,user_global_ns=None,banner2='',
192 user_ns = None,user_global_ns=None,banner2='',
192 custom_exceptions=((),None),embedded=False):
193 custom_exceptions=((),None),embedded=False):
193
194
195
194 # log system
196 # log system
195 self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate')
197 self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate')
196
198
@@ -607,6 +609,7 b' class InteractiveShell(object,Magic):'
607
609
608 rc = self.rc
610 rc = self.rc
609
611
612 self.db = pickleshare.PickleShareDB(rc.ipythondir + "/db")
610 # Load readline proper
613 # Load readline proper
611 if rc.readline:
614 if rc.readline:
612 self.init_readline()
615 self.init_readline()
@@ -648,32 +651,9 b' class InteractiveShell(object,Magic):'
648 # Load user aliases
651 # Load user aliases
649 for alias in rc.alias:
652 for alias in rc.alias:
650 self.magic_alias(alias)
653 self.magic_alias(alias)
651
654 self.hooks.late_startup_hook()
652 # dynamic data that survives through sessions
653 # XXX make the filename a config option?
654 persist_base = 'persist'
655 if rc.profile:
656 persist_base += '_%s' % rc.profile
657 self.persist_fname = os.path.join(rc.ipythondir,persist_base)
658
659 try:
660 self.persist = pickle.load(file(self.persist_fname))
661 except:
662 self.persist = {}
663
664
665 for (key, value) in [(k[2:],v) for (k,v) in self.persist.items() if k.startswith('S:')]:
666 try:
667 obj = pickle.loads(value)
668 except:
669
670 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % key
671 print "The error was:",sys.exc_info()[0]
672 continue
673
655
674
656
675 self.user_ns[key] = obj
676
677 def add_builtins(self):
657 def add_builtins(self):
678 """Store ipython references into the builtin namespace.
658 """Store ipython references into the builtin namespace.
679
659
@@ -1147,10 +1127,7 b' want to merge them back into the new files.""" % locals()'
1147 pass
1127 pass
1148
1128
1149 # save the "persistent data" catch-all dictionary
1129 # save the "persistent data" catch-all dictionary
1150 try:
1130 self.hooks.shutdown_hook()
1151 pickle.dump(self.persist, open(self.persist_fname,"w"))
1152 except:
1153 print "*** ERROR *** persistent data saving failed."
1154
1131
1155 def savehist(self):
1132 def savehist(self):
1156 """Save input history to a file (via readline library)."""
1133 """Save input history to a file (via readline library)."""
@@ -1,3 +1,16 b''
1 2006-01-30 Ville Vainio <vivainio@gmail.com>
2
3 * pickleshare,pspersistence,ipapi,Magic: persistence overhaul.
4 Now %store and bookmarks work through PickleShare, meaning that
5 concurrent access is possible and all ipython sessions see the
6 same database situation all the time, instead of snapshot of
7 the situation when the session was started. Hence, %bookmark
8 results are immediately accessible from othes sessions. The database
9 is also available for use by user extensions. See:
10 http://www.python.org/pypi/pickleshare
11
12 * hooks.py: Two new hooks, 'shutdown_hook' and 'late_startup_hook'.
13
1 2006-01-29 Fernando Perez <Fernando.Perez@colorado.edu>
14 2006-01-29 Fernando Perez <Fernando.Perez@colorado.edu>
2
15
3 * IPython/iplib.py (interact): Fix that we were not catching
16 * IPython/iplib.py (interact): Fix that we were not catching
General Comments 0
You need to be logged in to leave comments. Login now