##// END OF EJS Templates
Implement magic registration and listing in magics manager.
Fernando Perez -
Show More
@@ -1,326 +1,328 b''
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 from getopt import getopt, GetoptError
21 from getopt import getopt, GetoptError
22
22
23 # Our own
23 # Our own
24 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
25 from IPython.core import oinspect
25 from IPython.core import oinspect
26 from IPython.core.error import UsageError
26 from IPython.core.error import UsageError
27 from IPython.core.prefilter import ESC_MAGIC
27 from IPython.core.prefilter import ESC_MAGIC
28 from IPython.external.decorator import decorator
28 from IPython.external.decorator import decorator
29 from IPython.utils.ipstruct import Struct
29 from IPython.utils.ipstruct import Struct
30 from IPython.utils.process import arg_split
30 from IPython.utils.process import arg_split
31 from IPython.utils.traitlets import Dict, Enum, Instance
31 from IPython.utils.traitlets import Dict, Enum, Instance
32 from IPython.utils.warn import error
32 from IPython.utils.warn import error
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Globals
35 # Globals
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 line_magics = {}
37 line_magics = {}
38 cell_magics = {}
38 cell_magics = {}
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Utility classes and functions
41 # Utility classes and functions
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 class Bunch: pass
44 class Bunch: pass
45
45
46
46
47 # Used for exception handling in magic_edit
47 # Used for exception handling in magic_edit
48 class MacroToEdit(ValueError): pass
48 class MacroToEdit(ValueError): pass
49
49
50
50
51 def on_off(tag):
51 def on_off(tag):
52 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
52 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
53 return ['OFF','ON'][tag]
53 return ['OFF','ON'][tag]
54
54
55
55
56 def compress_dhist(dh):
56 def compress_dhist(dh):
57 head, tail = dh[:-10], dh[-10:]
57 head, tail = dh[:-10], dh[-10:]
58
58
59 newhead = []
59 newhead = []
60 done = set()
60 done = set()
61 for h in head:
61 for h in head:
62 if h in done:
62 if h in done:
63 continue
63 continue
64 newhead.append(h)
64 newhead.append(h)
65 done.add(h)
65 done.add(h)
66
66
67 return newhead + tail
67 return newhead + tail
68
68
69
69
70 def needs_local_scope(func):
70 def needs_local_scope(func):
71 """Decorator to mark magic functions which need to local scope to run."""
71 """Decorator to mark magic functions which need to local scope to run."""
72 func.needs_local_scope = True
72 func.needs_local_scope = True
73 return func
73 return func
74
74
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76 # Class and method decorators for registering magics
76 # Class and method decorators for registering magics
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78
78
79 def register_magics(cls):
79 def register_magics(cls):
80 global line_magics, cell_magics
80 global line_magics, cell_magics
81
81
82 cls.line_magics = line_magics
82 cls.line_magics = line_magics
83 cls.cell_magics = cell_magics
83 cls.cell_magics = cell_magics
84 cls.registered = True
84 cls.registered = True
85 line_magics = {}
85 line_magics = {}
86 cell_magics = {}
86 cell_magics = {}
87 return cls
87 return cls
88
88
89
89
90 def _magic_marker(magic_type):
90 def _magic_marker(magic_type):
91 global line_magics, cell_magics
91 global line_magics, cell_magics
92
92
93 if magic_type not in ('line', 'cell'):
93 if magic_type not in ('line', 'cell'):
94 raise ValueError('magic_type must be one of ["line", "cell"], %s given'
94 raise ValueError('magic_type must be one of ["line", "cell"], %s given'
95 % magic_type)
95 % magic_type)
96 if magic_type == 'line':
96 if magic_type == 'line':
97 line_magics = {}
97 line_magics = {}
98 else:
98 else:
99 cell_magics = {}
99 cell_magics = {}
100
100
101 # This is a closure to capture the magic_type. We could also use a class,
101 # This is a closure to capture the magic_type. We could also use a class,
102 # but it's overkill for just that one bit of state.
102 # but it's overkill for just that one bit of state.
103 def magic_deco(arg):
103 def magic_deco(arg):
104 global line_magics, cell_magics
104 global line_magics, cell_magics
105 call = lambda f, *a, **k: f(*a, **k)
105 call = lambda f, *a, **k: f(*a, **k)
106
106
107 if callable(arg):
107 if callable(arg):
108 # "Naked" decorator call (just @foo, no args)
108 # "Naked" decorator call (just @foo, no args)
109 func = arg
109 func = arg
110 name = func.func_name
110 name = func.func_name
111 func.magic_name = name
111 func.magic_name = name
112 retval = decorator(call, func)
112 retval = decorator(call, func)
113 elif isinstance(arg, basestring):
113 elif isinstance(arg, basestring):
114 # Decorator called with arguments (@foo('bar'))
114 # Decorator called with arguments (@foo('bar'))
115 name = arg
115 name = arg
116 def mark(func, *a, **kw):
116 def mark(func, *a, **kw):
117 func.magic_name = name
117 func.magic_name = name
118 return decorator(call, func)
118 return decorator(call, func)
119 retval = mark
119 retval = mark
120 else:
120 else:
121 raise ValueError("Decorator can only be called with "
121 raise ValueError("Decorator can only be called with "
122 "string or function")
122 "string or function")
123 # Record the magic function in the global table that will then be
123 # Record the magic function in the global table that will then be
124 # appended to the class via the register_magics class decorator
124 # appended to the class via the register_magics class decorator
125 if magic_type == 'line':
125 if magic_type == 'line':
126 line_magics[name] = retval
126 line_magics[name] = retval
127 else:
127 else:
128 cell_magics[name] = retval
128 cell_magics[name] = retval
129
129
130 return retval
130 return retval
131
131
132 return magic_deco
132 return magic_deco
133
133
134
134
135 line_magic = _magic_marker('line')
135 line_magic = _magic_marker('line')
136 cell_magic = _magic_marker('cell')
136 cell_magic = _magic_marker('cell')
137
137
138 #-----------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
139 # Core Magic classes
139 # Core Magic classes
140 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141
141
142 class MagicManager(Configurable):
142 class MagicManager(Configurable):
143 """Object that handles all magic-related functionality for IPython.
143 """Object that handles all magic-related functionality for IPython.
144 """
144 """
145 # Non-configurable class attributes
146 line_magics = Dict
147 cell_magics = Dict
148
145 # An instance of the IPython shell we are attached to
149 # An instance of the IPython shell we are attached to
146 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
150 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
147
151
148 auto_status = Enum([
152 auto_status = Enum([
149 'Automagic is OFF, % prefix IS needed for magic functions.',
153 'Automagic is OFF, % prefix IS needed for magic functions.',
150 'Automagic is ON, % prefix NOT needed for magic functions.'])
154 'Automagic is ON, % prefix NOT needed for magic functions.'])
151
155
152 def __init__(self, shell=None, config=None, **traits):
156 def __init__(self, shell=None, config=None, **traits):
153
157
154 super(MagicManager, self).__init__(shell=shell, config=config, **traits)
158 super(MagicManager, self).__init__(shell=shell, config=config, **traits)
155
159
156
160
157 def lsmagic(self):
161 def lsmagic(self):
158 """Return a list of currently available magic functions.
162 """Return a dict of currently available magic functions.
159
163
160 Gives a list of the bare names after mangling (['ls','cd', ...], not
164 The return dict has the keys 'line' and 'cell', corresponding to the
161 ['magic_ls','magic_cd',...]"""
165 two types of magics we support. Each value is a list of names.
162
166 """
163 # FIXME. This needs a cleanup, in the way the magics list is built.
167
164
168 return dict(line = sorted(self.line_magics),
165 # magics in class definition
169 cell = sorted(self.cell_magics))
166 class_magic = lambda fn: fn.startswith('magic_') and \
170
167 callable(Magic.__dict__[fn])
171 def register(self, *magics):
168 # in instance namespace (run-time user additions)
172 """Register one or more instances of Magics.
169 inst_magic = lambda fn: fn.startswith('magic_') and \
173 """
170 callable(self.__dict__[fn])
174 # Start by validating them to ensure they have all had their magic
171 # and bound magics by user (so they can access self):
175 # methods registered at the instance level
172 inst_bound_magic = lambda fn: fn.startswith('magic_') and \
176 for m in magics:
173 callable(self.__class__.__dict__[fn])
177 if not m.registered:
174 magics = filter(class_magic, Magic.__dict__.keys()) + \
178 raise ValueError("Class of magics %r was constructed without "
175 filter(inst_magic, self.__dict__.keys()) + \
179 "the @register_macics class decorator")
176 filter(inst_bound_magic, self.__class__.__dict__.keys())
180 self.line_magics.update(m.line_magics)
177 out = []
181 self.cell_magics.update(m.cell_magics)
178 for fn in set(magics):
182
179 out.append(fn.replace('magic_', '', 1))
183
180 out.sort()
181 return out
182
184
183 # Key base class that provides the central functionality for magics.
185 # Key base class that provides the central functionality for magics.
184
186
185 class Magics(object):
187 class Magics(object):
186 """Base class for implementing magic functions.
188 """Base class for implementing magic functions.
187
189
188 Shell functions which can be reached as %function_name. All magic
190 Shell functions which can be reached as %function_name. All magic
189 functions should accept a string, which they can parse for their own
191 functions should accept a string, which they can parse for their own
190 needs. This can make some functions easier to type, eg `%cd ../`
192 needs. This can make some functions easier to type, eg `%cd ../`
191 vs. `%cd("../")`
193 vs. `%cd("../")`
192
194
193 Classes providing magic functions need to subclass this class, and they
195 Classes providing magic functions need to subclass this class, and they
194 MUST:
196 MUST:
195
197
196 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
198 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
197 individual methods as magic functions, AND
199 individual methods as magic functions, AND
198
200
199 - Use the class decorator `@register_magics` to ensure that the magic
201 - Use the class decorator `@register_magics` to ensure that the magic
200 methods are properly registered at the instance level upon instance
202 methods are properly registered at the instance level upon instance
201 initialization.
203 initialization.
202
204
203 See :mod:`magic_functions` for examples of actual implementation classes.
205 See :mod:`magic_functions` for examples of actual implementation classes.
204 """
206 """
205
207
206 options_table = Dict(config=True,
208 options_table = Dict(config=True,
207 help = """Dict holding all command-line options for each magic.
209 help = """Dict holding all command-line options for each magic.
208 """)
210 """)
209
211
210 class __metaclass__(type):
212 class __metaclass__(type):
211 def __new__(cls, name, bases, dct):
213 def __new__(cls, name, bases, dct):
212 cls.registered = False
214 cls.registered = False
213 return type.__new__(cls, name, bases, dct)
215 return type.__new__(cls, name, bases, dct)
214
216
215 def __init__(self, shell):
217 def __init__(self, shell):
216 if not(self.__class__.registered):
218 if not(self.__class__.registered):
217 raise ValueError('unregistered Magics')
219 raise ValueError('unregistered Magics')
218 self.shell = shell
220 self.shell = shell
219
221
220 def arg_err(self,func):
222 def arg_err(self,func):
221 """Print docstring if incorrect arguments were passed"""
223 """Print docstring if incorrect arguments were passed"""
222 print 'Error in arguments:'
224 print 'Error in arguments:'
223 print oinspect.getdoc(func)
225 print oinspect.getdoc(func)
224
226
225 def format_latex(self,strng):
227 def format_latex(self,strng):
226 """Format a string for latex inclusion."""
228 """Format a string for latex inclusion."""
227
229
228 # Characters that need to be escaped for latex:
230 # Characters that need to be escaped for latex:
229 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
231 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
230 # Magic command names as headers:
232 # Magic command names as headers:
231 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
233 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
232 re.MULTILINE)
234 re.MULTILINE)
233 # Magic commands
235 # Magic commands
234 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
236 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
235 re.MULTILINE)
237 re.MULTILINE)
236 # Paragraph continue
238 # Paragraph continue
237 par_re = re.compile(r'\\$',re.MULTILINE)
239 par_re = re.compile(r'\\$',re.MULTILINE)
238
240
239 # The "\n" symbol
241 # The "\n" symbol
240 newline_re = re.compile(r'\\n')
242 newline_re = re.compile(r'\\n')
241
243
242 # Now build the string for output:
244 # Now build the string for output:
243 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
245 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
244 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
246 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
245 strng)
247 strng)
246 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
248 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
247 strng = par_re.sub(r'\\\\',strng)
249 strng = par_re.sub(r'\\\\',strng)
248 strng = escape_re.sub(r'\\\1',strng)
250 strng = escape_re.sub(r'\\\1',strng)
249 strng = newline_re.sub(r'\\textbackslash{}n',strng)
251 strng = newline_re.sub(r'\\textbackslash{}n',strng)
250 return strng
252 return strng
251
253
252 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
254 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
253 """Parse options passed to an argument string.
255 """Parse options passed to an argument string.
254
256
255 The interface is similar to that of getopt(), but it returns back a
257 The interface is similar to that of getopt(), but it returns back a
256 Struct with the options as keys and the stripped argument string still
258 Struct with the options as keys and the stripped argument string still
257 as a string.
259 as a string.
258
260
259 arg_str is quoted as a true sys.argv vector by using shlex.split.
261 arg_str is quoted as a true sys.argv vector by using shlex.split.
260 This allows us to easily expand variables, glob files, quote
262 This allows us to easily expand variables, glob files, quote
261 arguments, etc.
263 arguments, etc.
262
264
263 Options:
265 Options:
264 -mode: default 'string'. If given as 'list', the argument string is
266 -mode: default 'string'. If given as 'list', the argument string is
265 returned as a list (split on whitespace) instead of a string.
267 returned as a list (split on whitespace) instead of a string.
266
268
267 -list_all: put all option values in lists. Normally only options
269 -list_all: put all option values in lists. Normally only options
268 appearing more than once are put in a list.
270 appearing more than once are put in a list.
269
271
270 -posix (True): whether to split the input line in POSIX mode or not,
272 -posix (True): whether to split the input line in POSIX mode or not,
271 as per the conventions outlined in the shlex module from the
273 as per the conventions outlined in the shlex module from the
272 standard library."""
274 standard library."""
273
275
274 # inject default options at the beginning of the input line
276 # inject default options at the beginning of the input line
275 caller = sys._getframe(1).f_code.co_name.replace('magic_','')
277 caller = sys._getframe(1).f_code.co_name.replace('magic_','')
276 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
278 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
277
279
278 mode = kw.get('mode','string')
280 mode = kw.get('mode','string')
279 if mode not in ['string','list']:
281 if mode not in ['string','list']:
280 raise ValueError,'incorrect mode given: %s' % mode
282 raise ValueError,'incorrect mode given: %s' % mode
281 # Get options
283 # Get options
282 list_all = kw.get('list_all',0)
284 list_all = kw.get('list_all',0)
283 posix = kw.get('posix', os.name == 'posix')
285 posix = kw.get('posix', os.name == 'posix')
284 strict = kw.get('strict', True)
286 strict = kw.get('strict', True)
285
287
286 # Check if we have more than one argument to warrant extra processing:
288 # Check if we have more than one argument to warrant extra processing:
287 odict = {} # Dictionary with options
289 odict = {} # Dictionary with options
288 args = arg_str.split()
290 args = arg_str.split()
289 if len(args) >= 1:
291 if len(args) >= 1:
290 # If the list of inputs only has 0 or 1 thing in it, there's no
292 # If the list of inputs only has 0 or 1 thing in it, there's no
291 # need to look for options
293 # need to look for options
292 argv = arg_split(arg_str, posix, strict)
294 argv = arg_split(arg_str, posix, strict)
293 # Do regular option processing
295 # Do regular option processing
294 try:
296 try:
295 opts,args = getopt(argv,opt_str,*long_opts)
297 opts,args = getopt(argv,opt_str,*long_opts)
296 except GetoptError,e:
298 except GetoptError,e:
297 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
299 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
298 " ".join(long_opts)))
300 " ".join(long_opts)))
299 for o,a in opts:
301 for o,a in opts:
300 if o.startswith('--'):
302 if o.startswith('--'):
301 o = o[2:]
303 o = o[2:]
302 else:
304 else:
303 o = o[1:]
305 o = o[1:]
304 try:
306 try:
305 odict[o].append(a)
307 odict[o].append(a)
306 except AttributeError:
308 except AttributeError:
307 odict[o] = [odict[o],a]
309 odict[o] = [odict[o],a]
308 except KeyError:
310 except KeyError:
309 if list_all:
311 if list_all:
310 odict[o] = [a]
312 odict[o] = [a]
311 else:
313 else:
312 odict[o] = a
314 odict[o] = a
313
315
314 # Prepare opts,args for return
316 # Prepare opts,args for return
315 opts = Struct(odict)
317 opts = Struct(odict)
316 if mode == 'string':
318 if mode == 'string':
317 args = ' '.join(args)
319 args = ' '.join(args)
318
320
319 return opts,args
321 return opts,args
320
322
321 def default_option(self,fn,optstr):
323 def default_option(self,fn,optstr):
322 """Make an entry in the options_table for fn, with value optstr"""
324 """Make an entry in the options_table for fn, with value optstr"""
323
325
324 if fn not in self.lsmagic():
326 if fn not in self.lsmagic():
325 error("%s is not a magic function" % fn)
327 error("%s is not a magic function" % fn)
326 self.options_table[fn] = optstr
328 self.options_table[fn] = optstr
General Comments 0
You need to be logged in to leave comments. Login now