magic.py
387 lines
| 14.2 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2498 | # encoding: utf-8 | ||
Ville M. Vainio
|
r1032 | """Magic functions for InteractiveShell. | ||
Fernando Perez
|
r1853 | """ | ||
Ville M. Vainio
|
r1032 | |||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and | ||||
Fernando Perez
|
r6917 | # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu> | ||
# Copyright (C) 2008 The IPython Development Team | ||||
Brian Granger
|
r2498 | |||
Ville M. Vainio
|
r1032 | # Distributed under the terms of the BSD License. The full license is in | ||
# the file COPYING, distributed as part of this software. | ||||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
Ville M. Vainio
|
r1032 | |||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
Fernando Perez
|
r6919 | # Stdlib | ||
Ville M. Vainio
|
r1032 | import os | ||
import re | ||||
Fernando Perez
|
r6917 | import sys | ||
Fernando Perez
|
r6923 | import types | ||
Fernando Perez
|
r6919 | from getopt import getopt, GetoptError | ||
# Our own | ||||
Fernando Perez
|
r6917 | from IPython.config.configurable import Configurable | ||
Fernando Perez
|
r6919 | from IPython.core import oinspect | ||
Fernando Perez
|
r2363 | from IPython.core.error import UsageError | ||
Brian Granger
|
r2245 | from IPython.core.prefilter import ESC_MAGIC | ||
Fernando Perez
|
r6919 | from IPython.external.decorator import decorator | ||
Fernando Perez
|
r6917 | from IPython.utils.ipstruct import Struct | ||
Fernando Perez
|
r6919 | from IPython.utils.process import arg_split | ||
Fernando Perez
|
r6922 | from IPython.utils.traitlets import Bool, Dict, Instance | ||
Fernando Perez
|
r6936 | from IPython.utils.warn import error, warn | ||
Fernando Perez
|
r6919 | |||
#----------------------------------------------------------------------------- | ||||
# Globals | ||||
#----------------------------------------------------------------------------- | ||||
Fernando Perez
|
r6922 | |||
# A dict we'll use for each class that has magics, used as temporary storage to | ||||
# pass information between the @line/cell_magic method decorators and the | ||||
# @register_magics class decorator, because the method decorators have no | ||||
# access to the class when they run. See for more details: | ||||
# http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class | ||||
Fernando Perez
|
r6923 | magics = dict(line={}, cell={}) | ||
magic_types = ('line', 'cell') | ||||
Fernando Perez
|
r6953 | magic_spec = ('line', 'cell', 'line_cell') | ||
Fernando Perez
|
r2363 | |||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
Fernando Perez
|
r6917 | # Utility classes and functions | ||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
Fernando Perez
|
r6917 | class Bunch: pass | ||
Ville M. Vainio
|
r1032 | def on_off(tag): | ||
"""Return an ON/OFF string for a 1/0 input. Simple utility function.""" | ||||
return ['OFF','ON'][tag] | ||||
def compress_dhist(dh): | ||||
head, tail = dh[:-10], dh[-10:] | ||||
newhead = [] | ||||
Fernando Perez
|
r1860 | done = set() | ||
Ville M. Vainio
|
r1032 | for h in head: | ||
if h in done: | ||||
continue | ||||
newhead.append(h) | ||||
done.add(h) | ||||
Bernardo B. Marques
|
r4872 | return newhead + tail | ||
Fernando Perez
|
r2358 | |||
Fernando Perez
|
r6917 | |||
Thomas Kluyver
|
r3479 | def needs_local_scope(func): | ||
"""Decorator to mark magic functions which need to local scope to run.""" | ||||
func.needs_local_scope = True | ||||
return func | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6919 | #----------------------------------------------------------------------------- | ||
# Class and method decorators for registering magics | ||||
#----------------------------------------------------------------------------- | ||||
def register_magics(cls): | ||||
cls.registered = True | ||||
Fernando Perez
|
r6923 | cls.magics = dict(line = magics['line'], | ||
cell = magics['cell']) | ||||
magics['line'] = {} | ||||
magics['cell'] = {} | ||||
Fernando Perez
|
r6919 | return cls | ||
Fernando Perez
|
r6953 | |||
def record_magic(dct, mtype, mname, func): | ||||
Fernando Perez
|
r6933 | if mtype == 'line_cell': | ||
dct['line'][mname] = dct['cell'][mname] = func | ||||
else: | ||||
dct[mtype][mname] = func | ||||
Fernando Perez
|
r6919 | |||
Fernando Perez
|
r6953 | |||
Fernando Perez
|
r6923 | def validate_type(magic_type): | ||
Fernando Perez
|
r6953 | if magic_type not in magic_spec: | ||
Fernando Perez
|
r6923 | raise ValueError('magic_type must be one of %s, %s given' % | ||
magic_types, magic_type) | ||||
Fernando Perez
|
r6919 | |||
Fernando Perez
|
r6922 | |||
Fernando Perez
|
r6923 | def _magic_marker(magic_type): | ||
validate_type(magic_type) | ||||
Fernando Perez
|
r6919 | |||
# This is a closure to capture the magic_type. We could also use a class, | ||||
# but it's overkill for just that one bit of state. | ||||
def magic_deco(arg): | ||||
call = lambda f, *a, **k: f(*a, **k) | ||||
if callable(arg): | ||||
# "Naked" decorator call (just @foo, no args) | ||||
func = arg | ||||
name = func.func_name | ||||
func.magic_name = name | ||||
retval = decorator(call, func) | ||||
Fernando Perez
|
r6953 | record_magic(magics, magic_type, name, name) | ||
Fernando Perez
|
r6919 | elif isinstance(arg, basestring): | ||
# Decorator called with arguments (@foo('bar')) | ||||
name = arg | ||||
def mark(func, *a, **kw): | ||||
func.magic_name = name | ||||
Fernando Perez
|
r6953 | record_magic(magics, magic_type, name, func.func_name) | ||
Fernando Perez
|
r6919 | return decorator(call, func) | ||
retval = mark | ||||
else: | ||||
raise ValueError("Decorator can only be called with " | ||||
"string or function") | ||||
return retval | ||||
return magic_deco | ||||
line_magic = _magic_marker('line') | ||||
cell_magic = _magic_marker('cell') | ||||
Fernando Perez
|
r6953 | line_cell_magic = _magic_marker('line_cell') | ||
Fernando Perez
|
r6919 | |||
#----------------------------------------------------------------------------- | ||||
# Core Magic classes | ||||
#----------------------------------------------------------------------------- | ||||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r6923 | class MagicsManager(Configurable): | ||
Fernando Perez
|
r6917 | """Object that handles all magic-related functionality for IPython. | ||
""" | ||||
Fernando Perez
|
r6921 | # Non-configurable class attributes | ||
Fernando Perez
|
r6949 | |||
# A two-level dict, first keyed by magic type, then by magic function, and | ||||
# holding the actual callable object as value. This is the dict used for | ||||
# magic function dispatch | ||||
Fernando Perez
|
r6922 | magics = Dict | ||
Fernando Perez
|
r6921 | |||
Fernando Perez
|
r6949 | # A registry of the original objects that we've been given holding magics. | ||
registry = Dict | ||||
Fernando Perez
|
r6917 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | ||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r6922 | auto_magic = Bool | ||
_auto_status = [ | ||||
Fernando Perez
|
r6917 | 'Automagic is OFF, % prefix IS needed for magic functions.', | ||
Fernando Perez
|
r6922 | 'Automagic is ON, % prefix IS NOT needed for magic functions.'] | ||
MinRK
|
r5225 | |||
Fernando Perez
|
r6957 | user_magics = Instance('IPython.core.magics.UserMagics') | ||
Fernando Perez
|
r6910 | |||
Fernando Perez
|
r6923 | def __init__(self, shell=None, config=None, user_magics=None, **traits): | ||
super(MagicsManager, self).__init__(shell=shell, config=config, | ||||
user_magics=user_magics, **traits) | ||||
Fernando Perez
|
r6924 | self.magics = dict(line={}, cell={}) | ||
Fernando Perez
|
r6949 | # Let's add the user_magics to the registry for uniformity, so *all* | ||
# registered magic containers can be found there. | ||||
self.registry[user_magics.__class__.__name__] = user_magics | ||||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r6922 | def auto_status(self): | ||
"""Return descriptive string with automagic status.""" | ||||
return self._auto_status[self.auto_magic] | ||||
Ville M. Vainio
|
r1032 | |||
def lsmagic(self): | ||||
Fernando Perez
|
r6921 | """Return a dict of currently available magic functions. | ||
The return dict has the keys 'line' and 'cell', corresponding to the | ||||
two types of magics we support. Each value is a list of names. | ||||
""" | ||||
Fernando Perez
|
r6922 | return self.magics | ||
Fernando Perez
|
r6921 | |||
Fernando Perez
|
r6924 | def register(self, *magic_objects): | ||
Fernando Perez
|
r6921 | """Register one or more instances of Magics. | ||
""" | ||||
# Start by validating them to ensure they have all had their magic | ||||
# methods registered at the instance level | ||||
Fernando Perez
|
r6924 | for m in magic_objects: | ||
Fernando Perez
|
r6921 | if not m.registered: | ||
raise ValueError("Class of magics %r was constructed without " | ||||
"the @register_macics class decorator") | ||||
Fernando Perez
|
r6927 | if type(m) is type: | ||
# If we're given an uninstantiated class | ||||
m = m(self.shell) | ||||
Fernando Perez
|
r6949 | # Now that we have an instance, we can register it and update the | ||
# table of callables | ||||
self.registry[m.__class__.__name__] = m | ||||
Fernando Perez
|
r6924 | for mtype in magic_types: | ||
self.magics[mtype].update(m.magics[mtype]) | ||||
Fernando Perez
|
r6921 | |||
Fernando Perez
|
r6954 | def register_function(self, func, magic_type='line', magic_name=None): | ||
Fernando Perez
|
r6935 | """Expose a standalone function as magic function for ipython. | ||
Fernando Perez
|
r6923 | """ | ||
Fernando Perez
|
r6933 | |||
Fernando Perez
|
r6923 | # Create the new method in the user_magics and register it in the | ||
# global table | ||||
Fernando Perez
|
r6936 | validate_type(magic_type) | ||
magic_name = func.func_name if magic_name is None else magic_name | ||||
setattr(self.user_magics, magic_name, func) | ||||
Fernando Perez
|
r6953 | record_magic(self.magics, magic_type, magic_name, func) | ||
Fernando Perez
|
r6936 | |||
Fernando Perez
|
r6954 | def define_magic(self, name, func): | ||
Fernando Perez
|
r6936 | """Support for deprecated API. | ||
This method exists only to support the old-style definition of magics. | ||||
It will eventually be removed. Deliberately not documented further. | ||||
""" | ||||
meth = types.MethodType(func, self.user_magics) | ||||
setattr(self.user_magics, name, meth) | ||||
Fernando Perez
|
r6953 | record_magic(self.magics, 'line', name, meth) | ||
Fernando Perez
|
r6936 | |||
Fernando Perez
|
r6919 | # Key base class that provides the central functionality for magics. | ||
Fernando Perez
|
r6917 | |||
Fernando Perez
|
r6919 | class Magics(object): | ||
Fernando Perez
|
r6917 | """Base class for implementing magic functions. | ||
Shell functions which can be reached as %function_name. All magic | ||||
functions should accept a string, which they can parse for their own | ||||
needs. This can make some functions easier to type, eg `%cd ../` | ||||
vs. `%cd("../")` | ||||
Fernando Perez
|
r6919 | |||
Classes providing magic functions need to subclass this class, and they | ||||
MUST: | ||||
- Use the method decorators `@line_magic` and `@cell_magic` to decorate | ||||
individual methods as magic functions, AND | ||||
- Use the class decorator `@register_magics` to ensure that the magic | ||||
methods are properly registered at the instance level upon instance | ||||
initialization. | ||||
See :mod:`magic_functions` for examples of actual implementation classes. | ||||
Fernando Perez
|
r6917 | """ | ||
Fernando Perez
|
r6923 | # Dict holding all command-line options for each magic. | ||
options_table = None | ||||
Fernando Perez
|
r6929 | # Dict for the mapping of magic names to methods, set by class decorator | ||
magics = None | ||||
# Flag to check that the class decorator was properly applied | ||||
Fernando Perez
|
r6927 | registered = False | ||
Fernando Perez
|
r6930 | # Instance of IPython shell | ||
shell = None | ||||
Fernando Perez
|
r6917 | |||
def __init__(self, shell): | ||||
if not(self.__class__.registered): | ||||
Fernando Perez
|
r6930 | raise ValueError('Magics subclass without registration - ' | ||
'did you forget to apply @register_magics?') | ||||
Fernando Perez
|
r6917 | self.shell = shell | ||
Fernando Perez
|
r6929 | self.options_table = {} | ||
Fernando Perez
|
r6930 | # The method decorators are run when the instance doesn't exist yet, so | ||
# they can only record the names of the methods they are supposed to | ||||
# grab. Only now, that the instance exists, can we create the proper | ||||
# mapping to bound methods. So we read the info off the original names | ||||
# table and replace each method name by the actual bound method. | ||||
Fernando Perez
|
r6924 | for mtype in magic_types: | ||
Fernando Perez
|
r6930 | tab = self.magics[mtype] | ||
# must explicitly use keys, as we're mutating this puppy | ||||
for magic_name in tab.keys(): | ||||
meth_name = tab[magic_name] | ||||
Fernando Perez
|
r6927 | if isinstance(meth_name, basestring): | ||
tab[magic_name] = getattr(self, meth_name) | ||||
Fernando Perez
|
r6917 | |||
Ville M. Vainio
|
r1032 | def arg_err(self,func): | ||
"""Print docstring if incorrect arguments were passed""" | ||||
print 'Error in arguments:' | ||||
Brian Granger
|
r2498 | print oinspect.getdoc(func) | ||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r6929 | def format_latex(self, strng): | ||
Ville M. Vainio
|
r1032 | """Format a string for latex inclusion.""" | ||
# Characters that need to be escaped for latex: | ||||
escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE) | ||||
# Magic command names as headers: | ||||
Brian Granger
|
r2245 | cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC, | ||
Ville M. Vainio
|
r1032 | re.MULTILINE) | ||
Bernardo B. Marques
|
r4872 | # Magic commands | ||
Brian Granger
|
r2245 | cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC, | ||
Ville M. Vainio
|
r1032 | re.MULTILINE) | ||
# Paragraph continue | ||||
par_re = re.compile(r'\\$',re.MULTILINE) | ||||
# The "\n" symbol | ||||
newline_re = re.compile(r'\\n') | ||||
# Now build the string for output: | ||||
#strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng) | ||||
strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:', | ||||
strng) | ||||
strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng) | ||||
strng = par_re.sub(r'\\\\',strng) | ||||
strng = escape_re.sub(r'\\\1',strng) | ||||
strng = newline_re.sub(r'\\textbackslash{}n',strng) | ||||
return strng | ||||
Fernando Perez
|
r6917 | def parse_options(self, arg_str, opt_str, *long_opts, **kw): | ||
Ville M. Vainio
|
r1032 | """Parse options passed to an argument string. | ||
The interface is similar to that of getopt(), but it returns back a | ||||
Struct with the options as keys and the stripped argument string still | ||||
as a string. | ||||
arg_str is quoted as a true sys.argv vector by using shlex.split. | ||||
This allows us to easily expand variables, glob files, quote | ||||
arguments, etc. | ||||
Options: | ||||
-mode: default 'string'. If given as 'list', the argument string is | ||||
returned as a list (split on whitespace) instead of a string. | ||||
-list_all: put all option values in lists. Normally only options | ||||
appearing more than once are put in a list. | ||||
-posix (True): whether to split the input line in POSIX mode or not, | ||||
as per the conventions outlined in the shlex module from the | ||||
standard library.""" | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | # inject default options at the beginning of the input line | ||
Fernando Perez
|
r6929 | caller = sys._getframe(1).f_code.co_name | ||
Ville M. Vainio
|
r1032 | arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str) | ||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | mode = kw.get('mode','string') | ||
if mode not in ['string','list']: | ||||
raise ValueError,'incorrect mode given: %s' % mode | ||||
# Get options | ||||
list_all = kw.get('list_all',0) | ||||
Fernando Perez
|
r2450 | posix = kw.get('posix', os.name == 'posix') | ||
MinRK
|
r5672 | strict = kw.get('strict', True) | ||
Ville M. Vainio
|
r1032 | |||
# Check if we have more than one argument to warrant extra processing: | ||||
odict = {} # Dictionary with options | ||||
args = arg_str.split() | ||||
if len(args) >= 1: | ||||
# If the list of inputs only has 0 or 1 thing in it, there's no | ||||
# need to look for options | ||||
MinRK
|
r5672 | argv = arg_split(arg_str, posix, strict) | ||
Ville M. Vainio
|
r1032 | # Do regular option processing | ||
try: | ||||
opts,args = getopt(argv,opt_str,*long_opts) | ||||
except GetoptError,e: | ||||
Bernardo B. Marques
|
r4872 | raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, | ||
Ville M. Vainio
|
r1032 | " ".join(long_opts))) | ||
for o,a in opts: | ||||
if o.startswith('--'): | ||||
o = o[2:] | ||||
else: | ||||
o = o[1:] | ||||
try: | ||||
odict[o].append(a) | ||||
except AttributeError: | ||||
odict[o] = [odict[o],a] | ||||
except KeyError: | ||||
if list_all: | ||||
odict[o] = [a] | ||||
else: | ||||
odict[o] = a | ||||
# Prepare opts,args for return | ||||
opts = Struct(odict) | ||||
if mode == 'string': | ||||
args = ' '.join(args) | ||||
return opts,args | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6923 | def default_option(self, fn, optstr): | ||
Fernando Perez
|
r6917 | """Make an entry in the options_table for fn, with value optstr""" | ||
if fn not in self.lsmagic(): | ||||
error("%s is not a magic function" % fn) | ||||
self.options_table[fn] = optstr | ||||