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