Show More
@@ -114,6 +114,7 b' class NbconvertPostHandler(IPythonHandler):' | |||
|
114 | 114 | exporter = get_exporter(format, config=self.config) |
|
115 | 115 | |
|
116 | 116 | model = self.get_json_body() |
|
117 | name = model.get('name', 'notebook.ipynb') | |
|
117 | 118 | nbnode = to_notebook_json(model['content']) |
|
118 | 119 | |
|
119 | 120 | try: |
@@ -121,7 +122,7 b' class NbconvertPostHandler(IPythonHandler):' | |||
|
121 | 122 | except Exception as e: |
|
122 | 123 | raise web.HTTPError(500, "nbconvert failed: %s" % e) |
|
123 | 124 | |
|
124 |
if respond_zip(self, |
|
|
125 | if respond_zip(self, name, output, resources): | |
|
125 | 126 | return |
|
126 | 127 | |
|
127 | 128 | # MIME type |
@@ -10,7 +10,7 b' import requests' | |||
|
10 | 10 | |
|
11 | 11 | from IPython.html.utils import url_path_join |
|
12 | 12 | from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error |
|
13 |
from IPython.nbformat.current import (new_notebook, write, |
|
|
13 | from IPython.nbformat.current import (new_notebook, write, | |
|
14 | 14 | new_heading_cell, new_code_cell, |
|
15 | 15 | new_output) |
|
16 | 16 | |
@@ -43,7 +43,8 b' class NbconvertAPI(object):' | |||
|
43 | 43 | |
|
44 | 44 | png_green_pixel = base64.encodestring(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00' |
|
45 | 45 | b'\x00\x00\x01\x00\x00x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDAT' |
|
46 |
b'\x08\xd7c\x90\xfb\xcf\x00\x00\x02\\\x01\x1e.~d\x87\x00\x00\x00\x00IEND\xaeB`\x82' |
|
|
46 | b'\x08\xd7c\x90\xfb\xcf\x00\x00\x02\\\x01\x1e.~d\x87\x00\x00\x00\x00IEND\xaeB`\x82' | |
|
47 | ).decode('ascii') | |
|
47 | 48 | |
|
48 | 49 | class APITest(NotebookTestBase): |
|
49 | 50 | def setUp(self): |
@@ -52,19 +53,20 b' class APITest(NotebookTestBase):' | |||
|
52 | 53 | if not os.path.isdir(pjoin(nbdir, 'foo')): |
|
53 | 54 | os.mkdir(pjoin(nbdir, 'foo')) |
|
54 | 55 | |
|
55 |
nb = new_notebook( |
|
|
56 | nb = new_notebook() | |
|
56 | 57 | |
|
57 | ws = new_worksheet() | |
|
58 | nb.worksheets = [ws] | |
|
59 | ws.cells.append(new_heading_cell(u'Created by test ³')) | |
|
60 | cc1 = new_code_cell(input=u'print(2*6)') | |
|
61 | cc1.outputs.append(new_output(output_text=u'12', output_type='stream')) | |
|
62 | cc1.outputs.append(new_output(output_png=png_green_pixel, output_type='pyout')) | |
|
63 | ws.cells.append(cc1) | |
|
58 | nb.cells.append(new_heading_cell(u'Created by test ³')) | |
|
59 | cc1 = new_code_cell(source=u'print(2*6)') | |
|
60 | cc1.outputs.append(new_output(output_type="stream", data=u'12')) | |
|
61 | cc1.outputs.append(new_output(output_type="execute_result", | |
|
62 | mime_bundle={'image/png' : png_green_pixel}, | |
|
63 | prompt_number=1, | |
|
64 | )) | |
|
65 | nb.cells.append(cc1) | |
|
64 | 66 | |
|
65 | 67 | with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w', |
|
66 | 68 | encoding='utf-8') as f: |
|
67 |
write(nb, f |
|
|
69 | write(nb, f) | |
|
68 | 70 | |
|
69 | 71 | self.nbconvert_api = NbconvertAPI(self.base_url()) |
|
70 | 72 |
@@ -234,8 +234,7 b' class ContentsManager(LoggingConfigurable):' | |||
|
234 | 234 | model = {} |
|
235 | 235 | if 'content' not in model and model.get('type', None) != 'directory': |
|
236 | 236 | if ext == '.ipynb': |
|
237 |
m |
|
|
238 | model['content'] = current.new_notebook(metadata=metadata) | |
|
237 | model['content'] = current.new_notebook() | |
|
239 | 238 | model['type'] = 'notebook' |
|
240 | 239 | model['format'] = 'json' |
|
241 | 240 | else: |
@@ -15,7 +15,7 b' import requests' | |||
|
15 | 15 | from IPython.html.utils import url_path_join, url_escape |
|
16 | 16 | from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error |
|
17 | 17 | from IPython.nbformat import current |
|
18 |
from IPython.nbformat.current import (new_notebook, write, read, |
|
|
18 | from IPython.nbformat.current import (new_notebook, write, read, | |
|
19 | 19 | new_heading_cell, to_notebook_json) |
|
20 | 20 | from IPython.nbformat import v2 |
|
21 | 21 | from IPython.utils import py3compat |
@@ -142,7 +142,7 b' class APITest(NotebookTestBase):' | |||
|
142 | 142 | # create a notebook |
|
143 | 143 | with io.open(pjoin(nbdir, d, '%s.ipynb' % name), 'w', |
|
144 | 144 | encoding='utf-8') as f: |
|
145 |
nb = new_notebook( |
|
|
145 | nb = new_notebook() | |
|
146 | 146 | write(nb, f, format='ipynb') |
|
147 | 147 | |
|
148 | 148 | # create a text file |
@@ -286,14 +286,14 b' class APITest(NotebookTestBase):' | |||
|
286 | 286 | self.assertEqual(model['content'], '') |
|
287 | 287 | |
|
288 | 288 | def test_upload_untitled(self): |
|
289 |
nb = new_notebook( |
|
|
289 | nb = new_notebook() | |
|
290 | 290 | nbmodel = {'content': nb, 'type': 'notebook'} |
|
291 | 291 | resp = self.api.upload_untitled(path=u'å b', |
|
292 | 292 | body=json.dumps(nbmodel)) |
|
293 | 293 | self._check_created(resp, 'Untitled0.ipynb', u'å b') |
|
294 | 294 | |
|
295 | 295 | def test_upload(self): |
|
296 |
nb = new_notebook( |
|
|
296 | nb = new_notebook() | |
|
297 | 297 | nbmodel = {'content': nb, 'type': 'notebook'} |
|
298 | 298 | resp = self.api.upload(u'Upload tést.ipynb', path=u'å b', |
|
299 | 299 | body=json.dumps(nbmodel)) |
@@ -355,7 +355,6 b' class APITest(NotebookTestBase):' | |||
|
355 | 355 | resp = self.api.read(u'Upload tést.ipynb', u'å b') |
|
356 | 356 | data = resp.json() |
|
357 | 357 | self.assertEqual(data['content']['nbformat'], current.nbformat) |
|
358 | self.assertEqual(data['content']['orig_nbformat'], 2) | |
|
359 | 358 | |
|
360 | 359 | def test_copy_untitled(self): |
|
361 | 360 | resp = self.api.copy_untitled(u'ç d.ipynb', path=u'å b') |
@@ -416,9 +415,7 b' class APITest(NotebookTestBase):' | |||
|
416 | 415 | resp = self.api.read('a.ipynb', 'foo') |
|
417 | 416 | nbcontent = json.loads(resp.text)['content'] |
|
418 | 417 | nb = to_notebook_json(nbcontent) |
|
419 | ws = new_worksheet() | |
|
420 | nb.worksheets = [ws] | |
|
421 | ws.cells.append(new_heading_cell(u'Created by test ³')) | |
|
418 | nb.cells.append(new_heading_cell(u'Created by test ³')) | |
|
422 | 419 | |
|
423 | 420 | nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb, 'type': 'notebook'} |
|
424 | 421 | resp = self.api.save('a.ipynb', path='foo', body=json.dumps(nbmodel)) |
@@ -426,11 +423,11 b' class APITest(NotebookTestBase):' | |||
|
426 | 423 | nbfile = pjoin(self.notebook_dir.name, 'foo', 'a.ipynb') |
|
427 | 424 | with io.open(nbfile, 'r', encoding='utf-8') as f: |
|
428 | 425 | newnb = read(f, format='ipynb') |
|
429 |
self.assertEqual(newnb |
|
|
426 | self.assertEqual(newnb.cells[0].source, | |
|
430 | 427 | u'Created by test ³') |
|
431 | 428 | nbcontent = self.api.read('a.ipynb', 'foo').json()['content'] |
|
432 | 429 | newnb = to_notebook_json(nbcontent) |
|
433 |
self.assertEqual(newnb |
|
|
430 | self.assertEqual(newnb.cells[0].source, | |
|
434 | 431 | u'Created by test ³') |
|
435 | 432 | |
|
436 | 433 | # Save and rename |
@@ -455,10 +452,8 b' class APITest(NotebookTestBase):' | |||
|
455 | 452 | # Modify it |
|
456 | 453 | nbcontent = json.loads(resp.text)['content'] |
|
457 | 454 | nb = to_notebook_json(nbcontent) |
|
458 | ws = new_worksheet() | |
|
459 | nb.worksheets = [ws] | |
|
460 | 455 | hcell = new_heading_cell('Created by test') |
|
461 |
|
|
|
456 | nb.cells.append(hcell) | |
|
462 | 457 | # Save |
|
463 | 458 | nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb, 'type': 'notebook'} |
|
464 | 459 | resp = self.api.save('a.ipynb', path='foo', body=json.dumps(nbmodel)) |
@@ -469,14 +464,14 b' class APITest(NotebookTestBase):' | |||
|
469 | 464 | |
|
470 | 465 | nbcontent = self.api.read('a.ipynb', 'foo').json()['content'] |
|
471 | 466 | nb = to_notebook_json(nbcontent) |
|
472 |
self.assertEqual(nb |
|
|
467 | self.assertEqual(nb.cells[0].source, 'Created by test') | |
|
473 | 468 | |
|
474 | 469 | # Restore cp1 |
|
475 | 470 | r = self.api.restore_checkpoint('a.ipynb', 'foo', cp1['id']) |
|
476 | 471 | self.assertEqual(r.status_code, 204) |
|
477 | 472 | nbcontent = self.api.read('a.ipynb', 'foo').json()['content'] |
|
478 | 473 | nb = to_notebook_json(nbcontent) |
|
479 |
self.assertEqual(nb. |
|
|
474 | self.assertEqual(nb.cells, []) | |
|
480 | 475 | |
|
481 | 476 | # Delete cp1 |
|
482 | 477 | r = self.api.delete_checkpoint('a.ipynb', 'foo', cp1['id']) |
@@ -95,11 +95,9 b' class TestContentsManager(TestCase):' | |||
|
95 | 95 | return os_path |
|
96 | 96 | |
|
97 | 97 | def add_code_cell(self, nb): |
|
98 |
output = current.new_output("display_data", |
|
|
98 | output = current.new_output("display_data", {'application/javascript': "alert('hi');"}) | |
|
99 | 99 | cell = current.new_code_cell("print('hi')", outputs=[output]) |
|
100 | if not nb.worksheets: | |
|
101 | nb.worksheets.append(current.new_worksheet()) | |
|
102 | nb.worksheets[0].cells.append(cell) | |
|
100 | nb.cells.append(cell) | |
|
103 | 101 | |
|
104 | 102 | def new_notebook(self): |
|
105 | 103 | cm = self.contents_manager |
@@ -309,13 +307,13 b' class TestContentsManager(TestCase):' | |||
|
309 | 307 | nb, name, path = self.new_notebook() |
|
310 | 308 | |
|
311 | 309 | cm.mark_trusted_cells(nb, name, path) |
|
312 |
for cell in nb. |
|
|
310 | for cell in nb.cells: | |
|
313 | 311 | if cell.cell_type == 'code': |
|
314 | 312 | assert not cell.metadata.trusted |
|
315 | 313 | |
|
316 | 314 | cm.trust_notebook(name, path) |
|
317 | 315 | nb = cm.get_model(name, path)['content'] |
|
318 |
for cell in nb. |
|
|
316 | for cell in nb.cells: | |
|
319 | 317 | if cell.cell_type == 'code': |
|
320 | 318 | assert cell.metadata.trusted |
|
321 | 319 |
@@ -62,7 +62,7 b' class SessionAPITest(NotebookTestBase):' | |||
|
62 | 62 | |
|
63 | 63 | with io.open(pjoin(nbdir, 'foo', 'nb1.ipynb'), 'w', |
|
64 | 64 | encoding='utf-8') as f: |
|
65 |
nb = new_notebook( |
|
|
65 | nb = new_notebook() | |
|
66 | 66 | write(nb, f, format='ipynb') |
|
67 | 67 | |
|
68 | 68 | self.sess_api = SessionAPI(self.base_url()) |
@@ -382,13 +382,11 b' define([' | |||
|
382 | 382 | |
|
383 | 383 | |
|
384 | 384 | CodeCell.prototype.collapse_output = function () { |
|
385 | this.collapsed = true; | |
|
386 | 385 | this.output_area.collapse(); |
|
387 | 386 | }; |
|
388 | 387 | |
|
389 | 388 | |
|
390 | 389 | CodeCell.prototype.expand_output = function () { |
|
391 | this.collapsed = false; | |
|
392 | 390 | this.output_area.expand(); |
|
393 | 391 | this.output_area.unscroll_area(); |
|
394 | 392 | }; |
@@ -399,7 +397,6 b' define([' | |||
|
399 | 397 | }; |
|
400 | 398 | |
|
401 | 399 | CodeCell.prototype.toggle_output = function () { |
|
402 | this.collapsed = Boolean(1 - this.collapsed); | |
|
403 | 400 | this.output_area.toggle_output(); |
|
404 | 401 | }; |
|
405 | 402 | |
@@ -467,22 +464,18 b' define([' | |||
|
467 | 464 | CodeCell.prototype.fromJSON = function (data) { |
|
468 | 465 | Cell.prototype.fromJSON.apply(this, arguments); |
|
469 | 466 | if (data.cell_type === 'code') { |
|
470 |
if (data. |
|
|
471 |
this.set_text(data. |
|
|
467 | if (data.source !== undefined) { | |
|
468 | this.set_text(data.source); | |
|
472 | 469 | // make this value the starting point, so that we can only undo |
|
473 | 470 | // to this state, instead of a blank cell |
|
474 | 471 | this.code_mirror.clearHistory(); |
|
475 | 472 | this.auto_highlight(); |
|
476 | 473 | } |
|
477 |
|
|
|
478 | this.set_input_prompt(data.prompt_number); | |
|
479 | } else { | |
|
480 | this.set_input_prompt(); | |
|
481 | } | |
|
474 | this.set_input_prompt(data.prompt_number); | |
|
482 | 475 | this.output_area.trusted = data.metadata.trusted || false; |
|
483 | 476 | this.output_area.fromJSON(data.outputs); |
|
484 | if (data.collapsed !== undefined) { | |
|
485 | if (data.collapsed) { | |
|
477 | if (data.metadata.collapsed !== undefined) { | |
|
478 | if (data.metadata.collapsed) { | |
|
486 | 479 | this.collapse_output(); |
|
487 | 480 | } else { |
|
488 | 481 | this.expand_output(); |
@@ -494,16 +487,17 b' define([' | |||
|
494 | 487 | |
|
495 | 488 | CodeCell.prototype.toJSON = function () { |
|
496 | 489 | var data = Cell.prototype.toJSON.apply(this); |
|
497 |
data. |
|
|
490 | data.source = this.get_text(); | |
|
498 | 491 | // is finite protect against undefined and '*' value |
|
499 | 492 | if (isFinite(this.input_prompt_number)) { |
|
500 | 493 | data.prompt_number = this.input_prompt_number; |
|
494 | } else { | |
|
495 | data.prompt_number = null; | |
|
501 | 496 | } |
|
502 | 497 | var outputs = this.output_area.toJSON(); |
|
503 | 498 | data.outputs = outputs; |
|
504 | data.language = 'python'; | |
|
505 | 499 | data.metadata.trusted = this.output_area.trusted; |
|
506 | data.collapsed = this.output_area.collapsed; | |
|
500 | data.metadata.collapsed = this.output_area.collapsed; | |
|
507 | 501 | return data; |
|
508 | 502 | }; |
|
509 | 503 |
@@ -121,10 +121,8 b' define([' | |||
|
121 | 121 | this.autosave_timer = null; |
|
122 | 122 | // autosave *at most* every two minutes |
|
123 | 123 | this.minimum_autosave_interval = 120000; |
|
124 | // single worksheet for now | |
|
125 | this.worksheet_metadata = {}; | |
|
126 | 124 | this.notebook_name_blacklist_re = /[\/\\:]/; |
|
127 |
this.nbformat = |
|
|
125 | this.nbformat = 4; // Increment this when changing the nbformat | |
|
128 | 126 | this.nbformat_minor = 0; // Increment this when changing the nbformat |
|
129 | 127 | this.codemirror_mode = 'ipython'; |
|
130 | 128 | this.create_elements(); |
@@ -1785,8 +1783,6 b' define([' | |||
|
1785 | 1783 | /** |
|
1786 | 1784 | * Load a notebook from JSON (.ipynb). |
|
1787 | 1785 | * |
|
1788 | * This currently handles one worksheet: others are deleted. | |
|
1789 | * | |
|
1790 | 1786 | * @method fromJSON |
|
1791 | 1787 | * @param {Object} data JSON representation of a notebook |
|
1792 | 1788 | */ |
@@ -1818,50 +1814,22 b' define([' | |||
|
1818 | 1814 | this.set_codemirror_mode(cm_mode); |
|
1819 | 1815 | } |
|
1820 | 1816 | |
|
1821 | // Only handle 1 worksheet for now. | |
|
1822 | var worksheet = content.worksheets[0]; | |
|
1823 | if (worksheet !== undefined) { | |
|
1824 | if (worksheet.metadata) { | |
|
1825 | this.worksheet_metadata = worksheet.metadata; | |
|
1826 | } | |
|
1827 | var new_cells = worksheet.cells; | |
|
1828 |
|
|
|
1829 | var cell_data = null; | |
|
1830 | var new_cell = null; | |
|
1831 | for (i=0; i<ncells; i++) { | |
|
1832 | cell_data = new_cells[i]; | |
|
1833 | // VERSIONHACK: plaintext -> raw | |
|
1834 | // handle never-released plaintext name for raw cells | |
|
1835 | if (cell_data.cell_type === 'plaintext'){ | |
|
1836 | cell_data.cell_type = 'raw'; | |
|
1837 | } | |
|
1838 | ||
|
1839 | new_cell = this.insert_cell_at_index(cell_data.cell_type, i); | |
|
1840 | new_cell.fromJSON(cell_data); | |
|
1841 | if (new_cell.cell_type == 'code' && !new_cell.output_area.trusted) { | |
|
1842 | trusted = false; | |
|
1843 | } | |
|
1817 | var new_cells = content.cells; | |
|
1818 | ncells = new_cells.length; | |
|
1819 | var cell_data = null; | |
|
1820 | var new_cell = null; | |
|
1821 | for (i=0; i<ncells; i++) { | |
|
1822 | cell_data = new_cells[i]; | |
|
1823 | new_cell = this.insert_cell_at_index(cell_data.cell_type, i); | |
|
1824 | new_cell.fromJSON(cell_data); | |
|
1825 | if (new_cell.cell_type == 'code' && !new_cell.output_area.trusted) { | |
|
1826 | trusted = false; | |
|
1844 | 1827 | } |
|
1845 | 1828 | } |
|
1846 | 1829 | if (trusted !== this.trusted) { |
|
1847 | 1830 | this.trusted = trusted; |
|
1848 | 1831 | this.events.trigger("trust_changed.Notebook", trusted); |
|
1849 | 1832 | } |
|
1850 | if (content.worksheets.length > 1) { | |
|
1851 | dialog.modal({ | |
|
1852 | notebook: this, | |
|
1853 | keyboard_manager: this.keyboard_manager, | |
|
1854 | title : "Multiple worksheets", | |
|
1855 | body : "This notebook has " + data.worksheets.length + " worksheets, " + | |
|
1856 | "but this version of IPython can only handle the first. " + | |
|
1857 | "If you save this notebook, worksheets after the first will be lost.", | |
|
1858 | buttons : { | |
|
1859 | OK : { | |
|
1860 | class : "btn-danger" | |
|
1861 | } | |
|
1862 | } | |
|
1863 | }); | |
|
1864 | } | |
|
1865 | 1833 | }; |
|
1866 | 1834 | |
|
1867 | 1835 | /** |
@@ -1871,6 +1839,10 b' define([' | |||
|
1871 | 1839 | * @return {Object} A JSON-friendly representation of this notebook. |
|
1872 | 1840 | */ |
|
1873 | 1841 | Notebook.prototype.toJSON = function () { |
|
1842 | // remove the conversion indicator, which only belongs in-memory | |
|
1843 | delete this.metadata.orig_nbformat; | |
|
1844 | delete this.metadata.orig_nbformat_minor; | |
|
1845 | ||
|
1874 | 1846 | var cells = this.get_cells(); |
|
1875 | 1847 | var ncells = cells.length; |
|
1876 | 1848 | var cell_array = new Array(ncells); |
@@ -1883,11 +1855,7 b' define([' | |||
|
1883 | 1855 | cell_array[i] = cell.toJSON(); |
|
1884 | 1856 | } |
|
1885 | 1857 | var data = { |
|
1886 | // Only handle 1 worksheet for now. | |
|
1887 | worksheets : [{ | |
|
1888 | cells: cell_array, | |
|
1889 | metadata: this.worksheet_metadata | |
|
1890 | }], | |
|
1858 | cells: cell_array, | |
|
1891 | 1859 | metadata : this.metadata |
|
1892 | 1860 | }; |
|
1893 | 1861 | if (trusted != this.trusted) { |
@@ -2337,10 +2305,13 b' define([' | |||
|
2337 | 2305 | } |
|
2338 | 2306 | this.set_dirty(false); |
|
2339 | 2307 | this.scroll_to_top(); |
|
2340 | if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) { | |
|
2308 | var nbmodel = data.content; | |
|
2309 | var orig_nbformat = nbmodel.metadata.orig_nbformat; | |
|
2310 | var orig_nbformat_minor = nbmodel.metadata.orig_nbformat_minor; | |
|
2311 | if (orig_nbformat !== undefined && nbmodel.nbformat !== orig_nbformat) { | |
|
2341 | 2312 | var msg = "This notebook has been converted from an older " + |
|
2342 |
"notebook format (v"+ |
|
|
2343 |
"format (v"+ |
|
|
2313 | "notebook format (v"+orig_nbformat+") to the current notebook " + | |
|
2314 | "format (v"+nbmodel.nbformat+"). The next time you save this notebook, the " + | |
|
2344 | 2315 | "newer notebook format will be used and older versions of IPython " + |
|
2345 | 2316 | "may not be able to read it. To keep the older version, close the " + |
|
2346 | 2317 | "notebook without saving it."; |
@@ -2355,10 +2326,10 b' define([' | |||
|
2355 | 2326 | } |
|
2356 | 2327 | } |
|
2357 | 2328 | }); |
|
2358 |
} else if ( |
|
|
2329 | } else if (orig_nbformat_minor !== undefined && nbmodel.nbformat_minor !== orig_nbformat_minor) { | |
|
2359 | 2330 | var that = this; |
|
2360 |
var orig_vs = 'v' + |
|
|
2361 |
var this_vs = 'v' + |
|
|
2331 | var orig_vs = 'v' + nbmodel.nbformat + '.' + orig_nbformat_minor; | |
|
2332 | var this_vs = 'v' + nbmodel.nbformat + '.' + this.nbformat_minor; | |
|
2362 | 2333 | var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " + |
|
2363 | 2334 | this_vs + ". You can still work with this notebook, but some features " + |
|
2364 | 2335 | "introduced in later notebook versions may not be available."; |
@@ -211,7 +211,7 b' define([' | |||
|
211 | 211 | var content = msg.content; |
|
212 | 212 | if (msg_type === "stream") { |
|
213 | 213 | json.text = content.text; |
|
214 |
json. |
|
|
214 | json.name = content.name; | |
|
215 | 215 | } else if (msg_type === "display_data") { |
|
216 | 216 | json = content.data; |
|
217 | 217 | json.output_type = msg_type; |
@@ -234,6 +234,7 b' define([' | |||
|
234 | 234 | |
|
235 | 235 | |
|
236 | 236 | OutputArea.prototype.rename_keys = function (data, key_map) { |
|
237 | // TODO: This is now unused, should it be removed? | |
|
237 | 238 | var remapped = {}; |
|
238 | 239 | for (var key in data) { |
|
239 | 240 | var new_key = key_map[key] || key; |
@@ -260,7 +261,10 b' define([' | |||
|
260 | 261 | // TODO: right now everything is a string, but JSON really shouldn't be. |
|
261 | 262 | // nbformat 4 will fix that. |
|
262 | 263 | $.map(OutputArea.output_types, function(key){ |
|
263 | if (json[key] !== undefined && typeof json[key] !== 'string') { | |
|
264 | if (key !== 'application/json' && | |
|
265 | json[key] !== undefined && | |
|
266 | typeof json[key] !== 'string' | |
|
267 | ) { | |
|
264 | 268 | console.log("Invalid type for " + key, json[key]); |
|
265 | 269 | delete json[key]; |
|
266 | 270 | } |
@@ -449,23 +453,18 b' define([' | |||
|
449 | 453 | |
|
450 | 454 | |
|
451 | 455 | OutputArea.prototype.append_stream = function (json) { |
|
452 | // temporary fix: if stream undefined (json file written prior to this patch), | |
|
453 | // default to most likely stdout: | |
|
454 | if (json.stream === undefined){ | |
|
455 | json.stream = 'stdout'; | |
|
456 | } | |
|
457 | var text = json.text; | |
|
458 | var subclass = "output_"+json.stream; | |
|
456 | var text = json.data; | |
|
457 | var subclass = "output_"+json.name; | |
|
459 | 458 | if (this.outputs.length > 0){ |
|
460 | 459 | // have at least one output to consider |
|
461 | 460 | var last = this.outputs[this.outputs.length-1]; |
|
462 |
if (last.output_type == 'stream' && json. |
|
|
461 | if (last.output_type == 'stream' && json.name == last.name){ | |
|
463 | 462 | // latest output was in the same stream, |
|
464 | 463 | // so append directly into its pre tag |
|
465 | 464 | // escape ANSI & HTML specials: |
|
466 |
last. |
|
|
465 | last.data = utils.fixCarriageReturn(last.data + json.data); | |
|
467 | 466 | var pre = this.element.find('div.'+subclass).last().find('pre'); |
|
468 |
var html = utils.fixConsole(last. |
|
|
467 | var html = utils.fixConsole(last.data); | |
|
469 | 468 | // The only user content injected with this HTML call is |
|
470 | 469 | // escaped by the fixConsole() method. |
|
471 | 470 | pre.html(html); |
@@ -852,70 +851,33 b' define([' | |||
|
852 | 851 | |
|
853 | 852 | // JSON serialization |
|
854 | 853 | |
|
855 | OutputArea.prototype.fromJSON = function (outputs) { | |
|
854 | OutputArea.prototype.fromJSON = function (outputs, metadata) { | |
|
856 | 855 | var len = outputs.length; |
|
857 | var data; | |
|
856 | metadata = metadata || {}; | |
|
858 | 857 | |
|
859 | 858 | for (var i=0; i<len; i++) { |
|
860 |
|
|
|
861 | var msg_type = data.output_type; | |
|
862 | if (msg_type == "pyout") { | |
|
863 | // pyout message has been renamed to execute_result, | |
|
864 | // but the nbformat has not been updated, | |
|
865 | // so transform back to pyout for json. | |
|
866 | msg_type = data.output_type = "execute_result"; | |
|
867 | } else if (msg_type == "pyerr") { | |
|
868 | // pyerr message has been renamed to error, | |
|
869 | // but the nbformat has not been updated, | |
|
870 | // so transform back to pyerr for json. | |
|
871 | msg_type = data.output_type = "error"; | |
|
859 | this.append_output(outputs[i]); | |
|
860 | } | |
|
861 | ||
|
862 | if (metadata.collapsed !== undefined) { | |
|
863 | this.collapsed = metadata.collapsed; | |
|
864 | if (metadata.collapsed) { | |
|
865 | this.collapse_output(); | |
|
872 | 866 | } |
|
873 | if (msg_type === "display_data" || msg_type === "execute_result") { | |
|
874 | // convert short keys to mime keys | |
|
875 | // TODO: remove mapping of short keys when we update to nbformat 4 | |
|
876 | data = this.rename_keys(data, OutputArea.mime_map_r); | |
|
877 | data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r); | |
|
878 | // msg spec JSON is an object, nbformat v3 JSON is a JSON string | |
|
879 | if (data["application/json"] !== undefined && typeof data["application/json"] === 'string') { | |
|
880 | data["application/json"] = JSON.parse(data["application/json"]); | |
|
881 | } | |
|
867 | } | |
|
868 | if (metadata.autoscroll !== undefined) { | |
|
869 | this.collapsed = metadata.collapsed; | |
|
870 | if (metadata.collapsed) { | |
|
871 | this.collapse_output(); | |
|
872 | } else { | |
|
873 | this.expand_output(); | |
|
882 | 874 | } |
|
883 | ||
|
884 | this.append_output(data); | |
|
885 | 875 | } |
|
886 | 876 | }; |
|
887 | 877 | |
|
888 | 878 | |
|
889 | 879 | OutputArea.prototype.toJSON = function () { |
|
890 |
|
|
|
891 | var len = this.outputs.length; | |
|
892 | var data; | |
|
893 | for (var i=0; i<len; i++) { | |
|
894 | data = this.outputs[i]; | |
|
895 | var msg_type = data.output_type; | |
|
896 | if (msg_type === "display_data" || msg_type === "execute_result") { | |
|
897 | // convert mime keys to short keys | |
|
898 | data = this.rename_keys(data, OutputArea.mime_map); | |
|
899 | data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map); | |
|
900 | // msg spec JSON is an object, nbformat v3 JSON is a JSON string | |
|
901 | if (data.json !== undefined && typeof data.json !== 'string') { | |
|
902 | data.json = JSON.stringify(data.json); | |
|
903 | } | |
|
904 | } | |
|
905 | if (msg_type == "execute_result") { | |
|
906 | // pyout message has been renamed to execute_result, | |
|
907 | // but the nbformat has not been updated, | |
|
908 | // so transform back to pyout for json. | |
|
909 | data.output_type = "pyout"; | |
|
910 | } else if (msg_type == "error") { | |
|
911 | // pyerr message has been renamed to error, | |
|
912 | // but the nbformat has not been updated, | |
|
913 | // so transform back to pyerr for json. | |
|
914 | data.output_type = "pyerr"; | |
|
915 | } | |
|
916 | outputs[i] = data; | |
|
917 | } | |
|
918 | return outputs; | |
|
880 | return this.outputs; | |
|
919 | 881 | }; |
|
920 | 882 | |
|
921 | 883 | /** |
@@ -948,29 +910,6 b' define([' | |||
|
948 | 910 | OutputArea.minimum_scroll_threshold = 20; |
|
949 | 911 | |
|
950 | 912 | |
|
951 | ||
|
952 | OutputArea.mime_map = { | |
|
953 | "text/plain" : "text", | |
|
954 | "text/html" : "html", | |
|
955 | "image/svg+xml" : "svg", | |
|
956 | "image/png" : "png", | |
|
957 | "image/jpeg" : "jpeg", | |
|
958 | "text/latex" : "latex", | |
|
959 | "application/json" : "json", | |
|
960 | "application/javascript" : "javascript", | |
|
961 | }; | |
|
962 | ||
|
963 | OutputArea.mime_map_r = { | |
|
964 | "text" : "text/plain", | |
|
965 | "html" : "text/html", | |
|
966 | "svg" : "image/svg+xml", | |
|
967 | "png" : "image/png", | |
|
968 | "jpeg" : "image/jpeg", | |
|
969 | "latex" : "text/latex", | |
|
970 | "json" : "application/json", | |
|
971 | "javascript" : "application/javascript", | |
|
972 | }; | |
|
973 | ||
|
974 | 913 | OutputArea.display_order = [ |
|
975 | 914 | 'application/javascript', |
|
976 | 915 | 'text/html', |
@@ -29,7 +29,7 b' casper.notebook_test(function () {' | |||
|
29 | 29 | var ex = expected[i]; |
|
30 | 30 | this.test.assertEquals(r.output_type, ex.output_type, "output " + i); |
|
31 | 31 | if (r.output_type === 'stream') { |
|
32 |
this.test.assertEquals(r. |
|
|
32 | this.test.assertEquals(r.name, ex.name, "stream " + i); | |
|
33 | 33 | this.test.assertEquals(r.text, ex.text, "content " + i); |
|
34 | 34 | } |
|
35 | 35 | } |
@@ -57,7 +57,7 b' casper.notebook_test(function () {' | |||
|
57 | 57 | "print(3)" |
|
58 | 58 | ].join("\n"), [{ |
|
59 | 59 | output_type: "stream", |
|
60 |
|
|
|
60 | name: "stdout", | |
|
61 | 61 | text: "1\n2\n3\n" |
|
62 | 62 | }] |
|
63 | 63 | ); |
@@ -69,11 +69,11 b' casper.notebook_test(function () {' | |||
|
69 | 69 | "print(3, file=sys.stderr)" |
|
70 | 70 | ].join("\n"), [{ |
|
71 | 71 | output_type: "stream", |
|
72 |
|
|
|
72 | name: "stdout", | |
|
73 | 73 | text: "1\n2\n" |
|
74 | 74 | },{ |
|
75 | 75 | output_type: "stream", |
|
76 |
|
|
|
76 | name: "stderr", | |
|
77 | 77 | text: "3\n" |
|
78 | 78 | }] |
|
79 | 79 | ); |
@@ -85,13 +85,13 b' casper.notebook_test(function () {' | |||
|
85 | 85 | "print(3)" |
|
86 | 86 | ].join("\n"), [{ |
|
87 | 87 | output_type: "stream", |
|
88 |
|
|
|
88 | name: "stdout", | |
|
89 | 89 | text: "1\n" |
|
90 | 90 | },{ |
|
91 | 91 | output_type: "display_data", |
|
92 | 92 | },{ |
|
93 | 93 | output_type: "stream", |
|
94 |
|
|
|
94 | name: "stdout", | |
|
95 | 95 | text: "3\n" |
|
96 | 96 | }] |
|
97 | 97 | ); |
@@ -14,7 +14,7 b' mime = {' | |||
|
14 | 14 | "json" : "application/json", |
|
15 | 15 | "javascript" : "application/javascript", |
|
16 | 16 | }; |
|
17 | ||
|
17 | ||
|
18 | 18 | var black_dot_jpeg="u\"\"\"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDACodICUgGiolIiUvLSoyP2lEPzo6P4FcYUxpmYagnpaG\nk5GovfLNqLPltZGT0v/V5fr/////o8v///////L/////2wBDAS0vLz83P3xERHz/rpOu////////\n////////////////////////////////////////////////////////////wgARCAABAAEDAREA\nAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAABP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEA\nAhADEAAAARn/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAA\nAAAAAAAA/9oACAEDAQE/AX//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AX//xAAUEAEA\nAAAAAAAAAAAAAAAAAAAA/9oACAEBAAY/An//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nIX//2gAMAwEAAgADAAAAEB//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/EH//xAAUEQEA\nAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/EH//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nEH//2Q==\"\"\""; |
|
19 | 19 | var black_dot_png = 'u\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QA\\niAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AA\\nAAACAAHiIbwzAAAAAElFTkSuQmCC\"'; |
|
20 | 20 | var svg = "\"<svg width='1cm' height='1cm' viewBox='0 0 1000 500'><defs><style>rect {fill:red;}; </style></defs><rect id='r1' x='200' y='100' width='600' height='300' /></svg>\""; |
@@ -24,8 +24,10 b' var svg = "\\"<svg width=\'1cm\' height=\'1cm\' viewBox=\'0 0 1000 500\'><defs><style>r' | |||
|
24 | 24 | // name, and that fromJSON also gets its long mimetype name |
|
25 | 25 | function assert_has(short_name, json, result, result2) { |
|
26 | 26 | long_name = mime[short_name]; |
|
27 |
this.test.assert |
|
|
28 |
|
|
|
27 | this.test.assertFalse(json[0].hasOwnProperty(short_name), | |
|
28 | "toJSON() representation doesn't use " + short_name); | |
|
29 | this.test.assertTrue(json[0].hasOwnProperty(long_name), | |
|
30 | 'toJSON() representation uses ' + long_name); | |
|
29 | 31 | this.test.assertTrue(result.hasOwnProperty(long_name), |
|
30 | 32 | 'toJSON() original embedded JSON keeps ' + long_name); |
|
31 | 33 | this.test.assertTrue(result2.hasOwnProperty(long_name), |
@@ -34,8 +36,8 b' function assert_has(short_name, json, result, result2) {' | |||
|
34 | 36 | |
|
35 | 37 | // helper function for checkout that the first two cells have a particular |
|
36 | 38 | // output_type (either 'execute_result' or 'display_data'), and checks the to/fromJSON |
|
37 |
// for a set of mimetype keys, |
|
|
38 | // 'png', etc). | |
|
39 | // for a set of mimetype keys, ensuring the old short names ('javascript', 'text', | |
|
40 | // 'png', etc) are not used. | |
|
39 | 41 | function check_output_area(output_type, keys) { |
|
40 | 42 | this.wait_for_output(0); |
|
41 | 43 | json = this.evaluate(function() { |
@@ -10,8 +10,8 b' pjoin = os.path.join' | |||
|
10 | 10 | import requests |
|
11 | 11 | import json |
|
12 | 12 | |
|
13 |
from IPython.nbformat.current import (new_notebook, write, |
|
|
14 |
new_ |
|
|
13 | from IPython.nbformat.current import (new_notebook, write, | |
|
14 | new_markdown_cell, new_code_cell, | |
|
15 | 15 | new_output) |
|
16 | 16 | |
|
17 | 17 | from IPython.html.utils import url_path_join |
@@ -62,18 +62,18 b' class FilesTest(NotebookTestBase):' | |||
|
62 | 62 | nbdir = self.notebook_dir.name |
|
63 | 63 | base = self.base_url() |
|
64 | 64 | |
|
65 |
nb = new_notebook( |
|
|
66 | ||
|
67 | ws = new_worksheet() | |
|
68 | nb.worksheets = [ws] | |
|
69 | ws.cells.append(new_heading_cell(u'Created by test ³')) | |
|
70 | cc1 = new_code_cell(input=u'print(2*6)') | |
|
71 | cc1.outputs.append(new_output(output_text=u'12', output_type='stream')) | |
|
72 | ws.cells.append(cc1) | |
|
65 | nb = new_notebook( | |
|
66 | cells=[ | |
|
67 | new_markdown_cell(u'Created by test ³'), | |
|
68 | new_code_cell("print(2*6)", outputs=[ | |
|
69 | new_output("stream", text="12"), | |
|
70 | ]) | |
|
71 | ] | |
|
72 | ) | |
|
73 | 73 | |
|
74 | 74 | with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w', |
|
75 | 75 | encoding='utf-8') as f: |
|
76 |
write(nb, f |
|
|
76 | write(nb, f) | |
|
77 | 77 | |
|
78 | 78 | with io.open(pjoin(nbdir, 'test.bin'), 'wb') as f: |
|
79 | 79 | f.write(b'\xff' + os.urandom(5)) |
General Comments 0
You need to be logged in to leave comments.
Login now