pspersistence.py
183 lines
| 5.7 KiB
| text/x-python
|
PythonLexer
vivainio
|
r166 | # -*- coding: utf-8 -*- | ||
""" | ||||
%store magic for lightweight persistence. | ||||
Stores variables, aliases etc. in PickleShare database. | ||||
""" | ||||
Brian Granger
|
r2027 | from IPython.core import ipapi | ||
Brian Granger
|
r2205 | from IPython.core.error import TryNext, UsageError | ||
Brian Granger
|
r2027 | ip = ipapi.get() | ||
vivainio
|
r165 | |||
import pickleshare | ||||
vivainio
|
r246 | import inspect,pickle,os,sys,textwrap | ||
Brian Granger
|
r2020 | from IPython.core.fakemodule import FakeModule | ||
vivainio
|
r165 | |||
vivainio
|
r166 | def restore_aliases(self): | ||
ip = self.getapi() | ||||
fperez
|
r284 | staliases = ip.db.get('stored_aliases', {}) | ||
vivainio
|
r166 | for k,v in staliases.items(): | ||
#print "restore alias",k,v # dbg | ||||
vivainio
|
r783 | #self.alias_table[k] = v | ||
Brian Granger
|
r2205 | ip.define_alias(k,v) | ||
vivainio
|
r166 | |||
vivainio
|
r165 | def refresh_variables(ip): | ||
fperez
|
r284 | db = ip.db | ||
vivainio
|
r165 | for key in db.keys('autorestore/*'): | ||
# strip autorestore | ||||
justkey = os.path.basename(key) | ||||
try: | ||||
obj = db[key] | ||||
except KeyError: | ||||
print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey | ||||
print "The error was:",sys.exc_info()[0] | ||||
else: | ||||
#print "restored",justkey,"=",obj #dbg | ||||
fperez
|
r284 | ip.user_ns[justkey] = obj | ||
vivainio
|
r165 | |||
vivainio
|
r713 | def restore_dhist(ip): | ||
db = ip.db | ||||
ip.user_ns['_dh'] = db.get('dhist',[]) | ||||
vivainio
|
r165 | def restore_data(self): | ||
ip = self.getapi() | ||||
refresh_variables(ip) | ||||
vivainio
|
r166 | restore_aliases(self) | ||
vivainio
|
r713 | restore_dhist(self) | ||
Brian Granger
|
r2205 | raise TryNext | ||
vivainio
|
r165 | |||
ip.set_hook('late_startup_hook', restore_data) | ||||
def magic_store(self, parameter_s=''): | ||||
"""Lightweight persistence for python variables. | ||||
Example: | ||||
ville@badger[~]|1> A = ['hello',10,'world']\\ | ||||
ville@badger[~]|2> %store A\\ | ||||
ville@badger[~]|3> Exit | ||||
(IPython session is closed and started again...) | ||||
ville@badger:~$ ipython -p pysh\\ | ||||
ville@badger[~]|1> print A | ||||
['hello', 10, 'world'] | ||||
Usage: | ||||
%store - Show list of all variables and their current values\\ | ||||
%store <var> - Store the *current* value of the variable to disk\\ | ||||
%store -d <var> - Remove the variable and its value from storage\\ | ||||
%store -z - Remove all variables from storage\\ | ||||
%store -r - Refresh all variables from store (delete current vals)\\ | ||||
%store foo >a.txt - Store value of foo to new file a.txt\\ | ||||
%store foo >>a.txt - Append value of foo to file a.txt\\ | ||||
It should be noted that if you change the value of a variable, you | ||||
need to %store it again if you want to persist the new value. | ||||
Note also that the variables will need to be pickleable; most basic | ||||
python types can be safely %stored. | ||||
vivainio
|
r476 | |||
Also aliases can be %store'd across sessions. | ||||
vivainio
|
r165 | """ | ||
opts,argsl = self.parse_options(parameter_s,'drz',mode='string') | ||||
args = argsl.split(None,1) | ||||
ip = self.getapi() | ||||
fperez
|
r284 | db = ip.db | ||
vivainio
|
r165 | # delete | ||
if opts.has_key('d'): | ||||
try: | ||||
todel = args[0] | ||||
except IndexError: | ||||
Ville M. Vainio
|
r1223 | raise UsageError('You must provide the variable to forget') | ||
vivainio
|
r165 | else: | ||
try: | ||||
vivainio
|
r166 | del db['autorestore/' + todel] | ||
vivainio
|
r165 | except: | ||
Ville M. Vainio
|
r1223 | raise UsageError("Can't delete variable '%s'" % todel) | ||
vivainio
|
r165 | # reset | ||
elif opts.has_key('z'): | ||||
vivainio
|
r166 | for k in db.keys('autorestore/*'): | ||
del db[k] | ||||
vivainio
|
r165 | |||
elif opts.has_key('r'): | ||||
refresh_variables(ip) | ||||
# run without arguments -> list variables & values | ||||
elif not args: | ||||
vars = self.db.keys('autorestore/*') | ||||
vars.sort() | ||||
if vars: | ||||
size = max(map(len,vars)) | ||||
else: | ||||
size = 0 | ||||
print 'Stored variables and their in-db values:' | ||||
fmt = '%-'+str(size)+'s -> %s' | ||||
vivainio
|
r166 | get = db.get | ||
vivainio
|
r165 | for var in vars: | ||
justkey = os.path.basename(var) | ||||
# print 30 first characters from every var | ||||
print fmt % (justkey,repr(get(var,'<unavailable>'))[:50]) | ||||
# default action - store the variable | ||||
else: | ||||
# %store foo >file.txt or >>file.txt | ||||
if len(args) > 1 and args[1].startswith('>'): | ||||
fnam = os.path.expanduser(args[1].lstrip('>').lstrip()) | ||||
if args[1].startswith('>>'): | ||||
fil = open(fnam,'a') | ||||
else: | ||||
fil = open(fnam,'w') | ||||
obj = ip.ev(args[0]) | ||||
print "Writing '%s' (%s) to file '%s'." % (args[0], | ||||
obj.__class__.__name__, fnam) | ||||
if not isinstance (obj,basestring): | ||||
vivainio
|
r243 | from pprint import pprint | ||
vivainio
|
r165 | pprint(obj,fil) | ||
else: | ||||
fil.write(obj) | ||||
if not obj.endswith('\n'): | ||||
fil.write('\n') | ||||
fil.close() | ||||
return | ||||
# %store foo | ||||
vivainio
|
r166 | try: | ||
fperez
|
r284 | obj = ip.user_ns[args[0]] | ||
vivainio
|
r243 | except KeyError: | ||
vivainio
|
r166 | # it might be an alias | ||
Brian Granger
|
r2245 | # This needs to be refactored to use the new AliasManager stuff. | ||
vivainio
|
r166 | if args[0] in self.alias_table: | ||
staliases = db.get('stored_aliases',{}) | ||||
staliases[ args[0] ] = self.alias_table[ args[0] ] | ||||
db['stored_aliases'] = staliases | ||||
print "Alias stored:", args[0], self.alias_table[ args[0] ] | ||||
return | ||||
vivainio
|
r243 | else: | ||
Ville M. Vainio
|
r1223 | raise UsageError("Unknown variable '%s'" % args[0]) | ||
vivainio
|
r243 | |||
vivainio
|
r166 | else: | ||
if isinstance(inspect.getmodule(obj), FakeModule): | ||||
print textwrap.dedent("""\ | ||||
Warning:%s is %s | ||||
Proper storage of interactively declared classes (or instances | ||||
of those classes) is not possible! Only instances | ||||
of classes in real modules on file system can be %%store'd. | ||||
""" % (args[0], obj) ) | ||||
return | ||||
#pickled = pickle.dumps(obj) | ||||
self.db[ 'autorestore/' + args[0] ] = obj | ||||
print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__) | ||||
vivainio
|
r165 | |||
Brian Granger
|
r2205 | ip.define_magic('store',magic_store) | ||