Coverage for src/jyquickhelper/helper_in_notebook.py: 87%

38 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-02 00:05 +0200

1# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief Functions to call from the notebook 

5""" 

6from IPython.display import Javascript, HTML 

7 

8 

9def set_notebook_name_theNotebook(name="theNotebook", display=True): 

10 """ 

11 This function must be called from the notebook 

12 you want to know the name. It relies on 

13 a javascript piece of code. It populates 

14 the variable ``theNotebook`` with the notebook name. 

15 

16 @param name name of the variable to create 

17 @param display calls `display <http://ipython.readthedocs.io/en/stable/api/generated/ 

18 IPython.display.html#IPython.display.display>`_ 

19 or returns a javascript object 

20 @return None or `Javascript <http://ipython.readthedocs.io/en/stable/api/generated/ 

21 IPython.display.html#IPython.display.Javascript>`_ 

22 

23 This solution was found at 

24 `How to I get the current IPython Notebook name 

25 <http://stackoverflow.com/questions/12544056/how-to-i-get-the-current-ipython-notebook-name>`_. 

26 

27 The function can be called in a cell. 

28 The variable ``theNotebook`` will be available in the next cells. 

29 

30 Try function @see fn store_notebook_path if this one does not work. 

31 """ 

32 from IPython.core.display import display as jdisp # pylint: disable=E0611 

33 

34 code = """var kernel = IPython.notebook.kernel; 

35 var body = document.body, attribs = body.attributes; 

36 var command = "__NAME__ = " + "'"+attribs['data-notebook-name'].value+"'"; 

37 kernel.execute(command);""".replace(" ", "").replace("__NAME__", name) 

38 

39 def get_name(): 

40 "return name" 

41 j = Javascript(code) 

42 if display: 

43 jdisp(j) 

44 return j 

45 return get_name() 

46 

47 

48def _add_notebook_menu_js(): 

49 return """ 

50 function repeat_indent_string(n){ 

51 var a = "" ; 

52 for ( ; n > 0 ; --n) 

53 a += " "; 

54 return a; 

55 } 

56 // look up into all sections and builds an automated menu // 

57 var update_menu_string = function(begin, lfirst, llast, sformat, send, keep_item, begin_format, end_format) { 

58 var anchors = document.getElementsByClassName("section"); 

59 if (anchors.length == 0) { 

60 anchors = document.getElementsByClassName("text_cell_render rendered_html"); 

61 } 

62 var i,t; 

63 var text_menu = begin; 

64 var text_memo = "<pre>\\nlength:" + anchors.length + "\\n"; 

65 var ind = ""; 

66 var memo_level = 1; 

67 var href; 

68 var tags = []; 

69 var main_item = 0; 

70 var format_open = 0; 

71 for (i = 0; i <= llast; i++) 

72 tags.push("h" + i); 

73 

74 for (i = 0; i < anchors.length; i++) { 

75 text_memo += "**" + anchors[i].id + "--\\n"; 

76 

77 var child = null; 

78 for(t = 0; t < tags.length; t++) { 

79 var r = anchors[i].getElementsByTagName(tags[t]); 

80 if (r.length > 0) { 

81 child = r[0]; 

82 break; 

83 } 

84 } 

85 if (child == null) { 

86 text_memo += "null\\n"; 

87 continue; 

88 } 

89 if (anchors[i].hasAttribute("id")) { 

90 // when converted in RST 

91 href = anchors[i].id; 

92 text_memo += "#1-" + href; 

93 // passer à child suivant (le chercher) 

94 } 

95 else if (child.hasAttribute("id")) { 

96 // in a notebook 

97 href = child.id; 

98 text_memo += "#2-" + href; 

99 } 

100 else { 

101 text_memo += "#3-" + "*" + "\\n"; 

102 continue; 

103 } 

104 var title = child.textContent; 

105 var level = parseInt(child.tagName.substring(1,2)); 

106 

107 text_memo += "--" + level + "?" + lfirst + "--" + title + "\\n"; 

108 

109 if ((level < lfirst) || (level > llast)) { 

110 continue ; 

111 } 

112 if (title.endsWith('¶')) { 

113 title = title.substring(0,title.length-1).replace("<", "&lt;") 

114 .replace(">", "&gt;").replace("&", "&amp;"); 

115 } 

116 if (title.length == 0) { 

117 continue; 

118 } 

119 

120 while (level < memo_level) { 

121 text_menu += end_format + "</ul>\\n"; 

122 format_open -= 1; 

123 memo_level -= 1; 

124 } 

125 if (level == lfirst) { 

126 main_item += 1; 

127 } 

128 if (keep_item != -1 && main_item != keep_item + 1) { 

129 // alert(main_item + " - " + level + " - " + keep_item); 

130 continue; 

131 } 

132 while (level > memo_level) { 

133 text_menu += "<ul>\\n"; 

134 memo_level += 1; 

135 } 

136 text_menu += repeat_indent_string(level-2); 

137 text_menu += begin_format + sformat.replace("__HREF__", href).replace("__TITLE__", title); 

138 format_open += 1; 

139 } 

140 while (1 < memo_level) { 

141 text_menu += end_format + "</ul>\\n"; 

142 memo_level -= 1; 

143 format_open -= 1; 

144 } 

145 text_menu += send; 

146 //text_menu += "\\n" + text_memo; 

147 

148 while (format_open > 0) { 

149 text_menu += end_format; 

150 format_open -= 1; 

151 } 

152 return text_menu; 

153 }; 

154 var update_menu = function() { 

155 var sbegin = "__BEGIN__"; 

156 var sformat = __FORMAT__; 

157 var send = "__END__"; 

158 var begin_format = __BEGIN_FORMAT__; 

159 var end_format = __END_FORMAT__; 

160 var keep_item = __KEEP_ITEM__; 

161 var text_menu = update_menu_string(sbegin, __FIRST__, __LAST__, sformat, send, keep_item, 

162 begin_format, end_format); 

163 var menu = document.getElementById("__MENUID__"); 

164 menu.innerHTML=text_menu; 

165 }; 

166 window.setTimeout(update_menu,2000); 

167 """ 

168 

169 

170def add_notebook_menu(menu_id="my_id_menu_nb", raw=False, format="html", header=None, 

171 first_level=2, last_level=4, keep_item=None): 

172 """ 

173 Adds :epkg:`javascript` and :epkg:`HTML` to the notebook 

174 which gathers all in the notebook and builds a menu. 

175 

176 @param menu_id menu_id 

177 @param raw raw HTML and Javascript 

178 @param format *html* or *rst* 

179 @param header title of the menu (None for None) 

180 @param first_level first level to consider 

181 @param last_level last level to consider 

182 @param keep_item None or integer (starts at 0), reduce the number of displayed items to 1 

183 and its descendant 

184 @return HTML object 

185 

186 In a notebook, it is easier to do by using a magic command 

187 ``%%html`` for the HTML and another one 

188 ``%%javascript`` for the Javascript. 

189 This function returns a full text with :epkg:`HTML` and 

190 :epkg:`javascript`. 

191 

192 If the format is :epkg:`RST`, the menu can be copied/pasted in a text cell. 

193 

194 On the notebook, the instruction would work:: 

195 

196 var anchors = document.getElementsByClassName("anchor-link"); 

197 

198 But it fails during the conversion from a notebook to format RST. 

199 """ 

200 if keep_item is not None: 

201 menu_id += str(keep_item) 

202 html = f'<div id="{menu_id}">run previous cell, wait for 2 seconds</div>' 

203 

204 add_notebook_menu_js = _add_notebook_menu_js() 

205 js = add_notebook_menu_js.replace(" ", "") \ 

206 .replace("__MENUID__", menu_id) \ 

207 .replace("__FIRST__", str(first_level)) \ 

208 .replace("__LAST__", str(last_level)) 

209 

210 full = f"{html}\n<script>{js}</script>" 

211 if keep_item is None: 

212 keep_item = -1 

213 

214 if format == "html": 

215 if header is not None and len(header) > 0: 

216 header = f"<b>{header}</b>\n" 

217 else: 

218 header = "" 

219 full = header + \ 

220 full.replace("__FORMAT__", """'<a href="#__HREF__">__TITLE__</a>'""") \ 

221 .replace("__BEGIN__", "") \ 

222 .replace("__END__", "") \ 

223 .replace("__KEEP_ITEM__", str(keep_item)) \ 

224 .replace("__BEGIN_FORMAT__", "'<li>'") \ 

225 .replace("__END_FORMAT__", "'</li>'") 

226 elif format == "rst": 

227 if header is not None and len(header) > 0: 

228 header = f"{header}\n\n" 

229 else: 

230 header = "" 

231 full = header + \ 

232 full.replace("__FORMAT__", """'* [' + title + '](#' + href + ')\\n'""") \ 

233 .replace("<ul>", "") \ 

234 .replace("</ul>", "") \ 

235 .replace("__BEGIN__", "<pre>\\n") \ 

236 .replace("__END__", "</pre>\\n") \ 

237 .replace("__KEEP_ITEM__", str(keep_item)) \ 

238 .replace("__BEGIN_FORMAT__", "") \ 

239 .replace("__END_FORMAT__", "") 

240 else: 

241 raise ValueError("format must be html or rst") 

242 

243 if raw: 

244 return full 

245 else: 

246 return HTML(full) 

247 

248 

249def load_extension(name): 

250 """ 

251 install an extension, checks first it exists, 

252 if not displays an exception with the list of them 

253 

254 @param name extension name 

255 """ 

256 return Javascript(f"IPython.utils.load_extensions('{name}')")