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