magic.py
326 lines
| 11.3 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
|
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 | ||
from IPython.utils.traitlets import Dict, Enum, Instance | ||||
from IPython.utils.warn import error | ||||
#----------------------------------------------------------------------------- | ||||
# Globals | ||||
#----------------------------------------------------------------------------- | ||||
line_magics = {} | ||||
cell_magics = {} | ||||
Fernando Perez
|
r2363 | |||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
Fernando Perez
|
r6917 | # Utility classes and functions | ||
Brian Granger
|
r2498 | #----------------------------------------------------------------------------- | ||
Fernando Perez
|
r6917 | class Bunch: pass | ||
# Used for exception handling in magic_edit | ||||
class MacroToEdit(ValueError): 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): | ||||
global line_magics, cell_magics | ||||
cls.line_magics = line_magics | ||||
cls.cell_magics = cell_magics | ||||
cls.registered = True | ||||
line_magics = {} | ||||
cell_magics = {} | ||||
return cls | ||||
def _magic_marker(magic_type): | ||||
global line_magics, cell_magics | ||||
if magic_type not in ('line', 'cell'): | ||||
raise ValueError('magic_type must be one of ["line", "cell"], %s given' | ||||
% magic_type) | ||||
if magic_type == 'line': | ||||
line_magics = {} | ||||
else: | ||||
cell_magics = {} | ||||
# 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): | ||||
global line_magics, cell_magics | ||||
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) | ||||
elif isinstance(arg, basestring): | ||||
# Decorator called with arguments (@foo('bar')) | ||||
name = arg | ||||
def mark(func, *a, **kw): | ||||
func.magic_name = name | ||||
return decorator(call, func) | ||||
retval = mark | ||||
else: | ||||
raise ValueError("Decorator can only be called with " | ||||
"string or function") | ||||
# Record the magic function in the global table that will then be | ||||
# appended to the class via the register_magics class decorator | ||||
if magic_type == 'line': | ||||
line_magics[name] = retval | ||||
else: | ||||
cell_magics[name] = retval | ||||
return retval | ||||
return magic_deco | ||||
line_magic = _magic_marker('line') | ||||
cell_magic = _magic_marker('cell') | ||||
#----------------------------------------------------------------------------- | ||||
# Core Magic classes | ||||
#----------------------------------------------------------------------------- | ||||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r6917 | class MagicManager(Configurable): | ||
"""Object that handles all magic-related functionality for IPython. | ||||
""" | ||||
# An instance of the IPython shell we are attached to | ||||
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | ||||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r6917 | auto_status = Enum([ | ||
'Automagic is OFF, % prefix IS needed for magic functions.', | ||||
'Automagic is ON, % prefix NOT needed for magic functions.']) | ||||
MinRK
|
r5225 | |||
Fernando Perez
|
r6917 | def __init__(self, shell=None, config=None, **traits): | ||
Fernando Perez
|
r6910 | |||
Fernando Perez
|
r6917 | super(MagicManager, self).__init__(shell=shell, config=config, **traits) | ||
Ville M. Vainio
|
r1032 | |||
def lsmagic(self): | ||||
"""Return a list of currently available magic functions. | ||||
Gives a list of the bare names after mangling (['ls','cd', ...], not | ||||
['magic_ls','magic_cd',...]""" | ||||
# FIXME. This needs a cleanup, in the way the magics list is built. | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | # magics in class definition | ||
class_magic = lambda fn: fn.startswith('magic_') and \ | ||||
callable(Magic.__dict__[fn]) | ||||
# in instance namespace (run-time user additions) | ||||
inst_magic = lambda fn: fn.startswith('magic_') and \ | ||||
callable(self.__dict__[fn]) | ||||
# and bound magics by user (so they can access self): | ||||
inst_bound_magic = lambda fn: fn.startswith('magic_') and \ | ||||
callable(self.__class__.__dict__[fn]) | ||||
Fernando Perez
|
r6917 | magics = filter(class_magic, Magic.__dict__.keys()) + \ | ||
Fernando Perez
|
r6912 | filter(inst_magic, self.__dict__.keys()) + \ | ||
filter(inst_bound_magic, self.__class__.__dict__.keys()) | ||||
Ville M. Vainio
|
r1032 | out = [] | ||
Fernando Perez
|
r1860 | for fn in set(magics): | ||
Fernando Perez
|
r6917 | out.append(fn.replace('magic_', '', 1)) | ||
Ville M. Vainio
|
r1032 | out.sort() | ||
return out | ||||
Bernardo B. Marques
|
r4872 | |||
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 | """ | ||
options_table = Dict(config=True, | ||||
help = """Dict holding all command-line options for each magic. | ||||
""") | ||||
class __metaclass__(type): | ||||
def __new__(cls, name, bases, dct): | ||||
cls.registered = False | ||||
return type.__new__(cls, name, bases, dct) | ||||
def __init__(self, shell): | ||||
if not(self.__class__.registered): | ||||
raise ValueError('unregistered Magics') | ||||
self.shell = shell | ||||
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 | |||
def format_latex(self,strng): | ||||
"""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 | ||
caller = sys._getframe(1).f_code.co_name.replace('magic_','') | ||||
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
|
r6917 | def default_option(self,fn,optstr): | ||
"""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 | ||||