I have successfully made several functions that search inputted keywords (they can be comments, codes, markdowns, or raw codes) inside the current jupyter ipynb file and run any cells containing those keywords. I am satisfied with my work but one problem is that running cells by Javascript command inside a loop will simultaneously run selected cells. This is not a problem for small processes but I believe that might cause problem for heavy process. Does anyone have any suggestion about how to make these runs sequential and orderly so that each run wait till the previous run is finished? Also if anyone has a better idea about searching and running jupyter cells with keywords I appreciate your suggestion.
My codes contain two jupyter cells (cell A and B) that one produces a jupyter widget to input keywords and functions to: 1) read ipynb file (using ipynbname
library, you have to install it by pip install ipynbname
), 2) search keywords (kwsearch
function), 3) index each jupyter cell by reading ipynb file (cell_indices
, the last index in cell_indices corresponds to the current code cell number), and 4) connect keyword indices to the corresponding cell indices (indice_matcher
).
Cell B runs cell A functions for any updated value inside text input widget and run resulted cells in a loop. The only reason that cell A and B should be separated is because running cell A will cause the text widget to be updated into the default values (becomes empty), hence another cell should call the modified inputs and functions.
Below compose cell A:
### trying to make Jupyter ipynb to run cells containing especial keywords
# cell A >> preparing functions and the input widget
# kw is short form of keyword(s)
import numpy as np
import codecs
import ipynbname #pip install ipynbname
from IPython.display import Javascript, display
import ipywidgets as widgets
from ipywidgets import Layout, Textarea
ID = '5oG9gNy7myn/k86/+/8cemphdkEsK237SjQltj2GZGU=' # unique ID for finding current code cell number inside ipynb file
def indice_matcher(j01,j02): # if positive difference of j02[n] and j01[n] is less than j01[n] and j01[+1] then they have matching indices
'''j01 has the bigger range '''
jj = []
for j1 in range(len(j01)-1):
for j2 in range(len(j02)):
if j02[j2] - j01[j1] < j01[j1+1] - j01[j1] and j02[j2] - j01[j1] > 0:
jj.append(j1)
return jj # returns list indices of matched indices
def kwsearch(x,char): # x is the big string and char is the small string
f = 0
i = []
f = x.find(char)
i.append(f)
while f != -1:
f = x[i[-1]+1:].find(char)
i.append(f+1+i[-1])
return i[:-1] # returns all indices of ONE searched character inside x string
def flat(lis):
''' # Converts a nested list into a flat list;
source : https://www.geeksforgeeks.org/python-convert-a-nested-list-into-a-flat-list/'''
flatList = []
# Iterate with outer list
for element in lis:
if type(element) is list:
# Check if type is list than iterate through the sublist
for item in element:
flatList.append(item)
else:
flatList.append(element)
return flatList
def kwrun(kw_string):
kw_string.append(ID)
N = len(kw_string)
# nb_fname = ipynbname.name() # current ipynb file's name
nb_path = ipynbname.path() # current ipynb file's path
f=codecs.open(nb_path, 'r')
current_ipynb = f.read()
kw_indices = [] # indices of all inputted keywords
for n in range(N): # the loop repeats itself till N keywords are searched
kw_indices.append(kwsearch(current_ipynb,kw_string[n]))
cell_indices = kwsearch(current_ipynb,'"cell_type"') # searching "cell_type" inside ipynb file helps us to find indices for all cells
# calculating selected cell number
cell_n = []
for n in range(N): # the loop repeats till N kewords are searched
cell_n.append(indice_matcher(cell_indices,kw_indices[n])) # returns list of cell numbers that should be run ; # cell numbers in this way is equal to cell_indices' number of each index
cell_n = flat(cell_n)
print(f'Running Cells: {cell_n[:-1]} n current code cell number: {cell_n[-1]}')
return cell_n
w1 = widgets.Text(description='Keywords') # an elegant way to input keywords
display(w1)
And below codes represent cell B:
# cell B >> search and run
cell_n = kwrun((w1.value).split()) # w1.value is value of inputted words inside cell 1 widget; the keywords should be separated by space
for n in range(len(cell_n)-1): # the -1 in range removes loops to run current code cell number (cell A)
display(Javascript(f'IPython.notebook.execute_cells([{str(cell_n[n])}])')) #if a name is not found, no cell will be run
After running cell A once to produce the widget, by inputting any desired keyword, run cell B. By that, the corresponding cells that contain inputted keywords will be run, but what might become a problem later is that they run simultaneously.
Some final considerations: if you use above codes, choose long unique unspaced strings for desired cells. If keywords are repeated in different cells, all those cells will be run simultaneously.
These functions help to run necessary jupyter cells at the beginning of each work by remembering the most crucial keyword in each cell. for example I use “.npy” keyword to load the cell that loads my original dataset like below:
Thank you for your consideration.