| |
| """ |
| %store magic for lightweight persistence. |
| |
| Stores variables, aliases and macros in IPython's database. |
| |
| To automatically restore stored variables at startup, add this to your |
| :file:`ipython_config.py` file:: |
| |
| c.StoreMagics.autorestore = True |
| """ |
|
|
| |
| |
|
|
| import inspect, os, sys, textwrap |
|
|
| from IPython.core.error import UsageError |
| from IPython.core.magic import Magics, magics_class, line_magic |
| from IPython.testing.skipdoctest import skip_doctest |
| from traitlets import Bool |
|
|
|
|
| def restore_aliases(ip, alias=None): |
| staliases = ip.db.get('stored_aliases', {}) |
| if alias is None: |
| for k,v in staliases.items(): |
| |
| |
| ip.alias_manager.define_alias(k,v) |
| else: |
| ip.alias_manager.define_alias(alias, staliases[alias]) |
|
|
|
|
| def refresh_variables(ip): |
| db = ip.db |
| for key in db.keys('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: |
| |
| ip.user_ns[justkey] = obj |
|
|
|
|
| def restore_dhist(ip): |
| ip.user_ns['_dh'] = ip.db.get('dhist',[]) |
|
|
|
|
| def restore_data(ip): |
| refresh_variables(ip) |
| restore_aliases(ip) |
| restore_dhist(ip) |
|
|
|
|
| @magics_class |
| class StoreMagics(Magics): |
| """Lightweight persistence for python variables. |
| |
| Provides the %store magic.""" |
|
|
| autorestore = Bool(False, help= |
| """If True, any %store-d variables will be automatically restored |
| when IPython starts. |
| """ |
| ).tag(config=True) |
|
|
| def __init__(self, shell): |
| super(StoreMagics, self).__init__(shell=shell) |
| self.shell.configurables.append(self) |
| if self.autorestore: |
| restore_data(self.shell) |
|
|
| @skip_doctest |
| @line_magic |
| def store(self, parameter_s=''): |
| """Lightweight persistence for python variables. |
| |
| Example:: |
| |
| In [1]: l = ['hello',10,'world'] |
| In [2]: %store l |
| Stored 'l' (list) |
| In [3]: exit |
| |
| (IPython session is closed and started again...) |
| |
| ville@badger:~$ ipython |
| In [1]: l |
| NameError: name 'l' is not defined |
| In [2]: %store -r |
| In [3]: l |
| Out[3]: ['hello', 10, 'world'] |
| |
| Usage: |
| |
| * ``%store`` - Show list of all variables and their current |
| values |
| * ``%store spam bar`` - Store the *current* value of the variables spam |
| and bar to disk |
| * ``%store -d spam`` - Remove the variable and its value from storage |
| * ``%store -z`` - Remove all variables from storage |
| * ``%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 |
| (delete current val) |
| * ``%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 %store'd. |
| |
| Also aliases can be %store'd across sessions. |
| To remove an alias from the storage, use the %unalias magic. |
| """ |
|
|
| opts,argsl = self.parse_options(parameter_s,'drz',mode='string') |
| args = argsl.split() |
| ip = self.shell |
| db = ip.db |
| |
| if 'd' in opts: |
| try: |
| todel = args[0] |
| except IndexError as e: |
| raise UsageError('You must provide the variable to forget') from e |
| else: |
| try: |
| del db['autorestore/' + todel] |
| except BaseException as e: |
| raise UsageError("Can't delete variable '%s'" % todel) from e |
| |
| elif 'z' in opts: |
| for k in db.keys('autorestore/*'): |
| del db[k] |
|
|
| elif 'r' in opts: |
| if args: |
| for arg in args: |
| try: |
| obj = db["autorestore/" + arg] |
| except KeyError: |
| try: |
| restore_aliases(ip, alias=arg) |
| except KeyError: |
| print("no stored variable or alias %s" % arg) |
| else: |
| ip.user_ns[arg] = obj |
| else: |
| restore_data(ip) |
|
|
| |
| elif not args: |
| vars = 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(fmt % (justkey, repr(get(var, '<unavailable>'))[:50])) |
|
|
| |
| else: |
| |
| 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") |
| else: |
| fil = open(fnam, "w", encoding="utf-8") |
| 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') |
|
|
| return |
|
|
| |
| for arg in args: |
| try: |
| obj = ip.user_ns[arg] |
| except KeyError: |
| |
| name = arg |
| try: |
| cmd = ip.alias_manager.retrieve_alias(name) |
| except ValueError as e: |
| raise UsageError("Unknown variable '%s'" % name) from e |
|
|
| staliases = db.get('stored_aliases',{}) |
| staliases[name] = cmd |
| db['stored_aliases'] = staliases |
| print("Alias stored: %s (%s)" % (name, cmd)) |
| return |
|
|
| 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 |
| |
| db[ 'autorestore/' + arg ] = obj |
| print("Stored '%s' (%s)" % (arg, obj.__class__.__name__)) |
|
|
|
|
| def load_ipython_extension(ip): |
| """Load the extension in IPython.""" |
| ip.register_magics(StoreMagics) |
|
|
|
|