Skip to content

Commit 67c634d

Browse files
committed
render_nb_from_stream to build inline jupyter notebooks in jupyter from packet stream
1 parent b6abc5b commit 67c634d

1 file changed

Lines changed: 59 additions & 1 deletion

File tree

appyter/render/nbviewer.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import nbconvert
22
from bs4 import BeautifulSoup
33

4-
def render_nbviewer_from_nb(env, nb):
4+
def render_nbviewer_from_nb_soup(env, nb):
55
''' Render an nbviewer (HTML serialization of the notebook)
66
'''
77
exporter = nbconvert.HTMLExporter()
@@ -15,7 +15,65 @@ def render_nbviewer_from_nb(env, nb):
1515
soup.find('script').decompose()
1616
# soup.find('style').decompose() # remove first style (bootstrap)
1717
soup.find('link').decompose() # remove link to custom stylesheet
18+
return soup
19+
20+
def render_nbviewer_cell_from_nb(env, nb, cell_index):
21+
''' Render a single cell from a notebook
22+
23+
TODO: Surely this can be more efficient..
24+
'''
25+
exporter = nbconvert.HTMLExporter()
26+
export, _ = exporter.from_notebook_node(nb)
27+
soup = BeautifulSoup(export, 'html.parser')
28+
return soup.select('.cell')[cell_index]
29+
30+
def render_nbviewer_from_nb(env, nb):
31+
''' Render an nbviewer (HTML serialization of the notebook)
32+
'''
33+
soup = render_nbviewer_from_nb_soup(env, nb)
1834
nb_container = soup.select('#notebook-container')[0]
1935
nb_container['class'] = ''
2036
nb_container['id'] = ''
2137
return str(soup)
38+
39+
def render_nb_from_stream(env, stream):
40+
''' Render a jupyter notebook and update it *in* a jupyter notebook from an nbexecute progress stream.
41+
42+
:param nb: (ipynb) The loaded jupyter notebook
43+
:param stream: (generator) The stream of messages coming from nbexecute.
44+
'''
45+
import json
46+
import uuid
47+
from IPython.display import display, update_display, HTML
48+
from appyter.util import try_json_loads
49+
from appyter.parse.nb import nb_from_json
50+
id = '_' + str(uuid.uuid4())
51+
nb = None
52+
display(HTML('Starting...'), display_id=id+'_status')
53+
for msg in stream:
54+
msg = try_json_loads(msg)
55+
if type(msg) == dict:
56+
if nb is None and msg['type'] == 'nb':
57+
# received the constructed notebook parse and render it
58+
nb = msg['data']
59+
nb_html = render_nbviewer_from_nb_soup(env, nb_from_json(nb))
60+
nb_html.select('#notebook-container')[0]['id'] = '#' + id
61+
# show each cell separately with an id based on the index
62+
for cell_index, cell in enumerate(nb_html.select('.cell')):
63+
display(HTML(str(cell)), display_id=id+'_%d' % (cell_index))
64+
elif nb is not None and msg['type'] == 'cell':
65+
cell, cell_index = msg['data']
66+
# when a cell updates, we'll update the notebook and update the cell display
67+
nb['cells'][cell_index] = cell
68+
cell_rendered = str(render_nbviewer_cell_from_nb(env, nb_from_json(nb), cell_index))
69+
update_display(HTML(cell_rendered), display_id=id+'_%d' % (cell_index))
70+
elif msg['type'] == 'status':
71+
update_display(HTML(str(msg['data'])), display_id=id+'_status')
72+
elif msg['type'] == 'error':
73+
update_display(HTML('Error'), display_id=id+'_status')
74+
raise Exception(msg['data'])
75+
else:
76+
update_display(HTML(str(msg)), display_id=id+'_status')
77+
update_display(HTML(''), display_id=id+'_status')
78+
#
79+
return nb

0 commit comments

Comments
 (0)