4

Suppose I have a Python script called my_script.py with a one function called my_func() inside. I import this script into a Jupyter Notebook so I can run my_func() in the cells.

My question is, in the definition of my_func(), how to find which cell number it is called from, so that I can log the cell number? Any API that I could use?

Something like

# my_script.py

def my_func():
    # find which cell this is called from
    cell_number_called_from = some_IPython_history_class_api.get_current_cell()

    # log the cell number and do the rest of my things
Jinsong Li
  • 6,347
  • 1
  • 23
  • 20
  • 1
    It's not exactly the same, but there are some instructions to find the identity of the caller [here](https://stackoverflow.com/q/2654113/11301900). – AMC Jan 08 '20 at 22:25
  • @AMC Thanks for your tip. It is working! – Jinsong Li Jan 09 '20 at 19:13
  • Does this answer your question? [How to write a cell magic that knows the input number of the cell?](https://stackoverflow.com/questions/60694633/how-to-write-a-cell-magic-that-knows-the-input-number-of-the-cell) – Georgy Apr 20 '20 at 11:21

3 Answers3

2

The following javascript snippet in your Jupyter Notebook's cell will give you that cell's index:

%%javascript
var output_area = this;
// find my cell element
var cell_element = output_area.element.parents('.cell');
// which cell is it?
var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);
console.log(cell_idx)
Rajanya Dhar
  • 166
  • 6
1

Here is my solution. Two limitations of this method are as follows:

  1. It works only on vscode. (This problem can be solved by modifying the code.)
  2. You must save the notebook file before execute.

It loads the current ipynb file, and find index of a cell that has the same source with the current input.

# my_script.py

import json
import IPython


def get_cell_idx():
  shell = IPython.get_ipython()
  In = shell.ev('In')

  depth = 0
  while True:
    try:
      with open(
          IPython.extract_module_locals(depth=depth)[1]['__vsc_ipynb_file__'],
          encoding='utf8') as f:
        nb = json.load(f)
        break
    except ValueError:
      return None
    except KeyError:
      depth += 1

  for idx, cell in enumerate(nb['cells']):
    if ''.join(cell['source']).strip() == In[-1]:
      return idx
# Cell

from my_script import get_cell_idx

get_cell_idx()
calee
  • 81
  • 2
  • 6
0

The idea of calee's solution is finding all Input cells, and then matching the source of code cell.

I enhance his solution in two aspects:

  1. Works in JupyterLab
  2. Works for duplicated cells (i.e., have same source content)

The idea is matching the cell id in metadata, which is unique for each cell.

You might need to install ipynbname since the script needs to get current notebook path in get_notebook_cells.

pip install ipynbname

Here is the script:

import nbformat
import ipynbname


def get_notebook_cells(notebook_path=None, cell_types=["markdown", "code", "raw"]):
    if not notebook_path:
        notebook_path = ipynbname.path()

    with open(notebook_path, "r", encoding="utf-8") as rf:
        nb = nbformat.read(rf, as_version=4)

    cells = [cell for i, cell in enumerate(nb.cells) if cell["cell_type"] in cell_types]
    return cells


def get_cell_id():
    cell_id = get_ipython().get_parent()["metadata"]["cellId"]
    return cell_id


def get_cell_index():
    cell_id = get_cell_id()
    cells = get_notebook_cells()
    for idx, cell in enumerate(cells):
        if cell["id"] == cell_id:
            return idx

print(get_cell_index())

Here is the example of execution:

get_cell_index

Notes:

  • In my case, I put the get_cell_index() in another file to make it easily re-used by other notebooks.
  • The cell index starts from 0.
Hansimov
  • 597
  • 7
  • 10