|
|
==============================
|
|
|
The magic commands subsystem
|
|
|
==============================
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
These are *preliminary* notes and thoughts on the magic system, kept here
|
|
|
for reference so we can come up with a good design now that the major core
|
|
|
refactoring has made so much progress. Do not consider yet any part of this
|
|
|
document final.
|
|
|
|
|
|
Two entry points:
|
|
|
|
|
|
- m.line_eval(self,parameter_s): like today
|
|
|
- m.block_eval(self,code_block): for whole-block evaluation.
|
|
|
|
|
|
This would allow us to have magics that take input, and whose single line form
|
|
|
can even take input and call block_eval later (like %cpaste does, but with a
|
|
|
generalized interface).
|
|
|
|
|
|
Constructor
|
|
|
===========
|
|
|
|
|
|
Suggested syntax::
|
|
|
|
|
|
class MyMagic(BaseMagic):
|
|
|
requires_shell = True/False
|
|
|
def __init__(self,shell=None):
|
|
|
|
|
|
|
|
|
Registering magics
|
|
|
==================
|
|
|
|
|
|
Today, ipapi provides an *expose_magic()* function for making simple magics.
|
|
|
We will probably extend this (in a backwards-compatible manner if possible) to
|
|
|
allow the simplest cases to work as today, while letting users register more
|
|
|
complex ones.
|
|
|
|
|
|
Use cases::
|
|
|
|
|
|
def func(arg): pass # note signature, no 'self'
|
|
|
ip.expose_magic('name',func)
|
|
|
|
|
|
def func_line(arg): pass
|
|
|
def func_block(arg):pass
|
|
|
ip.expose_magic('name',func_line,func_block)
|
|
|
|
|
|
class mymagic(BaseMagic):
|
|
|
"""Magic docstring, used in help messages.
|
|
|
"""
|
|
|
def line_eval(self,arg): pass
|
|
|
def block_eval(self,arg): pass
|
|
|
|
|
|
ip.register_magic(mymagic)
|
|
|
|
|
|
|
|
|
The BaseMagic class will offer common functionality to all, including things
|
|
|
like options handling (via argparse).
|
|
|
|
|
|
|
|
|
Call forms: line and block
|
|
|
==========================
|
|
|
|
|
|
Block-oriented environments will call line_eval() for the first line of input
|
|
|
(the call line starting with '%') and will then feed the rest of the block to
|
|
|
block_eval() if the magic in question has a block mode.
|
|
|
|
|
|
In line environments, by default %foo -> foo.line_eval(), but no block call is
|
|
|
made. Specific implementations of line_eval can decide to then call block_eval
|
|
|
if they want to provide for whole-block input in line-oriented environments.
|
|
|
|
|
|
The api might be adapted for this decision to be made automatically by the
|
|
|
frontend...
|
|
|
|
|
|
|
|
|
Precompiled magics for rapid loading
|
|
|
====================================
|
|
|
|
|
|
For IPython itself, we'll have a module of 'core' magic functions that do not
|
|
|
require run-time registration. These will be the ones contained today in
|
|
|
Magic.py, plus any others we deem worthy of being available by default. This
|
|
|
is a trick to enable faster startup, since once we move to a model where each
|
|
|
magic can in principle be registered at runtime, creating a lot of them can
|
|
|
easily swamp startup time.
|
|
|
|
|
|
The trick is to make a module with a top-level class object that contains
|
|
|
explicit references to all the 'core' magics in its dict. This way, the magic
|
|
|
table can be quickly updated at interpreter startup with a single call, by
|
|
|
doing something along the lines of::
|
|
|
|
|
|
self.magic_table.update(static_magics.__dict__)
|
|
|
|
|
|
The point will be to be able to bypass the explicit calling of whatever
|
|
|
register_magic() API we end up making for users to declare their own magics.
|
|
|
So ultimately one should be able to do either::
|
|
|
|
|
|
ip.register_magic(mymagic) # for one function
|
|
|
|
|
|
or::
|
|
|
|
|
|
ip.load_magics(static_magics) # for a bunch of them
|
|
|
|
|
|
I still need to clarify exactly how this should work though.
|
|
|
|