##// END OF EJS Templates
Multiple improvements to tab completion....
Multiple improvements to tab completion. I refactored the API quite a bit, to retain readline compatibility but make it more independent of readline. There's still more to do in cleaning up our init_readline() method, but now the completer objects have separate rlcomplete() and complete() methods. The former uses the quirky readline API with a state flag, while the latter is stateless, takes only text information, and is more suitable for GUIs and other frontends to call programatically. Made other minor fixes to ensure the test suite passes in full. While all this code is a bit messy, we're getting in the direction of the APIs we need in the long run.

File last commit:

r2267:928c921b
r2839:8cff4913
Show More
pspersistence.py
183 lines | 5.7 KiB | text/x-python | PythonLexer
# -*- coding: utf-8 -*-
"""
%store magic for lightweight persistence.
Stores variables, aliases etc. in PickleShare database.
"""
from IPython.core import ipapi
from IPython.core.error import TryNext, UsageError
ip = ipapi.get()
import pickleshare
import inspect,pickle,os,sys,textwrap
from IPython.core.fakemodule import FakeModule
def restore_aliases(self):
ip = self.getapi()
staliases = ip.db.get('stored_aliases', {})
for k,v in staliases.items():
#print "restore alias",k,v # dbg
#self.alias_table[k] = v
ip.define_alias(k,v)
def refresh_variables(ip):
db = ip.db
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
ip.user_ns[justkey] = obj
def restore_dhist(ip):
db = ip.db
ip.user_ns['_dh'] = db.get('dhist',[])
def restore_data(self):
ip = self.getapi()
refresh_variables(ip)
restore_aliases(self)
restore_dhist(self)
raise TryNext
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.
Also aliases can be %store'd across sessions.
"""
opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
args = argsl.split(None,1)
ip = self.getapi()
db = ip.db
# delete
if opts.has_key('d'):
try:
todel = args[0]
except IndexError:
raise UsageError('You must provide the variable to forget')
else:
try:
del db['autorestore/' + todel]
except:
raise UsageError("Can't delete variable '%s'" % todel)
# reset
elif opts.has_key('z'):
for k in db.keys('autorestore/*'):
del db[k]
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'
get = db.get
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):
from pprint import pprint
pprint(obj,fil)
else:
fil.write(obj)
if not obj.endswith('\n'):
fil.write('\n')
fil.close()
return
# %store foo
try:
obj = ip.user_ns[args[0]]
except KeyError:
# it might be an alias
# This needs to be refactored to use the new AliasManager stuff.
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
else:
raise UsageError("Unknown variable '%s'" % args[0])
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__)
ip.define_magic('store',magic_store)