Show More
@@ -1,1069 +1,1074 b'' | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2008-2011 The IPython Development Team |
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |
3 | // |
|
3 | // | |
4 | // Distributed under the terms of the BSD License. The full license is in |
|
4 | // Distributed under the terms of the BSD License. The full license is in | |
5 | // the file COPYING, distributed as part of this software. |
|
5 | // the file COPYING, distributed as part of this software. | |
6 | //---------------------------------------------------------------------------- |
|
6 | //---------------------------------------------------------------------------- | |
7 |
|
7 | |||
8 | //============================================================================ |
|
8 | //============================================================================ | |
9 | // Notebook |
|
9 | // Notebook | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 |
|
11 | |||
12 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
13 |
|
13 | |||
14 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
15 |
|
15 | |||
16 | var Notebook = function (selector) { |
|
16 | var Notebook = function (selector) { | |
17 | this.read_only = IPython.read_only; |
|
17 | this.read_only = IPython.read_only; | |
18 | this.element = $(selector); |
|
18 | this.element = $(selector); | |
19 | this.element.scroll(); |
|
19 | this.element.scroll(); | |
20 | this.element.data("notebook", this); |
|
20 | this.element.data("notebook", this); | |
21 | this.next_prompt_number = 1; |
|
21 | this.next_prompt_number = 1; | |
22 | this.kernel = null; |
|
22 | this.kernel = null; | |
23 | this.dirty = false; |
|
23 | this.dirty = false; | |
24 | this.msg_cell_map = {}; |
|
24 | this.msg_cell_map = {}; | |
25 | this.metadata = {}; |
|
25 | this.metadata = {}; | |
26 | this.control_key_active = false; |
|
26 | this.control_key_active = false; | |
27 | this.style(); |
|
27 | this.style(); | |
28 | this.create_elements(); |
|
28 | this.create_elements(); | |
29 | this.bind_events(); |
|
29 | this.bind_events(); | |
30 | this.set_tooltipontab(true); |
|
30 | this.set_tooltipontab(true); | |
31 | this.set_smartcompleter(true); |
|
31 | this.set_smartcompleter(true); | |
32 | this.set_timebeforetooltip(1200); |
|
32 | this.set_timebeforetooltip(1200); | |
33 | }; |
|
33 | }; | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | Notebook.prototype.style = function () { |
|
36 | Notebook.prototype.style = function () { | |
37 | $('div#notebook').addClass('border-box-sizing'); |
|
37 | $('div#notebook').addClass('border-box-sizing'); | |
38 | }; |
|
38 | }; | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | Notebook.prototype.create_elements = function () { |
|
41 | Notebook.prototype.create_elements = function () { | |
42 | // We add this end_space div to the end of the notebook div to: |
|
42 | // We add this end_space div to the end of the notebook div to: | |
43 | // i) provide a margin between the last cell and the end of the notebook |
|
43 | // i) provide a margin between the last cell and the end of the notebook | |
44 | // ii) to prevent the div from scrolling up when the last cell is being |
|
44 | // ii) to prevent the div from scrolling up when the last cell is being | |
45 | // edited, but is too low on the page, which browsers will do automatically. |
|
45 | // edited, but is too low on the page, which browsers will do automatically. | |
46 | var that = this; |
|
46 | var that = this; | |
47 | var end_space = $('<div class="end_space"></div>').height(150); |
|
47 | var end_space = $('<div class="end_space"></div>').height(150); | |
48 | end_space.dblclick(function (e) { |
|
48 | end_space.dblclick(function (e) { | |
49 | if (that.read_only) return; |
|
49 | if (that.read_only) return; | |
50 | var ncells = that.ncells(); |
|
50 | var ncells = that.ncells(); | |
51 | that.insert_code_cell_below(ncells-1); |
|
51 | that.insert_code_cell_below(ncells-1); | |
52 | }); |
|
52 | }); | |
53 | this.element.append(end_space); |
|
53 | this.element.append(end_space); | |
54 | $('div#notebook').addClass('border-box-sizing'); |
|
54 | $('div#notebook').addClass('border-box-sizing'); | |
55 | }; |
|
55 | }; | |
56 |
|
56 | |||
57 |
|
57 | |||
58 | Notebook.prototype.bind_events = function () { |
|
58 | Notebook.prototype.bind_events = function () { | |
59 | var that = this; |
|
59 | var that = this; | |
60 | $(document).keydown(function (event) { |
|
60 | $(document).keydown(function (event) { | |
61 | // console.log(event); |
|
61 | // console.log(event); | |
62 | if (that.read_only) return; |
|
62 | if (that.read_only) return; | |
63 | if (event.which === 27) { |
|
63 | if (event.which === 27) { | |
64 | // Intercept escape at highest level to avoid closing |
|
64 | // Intercept escape at highest level to avoid closing | |
65 | // websocket connection with firefox |
|
65 | // websocket connection with firefox | |
66 | event.preventDefault(); |
|
66 | event.preventDefault(); | |
67 | } |
|
67 | } | |
68 | if (event.which === 38 && !event.shiftKey) { |
|
68 | if (event.which === 38 && !event.shiftKey) { | |
69 | var cell = that.selected_cell(); |
|
69 | var cell = that.selected_cell(); | |
70 | if (cell.at_top()) { |
|
70 | if (cell.at_top()) { | |
71 | event.preventDefault(); |
|
71 | event.preventDefault(); | |
72 | that.select_prev(); |
|
72 | that.select_prev(); | |
73 | }; |
|
73 | }; | |
74 | } else if (event.which === 40 && !event.shiftKey) { |
|
74 | } else if (event.which === 40 && !event.shiftKey) { | |
75 | var cell = that.selected_cell(); |
|
75 | var cell = that.selected_cell(); | |
76 | if (cell.at_bottom()) { |
|
76 | if (cell.at_bottom()) { | |
77 | event.preventDefault(); |
|
77 | event.preventDefault(); | |
78 | that.select_next(); |
|
78 | that.select_next(); | |
79 | }; |
|
79 | }; | |
80 | } else if (event.which === 13 && event.shiftKey) { |
|
80 | } else if (event.which === 13 && event.shiftKey) { | |
81 | that.execute_selected_cell(); |
|
81 | that.execute_selected_cell(); | |
82 | return false; |
|
82 | return false; | |
83 | } else if (event.which === 13 && event.ctrlKey) { |
|
83 | } else if (event.which === 13 && event.ctrlKey) { | |
84 | that.execute_selected_cell({terminal:true}); |
|
84 | that.execute_selected_cell({terminal:true}); | |
85 | return false; |
|
85 | return false; | |
86 | } else if (event.which === 77 && event.ctrlKey) { |
|
86 | } else if (event.which === 77 && event.ctrlKey) { | |
87 | that.control_key_active = true; |
|
87 | that.control_key_active = true; | |
88 | return false; |
|
88 | return false; | |
89 | } else if (event.which === 68 && that.control_key_active) { |
|
89 | } else if (event.which === 68 && that.control_key_active) { | |
90 | // Delete selected cell = d |
|
90 | // Delete selected cell = d | |
91 | that.delete_cell(); |
|
91 | that.delete_cell(); | |
92 | that.control_key_active = false; |
|
92 | that.control_key_active = false; | |
93 | return false; |
|
93 | return false; | |
94 | } else if (event.which === 65 && that.control_key_active) { |
|
94 | } else if (event.which === 65 && that.control_key_active) { | |
95 | // Insert code cell above selected = a |
|
95 | // Insert code cell above selected = a | |
96 | that.insert_code_cell_above(); |
|
96 | that.insert_code_cell_above(); | |
97 | that.control_key_active = false; |
|
97 | that.control_key_active = false; | |
98 | return false; |
|
98 | return false; | |
99 | } else if (event.which === 66 && that.control_key_active) { |
|
99 | } else if (event.which === 66 && that.control_key_active) { | |
100 | // Insert code cell below selected = b |
|
100 | // Insert code cell below selected = b | |
101 | that.insert_code_cell_below(); |
|
101 | that.insert_code_cell_below(); | |
102 | that.control_key_active = false; |
|
102 | that.control_key_active = false; | |
103 | return false; |
|
103 | return false; | |
104 | } else if (event.which === 67 && that.control_key_active) { |
|
104 | } else if (event.which === 67 && that.control_key_active) { | |
105 | // To code = c |
|
105 | // To code = c | |
106 | that.to_code(); |
|
106 | that.to_code(); | |
107 | that.control_key_active = false; |
|
107 | that.control_key_active = false; | |
108 | return false; |
|
108 | return false; | |
109 | } else if (event.which === 77 && that.control_key_active) { |
|
109 | } else if (event.which === 77 && that.control_key_active) { | |
110 | // To markdown = m |
|
110 | // To markdown = m | |
111 | that.to_markdown(); |
|
111 | that.to_markdown(); | |
112 | that.control_key_active = false; |
|
112 | that.control_key_active = false; | |
113 | return false; |
|
113 | return false; | |
114 | } else if (event.which === 84 && that.control_key_active) { |
|
114 | } else if (event.which === 84 && that.control_key_active) { | |
115 | // Toggle output = t |
|
115 | // Toggle output = t | |
116 | that.toggle_output(); |
|
116 | that.toggle_output(); | |
117 | that.control_key_active = false; |
|
117 | that.control_key_active = false; | |
118 | return false; |
|
118 | return false; | |
119 | } else if (event.which === 83 && that.control_key_active) { |
|
119 | } else if (event.which === 83 && that.control_key_active) { | |
120 | // Save notebook = s |
|
120 | // Save notebook = s | |
121 | IPython.save_widget.save_notebook(); |
|
121 | IPython.save_widget.save_notebook(); | |
122 | that.control_key_active = false; |
|
122 | that.control_key_active = false; | |
123 | return false; |
|
123 | return false; | |
124 | } else if (event.which === 74 && that.control_key_active) { |
|
124 | } else if (event.which === 74 && that.control_key_active) { | |
125 | // Move cell down = j |
|
125 | // Move cell down = j | |
126 | that.move_cell_down(); |
|
126 | that.move_cell_down(); | |
127 | that.control_key_active = false; |
|
127 | that.control_key_active = false; | |
128 | return false; |
|
128 | return false; | |
129 | } else if (event.which === 75 && that.control_key_active) { |
|
129 | } else if (event.which === 75 && that.control_key_active) { | |
130 | // Move cell up = k |
|
130 | // Move cell up = k | |
131 | that.move_cell_up(); |
|
131 | that.move_cell_up(); | |
132 | that.control_key_active = false; |
|
132 | that.control_key_active = false; | |
133 | return false; |
|
133 | return false; | |
134 | } else if (event.which === 80 && that.control_key_active) { |
|
134 | } else if (event.which === 80 && that.control_key_active) { | |
135 | // Select previous = p |
|
135 | // Select previous = p | |
136 | that.select_prev(); |
|
136 | that.select_prev(); | |
137 | that.control_key_active = false; |
|
137 | that.control_key_active = false; | |
138 | return false; |
|
138 | return false; | |
139 | } else if (event.which === 78 && that.control_key_active) { |
|
139 | } else if (event.which === 78 && that.control_key_active) { | |
140 | // Select next = n |
|
140 | // Select next = n | |
141 | that.select_next(); |
|
141 | that.select_next(); | |
142 | that.control_key_active = false; |
|
142 | that.control_key_active = false; | |
143 | return false; |
|
143 | return false; | |
144 | } else if (event.which === 76 && that.control_key_active) { |
|
144 | } else if (event.which === 76 && that.control_key_active) { | |
145 | // Toggle line numbers = l |
|
145 | // Toggle line numbers = l | |
146 | that.cell_toggle_line_numbers(); |
|
146 | that.cell_toggle_line_numbers(); | |
147 | that.control_key_active = false; |
|
147 | that.control_key_active = false; | |
148 | return false; |
|
148 | return false; | |
149 | } else if (event.which === 73 && that.control_key_active) { |
|
149 | } else if (event.which === 73 && that.control_key_active) { | |
150 | // Interrupt kernel = i |
|
150 | // Interrupt kernel = i | |
151 | IPython.notebook.kernel.interrupt(); |
|
151 | IPython.notebook.kernel.interrupt(); | |
152 | that.control_key_active = false; |
|
152 | that.control_key_active = false; | |
153 | return false; |
|
153 | return false; | |
154 | } else if (event.which === 190 && that.control_key_active) { |
|
154 | } else if (event.which === 190 && that.control_key_active) { | |
155 | // Restart kernel = . # matches qt console |
|
155 | // Restart kernel = . # matches qt console | |
156 | IPython.notebook.restart_kernel(); |
|
156 | IPython.notebook.restart_kernel(); | |
157 | that.control_key_active = false; |
|
157 | that.control_key_active = false; | |
158 | return false; |
|
158 | return false; | |
159 | } else if (event.which === 72 && that.control_key_active) { |
|
159 | } else if (event.which === 72 && that.control_key_active) { | |
160 | // Show keyboard shortcuts = h |
|
160 | // Show keyboard shortcuts = h | |
161 | that.toggle_keyboard_shortcuts(); |
|
161 | that.toggle_keyboard_shortcuts(); | |
162 | that.control_key_active = false; |
|
162 | that.control_key_active = false; | |
163 | return false; |
|
163 | return false; | |
164 | } else if (that.control_key_active) { |
|
164 | } else if (that.control_key_active) { | |
165 | that.control_key_active = false; |
|
165 | that.control_key_active = false; | |
166 | return true; |
|
166 | return true; | |
167 | }; |
|
167 | }; | |
168 | }); |
|
168 | }); | |
169 |
|
169 | |||
170 | this.element.bind('collapse_pager', function () { |
|
170 | this.element.bind('collapse_pager', function () { | |
171 | var app_height = $('div#main_app').height(); // content height |
|
171 | var app_height = $('div#main_app').height(); // content height | |
172 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
172 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
173 | var new_height = app_height - splitter_height; |
|
173 | var new_height = app_height - splitter_height; | |
174 | that.element.animate({height : new_height + 'px'}, 'fast'); |
|
174 | that.element.animate({height : new_height + 'px'}, 'fast'); | |
175 | }); |
|
175 | }); | |
176 |
|
176 | |||
177 | this.element.bind('expand_pager', function () { |
|
177 | this.element.bind('expand_pager', function () { | |
178 | var app_height = $('div#main_app').height(); // content height |
|
178 | var app_height = $('div#main_app').height(); // content height | |
179 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
179 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
180 | var pager_height = $('div#pager').outerHeight(true); |
|
180 | var pager_height = $('div#pager').outerHeight(true); | |
181 | var new_height = app_height - pager_height - splitter_height; |
|
181 | var new_height = app_height - pager_height - splitter_height; | |
182 | that.element.animate({height : new_height + 'px'}, 'fast'); |
|
182 | that.element.animate({height : new_height + 'px'}, 'fast'); | |
183 | }); |
|
183 | }); | |
184 |
|
184 | |||
185 | this.element.bind('collapse_left_panel', function () { |
|
185 | this.element.bind('collapse_left_panel', function () { | |
186 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); |
|
186 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); | |
187 | var new_margin = splitter_width; |
|
187 | var new_margin = splitter_width; | |
188 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); |
|
188 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); | |
189 | }); |
|
189 | }); | |
190 |
|
190 | |||
191 | this.element.bind('expand_left_panel', function () { |
|
191 | this.element.bind('expand_left_panel', function () { | |
192 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); |
|
192 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); | |
193 | var left_panel_width = IPython.left_panel.width; |
|
193 | var left_panel_width = IPython.left_panel.width; | |
194 | var new_margin = splitter_width + left_panel_width; |
|
194 | var new_margin = splitter_width + left_panel_width; | |
195 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); |
|
195 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); | |
196 | }); |
|
196 | }); | |
197 |
|
197 | |||
198 | $(window).bind('beforeunload', function () { |
|
198 | $(window).bind('beforeunload', function () { | |
199 | var kill_kernel = $('#kill_kernel').prop('checked'); |
|
199 | var kill_kernel = $('#kill_kernel').prop('checked'); | |
200 | if (kill_kernel) { |
|
200 | if (kill_kernel) { | |
201 | that.kernel.kill(); |
|
201 | that.kernel.kill(); | |
202 | } |
|
202 | } | |
203 | if (that.dirty && ! that.read_only) { |
|
203 | if (that.dirty && ! that.read_only) { | |
204 | return "You have unsaved changes that will be lost if you leave this page."; |
|
204 | return "You have unsaved changes that will be lost if you leave this page."; | |
205 | }; |
|
205 | }; | |
206 | }); |
|
206 | }); | |
207 | }; |
|
207 | }; | |
208 |
|
208 | |||
209 |
|
209 | |||
210 | Notebook.prototype.toggle_keyboard_shortcuts = function () { |
|
210 | Notebook.prototype.toggle_keyboard_shortcuts = function () { | |
211 | // toggles display of keyboard shortcut dialog |
|
211 | // toggles display of keyboard shortcut dialog | |
212 | var that = this; |
|
212 | var that = this; | |
213 | if ( this.shortcut_dialog ){ |
|
213 | if ( this.shortcut_dialog ){ | |
214 | // if dialog is already shown, close it |
|
214 | // if dialog is already shown, close it | |
215 | this.shortcut_dialog.dialog("close"); |
|
215 | this.shortcut_dialog.dialog("close"); | |
216 | this.shortcut_dialog = null; |
|
216 | this.shortcut_dialog = null; | |
217 | return; |
|
217 | return; | |
218 | } |
|
218 | } | |
219 | var dialog = $('<div/>'); |
|
219 | var dialog = $('<div/>'); | |
220 | this.shortcut_dialog = dialog; |
|
220 | this.shortcut_dialog = dialog; | |
221 | var shortcuts = [ |
|
221 | var shortcuts = [ | |
222 | {key: 'Shift-Enter', help: 'run cell'}, |
|
222 | {key: 'Shift-Enter', help: 'run cell'}, | |
223 | {key: 'Ctrl-Enter', help: 'run cell in-place'}, |
|
223 | {key: 'Ctrl-Enter', help: 'run cell in-place'}, | |
224 | {key: 'Ctrl-m d', help: 'delete cell'}, |
|
224 | {key: 'Ctrl-m d', help: 'delete cell'}, | |
225 | {key: 'Ctrl-m a', help: 'insert cell above'}, |
|
225 | {key: 'Ctrl-m a', help: 'insert cell above'}, | |
226 | {key: 'Ctrl-m b', help: 'insert cell below'}, |
|
226 | {key: 'Ctrl-m b', help: 'insert cell below'}, | |
227 | {key: 'Ctrl-m t', help: 'toggle output'}, |
|
227 | {key: 'Ctrl-m t', help: 'toggle output'}, | |
228 | {key: 'Ctrl-m l', help: 'toggle line numbers'}, |
|
228 | {key: 'Ctrl-m l', help: 'toggle line numbers'}, | |
229 | {key: 'Ctrl-m s', help: 'save notebook'}, |
|
229 | {key: 'Ctrl-m s', help: 'save notebook'}, | |
230 | {key: 'Ctrl-m j', help: 'move cell down'}, |
|
230 | {key: 'Ctrl-m j', help: 'move cell down'}, | |
231 | {key: 'Ctrl-m k', help: 'move cell up'}, |
|
231 | {key: 'Ctrl-m k', help: 'move cell up'}, | |
232 | {key: 'Ctrl-m c', help: 'code cell'}, |
|
232 | {key: 'Ctrl-m c', help: 'code cell'}, | |
233 | {key: 'Ctrl-m m', help: 'markdown cell'}, |
|
233 | {key: 'Ctrl-m m', help: 'markdown cell'}, | |
234 | {key: 'Ctrl-m p', help: 'select previous'}, |
|
234 | {key: 'Ctrl-m p', help: 'select previous'}, | |
235 | {key: 'Ctrl-m n', help: 'select next'}, |
|
235 | {key: 'Ctrl-m n', help: 'select next'}, | |
236 | {key: 'Ctrl-m i', help: 'interrupt kernel'}, |
|
236 | {key: 'Ctrl-m i', help: 'interrupt kernel'}, | |
237 | {key: 'Ctrl-m .', help: 'restart kernel'}, |
|
237 | {key: 'Ctrl-m .', help: 'restart kernel'}, | |
238 | {key: 'Ctrl-m h', help: 'show keyboard shortcuts'} |
|
238 | {key: 'Ctrl-m h', help: 'show keyboard shortcuts'} | |
239 | ]; |
|
239 | ]; | |
240 | for (var i=0; i<shortcuts.length; i++) { |
|
240 | for (var i=0; i<shortcuts.length; i++) { | |
241 | dialog.append($('<div>'). |
|
241 | dialog.append($('<div>'). | |
242 | append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)). |
|
242 | append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)). | |
243 | append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help)) |
|
243 | append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help)) | |
244 | ); |
|
244 | ); | |
245 | }; |
|
245 | }; | |
246 | dialog.bind('dialogclose', function(event) { |
|
246 | dialog.bind('dialogclose', function(event) { | |
247 | // dialog has been closed, allow it to be drawn again. |
|
247 | // dialog has been closed, allow it to be drawn again. | |
248 | that.shortcut_dialog = null; |
|
248 | that.shortcut_dialog = null; | |
249 | }); |
|
249 | }); | |
250 | dialog.dialog({title: 'Keyboard shortcuts'}); |
|
250 | dialog.dialog({title: 'Keyboard shortcuts'}); | |
251 | }; |
|
251 | }; | |
252 |
|
252 | |||
253 |
|
253 | |||
254 | Notebook.prototype.scroll_to_bottom = function () { |
|
254 | Notebook.prototype.scroll_to_bottom = function () { | |
255 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); |
|
255 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); | |
256 | }; |
|
256 | }; | |
257 |
|
257 | |||
258 |
|
258 | |||
259 | Notebook.prototype.scroll_to_top = function () { |
|
259 | Notebook.prototype.scroll_to_top = function () { | |
260 | this.element.animate({scrollTop:0}, 0); |
|
260 | this.element.animate({scrollTop:0}, 0); | |
261 | }; |
|
261 | }; | |
262 |
|
262 | |||
263 |
|
263 | |||
264 | // Cell indexing, retrieval, etc. |
|
264 | // Cell indexing, retrieval, etc. | |
265 |
|
265 | |||
266 |
|
266 | |||
267 | Notebook.prototype.cell_elements = function () { |
|
267 | Notebook.prototype.cell_elements = function () { | |
268 | return this.element.children("div.cell"); |
|
268 | return this.element.children("div.cell"); | |
269 | } |
|
269 | } | |
270 |
|
270 | |||
271 |
|
271 | |||
272 | Notebook.prototype.ncells = function (cell) { |
|
272 | Notebook.prototype.ncells = function (cell) { | |
273 | return this.cell_elements().length; |
|
273 | return this.cell_elements().length; | |
274 | } |
|
274 | } | |
275 |
|
275 | |||
276 |
|
276 | |||
277 | // TODO: we are often calling cells as cells()[i], which we should optimize |
|
277 | // TODO: we are often calling cells as cells()[i], which we should optimize | |
278 | // to cells(i) or a new method. |
|
278 | // to cells(i) or a new method. | |
279 | Notebook.prototype.cells = function () { |
|
279 | Notebook.prototype.cells = function () { | |
280 | return this.cell_elements().toArray().map(function (e) { |
|
280 | return this.cell_elements().toArray().map(function (e) { | |
281 | return $(e).data("cell"); |
|
281 | return $(e).data("cell"); | |
282 | }); |
|
282 | }); | |
283 | } |
|
283 | } | |
284 |
|
284 | |||
285 |
|
285 | |||
286 | Notebook.prototype.find_cell_index = function (cell) { |
|
286 | Notebook.prototype.find_cell_index = function (cell) { | |
287 | var result = null; |
|
287 | var result = null; | |
288 | this.cell_elements().filter(function (index) { |
|
288 | this.cell_elements().filter(function (index) { | |
289 | if ($(this).data("cell") === cell) { |
|
289 | if ($(this).data("cell") === cell) { | |
290 | result = index; |
|
290 | result = index; | |
291 | }; |
|
291 | }; | |
292 | }); |
|
292 | }); | |
293 | return result; |
|
293 | return result; | |
294 | }; |
|
294 | }; | |
295 |
|
295 | |||
296 |
|
296 | |||
297 | Notebook.prototype.index_or_selected = function (index) { |
|
297 | Notebook.prototype.index_or_selected = function (index) { | |
298 | return index || this.selected_index() || 0; |
|
298 | return index || this.selected_index() || 0; | |
299 | } |
|
299 | } | |
300 |
|
300 | |||
301 |
|
301 | |||
302 | Notebook.prototype.select = function (index) { |
|
302 | Notebook.prototype.select = function (index) { | |
303 | if (index !== undefined && index >= 0 && index < this.ncells()) { |
|
303 | if (index !== undefined && index >= 0 && index < this.ncells()) { | |
304 | if (this.selected_index() !== null) { |
|
304 | if (this.selected_index() !== null) { | |
305 | this.selected_cell().unselect(); |
|
305 | this.selected_cell().unselect(); | |
306 | }; |
|
306 | }; | |
307 | this.cells()[index].select(); |
|
307 | this.cells()[index].select(); | |
308 | }; |
|
308 | }; | |
309 | return this; |
|
309 | return this; | |
310 | }; |
|
310 | }; | |
311 |
|
311 | |||
312 |
|
312 | |||
313 | Notebook.prototype.select_next = function () { |
|
313 | Notebook.prototype.select_next = function () { | |
314 | var index = this.selected_index(); |
|
314 | var index = this.selected_index(); | |
315 | if (index !== null && index >= 0 && (index+1) < this.ncells()) { |
|
315 | if (index !== null && index >= 0 && (index+1) < this.ncells()) { | |
316 | this.select(index+1); |
|
316 | this.select(index+1); | |
317 | }; |
|
317 | }; | |
318 | return this; |
|
318 | return this; | |
319 | }; |
|
319 | }; | |
320 |
|
320 | |||
321 |
|
321 | |||
322 | Notebook.prototype.select_prev = function () { |
|
322 | Notebook.prototype.select_prev = function () { | |
323 | var index = this.selected_index(); |
|
323 | var index = this.selected_index(); | |
324 | if (index !== null && index >= 0 && (index-1) < this.ncells()) { |
|
324 | if (index !== null && index >= 0 && (index-1) < this.ncells()) { | |
325 | this.select(index-1); |
|
325 | this.select(index-1); | |
326 | }; |
|
326 | }; | |
327 | return this; |
|
327 | return this; | |
328 | }; |
|
328 | }; | |
329 |
|
329 | |||
330 |
|
330 | |||
331 | Notebook.prototype.selected_index = function () { |
|
331 | Notebook.prototype.selected_index = function () { | |
332 | var result = null; |
|
332 | var result = null; | |
333 | this.cell_elements().filter(function (index) { |
|
333 | this.cell_elements().filter(function (index) { | |
334 | if ($(this).data("cell").selected === true) { |
|
334 | if ($(this).data("cell").selected === true) { | |
335 | result = index; |
|
335 | result = index; | |
336 | }; |
|
336 | }; | |
337 | }); |
|
337 | }); | |
338 | return result; |
|
338 | return result; | |
339 | }; |
|
339 | }; | |
340 |
|
340 | |||
341 |
|
341 | |||
342 | Notebook.prototype.cell_for_msg = function (msg_id) { |
|
342 | Notebook.prototype.cell_for_msg = function (msg_id) { | |
343 | var cell_id = this.msg_cell_map[msg_id]; |
|
343 | var cell_id = this.msg_cell_map[msg_id]; | |
344 | var result = null; |
|
344 | var result = null; | |
345 | this.cell_elements().filter(function (index) { |
|
345 | this.cell_elements().filter(function (index) { | |
346 | cell = $(this).data("cell"); |
|
346 | cell = $(this).data("cell"); | |
347 | if (cell.cell_id === cell_id) { |
|
347 | if (cell.cell_id === cell_id) { | |
348 | result = cell; |
|
348 | result = cell; | |
349 | }; |
|
349 | }; | |
350 | }); |
|
350 | }); | |
351 | return result; |
|
351 | return result; | |
352 | }; |
|
352 | }; | |
353 |
|
353 | |||
354 |
|
354 | |||
355 | Notebook.prototype.selected_cell = function () { |
|
355 | Notebook.prototype.selected_cell = function () { | |
356 | return this.cell_elements().eq(this.selected_index()).data("cell"); |
|
356 | return this.cell_elements().eq(this.selected_index()).data("cell"); | |
357 | } |
|
357 | } | |
358 |
|
358 | |||
359 |
|
359 | |||
360 | // Cell insertion, deletion and moving. |
|
360 | // Cell insertion, deletion and moving. | |
361 |
|
361 | |||
362 |
|
362 | |||
363 | Notebook.prototype.delete_cell = function (index) { |
|
363 | Notebook.prototype.delete_cell = function (index) { | |
364 | var i = index || this.selected_index(); |
|
364 | var i = index || this.selected_index(); | |
365 | if (i !== null && i >= 0 && i < this.ncells()) { |
|
365 | if (i !== null && i >= 0 && i < this.ncells()) { | |
366 | this.cell_elements().eq(i).remove(); |
|
366 | this.cell_elements().eq(i).remove(); | |
367 | if (i === (this.ncells())) { |
|
367 | if (i === (this.ncells())) { | |
368 | this.select(i-1); |
|
368 | this.select(i-1); | |
369 | } else { |
|
369 | } else { | |
370 | this.select(i); |
|
370 | this.select(i); | |
371 | }; |
|
371 | }; | |
372 | }; |
|
372 | }; | |
373 | this.dirty = true; |
|
373 | this.dirty = true; | |
374 | return this; |
|
374 | return this; | |
375 | }; |
|
375 | }; | |
376 |
|
376 | |||
377 |
|
377 | |||
378 | Notebook.prototype.append_cell = function (cell) { |
|
378 | Notebook.prototype.append_cell = function (cell) { | |
379 | this.element.find('div.end_space').before(cell.element); |
|
379 | this.element.find('div.end_space').before(cell.element); | |
380 | this.dirty = true; |
|
380 | this.dirty = true; | |
381 | return this; |
|
381 | return this; | |
382 | }; |
|
382 | }; | |
383 |
|
383 | |||
384 |
|
384 | |||
385 | Notebook.prototype.insert_cell_below = function (cell, index) { |
|
385 | Notebook.prototype.insert_cell_below = function (cell, index) { | |
386 | var ncells = this.ncells(); |
|
386 | var ncells = this.ncells(); | |
387 | if (ncells === 0) { |
|
387 | if (ncells === 0) { | |
388 | this.append_cell(cell); |
|
388 | this.append_cell(cell); | |
389 | return this; |
|
389 | return this; | |
390 | }; |
|
390 | }; | |
391 | if (index >= 0 && index < ncells) { |
|
391 | if (index >= 0 && index < ncells) { | |
392 | this.cell_elements().eq(index).after(cell.element); |
|
392 | this.cell_elements().eq(index).after(cell.element); | |
393 | }; |
|
393 | }; | |
394 | this.dirty = true; |
|
394 | this.dirty = true; | |
395 | return this |
|
395 | return this | |
396 | }; |
|
396 | }; | |
397 |
|
397 | |||
398 |
|
398 | |||
399 | Notebook.prototype.insert_cell_above = function (cell, index) { |
|
399 | Notebook.prototype.insert_cell_above = function (cell, index) { | |
400 | var ncells = this.ncells(); |
|
400 | var ncells = this.ncells(); | |
401 | if (ncells === 0) { |
|
401 | if (ncells === 0) { | |
402 | this.append_cell(cell); |
|
402 | this.append_cell(cell); | |
403 | return this; |
|
403 | return this; | |
404 | }; |
|
404 | }; | |
405 | if (index >= 0 && index < ncells) { |
|
405 | if (index >= 0 && index < ncells) { | |
406 | this.cell_elements().eq(index).before(cell.element); |
|
406 | this.cell_elements().eq(index).before(cell.element); | |
407 | }; |
|
407 | }; | |
408 | this.dirty = true; |
|
408 | this.dirty = true; | |
409 | return this; |
|
409 | return this; | |
410 | }; |
|
410 | }; | |
411 |
|
411 | |||
412 |
|
412 | |||
413 | Notebook.prototype.move_cell_up = function (index) { |
|
413 | Notebook.prototype.move_cell_up = function (index) { | |
414 | var i = index || this.selected_index(); |
|
414 | var i = index || this.selected_index(); | |
415 | if (i !== null && i < this.ncells() && i > 0) { |
|
415 | if (i !== null && i < this.ncells() && i > 0) { | |
416 | var pivot = this.cell_elements().eq(i-1); |
|
416 | var pivot = this.cell_elements().eq(i-1); | |
417 | var tomove = this.cell_elements().eq(i); |
|
417 | var tomove = this.cell_elements().eq(i); | |
418 | if (pivot !== null && tomove !== null) { |
|
418 | if (pivot !== null && tomove !== null) { | |
419 | tomove.detach(); |
|
419 | tomove.detach(); | |
420 | pivot.before(tomove); |
|
420 | pivot.before(tomove); | |
421 | this.select(i-1); |
|
421 | this.select(i-1); | |
422 | }; |
|
422 | }; | |
423 | }; |
|
423 | }; | |
424 | this.dirty = true; |
|
424 | this.dirty = true; | |
425 | return this; |
|
425 | return this; | |
426 | } |
|
426 | } | |
427 |
|
427 | |||
428 |
|
428 | |||
429 | Notebook.prototype.move_cell_down = function (index) { |
|
429 | Notebook.prototype.move_cell_down = function (index) { | |
430 | var i = index || this.selected_index(); |
|
430 | var i = index || this.selected_index(); | |
431 | if (i !== null && i < (this.ncells()-1) && i >= 0) { |
|
431 | if (i !== null && i < (this.ncells()-1) && i >= 0) { | |
432 | var pivot = this.cell_elements().eq(i+1) |
|
432 | var pivot = this.cell_elements().eq(i+1) | |
433 | var tomove = this.cell_elements().eq(i) |
|
433 | var tomove = this.cell_elements().eq(i) | |
434 | if (pivot !== null && tomove !== null) { |
|
434 | if (pivot !== null && tomove !== null) { | |
435 | tomove.detach(); |
|
435 | tomove.detach(); | |
436 | pivot.after(tomove); |
|
436 | pivot.after(tomove); | |
437 | this.select(i+1); |
|
437 | this.select(i+1); | |
438 | }; |
|
438 | }; | |
439 | }; |
|
439 | }; | |
440 | this.dirty = true; |
|
440 | this.dirty = true; | |
441 | return this; |
|
441 | return this; | |
442 | } |
|
442 | } | |
443 |
|
443 | |||
444 |
|
444 | |||
445 | Notebook.prototype.sort_cells = function () { |
|
445 | Notebook.prototype.sort_cells = function () { | |
446 | var ncells = this.ncells(); |
|
446 | var ncells = this.ncells(); | |
447 | var sindex = this.selected_index(); |
|
447 | var sindex = this.selected_index(); | |
448 | var swapped; |
|
448 | var swapped; | |
449 | do { |
|
449 | do { | |
450 | swapped = false |
|
450 | swapped = false | |
451 | for (var i=1; i<ncells; i++) { |
|
451 | for (var i=1; i<ncells; i++) { | |
452 | current = this.cell_elements().eq(i).data("cell"); |
|
452 | current = this.cell_elements().eq(i).data("cell"); | |
453 | previous = this.cell_elements().eq(i-1).data("cell"); |
|
453 | previous = this.cell_elements().eq(i-1).data("cell"); | |
454 | if (previous.input_prompt_number > current.input_prompt_number) { |
|
454 | if (previous.input_prompt_number > current.input_prompt_number) { | |
455 | this.move_cell_up(i); |
|
455 | this.move_cell_up(i); | |
456 | swapped = true; |
|
456 | swapped = true; | |
457 | }; |
|
457 | }; | |
458 | }; |
|
458 | }; | |
459 | } while (swapped); |
|
459 | } while (swapped); | |
460 | this.select(sindex); |
|
460 | this.select(sindex); | |
461 | return this; |
|
461 | return this; | |
462 | }; |
|
462 | }; | |
463 |
|
463 | |||
464 |
|
464 | |||
465 | Notebook.prototype.insert_code_cell_above = function (index) { |
|
465 | Notebook.prototype.insert_code_cell_above = function (index) { | |
466 | // TODO: Bounds check for i |
|
466 | // TODO: Bounds check for i | |
467 | var i = this.index_or_selected(index); |
|
467 | var i = this.index_or_selected(index); | |
468 | var cell = new IPython.CodeCell(this); |
|
468 | var cell = new IPython.CodeCell(this); | |
469 | cell.set_input_prompt(); |
|
469 | cell.set_input_prompt(); | |
470 | this.insert_cell_above(cell, i); |
|
470 | this.insert_cell_above(cell, i); | |
471 | this.select(this.find_cell_index(cell)); |
|
471 | this.select(this.find_cell_index(cell)); | |
472 | return cell; |
|
472 | return cell; | |
473 | } |
|
473 | } | |
474 |
|
474 | |||
475 |
|
475 | |||
476 | Notebook.prototype.insert_code_cell_below = function (index) { |
|
476 | Notebook.prototype.insert_code_cell_below = function (index) { | |
477 | // TODO: Bounds check for i |
|
477 | // TODO: Bounds check for i | |
478 | var i = this.index_or_selected(index); |
|
478 | var i = this.index_or_selected(index); | |
479 | var cell = new IPython.CodeCell(this); |
|
479 | var cell = new IPython.CodeCell(this); | |
480 | cell.set_input_prompt(); |
|
480 | cell.set_input_prompt(); | |
481 | this.insert_cell_below(cell, i); |
|
481 | this.insert_cell_below(cell, i); | |
482 | this.select(this.find_cell_index(cell)); |
|
482 | this.select(this.find_cell_index(cell)); | |
483 | return cell; |
|
483 | return cell; | |
484 | } |
|
484 | } | |
485 |
|
485 | |||
486 |
|
486 | |||
487 | Notebook.prototype.insert_html_cell_above = function (index) { |
|
487 | Notebook.prototype.insert_html_cell_above = function (index) { | |
488 | // TODO: Bounds check for i |
|
488 | // TODO: Bounds check for i | |
489 | var i = this.index_or_selected(index); |
|
489 | var i = this.index_or_selected(index); | |
490 | var cell = new IPython.HTMLCell(this); |
|
490 | var cell = new IPython.HTMLCell(this); | |
491 | cell.config_mathjax(); |
|
491 | cell.config_mathjax(); | |
492 | this.insert_cell_above(cell, i); |
|
492 | this.insert_cell_above(cell, i); | |
493 | this.select(this.find_cell_index(cell)); |
|
493 | this.select(this.find_cell_index(cell)); | |
494 | return cell; |
|
494 | return cell; | |
495 | } |
|
495 | } | |
496 |
|
496 | |||
497 |
|
497 | |||
498 | Notebook.prototype.insert_html_cell_below = function (index) { |
|
498 | Notebook.prototype.insert_html_cell_below = function (index) { | |
499 | // TODO: Bounds check for i |
|
499 | // TODO: Bounds check for i | |
500 | var i = this.index_or_selected(index); |
|
500 | var i = this.index_or_selected(index); | |
501 | var cell = new IPython.HTMLCell(this); |
|
501 | var cell = new IPython.HTMLCell(this); | |
502 | cell.config_mathjax(); |
|
502 | cell.config_mathjax(); | |
503 | this.insert_cell_below(cell, i); |
|
503 | this.insert_cell_below(cell, i); | |
504 | this.select(this.find_cell_index(cell)); |
|
504 | this.select(this.find_cell_index(cell)); | |
505 | return cell; |
|
505 | return cell; | |
506 | } |
|
506 | } | |
507 |
|
507 | |||
508 |
|
508 | |||
509 | Notebook.prototype.insert_markdown_cell_above = function (index) { |
|
509 | Notebook.prototype.insert_markdown_cell_above = function (index) { | |
510 | // TODO: Bounds check for i |
|
510 | // TODO: Bounds check for i | |
511 | var i = this.index_or_selected(index); |
|
511 | var i = this.index_or_selected(index); | |
512 | var cell = new IPython.MarkdownCell(this); |
|
512 | var cell = new IPython.MarkdownCell(this); | |
513 | cell.config_mathjax(); |
|
513 | cell.config_mathjax(); | |
514 | this.insert_cell_above(cell, i); |
|
514 | this.insert_cell_above(cell, i); | |
515 | this.select(this.find_cell_index(cell)); |
|
515 | this.select(this.find_cell_index(cell)); | |
516 | return cell; |
|
516 | return cell; | |
517 | } |
|
517 | } | |
518 |
|
518 | |||
519 |
|
519 | |||
520 | Notebook.prototype.insert_markdown_cell_below = function (index) { |
|
520 | Notebook.prototype.insert_markdown_cell_below = function (index) { | |
521 | // TODO: Bounds check for i |
|
521 | // TODO: Bounds check for i | |
522 | var i = this.index_or_selected(index); |
|
522 | var i = this.index_or_selected(index); | |
523 | var cell = new IPython.MarkdownCell(this); |
|
523 | var cell = new IPython.MarkdownCell(this); | |
524 | cell.config_mathjax(); |
|
524 | cell.config_mathjax(); | |
525 | this.insert_cell_below(cell, i); |
|
525 | this.insert_cell_below(cell, i); | |
526 | this.select(this.find_cell_index(cell)); |
|
526 | this.select(this.find_cell_index(cell)); | |
527 | return cell; |
|
527 | return cell; | |
528 | } |
|
528 | } | |
529 |
|
529 | |||
530 |
|
530 | |||
531 | Notebook.prototype.to_code = function (index) { |
|
531 | Notebook.prototype.to_code = function (index) { | |
532 | // TODO: Bounds check for i |
|
532 | // TODO: Bounds check for i | |
533 | var i = this.index_or_selected(index); |
|
533 | var i = this.index_or_selected(index); | |
534 | var source_element = this.cell_elements().eq(i); |
|
534 | var source_element = this.cell_elements().eq(i); | |
535 | var source_cell = source_element.data("cell"); |
|
535 | var source_cell = source_element.data("cell"); | |
536 | if (source_cell instanceof IPython.HTMLCell || |
|
536 | if (source_cell instanceof IPython.HTMLCell || | |
537 | source_cell instanceof IPython.MarkdownCell) { |
|
537 | source_cell instanceof IPython.MarkdownCell) { | |
538 | this.insert_code_cell_below(i); |
|
538 | this.insert_code_cell_below(i); | |
539 | var target_cell = this.cells()[i+1]; |
|
539 | var target_cell = this.cells()[i+1]; | |
540 | target_cell.set_code(source_cell.get_source()); |
|
540 | target_cell.set_code(source_cell.get_source()); | |
541 | source_element.remove(); |
|
541 | source_element.remove(); | |
542 | target_cell.select(); |
|
542 | target_cell.select(); | |
543 | }; |
|
543 | }; | |
544 | this.dirty = true; |
|
544 | this.dirty = true; | |
545 | }; |
|
545 | }; | |
546 |
|
546 | |||
547 |
|
547 | |||
548 | Notebook.prototype.to_markdown = function (index) { |
|
548 | Notebook.prototype.to_markdown = function (index) { | |
549 | // TODO: Bounds check for i |
|
549 | // TODO: Bounds check for i | |
550 | var i = this.index_or_selected(index); |
|
550 | var i = this.index_or_selected(index); | |
551 | var source_element = this.cell_elements().eq(i); |
|
551 | var source_element = this.cell_elements().eq(i); | |
552 | var source_cell = source_element.data("cell"); |
|
552 | var source_cell = source_element.data("cell"); | |
553 | var target_cell = null; |
|
553 | var target_cell = null; | |
554 | if (source_cell instanceof IPython.CodeCell) { |
|
554 | if (source_cell instanceof IPython.CodeCell) { | |
555 | this.insert_markdown_cell_below(i); |
|
555 | this.insert_markdown_cell_below(i); | |
556 | var target_cell = this.cells()[i+1]; |
|
556 | var target_cell = this.cells()[i+1]; | |
557 | var text = source_cell.get_code(); |
|
557 | var text = source_cell.get_code(); | |
558 | } else if (source_cell instanceof IPython.HTMLCell) { |
|
558 | } else if (source_cell instanceof IPython.HTMLCell) { | |
559 | this.insert_markdown_cell_below(i); |
|
559 | this.insert_markdown_cell_below(i); | |
560 | var target_cell = this.cells()[i+1]; |
|
560 | var target_cell = this.cells()[i+1]; | |
561 | var text = source_cell.get_source(); |
|
561 | var text = source_cell.get_source(); | |
562 | if (text === source_cell.placeholder) { |
|
562 | if (text === source_cell.placeholder) { | |
563 | text = target_cell.placeholder; |
|
563 | text = target_cell.placeholder; | |
564 | } |
|
564 | } | |
565 | } |
|
565 | } | |
566 | if (target_cell !== null) { |
|
566 | if (target_cell !== null) { | |
567 | if (text === "") {text = target_cell.placeholder;}; |
|
567 | if (text === "") {text = target_cell.placeholder;}; | |
568 | target_cell.set_source(text); |
|
568 | target_cell.set_source(text); | |
569 | source_element.remove(); |
|
569 | source_element.remove(); | |
570 | target_cell.edit(); |
|
570 | target_cell.edit(); | |
571 | } |
|
571 | } | |
572 | this.dirty = true; |
|
572 | this.dirty = true; | |
573 | }; |
|
573 | }; | |
574 |
|
574 | |||
575 |
|
575 | |||
576 | Notebook.prototype.to_html = function (index) { |
|
576 | Notebook.prototype.to_html = function (index) { | |
577 | // TODO: Bounds check for i |
|
577 | // TODO: Bounds check for i | |
578 | var i = this.index_or_selected(index); |
|
578 | var i = this.index_or_selected(index); | |
579 | var source_element = this.cell_elements().eq(i); |
|
579 | var source_element = this.cell_elements().eq(i); | |
580 | var source_cell = source_element.data("cell"); |
|
580 | var source_cell = source_element.data("cell"); | |
581 | var target_cell = null; |
|
581 | var target_cell = null; | |
582 | if (source_cell instanceof IPython.CodeCell) { |
|
582 | if (source_cell instanceof IPython.CodeCell) { | |
583 | this.insert_html_cell_below(i); |
|
583 | this.insert_html_cell_below(i); | |
584 | var target_cell = this.cells()[i+1]; |
|
584 | var target_cell = this.cells()[i+1]; | |
585 | var text = source_cell.get_code(); |
|
585 | var text = source_cell.get_code(); | |
586 | } else if (source_cell instanceof IPython.MarkdownCell) { |
|
586 | } else if (source_cell instanceof IPython.MarkdownCell) { | |
587 | this.insert_html_cell_below(i); |
|
587 | this.insert_html_cell_below(i); | |
588 | var target_cell = this.cells()[i+1]; |
|
588 | var target_cell = this.cells()[i+1]; | |
589 | var text = source_cell.get_source(); |
|
589 | var text = source_cell.get_source(); | |
590 | if (text === source_cell.placeholder) { |
|
590 | if (text === source_cell.placeholder) { | |
591 | text = target_cell.placeholder; |
|
591 | text = target_cell.placeholder; | |
592 | } |
|
592 | } | |
593 | } |
|
593 | } | |
594 | if (target_cell !== null) { |
|
594 | if (target_cell !== null) { | |
595 | if (text === "") {text = target_cell.placeholder;}; |
|
595 | if (text === "") {text = target_cell.placeholder;}; | |
596 | target_cell.set_source(text); |
|
596 | target_cell.set_source(text); | |
597 | source_element.remove(); |
|
597 | source_element.remove(); | |
598 | target_cell.edit(); |
|
598 | target_cell.edit(); | |
599 | } |
|
599 | } | |
600 | this.dirty = true; |
|
600 | this.dirty = true; | |
601 | }; |
|
601 | }; | |
602 |
|
602 | |||
603 |
|
603 | |||
604 | // Cell collapsing and output clearing |
|
604 | // Cell collapsing and output clearing | |
605 |
|
605 | |||
606 | Notebook.prototype.collapse = function (index) { |
|
606 | Notebook.prototype.collapse = function (index) { | |
607 | var i = this.index_or_selected(index); |
|
607 | var i = this.index_or_selected(index); | |
608 | this.cells()[i].collapse(); |
|
608 | this.cells()[i].collapse(); | |
609 | this.dirty = true; |
|
609 | this.dirty = true; | |
610 | }; |
|
610 | }; | |
611 |
|
611 | |||
612 |
|
612 | |||
613 | Notebook.prototype.expand = function (index) { |
|
613 | Notebook.prototype.expand = function (index) { | |
614 | var i = this.index_or_selected(index); |
|
614 | var i = this.index_or_selected(index); | |
615 | this.cells()[i].expand(); |
|
615 | this.cells()[i].expand(); | |
616 | this.dirty = true; |
|
616 | this.dirty = true; | |
617 | }; |
|
617 | }; | |
618 |
|
618 | |||
619 |
|
619 | |||
620 | Notebook.prototype.toggle_output = function (index) { |
|
620 | Notebook.prototype.toggle_output = function (index) { | |
621 | var i = this.index_or_selected(index); |
|
621 | var i = this.index_or_selected(index); | |
622 | this.cells()[i].toggle_output(); |
|
622 | this.cells()[i].toggle_output(); | |
623 | this.dirty = true; |
|
623 | this.dirty = true; | |
624 | }; |
|
624 | }; | |
625 |
|
625 | |||
626 |
|
626 | |||
627 | Notebook.prototype.set_timebeforetooltip = function (time) { |
|
627 | Notebook.prototype.set_timebeforetooltip = function (time) { | |
628 | console.log("change time before tooltip to : "+time); |
|
628 | console.log("change time before tooltip to : "+time); | |
629 | this.time_before_tooltip = time; |
|
629 | this.time_before_tooltip = time; | |
630 | }; |
|
630 | }; | |
631 |
|
631 | |||
632 | Notebook.prototype.set_tooltipontab = function (state) { |
|
632 | Notebook.prototype.set_tooltipontab = function (state) { | |
633 | console.log("change tooltip on tab to : "+state); |
|
633 | console.log("change tooltip on tab to : "+state); | |
634 | this.tooltip_on_tab = state; |
|
634 | this.tooltip_on_tab = state; | |
635 | }; |
|
635 | }; | |
636 |
|
636 | |||
637 | Notebook.prototype.set_smartcompleter = function (state) { |
|
637 | Notebook.prototype.set_smartcompleter = function (state) { | |
638 | console.log("Smart completion (kwargs first) changed to to : "+state); |
|
638 | console.log("Smart completion (kwargs first) changed to to : "+state); | |
639 | this.smart_completer = state; |
|
639 | this.smart_completer = state; | |
640 | }; |
|
640 | }; | |
641 |
|
641 | |||
642 | Notebook.prototype.set_autoindent = function (state) { |
|
642 | Notebook.prototype.set_autoindent = function (state) { | |
643 | var cells = this.cells(); |
|
643 | var cells = this.cells(); | |
644 | len = cells.length; |
|
644 | len = cells.length; | |
645 | for (var i=0; i<len; i++) { |
|
645 | for (var i=0; i<len; i++) { | |
646 | cells[i].set_autoindent(state) |
|
646 | cells[i].set_autoindent(state) | |
647 | }; |
|
647 | }; | |
648 | }; |
|
648 | }; | |
649 |
|
649 | |||
650 |
|
650 | |||
651 | Notebook.prototype.clear_all_output = function () { |
|
651 | Notebook.prototype.clear_all_output = function () { | |
652 | var ncells = this.ncells(); |
|
652 | var ncells = this.ncells(); | |
653 | var cells = this.cells(); |
|
653 | var cells = this.cells(); | |
654 | for (var i=0; i<ncells; i++) { |
|
654 | for (var i=0; i<ncells; i++) { | |
655 | if (cells[i] instanceof IPython.CodeCell) { |
|
655 | if (cells[i] instanceof IPython.CodeCell) { | |
656 | cells[i].clear_output(true,true,true); |
|
656 | cells[i].clear_output(true,true,true); | |
657 | } |
|
657 | } | |
658 | }; |
|
658 | }; | |
659 | this.dirty = true; |
|
659 | this.dirty = true; | |
660 | }; |
|
660 | }; | |
661 |
|
661 | |||
662 | // Other cell functions: line numbers, ... |
|
662 | // Other cell functions: line numbers, ... | |
663 |
|
663 | |||
664 | Notebook.prototype.cell_toggle_line_numbers = function() { |
|
664 | Notebook.prototype.cell_toggle_line_numbers = function() { | |
665 | this.selected_cell().toggle_line_numbers() |
|
665 | this.selected_cell().toggle_line_numbers() | |
666 | }; |
|
666 | }; | |
667 |
|
667 | |||
668 | // Kernel related things |
|
668 | // Kernel related things | |
669 |
|
669 | |||
670 | Notebook.prototype.start_kernel = function () { |
|
670 | Notebook.prototype.start_kernel = function () { | |
671 | this.kernel = new IPython.Kernel(); |
|
671 | this.kernel = new IPython.Kernel(); | |
672 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
672 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
673 | this.kernel.start(notebook_id, $.proxy(this.kernel_started, this)); |
|
673 | this.kernel.start(notebook_id, $.proxy(this.kernel_started, this)); | |
674 | }; |
|
674 | }; | |
675 |
|
675 | |||
676 |
|
676 | |||
677 | Notebook.prototype.restart_kernel = function () { |
|
677 | Notebook.prototype.restart_kernel = function () { | |
678 | var that = this; |
|
678 | var that = this; | |
679 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
679 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
680 |
|
680 | |||
681 | var dialog = $('<div/>'); |
|
681 | var dialog = $('<div/>'); | |
682 | dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.'); |
|
682 | dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.'); | |
683 | $(document).append(dialog); |
|
683 | $(document).append(dialog); | |
684 | dialog.dialog({ |
|
684 | dialog.dialog({ | |
685 | resizable: false, |
|
685 | resizable: false, | |
686 | modal: true, |
|
686 | modal: true, | |
687 | title: "Restart kernel or continue running?", |
|
687 | title: "Restart kernel or continue running?", | |
688 | buttons : { |
|
688 | buttons : { | |
689 | "Restart": function () { |
|
689 | "Restart": function () { | |
690 | that.kernel.restart($.proxy(that.kernel_started, that)); |
|
690 | that.kernel.restart($.proxy(that.kernel_started, that)); | |
691 | $(this).dialog('close'); |
|
691 | $(this).dialog('close'); | |
692 | }, |
|
692 | }, | |
693 | "Continue running": function () { |
|
693 | "Continue running": function () { | |
694 | $(this).dialog('close'); |
|
694 | $(this).dialog('close'); | |
695 | } |
|
695 | } | |
696 | } |
|
696 | } | |
697 | }); |
|
697 | }); | |
698 | }; |
|
698 | }; | |
699 |
|
699 | |||
700 |
|
700 | |||
701 | Notebook.prototype.kernel_started = function () { |
|
701 | Notebook.prototype.kernel_started = function () { | |
702 | console.log("Kernel started: ", this.kernel.kernel_id); |
|
702 | console.log("Kernel started: ", this.kernel.kernel_id); | |
703 | this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this); |
|
703 | this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this); | |
704 | this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this); |
|
704 | this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this); | |
705 | }; |
|
705 | }; | |
706 |
|
706 | |||
707 |
|
707 | |||
708 | Notebook.prototype.handle_shell_reply = function (e) { |
|
708 | Notebook.prototype.handle_shell_reply = function (e) { | |
709 | reply = $.parseJSON(e.data); |
|
709 | reply = $.parseJSON(e.data); | |
710 | var header = reply.header; |
|
710 | var header = reply.header; | |
711 | var content = reply.content; |
|
711 | var content = reply.content; | |
712 | var msg_type = header.msg_type; |
|
712 | var msg_type = header.msg_type; | |
713 | // console.log(reply); |
|
713 | // console.log(reply); | |
714 | var cell = this.cell_for_msg(reply.parent_header.msg_id); |
|
714 | var cell = this.cell_for_msg(reply.parent_header.msg_id); | |
715 | if (msg_type === "execute_reply") { |
|
715 | if (msg_type === "execute_reply") { | |
716 | cell.set_input_prompt(content.execution_count); |
|
716 | cell.set_input_prompt(content.execution_count); | |
717 | cell.element.removeClass("running"); |
|
717 | cell.element.removeClass("running"); | |
718 | this.dirty = true; |
|
718 | this.dirty = true; | |
719 | } else if (msg_type === "complete_reply") { |
|
719 | } else if (msg_type === "complete_reply") { | |
720 | cell.finish_completing(content.matched_text, content.matches); |
|
720 | cell.finish_completing(content.matched_text, content.matches); | |
721 | } else if (msg_type === "object_info_reply"){ |
|
721 | } else if (msg_type === "object_info_reply"){ | |
722 | //console.log('back from object_info_request : ') |
|
722 | //console.log('back from object_info_request : ') | |
723 | rep = reply.content; |
|
723 | rep = reply.content; | |
724 | if(rep.found) |
|
724 | if(rep.found) | |
725 | { |
|
725 | { | |
726 | cell.finish_tooltip(rep); |
|
726 | cell.finish_tooltip(rep); | |
727 | } |
|
727 | } | |
728 | } else { |
|
728 | } else { | |
729 | //console.log("unknown reply:"+msg_type); |
|
729 | //console.log("unknown reply:"+msg_type); | |
730 | } |
|
730 | } | |
731 | // when having a rely from object_info_reply, |
|
731 | // when having a rely from object_info_reply, | |
732 | // no payload so no nned to handle it |
|
732 | // no payload so no nned to handle it | |
733 | if(typeof(content.payload)!='undefined') { |
|
733 | if(typeof(content.payload)!='undefined') { | |
734 | var payload = content.payload || []; |
|
734 | var payload = content.payload || []; | |
735 | this.handle_payload(cell, payload); |
|
735 | this.handle_payload(cell, payload); | |
736 | } |
|
736 | } | |
737 | }; |
|
737 | }; | |
738 |
|
738 | |||
739 |
|
739 | |||
740 | Notebook.prototype.handle_payload = function (cell, payload) { |
|
740 | Notebook.prototype.handle_payload = function (cell, payload) { | |
741 | var l = payload.length; |
|
741 | var l = payload.length; | |
742 | for (var i=0; i<l; i++) { |
|
742 | for (var i=0; i<l; i++) { | |
743 | if (payload[i].source === 'IPython.zmq.page.page') { |
|
743 | if (payload[i].source === 'IPython.zmq.page.page') { | |
744 | if (payload[i].text.trim() !== '') { |
|
744 | if (payload[i].text.trim() !== '') { | |
745 | IPython.pager.clear(); |
|
745 | IPython.pager.clear(); | |
746 | IPython.pager.expand(); |
|
746 | IPython.pager.expand(); | |
747 | IPython.pager.append_text(payload[i].text); |
|
747 | IPython.pager.append_text(payload[i].text); | |
748 | } |
|
748 | } | |
749 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { |
|
749 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { | |
750 | var index = this.find_cell_index(cell); |
|
750 | var index = this.find_cell_index(cell); | |
751 | var new_cell = this.insert_code_cell_below(index); |
|
751 | var new_cell = this.insert_code_cell_below(index); | |
752 | new_cell.set_code(payload[i].text); |
|
752 | new_cell.set_code(payload[i].text); | |
753 | this.dirty = true; |
|
753 | this.dirty = true; | |
754 | } |
|
754 | } | |
755 | }; |
|
755 | }; | |
756 | }; |
|
756 | }; | |
757 |
|
757 | |||
758 |
|
758 | |||
759 | Notebook.prototype.handle_iopub_reply = function (e) { |
|
759 | Notebook.prototype.handle_iopub_reply = function (e) { | |
760 | reply = $.parseJSON(e.data); |
|
760 | reply = $.parseJSON(e.data); | |
761 | var content = reply.content; |
|
761 | var content = reply.content; | |
762 | // console.log(reply); |
|
762 | // console.log(reply); | |
763 | var msg_type = reply.header.msg_type; |
|
763 | var msg_type = reply.header.msg_type; | |
764 | var cell = this.cell_for_msg(reply.parent_header.msg_id); |
|
764 | var cell = this.cell_for_msg(reply.parent_header.msg_id); | |
|
765 | if (!cell){ | |||
|
766 | // message not from this notebook | |||
|
767 | console.log("Received IOPub message not caused by one of my cells"); | |||
|
768 | return; | |||
|
769 | } | |||
765 | var output_types = ['stream','display_data','pyout','pyerr']; |
|
770 | var output_types = ['stream','display_data','pyout','pyerr']; | |
766 | if (output_types.indexOf(msg_type) >= 0) { |
|
771 | if (output_types.indexOf(msg_type) >= 0) { | |
767 | this.handle_output(cell, msg_type, content); |
|
772 | this.handle_output(cell, msg_type, content); | |
768 | } else if (msg_type === 'status') { |
|
773 | } else if (msg_type === 'status') { | |
769 | if (content.execution_state === 'busy') { |
|
774 | if (content.execution_state === 'busy') { | |
770 | IPython.kernel_status_widget.status_busy(); |
|
775 | IPython.kernel_status_widget.status_busy(); | |
771 | } else if (content.execution_state === 'idle') { |
|
776 | } else if (content.execution_state === 'idle') { | |
772 | IPython.kernel_status_widget.status_idle(); |
|
777 | IPython.kernel_status_widget.status_idle(); | |
773 | } else if (content.execution_state === 'dead') { |
|
778 | } else if (content.execution_state === 'dead') { | |
774 | this.handle_status_dead(); |
|
779 | this.handle_status_dead(); | |
775 | }; |
|
780 | }; | |
776 | } else if (msg_type === 'clear_output') { |
|
781 | } else if (msg_type === 'clear_output') { | |
777 | cell.clear_output(content.stdout, content.stderr, content.other); |
|
782 | cell.clear_output(content.stdout, content.stderr, content.other); | |
778 | }; |
|
783 | }; | |
779 | }; |
|
784 | }; | |
780 |
|
785 | |||
781 |
|
786 | |||
782 | Notebook.prototype.handle_status_dead = function () { |
|
787 | Notebook.prototype.handle_status_dead = function () { | |
783 | var that = this; |
|
788 | var that = this; | |
784 | this.kernel.stop_channels(); |
|
789 | this.kernel.stop_channels(); | |
785 | var dialog = $('<div/>'); |
|
790 | var dialog = $('<div/>'); | |
786 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); |
|
791 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); | |
787 | $(document).append(dialog); |
|
792 | $(document).append(dialog); | |
788 | dialog.dialog({ |
|
793 | dialog.dialog({ | |
789 | resizable: false, |
|
794 | resizable: false, | |
790 | modal: true, |
|
795 | modal: true, | |
791 | title: "Dead kernel", |
|
796 | title: "Dead kernel", | |
792 | buttons : { |
|
797 | buttons : { | |
793 | "Restart": function () { |
|
798 | "Restart": function () { | |
794 | that.start_kernel(); |
|
799 | that.start_kernel(); | |
795 | $(this).dialog('close'); |
|
800 | $(this).dialog('close'); | |
796 | }, |
|
801 | }, | |
797 | "Continue running": function () { |
|
802 | "Continue running": function () { | |
798 | $(this).dialog('close'); |
|
803 | $(this).dialog('close'); | |
799 | } |
|
804 | } | |
800 | } |
|
805 | } | |
801 | }); |
|
806 | }); | |
802 | }; |
|
807 | }; | |
803 |
|
808 | |||
804 |
|
809 | |||
805 | Notebook.prototype.handle_output = function (cell, msg_type, content) { |
|
810 | Notebook.prototype.handle_output = function (cell, msg_type, content) { | |
806 | var json = {}; |
|
811 | var json = {}; | |
807 | json.output_type = msg_type; |
|
812 | json.output_type = msg_type; | |
808 | if (msg_type === "stream") { |
|
813 | if (msg_type === "stream") { | |
809 | json.text = utils.fixConsole(content.data); |
|
814 | json.text = utils.fixConsole(content.data); | |
810 | json.stream = content.name; |
|
815 | json.stream = content.name; | |
811 | } else if (msg_type === "display_data") { |
|
816 | } else if (msg_type === "display_data") { | |
812 | json = this.convert_mime_types(json, content.data); |
|
817 | json = this.convert_mime_types(json, content.data); | |
813 | } else if (msg_type === "pyout") { |
|
818 | } else if (msg_type === "pyout") { | |
814 | json.prompt_number = content.execution_count; |
|
819 | json.prompt_number = content.execution_count; | |
815 | json = this.convert_mime_types(json, content.data); |
|
820 | json = this.convert_mime_types(json, content.data); | |
816 | } else if (msg_type === "pyerr") { |
|
821 | } else if (msg_type === "pyerr") { | |
817 | json.ename = content.ename; |
|
822 | json.ename = content.ename; | |
818 | json.evalue = content.evalue; |
|
823 | json.evalue = content.evalue; | |
819 | var traceback = []; |
|
824 | var traceback = []; | |
820 | for (var i=0; i<content.traceback.length; i++) { |
|
825 | for (var i=0; i<content.traceback.length; i++) { | |
821 | traceback.push(utils.fixConsole(content.traceback[i])); |
|
826 | traceback.push(utils.fixConsole(content.traceback[i])); | |
822 | } |
|
827 | } | |
823 | json.traceback = traceback; |
|
828 | json.traceback = traceback; | |
824 | }; |
|
829 | }; | |
825 | cell.append_output(json); |
|
830 | cell.append_output(json); | |
826 | this.dirty = true; |
|
831 | this.dirty = true; | |
827 | }; |
|
832 | }; | |
828 |
|
833 | |||
829 |
|
834 | |||
830 | Notebook.prototype.convert_mime_types = function (json, data) { |
|
835 | Notebook.prototype.convert_mime_types = function (json, data) { | |
831 | if (data['text/plain'] !== undefined) { |
|
836 | if (data['text/plain'] !== undefined) { | |
832 | json.text = utils.fixConsole(data['text/plain']); |
|
837 | json.text = utils.fixConsole(data['text/plain']); | |
833 | }; |
|
838 | }; | |
834 | if (data['text/html'] !== undefined) { |
|
839 | if (data['text/html'] !== undefined) { | |
835 | json.html = data['text/html']; |
|
840 | json.html = data['text/html']; | |
836 | }; |
|
841 | }; | |
837 | if (data['image/svg+xml'] !== undefined) { |
|
842 | if (data['image/svg+xml'] !== undefined) { | |
838 | json.svg = data['image/svg+xml']; |
|
843 | json.svg = data['image/svg+xml']; | |
839 | }; |
|
844 | }; | |
840 | if (data['image/png'] !== undefined) { |
|
845 | if (data['image/png'] !== undefined) { | |
841 | json.png = data['image/png']; |
|
846 | json.png = data['image/png']; | |
842 | }; |
|
847 | }; | |
843 | if (data['image/jpeg'] !== undefined) { |
|
848 | if (data['image/jpeg'] !== undefined) { | |
844 | json.jpeg = data['image/jpeg']; |
|
849 | json.jpeg = data['image/jpeg']; | |
845 | }; |
|
850 | }; | |
846 | if (data['text/latex'] !== undefined) { |
|
851 | if (data['text/latex'] !== undefined) { | |
847 | json.latex = data['text/latex']; |
|
852 | json.latex = data['text/latex']; | |
848 | }; |
|
853 | }; | |
849 | if (data['application/json'] !== undefined) { |
|
854 | if (data['application/json'] !== undefined) { | |
850 | json.json = data['application/json']; |
|
855 | json.json = data['application/json']; | |
851 | }; |
|
856 | }; | |
852 | if (data['application/javascript'] !== undefined) { |
|
857 | if (data['application/javascript'] !== undefined) { | |
853 | json.javascript = data['application/javascript']; |
|
858 | json.javascript = data['application/javascript']; | |
854 | } |
|
859 | } | |
855 | return json; |
|
860 | return json; | |
856 | }; |
|
861 | }; | |
857 |
|
862 | |||
858 |
|
863 | |||
859 | Notebook.prototype.execute_selected_cell = function (options) { |
|
864 | Notebook.prototype.execute_selected_cell = function (options) { | |
860 | // add_new: should a new cell be added if we are at the end of the nb |
|
865 | // add_new: should a new cell be added if we are at the end of the nb | |
861 | // terminal: execute in terminal mode, which stays in the current cell |
|
866 | // terminal: execute in terminal mode, which stays in the current cell | |
862 | default_options = {terminal: false, add_new: true} |
|
867 | default_options = {terminal: false, add_new: true} | |
863 | $.extend(default_options, options) |
|
868 | $.extend(default_options, options) | |
864 | var that = this; |
|
869 | var that = this; | |
865 | var cell = that.selected_cell(); |
|
870 | var cell = that.selected_cell(); | |
866 | var cell_index = that.find_cell_index(cell); |
|
871 | var cell_index = that.find_cell_index(cell); | |
867 | if (cell instanceof IPython.CodeCell) { |
|
872 | if (cell instanceof IPython.CodeCell) { | |
868 | cell.clear_output(true, true, true); |
|
873 | cell.clear_output(true, true, true); | |
869 | cell.set_input_prompt('*'); |
|
874 | cell.set_input_prompt('*'); | |
870 | cell.element.addClass("running"); |
|
875 | cell.element.addClass("running"); | |
871 | var code = cell.get_code(); |
|
876 | var code = cell.get_code(); | |
872 | var msg_id = that.kernel.execute(cell.get_code()); |
|
877 | var msg_id = that.kernel.execute(cell.get_code()); | |
873 | that.msg_cell_map[msg_id] = cell.cell_id; |
|
878 | that.msg_cell_map[msg_id] = cell.cell_id; | |
874 | } else if (cell instanceof IPython.HTMLCell) { |
|
879 | } else if (cell instanceof IPython.HTMLCell) { | |
875 | cell.render(); |
|
880 | cell.render(); | |
876 | } |
|
881 | } | |
877 | if (default_options.terminal) { |
|
882 | if (default_options.terminal) { | |
878 | cell.select_all(); |
|
883 | cell.select_all(); | |
879 | } else { |
|
884 | } else { | |
880 | if ((cell_index === (that.ncells()-1)) && default_options.add_new) { |
|
885 | if ((cell_index === (that.ncells()-1)) && default_options.add_new) { | |
881 | that.insert_code_cell_below(); |
|
886 | that.insert_code_cell_below(); | |
882 | // If we are adding a new cell at the end, scroll down to show it. |
|
887 | // If we are adding a new cell at the end, scroll down to show it. | |
883 | that.scroll_to_bottom(); |
|
888 | that.scroll_to_bottom(); | |
884 | } else { |
|
889 | } else { | |
885 | that.select(cell_index+1); |
|
890 | that.select(cell_index+1); | |
886 | }; |
|
891 | }; | |
887 | }; |
|
892 | }; | |
888 | this.dirty = true; |
|
893 | this.dirty = true; | |
889 | }; |
|
894 | }; | |
890 |
|
895 | |||
891 |
|
896 | |||
892 | Notebook.prototype.execute_all_cells = function () { |
|
897 | Notebook.prototype.execute_all_cells = function () { | |
893 | var ncells = this.ncells(); |
|
898 | var ncells = this.ncells(); | |
894 | for (var i=0; i<ncells; i++) { |
|
899 | for (var i=0; i<ncells; i++) { | |
895 | this.select(i); |
|
900 | this.select(i); | |
896 | this.execute_selected_cell({add_new:false}); |
|
901 | this.execute_selected_cell({add_new:false}); | |
897 | }; |
|
902 | }; | |
898 | this.scroll_to_bottom(); |
|
903 | this.scroll_to_bottom(); | |
899 | }; |
|
904 | }; | |
900 |
|
905 | |||
901 |
|
906 | |||
902 | Notebook.prototype.request_tool_tip = function (cell,func) { |
|
907 | Notebook.prototype.request_tool_tip = function (cell,func) { | |
903 | // Feel free to shorten this logic if you are better |
|
908 | // Feel free to shorten this logic if you are better | |
904 | // than me in regEx |
|
909 | // than me in regEx | |
905 | // basicaly you shoul be able to get xxx.xxx.xxx from |
|
910 | // basicaly you shoul be able to get xxx.xxx.xxx from | |
906 | // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2, |
|
911 | // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2, | |
907 | // remove everything between matchin bracket (need to iterate) |
|
912 | // remove everything between matchin bracket (need to iterate) | |
908 | matchBracket = /\([^\(\)]+\)/g; |
|
913 | matchBracket = /\([^\(\)]+\)/g; | |
909 | oldfunc = func; |
|
914 | oldfunc = func; | |
910 | func = func.replace(matchBracket,""); |
|
915 | func = func.replace(matchBracket,""); | |
911 | while( oldfunc != func ) |
|
916 | while( oldfunc != func ) | |
912 | { |
|
917 | { | |
913 | oldfunc = func; |
|
918 | oldfunc = func; | |
914 | func = func.replace(matchBracket,""); |
|
919 | func = func.replace(matchBracket,""); | |
915 | } |
|
920 | } | |
916 | // remove everythin after last open bracket |
|
921 | // remove everythin after last open bracket | |
917 | endBracket = /\([^\(]*$/g; |
|
922 | endBracket = /\([^\(]*$/g; | |
918 | func = func.replace(endBracket,""); |
|
923 | func = func.replace(endBracket,""); | |
919 | var re = /[a-zA-Z._]+$/g; |
|
924 | var re = /[a-zA-Z._]+$/g; | |
920 | var msg_id = this.kernel.object_info_request(re.exec(func)); |
|
925 | var msg_id = this.kernel.object_info_request(re.exec(func)); | |
921 | if(typeof(msg_id)!='undefined'){ |
|
926 | if(typeof(msg_id)!='undefined'){ | |
922 | this.msg_cell_map[msg_id] = cell.cell_id; |
|
927 | this.msg_cell_map[msg_id] = cell.cell_id; | |
923 | } |
|
928 | } | |
924 | }; |
|
929 | }; | |
925 |
|
930 | |||
926 | Notebook.prototype.complete_cell = function (cell, line, cursor_pos) { |
|
931 | Notebook.prototype.complete_cell = function (cell, line, cursor_pos) { | |
927 | var msg_id = this.kernel.complete(line, cursor_pos); |
|
932 | var msg_id = this.kernel.complete(line, cursor_pos); | |
928 | this.msg_cell_map[msg_id] = cell.cell_id; |
|
933 | this.msg_cell_map[msg_id] = cell.cell_id; | |
929 | }; |
|
934 | }; | |
930 |
|
935 | |||
931 | // Persistance and loading |
|
936 | // Persistance and loading | |
932 |
|
937 | |||
933 |
|
938 | |||
934 | Notebook.prototype.fromJSON = function (data) { |
|
939 | Notebook.prototype.fromJSON = function (data) { | |
935 | var ncells = this.ncells(); |
|
940 | var ncells = this.ncells(); | |
936 | for (var i=0; i<ncells; i++) { |
|
941 | for (var i=0; i<ncells; i++) { | |
937 | // Always delete cell 0 as they get renumbered as they are deleted. |
|
942 | // Always delete cell 0 as they get renumbered as they are deleted. | |
938 | this.delete_cell(0); |
|
943 | this.delete_cell(0); | |
939 | }; |
|
944 | }; | |
940 | // Save the metadata |
|
945 | // Save the metadata | |
941 | this.metadata = data.metadata; |
|
946 | this.metadata = data.metadata; | |
942 | // Only handle 1 worksheet for now. |
|
947 | // Only handle 1 worksheet for now. | |
943 | var worksheet = data.worksheets[0]; |
|
948 | var worksheet = data.worksheets[0]; | |
944 | if (worksheet !== undefined) { |
|
949 | if (worksheet !== undefined) { | |
945 | var new_cells = worksheet.cells; |
|
950 | var new_cells = worksheet.cells; | |
946 | ncells = new_cells.length; |
|
951 | ncells = new_cells.length; | |
947 | var cell_data = null; |
|
952 | var cell_data = null; | |
948 | var new_cell = null; |
|
953 | var new_cell = null; | |
949 | for (var i=0; i<ncells; i++) { |
|
954 | for (var i=0; i<ncells; i++) { | |
950 | cell_data = new_cells[i]; |
|
955 | cell_data = new_cells[i]; | |
951 | if (cell_data.cell_type == 'code') { |
|
956 | if (cell_data.cell_type == 'code') { | |
952 | new_cell = this.insert_code_cell_below(); |
|
957 | new_cell = this.insert_code_cell_below(); | |
953 | new_cell.fromJSON(cell_data); |
|
958 | new_cell.fromJSON(cell_data); | |
954 | } else if (cell_data.cell_type === 'html') { |
|
959 | } else if (cell_data.cell_type === 'html') { | |
955 | new_cell = this.insert_html_cell_below(); |
|
960 | new_cell = this.insert_html_cell_below(); | |
956 | new_cell.fromJSON(cell_data); |
|
961 | new_cell.fromJSON(cell_data); | |
957 | } else if (cell_data.cell_type === 'markdown') { |
|
962 | } else if (cell_data.cell_type === 'markdown') { | |
958 | new_cell = this.insert_markdown_cell_below(); |
|
963 | new_cell = this.insert_markdown_cell_below(); | |
959 | new_cell.fromJSON(cell_data); |
|
964 | new_cell.fromJSON(cell_data); | |
960 | }; |
|
965 | }; | |
961 | }; |
|
966 | }; | |
962 | }; |
|
967 | }; | |
963 | }; |
|
968 | }; | |
964 |
|
969 | |||
965 |
|
970 | |||
966 | Notebook.prototype.toJSON = function () { |
|
971 | Notebook.prototype.toJSON = function () { | |
967 | var cells = this.cells(); |
|
972 | var cells = this.cells(); | |
968 | var ncells = cells.length; |
|
973 | var ncells = cells.length; | |
969 | cell_array = new Array(ncells); |
|
974 | cell_array = new Array(ncells); | |
970 | for (var i=0; i<ncells; i++) { |
|
975 | for (var i=0; i<ncells; i++) { | |
971 | cell_array[i] = cells[i].toJSON(); |
|
976 | cell_array[i] = cells[i].toJSON(); | |
972 | }; |
|
977 | }; | |
973 | data = { |
|
978 | data = { | |
974 | // Only handle 1 worksheet for now. |
|
979 | // Only handle 1 worksheet for now. | |
975 | worksheets : [{cells:cell_array}], |
|
980 | worksheets : [{cells:cell_array}], | |
976 | metadata : this.metadata |
|
981 | metadata : this.metadata | |
977 | } |
|
982 | } | |
978 | return data |
|
983 | return data | |
979 | }; |
|
984 | }; | |
980 |
|
985 | |||
981 | Notebook.prototype.save_notebook = function () { |
|
986 | Notebook.prototype.save_notebook = function () { | |
982 | if (IPython.save_widget.test_notebook_name()) { |
|
987 | if (IPython.save_widget.test_notebook_name()) { | |
983 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
988 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
984 | var nbname = IPython.save_widget.get_notebook_name(); |
|
989 | var nbname = IPython.save_widget.get_notebook_name(); | |
985 | // We may want to move the name/id/nbformat logic inside toJSON? |
|
990 | // We may want to move the name/id/nbformat logic inside toJSON? | |
986 | var data = this.toJSON(); |
|
991 | var data = this.toJSON(); | |
987 | data.metadata.name = nbname; |
|
992 | data.metadata.name = nbname; | |
988 | data.nbformat = 2; |
|
993 | data.nbformat = 2; | |
989 | // We do the call with settings so we can set cache to false. |
|
994 | // We do the call with settings so we can set cache to false. | |
990 | var settings = { |
|
995 | var settings = { | |
991 | processData : false, |
|
996 | processData : false, | |
992 | cache : false, |
|
997 | cache : false, | |
993 | type : "PUT", |
|
998 | type : "PUT", | |
994 | data : JSON.stringify(data), |
|
999 | data : JSON.stringify(data), | |
995 | headers : {'Content-Type': 'application/json'}, |
|
1000 | headers : {'Content-Type': 'application/json'}, | |
996 | success : $.proxy(this.notebook_saved,this), |
|
1001 | success : $.proxy(this.notebook_saved,this), | |
997 | error : $.proxy(this.notebook_save_failed,this) |
|
1002 | error : $.proxy(this.notebook_save_failed,this) | |
998 | }; |
|
1003 | }; | |
999 | IPython.save_widget.status_saving(); |
|
1004 | IPython.save_widget.status_saving(); | |
1000 | var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id |
|
1005 | var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id | |
1001 | $.ajax(url, settings); |
|
1006 | $.ajax(url, settings); | |
1002 | }; |
|
1007 | }; | |
1003 | }; |
|
1008 | }; | |
1004 |
|
1009 | |||
1005 |
|
1010 | |||
1006 | Notebook.prototype.notebook_saved = function (data, status, xhr) { |
|
1011 | Notebook.prototype.notebook_saved = function (data, status, xhr) { | |
1007 | this.dirty = false; |
|
1012 | this.dirty = false; | |
1008 | IPython.save_widget.notebook_saved(); |
|
1013 | IPython.save_widget.notebook_saved(); | |
1009 | IPython.save_widget.status_save(); |
|
1014 | IPython.save_widget.status_save(); | |
1010 | } |
|
1015 | } | |
1011 |
|
1016 | |||
1012 |
|
1017 | |||
1013 | Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) { |
|
1018 | Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) { | |
1014 | // Notify the user and reset the save button |
|
1019 | // Notify the user and reset the save button | |
1015 | // TODO: Handle different types of errors (timeout etc.) |
|
1020 | // TODO: Handle different types of errors (timeout etc.) | |
1016 | alert('An unexpected error occured while saving the notebook.'); |
|
1021 | alert('An unexpected error occured while saving the notebook.'); | |
1017 | IPython.save_widget.reset_status(); |
|
1022 | IPython.save_widget.reset_status(); | |
1018 | } |
|
1023 | } | |
1019 |
|
1024 | |||
1020 |
|
1025 | |||
1021 | Notebook.prototype.load_notebook = function (callback) { |
|
1026 | Notebook.prototype.load_notebook = function (callback) { | |
1022 | var that = this; |
|
1027 | var that = this; | |
1023 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
1028 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
1024 | // We do the call with settings so we can set cache to false. |
|
1029 | // We do the call with settings so we can set cache to false. | |
1025 | var settings = { |
|
1030 | var settings = { | |
1026 | processData : false, |
|
1031 | processData : false, | |
1027 | cache : false, |
|
1032 | cache : false, | |
1028 | type : "GET", |
|
1033 | type : "GET", | |
1029 | dataType : "json", |
|
1034 | dataType : "json", | |
1030 | success : function (data, status, xhr) { |
|
1035 | success : function (data, status, xhr) { | |
1031 | that.notebook_loaded(data, status, xhr); |
|
1036 | that.notebook_loaded(data, status, xhr); | |
1032 | if (callback !== undefined) { |
|
1037 | if (callback !== undefined) { | |
1033 | callback(); |
|
1038 | callback(); | |
1034 | }; |
|
1039 | }; | |
1035 | } |
|
1040 | } | |
1036 | }; |
|
1041 | }; | |
1037 | IPython.save_widget.status_loading(); |
|
1042 | IPython.save_widget.status_loading(); | |
1038 | var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id |
|
1043 | var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id | |
1039 | $.ajax(url, settings); |
|
1044 | $.ajax(url, settings); | |
1040 | } |
|
1045 | } | |
1041 |
|
1046 | |||
1042 |
|
1047 | |||
1043 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { |
|
1048 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { | |
1044 | var allowed = xhr.getResponseHeader('Allow'); |
|
1049 | var allowed = xhr.getResponseHeader('Allow'); | |
1045 | this.fromJSON(data); |
|
1050 | this.fromJSON(data); | |
1046 | if (this.ncells() === 0) { |
|
1051 | if (this.ncells() === 0) { | |
1047 | this.insert_code_cell_below(); |
|
1052 | this.insert_code_cell_below(); | |
1048 | }; |
|
1053 | }; | |
1049 | IPython.save_widget.status_save(); |
|
1054 | IPython.save_widget.status_save(); | |
1050 | IPython.save_widget.set_notebook_name(data.metadata.name); |
|
1055 | IPython.save_widget.set_notebook_name(data.metadata.name); | |
1051 | this.dirty = false; |
|
1056 | this.dirty = false; | |
1052 | if (! this.read_only) { |
|
1057 | if (! this.read_only) { | |
1053 | this.start_kernel(); |
|
1058 | this.start_kernel(); | |
1054 | } |
|
1059 | } | |
1055 | // fromJSON always selects the last cell inserted. We need to wait |
|
1060 | // fromJSON always selects the last cell inserted. We need to wait | |
1056 | // until that is done before scrolling to the top. |
|
1061 | // until that is done before scrolling to the top. | |
1057 | setTimeout(function () { |
|
1062 | setTimeout(function () { | |
1058 | IPython.notebook.select(0); |
|
1063 | IPython.notebook.select(0); | |
1059 | IPython.notebook.scroll_to_top(); |
|
1064 | IPython.notebook.scroll_to_top(); | |
1060 | }, 50); |
|
1065 | }, 50); | |
1061 | }; |
|
1066 | }; | |
1062 |
|
1067 | |||
1063 | IPython.Notebook = Notebook; |
|
1068 | IPython.Notebook = Notebook; | |
1064 |
|
1069 | |||
1065 |
|
1070 | |||
1066 | return IPython; |
|
1071 | return IPython; | |
1067 |
|
1072 | |||
1068 | }(IPython)); |
|
1073 | }(IPython)); | |
1069 |
|
1074 |
@@ -1,109 +1,114 b'' | |||||
1 | """ Defines a convenient mix-in class for implementing Qt frontends. |
|
1 | """ Defines a convenient mix-in class for implementing Qt frontends. | |
2 | """ |
|
2 | """ | |
3 |
|
3 | |||
4 | class BaseFrontendMixin(object): |
|
4 | class BaseFrontendMixin(object): | |
5 | """ A mix-in class for implementing Qt frontends. |
|
5 | """ A mix-in class for implementing Qt frontends. | |
6 |
|
6 | |||
7 | To handle messages of a particular type, frontends need only define an |
|
7 | To handle messages of a particular type, frontends need only define an | |
8 | appropriate handler method. For example, to handle 'stream' messaged, define |
|
8 | appropriate handler method. For example, to handle 'stream' messaged, define | |
9 | a '_handle_stream(msg)' method. |
|
9 | a '_handle_stream(msg)' method. | |
10 | """ |
|
10 | """ | |
11 |
|
11 | |||
12 | #--------------------------------------------------------------------------- |
|
12 | #--------------------------------------------------------------------------- | |
13 | # 'BaseFrontendMixin' concrete interface |
|
13 | # 'BaseFrontendMixin' concrete interface | |
14 | #--------------------------------------------------------------------------- |
|
14 | #--------------------------------------------------------------------------- | |
15 |
|
15 | |||
16 | def _get_kernel_manager(self): |
|
16 | def _get_kernel_manager(self): | |
17 | """ Returns the current kernel manager. |
|
17 | """ Returns the current kernel manager. | |
18 | """ |
|
18 | """ | |
19 | return self._kernel_manager |
|
19 | return self._kernel_manager | |
20 |
|
20 | |||
21 | def _set_kernel_manager(self, kernel_manager): |
|
21 | def _set_kernel_manager(self, kernel_manager): | |
22 | """ Disconnect from the current kernel manager (if any) and set a new |
|
22 | """ Disconnect from the current kernel manager (if any) and set a new | |
23 | kernel manager. |
|
23 | kernel manager. | |
24 | """ |
|
24 | """ | |
25 | # Disconnect the old kernel manager, if necessary. |
|
25 | # Disconnect the old kernel manager, if necessary. | |
26 | old_manager = self._kernel_manager |
|
26 | old_manager = self._kernel_manager | |
27 | if old_manager is not None: |
|
27 | if old_manager is not None: | |
28 | old_manager.started_channels.disconnect(self._started_channels) |
|
28 | old_manager.started_channels.disconnect(self._started_channels) | |
29 | old_manager.stopped_channels.disconnect(self._stopped_channels) |
|
29 | old_manager.stopped_channels.disconnect(self._stopped_channels) | |
30 |
|
30 | |||
31 | # Disconnect the old kernel manager's channels. |
|
31 | # Disconnect the old kernel manager's channels. | |
32 | old_manager.sub_channel.message_received.disconnect(self._dispatch) |
|
32 | old_manager.sub_channel.message_received.disconnect(self._dispatch) | |
33 | old_manager.shell_channel.message_received.disconnect(self._dispatch) |
|
33 | old_manager.shell_channel.message_received.disconnect(self._dispatch) | |
34 | old_manager.stdin_channel.message_received.disconnect(self._dispatch) |
|
34 | old_manager.stdin_channel.message_received.disconnect(self._dispatch) | |
35 | old_manager.hb_channel.kernel_died.disconnect( |
|
35 | old_manager.hb_channel.kernel_died.disconnect( | |
36 | self._handle_kernel_died) |
|
36 | self._handle_kernel_died) | |
37 |
|
37 | |||
38 | # Handle the case where the old kernel manager is still listening. |
|
38 | # Handle the case where the old kernel manager is still listening. | |
39 | if old_manager.channels_running: |
|
39 | if old_manager.channels_running: | |
40 | self._stopped_channels() |
|
40 | self._stopped_channels() | |
41 |
|
41 | |||
42 | # Set the new kernel manager. |
|
42 | # Set the new kernel manager. | |
43 | self._kernel_manager = kernel_manager |
|
43 | self._kernel_manager = kernel_manager | |
44 | if kernel_manager is None: |
|
44 | if kernel_manager is None: | |
45 | return |
|
45 | return | |
46 |
|
46 | |||
47 | # Connect the new kernel manager. |
|
47 | # Connect the new kernel manager. | |
48 | kernel_manager.started_channels.connect(self._started_channels) |
|
48 | kernel_manager.started_channels.connect(self._started_channels) | |
49 | kernel_manager.stopped_channels.connect(self._stopped_channels) |
|
49 | kernel_manager.stopped_channels.connect(self._stopped_channels) | |
50 |
|
50 | |||
51 | # Connect the new kernel manager's channels. |
|
51 | # Connect the new kernel manager's channels. | |
52 | kernel_manager.sub_channel.message_received.connect(self._dispatch) |
|
52 | kernel_manager.sub_channel.message_received.connect(self._dispatch) | |
53 | kernel_manager.shell_channel.message_received.connect(self._dispatch) |
|
53 | kernel_manager.shell_channel.message_received.connect(self._dispatch) | |
54 | kernel_manager.stdin_channel.message_received.connect(self._dispatch) |
|
54 | kernel_manager.stdin_channel.message_received.connect(self._dispatch) | |
55 | kernel_manager.hb_channel.kernel_died.connect(self._handle_kernel_died) |
|
55 | kernel_manager.hb_channel.kernel_died.connect(self._handle_kernel_died) | |
56 |
|
56 | |||
57 | # Handle the case where the kernel manager started channels before |
|
57 | # Handle the case where the kernel manager started channels before | |
58 | # we connected. |
|
58 | # we connected. | |
59 | if kernel_manager.channels_running: |
|
59 | if kernel_manager.channels_running: | |
60 | self._started_channels() |
|
60 | self._started_channels() | |
61 |
|
61 | |||
62 | kernel_manager = property(_get_kernel_manager, _set_kernel_manager) |
|
62 | kernel_manager = property(_get_kernel_manager, _set_kernel_manager) | |
63 |
|
63 | |||
64 | #--------------------------------------------------------------------------- |
|
64 | #--------------------------------------------------------------------------- | |
65 | # 'BaseFrontendMixin' abstract interface |
|
65 | # 'BaseFrontendMixin' abstract interface | |
66 | #--------------------------------------------------------------------------- |
|
66 | #--------------------------------------------------------------------------- | |
67 |
|
67 | |||
68 | def _handle_kernel_died(self, since_last_heartbeat): |
|
68 | def _handle_kernel_died(self, since_last_heartbeat): | |
69 | """ This is called when the ``kernel_died`` signal is emitted. |
|
69 | """ This is called when the ``kernel_died`` signal is emitted. | |
70 |
|
70 | |||
71 | This method is called when the kernel heartbeat has not been |
|
71 | This method is called when the kernel heartbeat has not been | |
72 | active for a certain amount of time. The typical action will be to |
|
72 | active for a certain amount of time. The typical action will be to | |
73 | give the user the option of restarting the kernel. |
|
73 | give the user the option of restarting the kernel. | |
74 |
|
74 | |||
75 | Parameters |
|
75 | Parameters | |
76 | ---------- |
|
76 | ---------- | |
77 | since_last_heartbeat : float |
|
77 | since_last_heartbeat : float | |
78 | The time since the heartbeat was last received. |
|
78 | The time since the heartbeat was last received. | |
79 | """ |
|
79 | """ | |
80 |
|
80 | |||
81 | def _started_channels(self): |
|
81 | def _started_channels(self): | |
82 | """ Called when the KernelManager channels have started listening or |
|
82 | """ Called when the KernelManager channels have started listening or | |
83 | when the frontend is assigned an already listening KernelManager. |
|
83 | when the frontend is assigned an already listening KernelManager. | |
84 | """ |
|
84 | """ | |
85 |
|
85 | |||
86 | def _stopped_channels(self): |
|
86 | def _stopped_channels(self): | |
87 | """ Called when the KernelManager channels have stopped listening or |
|
87 | """ Called when the KernelManager channels have stopped listening or | |
88 | when a listening KernelManager is removed from the frontend. |
|
88 | when a listening KernelManager is removed from the frontend. | |
89 | """ |
|
89 | """ | |
90 |
|
90 | |||
91 | #--------------------------------------------------------------------------- |
|
91 | #--------------------------------------------------------------------------- | |
92 | # 'BaseFrontendMixin' protected interface |
|
92 | # 'BaseFrontendMixin' protected interface | |
93 | #--------------------------------------------------------------------------- |
|
93 | #--------------------------------------------------------------------------- | |
94 |
|
94 | |||
95 | def _dispatch(self, msg): |
|
95 | def _dispatch(self, msg): | |
96 | """ Calls the frontend handler associated with the message type of the |
|
96 | """ Calls the frontend handler associated with the message type of the | |
97 | given message. |
|
97 | given message. | |
98 | """ |
|
98 | """ | |
99 | msg_type = msg['header']['msg_type'] |
|
99 | msg_type = msg['header']['msg_type'] | |
100 | handler = getattr(self, '_handle_' + msg_type, None) |
|
100 | handler = getattr(self, '_handle_' + msg_type, None) | |
101 | if handler: |
|
101 | if handler: | |
102 | handler(msg) |
|
102 | handler(msg) | |
103 |
|
103 | |||
104 | def _is_from_this_session(self, msg): |
|
104 | def _is_from_this_session(self, msg): | |
105 | """ Returns whether a reply from the kernel originated from a request |
|
105 | """ Returns whether a reply from the kernel originated from a request | |
106 | from this frontend. |
|
106 | from this frontend. | |
107 | """ |
|
107 | """ | |
108 | session = self._kernel_manager.session.session |
|
108 | session = self._kernel_manager.session.session | |
109 |
re |
|
109 | parent = msg['parent_header'] | |
|
110 | if not parent: | |||
|
111 | # if the message has no parent, assume it is meant for all frontends | |||
|
112 | return True | |||
|
113 | else: | |||
|
114 | return parent.get('session') == session |
@@ -1,322 +1,325 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """Pylab (matplotlib) support utilities. |
|
2 | """Pylab (matplotlib) support utilities. | |
3 |
|
3 | |||
4 | Authors |
|
4 | Authors | |
5 | ------- |
|
5 | ------- | |
6 |
|
6 | |||
7 | * Fernando Perez. |
|
7 | * Fernando Perez. | |
8 | * Brian Granger |
|
8 | * Brian Granger | |
9 | """ |
|
9 | """ | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Copyright (C) 2009-2011 The IPython Development Team |
|
12 | # Copyright (C) 2009-2011 The IPython Development Team | |
13 | # |
|
13 | # | |
14 | # Distributed under the terms of the BSD License. The full license is in |
|
14 | # Distributed under the terms of the BSD License. The full license is in | |
15 | # the file COPYING, distributed as part of this software. |
|
15 | # the file COPYING, distributed as part of this software. | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 | # Imports |
|
19 | # Imports | |
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 |
|
21 | |||
|
22 | import sys | |||
22 | from io import BytesIO |
|
23 | from io import BytesIO | |
23 |
|
24 | |||
24 | from IPython.utils.decorators import flag_calls |
|
25 | from IPython.utils.decorators import flag_calls | |
25 |
|
26 | |||
26 | # If user specifies a GUI, that dictates the backend, otherwise we read the |
|
27 | # If user specifies a GUI, that dictates the backend, otherwise we read the | |
27 | # user's mpl default from the mpl rc structure |
|
28 | # user's mpl default from the mpl rc structure | |
28 | backends = {'tk': 'TkAgg', |
|
29 | backends = {'tk': 'TkAgg', | |
29 | 'gtk': 'GTKAgg', |
|
30 | 'gtk': 'GTKAgg', | |
30 | 'wx': 'WXAgg', |
|
31 | 'wx': 'WXAgg', | |
31 | 'qt': 'Qt4Agg', # qt3 not supported |
|
32 | 'qt': 'Qt4Agg', # qt3 not supported | |
32 | 'qt4': 'Qt4Agg', |
|
33 | 'qt4': 'Qt4Agg', | |
33 | 'osx': 'MacOSX', |
|
34 | 'osx': 'MacOSX', | |
34 | 'inline' : 'module://IPython.zmq.pylab.backend_inline'} |
|
35 | 'inline' : 'module://IPython.zmq.pylab.backend_inline'} | |
35 |
|
36 | |||
36 | # We also need a reverse backends2guis mapping that will properly choose which |
|
37 | # We also need a reverse backends2guis mapping that will properly choose which | |
37 | # GUI support to activate based on the desired matplotlib backend. For the |
|
38 | # GUI support to activate based on the desired matplotlib backend. For the | |
38 | # most part it's just a reverse of the above dict, but we also need to add a |
|
39 | # most part it's just a reverse of the above dict, but we also need to add a | |
39 | # few others that map to the same GUI manually: |
|
40 | # few others that map to the same GUI manually: | |
40 | backend2gui = dict(zip(backends.values(), backends.keys())) |
|
41 | backend2gui = dict(zip(backends.values(), backends.keys())) | |
41 | # In the reverse mapping, there are a few extra valid matplotlib backends that |
|
42 | # In the reverse mapping, there are a few extra valid matplotlib backends that | |
42 | # map to the same GUI support |
|
43 | # map to the same GUI support | |
43 | backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk' |
|
44 | backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk' | |
44 | backend2gui['WX'] = 'wx' |
|
45 | backend2gui['WX'] = 'wx' | |
45 | backend2gui['CocoaAgg'] = 'osx' |
|
46 | backend2gui['CocoaAgg'] = 'osx' | |
46 |
|
47 | |||
47 | #----------------------------------------------------------------------------- |
|
48 | #----------------------------------------------------------------------------- | |
48 | # Matplotlib utilities |
|
49 | # Matplotlib utilities | |
49 | #----------------------------------------------------------------------------- |
|
50 | #----------------------------------------------------------------------------- | |
50 |
|
51 | |||
51 |
|
52 | |||
52 | def getfigs(*fig_nums): |
|
53 | def getfigs(*fig_nums): | |
53 | """Get a list of matplotlib figures by figure numbers. |
|
54 | """Get a list of matplotlib figures by figure numbers. | |
54 |
|
55 | |||
55 | If no arguments are given, all available figures are returned. If the |
|
56 | If no arguments are given, all available figures are returned. If the | |
56 | argument list contains references to invalid figures, a warning is printed |
|
57 | argument list contains references to invalid figures, a warning is printed | |
57 | but the function continues pasting further figures. |
|
58 | but the function continues pasting further figures. | |
58 |
|
59 | |||
59 | Parameters |
|
60 | Parameters | |
60 | ---------- |
|
61 | ---------- | |
61 | figs : tuple |
|
62 | figs : tuple | |
62 | A tuple of ints giving the figure numbers of the figures to return. |
|
63 | A tuple of ints giving the figure numbers of the figures to return. | |
63 | """ |
|
64 | """ | |
64 | from matplotlib._pylab_helpers import Gcf |
|
65 | from matplotlib._pylab_helpers import Gcf | |
65 | if not fig_nums: |
|
66 | if not fig_nums: | |
66 | fig_managers = Gcf.get_all_fig_managers() |
|
67 | fig_managers = Gcf.get_all_fig_managers() | |
67 | return [fm.canvas.figure for fm in fig_managers] |
|
68 | return [fm.canvas.figure for fm in fig_managers] | |
68 | else: |
|
69 | else: | |
69 | figs = [] |
|
70 | figs = [] | |
70 | for num in fig_nums: |
|
71 | for num in fig_nums: | |
71 | f = Gcf.figs.get(num) |
|
72 | f = Gcf.figs.get(num) | |
72 | if f is None: |
|
73 | if f is None: | |
73 | print('Warning: figure %s not available.' % num) |
|
74 | print('Warning: figure %s not available.' % num) | |
74 | else: |
|
75 | else: | |
75 | figs.append(f.canvas.figure) |
|
76 | figs.append(f.canvas.figure) | |
76 | return figs |
|
77 | return figs | |
77 |
|
78 | |||
78 |
|
79 | |||
79 | def figsize(sizex, sizey): |
|
80 | def figsize(sizex, sizey): | |
80 | """Set the default figure size to be [sizex, sizey]. |
|
81 | """Set the default figure size to be [sizex, sizey]. | |
81 |
|
82 | |||
82 | This is just an easy to remember, convenience wrapper that sets:: |
|
83 | This is just an easy to remember, convenience wrapper that sets:: | |
83 |
|
84 | |||
84 | matplotlib.rcParams['figure.figsize'] = [sizex, sizey] |
|
85 | matplotlib.rcParams['figure.figsize'] = [sizex, sizey] | |
85 | """ |
|
86 | """ | |
86 | import matplotlib |
|
87 | import matplotlib | |
87 | matplotlib.rcParams['figure.figsize'] = [sizex, sizey] |
|
88 | matplotlib.rcParams['figure.figsize'] = [sizex, sizey] | |
88 |
|
89 | |||
89 |
|
90 | |||
90 | def print_figure(fig, fmt='png'): |
|
91 | def print_figure(fig, fmt='png'): | |
91 | """Convert a figure to svg or png for inline display.""" |
|
92 | """Convert a figure to svg or png for inline display.""" | |
92 | # When there's an empty figure, we shouldn't return anything, otherwise we |
|
93 | # When there's an empty figure, we shouldn't return anything, otherwise we | |
93 | # get big blank areas in the qt console. |
|
94 | # get big blank areas in the qt console. | |
94 | if not fig.axes: |
|
95 | if not fig.axes: | |
95 | return |
|
96 | return | |
96 |
|
97 | |||
97 | fc = fig.get_facecolor() |
|
98 | fc = fig.get_facecolor() | |
98 | ec = fig.get_edgecolor() |
|
99 | ec = fig.get_edgecolor() | |
99 | fig.set_facecolor('white') |
|
100 | fig.set_facecolor('white') | |
100 | fig.set_edgecolor('white') |
|
101 | fig.set_edgecolor('white') | |
101 | try: |
|
102 | try: | |
102 | bytes_io = BytesIO() |
|
103 | bytes_io = BytesIO() | |
103 | fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight') |
|
104 | fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight') | |
104 | data = bytes_io.getvalue() |
|
105 | data = bytes_io.getvalue() | |
105 | finally: |
|
106 | finally: | |
106 | fig.set_facecolor(fc) |
|
107 | fig.set_facecolor(fc) | |
107 | fig.set_edgecolor(ec) |
|
108 | fig.set_edgecolor(ec) | |
108 | return data |
|
109 | return data | |
109 |
|
110 | |||
110 |
|
111 | |||
111 | # We need a little factory function here to create the closure where |
|
112 | # We need a little factory function here to create the closure where | |
112 | # safe_execfile can live. |
|
113 | # safe_execfile can live. | |
113 | def mpl_runner(safe_execfile): |
|
114 | def mpl_runner(safe_execfile): | |
114 | """Factory to return a matplotlib-enabled runner for %run. |
|
115 | """Factory to return a matplotlib-enabled runner for %run. | |
115 |
|
116 | |||
116 | Parameters |
|
117 | Parameters | |
117 | ---------- |
|
118 | ---------- | |
118 | safe_execfile : function |
|
119 | safe_execfile : function | |
119 | This must be a function with the same interface as the |
|
120 | This must be a function with the same interface as the | |
120 | :meth:`safe_execfile` method of IPython. |
|
121 | :meth:`safe_execfile` method of IPython. | |
121 |
|
122 | |||
122 | Returns |
|
123 | Returns | |
123 | ------- |
|
124 | ------- | |
124 | A function suitable for use as the ``runner`` argument of the %run magic |
|
125 | A function suitable for use as the ``runner`` argument of the %run magic | |
125 | function. |
|
126 | function. | |
126 | """ |
|
127 | """ | |
127 |
|
128 | |||
128 | def mpl_execfile(fname,*where,**kw): |
|
129 | def mpl_execfile(fname,*where,**kw): | |
129 | """matplotlib-aware wrapper around safe_execfile. |
|
130 | """matplotlib-aware wrapper around safe_execfile. | |
130 |
|
131 | |||
131 | Its interface is identical to that of the :func:`execfile` builtin. |
|
132 | Its interface is identical to that of the :func:`execfile` builtin. | |
132 |
|
133 | |||
133 | This is ultimately a call to execfile(), but wrapped in safeties to |
|
134 | This is ultimately a call to execfile(), but wrapped in safeties to | |
134 | properly handle interactive rendering.""" |
|
135 | properly handle interactive rendering.""" | |
135 |
|
136 | |||
136 | import matplotlib |
|
137 | import matplotlib | |
137 | import matplotlib.pylab as pylab |
|
138 | import matplotlib.pylab as pylab | |
138 |
|
139 | |||
139 | #print '*** Matplotlib runner ***' # dbg |
|
140 | #print '*** Matplotlib runner ***' # dbg | |
140 | # turn off rendering until end of script |
|
141 | # turn off rendering until end of script | |
141 | is_interactive = matplotlib.rcParams['interactive'] |
|
142 | is_interactive = matplotlib.rcParams['interactive'] | |
142 | matplotlib.interactive(False) |
|
143 | matplotlib.interactive(False) | |
143 | safe_execfile(fname,*where,**kw) |
|
144 | safe_execfile(fname,*where,**kw) | |
144 | matplotlib.interactive(is_interactive) |
|
145 | matplotlib.interactive(is_interactive) | |
145 | # make rendering call now, if the user tried to do it |
|
146 | # make rendering call now, if the user tried to do it | |
146 | if pylab.draw_if_interactive.called: |
|
147 | if pylab.draw_if_interactive.called: | |
147 | pylab.draw() |
|
148 | pylab.draw() | |
148 | pylab.draw_if_interactive.called = False |
|
149 | pylab.draw_if_interactive.called = False | |
149 |
|
150 | |||
150 | return mpl_execfile |
|
151 | return mpl_execfile | |
151 |
|
152 | |||
152 |
|
153 | |||
153 | def select_figure_format(shell, fmt): |
|
154 | def select_figure_format(shell, fmt): | |
154 | """Select figure format for inline backend, either 'png' or 'svg'. |
|
155 | """Select figure format for inline backend, either 'png' or 'svg'. | |
155 |
|
156 | |||
156 | Using this method ensures only one figure format is active at a time. |
|
157 | Using this method ensures only one figure format is active at a time. | |
157 | """ |
|
158 | """ | |
158 | from matplotlib.figure import Figure |
|
159 | from matplotlib.figure import Figure | |
159 | from IPython.zmq.pylab import backend_inline |
|
160 | from IPython.zmq.pylab import backend_inline | |
160 |
|
161 | |||
161 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] |
|
162 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] | |
162 | png_formatter = shell.display_formatter.formatters['image/png'] |
|
163 | png_formatter = shell.display_formatter.formatters['image/png'] | |
163 |
|
164 | |||
164 | if fmt=='png': |
|
165 | if fmt=='png': | |
165 | svg_formatter.type_printers.pop(Figure, None) |
|
166 | svg_formatter.type_printers.pop(Figure, None) | |
166 | png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) |
|
167 | png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) | |
167 | elif fmt=='svg': |
|
168 | elif fmt=='svg': | |
168 | png_formatter.type_printers.pop(Figure, None) |
|
169 | png_formatter.type_printers.pop(Figure, None) | |
169 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) |
|
170 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) | |
170 | else: |
|
171 | else: | |
171 | raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt) |
|
172 | raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt) | |
172 |
|
173 | |||
173 | # set the format to be used in the backend() |
|
174 | # set the format to be used in the backend() | |
174 | backend_inline._figure_format = fmt |
|
175 | backend_inline._figure_format = fmt | |
175 |
|
176 | |||
176 | #----------------------------------------------------------------------------- |
|
177 | #----------------------------------------------------------------------------- | |
177 | # Code for initializing matplotlib and importing pylab |
|
178 | # Code for initializing matplotlib and importing pylab | |
178 | #----------------------------------------------------------------------------- |
|
179 | #----------------------------------------------------------------------------- | |
179 |
|
180 | |||
180 |
|
181 | |||
181 | def find_gui_and_backend(gui=None): |
|
182 | def find_gui_and_backend(gui=None): | |
182 | """Given a gui string return the gui and mpl backend. |
|
183 | """Given a gui string return the gui and mpl backend. | |
183 |
|
184 | |||
184 | Parameters |
|
185 | Parameters | |
185 | ---------- |
|
186 | ---------- | |
186 | gui : str |
|
187 | gui : str | |
187 | Can be one of ('tk','gtk','wx','qt','qt4','inline'). |
|
188 | Can be one of ('tk','gtk','wx','qt','qt4','inline'). | |
188 |
|
189 | |||
189 | Returns |
|
190 | Returns | |
190 | ------- |
|
191 | ------- | |
191 | A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg', |
|
192 | A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg', | |
192 | 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline'). |
|
193 | 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline'). | |
193 | """ |
|
194 | """ | |
194 |
|
195 | |||
195 | import matplotlib |
|
196 | import matplotlib | |
196 |
|
197 | |||
197 | if gui and gui != 'auto': |
|
198 | if gui and gui != 'auto': | |
198 | # select backend based on requested gui |
|
199 | # select backend based on requested gui | |
199 | backend = backends[gui] |
|
200 | backend = backends[gui] | |
200 | else: |
|
201 | else: | |
201 | backend = matplotlib.rcParams['backend'] |
|
202 | backend = matplotlib.rcParams['backend'] | |
202 | # In this case, we need to find what the appropriate gui selection call |
|
203 | # In this case, we need to find what the appropriate gui selection call | |
203 | # should be for IPython, so we can activate inputhook accordingly |
|
204 | # should be for IPython, so we can activate inputhook accordingly | |
204 | gui = backend2gui.get(backend, None) |
|
205 | gui = backend2gui.get(backend, None) | |
205 | return gui, backend |
|
206 | return gui, backend | |
206 |
|
207 | |||
207 |
|
208 | |||
208 | def activate_matplotlib(backend): |
|
209 | def activate_matplotlib(backend): | |
209 | """Activate the given backend and set interactive to True.""" |
|
210 | """Activate the given backend and set interactive to True.""" | |
210 |
|
211 | |||
211 | import matplotlib |
|
212 | import matplotlib | |
212 | if backend.startswith('module://'): |
|
213 | if backend.startswith('module://'): | |
213 | # Work around bug in matplotlib: matplotlib.use converts the |
|
214 | # Work around bug in matplotlib: matplotlib.use converts the | |
214 | # backend_id to lowercase even if a module name is specified! |
|
215 | # backend_id to lowercase even if a module name is specified! | |
215 | matplotlib.rcParams['backend'] = backend |
|
216 | matplotlib.rcParams['backend'] = backend | |
216 | else: |
|
217 | else: | |
217 | matplotlib.use(backend) |
|
218 | matplotlib.use(backend) | |
218 | matplotlib.interactive(True) |
|
219 | matplotlib.interactive(True) | |
219 |
|
220 | |||
220 | # This must be imported last in the matplotlib series, after |
|
221 | # This must be imported last in the matplotlib series, after | |
221 | # backend/interactivity choices have been made |
|
222 | # backend/interactivity choices have been made | |
222 | import matplotlib.pylab as pylab |
|
223 | import matplotlib.pylab as pylab | |
223 |
|
224 | |||
224 | # XXX For now leave this commented out, but depending on discussions with |
|
225 | # XXX For now leave this commented out, but depending on discussions with | |
225 | # mpl-dev, we may be able to allow interactive switching... |
|
226 | # mpl-dev, we may be able to allow interactive switching... | |
226 | #import matplotlib.pyplot |
|
227 | #import matplotlib.pyplot | |
227 | #matplotlib.pyplot.switch_backend(backend) |
|
228 | #matplotlib.pyplot.switch_backend(backend) | |
228 |
|
229 | |||
229 | pylab.show._needmain = False |
|
230 | pylab.show._needmain = False | |
230 | # We need to detect at runtime whether show() is called by the user. |
|
231 | # We need to detect at runtime whether show() is called by the user. | |
231 | # For this, we wrap it into a decorator which adds a 'called' flag. |
|
232 | # For this, we wrap it into a decorator which adds a 'called' flag. | |
232 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) |
|
233 | pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) | |
233 |
|
234 | |||
234 | def import_pylab(user_ns, backend, import_all=True, shell=None): |
|
235 | def import_pylab(user_ns, backend, import_all=True, shell=None): | |
235 | """Import the standard pylab symbols into user_ns.""" |
|
236 | """Import the standard pylab symbols into user_ns.""" | |
236 |
|
237 | |||
237 | # Import numpy as np/pyplot as plt are conventions we're trying to |
|
238 | # Import numpy as np/pyplot as plt are conventions we're trying to | |
238 | # somewhat standardize on. Making them available to users by default |
|
239 | # somewhat standardize on. Making them available to users by default | |
239 | # will greatly help this. |
|
240 | # will greatly help this. | |
240 | s = ("import numpy\n" |
|
241 | s = ("import numpy\n" | |
241 | "import matplotlib\n" |
|
242 | "import matplotlib\n" | |
242 | "from matplotlib import pylab, mlab, pyplot\n" |
|
243 | "from matplotlib import pylab, mlab, pyplot\n" | |
243 | "np = numpy\n" |
|
244 | "np = numpy\n" | |
244 | "plt = pyplot\n" |
|
245 | "plt = pyplot\n" | |
245 | ) |
|
246 | ) | |
246 | exec s in user_ns |
|
247 | exec s in user_ns | |
247 |
|
248 | |||
248 | if shell is not None: |
|
249 | if shell is not None: | |
249 | exec s in shell.user_ns_hidden |
|
250 | exec s in shell.user_ns_hidden | |
250 | # If using our svg payload backend, register the post-execution |
|
251 | # If using our svg payload backend, register the post-execution | |
251 | # function that will pick up the results for display. This can only be |
|
252 | # function that will pick up the results for display. This can only be | |
252 | # done with access to the real shell object. |
|
253 | # done with access to the real shell object. | |
253 | # |
|
254 | # | |
254 | from IPython.zmq.pylab.backend_inline import InlineBackend |
|
255 | from IPython.zmq.pylab.backend_inline import InlineBackend | |
255 |
|
256 | |||
256 | cfg = InlineBackend.instance(config=shell.config) |
|
257 | cfg = InlineBackend.instance(config=shell.config) | |
257 | cfg.shell = shell |
|
258 | cfg.shell = shell | |
258 | if cfg not in shell.configurables: |
|
259 | if cfg not in shell.configurables: | |
259 | shell.configurables.append(cfg) |
|
260 | shell.configurables.append(cfg) | |
260 |
|
261 | |||
261 | if backend == backends['inline']: |
|
262 | if backend == backends['inline']: | |
262 | from IPython.zmq.pylab.backend_inline import flush_figures |
|
263 | from IPython.zmq.pylab.backend_inline import flush_figures | |
263 | from matplotlib import pyplot |
|
264 | from matplotlib import pyplot | |
264 | shell.register_post_execute(flush_figures) |
|
265 | shell.register_post_execute(flush_figures) | |
265 | # load inline_rc |
|
266 | # load inline_rc | |
266 | pyplot.rcParams.update(cfg.rc) |
|
267 | pyplot.rcParams.update(cfg.rc) | |
267 |
|
268 | |||
268 | # Add 'figsize' to pyplot and to the user's namespace |
|
269 | # Add 'figsize' to pyplot and to the user's namespace | |
269 | user_ns['figsize'] = pyplot.figsize = figsize |
|
270 | user_ns['figsize'] = pyplot.figsize = figsize | |
270 | shell.user_ns_hidden['figsize'] = figsize |
|
271 | shell.user_ns_hidden['figsize'] = figsize | |
271 |
|
272 | |||
272 | # Setup the default figure format |
|
273 | # Setup the default figure format | |
273 | fmt = cfg.figure_format |
|
274 | fmt = cfg.figure_format | |
274 | select_figure_format(shell, fmt) |
|
275 | select_figure_format(shell, fmt) | |
275 |
|
276 | |||
276 | # The old pastefig function has been replaced by display |
|
277 | # The old pastefig function has been replaced by display | |
277 | from IPython.core.display import display |
|
278 | from IPython.core.display import display | |
278 | # Add display and display_png to the user's namespace |
|
279 | # Add display and display_png to the user's namespace | |
279 | user_ns['display'] = display |
|
280 | user_ns['display'] = display | |
280 | shell.user_ns_hidden['display'] = display |
|
281 | shell.user_ns_hidden['display'] = display | |
281 | user_ns['getfigs'] = getfigs |
|
282 | user_ns['getfigs'] = getfigs | |
282 | shell.user_ns_hidden['getfigs'] = getfigs |
|
283 | shell.user_ns_hidden['getfigs'] = getfigs | |
283 |
|
284 | |||
284 | if import_all: |
|
285 | if import_all: | |
285 | s = ("from matplotlib.pylab import *\n" |
|
286 | s = ("from matplotlib.pylab import *\n" | |
286 | "from numpy import *\n") |
|
287 | "from numpy import *\n") | |
287 | exec s in user_ns |
|
288 | exec s in user_ns | |
288 | if shell is not None: |
|
289 | if shell is not None: | |
289 | exec s in shell.user_ns_hidden |
|
290 | exec s in shell.user_ns_hidden | |
290 |
|
291 | |||
291 |
|
292 | |||
292 | def pylab_activate(user_ns, gui=None, import_all=True, shell=None): |
|
293 | def pylab_activate(user_ns, gui=None, import_all=True, shell=None): | |
293 | """Activate pylab mode in the user's namespace. |
|
294 | """Activate pylab mode in the user's namespace. | |
294 |
|
295 | |||
295 | Loads and initializes numpy, matplotlib and friends for interactive use. |
|
296 | Loads and initializes numpy, matplotlib and friends for interactive use. | |
296 |
|
297 | |||
297 | Parameters |
|
298 | Parameters | |
298 | ---------- |
|
299 | ---------- | |
299 | user_ns : dict |
|
300 | user_ns : dict | |
300 | Namespace where the imports will occur. |
|
301 | Namespace where the imports will occur. | |
301 |
|
302 | |||
302 | gui : optional, string |
|
303 | gui : optional, string | |
303 | A valid gui name following the conventions of the %gui magic. |
|
304 | A valid gui name following the conventions of the %gui magic. | |
304 |
|
305 | |||
305 | import_all : optional, boolean |
|
306 | import_all : optional, boolean | |
306 | If true, an 'import *' is done from numpy and pylab. |
|
307 | If true, an 'import *' is done from numpy and pylab. | |
307 |
|
308 | |||
308 | Returns |
|
309 | Returns | |
309 | ------- |
|
310 | ------- | |
310 | The actual gui used (if not given as input, it was obtained from matplotlib |
|
311 | The actual gui used (if not given as input, it was obtained from matplotlib | |
311 | itself, and will be needed next to configure IPython's gui integration. |
|
312 | itself, and will be needed next to configure IPython's gui integration. | |
312 | """ |
|
313 | """ | |
313 | gui, backend = find_gui_and_backend(gui) |
|
314 | gui, backend = find_gui_and_backend(gui) | |
314 | activate_matplotlib(backend) |
|
315 | activate_matplotlib(backend) | |
315 | import_pylab(user_ns, backend, import_all, shell) |
|
316 | import_pylab(user_ns, backend, import_all, shell) | |
316 |
|
317 | |||
317 | print """ |
|
318 | print """ | |
318 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. |
|
319 | Welcome to pylab, a matplotlib-based Python environment [backend: %s]. | |
319 | For more information, type 'help(pylab)'.""" % backend |
|
320 | For more information, type 'help(pylab)'.""" % backend | |
|
321 | # flush stdout, just to be safe | |||
|
322 | sys.stdout.flush() | |||
320 |
|
323 | |||
321 | return gui |
|
324 | return gui | |
322 |
|
325 |
@@ -1,299 +1,303 b'' | |||||
1 | """An Application for launching a kernel |
|
1 | """An Application for launching a kernel | |
2 |
|
2 | |||
3 | Authors |
|
3 | Authors | |
4 | ------- |
|
4 | ------- | |
5 | * MinRK |
|
5 | * MinRK | |
6 | """ |
|
6 | """ | |
7 | #----------------------------------------------------------------------------- |
|
7 | #----------------------------------------------------------------------------- | |
8 | # Copyright (C) 2011 The IPython Development Team |
|
8 | # Copyright (C) 2011 The IPython Development Team | |
9 | # |
|
9 | # | |
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING.txt, distributed as part of this software. |
|
11 | # the file COPYING.txt, distributed as part of this software. | |
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | # Standard library imports. |
|
18 | # Standard library imports. | |
19 | import json |
|
19 | import json | |
20 | import os |
|
20 | import os | |
21 | import sys |
|
21 | import sys | |
22 |
|
22 | |||
23 | # System library imports. |
|
23 | # System library imports. | |
24 | import zmq |
|
24 | import zmq | |
25 |
|
25 | |||
26 | # IPython imports. |
|
26 | # IPython imports. | |
27 | from IPython.core.ultratb import FormattedTB |
|
27 | from IPython.core.ultratb import FormattedTB | |
28 | from IPython.core.application import ( |
|
28 | from IPython.core.application import ( | |
29 | BaseIPythonApplication, base_flags, base_aliases, catch_config_error |
|
29 | BaseIPythonApplication, base_flags, base_aliases, catch_config_error | |
30 | ) |
|
30 | ) | |
31 | from IPython.utils import io |
|
31 | from IPython.utils import io | |
32 | from IPython.utils.localinterfaces import LOCALHOST |
|
32 | from IPython.utils.localinterfaces import LOCALHOST | |
33 | from IPython.utils.path import filefind |
|
33 | from IPython.utils.path import filefind | |
34 | from IPython.utils.py3compat import str_to_bytes |
|
34 | from IPython.utils.py3compat import str_to_bytes | |
35 | from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Integer, Bool, |
|
35 | from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Integer, Bool, | |
36 | DottedObjectName) |
|
36 | DottedObjectName) | |
37 | from IPython.utils.importstring import import_item |
|
37 | from IPython.utils.importstring import import_item | |
38 | # local imports |
|
38 | # local imports | |
39 | from IPython.zmq.entry_point import write_connection_file |
|
39 | from IPython.zmq.entry_point import write_connection_file | |
40 | from IPython.zmq.heartbeat import Heartbeat |
|
40 | from IPython.zmq.heartbeat import Heartbeat | |
41 | from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows |
|
41 | from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows | |
42 | from IPython.zmq.session import ( |
|
42 | from IPython.zmq.session import ( | |
43 | Session, session_flags, session_aliases, default_secure, |
|
43 | Session, session_flags, session_aliases, default_secure, | |
44 | ) |
|
44 | ) | |
45 |
|
45 | |||
46 |
|
46 | |||
47 | #----------------------------------------------------------------------------- |
|
47 | #----------------------------------------------------------------------------- | |
48 | # Flags and Aliases |
|
48 | # Flags and Aliases | |
49 | #----------------------------------------------------------------------------- |
|
49 | #----------------------------------------------------------------------------- | |
50 |
|
50 | |||
51 | kernel_aliases = dict(base_aliases) |
|
51 | kernel_aliases = dict(base_aliases) | |
52 | kernel_aliases.update({ |
|
52 | kernel_aliases.update({ | |
53 | 'ip' : 'KernelApp.ip', |
|
53 | 'ip' : 'KernelApp.ip', | |
54 | 'hb' : 'KernelApp.hb_port', |
|
54 | 'hb' : 'KernelApp.hb_port', | |
55 | 'shell' : 'KernelApp.shell_port', |
|
55 | 'shell' : 'KernelApp.shell_port', | |
56 | 'iopub' : 'KernelApp.iopub_port', |
|
56 | 'iopub' : 'KernelApp.iopub_port', | |
57 | 'stdin' : 'KernelApp.stdin_port', |
|
57 | 'stdin' : 'KernelApp.stdin_port', | |
58 | 'f' : 'KernelApp.connection_file', |
|
58 | 'f' : 'KernelApp.connection_file', | |
59 | 'parent': 'KernelApp.parent', |
|
59 | 'parent': 'KernelApp.parent', | |
60 | }) |
|
60 | }) | |
61 | if sys.platform.startswith('win'): |
|
61 | if sys.platform.startswith('win'): | |
62 | kernel_aliases['interrupt'] = 'KernelApp.interrupt' |
|
62 | kernel_aliases['interrupt'] = 'KernelApp.interrupt' | |
63 |
|
63 | |||
64 | kernel_flags = dict(base_flags) |
|
64 | kernel_flags = dict(base_flags) | |
65 | kernel_flags.update({ |
|
65 | kernel_flags.update({ | |
66 | 'no-stdout' : ( |
|
66 | 'no-stdout' : ( | |
67 | {'KernelApp' : {'no_stdout' : True}}, |
|
67 | {'KernelApp' : {'no_stdout' : True}}, | |
68 | "redirect stdout to the null device"), |
|
68 | "redirect stdout to the null device"), | |
69 | 'no-stderr' : ( |
|
69 | 'no-stderr' : ( | |
70 | {'KernelApp' : {'no_stderr' : True}}, |
|
70 | {'KernelApp' : {'no_stderr' : True}}, | |
71 | "redirect stderr to the null device"), |
|
71 | "redirect stderr to the null device"), | |
72 | }) |
|
72 | }) | |
73 |
|
73 | |||
74 | # inherit flags&aliases for Sessions |
|
74 | # inherit flags&aliases for Sessions | |
75 | kernel_aliases.update(session_aliases) |
|
75 | kernel_aliases.update(session_aliases) | |
76 | kernel_flags.update(session_flags) |
|
76 | kernel_flags.update(session_flags) | |
77 |
|
77 | |||
78 |
|
78 | |||
79 |
|
79 | |||
80 | #----------------------------------------------------------------------------- |
|
80 | #----------------------------------------------------------------------------- | |
81 | # Application class for starting a Kernel |
|
81 | # Application class for starting a Kernel | |
82 | #----------------------------------------------------------------------------- |
|
82 | #----------------------------------------------------------------------------- | |
83 |
|
83 | |||
84 | class KernelApp(BaseIPythonApplication): |
|
84 | class KernelApp(BaseIPythonApplication): | |
85 | name='pykernel' |
|
85 | name='pykernel' | |
86 | aliases = Dict(kernel_aliases) |
|
86 | aliases = Dict(kernel_aliases) | |
87 | flags = Dict(kernel_flags) |
|
87 | flags = Dict(kernel_flags) | |
88 | classes = [Session] |
|
88 | classes = [Session] | |
89 | # the kernel class, as an importstring |
|
89 | # the kernel class, as an importstring | |
90 | kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel') |
|
90 | kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel') | |
91 | kernel = Any() |
|
91 | kernel = Any() | |
92 | poller = Any() # don't restrict this even though current pollers are all Threads |
|
92 | poller = Any() # don't restrict this even though current pollers are all Threads | |
93 | heartbeat = Instance(Heartbeat) |
|
93 | heartbeat = Instance(Heartbeat) | |
94 | session = Instance('IPython.zmq.session.Session') |
|
94 | session = Instance('IPython.zmq.session.Session') | |
95 | ports = Dict() |
|
95 | ports = Dict() | |
96 |
|
96 | |||
97 | # inherit config file name from parent: |
|
97 | # inherit config file name from parent: | |
98 | parent_appname = Unicode(config=True) |
|
98 | parent_appname = Unicode(config=True) | |
99 | def _parent_appname_changed(self, name, old, new): |
|
99 | def _parent_appname_changed(self, name, old, new): | |
100 | if self.config_file_specified: |
|
100 | if self.config_file_specified: | |
101 | # it was manually specified, ignore |
|
101 | # it was manually specified, ignore | |
102 | return |
|
102 | return | |
103 | self.config_file_name = new.replace('-','_') + u'_config.py' |
|
103 | self.config_file_name = new.replace('-','_') + u'_config.py' | |
104 | # don't let this count as specifying the config file |
|
104 | # don't let this count as specifying the config file | |
105 | self.config_file_specified = False |
|
105 | self.config_file_specified = False | |
106 |
|
106 | |||
107 | # connection info: |
|
107 | # connection info: | |
108 | ip = Unicode(LOCALHOST, config=True, |
|
108 | ip = Unicode(LOCALHOST, config=True, | |
109 | help="Set the IP or interface on which the kernel will listen.") |
|
109 | help="Set the IP or interface on which the kernel will listen.") | |
110 | hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]") |
|
110 | hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]") | |
111 | shell_port = Integer(0, config=True, help="set the shell (XREP) port [default: random]") |
|
111 | shell_port = Integer(0, config=True, help="set the shell (XREP) port [default: random]") | |
112 | iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]") |
|
112 | iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]") | |
113 | stdin_port = Integer(0, config=True, help="set the stdin (XREQ) port [default: random]") |
|
113 | stdin_port = Integer(0, config=True, help="set the stdin (XREQ) port [default: random]") | |
114 | connection_file = Unicode('', config=True, |
|
114 | connection_file = Unicode('', config=True, | |
115 | help="""JSON file in which to store connection info [default: kernel-<pid>.json] |
|
115 | help="""JSON file in which to store connection info [default: kernel-<pid>.json] | |
116 |
|
116 | |||
117 | This file will contain the IP, ports, and authentication key needed to connect |
|
117 | This file will contain the IP, ports, and authentication key needed to connect | |
118 | clients to this kernel. By default, this file will be created in the security-dir |
|
118 | clients to this kernel. By default, this file will be created in the security-dir | |
119 | of the current profile, but can be specified by absolute path. |
|
119 | of the current profile, but can be specified by absolute path. | |
120 | """) |
|
120 | """) | |
121 |
|
121 | |||
122 | # streams, etc. |
|
122 | # streams, etc. | |
123 | no_stdout = Bool(False, config=True, help="redirect stdout to the null device") |
|
123 | no_stdout = Bool(False, config=True, help="redirect stdout to the null device") | |
124 | no_stderr = Bool(False, config=True, help="redirect stderr to the null device") |
|
124 | no_stderr = Bool(False, config=True, help="redirect stderr to the null device") | |
125 | outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream', |
|
125 | outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream', | |
126 | config=True, help="The importstring for the OutStream factory") |
|
126 | config=True, help="The importstring for the OutStream factory") | |
127 | displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook', |
|
127 | displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook', | |
128 | config=True, help="The importstring for the DisplayHook factory") |
|
128 | config=True, help="The importstring for the DisplayHook factory") | |
129 |
|
129 | |||
130 | # polling |
|
130 | # polling | |
131 | parent = Integer(0, config=True, |
|
131 | parent = Integer(0, config=True, | |
132 | help="""kill this process if its parent dies. On Windows, the argument |
|
132 | help="""kill this process if its parent dies. On Windows, the argument | |
133 | specifies the HANDLE of the parent process, otherwise it is simply boolean. |
|
133 | specifies the HANDLE of the parent process, otherwise it is simply boolean. | |
134 | """) |
|
134 | """) | |
135 | interrupt = Integer(0, config=True, |
|
135 | interrupt = Integer(0, config=True, | |
136 | help="""ONLY USED ON WINDOWS |
|
136 | help="""ONLY USED ON WINDOWS | |
137 | Interrupt this process when the parent is signalled. |
|
137 | Interrupt this process when the parent is signalled. | |
138 | """) |
|
138 | """) | |
139 |
|
139 | |||
140 | def init_crash_handler(self): |
|
140 | def init_crash_handler(self): | |
141 | # Install minimal exception handling |
|
141 | # Install minimal exception handling | |
142 | sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', |
|
142 | sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', | |
143 | ostream=sys.__stdout__) |
|
143 | ostream=sys.__stdout__) | |
144 |
|
144 | |||
145 | def init_poller(self): |
|
145 | def init_poller(self): | |
146 | if sys.platform == 'win32': |
|
146 | if sys.platform == 'win32': | |
147 | if self.interrupt or self.parent: |
|
147 | if self.interrupt or self.parent: | |
148 | self.poller = ParentPollerWindows(self.interrupt, self.parent) |
|
148 | self.poller = ParentPollerWindows(self.interrupt, self.parent) | |
149 | elif self.parent: |
|
149 | elif self.parent: | |
150 | self.poller = ParentPollerUnix() |
|
150 | self.poller = ParentPollerUnix() | |
151 |
|
151 | |||
152 | def _bind_socket(self, s, port): |
|
152 | def _bind_socket(self, s, port): | |
153 | iface = 'tcp://%s' % self.ip |
|
153 | iface = 'tcp://%s' % self.ip | |
154 | if port <= 0: |
|
154 | if port <= 0: | |
155 | port = s.bind_to_random_port(iface) |
|
155 | port = s.bind_to_random_port(iface) | |
156 | else: |
|
156 | else: | |
157 | s.bind(iface + ':%i'%port) |
|
157 | s.bind(iface + ':%i'%port) | |
158 | return port |
|
158 | return port | |
159 |
|
159 | |||
160 | def load_connection_file(self): |
|
160 | def load_connection_file(self): | |
161 | """load ip/port/hmac config from JSON connection file""" |
|
161 | """load ip/port/hmac config from JSON connection file""" | |
162 | try: |
|
162 | try: | |
163 | fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir]) |
|
163 | fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir]) | |
164 | except IOError: |
|
164 | except IOError: | |
165 | self.log.debug("Connection file not found: %s", self.connection_file) |
|
165 | self.log.debug("Connection file not found: %s", self.connection_file) | |
166 | return |
|
166 | return | |
167 | self.log.debug(u"Loading connection file %s", fname) |
|
167 | self.log.debug(u"Loading connection file %s", fname) | |
168 | with open(fname) as f: |
|
168 | with open(fname) as f: | |
169 | s = f.read() |
|
169 | s = f.read() | |
170 | cfg = json.loads(s) |
|
170 | cfg = json.loads(s) | |
171 | if self.ip == LOCALHOST and 'ip' in cfg: |
|
171 | if self.ip == LOCALHOST and 'ip' in cfg: | |
172 | # not overridden by config or cl_args |
|
172 | # not overridden by config or cl_args | |
173 | self.ip = cfg['ip'] |
|
173 | self.ip = cfg['ip'] | |
174 | for channel in ('hb', 'shell', 'iopub', 'stdin'): |
|
174 | for channel in ('hb', 'shell', 'iopub', 'stdin'): | |
175 | name = channel + '_port' |
|
175 | name = channel + '_port' | |
176 | if getattr(self, name) == 0 and name in cfg: |
|
176 | if getattr(self, name) == 0 and name in cfg: | |
177 | # not overridden by config or cl_args |
|
177 | # not overridden by config or cl_args | |
178 | setattr(self, name, cfg[name]) |
|
178 | setattr(self, name, cfg[name]) | |
179 | if 'key' in cfg: |
|
179 | if 'key' in cfg: | |
180 | self.config.Session.key = str_to_bytes(cfg['key']) |
|
180 | self.config.Session.key = str_to_bytes(cfg['key']) | |
181 |
|
181 | |||
182 | def write_connection_file(self): |
|
182 | def write_connection_file(self): | |
183 | """write connection info to JSON file""" |
|
183 | """write connection info to JSON file""" | |
184 | if os.path.basename(self.connection_file) == self.connection_file: |
|
184 | if os.path.basename(self.connection_file) == self.connection_file: | |
185 | cf = os.path.join(self.profile_dir.security_dir, self.connection_file) |
|
185 | cf = os.path.join(self.profile_dir.security_dir, self.connection_file) | |
186 | else: |
|
186 | else: | |
187 | cf = self.connection_file |
|
187 | cf = self.connection_file | |
188 | write_connection_file(cf, ip=self.ip, key=self.session.key, |
|
188 | write_connection_file(cf, ip=self.ip, key=self.session.key, | |
189 | shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port, |
|
189 | shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port, | |
190 | iopub_port=self.iopub_port) |
|
190 | iopub_port=self.iopub_port) | |
191 |
|
191 | |||
192 | def init_connection_file(self): |
|
192 | def init_connection_file(self): | |
193 | if not self.connection_file: |
|
193 | if not self.connection_file: | |
194 | self.connection_file = "kernel-%s.json"%os.getpid() |
|
194 | self.connection_file = "kernel-%s.json"%os.getpid() | |
195 | try: |
|
195 | try: | |
196 | self.load_connection_file() |
|
196 | self.load_connection_file() | |
197 | except Exception: |
|
197 | except Exception: | |
198 | self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True) |
|
198 | self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True) | |
199 | self.exit(1) |
|
199 | self.exit(1) | |
200 |
|
200 | |||
201 | def init_sockets(self): |
|
201 | def init_sockets(self): | |
202 | # Create a context, a session, and the kernel sockets. |
|
202 | # Create a context, a session, and the kernel sockets. | |
203 | self.log.info("Starting the kernel at pid: %i", os.getpid()) |
|
203 | self.log.info("Starting the kernel at pid: %i", os.getpid()) | |
204 | context = zmq.Context.instance() |
|
204 | context = zmq.Context.instance() | |
205 | # Uncomment this to try closing the context. |
|
205 | # Uncomment this to try closing the context. | |
206 | # atexit.register(context.term) |
|
206 | # atexit.register(context.term) | |
207 |
|
207 | |||
208 | self.shell_socket = context.socket(zmq.ROUTER) |
|
208 | self.shell_socket = context.socket(zmq.ROUTER) | |
209 | self.shell_port = self._bind_socket(self.shell_socket, self.shell_port) |
|
209 | self.shell_port = self._bind_socket(self.shell_socket, self.shell_port) | |
210 | self.log.debug("shell ROUTER Channel on port: %i"%self.shell_port) |
|
210 | self.log.debug("shell ROUTER Channel on port: %i"%self.shell_port) | |
211 |
|
211 | |||
212 | self.iopub_socket = context.socket(zmq.PUB) |
|
212 | self.iopub_socket = context.socket(zmq.PUB) | |
213 | self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port) |
|
213 | self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port) | |
214 | self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port) |
|
214 | self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port) | |
215 |
|
215 | |||
216 | self.stdin_socket = context.socket(zmq.ROUTER) |
|
216 | self.stdin_socket = context.socket(zmq.ROUTER) | |
217 | self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port) |
|
217 | self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port) | |
218 | self.log.debug("stdin ROUTER Channel on port: %i"%self.stdin_port) |
|
218 | self.log.debug("stdin ROUTER Channel on port: %i"%self.stdin_port) | |
219 |
|
219 | |||
220 | self.heartbeat = Heartbeat(context, (self.ip, self.hb_port)) |
|
220 | self.heartbeat = Heartbeat(context, (self.ip, self.hb_port)) | |
221 | self.hb_port = self.heartbeat.port |
|
221 | self.hb_port = self.heartbeat.port | |
222 | self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port) |
|
222 | self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port) | |
223 |
|
223 | |||
224 | # Helper to make it easier to connect to an existing kernel. |
|
224 | # Helper to make it easier to connect to an existing kernel. | |
225 | # set log-level to critical, to make sure it is output |
|
225 | # set log-level to critical, to make sure it is output | |
226 | self.log.critical("To connect another client to this kernel, use:") |
|
226 | self.log.critical("To connect another client to this kernel, use:") | |
227 |
|
227 | |||
228 | basename = os.path.basename(self.connection_file) |
|
228 | basename = os.path.basename(self.connection_file) | |
229 | if basename == self.connection_file or \ |
|
229 | if basename == self.connection_file or \ | |
230 | os.path.dirname(self.connection_file) == self.profile_dir.security_dir: |
|
230 | os.path.dirname(self.connection_file) == self.profile_dir.security_dir: | |
231 | # use shortname |
|
231 | # use shortname | |
232 | tail = basename |
|
232 | tail = basename | |
233 | if self.profile != 'default': |
|
233 | if self.profile != 'default': | |
234 | tail += " --profile %s" % self.profile |
|
234 | tail += " --profile %s" % self.profile | |
235 | else: |
|
235 | else: | |
236 | tail = self.connection_file |
|
236 | tail = self.connection_file | |
237 | self.log.critical("--existing %s", tail) |
|
237 | self.log.critical("--existing %s", tail) | |
238 |
|
238 | |||
239 |
|
239 | |||
240 | self.ports = dict(shell=self.shell_port, iopub=self.iopub_port, |
|
240 | self.ports = dict(shell=self.shell_port, iopub=self.iopub_port, | |
241 | stdin=self.stdin_port, hb=self.hb_port) |
|
241 | stdin=self.stdin_port, hb=self.hb_port) | |
242 |
|
242 | |||
243 | def init_session(self): |
|
243 | def init_session(self): | |
244 | """create our session object""" |
|
244 | """create our session object""" | |
245 | default_secure(self.config) |
|
245 | default_secure(self.config) | |
246 | self.session = Session(config=self.config, username=u'kernel') |
|
246 | self.session = Session(config=self.config, username=u'kernel') | |
247 |
|
247 | |||
248 | def init_blackhole(self): |
|
248 | def init_blackhole(self): | |
249 | """redirects stdout/stderr to devnull if necessary""" |
|
249 | """redirects stdout/stderr to devnull if necessary""" | |
250 | if self.no_stdout or self.no_stderr: |
|
250 | if self.no_stdout or self.no_stderr: | |
251 | blackhole = file(os.devnull, 'w') |
|
251 | blackhole = file(os.devnull, 'w') | |
252 | if self.no_stdout: |
|
252 | if self.no_stdout: | |
253 | sys.stdout = sys.__stdout__ = blackhole |
|
253 | sys.stdout = sys.__stdout__ = blackhole | |
254 | if self.no_stderr: |
|
254 | if self.no_stderr: | |
255 | sys.stderr = sys.__stderr__ = blackhole |
|
255 | sys.stderr = sys.__stderr__ = blackhole | |
256 |
|
256 | |||
257 | def init_io(self): |
|
257 | def init_io(self): | |
258 | """Redirect input streams and set a display hook.""" |
|
258 | """Redirect input streams and set a display hook.""" | |
259 | if self.outstream_class: |
|
259 | if self.outstream_class: | |
260 | outstream_factory = import_item(str(self.outstream_class)) |
|
260 | outstream_factory = import_item(str(self.outstream_class)) | |
261 | sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout') |
|
261 | sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout') | |
262 | sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr') |
|
262 | sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr') | |
263 | if self.displayhook_class: |
|
263 | if self.displayhook_class: | |
264 | displayhook_factory = import_item(str(self.displayhook_class)) |
|
264 | displayhook_factory = import_item(str(self.displayhook_class)) | |
265 | sys.displayhook = displayhook_factory(self.session, self.iopub_socket) |
|
265 | sys.displayhook = displayhook_factory(self.session, self.iopub_socket) | |
266 |
|
266 | |||
267 | def init_kernel(self): |
|
267 | def init_kernel(self): | |
268 | """Create the Kernel object itself""" |
|
268 | """Create the Kernel object itself""" | |
269 | kernel_factory = import_item(str(self.kernel_class)) |
|
269 | kernel_factory = import_item(str(self.kernel_class)) | |
270 | self.kernel = kernel_factory(config=self.config, session=self.session, |
|
270 | self.kernel = kernel_factory(config=self.config, session=self.session, | |
271 | shell_socket=self.shell_socket, |
|
271 | shell_socket=self.shell_socket, | |
272 | iopub_socket=self.iopub_socket, |
|
272 | iopub_socket=self.iopub_socket, | |
273 | stdin_socket=self.stdin_socket, |
|
273 | stdin_socket=self.stdin_socket, | |
274 | log=self.log |
|
274 | log=self.log | |
275 | ) |
|
275 | ) | |
276 | self.kernel.record_ports(self.ports) |
|
276 | self.kernel.record_ports(self.ports) | |
277 |
|
277 | |||
278 | @catch_config_error |
|
278 | @catch_config_error | |
279 | def initialize(self, argv=None): |
|
279 | def initialize(self, argv=None): | |
280 | super(KernelApp, self).initialize(argv) |
|
280 | super(KernelApp, self).initialize(argv) | |
281 | self.init_blackhole() |
|
281 | self.init_blackhole() | |
282 | self.init_connection_file() |
|
282 | self.init_connection_file() | |
283 | self.init_session() |
|
283 | self.init_session() | |
284 | self.init_poller() |
|
284 | self.init_poller() | |
285 | self.init_sockets() |
|
285 | self.init_sockets() | |
286 | # writing connection file must be *after* init_sockets |
|
286 | # writing connection file must be *after* init_sockets | |
287 | self.write_connection_file() |
|
287 | self.write_connection_file() | |
288 | self.init_io() |
|
288 | self.init_io() | |
289 | self.init_kernel() |
|
289 | self.init_kernel() | |
|
290 | # flush stdout/stderr, so that anything written to these streams during | |||
|
291 | # initialization do not get associated with the first execution request | |||
|
292 | sys.stdout.flush() | |||
|
293 | sys.stderr.flush() | |||
290 |
|
294 | |||
291 | def start(self): |
|
295 | def start(self): | |
292 | self.heartbeat.start() |
|
296 | self.heartbeat.start() | |
293 | if self.poller is not None: |
|
297 | if self.poller is not None: | |
294 | self.poller.start() |
|
298 | self.poller.start() | |
295 | try: |
|
299 | try: | |
296 | self.kernel.start() |
|
300 | self.kernel.start() | |
297 | except KeyboardInterrupt: |
|
301 | except KeyboardInterrupt: | |
298 | pass |
|
302 | pass | |
299 |
|
303 |
General Comments 0
You need to be logged in to leave comments.
Login now