Is it possible to combine magics in IPython / Jupyter?

Viewed 1307

Sometimes you want to use several magics at the same time. Now I know you can use

%%time
%%bash
ls 

But when I make my own commands this chaining doesn't work...

from IPython.core.magic import register_cell_magic

@register_cell_magic
def accio(line, cell):
    print('accio')
    exec(cell)

results in an error when using

%%accio
%%bash
ls

What should I use rather than exec?

2 Answers

you have to apply the IPython special transformations, to run the nested magic with the cell, like the %%time magic:

@register_cell_magic
def accio(line, cell):
    ipy = get_ipython()
    expr = ipy.input_transformer_manager.transform_cell(cell)
    expr_ast = ipy.compile.ast_parse(expr)
    expr_ast = ipy.transform_ast(expr_ast)
    code = ipy.compile(expr_ast, '', 'exec')
    exec(code)

or simply call run_cell:

@register_cell_magic
def accio(line, cell):
    get_ipython().run_cell(cell)

result:

In [1]: %%accio
   ...: %%time
   ...: %%bash
   ...: date
   ...:
accio
Wed Nov 14 17:41:55 CST 2018
CPU times: user 1.42 ms, sys: 4.21 ms, total: 5.63 ms
Wall time: 9.64 ms

In IPython source code, they almost always use a class for creating magic statements because they can hold values, and I think that's what your looking for.

Check this source code to see some examples.

Related