11import nbconvert
22from 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