##// END OF EJS Templates
Restore autorestore option for storemagic....
Thomas Kluyver -
Show More
@@ -1,227 +1,243 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 %store magic for lightweight persistence.
4 4
5 5 Stores variables, aliases and macros in IPython's database.
6 6
7 7 To automatically restore stored variables at startup, add this to your
8 8 :file:`ipython_config.py` file::
9 9
10 10 c.StoreMagic.autorestore = True
11 11 """
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (c) 2012, The IPython Development Team.
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.txt, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 # Stdlib
25 25 import inspect, os, sys, textwrap
26 26
27 27 # Our own
28 from IPython.config.configurable import Configurable
28 29 from IPython.core.error import UsageError
29 30 from IPython.core.fakemodule import FakeModule
30 31 from IPython.core.magic import Magics, magics_class, line_magic
31 32 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.utils.traitlets import Bool
32 34
33 35 #-----------------------------------------------------------------------------
34 36 # Functions and classes
35 37 #-----------------------------------------------------------------------------
36 38
37 39 def restore_aliases(ip):
38 40 staliases = ip.db.get('stored_aliases', {})
39 41 for k,v in staliases.items():
40 42 #print "restore alias",k,v # dbg
41 43 #self.alias_table[k] = v
42 44 ip.alias_manager.define_alias(k,v)
43 45
44 46
45 47 def refresh_variables(ip):
46 48 db = ip.db
47 49 for key in db.keys('autorestore/*'):
48 50 # strip autorestore
49 51 justkey = os.path.basename(key)
50 52 try:
51 53 obj = db[key]
52 54 except KeyError:
53 55 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
54 56 print "The error was:", sys.exc_info()[0]
55 57 else:
56 58 #print "restored",justkey,"=",obj #dbg
57 59 ip.user_ns[justkey] = obj
58 60
59 61
60 62 def restore_dhist(ip):
61 63 ip.user_ns['_dh'] = ip.db.get('dhist',[])
62 64
63 65
64 66 def restore_data(ip):
65 67 refresh_variables(ip)
66 68 restore_aliases(ip)
67 69 restore_dhist(ip)
68 70
69 71
70 72 @magics_class
71 class StoreMagics(Magics):
73 class StoreMagics(Magics, Configurable):
72 74 """Lightweight persistence for python variables.
73 75
74 76 Provides the %store magic."""
77
78 autorestore = Bool(False, config=True, help=
79 """If True, any %store-d variables will be automatically restored
80 when IPython starts.
81 """
82 )
83
84 def __init__(self, shell):
85 Configurable.__init__(self, config=shell.config)
86 Magics.__init__(self, shell=shell)
87 self.shell.configurables.append(self)
88 if self.autorestore:
89 restore_data(self.shell)
75 90
76 91 @skip_doctest
77 92 @line_magic
78 93 def store(self, parameter_s=''):
79 94 """Lightweight persistence for python variables.
80 95
81 96 Example::
82 97
83 98 In [1]: l = ['hello',10,'world']
84 99 In [2]: %store l
85 100 In [3]: exit
86 101
87 102 (IPython session is closed and started again...)
88 103
89 104 ville@badger:~$ ipython
90 105 In [1]: l
91 106 NameError: name 'l' is not defined
92 107 In [2]: %store -r
93 108 In [3]: l
94 109 Out[3]: ['hello', 10, 'world']
95 110
96 111 Usage:
97 112
98 113 * ``%store`` - Show list of all variables and their current
99 114 values
100 115 * ``%store spam`` - Store the *current* value of the variable spam
101 116 to disk
102 117 * ``%store -d spam`` - Remove the variable and its value from storage
103 118 * ``%store -z`` - Remove all variables from storage
104 119 * ``%store -r`` - Refresh all variables from store (overwrite
105 120 current vals)
106 121 * ``%store -r spam bar`` - Refresh specified variables from store
107 122 (delete current val)
108 123 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
109 124 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
110 125
111 126 It should be noted that if you change the value of a variable, you
112 127 need to %store it again if you want to persist the new value.
113 128
114 129 Note also that the variables will need to be pickleable; most basic
115 130 python types can be safely %store'd.
116 131
117 132 Also aliases can be %store'd across sessions.
118 133 """
119 134
120 135 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
121 136 args = argsl.split(None,1)
122 137 ip = self.shell
123 138 db = ip.db
124 139 # delete
125 140 if 'd' in opts:
126 141 try:
127 142 todel = args[0]
128 143 except IndexError:
129 144 raise UsageError('You must provide the variable to forget')
130 145 else:
131 146 try:
132 147 del db['autorestore/' + todel]
133 148 except:
134 149 raise UsageError("Can't delete variable '%s'" % todel)
135 150 # reset
136 151 elif 'z' in opts:
137 152 for k in db.keys('autorestore/*'):
138 153 del db[k]
139 154
140 155 elif 'r' in opts:
141 156 if args:
142 157 for arg in args:
143 158 try:
144 159 obj = db['autorestore/' + arg]
145 160 except KeyError:
146 161 print "no stored variable %s" % arg
147 162 else:
148 163 ip.user_ns[arg] = obj
149 164 else:
150 165 restore_data(ip)
151 166
152 167 # run without arguments -> list variables & values
153 168 elif not args:
154 169 vars = db.keys('autorestore/*')
155 170 vars.sort()
156 171 if vars:
157 172 size = max(map(len, vars))
158 173 else:
159 174 size = 0
160 175
161 176 print 'Stored variables and their in-db values:'
162 177 fmt = '%-'+str(size)+'s -> %s'
163 178 get = db.get
164 179 for var in vars:
165 180 justkey = os.path.basename(var)
166 181 # print 30 first characters from every var
167 182 print fmt % (justkey, repr(get(var, '<unavailable>'))[:50])
168 183
169 184 # default action - store the variable
170 185 else:
171 186 # %store foo >file.txt or >>file.txt
172 187 if len(args) > 1 and args[1].startswith('>'):
173 188 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
174 189 if args[1].startswith('>>'):
175 190 fil = open(fnam, 'a')
176 191 else:
177 192 fil = open(fnam, 'w')
178 193 obj = ip.ev(args[0])
179 194 print "Writing '%s' (%s) to file '%s'." % (args[0],
180 195 obj.__class__.__name__, fnam)
181 196
182 197
183 198 if not isinstance (obj, basestring):
184 199 from pprint import pprint
185 200 pprint(obj, fil)
186 201 else:
187 202 fil.write(obj)
188 203 if not obj.endswith('\n'):
189 204 fil.write('\n')
190 205
191 206 fil.close()
192 207 return
193 208
194 209 # %store foo
195 210 try:
196 211 obj = ip.user_ns[args[0]]
197 212 except KeyError:
198 213 # it might be an alias
199 214 # This needs to be refactored to use the new AliasManager stuff.
200 215 if args[0] in ip.alias_manager:
201 216 name = args[0]
202 217 nargs, cmd = ip.alias_manager.alias_table[ name ]
203 218 staliases = db.get('stored_aliases',{})
204 219 staliases[ name ] = cmd
205 220 db['stored_aliases'] = staliases
206 221 print "Alias stored: %s (%s)" % (name, cmd)
207 222 return
208 223 else:
209 224 raise UsageError("Unknown variable '%s'" % args[0])
210 225
211 226 else:
212 227 if isinstance(inspect.getmodule(obj), FakeModule):
213 228 print textwrap.dedent("""\
214 229 Warning:%s is %s
215 230 Proper storage of interactively declared classes (or instances
216 231 of those classes) is not possible! Only instances
217 232 of classes in real modules on file system can be %%store'd.
218 233 """ % (args[0], obj) )
219 234 return
220 235 #pickled = pickle.dumps(obj)
221 236 db[ 'autorestore/' + args[0] ] = obj
222 237 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
223 238
224 239
225 240 def load_ipython_extension(ip):
226 241 """Load the extension in IPython."""
227 242 ip.register_magics(StoreMagics)
243
@@ -1,386 +1,388 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6
7 7 Authors
8 8 -------
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 * Min Ragan-Kelley
13 13 """
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Copyright (C) 2008-2011 The IPython Development Team
17 17 #
18 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 from __future__ import absolute_import
27 27
28 28 import logging
29 29 import os
30 30 import sys
31 31
32 32 from IPython.config.loader import (
33 33 Config, PyFileConfigLoader, ConfigFileNotFound
34 34 )
35 35 from IPython.config.application import boolean_flag, catch_config_error
36 36 from IPython.core import release
37 37 from IPython.core import usage
38 38 from IPython.core.completer import IPCompleter
39 39 from IPython.core.crashhandler import CrashHandler
40 40 from IPython.core.formatters import PlainTextFormatter
41 41 from IPython.core.history import HistoryManager
42 42 from IPython.core.prompts import PromptManager
43 43 from IPython.core.application import (
44 44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
45 45 )
46 46 from IPython.core.magics import ScriptMagics
47 47 from IPython.core.shellapp import (
48 48 InteractiveShellApp, shell_flags, shell_aliases
49 49 )
50 from IPython.extensions.storemagic import StoreMagics
50 51 from IPython.terminal.interactiveshell import TerminalInteractiveShell
51 52 from IPython.utils import warn
52 53 from IPython.utils.path import get_ipython_dir, check_for_old_config
53 54 from IPython.utils.traitlets import (
54 55 Bool, List, Dict,
55 56 )
56 57
57 58 #-----------------------------------------------------------------------------
58 59 # Globals, utilities and helpers
59 60 #-----------------------------------------------------------------------------
60 61
61 62 _examples = """
62 63 ipython --matplotlib # enable matplotlib integration
63 64 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
64 65
65 66 ipython --log-level=DEBUG # set logging to DEBUG
66 67 ipython --profile=foo # start with profile foo
67 68
68 69 ipython qtconsole # start the qtconsole GUI application
69 70 ipython help qtconsole # show the help for the qtconsole subcmd
70 71
71 72 ipython console # start the terminal-based console application
72 73 ipython help console # show the help for the console subcmd
73 74
74 75 ipython notebook # start the IPython notebook
75 76 ipython help notebook # show the help for the notebook subcmd
76 77
77 78 ipython profile create foo # create profile foo w/ default config files
78 79 ipython help profile # show the help for the profile subcmd
79 80
80 81 ipython locate # print the path to the IPython directory
81 82 ipython locate profile foo # print the path to the directory for profile `foo`
82 83
83 84 ipython nbconvert # convert notebooks to/from other formats
84 85 """
85 86
86 87 #-----------------------------------------------------------------------------
87 88 # Crash handler for this application
88 89 #-----------------------------------------------------------------------------
89 90
90 91 class IPAppCrashHandler(CrashHandler):
91 92 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
92 93
93 94 def __init__(self, app):
94 95 contact_name = release.author
95 96 contact_email = release.author_email
96 97 bug_tracker = 'https://github.com/ipython/ipython/issues'
97 98 super(IPAppCrashHandler,self).__init__(
98 99 app, contact_name, contact_email, bug_tracker
99 100 )
100 101
101 102 def make_report(self,traceback):
102 103 """Return a string containing a crash report."""
103 104
104 105 sec_sep = self.section_sep
105 106 # Start with parent report
106 107 report = [super(IPAppCrashHandler, self).make_report(traceback)]
107 108 # Add interactive-specific info we may have
108 109 rpt_add = report.append
109 110 try:
110 111 rpt_add(sec_sep+"History of session input:")
111 112 for line in self.app.shell.user_ns['_ih']:
112 113 rpt_add(line)
113 114 rpt_add('\n*** Last line of input (may not be in above history):\n')
114 115 rpt_add(self.app.shell._last_input_line+'\n')
115 116 except:
116 117 pass
117 118
118 119 return ''.join(report)
119 120
120 121 #-----------------------------------------------------------------------------
121 122 # Aliases and Flags
122 123 #-----------------------------------------------------------------------------
123 124 flags = dict(base_flags)
124 125 flags.update(shell_flags)
125 126 frontend_flags = {}
126 127 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
127 128 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
128 129 'Turn on auto editing of files with syntax errors.',
129 130 'Turn off auto editing of files with syntax errors.'
130 131 )
131 132 addflag('banner', 'TerminalIPythonApp.display_banner',
132 133 "Display a banner upon starting IPython.",
133 134 "Don't display a banner upon starting IPython."
134 135 )
135 136 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
136 137 """Set to confirm when you try to exit IPython with an EOF (Control-D
137 138 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
138 139 you can force a direct exit without any confirmation.""",
139 140 "Don't prompt the user when exiting."
140 141 )
141 142 addflag('term-title', 'TerminalInteractiveShell.term_title',
142 143 "Enable auto setting the terminal title.",
143 144 "Disable auto setting the terminal title."
144 145 )
145 146 classic_config = Config()
146 147 classic_config.InteractiveShell.cache_size = 0
147 148 classic_config.PlainTextFormatter.pprint = False
148 149 classic_config.PromptManager.in_template = '>>> '
149 150 classic_config.PromptManager.in2_template = '... '
150 151 classic_config.PromptManager.out_template = ''
151 152 classic_config.InteractiveShell.separate_in = ''
152 153 classic_config.InteractiveShell.separate_out = ''
153 154 classic_config.InteractiveShell.separate_out2 = ''
154 155 classic_config.InteractiveShell.colors = 'NoColor'
155 156 classic_config.InteractiveShell.xmode = 'Plain'
156 157
157 158 frontend_flags['classic']=(
158 159 classic_config,
159 160 "Gives IPython a similar feel to the classic Python prompt."
160 161 )
161 162 # # log doesn't make so much sense this way anymore
162 163 # paa('--log','-l',
163 164 # action='store_true', dest='InteractiveShell.logstart',
164 165 # help="Start logging to the default log file (./ipython_log.py).")
165 166 #
166 167 # # quick is harder to implement
167 168 frontend_flags['quick']=(
168 169 {'TerminalIPythonApp' : {'quick' : True}},
169 170 "Enable quick startup with no config files."
170 171 )
171 172
172 173 frontend_flags['i'] = (
173 174 {'TerminalIPythonApp' : {'force_interact' : True}},
174 175 """If running code from the command line, become interactive afterwards.
175 176 Note: can also be given simply as '-i.'"""
176 177 )
177 178 flags.update(frontend_flags)
178 179
179 180 aliases = dict(base_aliases)
180 181 aliases.update(shell_aliases)
181 182
182 183 #-----------------------------------------------------------------------------
183 184 # Main classes and functions
184 185 #-----------------------------------------------------------------------------
185 186
186 187
187 188 class LocateIPythonApp(BaseIPythonApplication):
188 189 description = """print the path to the IPython dir"""
189 190 subcommands = Dict(dict(
190 191 profile=('IPython.core.profileapp.ProfileLocate',
191 192 "print the path to an IPython profile directory",
192 193 ),
193 194 ))
194 195 def start(self):
195 196 if self.subapp is not None:
196 197 return self.subapp.start()
197 198 else:
198 199 print self.ipython_dir
199 200
200 201
201 202 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
202 203 name = u'ipython'
203 204 description = usage.cl_usage
204 205 crash_handler_class = IPAppCrashHandler
205 206 examples = _examples
206 207
207 208 flags = Dict(flags)
208 209 aliases = Dict(aliases)
209 210 classes = List()
210 211 def _classes_default(self):
211 212 """This has to be in a method, for TerminalIPythonApp to be available."""
212 213 return [
213 214 InteractiveShellApp, # ShellApp comes before TerminalApp, because
214 215 self.__class__, # it will also affect subclasses (e.g. QtConsole)
215 216 TerminalInteractiveShell,
216 217 PromptManager,
217 218 HistoryManager,
218 219 ProfileDir,
219 220 PlainTextFormatter,
220 221 IPCompleter,
221 222 ScriptMagics,
223 StoreMagics,
222 224 ]
223 225
224 226 subcommands = Dict(dict(
225 227 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
226 228 """Launch the IPython Qt Console."""
227 229 ),
228 230 notebook=('IPython.html.notebookapp.NotebookApp',
229 231 """Launch the IPython HTML Notebook Server."""
230 232 ),
231 233 profile = ("IPython.core.profileapp.ProfileApp",
232 234 "Create and manage IPython profiles."
233 235 ),
234 236 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
235 237 "Start a kernel without an attached frontend."
236 238 ),
237 239 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
238 240 """Launch the IPython terminal-based Console."""
239 241 ),
240 242 locate=('IPython.terminal.ipapp.LocateIPythonApp',
241 243 LocateIPythonApp.description
242 244 ),
243 245 history=('IPython.core.historyapp.HistoryApp',
244 246 "Manage the IPython history database."
245 247 ),
246 248 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
247 249 "Convert notebooks to/from other formats."
248 250 ),
249 251 ))
250 252
251 253 # *do* autocreate requested profile, but don't create the config file.
252 254 auto_create=Bool(True)
253 255 # configurables
254 256 ignore_old_config=Bool(False, config=True,
255 257 help="Suppress warning messages about legacy config files"
256 258 )
257 259 quick = Bool(False, config=True,
258 260 help="""Start IPython quickly by skipping the loading of config files."""
259 261 )
260 262 def _quick_changed(self, name, old, new):
261 263 if new:
262 264 self.load_config_file = lambda *a, **kw: None
263 265 self.ignore_old_config=True
264 266
265 267 display_banner = Bool(True, config=True,
266 268 help="Whether to display a banner upon starting IPython."
267 269 )
268 270
269 271 # if there is code of files to run from the cmd line, don't interact
270 272 # unless the --i flag (App.force_interact) is true.
271 273 force_interact = Bool(False, config=True,
272 274 help="""If a command or file is given via the command-line,
273 275 e.g. 'ipython foo.py"""
274 276 )
275 277 def _force_interact_changed(self, name, old, new):
276 278 if new:
277 279 self.interact = True
278 280
279 281 def _file_to_run_changed(self, name, old, new):
280 282 if new:
281 283 self.something_to_run = True
282 284 if new and not self.force_interact:
283 285 self.interact = False
284 286 _code_to_run_changed = _file_to_run_changed
285 287 _module_to_run_changed = _file_to_run_changed
286 288
287 289 # internal, not-configurable
288 290 interact=Bool(True)
289 291 something_to_run=Bool(False)
290 292
291 293 def parse_command_line(self, argv=None):
292 294 """override to allow old '-pylab' flag with deprecation warning"""
293 295
294 296 argv = sys.argv[1:] if argv is None else argv
295 297
296 298 if '-pylab' in argv:
297 299 # deprecated `-pylab` given,
298 300 # warn and transform into current syntax
299 301 argv = argv[:] # copy, don't clobber
300 302 idx = argv.index('-pylab')
301 303 warn.warn("`-pylab` flag has been deprecated.\n"
302 304 " Use `--matplotlib <backend>` and import pylab manually.")
303 305 argv[idx] = '--pylab'
304 306
305 307 return super(TerminalIPythonApp, self).parse_command_line(argv)
306 308
307 309 @catch_config_error
308 310 def initialize(self, argv=None):
309 311 """Do actions after construct, but before starting the app."""
310 312 super(TerminalIPythonApp, self).initialize(argv)
311 313 if self.subapp is not None:
312 314 # don't bother initializing further, starting subapp
313 315 return
314 316 if not self.ignore_old_config:
315 317 check_for_old_config(self.ipython_dir)
316 318 # print self.extra_args
317 319 if self.extra_args and not self.something_to_run:
318 320 self.file_to_run = self.extra_args[0]
319 321 self.init_path()
320 322 # create the shell
321 323 self.init_shell()
322 324 # and draw the banner
323 325 self.init_banner()
324 326 # Now a variety of things that happen after the banner is printed.
325 327 self.init_gui_pylab()
326 328 self.init_extensions()
327 329 self.init_code()
328 330
329 331 def init_shell(self):
330 332 """initialize the InteractiveShell instance"""
331 333 # Create an InteractiveShell instance.
332 334 # shell.display_banner should always be False for the terminal
333 335 # based app, because we call shell.show_banner() by hand below
334 336 # so the banner shows *before* all extension loading stuff.
335 337 self.shell = TerminalInteractiveShell.instance(parent=self,
336 338 display_banner=False, profile_dir=self.profile_dir,
337 339 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
338 340 self.shell.configurables.append(self)
339 341
340 342 def init_banner(self):
341 343 """optionally display the banner"""
342 344 if self.display_banner and self.interact:
343 345 self.shell.show_banner()
344 346 # Make sure there is a space below the banner.
345 347 if self.log_level <= logging.INFO: print
346 348
347 349 def _pylab_changed(self, name, old, new):
348 350 """Replace --pylab='inline' with --pylab='auto'"""
349 351 if new == 'inline':
350 352 warn.warn("'inline' not available as pylab backend, "
351 353 "using 'auto' instead.")
352 354 self.pylab = 'auto'
353 355
354 356 def start(self):
355 357 if self.subapp is not None:
356 358 return self.subapp.start()
357 359 # perform any prexec steps:
358 360 if self.interact:
359 361 self.log.debug("Starting IPython's mainloop...")
360 362 self.shell.mainloop()
361 363 else:
362 364 self.log.debug("IPython not interactive...")
363 365
364 366
365 367 def load_default_config(ipython_dir=None):
366 368 """Load the default config file from the default ipython_dir.
367 369
368 370 This is useful for embedded shells.
369 371 """
370 372 if ipython_dir is None:
371 373 ipython_dir = get_ipython_dir()
372 374 profile_dir = os.path.join(ipython_dir, 'profile_default')
373 375 cl = PyFileConfigLoader("ipython_config.py", profile_dir)
374 376 try:
375 377 config = cl.load_config()
376 378 except ConfigFileNotFound:
377 379 # no config found
378 380 config = Config()
379 381 return config
380 382
381 383
382 384 launch_new_instance = TerminalIPythonApp.launch_instance
383 385
384 386
385 387 if __name__ == '__main__':
386 388 launch_new_instance()
General Comments 0
You need to be logged in to leave comments. Login now