storemagic.py
236 lines
| 8.0 KiB
| text/x-python
|
PythonLexer
vivainio
|
r166 | # -*- coding: utf-8 -*- | ||
""" | ||||
%store magic for lightweight persistence. | ||||
Thomas Kluyver
|
r5543 | Stores variables, aliases and macros in IPython's database. | ||
Fernando Perez
|
r5379 | |||
Thomas Kluyver
|
r5543 | To automatically restore stored variables at startup, add this to your | ||
:file:`ipython_config.py` file:: | ||||
Fernando Perez
|
r5379 | |||
Thomas Kluyver
|
r16280 | c.StoreMagics.autorestore = True | ||
vivainio
|
r166 | """ | ||
Min RK
|
r22340 | |||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
Fernando Perez
|
r6958 | import inspect, os, sys, textwrap | ||
from IPython.core.error import UsageError | ||||
Fernando Perez
|
r6973 | from IPython.core.magic import Magics, magics_class, line_magic | ||
Nikita Kniazev
|
r27102 | from IPython.testing.skipdoctest import skip_doctest | ||
Min RK
|
r21253 | from traitlets import Bool | ||
vivainio
|
r165 | |||
Michael Shuffett
|
r10343 | |||
Gökcen Eraslan
|
r25209 | def restore_aliases(ip, alias=None): | ||
fperez
|
r284 | staliases = ip.db.get('stored_aliases', {}) | ||
Gökcen Eraslan
|
r25209 | if alias is None: | ||
for k,v in staliases.items(): | ||||
#print "restore alias",k,v # dbg | ||||
#self.alias_table[k] = v | ||||
ip.alias_manager.define_alias(k,v) | ||||
else: | ||||
ip.alias_manager.define_alias(alias, staliases[alias]) | ||||
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: | ||||
Thomas Kluyver
|
r13348 | print("Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey) | ||
print("The error was:", sys.exc_info()[0]) | ||||
vivainio
|
r165 | else: | ||
#print "restored",justkey,"=",obj #dbg | ||||
fperez
|
r284 | ip.user_ns[justkey] = obj | ||
Bernardo B. Marques
|
r4872 | |||
vivainio
|
r165 | |||
vivainio
|
r713 | def restore_dhist(ip): | ||
Thomas Kluyver
|
r5378 | ip.user_ns['_dh'] = ip.db.get('dhist',[]) | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | |||
Thomas Kluyver
|
r5378 | def restore_data(ip): | ||
vivainio
|
r165 | refresh_variables(ip) | ||
Thomas Kluyver
|
r5378 | restore_aliases(ip) | ||
restore_dhist(ip) | ||||
vivainio
|
r165 | |||
Fernando Perez
|
r6935 | |||
Fernando Perez
|
r6973 | @magics_class | ||
Matthias BUSSONNIER
|
r13237 | class StoreMagics(Magics): | ||
vivainio
|
r165 | """Lightweight persistence for python variables. | ||
Fernando Perez
|
r6935 | Provides the %store magic.""" | ||
Gökcen Eraslan
|
r25209 | |||
Min RK
|
r22340 | autorestore = Bool(False, help= | ||
Thomas Kluyver
|
r12331 | """If True, any %store-d variables will be automatically restored | ||
when IPython starts. | ||||
""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
Gökcen Eraslan
|
r25209 | |||
Thomas Kluyver
|
r12331 | def __init__(self, shell): | ||
Matthias BUSSONNIER
|
r13237 | super(StoreMagics, self).__init__(shell=shell) | ||
Thomas Kluyver
|
r12331 | self.shell.configurables.append(self) | ||
if self.autorestore: | ||||
restore_data(self.shell) | ||||
Bernardo B. Marques
|
r4872 | |||
Nikita Kniazev
|
r27102 | @skip_doctest | ||
Fernando Perez
|
r6935 | @line_magic | ||
def store(self, parameter_s=''): | ||||
"""Lightweight persistence for python variables. | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | Example:: | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | In [1]: l = ['hello',10,'world'] | ||
In [2]: %store l | ||||
Nikita Kniazev
|
r27102 | Stored 'l' (list) | ||
Fernando Perez
|
r6935 | In [3]: exit | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | (IPython session is closed and started again...) | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | ville@badger:~$ ipython | ||
In [1]: l | ||||
MinRK
|
r11155 | NameError: name 'l' is not defined | ||
In [2]: %store -r | ||||
In [3]: l | ||||
Out[3]: ['hello', 10, 'world'] | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | Usage: | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | * ``%store`` - Show list of all variables and their current | ||
values | ||||
Gökcen Eraslan
|
r25209 | * ``%store spam bar`` - Store the *current* value of the variables spam | ||
and bar to disk | ||||
Fernando Perez
|
r6935 | * ``%store -d spam`` - Remove the variable and its value from storage | ||
* ``%store -z`` - Remove all variables from storage | ||||
Gökcen Eraslan
|
r25209 | * ``%store -r`` - Refresh all variables, aliases and directory history | ||
from store (overwrite current vals) | ||||
* ``%store -r spam bar`` - Refresh specified variables and aliases from store | ||||
Michael Shuffett
|
r10344 | (delete current val) | ||
Fernando Perez
|
r6935 | * ``%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 | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | 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. | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | Note also that the variables will need to be pickleable; most basic | ||
python types can be safely %store'd. | ||||
vivainio
|
r165 | |||
Fernando Perez
|
r6935 | Also aliases can be %store'd across sessions. | ||
Sebastian Witowski
|
r24997 | To remove an alias from the storage, use the %unalias magic. | ||
Fernando Perez
|
r6935 | """ | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | opts,argsl = self.parse_options(parameter_s,'drz',mode='string') | ||
Gökcen Eraslan
|
r25209 | args = argsl.split() | ||
Fernando Perez
|
r6935 | ip = self.shell | ||
db = ip.db | ||||
# delete | ||||
Bradley M. Froehle
|
r7859 | if 'd' in opts: | ||
Fernando Perez
|
r6935 | try: | ||
todel = args[0] | ||||
Ram Rachum
|
r25833 | except IndexError as e: | ||
raise UsageError('You must provide the variable to forget') from e | ||||
vivainio
|
r165 | else: | ||
Fernando Perez
|
r6935 | try: | ||
del db['autorestore/' + todel] | ||||
Ram Rachum
|
r25833 | except BaseException as e: | ||
raise UsageError("Can't delete variable '%s'" % todel) from e | ||||
Fernando Perez
|
r6935 | # reset | ||
Bradley M. Froehle
|
r7859 | elif 'z' in opts: | ||
Fernando Perez
|
r6935 | for k in db.keys('autorestore/*'): | ||
del db[k] | ||||
Bradley M. Froehle
|
r7859 | elif 'r' in opts: | ||
Michael Shuffett
|
r10343 | if args: | ||
Michael Shuffett
|
r10344 | for arg in args: | ||
try: | ||||
obj = db['autorestore/' + arg] | ||||
except KeyError: | ||||
Gökcen Eraslan
|
r25209 | try: | ||
restore_aliases(ip, alias=arg) | ||||
except KeyError: | ||||
print("no stored variable or alias %s" % arg) | ||||
Michael Shuffett
|
r10344 | else: | ||
ip.user_ns[arg] = obj | ||||
Michael Shuffett
|
r10343 | else: | ||
Thomas Kluyver
|
r11107 | restore_data(ip) | ||
Fernando Perez
|
r6935 | |||
# run without arguments -> list variables & values | ||||
elif not args: | ||||
Cavendish McKay
|
r8002 | vars = db.keys('autorestore/*') | ||
Fernando Perez
|
r6935 | vars.sort() | ||
if vars: | ||||
Fernando Perez
|
r6986 | size = max(map(len, vars)) | ||
vivainio
|
r243 | else: | ||
Fernando Perez
|
r6935 | size = 0 | ||
Thomas Kluyver
|
r13348 | print('Stored variables and their in-db values:') | ||
Fernando Perez
|
r6935 | fmt = '%-'+str(size)+'s -> %s' | ||
get = db.get | ||||
for var in vars: | ||||
justkey = os.path.basename(var) | ||||
# print 30 first characters from every var | ||||
Thomas Kluyver
|
r13348 | print(fmt % (justkey, repr(get(var, '<unavailable>'))[:50])) | ||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6935 | # default action - store the variable | ||
vivainio
|
r166 | else: | ||
Fernando Perez
|
r6935 | # %store foo >file.txt or >>file.txt | ||
gousaiyang
|
r27495 | if len(args) > 1 and args[1].startswith(">"): | ||
fnam = os.path.expanduser(args[1].lstrip(">").lstrip()) | ||||
if args[1].startswith(">>"): | ||||
fil = open(fnam, "a", encoding="utf-8") | ||||
Fernando Perez
|
r6935 | else: | ||
gousaiyang
|
r27495 | fil = open(fnam, "w", encoding="utf-8") | ||
Mickaël Schoentgen
|
r24897 | with fil: | ||
obj = ip.ev(args[0]) | ||||
print("Writing '%s' (%s) to file '%s'." % (args[0], | ||||
obj.__class__.__name__, fnam)) | ||||
if not isinstance (obj, str): | ||||
from pprint import pprint | ||||
pprint(obj, fil) | ||||
else: | ||||
fil.write(obj) | ||||
if not obj.endswith('\n'): | ||||
fil.write('\n') | ||||
Fernando Perez
|
r6935 | |||
vivainio
|
r166 | return | ||
Fernando Perez
|
r6935 | |||
# %store foo | ||||
Gökcen Eraslan
|
r25209 | for arg in args: | ||
Thomas Kluyver
|
r12596 | try: | ||
Gökcen Eraslan
|
r25209 | obj = ip.user_ns[arg] | ||
except KeyError: | ||||
# it might be an alias | ||||
name = arg | ||||
try: | ||||
cmd = ip.alias_manager.retrieve_alias(name) | ||||
Ram Rachum
|
r25833 | except ValueError as e: | ||
raise UsageError("Unknown variable '%s'" % name) from e | ||||
Gökcen Eraslan
|
r25209 | |||
staliases = db.get('stored_aliases',{}) | ||||
staliases[name] = cmd | ||||
db['stored_aliases'] = staliases | ||||
print("Alias stored: %s (%s)" % (name, cmd)) | ||||
Fernando Perez
|
r6935 | return | ||
Gökcen Eraslan
|
r25209 | |||
else: | ||||
modname = getattr(inspect.getmodule(obj), '__name__', '') | ||||
if modname == '__main__': | ||||
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. | ||||
""" % (arg, obj) )) | ||||
return | ||||
#pickled = pickle.dumps(obj) | ||||
db[ 'autorestore/' + arg ] = obj | ||||
print("Stored '%s' (%s)" % (arg, obj.__class__.__name__)) | ||||
vivainio
|
r165 | |||
Thomas Kluyver
|
r5541 | |||
Thomas Kluyver
|
r5378 | def load_ipython_extension(ip): | ||
Thomas Kluyver
|
r5541 | """Load the extension in IPython.""" | ||
Thomas Kluyver
|
r8552 | ip.register_magics(StoreMagics) | ||
Gökcen Eraslan
|
r25209 | |||