##// END OF EJS Templates
Update storemagic extension to new API
Fernando Perez -
Show More
@@ -1,378 +1,369
1 # encoding: utf-8
1 # encoding: utf-8
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 The IPython Development Team
9
9
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Stdlib
17 # Stdlib
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 import types
21 import types
22 from getopt import getopt, GetoptError
22 from getopt import getopt, GetoptError
23
23
24 # Our own
24 # Our own
25 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
26 from IPython.core import oinspect
26 from IPython.core import oinspect
27 from IPython.core.error import UsageError
27 from IPython.core.error import UsageError
28 from IPython.core.prefilter import ESC_MAGIC
28 from IPython.core.prefilter import ESC_MAGIC
29 from IPython.external.decorator import decorator
29 from IPython.external.decorator import decorator
30 from IPython.utils.ipstruct import Struct
30 from IPython.utils.ipstruct import Struct
31 from IPython.utils.process import arg_split
31 from IPython.utils.process import arg_split
32 from IPython.utils.traitlets import Bool, Dict, Instance
32 from IPython.utils.traitlets import Bool, Dict, Instance
33 from IPython.utils.warn import error
33 from IPython.utils.warn import error
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Globals
36 # Globals
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 # A dict we'll use for each class that has magics, used as temporary storage to
39 # A dict we'll use for each class that has magics, used as temporary storage to
40 # pass information between the @line/cell_magic method decorators and the
40 # pass information between the @line/cell_magic method decorators and the
41 # @register_magics class decorator, because the method decorators have no
41 # @register_magics class decorator, because the method decorators have no
42 # access to the class when they run. See for more details:
42 # access to the class when they run. See for more details:
43 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
43 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
44
44
45 magics = dict(line={}, cell={})
45 magics = dict(line={}, cell={})
46
46
47 magic_types = ('line', 'cell')
47 magic_types = ('line', 'cell')
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Utility classes and functions
50 # Utility classes and functions
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 class Bunch: pass
53 class Bunch: pass
54
54
55
55
56 def on_off(tag):
56 def on_off(tag):
57 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
57 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
58 return ['OFF','ON'][tag]
58 return ['OFF','ON'][tag]
59
59
60
60
61 def compress_dhist(dh):
61 def compress_dhist(dh):
62 head, tail = dh[:-10], dh[-10:]
62 head, tail = dh[:-10], dh[-10:]
63
63
64 newhead = []
64 newhead = []
65 done = set()
65 done = set()
66 for h in head:
66 for h in head:
67 if h in done:
67 if h in done:
68 continue
68 continue
69 newhead.append(h)
69 newhead.append(h)
70 done.add(h)
70 done.add(h)
71
71
72 return newhead + tail
72 return newhead + tail
73
73
74
74
75 def needs_local_scope(func):
75 def needs_local_scope(func):
76 """Decorator to mark magic functions which need to local scope to run."""
76 """Decorator to mark magic functions which need to local scope to run."""
77 func.needs_local_scope = True
77 func.needs_local_scope = True
78 return func
78 return func
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Class and method decorators for registering magics
81 # Class and method decorators for registering magics
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83
83
84 def register_magics(cls):
84 def register_magics(cls):
85 cls.registered = True
85 cls.registered = True
86 cls.magics = dict(line = magics['line'],
86 cls.magics = dict(line = magics['line'],
87 cell = magics['cell'])
87 cell = magics['cell'])
88 magics['line'] = {}
88 magics['line'] = {}
89 magics['cell'] = {}
89 magics['cell'] = {}
90 return cls
90 return cls
91
91
92 def _record_magic(dct, mtype, mname, func):
92 def _record_magic(dct, mtype, mname, func):
93 if mtype == 'line_cell':
93 if mtype == 'line_cell':
94 dct['line'][mname] = dct['cell'][mname] = func
94 dct['line'][mname] = dct['cell'][mname] = func
95 else:
95 else:
96 dct[mtype][mname] = func
96 dct[mtype][mname] = func
97
97
98 def validate_type(magic_type):
98 def validate_type(magic_type):
99 if magic_type not in magic_types:
99 if magic_type not in magic_types:
100 raise ValueError('magic_type must be one of %s, %s given' %
100 raise ValueError('magic_type must be one of %s, %s given' %
101 magic_types, magic_type)
101 magic_types, magic_type)
102
102
103
103
104 def _magic_marker(magic_type):
104 def _magic_marker(magic_type):
105 validate_type(magic_type)
105 validate_type(magic_type)
106
106
107 # This is a closure to capture the magic_type. We could also use a class,
107 # This is a closure to capture the magic_type. We could also use a class,
108 # but it's overkill for just that one bit of state.
108 # but it's overkill for just that one bit of state.
109 def magic_deco(arg):
109 def magic_deco(arg):
110 call = lambda f, *a, **k: f(*a, **k)
110 call = lambda f, *a, **k: f(*a, **k)
111
111
112 if callable(arg):
112 if callable(arg):
113 # "Naked" decorator call (just @foo, no args)
113 # "Naked" decorator call (just @foo, no args)
114 func = arg
114 func = arg
115 name = func.func_name
115 name = func.func_name
116 func.magic_name = name
116 func.magic_name = name
117 retval = decorator(call, func)
117 retval = decorator(call, func)
118 magics[magic_type][name] = name
118 magics[magic_type][name] = name
119 elif isinstance(arg, basestring):
119 elif isinstance(arg, basestring):
120 # Decorator called with arguments (@foo('bar'))
120 # Decorator called with arguments (@foo('bar'))
121 name = arg
121 name = arg
122 def mark(func, *a, **kw):
122 def mark(func, *a, **kw):
123 func.magic_name = name
123 func.magic_name = name
124 magics[magic_type][name] = func.func_name
124 magics[magic_type][name] = func.func_name
125 return decorator(call, func)
125 return decorator(call, func)
126 retval = mark
126 retval = mark
127 else:
127 else:
128 raise ValueError("Decorator can only be called with "
128 raise ValueError("Decorator can only be called with "
129 "string or function")
129 "string or function")
130
130
131 return retval
131 return retval
132
132
133 return magic_deco
133 return magic_deco
134
134
135
135
136 line_magic = _magic_marker('line')
136 line_magic = _magic_marker('line')
137 cell_magic = _magic_marker('cell')
137 cell_magic = _magic_marker('cell')
138
138
139 #-----------------------------------------------------------------------------
139 #-----------------------------------------------------------------------------
140 # Core Magic classes
140 # Core Magic classes
141 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
142
142
143 class MagicsManager(Configurable):
143 class MagicsManager(Configurable):
144 """Object that handles all magic-related functionality for IPython.
144 """Object that handles all magic-related functionality for IPython.
145 """
145 """
146 # Non-configurable class attributes
146 # Non-configurable class attributes
147 magics = Dict
147 magics = Dict
148
148
149 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
149 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
150
150
151 auto_magic = Bool
151 auto_magic = Bool
152
152
153 _auto_status = [
153 _auto_status = [
154 'Automagic is OFF, % prefix IS needed for magic functions.',
154 'Automagic is OFF, % prefix IS needed for magic functions.',
155 'Automagic is ON, % prefix IS NOT needed for magic functions.']
155 'Automagic is ON, % prefix IS NOT needed for magic functions.']
156
156
157 user_magics = Instance('IPython.core.magic_functions.UserMagics')
157 user_magics = Instance('IPython.core.magic_functions.UserMagics')
158
158
159 def __init__(self, shell=None, config=None, user_magics=None, **traits):
159 def __init__(self, shell=None, config=None, user_magics=None, **traits):
160
160
161 super(MagicsManager, self).__init__(shell=shell, config=config,
161 super(MagicsManager, self).__init__(shell=shell, config=config,
162 user_magics=user_magics, **traits)
162 user_magics=user_magics, **traits)
163 self.magics = dict(line={}, cell={})
163 self.magics = dict(line={}, cell={})
164
164
165 def auto_status(self):
165 def auto_status(self):
166 """Return descriptive string with automagic status."""
166 """Return descriptive string with automagic status."""
167 return self._auto_status[self.auto_magic]
167 return self._auto_status[self.auto_magic]
168
168
169 def lsmagic(self):
169 def lsmagic(self):
170 """Return a dict of currently available magic functions.
170 """Return a dict of currently available magic functions.
171
171
172 The return dict has the keys 'line' and 'cell', corresponding to the
172 The return dict has the keys 'line' and 'cell', corresponding to the
173 two types of magics we support. Each value is a list of names.
173 two types of magics we support. Each value is a list of names.
174 """
174 """
175 return self.magics
175 return self.magics
176
176
177 def register(self, *magic_objects):
177 def register(self, *magic_objects):
178 """Register one or more instances of Magics.
178 """Register one or more instances of Magics.
179 """
179 """
180 # Start by validating them to ensure they have all had their magic
180 # Start by validating them to ensure they have all had their magic
181 # methods registered at the instance level
181 # methods registered at the instance level
182 for m in magic_objects:
182 for m in magic_objects:
183 if not m.registered:
183 if not m.registered:
184 raise ValueError("Class of magics %r was constructed without "
184 raise ValueError("Class of magics %r was constructed without "
185 "the @register_macics class decorator")
185 "the @register_macics class decorator")
186 if type(m) is type:
186 if type(m) is type:
187 # If we're given an uninstantiated class
187 # If we're given an uninstantiated class
188 m = m(self.shell)
188 m = m(self.shell)
189
189
190 for mtype in magic_types:
190 for mtype in magic_types:
191 self.magics[mtype].update(m.magics[mtype])
191 self.magics[mtype].update(m.magics[mtype])
192
192
193 def new_magic(self, func, magic_name=None, magic_type='line'):
193 def new_magic(self, func, magic_name=None, magic_type='line'):
194 """Expose own function as magic function for ipython
194 """Expose a standalone function as magic function for ipython.
195
195
196 Example::
197
198 def foo_impl(self, parameter_s=''):
199 'My very own magic!. (Use docstrings, IPython reads them).'
200 print 'Magic function. Passed parameter is between < >:'
201 print '<%s>' % parameter_s
202 print 'The self object is:', self
203
204 ip.define_magic('foo', foo_impl)
205 """
196 """
206
197
207 # Create the new method in the user_magics and register it in the
198 # Create the new method in the user_magics and register it in the
208 # global table
199 # global table
209 newm, name = self.user_magics.new_magic(func, magic_type, magic_name)
200 newm, name = self.user_magics.new_magic(func, magic_type, magic_name)
210 _record_magic(self.magics, magic_type, name, newm)
201 _record_magic(self.magics, magic_type, name, newm)
211
202
212 # Key base class that provides the central functionality for magics.
203 # Key base class that provides the central functionality for magics.
213
204
214 class Magics(object):
205 class Magics(object):
215 """Base class for implementing magic functions.
206 """Base class for implementing magic functions.
216
207
217 Shell functions which can be reached as %function_name. All magic
208 Shell functions which can be reached as %function_name. All magic
218 functions should accept a string, which they can parse for their own
209 functions should accept a string, which they can parse for their own
219 needs. This can make some functions easier to type, eg `%cd ../`
210 needs. This can make some functions easier to type, eg `%cd ../`
220 vs. `%cd("../")`
211 vs. `%cd("../")`
221
212
222 Classes providing magic functions need to subclass this class, and they
213 Classes providing magic functions need to subclass this class, and they
223 MUST:
214 MUST:
224
215
225 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
216 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
226 individual methods as magic functions, AND
217 individual methods as magic functions, AND
227
218
228 - Use the class decorator `@register_magics` to ensure that the magic
219 - Use the class decorator `@register_magics` to ensure that the magic
229 methods are properly registered at the instance level upon instance
220 methods are properly registered at the instance level upon instance
230 initialization.
221 initialization.
231
222
232 See :mod:`magic_functions` for examples of actual implementation classes.
223 See :mod:`magic_functions` for examples of actual implementation classes.
233 """
224 """
234 # Dict holding all command-line options for each magic.
225 # Dict holding all command-line options for each magic.
235 options_table = None
226 options_table = None
236 # Dict for the mapping of magic names to methods, set by class decorator
227 # Dict for the mapping of magic names to methods, set by class decorator
237 magics = None
228 magics = None
238 # Flag to check that the class decorator was properly applied
229 # Flag to check that the class decorator was properly applied
239 registered = False
230 registered = False
240 # Instance of IPython shell
231 # Instance of IPython shell
241 shell = None
232 shell = None
242
233
243 def __init__(self, shell):
234 def __init__(self, shell):
244 if not(self.__class__.registered):
235 if not(self.__class__.registered):
245 raise ValueError('Magics subclass without registration - '
236 raise ValueError('Magics subclass without registration - '
246 'did you forget to apply @register_magics?')
237 'did you forget to apply @register_magics?')
247 self.shell = shell
238 self.shell = shell
248 self.options_table = {}
239 self.options_table = {}
249 # The method decorators are run when the instance doesn't exist yet, so
240 # The method decorators are run when the instance doesn't exist yet, so
250 # they can only record the names of the methods they are supposed to
241 # they can only record the names of the methods they are supposed to
251 # grab. Only now, that the instance exists, can we create the proper
242 # grab. Only now, that the instance exists, can we create the proper
252 # mapping to bound methods. So we read the info off the original names
243 # mapping to bound methods. So we read the info off the original names
253 # table and replace each method name by the actual bound method.
244 # table and replace each method name by the actual bound method.
254 for mtype in magic_types:
245 for mtype in magic_types:
255 tab = self.magics[mtype]
246 tab = self.magics[mtype]
256 # must explicitly use keys, as we're mutating this puppy
247 # must explicitly use keys, as we're mutating this puppy
257 for magic_name in tab.keys():
248 for magic_name in tab.keys():
258 meth_name = tab[magic_name]
249 meth_name = tab[magic_name]
259 if isinstance(meth_name, basestring):
250 if isinstance(meth_name, basestring):
260 tab[magic_name] = getattr(self, meth_name)
251 tab[magic_name] = getattr(self, meth_name)
261
252
262 def arg_err(self,func):
253 def arg_err(self,func):
263 """Print docstring if incorrect arguments were passed"""
254 """Print docstring if incorrect arguments were passed"""
264 print 'Error in arguments:'
255 print 'Error in arguments:'
265 print oinspect.getdoc(func)
256 print oinspect.getdoc(func)
266
257
267 def format_latex(self, strng):
258 def format_latex(self, strng):
268 """Format a string for latex inclusion."""
259 """Format a string for latex inclusion."""
269
260
270 # Characters that need to be escaped for latex:
261 # Characters that need to be escaped for latex:
271 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
262 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
272 # Magic command names as headers:
263 # Magic command names as headers:
273 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
264 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
274 re.MULTILINE)
265 re.MULTILINE)
275 # Magic commands
266 # Magic commands
276 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
267 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
277 re.MULTILINE)
268 re.MULTILINE)
278 # Paragraph continue
269 # Paragraph continue
279 par_re = re.compile(r'\\$',re.MULTILINE)
270 par_re = re.compile(r'\\$',re.MULTILINE)
280
271
281 # The "\n" symbol
272 # The "\n" symbol
282 newline_re = re.compile(r'\\n')
273 newline_re = re.compile(r'\\n')
283
274
284 # Now build the string for output:
275 # Now build the string for output:
285 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
276 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
286 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
277 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
287 strng)
278 strng)
288 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
279 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
289 strng = par_re.sub(r'\\\\',strng)
280 strng = par_re.sub(r'\\\\',strng)
290 strng = escape_re.sub(r'\\\1',strng)
281 strng = escape_re.sub(r'\\\1',strng)
291 strng = newline_re.sub(r'\\textbackslash{}n',strng)
282 strng = newline_re.sub(r'\\textbackslash{}n',strng)
292 return strng
283 return strng
293
284
294 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
285 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
295 """Parse options passed to an argument string.
286 """Parse options passed to an argument string.
296
287
297 The interface is similar to that of getopt(), but it returns back a
288 The interface is similar to that of getopt(), but it returns back a
298 Struct with the options as keys and the stripped argument string still
289 Struct with the options as keys and the stripped argument string still
299 as a string.
290 as a string.
300
291
301 arg_str is quoted as a true sys.argv vector by using shlex.split.
292 arg_str is quoted as a true sys.argv vector by using shlex.split.
302 This allows us to easily expand variables, glob files, quote
293 This allows us to easily expand variables, glob files, quote
303 arguments, etc.
294 arguments, etc.
304
295
305 Options:
296 Options:
306 -mode: default 'string'. If given as 'list', the argument string is
297 -mode: default 'string'. If given as 'list', the argument string is
307 returned as a list (split on whitespace) instead of a string.
298 returned as a list (split on whitespace) instead of a string.
308
299
309 -list_all: put all option values in lists. Normally only options
300 -list_all: put all option values in lists. Normally only options
310 appearing more than once are put in a list.
301 appearing more than once are put in a list.
311
302
312 -posix (True): whether to split the input line in POSIX mode or not,
303 -posix (True): whether to split the input line in POSIX mode or not,
313 as per the conventions outlined in the shlex module from the
304 as per the conventions outlined in the shlex module from the
314 standard library."""
305 standard library."""
315
306
316 # inject default options at the beginning of the input line
307 # inject default options at the beginning of the input line
317 caller = sys._getframe(1).f_code.co_name
308 caller = sys._getframe(1).f_code.co_name
318 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
309 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
319
310
320 mode = kw.get('mode','string')
311 mode = kw.get('mode','string')
321 if mode not in ['string','list']:
312 if mode not in ['string','list']:
322 raise ValueError,'incorrect mode given: %s' % mode
313 raise ValueError,'incorrect mode given: %s' % mode
323 # Get options
314 # Get options
324 list_all = kw.get('list_all',0)
315 list_all = kw.get('list_all',0)
325 posix = kw.get('posix', os.name == 'posix')
316 posix = kw.get('posix', os.name == 'posix')
326 strict = kw.get('strict', True)
317 strict = kw.get('strict', True)
327
318
328 # Check if we have more than one argument to warrant extra processing:
319 # Check if we have more than one argument to warrant extra processing:
329 odict = {} # Dictionary with options
320 odict = {} # Dictionary with options
330 args = arg_str.split()
321 args = arg_str.split()
331 if len(args) >= 1:
322 if len(args) >= 1:
332 # If the list of inputs only has 0 or 1 thing in it, there's no
323 # If the list of inputs only has 0 or 1 thing in it, there's no
333 # need to look for options
324 # need to look for options
334 argv = arg_split(arg_str, posix, strict)
325 argv = arg_split(arg_str, posix, strict)
335 # Do regular option processing
326 # Do regular option processing
336 try:
327 try:
337 opts,args = getopt(argv,opt_str,*long_opts)
328 opts,args = getopt(argv,opt_str,*long_opts)
338 except GetoptError,e:
329 except GetoptError,e:
339 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
330 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
340 " ".join(long_opts)))
331 " ".join(long_opts)))
341 for o,a in opts:
332 for o,a in opts:
342 if o.startswith('--'):
333 if o.startswith('--'):
343 o = o[2:]
334 o = o[2:]
344 else:
335 else:
345 o = o[1:]
336 o = o[1:]
346 try:
337 try:
347 odict[o].append(a)
338 odict[o].append(a)
348 except AttributeError:
339 except AttributeError:
349 odict[o] = [odict[o],a]
340 odict[o] = [odict[o],a]
350 except KeyError:
341 except KeyError:
351 if list_all:
342 if list_all:
352 odict[o] = [a]
343 odict[o] = [a]
353 else:
344 else:
354 odict[o] = a
345 odict[o] = a
355
346
356 # Prepare opts,args for return
347 # Prepare opts,args for return
357 opts = Struct(odict)
348 opts = Struct(odict)
358 if mode == 'string':
349 if mode == 'string':
359 args = ' '.join(args)
350 args = ' '.join(args)
360
351
361 return opts,args
352 return opts,args
362
353
363 def default_option(self, fn, optstr):
354 def default_option(self, fn, optstr):
364 """Make an entry in the options_table for fn, with value optstr"""
355 """Make an entry in the options_table for fn, with value optstr"""
365
356
366 if fn not in self.lsmagic():
357 if fn not in self.lsmagic():
367 error("%s is not a magic function" % fn)
358 error("%s is not a magic function" % fn)
368 self.options_table[fn] = optstr
359 self.options_table[fn] = optstr
369
360
370 def new_magic(self, func, magic_type='line', magic_name=None):
361 def new_magic(self, func, magic_type='line', magic_name=None):
371 """TODO
362 """TODO
372 """
363 """
373 magic_name = func.func_name if magic_name is None else magic_name
364 magic_name = func.func_name if magic_name is None else magic_name
374 validate_type(magic_type)
365 validate_type(magic_type)
375 meth = types.MethodType(func, self)
366 meth = types.MethodType(func, self)
376 setattr(self, magic_name, meth)
367 setattr(self, magic_name, meth)
377 _record_magic(self.magics, magic_type, magic_name, meth)
368 _record_magic(self.magics, magic_type, magic_name, meth)
378 return meth, magic_name
369 return meth, magic_name
@@ -1,205 +1,219
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 %store magic for lightweight persistence.
3 %store magic for lightweight persistence.
4
4
5 Stores variables, aliases and macros in IPython's database.
5 Stores variables, aliases and macros in IPython's database.
6
6
7 To automatically restore stored variables at startup, add this to your
7 To automatically restore stored variables at startup, add this to your
8 :file:`ipython_config.py` file::
8 :file:`ipython_config.py` file::
9
9
10 c.StoreMagic.autorestore = True
10 c.StoreMagic.autorestore = True
11
12 """
11 """
13
12
14 from IPython.core.error import TryNext, UsageError
13 from IPython.core.error import TryNext, UsageError
14 from IPython.core.magic import Magics, register_magics, line_magic
15 from IPython.core.plugin import Plugin
15 from IPython.core.plugin import Plugin
16 from IPython.testing.skipdoctest import skip_doctest
16 from IPython.testing.skipdoctest import skip_doctest
17 from IPython.utils import pickleshare
17 from IPython.utils import pickleshare
18 from IPython.utils.traitlets import Bool, Instance
18 from IPython.utils.traitlets import Bool, Instance
19
19
20 import inspect,pickle,os,sys,textwrap
20 import inspect,pickle,os,sys,textwrap
21 from IPython.core.fakemodule import FakeModule
21 from IPython.core.fakemodule import FakeModule
22
22
23
23 def restore_aliases(ip):
24 def restore_aliases(ip):
24 staliases = ip.db.get('stored_aliases', {})
25 staliases = ip.db.get('stored_aliases', {})
25 for k,v in staliases.items():
26 for k,v in staliases.items():
26 #print "restore alias",k,v # dbg
27 #print "restore alias",k,v # dbg
27 #self.alias_table[k] = v
28 #self.alias_table[k] = v
28 ip.alias_manager.define_alias(k,v)
29 ip.alias_manager.define_alias(k,v)
29
30
30
31
31 def refresh_variables(ip):
32 def refresh_variables(ip):
32 db = ip.db
33 db = ip.db
33 for key in db.keys('autorestore/*'):
34 for key in db.keys('autorestore/*'):
34 # strip autorestore
35 # strip autorestore
35 justkey = os.path.basename(key)
36 justkey = os.path.basename(key)
36 try:
37 try:
37 obj = db[key]
38 obj = db[key]
38 except KeyError:
39 except KeyError:
39 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
40 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
40 print "The error was:",sys.exc_info()[0]
41 print "The error was:", sys.exc_info()[0]
41 else:
42 else:
42 #print "restored",justkey,"=",obj #dbg
43 #print "restored",justkey,"=",obj #dbg
43 ip.user_ns[justkey] = obj
44 ip.user_ns[justkey] = obj
44
45
45
46
46 def restore_dhist(ip):
47 def restore_dhist(ip):
47 ip.user_ns['_dh'] = ip.db.get('dhist',[])
48 ip.user_ns['_dh'] = ip.db.get('dhist',[])
48
49
50
49 def restore_data(ip):
51 def restore_data(ip):
50 refresh_variables(ip)
52 refresh_variables(ip)
51 restore_aliases(ip)
53 restore_aliases(ip)
52 restore_dhist(ip)
54 restore_dhist(ip)
53
55
56
57 @register_magics
58 class StoreMagics(Magics):
59 """Lightweight persistence for python variables.
60
61 Provides the %store magic."""
62
54 @skip_doctest
63 @skip_doctest
55 def magic_store(self, parameter_s=''):
64 @line_magic
65 def store(self, parameter_s=''):
56 """Lightweight persistence for python variables.
66 """Lightweight persistence for python variables.
57
67
58 Example::
68 Example::
59
69
60 In [1]: l = ['hello',10,'world']
70 In [1]: l = ['hello',10,'world']
61 In [2]: %store l
71 In [2]: %store l
62 In [3]: exit
72 In [3]: exit
63
73
64 (IPython session is closed and started again...)
74 (IPython session is closed and started again...)
65
75
66 ville@badger:~$ ipython
76 ville@badger:~$ ipython
67 In [1]: l
77 In [1]: l
68 Out[1]: ['hello', 10, 'world']
78 Out[1]: ['hello', 10, 'world']
69
79
70 Usage:
80 Usage:
71
81
72 * ``%store`` - Show list of all variables and their current values
82 * ``%store`` - Show list of all variables and their current
73 * ``%store spam`` - Store the *current* value of the variable spam to disk
83 values
84 * ``%store spam`` - Store the *current* value of the variable spam
85 to disk
74 * ``%store -d spam`` - Remove the variable and its value from storage
86 * ``%store -d spam`` - Remove the variable and its value from storage
75 * ``%store -z`` - Remove all variables from storage
87 * ``%store -z`` - Remove all variables from storage
76 * ``%store -r`` - Refresh all variables from store (delete current vals)
88 * ``%store -r`` - Refresh all variables from store (delete
89 current vals)
77 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
90 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
78 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
91 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
79
92
80 It should be noted that if you change the value of a variable, you
93 It should be noted that if you change the value of a variable, you
81 need to %store it again if you want to persist the new value.
94 need to %store it again if you want to persist the new value.
82
95
83 Note also that the variables will need to be pickleable; most basic
96 Note also that the variables will need to be pickleable; most basic
84 python types can be safely %store'd.
97 python types can be safely %store'd.
85
98
86 Also aliases can be %store'd across sessions.
99 Also aliases can be %store'd across sessions.
87 """
100 """
88
101
89 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
102 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
90 args = argsl.split(None,1)
103 args = argsl.split(None,1)
91 ip = self.shell
104 ip = self.shell
92 db = ip.db
105 db = ip.db
93 # delete
106 # delete
94 if opts.has_key('d'):
107 if opts.has_key('d'):
95 try:
108 try:
96 todel = args[0]
109 todel = args[0]
97 except IndexError:
110 except IndexError:
98 raise UsageError('You must provide the variable to forget')
111 raise UsageError('You must provide the variable to forget')
99 else:
112 else:
100 try:
113 try:
101 del db['autorestore/' + todel]
114 del db['autorestore/' + todel]
102 except:
115 except:
103 raise UsageError("Can't delete variable '%s'" % todel)
116 raise UsageError("Can't delete variable '%s'" % todel)
104 # reset
117 # reset
105 elif opts.has_key('z'):
118 elif opts.has_key('z'):
106 for k in db.keys('autorestore/*'):
119 for k in db.keys('autorestore/*'):
107 del db[k]
120 del db[k]
108
121
109 elif opts.has_key('r'):
122 elif opts.has_key('r'):
110 refresh_variables(ip)
123 refresh_variables(ip)
111
124
112
125
113 # run without arguments -> list variables & values
126 # run without arguments -> list variables & values
114 elif not args:
127 elif not args:
115 vars = self.db.keys('autorestore/*')
128 vars = self.db.keys('autorestore/*')
116 vars.sort()
129 vars.sort()
117 if vars:
130 if vars:
118 size = max(map(len,vars))
131 size = max(map(len,vars))
119 else:
132 else:
120 size = 0
133 size = 0
121
134
122 print 'Stored variables and their in-db values:'
135 print 'Stored variables and their in-db values:'
123 fmt = '%-'+str(size)+'s -> %s'
136 fmt = '%-'+str(size)+'s -> %s'
124 get = db.get
137 get = db.get
125 for var in vars:
138 for var in vars:
126 justkey = os.path.basename(var)
139 justkey = os.path.basename(var)
127 # print 30 first characters from every var
140 # print 30 first characters from every var
128 print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
141 print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
129
142
130 # default action - store the variable
143 # default action - store the variable
131 else:
144 else:
132 # %store foo >file.txt or >>file.txt
145 # %store foo >file.txt or >>file.txt
133 if len(args) > 1 and args[1].startswith('>'):
146 if len(args) > 1 and args[1].startswith('>'):
134 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
147 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
135 if args[1].startswith('>>'):
148 if args[1].startswith('>>'):
136 fil = open(fnam,'a')
149 fil = open(fnam,'a')
137 else:
150 else:
138 fil = open(fnam,'w')
151 fil = open(fnam,'w')
139 obj = ip.ev(args[0])
152 obj = ip.ev(args[0])
140 print "Writing '%s' (%s) to file '%s'." % (args[0],
153 print "Writing '%s' (%s) to file '%s'." % (args[0],
141 obj.__class__.__name__, fnam)
154 obj.__class__.__name__, fnam)
142
155
143
156
144 if not isinstance (obj,basestring):
157 if not isinstance (obj,basestring):
145 from pprint import pprint
158 from pprint import pprint
146 pprint(obj,fil)
159 pprint(obj,fil)
147 else:
160 else:
148 fil.write(obj)
161 fil.write(obj)
149 if not obj.endswith('\n'):
162 if not obj.endswith('\n'):
150 fil.write('\n')
163 fil.write('\n')
151
164
152 fil.close()
165 fil.close()
153 return
166 return
154
167
155 # %store foo
168 # %store foo
156 try:
169 try:
157 obj = ip.user_ns[args[0]]
170 obj = ip.user_ns[args[0]]
158 except KeyError:
171 except KeyError:
159 # it might be an alias
172 # it might be an alias
160 # This needs to be refactored to use the new AliasManager stuff.
173 # This needs to be refactored to use the new AliasManager stuff.
161 if args[0] in self.alias_manager:
174 if args[0] in self.alias_manager:
162 name = args[0]
175 name = args[0]
163 nargs, cmd = self.alias_manager.alias_table[ name ]
176 nargs, cmd = self.alias_manager.alias_table[ name ]
164 staliases = db.get('stored_aliases',{})
177 staliases = db.get('stored_aliases',{})
165 staliases[ name ] = cmd
178 staliases[ name ] = cmd
166 db['stored_aliases'] = staliases
179 db['stored_aliases'] = staliases
167 print "Alias stored: %s (%s)" % (name, cmd)
180 print "Alias stored: %s (%s)" % (name, cmd)
168 return
181 return
169 else:
182 else:
170 raise UsageError("Unknown variable '%s'" % args[0])
183 raise UsageError("Unknown variable '%s'" % args[0])
171
184
172 else:
185 else:
173 if isinstance(inspect.getmodule(obj), FakeModule):
186 if isinstance(inspect.getmodule(obj), FakeModule):
174 print textwrap.dedent("""\
187 print textwrap.dedent("""\
175 Warning:%s is %s
188 Warning:%s is %s
176 Proper storage of interactively declared classes (or instances
189 Proper storage of interactively declared classes (or instances
177 of those classes) is not possible! Only instances
190 of those classes) is not possible! Only instances
178 of classes in real modules on file system can be %%store'd.
191 of classes in real modules on file system can be %%store'd.
179 """ % (args[0], obj) )
192 """ % (args[0], obj) )
180 return
193 return
181 #pickled = pickle.dumps(obj)
194 #pickled = pickle.dumps(obj)
182 self.db[ 'autorestore/' + args[0] ] = obj
195 self.db[ 'autorestore/' + args[0] ] = obj
183 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
196 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
184
197
185
198
186 class StoreMagic(Plugin):
199 class StoreMagic(Plugin):
187 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
200 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
188 autorestore = Bool(False, config=True)
201 autorestore = Bool(False, config=True)
189
202
190 def __init__(self, shell, config):
203 def __init__(self, shell, config):
191 super(StoreMagic, self).__init__(shell=shell, config=config)
204 super(StoreMagic, self).__init__(shell=shell, config=config)
192 shell.define_magic('store', magic_store)
205 shell.register_magics(StoreMagics)
193
206
194 if self.autorestore:
207 if self.autorestore:
195 restore_data(shell)
208 restore_data(shell)
196
209
210
197 _loaded = False
211 _loaded = False
198
212
199 def load_ipython_extension(ip):
213 def load_ipython_extension(ip):
200 """Load the extension in IPython."""
214 """Load the extension in IPython."""
201 global _loaded
215 global _loaded
202 if not _loaded:
216 if not _loaded:
203 plugin = StoreMagic(shell=ip, config=ip.config)
217 plugin = StoreMagic(shell=ip, config=ip.config)
204 ip.plugin_manager.register_plugin('storemagic', plugin)
218 ip.plugin_manager.register_plugin('storemagic', plugin)
205 _loaded = True
219 _loaded = True
General Comments 0
You need to be logged in to leave comments. Login now