Show More
@@ -1,48 +1,49 b'' | |||
|
1 | 1 | """Serve files directly from the ContentsManager.""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import os |
|
7 | 7 | import mimetypes |
|
8 | 8 | import json |
|
9 | 9 | import base64 |
|
10 | 10 | |
|
11 | 11 | from tornado import web |
|
12 | 12 | |
|
13 | 13 | from IPython.html.base.handlers import IPythonHandler |
|
14 | 14 | |
|
15 | 15 | class FilesHandler(IPythonHandler): |
|
16 | 16 | """serve files via ContentsManager""" |
|
17 | 17 | |
|
18 | 18 | @web.authenticated |
|
19 | 19 | def get(self, path): |
|
20 | 20 | cm = self.settings['contents_manager'] |
|
21 | 21 | if cm.is_hidden(path): |
|
22 | 22 | self.log.info("Refusing to serve hidden file, via 404 Error") |
|
23 | 23 | raise web.HTTPError(404) |
|
24 | 24 | |
|
25 | 25 | path, name = os.path.split(path) |
|
26 | 26 | model = cm.get_model(name, path) |
|
27 | ||
|
27 | ||
|
28 | if self.get_argument("download", False): | |
|
29 | self.set_header('Content-Disposition','attachment; filename="%s"' % name) | |
|
30 | ||
|
28 | 31 | if model['type'] == 'notebook': |
|
29 | 32 | self.set_header('Content-Type', 'application/json') |
|
30 | 33 | else: |
|
31 | 34 | cur_mime = mimetypes.guess_type(name)[0] |
|
32 | 35 | if cur_mime is not None: |
|
33 | 36 | self.set_header('Content-Type', cur_mime) |
|
34 | 37 | |
|
35 | self.set_header('Content-Disposition','attachment; filename="%s"' % name) | |
|
36 | ||
|
37 | 38 | if model['format'] == 'base64': |
|
38 | 39 | b64_bytes = model['content'].encode('ascii') |
|
39 | 40 | self.write(base64.decodestring(b64_bytes)) |
|
40 | 41 | elif model['format'] == 'json': |
|
41 | 42 | self.write(json.dumps(model['content'])) |
|
42 | 43 | else: |
|
43 | 44 | self.write(model['content']) |
|
44 | 45 | self.flush() |
|
45 | 46 | |
|
46 | 47 | default_handlers = [ |
|
47 | 48 | (r"/files/(.*)", FilesHandler), |
|
48 | 49 | ] No newline at end of file |
@@ -1,353 +1,353 b'' | |||
|
1 | 1 | // Copyright (c) IPython Development Team. |
|
2 | 2 | // Distributed under the terms of the Modified BSD License. |
|
3 | 3 | |
|
4 | 4 | define([ |
|
5 | 5 | 'base/js/namespace', |
|
6 | 6 | 'jquery', |
|
7 | 7 | 'base/js/utils', |
|
8 | 8 | 'notebook/js/tour', |
|
9 | 9 | 'bootstrap', |
|
10 | 10 | 'moment', |
|
11 | 11 | ], function(IPython, $, utils, tour, bootstrap, moment) { |
|
12 | 12 | "use strict"; |
|
13 | 13 | |
|
14 | 14 | var MenuBar = function (selector, options) { |
|
15 | 15 | // Constructor |
|
16 | 16 | // |
|
17 | 17 | // A MenuBar Class to generate the menubar of IPython notebook |
|
18 | 18 | // |
|
19 | 19 | // Parameters: |
|
20 | 20 | // selector: string |
|
21 | 21 | // options: dictionary |
|
22 | 22 | // Dictionary of keyword arguments. |
|
23 | 23 | // notebook: Notebook instance |
|
24 | 24 | // layout_manager: LayoutManager instance |
|
25 | 25 | // events: $(Events) instance |
|
26 | 26 | // save_widget: SaveWidget instance |
|
27 | 27 | // quick_help: QuickHelp instance |
|
28 | 28 | // base_url : string |
|
29 | 29 | // notebook_path : string |
|
30 | 30 | // notebook_name : string |
|
31 | 31 | options = options || {}; |
|
32 | 32 | this.base_url = options.base_url || utils.get_body_data("baseUrl"); |
|
33 | 33 | this.selector = selector; |
|
34 | 34 | this.notebook = options.notebook; |
|
35 | 35 | this.layout_manager = options.layout_manager; |
|
36 | 36 | this.events = options.events; |
|
37 | 37 | this.save_widget = options.save_widget; |
|
38 | 38 | this.quick_help = options.quick_help; |
|
39 | 39 | |
|
40 | 40 | try { |
|
41 | 41 | this.tour = new tour.Tour(this.notebook, this.events); |
|
42 | 42 | } catch (e) { |
|
43 | 43 | this.tour = undefined; |
|
44 | 44 | console.log("Failed to instantiate Notebook Tour", e); |
|
45 | 45 | } |
|
46 | 46 | |
|
47 | 47 | if (this.selector !== undefined) { |
|
48 | 48 | this.element = $(selector); |
|
49 | 49 | this.style(); |
|
50 | 50 | this.bind_events(); |
|
51 | 51 | } |
|
52 | 52 | }; |
|
53 | 53 | |
|
54 | 54 | // TODO: This has definitively nothing to do with style ... |
|
55 | 55 | MenuBar.prototype.style = function () { |
|
56 | 56 | var that = this; |
|
57 | 57 | this.element.find("li").click(function (event, ui) { |
|
58 | 58 | // The selected cell loses focus when the menu is entered, so we |
|
59 | 59 | // re-select it upon selection. |
|
60 | 60 | var i = that.notebook.get_selected_index(); |
|
61 | 61 | that.notebook.select(i); |
|
62 | 62 | } |
|
63 | 63 | ); |
|
64 | 64 | }; |
|
65 | 65 | |
|
66 | 66 | MenuBar.prototype._nbconvert = function (format, download) { |
|
67 | 67 | download = download || false; |
|
68 | 68 | var notebook_path = this.notebook.notebook_path; |
|
69 | 69 | var notebook_name = this.notebook.notebook_name; |
|
70 | 70 | if (this.notebook.dirty) { |
|
71 | 71 | this.notebook.save_notebook({async : false}); |
|
72 | 72 | } |
|
73 | 73 | var url = utils.url_join_encode( |
|
74 | 74 | this.base_url, |
|
75 | 75 | 'nbconvert', |
|
76 | 76 | format, |
|
77 | 77 | notebook_path, |
|
78 | 78 | notebook_name |
|
79 | 79 | ) + "?download=" + download.toString(); |
|
80 | 80 | |
|
81 | 81 | window.open(url); |
|
82 | 82 | }; |
|
83 | 83 | |
|
84 | 84 | MenuBar.prototype.bind_events = function () { |
|
85 | 85 | // File |
|
86 | 86 | var that = this; |
|
87 | 87 | this.element.find('#new_notebook').click(function () { |
|
88 | 88 | that.notebook.new_notebook(); |
|
89 | 89 | }); |
|
90 | 90 | this.element.find('#open_notebook').click(function () { |
|
91 | 91 | window.open(utils.url_join_encode( |
|
92 | 92 | that.notebook.base_url, |
|
93 | 93 | 'tree', |
|
94 | 94 | that.notebook.notebook_path |
|
95 | 95 | )); |
|
96 | 96 | }); |
|
97 | 97 | this.element.find('#copy_notebook').click(function () { |
|
98 | 98 | that.notebook.copy_notebook(); |
|
99 | 99 | return false; |
|
100 | 100 | }); |
|
101 | 101 | this.element.find('#download_ipynb').click(function () { |
|
102 | 102 | var base_url = that.notebook.base_url; |
|
103 | 103 | var notebook_path = that.notebook.notebook_path; |
|
104 | 104 | var notebook_name = that.notebook.notebook_name; |
|
105 | 105 | if (that.notebook.dirty) { |
|
106 | 106 | that.notebook.save_notebook({async : false}); |
|
107 | 107 | } |
|
108 | 108 | |
|
109 | 109 | var url = utils.url_join_encode( |
|
110 | 110 | base_url, |
|
111 | 111 | 'files', |
|
112 | 112 | notebook_path, |
|
113 | 113 | notebook_name |
|
114 | 114 | ); |
|
115 | window.open(url); | |
|
115 | window.open(url + '?download=1'); | |
|
116 | 116 | }); |
|
117 | 117 | |
|
118 | 118 | this.element.find('#print_preview').click(function () { |
|
119 | 119 | that._nbconvert('html', false); |
|
120 | 120 | }); |
|
121 | 121 | |
|
122 | 122 | this.element.find('#download_py').click(function () { |
|
123 | 123 | that._nbconvert('python', true); |
|
124 | 124 | }); |
|
125 | 125 | |
|
126 | 126 | this.element.find('#download_html').click(function () { |
|
127 | 127 | that._nbconvert('html', true); |
|
128 | 128 | }); |
|
129 | 129 | |
|
130 | 130 | this.element.find('#download_rst').click(function () { |
|
131 | 131 | that._nbconvert('rst', true); |
|
132 | 132 | }); |
|
133 | 133 | |
|
134 | 134 | this.element.find('#download_pdf').click(function () { |
|
135 | 135 | that._nbconvert('pdf', true); |
|
136 | 136 | }); |
|
137 | 137 | |
|
138 | 138 | this.element.find('#rename_notebook').click(function () { |
|
139 | 139 | that.save_widget.rename_notebook({notebook: that.notebook}); |
|
140 | 140 | }); |
|
141 | 141 | this.element.find('#save_checkpoint').click(function () { |
|
142 | 142 | that.notebook.save_checkpoint(); |
|
143 | 143 | }); |
|
144 | 144 | this.element.find('#restore_checkpoint').click(function () { |
|
145 | 145 | }); |
|
146 | 146 | this.element.find('#trust_notebook').click(function () { |
|
147 | 147 | that.notebook.trust_notebook(); |
|
148 | 148 | }); |
|
149 | 149 | this.events.on('trust_changed.Notebook', function (event, trusted) { |
|
150 | 150 | if (trusted) { |
|
151 | 151 | that.element.find('#trust_notebook') |
|
152 | 152 | .addClass("disabled") |
|
153 | 153 | .find("a").text("Trusted Notebook"); |
|
154 | 154 | } else { |
|
155 | 155 | that.element.find('#trust_notebook') |
|
156 | 156 | .removeClass("disabled") |
|
157 | 157 | .find("a").text("Trust Notebook"); |
|
158 | 158 | } |
|
159 | 159 | }); |
|
160 | 160 | this.element.find('#kill_and_exit').click(function () { |
|
161 | 161 | var close_window = function () { |
|
162 | 162 | // allow closing of new tabs in Chromium, impossible in FF |
|
163 | 163 | window.open('', '_self', ''); |
|
164 | 164 | window.close(); |
|
165 | 165 | }; |
|
166 | 166 | // finish with close on success or failure |
|
167 | 167 | that.notebook.session.delete(close_window, close_window); |
|
168 | 168 | }); |
|
169 | 169 | // Edit |
|
170 | 170 | this.element.find('#cut_cell').click(function () { |
|
171 | 171 | that.notebook.cut_cell(); |
|
172 | 172 | }); |
|
173 | 173 | this.element.find('#copy_cell').click(function () { |
|
174 | 174 | that.notebook.copy_cell(); |
|
175 | 175 | }); |
|
176 | 176 | this.element.find('#delete_cell').click(function () { |
|
177 | 177 | that.notebook.delete_cell(); |
|
178 | 178 | }); |
|
179 | 179 | this.element.find('#undelete_cell').click(function () { |
|
180 | 180 | that.notebook.undelete_cell(); |
|
181 | 181 | }); |
|
182 | 182 | this.element.find('#split_cell').click(function () { |
|
183 | 183 | that.notebook.split_cell(); |
|
184 | 184 | }); |
|
185 | 185 | this.element.find('#merge_cell_above').click(function () { |
|
186 | 186 | that.notebook.merge_cell_above(); |
|
187 | 187 | }); |
|
188 | 188 | this.element.find('#merge_cell_below').click(function () { |
|
189 | 189 | that.notebook.merge_cell_below(); |
|
190 | 190 | }); |
|
191 | 191 | this.element.find('#move_cell_up').click(function () { |
|
192 | 192 | that.notebook.move_cell_up(); |
|
193 | 193 | }); |
|
194 | 194 | this.element.find('#move_cell_down').click(function () { |
|
195 | 195 | that.notebook.move_cell_down(); |
|
196 | 196 | }); |
|
197 | 197 | this.element.find('#edit_nb_metadata').click(function () { |
|
198 | 198 | that.notebook.edit_metadata({ |
|
199 | 199 | notebook: that.notebook, |
|
200 | 200 | keyboard_manager: that.notebook.keyboard_manager}); |
|
201 | 201 | }); |
|
202 | 202 | |
|
203 | 203 | // View |
|
204 | 204 | this.element.find('#toggle_header').click(function () { |
|
205 | 205 | $('div#header').toggle(); |
|
206 | 206 | that.layout_manager.do_resize(); |
|
207 | 207 | }); |
|
208 | 208 | this.element.find('#toggle_toolbar').click(function () { |
|
209 | 209 | $('div#maintoolbar').toggle(); |
|
210 | 210 | that.layout_manager.do_resize(); |
|
211 | 211 | }); |
|
212 | 212 | // Insert |
|
213 | 213 | this.element.find('#insert_cell_above').click(function () { |
|
214 | 214 | that.notebook.insert_cell_above('code'); |
|
215 | 215 | that.notebook.select_prev(); |
|
216 | 216 | }); |
|
217 | 217 | this.element.find('#insert_cell_below').click(function () { |
|
218 | 218 | that.notebook.insert_cell_below('code'); |
|
219 | 219 | that.notebook.select_next(); |
|
220 | 220 | }); |
|
221 | 221 | // Cell |
|
222 | 222 | this.element.find('#run_cell').click(function () { |
|
223 | 223 | that.notebook.execute_cell(); |
|
224 | 224 | }); |
|
225 | 225 | this.element.find('#run_cell_select_below').click(function () { |
|
226 | 226 | that.notebook.execute_cell_and_select_below(); |
|
227 | 227 | }); |
|
228 | 228 | this.element.find('#run_cell_insert_below').click(function () { |
|
229 | 229 | that.notebook.execute_cell_and_insert_below(); |
|
230 | 230 | }); |
|
231 | 231 | this.element.find('#run_all_cells').click(function () { |
|
232 | 232 | that.notebook.execute_all_cells(); |
|
233 | 233 | }); |
|
234 | 234 | this.element.find('#run_all_cells_above').click(function () { |
|
235 | 235 | that.notebook.execute_cells_above(); |
|
236 | 236 | }); |
|
237 | 237 | this.element.find('#run_all_cells_below').click(function () { |
|
238 | 238 | that.notebook.execute_cells_below(); |
|
239 | 239 | }); |
|
240 | 240 | this.element.find('#to_code').click(function () { |
|
241 | 241 | that.notebook.to_code(); |
|
242 | 242 | }); |
|
243 | 243 | this.element.find('#to_markdown').click(function () { |
|
244 | 244 | that.notebook.to_markdown(); |
|
245 | 245 | }); |
|
246 | 246 | this.element.find('#to_raw').click(function () { |
|
247 | 247 | that.notebook.to_raw(); |
|
248 | 248 | }); |
|
249 | 249 | this.element.find('#to_heading1').click(function () { |
|
250 | 250 | that.notebook.to_heading(undefined, 1); |
|
251 | 251 | }); |
|
252 | 252 | this.element.find('#to_heading2').click(function () { |
|
253 | 253 | that.notebook.to_heading(undefined, 2); |
|
254 | 254 | }); |
|
255 | 255 | this.element.find('#to_heading3').click(function () { |
|
256 | 256 | that.notebook.to_heading(undefined, 3); |
|
257 | 257 | }); |
|
258 | 258 | this.element.find('#to_heading4').click(function () { |
|
259 | 259 | that.notebook.to_heading(undefined, 4); |
|
260 | 260 | }); |
|
261 | 261 | this.element.find('#to_heading5').click(function () { |
|
262 | 262 | that.notebook.to_heading(undefined, 5); |
|
263 | 263 | }); |
|
264 | 264 | this.element.find('#to_heading6').click(function () { |
|
265 | 265 | that.notebook.to_heading(undefined, 6); |
|
266 | 266 | }); |
|
267 | 267 | |
|
268 | 268 | this.element.find('#toggle_current_output').click(function () { |
|
269 | 269 | that.notebook.toggle_output(); |
|
270 | 270 | }); |
|
271 | 271 | this.element.find('#toggle_current_output_scroll').click(function () { |
|
272 | 272 | that.notebook.toggle_output_scroll(); |
|
273 | 273 | }); |
|
274 | 274 | this.element.find('#clear_current_output').click(function () { |
|
275 | 275 | that.notebook.clear_output(); |
|
276 | 276 | }); |
|
277 | 277 | |
|
278 | 278 | this.element.find('#toggle_all_output').click(function () { |
|
279 | 279 | that.notebook.toggle_all_output(); |
|
280 | 280 | }); |
|
281 | 281 | this.element.find('#toggle_all_output_scroll').click(function () { |
|
282 | 282 | that.notebook.toggle_all_output_scroll(); |
|
283 | 283 | }); |
|
284 | 284 | this.element.find('#clear_all_output').click(function () { |
|
285 | 285 | that.notebook.clear_all_output(); |
|
286 | 286 | }); |
|
287 | 287 | |
|
288 | 288 | // Kernel |
|
289 | 289 | this.element.find('#int_kernel').click(function () { |
|
290 | 290 | that.notebook.kernel.interrupt(); |
|
291 | 291 | }); |
|
292 | 292 | this.element.find('#restart_kernel').click(function () { |
|
293 | 293 | that.notebook.restart_kernel(); |
|
294 | 294 | }); |
|
295 | 295 | // Help |
|
296 | 296 | if (this.tour) { |
|
297 | 297 | this.element.find('#notebook_tour').click(function () { |
|
298 | 298 | that.tour.start(); |
|
299 | 299 | }); |
|
300 | 300 | } else { |
|
301 | 301 | this.element.find('#notebook_tour').addClass("disabled"); |
|
302 | 302 | } |
|
303 | 303 | this.element.find('#keyboard_shortcuts').click(function () { |
|
304 | 304 | that.quick_help.show_keyboard_shortcuts(); |
|
305 | 305 | }); |
|
306 | 306 | |
|
307 | 307 | this.update_restore_checkpoint(null); |
|
308 | 308 | |
|
309 | 309 | this.events.on('checkpoints_listed.Notebook', function (event, data) { |
|
310 | 310 | that.update_restore_checkpoint(that.notebook.checkpoints); |
|
311 | 311 | }); |
|
312 | 312 | |
|
313 | 313 | this.events.on('checkpoint_created.Notebook', function (event, data) { |
|
314 | 314 | that.update_restore_checkpoint(that.notebook.checkpoints); |
|
315 | 315 | }); |
|
316 | 316 | }; |
|
317 | 317 | |
|
318 | 318 | MenuBar.prototype.update_restore_checkpoint = function(checkpoints) { |
|
319 | 319 | var ul = this.element.find("#restore_checkpoint").find("ul"); |
|
320 | 320 | ul.empty(); |
|
321 | 321 | if (!checkpoints || checkpoints.length === 0) { |
|
322 | 322 | ul.append( |
|
323 | 323 | $("<li/>") |
|
324 | 324 | .addClass("disabled") |
|
325 | 325 | .append( |
|
326 | 326 | $("<a/>") |
|
327 | 327 | .text("No checkpoints") |
|
328 | 328 | ) |
|
329 | 329 | ); |
|
330 | 330 | return; |
|
331 | 331 | } |
|
332 | 332 | |
|
333 | 333 | var that = this; |
|
334 | 334 | checkpoints.map(function (checkpoint) { |
|
335 | 335 | var d = new Date(checkpoint.last_modified); |
|
336 | 336 | ul.append( |
|
337 | 337 | $("<li/>").append( |
|
338 | 338 | $("<a/>") |
|
339 | 339 | .attr("href", "#") |
|
340 | 340 | .text(moment(d).format("LLLL")) |
|
341 | 341 | .click(function () { |
|
342 | 342 | that.notebook.restore_checkpoint_dialog(checkpoint); |
|
343 | 343 | }) |
|
344 | 344 | ) |
|
345 | 345 | ); |
|
346 | 346 | }); |
|
347 | 347 | }; |
|
348 | 348 | |
|
349 | 349 | // Backwards compatability. |
|
350 | 350 | IPython.MenuBar = MenuBar; |
|
351 | 351 | |
|
352 | 352 | return {'MenuBar': MenuBar}; |
|
353 | 353 | }); |
@@ -1,135 +1,151 b'' | |||
|
1 | 1 | # coding: utf-8 |
|
2 | 2 | """Test the /files/ handler.""" |
|
3 | 3 | |
|
4 | 4 | import io |
|
5 | 5 | import os |
|
6 | 6 | from unicodedata import normalize |
|
7 | 7 | |
|
8 | 8 | pjoin = os.path.join |
|
9 | 9 | |
|
10 | 10 | import requests |
|
11 | 11 | import json |
|
12 | 12 | |
|
13 | 13 | from IPython.nbformat.current import (new_notebook, write, new_worksheet, |
|
14 | 14 | new_heading_cell, new_code_cell, |
|
15 | 15 | new_output) |
|
16 | 16 | |
|
17 | 17 | from IPython.html.utils import url_path_join |
|
18 | 18 | from .launchnotebook import NotebookTestBase |
|
19 | 19 | from IPython.utils import py3compat |
|
20 | 20 | |
|
21 | 21 | |
|
22 | 22 | class FilesTest(NotebookTestBase): |
|
23 | 23 | def test_hidden_files(self): |
|
24 | 24 | not_hidden = [ |
|
25 | 25 | u'Γ₯ b', |
|
26 | 26 | u'Γ₯ b/Γ§. d', |
|
27 | 27 | ] |
|
28 | 28 | hidden = [ |
|
29 | 29 | u'.Γ₯ b', |
|
30 | 30 | u'Γ₯ b/.Γ§ d', |
|
31 | 31 | ] |
|
32 | 32 | dirs = not_hidden + hidden |
|
33 | 33 | |
|
34 | 34 | nbdir = self.notebook_dir.name |
|
35 | 35 | for d in dirs: |
|
36 | 36 | path = pjoin(nbdir, d.replace('/', os.sep)) |
|
37 | 37 | if not os.path.exists(path): |
|
38 | 38 | os.mkdir(path) |
|
39 | 39 | with open(pjoin(path, 'foo'), 'w') as f: |
|
40 | 40 | f.write('foo') |
|
41 | 41 | with open(pjoin(path, '.foo'), 'w') as f: |
|
42 | 42 | f.write('.foo') |
|
43 | 43 | url = self.base_url() |
|
44 | 44 | |
|
45 | 45 | for d in not_hidden: |
|
46 | 46 | path = pjoin(nbdir, d.replace('/', os.sep)) |
|
47 | 47 | r = requests.get(url_path_join(url, 'files', d, 'foo')) |
|
48 | 48 | r.raise_for_status() |
|
49 | 49 | self.assertEqual(r.text, 'foo') |
|
50 | 50 | r = requests.get(url_path_join(url, 'files', d, '.foo')) |
|
51 | 51 | self.assertEqual(r.status_code, 404) |
|
52 | 52 | |
|
53 | 53 | for d in hidden: |
|
54 | 54 | path = pjoin(nbdir, d.replace('/', os.sep)) |
|
55 | 55 | for foo in ('foo', '.foo'): |
|
56 | 56 | r = requests.get(url_path_join(url, 'files', d, foo)) |
|
57 | 57 | self.assertEqual(r.status_code, 404) |
|
58 | 58 | |
|
59 | 59 | def test_contents_manager(self): |
|
60 | 60 | "make sure ContentsManager returns right files (ipynb, bin, txt)." |
|
61 | 61 | |
|
62 | 62 | nbdir = self.notebook_dir.name |
|
63 | 63 | base = self.base_url() |
|
64 | 64 | |
|
65 | 65 | nb = new_notebook(name='testnb') |
|
66 | 66 | |
|
67 | 67 | ws = new_worksheet() |
|
68 | 68 | nb.worksheets = [ws] |
|
69 | 69 | ws.cells.append(new_heading_cell(u'Created by test Β³')) |
|
70 | 70 | cc1 = new_code_cell(input=u'print(2*6)') |
|
71 | 71 | cc1.outputs.append(new_output(output_text=u'12', output_type='stream')) |
|
72 | 72 | ws.cells.append(cc1) |
|
73 | 73 | |
|
74 | 74 | with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w', |
|
75 | 75 | encoding='utf-8') as f: |
|
76 | 76 | write(nb, f, format='ipynb') |
|
77 | 77 | |
|
78 | 78 | with io.open(pjoin(nbdir, 'test.bin'), 'wb') as f: |
|
79 | 79 | f.write(b'\xff' + os.urandom(5)) |
|
80 | 80 | f.close() |
|
81 | 81 | |
|
82 | 82 | with io.open(pjoin(nbdir, 'test.txt'), 'w') as f: |
|
83 | 83 | f.write(u'foobar') |
|
84 | 84 | f.close() |
|
85 | 85 | |
|
86 | 86 | r = requests.get(url_path_join(base, 'files', 'testnb.ipynb')) |
|
87 | 87 | self.assertEqual(r.status_code, 200) |
|
88 | 88 | self.assertIn('print(2*6)', r.text) |
|
89 | 89 | json.loads(r.text) |
|
90 | 90 | |
|
91 | 91 | r = requests.get(url_path_join(base, 'files', 'test.bin')) |
|
92 | 92 | self.assertEqual(r.status_code, 200) |
|
93 | 93 | self.assertEqual(r.headers['content-type'], 'application/octet-stream') |
|
94 | 94 | self.assertEqual(r.content[:1], b'\xff') |
|
95 | 95 | self.assertEqual(len(r.content), 6) |
|
96 | 96 | |
|
97 | 97 | r = requests.get(url_path_join(base, 'files', 'test.txt')) |
|
98 | 98 | self.assertEqual(r.status_code, 200) |
|
99 | 99 | self.assertEqual(r.headers['content-type'], 'text/plain') |
|
100 | 100 | self.assertEqual(r.text, 'foobar') |
|
101 | ||
|
102 | def test_download(self): | |
|
103 | nbdir = self.notebook_dir.name | |
|
104 | base = self.base_url() | |
|
105 | ||
|
106 | text = 'hello' | |
|
107 | with open(pjoin(nbdir, 'test.txt'), 'w') as f: | |
|
108 | f.write(text) | |
|
109 | ||
|
110 | r = requests.get(url_path_join(base, 'files', 'test.txt')) | |
|
111 | disposition = r.headers.get('Content-Disposition', '') | |
|
112 | self.assertNotIn('attachment', disposition) | |
|
101 | 113 | |
|
114 | r = requests.get(url_path_join(base, 'files', 'test.txt') + '?download=1') | |
|
115 | disposition = r.headers.get('Content-Disposition', '') | |
|
116 | self.assertIn('attachment', disposition) | |
|
117 | self.assertIn('filename="test.txt"', disposition) | |
|
102 | 118 | |
|
103 | 119 | def test_old_files_redirect(self): |
|
104 | 120 | """pre-2.0 'files/' prefixed links are properly redirected""" |
|
105 | 121 | nbdir = self.notebook_dir.name |
|
106 | 122 | base = self.base_url() |
|
107 | 123 | |
|
108 | 124 | os.mkdir(pjoin(nbdir, 'files')) |
|
109 | 125 | os.makedirs(pjoin(nbdir, 'sub', 'files')) |
|
110 | 126 | |
|
111 | 127 | for prefix in ('', 'sub'): |
|
112 | 128 | with open(pjoin(nbdir, prefix, 'files', 'f1.txt'), 'w') as f: |
|
113 | 129 | f.write(prefix + '/files/f1') |
|
114 | 130 | with open(pjoin(nbdir, prefix, 'files', 'f2.txt'), 'w') as f: |
|
115 | 131 | f.write(prefix + '/files/f2') |
|
116 | 132 | with open(pjoin(nbdir, prefix, 'f2.txt'), 'w') as f: |
|
117 | 133 | f.write(prefix + '/f2') |
|
118 | 134 | with open(pjoin(nbdir, prefix, 'f3.txt'), 'w') as f: |
|
119 | 135 | f.write(prefix + '/f3') |
|
120 | 136 | |
|
121 | 137 | url = url_path_join(base, 'notebooks', prefix, 'files', 'f1.txt') |
|
122 | 138 | r = requests.get(url) |
|
123 | 139 | self.assertEqual(r.status_code, 200) |
|
124 | 140 | self.assertEqual(r.text, prefix + '/files/f1') |
|
125 | 141 | |
|
126 | 142 | url = url_path_join(base, 'notebooks', prefix, 'files', 'f2.txt') |
|
127 | 143 | r = requests.get(url) |
|
128 | 144 | self.assertEqual(r.status_code, 200) |
|
129 | 145 | self.assertEqual(r.text, prefix + '/files/f2') |
|
130 | 146 | |
|
131 | 147 | url = url_path_join(base, 'notebooks', prefix, 'files', 'f3.txt') |
|
132 | 148 | r = requests.get(url) |
|
133 | 149 | self.assertEqual(r.status_code, 200) |
|
134 | 150 | self.assertEqual(r.text, prefix + '/f3') |
|
135 | 151 |
General Comments 0
You need to be logged in to leave comments.
Login now