Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define a IPython magic which replaces the content of the next cell

The %load line-magic command loads the content of a given file into the current cell, for instance, executing:

[cell 1]    %load hello_world.py

... transform the cell into:

[cell 1]    # %load hello_world.py
            print("hello, world")

I would like to create a %load_next line-magic command which would instead load this file into the next cell. For example, executing cell 1 in the following notebook:

[cell 1]    %load_next hello_world.py

[cell 2]    print("hello, cruel world")  # original content

... would keep cell 1 unchanged and update cell 2 with the new content:

[cell 1]    %load_next hello_world.py

[cell 2]    print("hello, world")

I have tried this:

from IPython.core.magic import Magics, magics_class, line_magic
from pathlib import Path

@magics_class
class MyMagics(Magics):

    @line_magic
    def load_next(self, line):
        new_content = Path(line).read_text()
        self.shell.set_next_input(new_content, replace=False)

ip = get_ipython()
ip.register_magics(MyMagics)

But it inserts the content between the current and the next cell:

[cell 1]    %load_next hello_world.py

[cell 2]    print("hello, world")

[cell 3]    print("hello, cruel world")  # original content

Is it possible to make it either replace the next cell, or delete the next cell before inserting it?

like image 224
Aristide Avatar asked Nov 06 '22 03:11

Aristide


1 Answers

You can run below script. There is no way to get all cells, so I decided to run javascript code to remove the next cell. Js part finds all cells and remove the next cell from the current cell. I have tested on Jupyter Notebook and Jupyter Lab.

from IPython.display import display, HTML, Javascript
from IPython.core.magic import Magics, magics_class, line_magic
from pathlib import Path

@magics_class
class MyMagics(Magics):

    @line_magic
    def load_next(self, line):
        js_script = r"""<script>
            
            if (document.getElementById('notebook-container')) {
                //console.log('Jupyter Notebook');
                allCells = document.getElementById('notebook-container').children;
                selectionClass = /\bselected\b/;
                jupyter = 'notebook';
            }
            else if (document.getElementsByClassName('jp-Notebook-cell').length){
                //console.log('Jupyter Lab');
                allCells = document.getElementsByClassName('jp-Notebook-cell');
                selectionClass = /\bjp-mod-selected\b/;
                jupyter = 'lab';
            }
            else {
                console.log('Unknown Environment');
            }

            if (typeof allCells !== 'undefined') {
                for (i = 0; i < allCells.length - 1; i++) {
                    if(selectionClass.test(allCells[i].getAttribute('class'))){
                        allCells[i + 1].remove();
                        
                        // remove output indicators of current cell
                        window.setTimeout(function(){
                            if(jupyter === 'lab') {
                                allCells[i].setAttribute('class', allCells[i].getAttribute('class') + ' jp-mod-noOutputs');
                                allCells[i].getElementsByClassName('jp-OutputArea jp-Cell-outputArea')[0].innerHTML = '';
                            } else if(jupyter === 'notebook'){
                                allCells[i].getElementsByClassName('output')[0].innerHTML = '';
                            }
                        }, 20);
                        
                        break;
                    }
                }
            }
            </script>"""
        
        # remove next cell
        display(HTML(js_script))
        
        new_content = Path(line).read_text()
        self.shell.set_next_input(new_content, replace=False)

ip = get_ipython()
ip.register_magics(MyMagics)
like image 160
Ismail Durmaz Avatar answered Nov 12 '22 11:11

Ismail Durmaz