12

I would like to access the textual contents of another cell in the notebook from Python so that I can feed it to the unit testing script, regardless of whether it has been executed or not. It seems like this should be possible, but I can't find the right API to do it in the IPython kernel. Thoughts?

This question asks the same question, but I don't really want to use magics unless I have to. Ideally the workflow would be "select widget choice" followed by "click widget" to cause the tests to run.

Background

I'm working with some students to teach them Python, and in the past when I've done this I've set up a bunch of unit tests and then provided instructions on how to run the tests via a shell script. However, I'm working with some students that don't have access to computers at home, so I decided to try and use an Jupyter notebook environment (via mybinder.org) to allow them to do the same thing. I've got most of it working already via some ipywidgets and a helper script that runs the unit tests on some arbitrary set of code.

Community
  • 1
  • 1
Dustin Spicuzza
  • 694
  • 6
  • 12

3 Answers3

11

As far as the cells that have been run, the input and output caching system described at https://ipython.readthedocs.io/en/stable/interactive/reference.html#input-caching-system might be useful. (Examples of its use at https://stackoverflow.com/a/27952661/8508004 ). It works in Jupyter notebooks as shown below. (The corresponding notebook can be viewed/accessed here.) enter image description here


Because @A. Donda raised the issue of markdown in the comments below, I'll add here that nbformat provides related abilities that works with saved notebook files. Reading a saved notebook file with nbformat allowa getting cells and content, no matter if it is code or markdown, and sorting whether the cells are markdown or code, etc.. I have posted a number of examples of using nbformat on the Jupyter Discourse forum that can be seen listed via this search here. It offers more utility than the related json.load(open('test.ipynb','r')) command, highlighted in a comment here to read a notebook file because of the additional notebook context automatically included.

Wayne
  • 6,607
  • 8
  • 36
  • 93
  • 1
    This only applies to code cells, not text (Markdown) cells. – A. Donda Jun 04 '20 at 22:15
  • 1
    Minor note: `_oh` returns the output of the cell call (as do `_`, `__`, `_3`) as opposed to everything that was printed or displayed along the way. The cell output content can be retried via JS calls. – Matteo Ferla Mar 24 '21 at 13:23
  • 1
    @A.Donda [This question](https://stackoverflow.com/questions/22320414/how-to-use-the-content-of-a-ipython-notebook-markdown-cell-in-python) looks related to yours. I added a note here about a related resource that lets you get markdown if the notebook file has been saved and the name of that notebook file is known or can accessed. – Wayne Mar 25 '21 at 15:45
3

If you want to capture the contents of a specific cell to access it from another one, one workaround seems to bee to write the contents of the first cell to file when executing it and later loading the resulting file (i.e. the text giving the former cell's content) inside the latter cell, where the content of the former cell is required.

Cell's contents can be saved to file (when executing the respective cell) via the command

%%writefile foo.py

which has to be placed at the beginning of a cell. This results in the cell's content (in which the upper command is executed) being saved to the file foo.py and it's just a matter of later reading it in, again.

The output of a cell can be made available more easily:

Just place %%capture output in the first line of a cell. Then, the output of the cell (after execution) is going to be saved as a string to the variable output and can be used like any standard python string-variable.

References: Programmatically get current Ipython notebook cell output? and https://nbviewer.jupyter.org/github/ipython/ipython/blob/1.x/examples/notebooks/Cell%20Magics.ipynb

Daniel B.
  • 659
  • 1
  • 9
  • 17
3

I found a solution to this that can get the output of any cell. It requires running some Javascript.

Here is the code that you can put in a cell and run it an it will generate a Python variable called cell_outputs which will be an array of the cell outputs in the same order as they appear on the page. The output of the cell executing this code, will have an empty string.

%%js
{
    let outputs=[...document.querySelectorAll(".cell")].map(
        cell=> {
            let output=cell.querySelector(".output_text")
            if(output) return output.innerText
            output=cell.querySelector(".rendered_html")
            if(output) return output.innerHTML
            return ""
        }
    )
    
    IPython.notebook.kernel.execute("cell_outputs="+JSON.stringify(outputs))    
}

If you need the output of a specific cell, just use its index, eg: cell_outputs[2] in your Python code to access the output of cell #3.

I tested this on my Jupyter notebook 6.0.3 (recent install via the Anaconda community edition) on Google Chrome. The above could should work fine on any modern browser (Chrome, Firefox or Edge).

BenVida
  • 1,796
  • 1
  • 16
  • 25
  • Can we run this code without %%js cell. Basically i have library whose functions are getting called in notebook python cell. and i want above information inside that library function. – Djai Mar 04 '22 at 16:36
  • No. This solution is based on Javascript. – BenVida Mar 06 '22 at 18:36