scsLeal
scsLeal

Reputation: 31

Custom IPython magic command for multiple cells

How to build a custom IPython magic command that:

  1. run a block of code before running a cell;
  2. only needs to be called once to be applied on every cell of notebook.

Similar cases
%matplotlib, %pdb, %doctest_mode

Example

In [1]: %myMagic 1
Out[1]: myMagic is: ON

In [2]: x = 1
Out[2]: 'Hello World'

In [3]: x
Out[3]: 'Hello World'
   ...:  1

In [4]: %myMagic 0
Out[4]: myMagic is: OFF

In [5]: y=x+1
   ...: y
Out[5]: 2

Upvotes: 3

Views: 375

Answers (1)

hBy2Py
hBy2Py

Reputation: 1832

I'm currently working on a Jupyter nbextension where I want to wrap a code cell's entire contents in a specific context manager before the kernel executes it, where code cells are wrapped or not based upon various user-configurable logic.

As far as I've been able to determine, it's not possible to do what you want using magics, because magics aren't able to hook into the execution machinery of the IPython kernel itself. As best I know, all of those magics you mention work by changing settings within some specific module or class, which then control the global behavior of that module/class in the rest of the notebook.

What I've had to do is approach this from the nbextension side, where I fetch the cell code in the frontend Javascript, inject my context manager, indent the block, and then submit the edited code for execution by the kernel. For reference, my WIP as of this writing is here; a barebones implementation is:

define([
  'notebook/js/codecell'
], function (codecell) {

    "use strict";

    var CodeCell = codecell.CodeCell

    return {
        load_ipython_extension: function () {
            /* Store the original .execute() before overriding,
             * for use in the overridden method
             */ 
            var orig_execute = CodeCell.prototype.execute;

            // Override .execute()
            CodeCell.prototype.execute = function (stop_on_error) {
                var orig_text = this.get_text();
                var new_text = orig_text;

                /* == Make whatever modifications to new_text == */

                /* Rewrite the cell text, make the .execute() call,
                 * and restore the original cell text
                 */
                this.set_text(new_text);
                orig_execute.call(this, stop_on_error);
                this.set_text(orig_text);
            };
        }
    };
});

Upvotes: 1

Related Questions