Show More
@@ -1,131 +1,131 | |||||
1 | # coding: utf-8 |
|
1 | # coding: utf-8 | |
2 | import base64 |
|
2 | import base64 | |
3 | import io |
|
3 | import io | |
4 | import json |
|
4 | import json | |
5 | import os |
|
5 | import os | |
6 | from os.path import join as pjoin |
|
6 | from os.path import join as pjoin | |
7 | import shutil |
|
7 | import shutil | |
8 |
|
8 | |||
9 | import requests |
|
9 | 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, |
|
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 | |||
17 | from IPython.testing.decorators import onlyif_cmds_exist |
|
17 | from IPython.testing.decorators import onlyif_cmds_exist | |
18 |
|
18 | |||
19 |
|
19 | |||
20 | class NbconvertAPI(object): |
|
20 | class NbconvertAPI(object): | |
21 | """Wrapper for nbconvert API calls.""" |
|
21 | """Wrapper for nbconvert API calls.""" | |
22 | def __init__(self, base_url): |
|
22 | def __init__(self, base_url): | |
23 | self.base_url = base_url |
|
23 | self.base_url = base_url | |
24 |
|
24 | |||
25 | def _req(self, verb, path, body=None, params=None): |
|
25 | def _req(self, verb, path, body=None, params=None): | |
26 | response = requests.request(verb, |
|
26 | response = requests.request(verb, | |
27 | url_path_join(self.base_url, 'nbconvert', path), |
|
27 | url_path_join(self.base_url, 'nbconvert', path), | |
28 | data=body, params=params, |
|
28 | data=body, params=params, | |
29 | ) |
|
29 | ) | |
30 | response.raise_for_status() |
|
30 | response.raise_for_status() | |
31 | return response |
|
31 | return response | |
32 |
|
32 | |||
33 | def from_file(self, format, path, name, download=False): |
|
33 | def from_file(self, format, path, name, download=False): | |
34 | return self._req('GET', url_path_join(format, path, name), |
|
34 | return self._req('GET', url_path_join(format, path, name), | |
35 | params={'download':download}) |
|
35 | params={'download':download}) | |
36 |
|
36 | |||
37 | def from_post(self, format, nbmodel): |
|
37 | def from_post(self, format, nbmodel): | |
38 | body = json.dumps(nbmodel) |
|
38 | body = json.dumps(nbmodel) | |
39 | return self._req('POST', format, body) |
|
39 | return self._req('POST', format, body) | |
40 |
|
40 | |||
41 | def list_formats(self): |
|
41 | def list_formats(self): | |
42 | return self._req('GET', '') |
|
42 | return self._req('GET', '') | |
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 | ).decode('ascii') | |
48 |
|
48 | |||
49 | class APITest(NotebookTestBase): |
|
49 | class APITest(NotebookTestBase): | |
50 | def setUp(self): |
|
50 | def setUp(self): | |
51 | nbdir = self.notebook_dir.name |
|
51 | nbdir = self.notebook_dir.name | |
52 |
|
52 | |||
53 | if not os.path.isdir(pjoin(nbdir, 'foo')): |
|
53 | if not os.path.isdir(pjoin(nbdir, 'foo')): | |
54 | os.mkdir(pjoin(nbdir, 'foo')) |
|
54 | os.mkdir(pjoin(nbdir, 'foo')) | |
55 |
|
55 | |||
56 | nb = new_notebook() |
|
56 | nb = new_notebook() | |
57 |
|
57 | |||
58 | nb.cells.append(new_heading_cell(u'Created by test ³')) |
|
58 | nb.cells.append(new_heading_cell(u'Created by test ³')) | |
59 | cc1 = new_code_cell(source=u'print(2*6)') |
|
59 | cc1 = new_code_cell(source=u'print(2*6)') | |
60 | cc1.outputs.append(new_output(output_type="stream", data=u'12')) |
|
60 | cc1.outputs.append(new_output(output_type="stream", data=u'12')) | |
61 | cc1.outputs.append(new_output(output_type="execute_result", |
|
61 | cc1.outputs.append(new_output(output_type="execute_result", | |
62 | mime_bundle={'image/png' : png_green_pixel}, |
|
62 | mime_bundle={'image/png' : png_green_pixel}, | |
63 | prompt_number=1, |
|
63 | execution_count=1, | |
64 | )) |
|
64 | )) | |
65 | nb.cells.append(cc1) |
|
65 | nb.cells.append(cc1) | |
66 |
|
66 | |||
67 | with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w', |
|
67 | with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w', | |
68 | encoding='utf-8') as f: |
|
68 | encoding='utf-8') as f: | |
69 | write(nb, f) |
|
69 | write(nb, f) | |
70 |
|
70 | |||
71 | self.nbconvert_api = NbconvertAPI(self.base_url()) |
|
71 | self.nbconvert_api = NbconvertAPI(self.base_url()) | |
72 |
|
72 | |||
73 | def tearDown(self): |
|
73 | def tearDown(self): | |
74 | nbdir = self.notebook_dir.name |
|
74 | nbdir = self.notebook_dir.name | |
75 |
|
75 | |||
76 | for dname in ['foo']: |
|
76 | for dname in ['foo']: | |
77 | shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True) |
|
77 | shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True) | |
78 |
|
78 | |||
79 | @onlyif_cmds_exist('pandoc') |
|
79 | @onlyif_cmds_exist('pandoc') | |
80 | def test_from_file(self): |
|
80 | def test_from_file(self): | |
81 | r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb') |
|
81 | r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb') | |
82 | self.assertEqual(r.status_code, 200) |
|
82 | self.assertEqual(r.status_code, 200) | |
83 | self.assertIn(u'text/html', r.headers['Content-Type']) |
|
83 | self.assertIn(u'text/html', r.headers['Content-Type']) | |
84 | self.assertIn(u'Created by test', r.text) |
|
84 | self.assertIn(u'Created by test', r.text) | |
85 | self.assertIn(u'print', r.text) |
|
85 | self.assertIn(u'print', r.text) | |
86 |
|
86 | |||
87 | r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb') |
|
87 | r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb') | |
88 | self.assertIn(u'text/x-python', r.headers['Content-Type']) |
|
88 | self.assertIn(u'text/x-python', r.headers['Content-Type']) | |
89 | self.assertIn(u'print(2*6)', r.text) |
|
89 | self.assertIn(u'print(2*6)', r.text) | |
90 |
|
90 | |||
91 | @onlyif_cmds_exist('pandoc') |
|
91 | @onlyif_cmds_exist('pandoc') | |
92 | def test_from_file_404(self): |
|
92 | def test_from_file_404(self): | |
93 | with assert_http_error(404): |
|
93 | with assert_http_error(404): | |
94 | self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb') |
|
94 | self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb') | |
95 |
|
95 | |||
96 | @onlyif_cmds_exist('pandoc') |
|
96 | @onlyif_cmds_exist('pandoc') | |
97 | def test_from_file_download(self): |
|
97 | def test_from_file_download(self): | |
98 | r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True) |
|
98 | r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True) | |
99 | content_disposition = r.headers['Content-Disposition'] |
|
99 | content_disposition = r.headers['Content-Disposition'] | |
100 | self.assertIn('attachment', content_disposition) |
|
100 | self.assertIn('attachment', content_disposition) | |
101 | self.assertIn('testnb.py', content_disposition) |
|
101 | self.assertIn('testnb.py', content_disposition) | |
102 |
|
102 | |||
103 | @onlyif_cmds_exist('pandoc') |
|
103 | @onlyif_cmds_exist('pandoc') | |
104 | def test_from_file_zip(self): |
|
104 | def test_from_file_zip(self): | |
105 | r = self.nbconvert_api.from_file('latex', 'foo', 'testnb.ipynb', download=True) |
|
105 | r = self.nbconvert_api.from_file('latex', 'foo', 'testnb.ipynb', download=True) | |
106 | self.assertIn(u'application/zip', r.headers['Content-Type']) |
|
106 | self.assertIn(u'application/zip', r.headers['Content-Type']) | |
107 | self.assertIn(u'.zip', r.headers['Content-Disposition']) |
|
107 | self.assertIn(u'.zip', r.headers['Content-Disposition']) | |
108 |
|
108 | |||
109 | @onlyif_cmds_exist('pandoc') |
|
109 | @onlyif_cmds_exist('pandoc') | |
110 | def test_from_post(self): |
|
110 | def test_from_post(self): | |
111 | nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb') |
|
111 | nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb') | |
112 | nbmodel = requests.get(nbmodel_url).json() |
|
112 | nbmodel = requests.get(nbmodel_url).json() | |
113 |
|
113 | |||
114 | r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel) |
|
114 | r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel) | |
115 | self.assertEqual(r.status_code, 200) |
|
115 | self.assertEqual(r.status_code, 200) | |
116 | self.assertIn(u'text/html', r.headers['Content-Type']) |
|
116 | self.assertIn(u'text/html', r.headers['Content-Type']) | |
117 | self.assertIn(u'Created by test', r.text) |
|
117 | self.assertIn(u'Created by test', r.text) | |
118 | self.assertIn(u'print', r.text) |
|
118 | self.assertIn(u'print', r.text) | |
119 |
|
119 | |||
120 | r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel) |
|
120 | r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel) | |
121 | self.assertIn(u'text/x-python', r.headers['Content-Type']) |
|
121 | self.assertIn(u'text/x-python', r.headers['Content-Type']) | |
122 | self.assertIn(u'print(2*6)', r.text) |
|
122 | self.assertIn(u'print(2*6)', r.text) | |
123 |
|
123 | |||
124 | @onlyif_cmds_exist('pandoc') |
|
124 | @onlyif_cmds_exist('pandoc') | |
125 | def test_from_post_zip(self): |
|
125 | def test_from_post_zip(self): | |
126 | nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb') |
|
126 | nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb') | |
127 | nbmodel = requests.get(nbmodel_url).json() |
|
127 | nbmodel = requests.get(nbmodel_url).json() | |
128 |
|
128 | |||
129 | r = self.nbconvert_api.from_post(format='latex', nbmodel=nbmodel) |
|
129 | r = self.nbconvert_api.from_post(format='latex', nbmodel=nbmodel) | |
130 | self.assertIn(u'application/zip', r.headers['Content-Type']) |
|
130 | self.assertIn(u'application/zip', r.headers['Content-Type']) | |
131 | self.assertIn(u'.zip', r.headers['Content-Disposition']) |
|
131 | self.assertIn(u'.zip', r.headers['Content-Disposition']) |
@@ -1,526 +1,526 | |||||
1 | // Copyright (c) IPython Development Team. |
|
1 | // Copyright (c) IPython Development Team. | |
2 | // Distributed under the terms of the Modified BSD License. |
|
2 | // Distributed under the terms of the Modified BSD License. | |
3 | /** |
|
3 | /** | |
4 | * |
|
4 | * | |
5 | * |
|
5 | * | |
6 | * @module codecell |
|
6 | * @module codecell | |
7 | * @namespace codecell |
|
7 | * @namespace codecell | |
8 | * @class CodeCell |
|
8 | * @class CodeCell | |
9 | */ |
|
9 | */ | |
10 |
|
10 | |||
11 |
|
11 | |||
12 | define([ |
|
12 | define([ | |
13 | 'base/js/namespace', |
|
13 | 'base/js/namespace', | |
14 | 'jquery', |
|
14 | 'jquery', | |
15 | 'base/js/utils', |
|
15 | 'base/js/utils', | |
16 | 'base/js/keyboard', |
|
16 | 'base/js/keyboard', | |
17 | 'notebook/js/cell', |
|
17 | 'notebook/js/cell', | |
18 | 'notebook/js/outputarea', |
|
18 | 'notebook/js/outputarea', | |
19 | 'notebook/js/completer', |
|
19 | 'notebook/js/completer', | |
20 | 'notebook/js/celltoolbar', |
|
20 | 'notebook/js/celltoolbar', | |
21 | 'codemirror/lib/codemirror', |
|
21 | 'codemirror/lib/codemirror', | |
22 | 'codemirror/mode/python/python', |
|
22 | 'codemirror/mode/python/python', | |
23 | 'notebook/js/codemirror-ipython' |
|
23 | 'notebook/js/codemirror-ipython' | |
24 | ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) { |
|
24 | ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) { | |
25 | "use strict"; |
|
25 | "use strict"; | |
26 | var Cell = cell.Cell; |
|
26 | var Cell = cell.Cell; | |
27 |
|
27 | |||
28 | /* local util for codemirror */ |
|
28 | /* local util for codemirror */ | |
29 | var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;}; |
|
29 | var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;}; | |
30 |
|
30 | |||
31 | /** |
|
31 | /** | |
32 | * |
|
32 | * | |
33 | * function to delete until previous non blanking space character |
|
33 | * function to delete until previous non blanking space character | |
34 | * or first multiple of 4 tabstop. |
|
34 | * or first multiple of 4 tabstop. | |
35 | * @private |
|
35 | * @private | |
36 | */ |
|
36 | */ | |
37 | CodeMirror.commands.delSpaceToPrevTabStop = function(cm){ |
|
37 | CodeMirror.commands.delSpaceToPrevTabStop = function(cm){ | |
38 | var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to); |
|
38 | var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to); | |
39 | if (!posEq(from, to)) { cm.replaceRange("", from, to); return; } |
|
39 | if (!posEq(from, to)) { cm.replaceRange("", from, to); return; } | |
40 | var cur = cm.getCursor(), line = cm.getLine(cur.line); |
|
40 | var cur = cm.getCursor(), line = cm.getLine(cur.line); | |
41 | var tabsize = cm.getOption('tabSize'); |
|
41 | var tabsize = cm.getOption('tabSize'); | |
42 | var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize; |
|
42 | var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize; | |
43 | from = {ch:cur.ch-chToPrevTabStop,line:cur.line}; |
|
43 | from = {ch:cur.ch-chToPrevTabStop,line:cur.line}; | |
44 | var select = cm.getRange(from,cur); |
|
44 | var select = cm.getRange(from,cur); | |
45 | if( select.match(/^\ +$/) !== null){ |
|
45 | if( select.match(/^\ +$/) !== null){ | |
46 | cm.replaceRange("",from,cur); |
|
46 | cm.replaceRange("",from,cur); | |
47 | } else { |
|
47 | } else { | |
48 | cm.deleteH(-1,"char"); |
|
48 | cm.deleteH(-1,"char"); | |
49 | } |
|
49 | } | |
50 | }; |
|
50 | }; | |
51 |
|
51 | |||
52 | var keycodes = keyboard.keycodes; |
|
52 | var keycodes = keyboard.keycodes; | |
53 |
|
53 | |||
54 | var CodeCell = function (kernel, options) { |
|
54 | var CodeCell = function (kernel, options) { | |
55 | // Constructor |
|
55 | // Constructor | |
56 | // |
|
56 | // | |
57 | // A Cell conceived to write code. |
|
57 | // A Cell conceived to write code. | |
58 | // |
|
58 | // | |
59 | // Parameters: |
|
59 | // Parameters: | |
60 | // kernel: Kernel instance |
|
60 | // kernel: Kernel instance | |
61 | // The kernel doesn't have to be set at creation time, in that case |
|
61 | // The kernel doesn't have to be set at creation time, in that case | |
62 | // it will be null and set_kernel has to be called later. |
|
62 | // it will be null and set_kernel has to be called later. | |
63 | // options: dictionary |
|
63 | // options: dictionary | |
64 | // Dictionary of keyword arguments. |
|
64 | // Dictionary of keyword arguments. | |
65 | // events: $(Events) instance |
|
65 | // events: $(Events) instance | |
66 | // config: dictionary |
|
66 | // config: dictionary | |
67 | // keyboard_manager: KeyboardManager instance |
|
67 | // keyboard_manager: KeyboardManager instance | |
68 | // notebook: Notebook instance |
|
68 | // notebook: Notebook instance | |
69 | // tooltip: Tooltip instance |
|
69 | // tooltip: Tooltip instance | |
70 | this.kernel = kernel || null; |
|
70 | this.kernel = kernel || null; | |
71 | this.notebook = options.notebook; |
|
71 | this.notebook = options.notebook; | |
72 | this.collapsed = false; |
|
72 | this.collapsed = false; | |
73 | this.events = options.events; |
|
73 | this.events = options.events; | |
74 | this.tooltip = options.tooltip; |
|
74 | this.tooltip = options.tooltip; | |
75 | this.config = options.config; |
|
75 | this.config = options.config; | |
76 |
|
76 | |||
77 | // create all attributed in constructor function |
|
77 | // create all attributed in constructor function | |
78 | // even if null for V8 VM optimisation |
|
78 | // even if null for V8 VM optimisation | |
79 | this.input_prompt_number = null; |
|
79 | this.input_prompt_number = null; | |
80 | this.celltoolbar = null; |
|
80 | this.celltoolbar = null; | |
81 | this.output_area = null; |
|
81 | this.output_area = null; | |
82 | this.last_msg_id = null; |
|
82 | this.last_msg_id = null; | |
83 | this.completer = null; |
|
83 | this.completer = null; | |
84 |
|
84 | |||
85 |
|
85 | |||
86 | var config = utils.mergeopt(CodeCell, this.config); |
|
86 | var config = utils.mergeopt(CodeCell, this.config); | |
87 | Cell.apply(this,[{ |
|
87 | Cell.apply(this,[{ | |
88 | config: config, |
|
88 | config: config, | |
89 | keyboard_manager: options.keyboard_manager, |
|
89 | keyboard_manager: options.keyboard_manager, | |
90 | events: this.events}]); |
|
90 | events: this.events}]); | |
91 |
|
91 | |||
92 | // Attributes we want to override in this subclass. |
|
92 | // Attributes we want to override in this subclass. | |
93 | this.cell_type = "code"; |
|
93 | this.cell_type = "code"; | |
94 |
|
94 | |||
95 | var that = this; |
|
95 | var that = this; | |
96 | this.element.focusout( |
|
96 | this.element.focusout( | |
97 | function() { that.auto_highlight(); } |
|
97 | function() { that.auto_highlight(); } | |
98 | ); |
|
98 | ); | |
99 | }; |
|
99 | }; | |
100 |
|
100 | |||
101 | CodeCell.options_default = { |
|
101 | CodeCell.options_default = { | |
102 | cm_config : { |
|
102 | cm_config : { | |
103 | extraKeys: { |
|
103 | extraKeys: { | |
104 | "Tab" : "indentMore", |
|
104 | "Tab" : "indentMore", | |
105 | "Shift-Tab" : "indentLess", |
|
105 | "Shift-Tab" : "indentLess", | |
106 | "Backspace" : "delSpaceToPrevTabStop", |
|
106 | "Backspace" : "delSpaceToPrevTabStop", | |
107 | "Cmd-/" : "toggleComment", |
|
107 | "Cmd-/" : "toggleComment", | |
108 | "Ctrl-/" : "toggleComment" |
|
108 | "Ctrl-/" : "toggleComment" | |
109 | }, |
|
109 | }, | |
110 | mode: 'ipython', |
|
110 | mode: 'ipython', | |
111 | theme: 'ipython', |
|
111 | theme: 'ipython', | |
112 | matchBrackets: true |
|
112 | matchBrackets: true | |
113 | } |
|
113 | } | |
114 | }; |
|
114 | }; | |
115 |
|
115 | |||
116 | CodeCell.msg_cells = {}; |
|
116 | CodeCell.msg_cells = {}; | |
117 |
|
117 | |||
118 | CodeCell.prototype = Object.create(Cell.prototype); |
|
118 | CodeCell.prototype = Object.create(Cell.prototype); | |
119 |
|
119 | |||
120 | /** |
|
120 | /** | |
121 | * @method auto_highlight |
|
121 | * @method auto_highlight | |
122 | */ |
|
122 | */ | |
123 | CodeCell.prototype.auto_highlight = function () { |
|
123 | CodeCell.prototype.auto_highlight = function () { | |
124 | this._auto_highlight(this.config.cell_magic_highlight); |
|
124 | this._auto_highlight(this.config.cell_magic_highlight); | |
125 | }; |
|
125 | }; | |
126 |
|
126 | |||
127 | /** @method create_element */ |
|
127 | /** @method create_element */ | |
128 | CodeCell.prototype.create_element = function () { |
|
128 | CodeCell.prototype.create_element = function () { | |
129 | Cell.prototype.create_element.apply(this, arguments); |
|
129 | Cell.prototype.create_element.apply(this, arguments); | |
130 |
|
130 | |||
131 | var cell = $('<div></div>').addClass('cell code_cell'); |
|
131 | var cell = $('<div></div>').addClass('cell code_cell'); | |
132 | cell.attr('tabindex','2'); |
|
132 | cell.attr('tabindex','2'); | |
133 |
|
133 | |||
134 | var input = $('<div></div>').addClass('input'); |
|
134 | var input = $('<div></div>').addClass('input'); | |
135 | var prompt = $('<div/>').addClass('prompt input_prompt'); |
|
135 | var prompt = $('<div/>').addClass('prompt input_prompt'); | |
136 | var inner_cell = $('<div/>').addClass('inner_cell'); |
|
136 | var inner_cell = $('<div/>').addClass('inner_cell'); | |
137 | this.celltoolbar = new celltoolbar.CellToolbar({ |
|
137 | this.celltoolbar = new celltoolbar.CellToolbar({ | |
138 | cell: this, |
|
138 | cell: this, | |
139 | notebook: this.notebook}); |
|
139 | notebook: this.notebook}); | |
140 | inner_cell.append(this.celltoolbar.element); |
|
140 | inner_cell.append(this.celltoolbar.element); | |
141 | var input_area = $('<div/>').addClass('input_area'); |
|
141 | var input_area = $('<div/>').addClass('input_area'); | |
142 | this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config); |
|
142 | this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config); | |
143 | this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this)) |
|
143 | this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this)) | |
144 | $(this.code_mirror.getInputField()).attr("spellcheck", "false"); |
|
144 | $(this.code_mirror.getInputField()).attr("spellcheck", "false"); | |
145 | inner_cell.append(input_area); |
|
145 | inner_cell.append(input_area); | |
146 | input.append(prompt).append(inner_cell); |
|
146 | input.append(prompt).append(inner_cell); | |
147 |
|
147 | |||
148 | var widget_area = $('<div/>') |
|
148 | var widget_area = $('<div/>') | |
149 | .addClass('widget-area') |
|
149 | .addClass('widget-area') | |
150 | .hide(); |
|
150 | .hide(); | |
151 | this.widget_area = widget_area; |
|
151 | this.widget_area = widget_area; | |
152 | var widget_prompt = $('<div/>') |
|
152 | var widget_prompt = $('<div/>') | |
153 | .addClass('prompt') |
|
153 | .addClass('prompt') | |
154 | .appendTo(widget_area); |
|
154 | .appendTo(widget_area); | |
155 | var widget_subarea = $('<div/>') |
|
155 | var widget_subarea = $('<div/>') | |
156 | .addClass('widget-subarea') |
|
156 | .addClass('widget-subarea') | |
157 | .appendTo(widget_area); |
|
157 | .appendTo(widget_area); | |
158 | this.widget_subarea = widget_subarea; |
|
158 | this.widget_subarea = widget_subarea; | |
159 | var widget_clear_buton = $('<button />') |
|
159 | var widget_clear_buton = $('<button />') | |
160 | .addClass('close') |
|
160 | .addClass('close') | |
161 | .html('×') |
|
161 | .html('×') | |
162 | .click(function() { |
|
162 | .click(function() { | |
163 | widget_area.slideUp('', function(){ widget_subarea.html(''); }); |
|
163 | widget_area.slideUp('', function(){ widget_subarea.html(''); }); | |
164 | }) |
|
164 | }) | |
165 | .appendTo(widget_prompt); |
|
165 | .appendTo(widget_prompt); | |
166 |
|
166 | |||
167 | var output = $('<div></div>'); |
|
167 | var output = $('<div></div>'); | |
168 | cell.append(input).append(widget_area).append(output); |
|
168 | cell.append(input).append(widget_area).append(output); | |
169 | this.element = cell; |
|
169 | this.element = cell; | |
170 | this.output_area = new outputarea.OutputArea({ |
|
170 | this.output_area = new outputarea.OutputArea({ | |
171 | selector: output, |
|
171 | selector: output, | |
172 | prompt_area: true, |
|
172 | prompt_area: true, | |
173 | events: this.events, |
|
173 | events: this.events, | |
174 | keyboard_manager: this.keyboard_manager}); |
|
174 | keyboard_manager: this.keyboard_manager}); | |
175 | this.completer = new completer.Completer(this, this.events); |
|
175 | this.completer = new completer.Completer(this, this.events); | |
176 | }; |
|
176 | }; | |
177 |
|
177 | |||
178 | /** @method bind_events */ |
|
178 | /** @method bind_events */ | |
179 | CodeCell.prototype.bind_events = function () { |
|
179 | CodeCell.prototype.bind_events = function () { | |
180 | Cell.prototype.bind_events.apply(this); |
|
180 | Cell.prototype.bind_events.apply(this); | |
181 | var that = this; |
|
181 | var that = this; | |
182 |
|
182 | |||
183 | this.element.focusout( |
|
183 | this.element.focusout( | |
184 | function() { that.auto_highlight(); } |
|
184 | function() { that.auto_highlight(); } | |
185 | ); |
|
185 | ); | |
186 | }; |
|
186 | }; | |
187 |
|
187 | |||
188 |
|
188 | |||
189 | /** |
|
189 | /** | |
190 | * This method gets called in CodeMirror's onKeyDown/onKeyPress |
|
190 | * This method gets called in CodeMirror's onKeyDown/onKeyPress | |
191 | * handlers and is used to provide custom key handling. Its return |
|
191 | * handlers and is used to provide custom key handling. Its return | |
192 | * value is used to determine if CodeMirror should ignore the event: |
|
192 | * value is used to determine if CodeMirror should ignore the event: | |
193 | * true = ignore, false = don't ignore. |
|
193 | * true = ignore, false = don't ignore. | |
194 | * @method handle_codemirror_keyevent |
|
194 | * @method handle_codemirror_keyevent | |
195 | */ |
|
195 | */ | |
196 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { |
|
196 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { | |
197 |
|
197 | |||
198 | var that = this; |
|
198 | var that = this; | |
199 | // whatever key is pressed, first, cancel the tooltip request before |
|
199 | // whatever key is pressed, first, cancel the tooltip request before | |
200 | // they are sent, and remove tooltip if any, except for tab again |
|
200 | // they are sent, and remove tooltip if any, except for tab again | |
201 | var tooltip_closed = null; |
|
201 | var tooltip_closed = null; | |
202 | if (event.type === 'keydown' && event.which != keycodes.tab ) { |
|
202 | if (event.type === 'keydown' && event.which != keycodes.tab ) { | |
203 | tooltip_closed = this.tooltip.remove_and_cancel_tooltip(); |
|
203 | tooltip_closed = this.tooltip.remove_and_cancel_tooltip(); | |
204 | } |
|
204 | } | |
205 |
|
205 | |||
206 | var cur = editor.getCursor(); |
|
206 | var cur = editor.getCursor(); | |
207 | if (event.keyCode === keycodes.enter){ |
|
207 | if (event.keyCode === keycodes.enter){ | |
208 | this.auto_highlight(); |
|
208 | this.auto_highlight(); | |
209 | } |
|
209 | } | |
210 |
|
210 | |||
211 | if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) { |
|
211 | if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) { | |
212 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform |
|
212 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform | |
213 | // browser and keyboard layout ! |
|
213 | // browser and keyboard layout ! | |
214 | // Pressing '(' , request tooltip, don't forget to reappend it |
|
214 | // Pressing '(' , request tooltip, don't forget to reappend it | |
215 | // The second argument says to hide the tooltip if the docstring |
|
215 | // The second argument says to hide the tooltip if the docstring | |
216 | // is actually empty |
|
216 | // is actually empty | |
217 | this.tooltip.pending(that, true); |
|
217 | this.tooltip.pending(that, true); | |
218 | } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') { |
|
218 | } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') { | |
219 | // If tooltip is active, cancel it. The call to |
|
219 | // If tooltip is active, cancel it. The call to | |
220 | // remove_and_cancel_tooltip above doesn't pass, force=true. |
|
220 | // remove_and_cancel_tooltip above doesn't pass, force=true. | |
221 | // Because of this it won't actually close the tooltip |
|
221 | // Because of this it won't actually close the tooltip | |
222 | // if it is in sticky mode. Thus, we have to check again if it is open |
|
222 | // if it is in sticky mode. Thus, we have to check again if it is open | |
223 | // and close it with force=true. |
|
223 | // and close it with force=true. | |
224 | if (!this.tooltip._hidden) { |
|
224 | if (!this.tooltip._hidden) { | |
225 | this.tooltip.remove_and_cancel_tooltip(true); |
|
225 | this.tooltip.remove_and_cancel_tooltip(true); | |
226 | } |
|
226 | } | |
227 | // If we closed the tooltip, don't let CM or the global handlers |
|
227 | // If we closed the tooltip, don't let CM or the global handlers | |
228 | // handle this event. |
|
228 | // handle this event. | |
229 | event.codemirrorIgnore = true; |
|
229 | event.codemirrorIgnore = true; | |
230 | event.preventDefault(); |
|
230 | event.preventDefault(); | |
231 | return true; |
|
231 | return true; | |
232 | } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) { |
|
232 | } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) { | |
233 | if (editor.somethingSelected() || editor.getSelections().length !== 1){ |
|
233 | if (editor.somethingSelected() || editor.getSelections().length !== 1){ | |
234 | var anchor = editor.getCursor("anchor"); |
|
234 | var anchor = editor.getCursor("anchor"); | |
235 | var head = editor.getCursor("head"); |
|
235 | var head = editor.getCursor("head"); | |
236 | if( anchor.line != head.line){ |
|
236 | if( anchor.line != head.line){ | |
237 | return false; |
|
237 | return false; | |
238 | } |
|
238 | } | |
239 | } |
|
239 | } | |
240 | this.tooltip.request(that); |
|
240 | this.tooltip.request(that); | |
241 | event.codemirrorIgnore = true; |
|
241 | event.codemirrorIgnore = true; | |
242 | event.preventDefault(); |
|
242 | event.preventDefault(); | |
243 | return true; |
|
243 | return true; | |
244 | } else if (event.keyCode === keycodes.tab && event.type == 'keydown') { |
|
244 | } else if (event.keyCode === keycodes.tab && event.type == 'keydown') { | |
245 | // Tab completion. |
|
245 | // Tab completion. | |
246 | this.tooltip.remove_and_cancel_tooltip(); |
|
246 | this.tooltip.remove_and_cancel_tooltip(); | |
247 |
|
247 | |||
248 | // completion does not work on multicursor, it might be possible though in some cases |
|
248 | // completion does not work on multicursor, it might be possible though in some cases | |
249 | if (editor.somethingSelected() || editor.getSelections().length > 1) { |
|
249 | if (editor.somethingSelected() || editor.getSelections().length > 1) { | |
250 | return false; |
|
250 | return false; | |
251 | } |
|
251 | } | |
252 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur); |
|
252 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur); | |
253 | if (pre_cursor.trim() === "") { |
|
253 | if (pre_cursor.trim() === "") { | |
254 | // Don't autocomplete if the part of the line before the cursor |
|
254 | // Don't autocomplete if the part of the line before the cursor | |
255 | // is empty. In this case, let CodeMirror handle indentation. |
|
255 | // is empty. In this case, let CodeMirror handle indentation. | |
256 | return false; |
|
256 | return false; | |
257 | } else { |
|
257 | } else { | |
258 | event.codemirrorIgnore = true; |
|
258 | event.codemirrorIgnore = true; | |
259 | event.preventDefault(); |
|
259 | event.preventDefault(); | |
260 | this.completer.startCompletion(); |
|
260 | this.completer.startCompletion(); | |
261 | return true; |
|
261 | return true; | |
262 | } |
|
262 | } | |
263 | } |
|
263 | } | |
264 |
|
264 | |||
265 | // keyboard event wasn't one of those unique to code cells, let's see |
|
265 | // keyboard event wasn't one of those unique to code cells, let's see | |
266 | // if it's one of the generic ones (i.e. check edit mode shortcuts) |
|
266 | // if it's one of the generic ones (i.e. check edit mode shortcuts) | |
267 | return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]); |
|
267 | return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]); | |
268 | }; |
|
268 | }; | |
269 |
|
269 | |||
270 | // Kernel related calls. |
|
270 | // Kernel related calls. | |
271 |
|
271 | |||
272 | CodeCell.prototype.set_kernel = function (kernel) { |
|
272 | CodeCell.prototype.set_kernel = function (kernel) { | |
273 | this.kernel = kernel; |
|
273 | this.kernel = kernel; | |
274 | }; |
|
274 | }; | |
275 |
|
275 | |||
276 | /** |
|
276 | /** | |
277 | * Execute current code cell to the kernel |
|
277 | * Execute current code cell to the kernel | |
278 | * @method execute |
|
278 | * @method execute | |
279 | */ |
|
279 | */ | |
280 | CodeCell.prototype.execute = function () { |
|
280 | CodeCell.prototype.execute = function () { | |
281 | this.output_area.clear_output(); |
|
281 | this.output_area.clear_output(); | |
282 |
|
282 | |||
283 | // Clear widget area |
|
283 | // Clear widget area | |
284 | this.widget_subarea.html(''); |
|
284 | this.widget_subarea.html(''); | |
285 | this.widget_subarea.height(''); |
|
285 | this.widget_subarea.height(''); | |
286 | this.widget_area.height(''); |
|
286 | this.widget_area.height(''); | |
287 | this.widget_area.hide(); |
|
287 | this.widget_area.hide(); | |
288 |
|
288 | |||
289 | this.set_input_prompt('*'); |
|
289 | this.set_input_prompt('*'); | |
290 | this.element.addClass("running"); |
|
290 | this.element.addClass("running"); | |
291 | if (this.last_msg_id) { |
|
291 | if (this.last_msg_id) { | |
292 | this.kernel.clear_callbacks_for_msg(this.last_msg_id); |
|
292 | this.kernel.clear_callbacks_for_msg(this.last_msg_id); | |
293 | } |
|
293 | } | |
294 | var callbacks = this.get_callbacks(); |
|
294 | var callbacks = this.get_callbacks(); | |
295 |
|
295 | |||
296 | var old_msg_id = this.last_msg_id; |
|
296 | var old_msg_id = this.last_msg_id; | |
297 | this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true}); |
|
297 | this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true}); | |
298 | if (old_msg_id) { |
|
298 | if (old_msg_id) { | |
299 | delete CodeCell.msg_cells[old_msg_id]; |
|
299 | delete CodeCell.msg_cells[old_msg_id]; | |
300 | } |
|
300 | } | |
301 | CodeCell.msg_cells[this.last_msg_id] = this; |
|
301 | CodeCell.msg_cells[this.last_msg_id] = this; | |
302 | this.render(); |
|
302 | this.render(); | |
303 | }; |
|
303 | }; | |
304 |
|
304 | |||
305 | /** |
|
305 | /** | |
306 | * Construct the default callbacks for |
|
306 | * Construct the default callbacks for | |
307 | * @method get_callbacks |
|
307 | * @method get_callbacks | |
308 | */ |
|
308 | */ | |
309 | CodeCell.prototype.get_callbacks = function () { |
|
309 | CodeCell.prototype.get_callbacks = function () { | |
310 | return { |
|
310 | return { | |
311 | shell : { |
|
311 | shell : { | |
312 | reply : $.proxy(this._handle_execute_reply, this), |
|
312 | reply : $.proxy(this._handle_execute_reply, this), | |
313 | payload : { |
|
313 | payload : { | |
314 | set_next_input : $.proxy(this._handle_set_next_input, this), |
|
314 | set_next_input : $.proxy(this._handle_set_next_input, this), | |
315 | page : $.proxy(this._open_with_pager, this) |
|
315 | page : $.proxy(this._open_with_pager, this) | |
316 | } |
|
316 | } | |
317 | }, |
|
317 | }, | |
318 | iopub : { |
|
318 | iopub : { | |
319 | output : $.proxy(this.output_area.handle_output, this.output_area), |
|
319 | output : $.proxy(this.output_area.handle_output, this.output_area), | |
320 | clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area), |
|
320 | clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area), | |
321 | }, |
|
321 | }, | |
322 | input : $.proxy(this._handle_input_request, this) |
|
322 | input : $.proxy(this._handle_input_request, this) | |
323 | }; |
|
323 | }; | |
324 | }; |
|
324 | }; | |
325 |
|
325 | |||
326 | CodeCell.prototype._open_with_pager = function (payload) { |
|
326 | CodeCell.prototype._open_with_pager = function (payload) { | |
327 | this.events.trigger('open_with_text.Pager', payload); |
|
327 | this.events.trigger('open_with_text.Pager', payload); | |
328 | }; |
|
328 | }; | |
329 |
|
329 | |||
330 | /** |
|
330 | /** | |
331 | * @method _handle_execute_reply |
|
331 | * @method _handle_execute_reply | |
332 | * @private |
|
332 | * @private | |
333 | */ |
|
333 | */ | |
334 | CodeCell.prototype._handle_execute_reply = function (msg) { |
|
334 | CodeCell.prototype._handle_execute_reply = function (msg) { | |
335 | this.set_input_prompt(msg.content.execution_count); |
|
335 | this.set_input_prompt(msg.content.execution_count); | |
336 | this.element.removeClass("running"); |
|
336 | this.element.removeClass("running"); | |
337 | this.events.trigger('set_dirty.Notebook', {value: true}); |
|
337 | this.events.trigger('set_dirty.Notebook', {value: true}); | |
338 | }; |
|
338 | }; | |
339 |
|
339 | |||
340 | /** |
|
340 | /** | |
341 | * @method _handle_set_next_input |
|
341 | * @method _handle_set_next_input | |
342 | * @private |
|
342 | * @private | |
343 | */ |
|
343 | */ | |
344 | CodeCell.prototype._handle_set_next_input = function (payload) { |
|
344 | CodeCell.prototype._handle_set_next_input = function (payload) { | |
345 | var data = {'cell': this, 'text': payload.text}; |
|
345 | var data = {'cell': this, 'text': payload.text}; | |
346 | this.events.trigger('set_next_input.Notebook', data); |
|
346 | this.events.trigger('set_next_input.Notebook', data); | |
347 | }; |
|
347 | }; | |
348 |
|
348 | |||
349 | /** |
|
349 | /** | |
350 | * @method _handle_input_request |
|
350 | * @method _handle_input_request | |
351 | * @private |
|
351 | * @private | |
352 | */ |
|
352 | */ | |
353 | CodeCell.prototype._handle_input_request = function (msg) { |
|
353 | CodeCell.prototype._handle_input_request = function (msg) { | |
354 | this.output_area.append_raw_input(msg); |
|
354 | this.output_area.append_raw_input(msg); | |
355 | }; |
|
355 | }; | |
356 |
|
356 | |||
357 |
|
357 | |||
358 | // Basic cell manipulation. |
|
358 | // Basic cell manipulation. | |
359 |
|
359 | |||
360 | CodeCell.prototype.select = function () { |
|
360 | CodeCell.prototype.select = function () { | |
361 | var cont = Cell.prototype.select.apply(this); |
|
361 | var cont = Cell.prototype.select.apply(this); | |
362 | if (cont) { |
|
362 | if (cont) { | |
363 | this.code_mirror.refresh(); |
|
363 | this.code_mirror.refresh(); | |
364 | this.auto_highlight(); |
|
364 | this.auto_highlight(); | |
365 | } |
|
365 | } | |
366 | return cont; |
|
366 | return cont; | |
367 | }; |
|
367 | }; | |
368 |
|
368 | |||
369 | CodeCell.prototype.render = function () { |
|
369 | CodeCell.prototype.render = function () { | |
370 | var cont = Cell.prototype.render.apply(this); |
|
370 | var cont = Cell.prototype.render.apply(this); | |
371 | // Always execute, even if we are already in the rendered state |
|
371 | // Always execute, even if we are already in the rendered state | |
372 | return cont; |
|
372 | return cont; | |
373 | }; |
|
373 | }; | |
374 |
|
374 | |||
375 | CodeCell.prototype.select_all = function () { |
|
375 | CodeCell.prototype.select_all = function () { | |
376 | var start = {line: 0, ch: 0}; |
|
376 | var start = {line: 0, ch: 0}; | |
377 | var nlines = this.code_mirror.lineCount(); |
|
377 | var nlines = this.code_mirror.lineCount(); | |
378 | var last_line = this.code_mirror.getLine(nlines-1); |
|
378 | var last_line = this.code_mirror.getLine(nlines-1); | |
379 | var end = {line: nlines-1, ch: last_line.length}; |
|
379 | var end = {line: nlines-1, ch: last_line.length}; | |
380 | this.code_mirror.setSelection(start, end); |
|
380 | this.code_mirror.setSelection(start, end); | |
381 | }; |
|
381 | }; | |
382 |
|
382 | |||
383 |
|
383 | |||
384 | CodeCell.prototype.collapse_output = function () { |
|
384 | CodeCell.prototype.collapse_output = function () { | |
385 | this.output_area.collapse(); |
|
385 | this.output_area.collapse(); | |
386 | }; |
|
386 | }; | |
387 |
|
387 | |||
388 |
|
388 | |||
389 | CodeCell.prototype.expand_output = function () { |
|
389 | CodeCell.prototype.expand_output = function () { | |
390 | this.output_area.expand(); |
|
390 | this.output_area.expand(); | |
391 | this.output_area.unscroll_area(); |
|
391 | this.output_area.unscroll_area(); | |
392 | }; |
|
392 | }; | |
393 |
|
393 | |||
394 | CodeCell.prototype.scroll_output = function () { |
|
394 | CodeCell.prototype.scroll_output = function () { | |
395 | this.output_area.expand(); |
|
395 | this.output_area.expand(); | |
396 | this.output_area.scroll_if_long(); |
|
396 | this.output_area.scroll_if_long(); | |
397 | }; |
|
397 | }; | |
398 |
|
398 | |||
399 | CodeCell.prototype.toggle_output = function () { |
|
399 | CodeCell.prototype.toggle_output = function () { | |
400 | this.output_area.toggle_output(); |
|
400 | this.output_area.toggle_output(); | |
401 | }; |
|
401 | }; | |
402 |
|
402 | |||
403 | CodeCell.prototype.toggle_output_scroll = function () { |
|
403 | CodeCell.prototype.toggle_output_scroll = function () { | |
404 | this.output_area.toggle_scroll(); |
|
404 | this.output_area.toggle_scroll(); | |
405 | }; |
|
405 | }; | |
406 |
|
406 | |||
407 |
|
407 | |||
408 | CodeCell.input_prompt_classical = function (prompt_value, lines_number) { |
|
408 | CodeCell.input_prompt_classical = function (prompt_value, lines_number) { | |
409 | var ns; |
|
409 | var ns; | |
410 | if (prompt_value === undefined || prompt_value === null) { |
|
410 | if (prompt_value === undefined || prompt_value === null) { | |
411 | ns = " "; |
|
411 | ns = " "; | |
412 | } else { |
|
412 | } else { | |
413 | ns = encodeURIComponent(prompt_value); |
|
413 | ns = encodeURIComponent(prompt_value); | |
414 | } |
|
414 | } | |
415 | return 'In [' + ns + ']:'; |
|
415 | return 'In [' + ns + ']:'; | |
416 | }; |
|
416 | }; | |
417 |
|
417 | |||
418 | CodeCell.input_prompt_continuation = function (prompt_value, lines_number) { |
|
418 | CodeCell.input_prompt_continuation = function (prompt_value, lines_number) { | |
419 | var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)]; |
|
419 | var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)]; | |
420 | for(var i=1; i < lines_number; i++) { |
|
420 | for(var i=1; i < lines_number; i++) { | |
421 | html.push(['...:']); |
|
421 | html.push(['...:']); | |
422 | } |
|
422 | } | |
423 | return html.join('<br/>'); |
|
423 | return html.join('<br/>'); | |
424 | }; |
|
424 | }; | |
425 |
|
425 | |||
426 | CodeCell.input_prompt_function = CodeCell.input_prompt_classical; |
|
426 | CodeCell.input_prompt_function = CodeCell.input_prompt_classical; | |
427 |
|
427 | |||
428 |
|
428 | |||
429 | CodeCell.prototype.set_input_prompt = function (number) { |
|
429 | CodeCell.prototype.set_input_prompt = function (number) { | |
430 | var nline = 1; |
|
430 | var nline = 1; | |
431 | if (this.code_mirror !== undefined) { |
|
431 | if (this.code_mirror !== undefined) { | |
432 | nline = this.code_mirror.lineCount(); |
|
432 | nline = this.code_mirror.lineCount(); | |
433 | } |
|
433 | } | |
434 | this.input_prompt_number = number; |
|
434 | this.input_prompt_number = number; | |
435 | var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline); |
|
435 | var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline); | |
436 | // This HTML call is okay because the user contents are escaped. |
|
436 | // This HTML call is okay because the user contents are escaped. | |
437 | this.element.find('div.input_prompt').html(prompt_html); |
|
437 | this.element.find('div.input_prompt').html(prompt_html); | |
438 | }; |
|
438 | }; | |
439 |
|
439 | |||
440 |
|
440 | |||
441 | CodeCell.prototype.clear_input = function () { |
|
441 | CodeCell.prototype.clear_input = function () { | |
442 | this.code_mirror.setValue(''); |
|
442 | this.code_mirror.setValue(''); | |
443 | }; |
|
443 | }; | |
444 |
|
444 | |||
445 |
|
445 | |||
446 | CodeCell.prototype.get_text = function () { |
|
446 | CodeCell.prototype.get_text = function () { | |
447 | return this.code_mirror.getValue(); |
|
447 | return this.code_mirror.getValue(); | |
448 | }; |
|
448 | }; | |
449 |
|
449 | |||
450 |
|
450 | |||
451 | CodeCell.prototype.set_text = function (code) { |
|
451 | CodeCell.prototype.set_text = function (code) { | |
452 | return this.code_mirror.setValue(code); |
|
452 | return this.code_mirror.setValue(code); | |
453 | }; |
|
453 | }; | |
454 |
|
454 | |||
455 |
|
455 | |||
456 | CodeCell.prototype.clear_output = function (wait) { |
|
456 | CodeCell.prototype.clear_output = function (wait) { | |
457 | this.output_area.clear_output(wait); |
|
457 | this.output_area.clear_output(wait); | |
458 | this.set_input_prompt(); |
|
458 | this.set_input_prompt(); | |
459 | }; |
|
459 | }; | |
460 |
|
460 | |||
461 |
|
461 | |||
462 | // JSON serialization |
|
462 | // JSON serialization | |
463 |
|
463 | |||
464 | CodeCell.prototype.fromJSON = function (data) { |
|
464 | CodeCell.prototype.fromJSON = function (data) { | |
465 | Cell.prototype.fromJSON.apply(this, arguments); |
|
465 | Cell.prototype.fromJSON.apply(this, arguments); | |
466 | if (data.cell_type === 'code') { |
|
466 | if (data.cell_type === 'code') { | |
467 | if (data.source !== undefined) { |
|
467 | if (data.source !== undefined) { | |
468 | this.set_text(data.source); |
|
468 | this.set_text(data.source); | |
469 | // 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 | |
470 | // to this state, instead of a blank cell |
|
470 | // to this state, instead of a blank cell | |
471 | this.code_mirror.clearHistory(); |
|
471 | this.code_mirror.clearHistory(); | |
472 | this.auto_highlight(); |
|
472 | this.auto_highlight(); | |
473 | } |
|
473 | } | |
474 |
this.set_input_prompt(data. |
|
474 | this.set_input_prompt(data.execution_count); | |
475 | this.output_area.trusted = data.metadata.trusted || false; |
|
475 | this.output_area.trusted = data.metadata.trusted || false; | |
476 | this.output_area.fromJSON(data.outputs); |
|
476 | this.output_area.fromJSON(data.outputs); | |
477 | if (data.metadata.collapsed !== undefined) { |
|
477 | if (data.metadata.collapsed !== undefined) { | |
478 | if (data.metadata.collapsed) { |
|
478 | if (data.metadata.collapsed) { | |
479 | this.collapse_output(); |
|
479 | this.collapse_output(); | |
480 | } else { |
|
480 | } else { | |
481 | this.expand_output(); |
|
481 | this.expand_output(); | |
482 | } |
|
482 | } | |
483 | } |
|
483 | } | |
484 | } |
|
484 | } | |
485 | }; |
|
485 | }; | |
486 |
|
486 | |||
487 |
|
487 | |||
488 | CodeCell.prototype.toJSON = function () { |
|
488 | CodeCell.prototype.toJSON = function () { | |
489 | var data = Cell.prototype.toJSON.apply(this); |
|
489 | var data = Cell.prototype.toJSON.apply(this); | |
490 | data.source = this.get_text(); |
|
490 | data.source = this.get_text(); | |
491 | // is finite protect against undefined and '*' value |
|
491 | // is finite protect against undefined and '*' value | |
492 | if (isFinite(this.input_prompt_number)) { |
|
492 | if (isFinite(this.input_prompt_number)) { | |
493 |
data. |
|
493 | data.execution_count = this.input_prompt_number; | |
494 | } else { |
|
494 | } else { | |
495 |
data. |
|
495 | data.execution_count = null; | |
496 | } |
|
496 | } | |
497 | var outputs = this.output_area.toJSON(); |
|
497 | var outputs = this.output_area.toJSON(); | |
498 | data.outputs = outputs; |
|
498 | data.outputs = outputs; | |
499 | data.metadata.trusted = this.output_area.trusted; |
|
499 | data.metadata.trusted = this.output_area.trusted; | |
500 | data.metadata.collapsed = this.output_area.collapsed; |
|
500 | data.metadata.collapsed = this.output_area.collapsed; | |
501 | return data; |
|
501 | return data; | |
502 | }; |
|
502 | }; | |
503 |
|
503 | |||
504 | /** |
|
504 | /** | |
505 | * handle cell level logic when a cell is unselected |
|
505 | * handle cell level logic when a cell is unselected | |
506 | * @method unselect |
|
506 | * @method unselect | |
507 | * @return is the action being taken |
|
507 | * @return is the action being taken | |
508 | */ |
|
508 | */ | |
509 | CodeCell.prototype.unselect = function () { |
|
509 | CodeCell.prototype.unselect = function () { | |
510 | var cont = Cell.prototype.unselect.apply(this); |
|
510 | var cont = Cell.prototype.unselect.apply(this); | |
511 | if (cont) { |
|
511 | if (cont) { | |
512 | // When a code cell is usnelected, make sure that the corresponding |
|
512 | // When a code cell is usnelected, make sure that the corresponding | |
513 | // tooltip and completer to that cell is closed. |
|
513 | // tooltip and completer to that cell is closed. | |
514 | this.tooltip.remove_and_cancel_tooltip(true); |
|
514 | this.tooltip.remove_and_cancel_tooltip(true); | |
515 | if (this.completer !== null) { |
|
515 | if (this.completer !== null) { | |
516 | this.completer.close(); |
|
516 | this.completer.close(); | |
517 | } |
|
517 | } | |
518 | } |
|
518 | } | |
519 | return cont; |
|
519 | return cont; | |
520 | }; |
|
520 | }; | |
521 |
|
521 | |||
522 | // Backwards compatability. |
|
522 | // Backwards compatability. | |
523 | IPython.CodeCell = CodeCell; |
|
523 | IPython.CodeCell = CodeCell; | |
524 |
|
524 | |||
525 | return {'CodeCell': CodeCell}; |
|
525 | return {'CodeCell': CodeCell}; | |
526 | }); |
|
526 | }); |
@@ -1,941 +1,941 | |||||
1 | // Copyright (c) IPython Development Team. |
|
1 | // Copyright (c) IPython Development Team. | |
2 | // Distributed under the terms of the Modified BSD License. |
|
2 | // Distributed under the terms of the Modified BSD License. | |
3 |
|
3 | |||
4 | define([ |
|
4 | define([ | |
5 | 'base/js/namespace', |
|
5 | 'base/js/namespace', | |
6 | 'jqueryui', |
|
6 | 'jqueryui', | |
7 | 'base/js/utils', |
|
7 | 'base/js/utils', | |
8 | 'base/js/security', |
|
8 | 'base/js/security', | |
9 | 'base/js/keyboard', |
|
9 | 'base/js/keyboard', | |
10 | 'notebook/js/mathjaxutils', |
|
10 | 'notebook/js/mathjaxutils', | |
11 | 'components/marked/lib/marked', |
|
11 | 'components/marked/lib/marked', | |
12 | ], function(IPython, $, utils, security, keyboard, mathjaxutils, marked) { |
|
12 | ], function(IPython, $, utils, security, keyboard, mathjaxutils, marked) { | |
13 | "use strict"; |
|
13 | "use strict"; | |
14 |
|
14 | |||
15 | /** |
|
15 | /** | |
16 | * @class OutputArea |
|
16 | * @class OutputArea | |
17 | * |
|
17 | * | |
18 | * @constructor |
|
18 | * @constructor | |
19 | */ |
|
19 | */ | |
20 |
|
20 | |||
21 | var OutputArea = function (options) { |
|
21 | var OutputArea = function (options) { | |
22 | this.selector = options.selector; |
|
22 | this.selector = options.selector; | |
23 | this.events = options.events; |
|
23 | this.events = options.events; | |
24 | this.keyboard_manager = options.keyboard_manager; |
|
24 | this.keyboard_manager = options.keyboard_manager; | |
25 | this.wrapper = $(options.selector); |
|
25 | this.wrapper = $(options.selector); | |
26 | this.outputs = []; |
|
26 | this.outputs = []; | |
27 | this.collapsed = false; |
|
27 | this.collapsed = false; | |
28 | this.scrolled = false; |
|
28 | this.scrolled = false; | |
29 | this.trusted = true; |
|
29 | this.trusted = true; | |
30 | this.clear_queued = null; |
|
30 | this.clear_queued = null; | |
31 | if (options.prompt_area === undefined) { |
|
31 | if (options.prompt_area === undefined) { | |
32 | this.prompt_area = true; |
|
32 | this.prompt_area = true; | |
33 | } else { |
|
33 | } else { | |
34 | this.prompt_area = options.prompt_area; |
|
34 | this.prompt_area = options.prompt_area; | |
35 | } |
|
35 | } | |
36 | this.create_elements(); |
|
36 | this.create_elements(); | |
37 | this.style(); |
|
37 | this.style(); | |
38 | this.bind_events(); |
|
38 | this.bind_events(); | |
39 | }; |
|
39 | }; | |
40 |
|
40 | |||
41 |
|
41 | |||
42 | /** |
|
42 | /** | |
43 | * Class prototypes |
|
43 | * Class prototypes | |
44 | **/ |
|
44 | **/ | |
45 |
|
45 | |||
46 | OutputArea.prototype.create_elements = function () { |
|
46 | OutputArea.prototype.create_elements = function () { | |
47 | this.element = $("<div/>"); |
|
47 | this.element = $("<div/>"); | |
48 | this.collapse_button = $("<div/>"); |
|
48 | this.collapse_button = $("<div/>"); | |
49 | this.prompt_overlay = $("<div/>"); |
|
49 | this.prompt_overlay = $("<div/>"); | |
50 | this.wrapper.append(this.prompt_overlay); |
|
50 | this.wrapper.append(this.prompt_overlay); | |
51 | this.wrapper.append(this.element); |
|
51 | this.wrapper.append(this.element); | |
52 | this.wrapper.append(this.collapse_button); |
|
52 | this.wrapper.append(this.collapse_button); | |
53 | }; |
|
53 | }; | |
54 |
|
54 | |||
55 |
|
55 | |||
56 | OutputArea.prototype.style = function () { |
|
56 | OutputArea.prototype.style = function () { | |
57 | this.collapse_button.hide(); |
|
57 | this.collapse_button.hide(); | |
58 | this.prompt_overlay.hide(); |
|
58 | this.prompt_overlay.hide(); | |
59 |
|
59 | |||
60 | this.wrapper.addClass('output_wrapper'); |
|
60 | this.wrapper.addClass('output_wrapper'); | |
61 | this.element.addClass('output'); |
|
61 | this.element.addClass('output'); | |
62 |
|
62 | |||
63 | this.collapse_button.addClass("btn btn-default output_collapsed"); |
|
63 | this.collapse_button.addClass("btn btn-default output_collapsed"); | |
64 | this.collapse_button.attr('title', 'click to expand output'); |
|
64 | this.collapse_button.attr('title', 'click to expand output'); | |
65 | this.collapse_button.text('. . .'); |
|
65 | this.collapse_button.text('. . .'); | |
66 |
|
66 | |||
67 | this.prompt_overlay.addClass('out_prompt_overlay prompt'); |
|
67 | this.prompt_overlay.addClass('out_prompt_overlay prompt'); | |
68 | this.prompt_overlay.attr('title', 'click to expand output; double click to hide output'); |
|
68 | this.prompt_overlay.attr('title', 'click to expand output; double click to hide output'); | |
69 |
|
69 | |||
70 | this.collapse(); |
|
70 | this.collapse(); | |
71 | }; |
|
71 | }; | |
72 |
|
72 | |||
73 | /** |
|
73 | /** | |
74 | * Should the OutputArea scroll? |
|
74 | * Should the OutputArea scroll? | |
75 | * Returns whether the height (in lines) exceeds a threshold. |
|
75 | * Returns whether the height (in lines) exceeds a threshold. | |
76 | * |
|
76 | * | |
77 | * @private |
|
77 | * @private | |
78 | * @method _should_scroll |
|
78 | * @method _should_scroll | |
79 | * @param [lines=100]{Integer} |
|
79 | * @param [lines=100]{Integer} | |
80 | * @return {Bool} |
|
80 | * @return {Bool} | |
81 | * |
|
81 | * | |
82 | */ |
|
82 | */ | |
83 | OutputArea.prototype._should_scroll = function (lines) { |
|
83 | OutputArea.prototype._should_scroll = function (lines) { | |
84 | if (lines <=0 ){ return } |
|
84 | if (lines <=0 ){ return } | |
85 | if (!lines) { |
|
85 | if (!lines) { | |
86 | lines = 100; |
|
86 | lines = 100; | |
87 | } |
|
87 | } | |
88 | // line-height from http://stackoverflow.com/questions/1185151 |
|
88 | // line-height from http://stackoverflow.com/questions/1185151 | |
89 | var fontSize = this.element.css('font-size'); |
|
89 | var fontSize = this.element.css('font-size'); | |
90 | var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5); |
|
90 | var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5); | |
91 |
|
91 | |||
92 | return (this.element.height() > lines * lineHeight); |
|
92 | return (this.element.height() > lines * lineHeight); | |
93 | }; |
|
93 | }; | |
94 |
|
94 | |||
95 |
|
95 | |||
96 | OutputArea.prototype.bind_events = function () { |
|
96 | OutputArea.prototype.bind_events = function () { | |
97 | var that = this; |
|
97 | var that = this; | |
98 | this.prompt_overlay.dblclick(function () { that.toggle_output(); }); |
|
98 | this.prompt_overlay.dblclick(function () { that.toggle_output(); }); | |
99 | this.prompt_overlay.click(function () { that.toggle_scroll(); }); |
|
99 | this.prompt_overlay.click(function () { that.toggle_scroll(); }); | |
100 |
|
100 | |||
101 | this.element.resize(function () { |
|
101 | this.element.resize(function () { | |
102 | // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled |
|
102 | // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled | |
103 | if ( utils.browser[0] === "Firefox" ) { |
|
103 | if ( utils.browser[0] === "Firefox" ) { | |
104 | return; |
|
104 | return; | |
105 | } |
|
105 | } | |
106 | // maybe scroll output, |
|
106 | // maybe scroll output, | |
107 | // if it's grown large enough and hasn't already been scrolled. |
|
107 | // if it's grown large enough and hasn't already been scrolled. | |
108 | if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) { |
|
108 | if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) { | |
109 | that.scroll_area(); |
|
109 | that.scroll_area(); | |
110 | } |
|
110 | } | |
111 | }); |
|
111 | }); | |
112 | this.collapse_button.click(function () { |
|
112 | this.collapse_button.click(function () { | |
113 | that.expand(); |
|
113 | that.expand(); | |
114 | }); |
|
114 | }); | |
115 | }; |
|
115 | }; | |
116 |
|
116 | |||
117 |
|
117 | |||
118 | OutputArea.prototype.collapse = function () { |
|
118 | OutputArea.prototype.collapse = function () { | |
119 | if (!this.collapsed) { |
|
119 | if (!this.collapsed) { | |
120 | this.element.hide(); |
|
120 | this.element.hide(); | |
121 | this.prompt_overlay.hide(); |
|
121 | this.prompt_overlay.hide(); | |
122 | if (this.element.html()){ |
|
122 | if (this.element.html()){ | |
123 | this.collapse_button.show(); |
|
123 | this.collapse_button.show(); | |
124 | } |
|
124 | } | |
125 | this.collapsed = true; |
|
125 | this.collapsed = true; | |
126 | } |
|
126 | } | |
127 | }; |
|
127 | }; | |
128 |
|
128 | |||
129 |
|
129 | |||
130 | OutputArea.prototype.expand = function () { |
|
130 | OutputArea.prototype.expand = function () { | |
131 | if (this.collapsed) { |
|
131 | if (this.collapsed) { | |
132 | this.collapse_button.hide(); |
|
132 | this.collapse_button.hide(); | |
133 | this.element.show(); |
|
133 | this.element.show(); | |
134 | this.prompt_overlay.show(); |
|
134 | this.prompt_overlay.show(); | |
135 | this.collapsed = false; |
|
135 | this.collapsed = false; | |
136 | } |
|
136 | } | |
137 | }; |
|
137 | }; | |
138 |
|
138 | |||
139 |
|
139 | |||
140 | OutputArea.prototype.toggle_output = function () { |
|
140 | OutputArea.prototype.toggle_output = function () { | |
141 | if (this.collapsed) { |
|
141 | if (this.collapsed) { | |
142 | this.expand(); |
|
142 | this.expand(); | |
143 | } else { |
|
143 | } else { | |
144 | this.collapse(); |
|
144 | this.collapse(); | |
145 | } |
|
145 | } | |
146 | }; |
|
146 | }; | |
147 |
|
147 | |||
148 |
|
148 | |||
149 | OutputArea.prototype.scroll_area = function () { |
|
149 | OutputArea.prototype.scroll_area = function () { | |
150 | this.element.addClass('output_scroll'); |
|
150 | this.element.addClass('output_scroll'); | |
151 | this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide'); |
|
151 | this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide'); | |
152 | this.scrolled = true; |
|
152 | this.scrolled = true; | |
153 | }; |
|
153 | }; | |
154 |
|
154 | |||
155 |
|
155 | |||
156 | OutputArea.prototype.unscroll_area = function () { |
|
156 | OutputArea.prototype.unscroll_area = function () { | |
157 | this.element.removeClass('output_scroll'); |
|
157 | this.element.removeClass('output_scroll'); | |
158 | this.prompt_overlay.attr('title', 'click to scroll output; double click to hide'); |
|
158 | this.prompt_overlay.attr('title', 'click to scroll output; double click to hide'); | |
159 | this.scrolled = false; |
|
159 | this.scrolled = false; | |
160 | }; |
|
160 | }; | |
161 |
|
161 | |||
162 | /** |
|
162 | /** | |
163 | * |
|
163 | * | |
164 | * Scroll OutputArea if height supperior than a threshold (in lines). |
|
164 | * Scroll OutputArea if height supperior than a threshold (in lines). | |
165 | * |
|
165 | * | |
166 | * Threshold is a maximum number of lines. If unspecified, defaults to |
|
166 | * Threshold is a maximum number of lines. If unspecified, defaults to | |
167 | * OutputArea.minimum_scroll_threshold. |
|
167 | * OutputArea.minimum_scroll_threshold. | |
168 | * |
|
168 | * | |
169 | * Negative threshold will prevent the OutputArea from ever scrolling. |
|
169 | * Negative threshold will prevent the OutputArea from ever scrolling. | |
170 | * |
|
170 | * | |
171 | * @method scroll_if_long |
|
171 | * @method scroll_if_long | |
172 | * |
|
172 | * | |
173 | * @param [lines=20]{Number} Default to 20 if not set, |
|
173 | * @param [lines=20]{Number} Default to 20 if not set, | |
174 | * behavior undefined for value of `0`. |
|
174 | * behavior undefined for value of `0`. | |
175 | * |
|
175 | * | |
176 | **/ |
|
176 | **/ | |
177 | OutputArea.prototype.scroll_if_long = function (lines) { |
|
177 | OutputArea.prototype.scroll_if_long = function (lines) { | |
178 | var n = lines | OutputArea.minimum_scroll_threshold; |
|
178 | var n = lines | OutputArea.minimum_scroll_threshold; | |
179 | if(n <= 0){ |
|
179 | if(n <= 0){ | |
180 | return |
|
180 | return | |
181 | } |
|
181 | } | |
182 |
|
182 | |||
183 | if (this._should_scroll(n)) { |
|
183 | if (this._should_scroll(n)) { | |
184 | // only allow scrolling long-enough output |
|
184 | // only allow scrolling long-enough output | |
185 | this.scroll_area(); |
|
185 | this.scroll_area(); | |
186 | } |
|
186 | } | |
187 | }; |
|
187 | }; | |
188 |
|
188 | |||
189 |
|
189 | |||
190 | OutputArea.prototype.toggle_scroll = function () { |
|
190 | OutputArea.prototype.toggle_scroll = function () { | |
191 | if (this.scrolled) { |
|
191 | if (this.scrolled) { | |
192 | this.unscroll_area(); |
|
192 | this.unscroll_area(); | |
193 | } else { |
|
193 | } else { | |
194 | // only allow scrolling long-enough output |
|
194 | // only allow scrolling long-enough output | |
195 | this.scroll_if_long(); |
|
195 | this.scroll_if_long(); | |
196 | } |
|
196 | } | |
197 | }; |
|
197 | }; | |
198 |
|
198 | |||
199 |
|
199 | |||
200 | // typeset with MathJax if MathJax is available |
|
200 | // typeset with MathJax if MathJax is available | |
201 | OutputArea.prototype.typeset = function () { |
|
201 | OutputArea.prototype.typeset = function () { | |
202 | if (window.MathJax){ |
|
202 | if (window.MathJax){ | |
203 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
203 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
204 | } |
|
204 | } | |
205 | }; |
|
205 | }; | |
206 |
|
206 | |||
207 |
|
207 | |||
208 | OutputArea.prototype.handle_output = function (msg) { |
|
208 | OutputArea.prototype.handle_output = function (msg) { | |
209 | var json = {}; |
|
209 | var json = {}; | |
210 | var msg_type = json.output_type = msg.header.msg_type; |
|
210 | var msg_type = json.output_type = msg.header.msg_type; | |
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.name = 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; | |
218 | json.metadata = content.metadata; |
|
218 | json.metadata = content.metadata; | |
219 | } else if (msg_type === "execute_result") { |
|
219 | } else if (msg_type === "execute_result") { | |
220 | json = content.data; |
|
220 | json = content.data; | |
221 | json.output_type = msg_type; |
|
221 | json.output_type = msg_type; | |
222 | json.metadata = content.metadata; |
|
222 | json.metadata = content.metadata; | |
223 |
json. |
|
223 | json.execution_count = content.execution_count; | |
224 | } else if (msg_type === "error") { |
|
224 | } else if (msg_type === "error") { | |
225 | json.ename = content.ename; |
|
225 | json.ename = content.ename; | |
226 | json.evalue = content.evalue; |
|
226 | json.evalue = content.evalue; | |
227 | json.traceback = content.traceback; |
|
227 | json.traceback = content.traceback; | |
228 | } else { |
|
228 | } else { | |
229 | console.log("unhandled output message", msg); |
|
229 | console.log("unhandled output message", msg); | |
230 | return; |
|
230 | return; | |
231 | } |
|
231 | } | |
232 | this.append_output(json); |
|
232 | this.append_output(json); | |
233 | }; |
|
233 | }; | |
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 | // TODO: This is now unused, should it be removed? | |
238 | var remapped = {}; |
|
238 | var remapped = {}; | |
239 | for (var key in data) { |
|
239 | for (var key in data) { | |
240 | var new_key = key_map[key] || key; |
|
240 | var new_key = key_map[key] || key; | |
241 | remapped[new_key] = data[key]; |
|
241 | remapped[new_key] = data[key]; | |
242 | } |
|
242 | } | |
243 | return remapped; |
|
243 | return remapped; | |
244 | }; |
|
244 | }; | |
245 |
|
245 | |||
246 |
|
246 | |||
247 | OutputArea.output_types = [ |
|
247 | OutputArea.output_types = [ | |
248 | 'application/javascript', |
|
248 | 'application/javascript', | |
249 | 'text/html', |
|
249 | 'text/html', | |
250 | 'text/markdown', |
|
250 | 'text/markdown', | |
251 | 'text/latex', |
|
251 | 'text/latex', | |
252 | 'image/svg+xml', |
|
252 | 'image/svg+xml', | |
253 | 'image/png', |
|
253 | 'image/png', | |
254 | 'image/jpeg', |
|
254 | 'image/jpeg', | |
255 | 'application/pdf', |
|
255 | 'application/pdf', | |
256 | 'text/plain' |
|
256 | 'text/plain' | |
257 | ]; |
|
257 | ]; | |
258 |
|
258 | |||
259 | OutputArea.prototype.validate_output = function (json) { |
|
259 | OutputArea.prototype.validate_output = function (json) { | |
260 | // scrub invalid outputs |
|
260 | // scrub invalid outputs | |
261 | // 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. | |
262 | // nbformat 4 will fix that. |
|
262 | // nbformat 4 will fix that. | |
263 | $.map(OutputArea.output_types, function(key){ |
|
263 | $.map(OutputArea.output_types, function(key){ | |
264 | if (key !== 'application/json' && |
|
264 | if (key !== 'application/json' && | |
265 | json[key] !== undefined && |
|
265 | json[key] !== undefined && | |
266 | typeof json[key] !== 'string' |
|
266 | typeof json[key] !== 'string' | |
267 | ) { |
|
267 | ) { | |
268 | console.log("Invalid type for " + key, json[key]); |
|
268 | console.log("Invalid type for " + key, json[key]); | |
269 | delete json[key]; |
|
269 | delete json[key]; | |
270 | } |
|
270 | } | |
271 | }); |
|
271 | }); | |
272 | return json; |
|
272 | return json; | |
273 | }; |
|
273 | }; | |
274 |
|
274 | |||
275 | OutputArea.prototype.append_output = function (json) { |
|
275 | OutputArea.prototype.append_output = function (json) { | |
276 | this.expand(); |
|
276 | this.expand(); | |
277 |
|
277 | |||
278 | // validate output data types |
|
278 | // validate output data types | |
279 | json = this.validate_output(json); |
|
279 | json = this.validate_output(json); | |
280 |
|
280 | |||
281 | // Clear the output if clear is queued. |
|
281 | // Clear the output if clear is queued. | |
282 | var needs_height_reset = false; |
|
282 | var needs_height_reset = false; | |
283 | if (this.clear_queued) { |
|
283 | if (this.clear_queued) { | |
284 | this.clear_output(false); |
|
284 | this.clear_output(false); | |
285 | needs_height_reset = true; |
|
285 | needs_height_reset = true; | |
286 | } |
|
286 | } | |
287 |
|
287 | |||
288 | var record_output = true; |
|
288 | var record_output = true; | |
289 |
|
289 | |||
290 | if (json.output_type === 'execute_result') { |
|
290 | if (json.output_type === 'execute_result') { | |
291 | this.append_execute_result(json); |
|
291 | this.append_execute_result(json); | |
292 | } else if (json.output_type === 'error') { |
|
292 | } else if (json.output_type === 'error') { | |
293 | this.append_error(json); |
|
293 | this.append_error(json); | |
294 | } else if (json.output_type === 'stream') { |
|
294 | } else if (json.output_type === 'stream') { | |
295 | // append_stream might have merged the output with earlier stream output |
|
295 | // append_stream might have merged the output with earlier stream output | |
296 | record_output = this.append_stream(json); |
|
296 | record_output = this.append_stream(json); | |
297 | } |
|
297 | } | |
298 |
|
298 | |||
299 | // We must release the animation fixed height in a callback since Gecko |
|
299 | // We must release the animation fixed height in a callback since Gecko | |
300 | // (FireFox) doesn't render the image immediately as the data is |
|
300 | // (FireFox) doesn't render the image immediately as the data is | |
301 | // available. |
|
301 | // available. | |
302 | var that = this; |
|
302 | var that = this; | |
303 | var handle_appended = function ($el) { |
|
303 | var handle_appended = function ($el) { | |
304 | // Only reset the height to automatic if the height is currently |
|
304 | // Only reset the height to automatic if the height is currently | |
305 | // fixed (done by wait=True flag on clear_output). |
|
305 | // fixed (done by wait=True flag on clear_output). | |
306 | if (needs_height_reset) { |
|
306 | if (needs_height_reset) { | |
307 | that.element.height(''); |
|
307 | that.element.height(''); | |
308 | } |
|
308 | } | |
309 | that.element.trigger('resize'); |
|
309 | that.element.trigger('resize'); | |
310 | }; |
|
310 | }; | |
311 | if (json.output_type === 'display_data') { |
|
311 | if (json.output_type === 'display_data') { | |
312 | this.append_display_data(json, handle_appended); |
|
312 | this.append_display_data(json, handle_appended); | |
313 | } else { |
|
313 | } else { | |
314 | handle_appended(); |
|
314 | handle_appended(); | |
315 | } |
|
315 | } | |
316 |
|
316 | |||
317 | if (record_output) { |
|
317 | if (record_output) { | |
318 | this.outputs.push(json); |
|
318 | this.outputs.push(json); | |
319 | } |
|
319 | } | |
320 | }; |
|
320 | }; | |
321 |
|
321 | |||
322 |
|
322 | |||
323 | OutputArea.prototype.create_output_area = function () { |
|
323 | OutputArea.prototype.create_output_area = function () { | |
324 | var oa = $("<div/>").addClass("output_area"); |
|
324 | var oa = $("<div/>").addClass("output_area"); | |
325 | if (this.prompt_area) { |
|
325 | if (this.prompt_area) { | |
326 | oa.append($('<div/>').addClass('prompt')); |
|
326 | oa.append($('<div/>').addClass('prompt')); | |
327 | } |
|
327 | } | |
328 | return oa; |
|
328 | return oa; | |
329 | }; |
|
329 | }; | |
330 |
|
330 | |||
331 |
|
331 | |||
332 | function _get_metadata_key(metadata, key, mime) { |
|
332 | function _get_metadata_key(metadata, key, mime) { | |
333 | var mime_md = metadata[mime]; |
|
333 | var mime_md = metadata[mime]; | |
334 | // mime-specific higher priority |
|
334 | // mime-specific higher priority | |
335 | if (mime_md && mime_md[key] !== undefined) { |
|
335 | if (mime_md && mime_md[key] !== undefined) { | |
336 | return mime_md[key]; |
|
336 | return mime_md[key]; | |
337 | } |
|
337 | } | |
338 | // fallback on global |
|
338 | // fallback on global | |
339 | return metadata[key]; |
|
339 | return metadata[key]; | |
340 | } |
|
340 | } | |
341 |
|
341 | |||
342 | OutputArea.prototype.create_output_subarea = function(md, classes, mime) { |
|
342 | OutputArea.prototype.create_output_subarea = function(md, classes, mime) { | |
343 | var subarea = $('<div/>').addClass('output_subarea').addClass(classes); |
|
343 | var subarea = $('<div/>').addClass('output_subarea').addClass(classes); | |
344 | if (_get_metadata_key(md, 'isolated', mime)) { |
|
344 | if (_get_metadata_key(md, 'isolated', mime)) { | |
345 | // Create an iframe to isolate the subarea from the rest of the |
|
345 | // Create an iframe to isolate the subarea from the rest of the | |
346 | // document |
|
346 | // document | |
347 | var iframe = $('<iframe/>').addClass('box-flex1'); |
|
347 | var iframe = $('<iframe/>').addClass('box-flex1'); | |
348 | iframe.css({'height':1, 'width':'100%', 'display':'block'}); |
|
348 | iframe.css({'height':1, 'width':'100%', 'display':'block'}); | |
349 | iframe.attr('frameborder', 0); |
|
349 | iframe.attr('frameborder', 0); | |
350 | iframe.attr('scrolling', 'auto'); |
|
350 | iframe.attr('scrolling', 'auto'); | |
351 |
|
351 | |||
352 | // Once the iframe is loaded, the subarea is dynamically inserted |
|
352 | // Once the iframe is loaded, the subarea is dynamically inserted | |
353 | iframe.on('load', function() { |
|
353 | iframe.on('load', function() { | |
354 | // Workaround needed by Firefox, to properly render svg inside |
|
354 | // Workaround needed by Firefox, to properly render svg inside | |
355 | // iframes, see http://stackoverflow.com/questions/10177190/ |
|
355 | // iframes, see http://stackoverflow.com/questions/10177190/ | |
356 | // svg-dynamically-added-to-iframe-does-not-render-correctly |
|
356 | // svg-dynamically-added-to-iframe-does-not-render-correctly | |
357 | this.contentDocument.open(); |
|
357 | this.contentDocument.open(); | |
358 |
|
358 | |||
359 | // Insert the subarea into the iframe |
|
359 | // Insert the subarea into the iframe | |
360 | // We must directly write the html. When using Jquery's append |
|
360 | // We must directly write the html. When using Jquery's append | |
361 | // method, javascript is evaluated in the parent document and |
|
361 | // method, javascript is evaluated in the parent document and | |
362 | // not in the iframe document. At this point, subarea doesn't |
|
362 | // not in the iframe document. At this point, subarea doesn't | |
363 | // contain any user content. |
|
363 | // contain any user content. | |
364 | this.contentDocument.write(subarea.html()); |
|
364 | this.contentDocument.write(subarea.html()); | |
365 |
|
365 | |||
366 | this.contentDocument.close(); |
|
366 | this.contentDocument.close(); | |
367 |
|
367 | |||
368 | var body = this.contentDocument.body; |
|
368 | var body = this.contentDocument.body; | |
369 | // Adjust the iframe height automatically |
|
369 | // Adjust the iframe height automatically | |
370 | iframe.height(body.scrollHeight + 'px'); |
|
370 | iframe.height(body.scrollHeight + 'px'); | |
371 | }); |
|
371 | }); | |
372 |
|
372 | |||
373 | // Elements should be appended to the inner subarea and not to the |
|
373 | // Elements should be appended to the inner subarea and not to the | |
374 | // iframe |
|
374 | // iframe | |
375 | iframe.append = function(that) { |
|
375 | iframe.append = function(that) { | |
376 | subarea.append(that); |
|
376 | subarea.append(that); | |
377 | }; |
|
377 | }; | |
378 |
|
378 | |||
379 | return iframe; |
|
379 | return iframe; | |
380 | } else { |
|
380 | } else { | |
381 | return subarea; |
|
381 | return subarea; | |
382 | } |
|
382 | } | |
383 | } |
|
383 | } | |
384 |
|
384 | |||
385 |
|
385 | |||
386 | OutputArea.prototype._append_javascript_error = function (err, element) { |
|
386 | OutputArea.prototype._append_javascript_error = function (err, element) { | |
387 | // display a message when a javascript error occurs in display output |
|
387 | // display a message when a javascript error occurs in display output | |
388 | var msg = "Javascript error adding output!" |
|
388 | var msg = "Javascript error adding output!" | |
389 | if ( element === undefined ) return; |
|
389 | if ( element === undefined ) return; | |
390 | element |
|
390 | element | |
391 | .append($('<div/>').text(msg).addClass('js-error')) |
|
391 | .append($('<div/>').text(msg).addClass('js-error')) | |
392 | .append($('<div/>').text(err.toString()).addClass('js-error')) |
|
392 | .append($('<div/>').text(err.toString()).addClass('js-error')) | |
393 | .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error')); |
|
393 | .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error')); | |
394 | }; |
|
394 | }; | |
395 |
|
395 | |||
396 | OutputArea.prototype._safe_append = function (toinsert) { |
|
396 | OutputArea.prototype._safe_append = function (toinsert) { | |
397 | // safely append an item to the document |
|
397 | // safely append an item to the document | |
398 | // this is an object created by user code, |
|
398 | // this is an object created by user code, | |
399 | // and may have errors, which should not be raised |
|
399 | // and may have errors, which should not be raised | |
400 | // under any circumstances. |
|
400 | // under any circumstances. | |
401 | try { |
|
401 | try { | |
402 | this.element.append(toinsert); |
|
402 | this.element.append(toinsert); | |
403 | } catch(err) { |
|
403 | } catch(err) { | |
404 | console.log(err); |
|
404 | console.log(err); | |
405 | // Create an actual output_area and output_subarea, which creates |
|
405 | // Create an actual output_area and output_subarea, which creates | |
406 | // the prompt area and the proper indentation. |
|
406 | // the prompt area and the proper indentation. | |
407 | var toinsert = this.create_output_area(); |
|
407 | var toinsert = this.create_output_area(); | |
408 | var subarea = $('<div/>').addClass('output_subarea'); |
|
408 | var subarea = $('<div/>').addClass('output_subarea'); | |
409 | toinsert.append(subarea); |
|
409 | toinsert.append(subarea); | |
410 | this._append_javascript_error(err, subarea); |
|
410 | this._append_javascript_error(err, subarea); | |
411 | this.element.append(toinsert); |
|
411 | this.element.append(toinsert); | |
412 | } |
|
412 | } | |
413 | }; |
|
413 | }; | |
414 |
|
414 | |||
415 |
|
415 | |||
416 | OutputArea.prototype.append_execute_result = function (json) { |
|
416 | OutputArea.prototype.append_execute_result = function (json) { | |
417 |
var n = json. |
|
417 | var n = json.execution_count || ' '; | |
418 | var toinsert = this.create_output_area(); |
|
418 | var toinsert = this.create_output_area(); | |
419 | if (this.prompt_area) { |
|
419 | if (this.prompt_area) { | |
420 | toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:'); |
|
420 | toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:'); | |
421 | } |
|
421 | } | |
422 | var inserted = this.append_mime_type(json, toinsert); |
|
422 | var inserted = this.append_mime_type(json, toinsert); | |
423 | if (inserted) { |
|
423 | if (inserted) { | |
424 | inserted.addClass('output_result'); |
|
424 | inserted.addClass('output_result'); | |
425 | } |
|
425 | } | |
426 | this._safe_append(toinsert); |
|
426 | this._safe_append(toinsert); | |
427 | // If we just output latex, typeset it. |
|
427 | // If we just output latex, typeset it. | |
428 | if ((json['text/latex'] !== undefined) || |
|
428 | if ((json['text/latex'] !== undefined) || | |
429 | (json['text/html'] !== undefined) || |
|
429 | (json['text/html'] !== undefined) || | |
430 | (json['text/markdown'] !== undefined)) { |
|
430 | (json['text/markdown'] !== undefined)) { | |
431 | this.typeset(); |
|
431 | this.typeset(); | |
432 | } |
|
432 | } | |
433 | }; |
|
433 | }; | |
434 |
|
434 | |||
435 |
|
435 | |||
436 | OutputArea.prototype.append_error = function (json) { |
|
436 | OutputArea.prototype.append_error = function (json) { | |
437 | var tb = json.traceback; |
|
437 | var tb = json.traceback; | |
438 | if (tb !== undefined && tb.length > 0) { |
|
438 | if (tb !== undefined && tb.length > 0) { | |
439 | var s = ''; |
|
439 | var s = ''; | |
440 | var len = tb.length; |
|
440 | var len = tb.length; | |
441 | for (var i=0; i<len; i++) { |
|
441 | for (var i=0; i<len; i++) { | |
442 | s = s + tb[i] + '\n'; |
|
442 | s = s + tb[i] + '\n'; | |
443 | } |
|
443 | } | |
444 | s = s + '\n'; |
|
444 | s = s + '\n'; | |
445 | var toinsert = this.create_output_area(); |
|
445 | var toinsert = this.create_output_area(); | |
446 | var append_text = OutputArea.append_map['text/plain']; |
|
446 | var append_text = OutputArea.append_map['text/plain']; | |
447 | if (append_text) { |
|
447 | if (append_text) { | |
448 | append_text.apply(this, [s, {}, toinsert]).addClass('output_error'); |
|
448 | append_text.apply(this, [s, {}, toinsert]).addClass('output_error'); | |
449 | } |
|
449 | } | |
450 | this._safe_append(toinsert); |
|
450 | this._safe_append(toinsert); | |
451 | } |
|
451 | } | |
452 | }; |
|
452 | }; | |
453 |
|
453 | |||
454 |
|
454 | |||
455 | OutputArea.prototype.append_stream = function (json) { |
|
455 | OutputArea.prototype.append_stream = function (json) { | |
456 | var text = json.data; |
|
456 | var text = json.data; | |
457 | var subclass = "output_"+json.name; |
|
457 | var subclass = "output_"+json.name; | |
458 | if (this.outputs.length > 0){ |
|
458 | if (this.outputs.length > 0){ | |
459 | // have at least one output to consider |
|
459 | // have at least one output to consider | |
460 | var last = this.outputs[this.outputs.length-1]; |
|
460 | var last = this.outputs[this.outputs.length-1]; | |
461 | if (last.output_type == 'stream' && json.name == last.name){ |
|
461 | if (last.output_type == 'stream' && json.name == last.name){ | |
462 | // latest output was in the same stream, |
|
462 | // latest output was in the same stream, | |
463 | // so append directly into its pre tag |
|
463 | // so append directly into its pre tag | |
464 | // escape ANSI & HTML specials: |
|
464 | // escape ANSI & HTML specials: | |
465 | last.data = utils.fixCarriageReturn(last.data + json.data); |
|
465 | last.data = utils.fixCarriageReturn(last.data + json.data); | |
466 | var pre = this.element.find('div.'+subclass).last().find('pre'); |
|
466 | var pre = this.element.find('div.'+subclass).last().find('pre'); | |
467 | var html = utils.fixConsole(last.data); |
|
467 | var html = utils.fixConsole(last.data); | |
468 | // The only user content injected with this HTML call is |
|
468 | // The only user content injected with this HTML call is | |
469 | // escaped by the fixConsole() method. |
|
469 | // escaped by the fixConsole() method. | |
470 | pre.html(html); |
|
470 | pre.html(html); | |
471 | // return false signals that we merged this output with the previous one, |
|
471 | // return false signals that we merged this output with the previous one, | |
472 | // and the new output shouldn't be recorded. |
|
472 | // and the new output shouldn't be recorded. | |
473 | return false; |
|
473 | return false; | |
474 | } |
|
474 | } | |
475 | } |
|
475 | } | |
476 |
|
476 | |||
477 | if (!text.replace("\r", "")) { |
|
477 | if (!text.replace("\r", "")) { | |
478 | // text is nothing (empty string, \r, etc.) |
|
478 | // text is nothing (empty string, \r, etc.) | |
479 | // so don't append any elements, which might add undesirable space |
|
479 | // so don't append any elements, which might add undesirable space | |
480 | // return true to indicate the output should be recorded. |
|
480 | // return true to indicate the output should be recorded. | |
481 | return true; |
|
481 | return true; | |
482 | } |
|
482 | } | |
483 |
|
483 | |||
484 | // If we got here, attach a new div |
|
484 | // If we got here, attach a new div | |
485 | var toinsert = this.create_output_area(); |
|
485 | var toinsert = this.create_output_area(); | |
486 | var append_text = OutputArea.append_map['text/plain']; |
|
486 | var append_text = OutputArea.append_map['text/plain']; | |
487 | if (append_text) { |
|
487 | if (append_text) { | |
488 | append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass); |
|
488 | append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass); | |
489 | } |
|
489 | } | |
490 | this._safe_append(toinsert); |
|
490 | this._safe_append(toinsert); | |
491 | return true; |
|
491 | return true; | |
492 | }; |
|
492 | }; | |
493 |
|
493 | |||
494 |
|
494 | |||
495 | OutputArea.prototype.append_display_data = function (json, handle_inserted) { |
|
495 | OutputArea.prototype.append_display_data = function (json, handle_inserted) { | |
496 | var toinsert = this.create_output_area(); |
|
496 | var toinsert = this.create_output_area(); | |
497 | if (this.append_mime_type(json, toinsert, handle_inserted)) { |
|
497 | if (this.append_mime_type(json, toinsert, handle_inserted)) { | |
498 | this._safe_append(toinsert); |
|
498 | this._safe_append(toinsert); | |
499 | // If we just output latex, typeset it. |
|
499 | // If we just output latex, typeset it. | |
500 | if ((json['text/latex'] !== undefined) || |
|
500 | if ((json['text/latex'] !== undefined) || | |
501 | (json['text/html'] !== undefined) || |
|
501 | (json['text/html'] !== undefined) || | |
502 | (json['text/markdown'] !== undefined)) { |
|
502 | (json['text/markdown'] !== undefined)) { | |
503 | this.typeset(); |
|
503 | this.typeset(); | |
504 | } |
|
504 | } | |
505 | } |
|
505 | } | |
506 | }; |
|
506 | }; | |
507 |
|
507 | |||
508 |
|
508 | |||
509 | OutputArea.safe_outputs = { |
|
509 | OutputArea.safe_outputs = { | |
510 | 'text/plain' : true, |
|
510 | 'text/plain' : true, | |
511 | 'text/latex' : true, |
|
511 | 'text/latex' : true, | |
512 | 'image/png' : true, |
|
512 | 'image/png' : true, | |
513 | 'image/jpeg' : true |
|
513 | 'image/jpeg' : true | |
514 | }; |
|
514 | }; | |
515 |
|
515 | |||
516 | OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) { |
|
516 | OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) { | |
517 | for (var i=0; i < OutputArea.display_order.length; i++) { |
|
517 | for (var i=0; i < OutputArea.display_order.length; i++) { | |
518 | var type = OutputArea.display_order[i]; |
|
518 | var type = OutputArea.display_order[i]; | |
519 | var append = OutputArea.append_map[type]; |
|
519 | var append = OutputArea.append_map[type]; | |
520 | if ((json[type] !== undefined) && append) { |
|
520 | if ((json[type] !== undefined) && append) { | |
521 | var value = json[type]; |
|
521 | var value = json[type]; | |
522 | if (!this.trusted && !OutputArea.safe_outputs[type]) { |
|
522 | if (!this.trusted && !OutputArea.safe_outputs[type]) { | |
523 | // not trusted, sanitize HTML |
|
523 | // not trusted, sanitize HTML | |
524 | if (type==='text/html' || type==='text/svg') { |
|
524 | if (type==='text/html' || type==='text/svg') { | |
525 | value = security.sanitize_html(value); |
|
525 | value = security.sanitize_html(value); | |
526 | } else { |
|
526 | } else { | |
527 | // don't display if we don't know how to sanitize it |
|
527 | // don't display if we don't know how to sanitize it | |
528 | console.log("Ignoring untrusted " + type + " output."); |
|
528 | console.log("Ignoring untrusted " + type + " output."); | |
529 | continue; |
|
529 | continue; | |
530 | } |
|
530 | } | |
531 | } |
|
531 | } | |
532 | var md = json.metadata || {}; |
|
532 | var md = json.metadata || {}; | |
533 | var toinsert = append.apply(this, [value, md, element, handle_inserted]); |
|
533 | var toinsert = append.apply(this, [value, md, element, handle_inserted]); | |
534 | // Since only the png and jpeg mime types call the inserted |
|
534 | // Since only the png and jpeg mime types call the inserted | |
535 | // callback, if the mime type is something other we must call the |
|
535 | // callback, if the mime type is something other we must call the | |
536 | // inserted callback only when the element is actually inserted |
|
536 | // inserted callback only when the element is actually inserted | |
537 | // into the DOM. Use a timeout of 0 to do this. |
|
537 | // into the DOM. Use a timeout of 0 to do this. | |
538 | if (['image/png', 'image/jpeg'].indexOf(type) < 0 && handle_inserted !== undefined) { |
|
538 | if (['image/png', 'image/jpeg'].indexOf(type) < 0 && handle_inserted !== undefined) { | |
539 | setTimeout(handle_inserted, 0); |
|
539 | setTimeout(handle_inserted, 0); | |
540 | } |
|
540 | } | |
541 | this.events.trigger('output_appended.OutputArea', [type, value, md, toinsert]); |
|
541 | this.events.trigger('output_appended.OutputArea', [type, value, md, toinsert]); | |
542 | return toinsert; |
|
542 | return toinsert; | |
543 | } |
|
543 | } | |
544 | } |
|
544 | } | |
545 | return null; |
|
545 | return null; | |
546 | }; |
|
546 | }; | |
547 |
|
547 | |||
548 |
|
548 | |||
549 | var append_html = function (html, md, element) { |
|
549 | var append_html = function (html, md, element) { | |
550 | var type = 'text/html'; |
|
550 | var type = 'text/html'; | |
551 | var toinsert = this.create_output_subarea(md, "output_html rendered_html", type); |
|
551 | var toinsert = this.create_output_subarea(md, "output_html rendered_html", type); | |
552 | this.keyboard_manager.register_events(toinsert); |
|
552 | this.keyboard_manager.register_events(toinsert); | |
553 | toinsert.append(html); |
|
553 | toinsert.append(html); | |
554 | element.append(toinsert); |
|
554 | element.append(toinsert); | |
555 | return toinsert; |
|
555 | return toinsert; | |
556 | }; |
|
556 | }; | |
557 |
|
557 | |||
558 |
|
558 | |||
559 | var append_markdown = function(markdown, md, element) { |
|
559 | var append_markdown = function(markdown, md, element) { | |
560 | var type = 'text/markdown'; |
|
560 | var type = 'text/markdown'; | |
561 | var toinsert = this.create_output_subarea(md, "output_markdown", type); |
|
561 | var toinsert = this.create_output_subarea(md, "output_markdown", type); | |
562 | var text_and_math = mathjaxutils.remove_math(markdown); |
|
562 | var text_and_math = mathjaxutils.remove_math(markdown); | |
563 | var text = text_and_math[0]; |
|
563 | var text = text_and_math[0]; | |
564 | var math = text_and_math[1]; |
|
564 | var math = text_and_math[1]; | |
565 | var html = marked.parser(marked.lexer(text)); |
|
565 | var html = marked.parser(marked.lexer(text)); | |
566 | html = mathjaxutils.replace_math(html, math); |
|
566 | html = mathjaxutils.replace_math(html, math); | |
567 | toinsert.append(html); |
|
567 | toinsert.append(html); | |
568 | element.append(toinsert); |
|
568 | element.append(toinsert); | |
569 | return toinsert; |
|
569 | return toinsert; | |
570 | }; |
|
570 | }; | |
571 |
|
571 | |||
572 |
|
572 | |||
573 | var append_javascript = function (js, md, element) { |
|
573 | var append_javascript = function (js, md, element) { | |
574 | // We just eval the JS code, element appears in the local scope. |
|
574 | // We just eval the JS code, element appears in the local scope. | |
575 | var type = 'application/javascript'; |
|
575 | var type = 'application/javascript'; | |
576 | var toinsert = this.create_output_subarea(md, "output_javascript", type); |
|
576 | var toinsert = this.create_output_subarea(md, "output_javascript", type); | |
577 | this.keyboard_manager.register_events(toinsert); |
|
577 | this.keyboard_manager.register_events(toinsert); | |
578 | element.append(toinsert); |
|
578 | element.append(toinsert); | |
579 |
|
579 | |||
580 | // Fix for ipython/issues/5293, make sure `element` is the area which |
|
580 | // Fix for ipython/issues/5293, make sure `element` is the area which | |
581 | // output can be inserted into at the time of JS execution. |
|
581 | // output can be inserted into at the time of JS execution. | |
582 | element = toinsert; |
|
582 | element = toinsert; | |
583 | try { |
|
583 | try { | |
584 | eval(js); |
|
584 | eval(js); | |
585 | } catch(err) { |
|
585 | } catch(err) { | |
586 | console.log(err); |
|
586 | console.log(err); | |
587 | this._append_javascript_error(err, toinsert); |
|
587 | this._append_javascript_error(err, toinsert); | |
588 | } |
|
588 | } | |
589 | return toinsert; |
|
589 | return toinsert; | |
590 | }; |
|
590 | }; | |
591 |
|
591 | |||
592 |
|
592 | |||
593 | var append_text = function (data, md, element) { |
|
593 | var append_text = function (data, md, element) { | |
594 | var type = 'text/plain'; |
|
594 | var type = 'text/plain'; | |
595 | var toinsert = this.create_output_subarea(md, "output_text", type); |
|
595 | var toinsert = this.create_output_subarea(md, "output_text", type); | |
596 | // escape ANSI & HTML specials in plaintext: |
|
596 | // escape ANSI & HTML specials in plaintext: | |
597 | data = utils.fixConsole(data); |
|
597 | data = utils.fixConsole(data); | |
598 | data = utils.fixCarriageReturn(data); |
|
598 | data = utils.fixCarriageReturn(data); | |
599 | data = utils.autoLinkUrls(data); |
|
599 | data = utils.autoLinkUrls(data); | |
600 | // The only user content injected with this HTML call is |
|
600 | // The only user content injected with this HTML call is | |
601 | // escaped by the fixConsole() method. |
|
601 | // escaped by the fixConsole() method. | |
602 | toinsert.append($("<pre/>").html(data)); |
|
602 | toinsert.append($("<pre/>").html(data)); | |
603 | element.append(toinsert); |
|
603 | element.append(toinsert); | |
604 | return toinsert; |
|
604 | return toinsert; | |
605 | }; |
|
605 | }; | |
606 |
|
606 | |||
607 |
|
607 | |||
608 | var append_svg = function (svg_html, md, element) { |
|
608 | var append_svg = function (svg_html, md, element) { | |
609 | var type = 'image/svg+xml'; |
|
609 | var type = 'image/svg+xml'; | |
610 | var toinsert = this.create_output_subarea(md, "output_svg", type); |
|
610 | var toinsert = this.create_output_subarea(md, "output_svg", type); | |
611 |
|
611 | |||
612 | // Get the svg element from within the HTML. |
|
612 | // Get the svg element from within the HTML. | |
613 | var svg = $('<div />').html(svg_html).find('svg'); |
|
613 | var svg = $('<div />').html(svg_html).find('svg'); | |
614 | var svg_area = $('<div />'); |
|
614 | var svg_area = $('<div />'); | |
615 | var width = svg.attr('width'); |
|
615 | var width = svg.attr('width'); | |
616 | var height = svg.attr('height'); |
|
616 | var height = svg.attr('height'); | |
617 | svg |
|
617 | svg | |
618 | .width('100%') |
|
618 | .width('100%') | |
619 | .height('100%'); |
|
619 | .height('100%'); | |
620 | svg_area |
|
620 | svg_area | |
621 | .width(width) |
|
621 | .width(width) | |
622 | .height(height); |
|
622 | .height(height); | |
623 |
|
623 | |||
624 | // The jQuery resize handlers don't seem to work on the svg element. |
|
624 | // The jQuery resize handlers don't seem to work on the svg element. | |
625 | // When the svg renders completely, measure it's size and set the parent |
|
625 | // When the svg renders completely, measure it's size and set the parent | |
626 | // div to that size. Then set the svg to 100% the size of the parent |
|
626 | // div to that size. Then set the svg to 100% the size of the parent | |
627 | // div and make the parent div resizable. |
|
627 | // div and make the parent div resizable. | |
628 | this._dblclick_to_reset_size(svg_area, true, false); |
|
628 | this._dblclick_to_reset_size(svg_area, true, false); | |
629 |
|
629 | |||
630 | svg_area.append(svg); |
|
630 | svg_area.append(svg); | |
631 | toinsert.append(svg_area); |
|
631 | toinsert.append(svg_area); | |
632 | element.append(toinsert); |
|
632 | element.append(toinsert); | |
633 |
|
633 | |||
634 | return toinsert; |
|
634 | return toinsert; | |
635 | }; |
|
635 | }; | |
636 |
|
636 | |||
637 | OutputArea.prototype._dblclick_to_reset_size = function (img, immediately, resize_parent) { |
|
637 | OutputArea.prototype._dblclick_to_reset_size = function (img, immediately, resize_parent) { | |
638 | // Add a resize handler to an element |
|
638 | // Add a resize handler to an element | |
639 | // |
|
639 | // | |
640 | // img: jQuery element |
|
640 | // img: jQuery element | |
641 | // immediately: bool=False |
|
641 | // immediately: bool=False | |
642 | // Wait for the element to load before creating the handle. |
|
642 | // Wait for the element to load before creating the handle. | |
643 | // resize_parent: bool=True |
|
643 | // resize_parent: bool=True | |
644 | // Should the parent of the element be resized when the element is |
|
644 | // Should the parent of the element be resized when the element is | |
645 | // reset (by double click). |
|
645 | // reset (by double click). | |
646 | var callback = function (){ |
|
646 | var callback = function (){ | |
647 | var h0 = img.height(); |
|
647 | var h0 = img.height(); | |
648 | var w0 = img.width(); |
|
648 | var w0 = img.width(); | |
649 | if (!(h0 && w0)) { |
|
649 | if (!(h0 && w0)) { | |
650 | // zero size, don't make it resizable |
|
650 | // zero size, don't make it resizable | |
651 | return; |
|
651 | return; | |
652 | } |
|
652 | } | |
653 | img.resizable({ |
|
653 | img.resizable({ | |
654 | aspectRatio: true, |
|
654 | aspectRatio: true, | |
655 | autoHide: true |
|
655 | autoHide: true | |
656 | }); |
|
656 | }); | |
657 | img.dblclick(function () { |
|
657 | img.dblclick(function () { | |
658 | // resize wrapper & image together for some reason: |
|
658 | // resize wrapper & image together for some reason: | |
659 | img.height(h0); |
|
659 | img.height(h0); | |
660 | img.width(w0); |
|
660 | img.width(w0); | |
661 | if (resize_parent === undefined || resize_parent) { |
|
661 | if (resize_parent === undefined || resize_parent) { | |
662 | img.parent().height(h0); |
|
662 | img.parent().height(h0); | |
663 | img.parent().width(w0); |
|
663 | img.parent().width(w0); | |
664 | } |
|
664 | } | |
665 | }); |
|
665 | }); | |
666 | }; |
|
666 | }; | |
667 |
|
667 | |||
668 | if (immediately) { |
|
668 | if (immediately) { | |
669 | callback(); |
|
669 | callback(); | |
670 | } else { |
|
670 | } else { | |
671 | img.on("load", callback); |
|
671 | img.on("load", callback); | |
672 | } |
|
672 | } | |
673 | }; |
|
673 | }; | |
674 |
|
674 | |||
675 | var set_width_height = function (img, md, mime) { |
|
675 | var set_width_height = function (img, md, mime) { | |
676 | // set width and height of an img element from metadata |
|
676 | // set width and height of an img element from metadata | |
677 | var height = _get_metadata_key(md, 'height', mime); |
|
677 | var height = _get_metadata_key(md, 'height', mime); | |
678 | if (height !== undefined) img.attr('height', height); |
|
678 | if (height !== undefined) img.attr('height', height); | |
679 | var width = _get_metadata_key(md, 'width', mime); |
|
679 | var width = _get_metadata_key(md, 'width', mime); | |
680 | if (width !== undefined) img.attr('width', width); |
|
680 | if (width !== undefined) img.attr('width', width); | |
681 | }; |
|
681 | }; | |
682 |
|
682 | |||
683 | var append_png = function (png, md, element, handle_inserted) { |
|
683 | var append_png = function (png, md, element, handle_inserted) { | |
684 | var type = 'image/png'; |
|
684 | var type = 'image/png'; | |
685 | var toinsert = this.create_output_subarea(md, "output_png", type); |
|
685 | var toinsert = this.create_output_subarea(md, "output_png", type); | |
686 | var img = $("<img/>"); |
|
686 | var img = $("<img/>"); | |
687 | if (handle_inserted !== undefined) { |
|
687 | if (handle_inserted !== undefined) { | |
688 | img.on('load', function(){ |
|
688 | img.on('load', function(){ | |
689 | handle_inserted(img); |
|
689 | handle_inserted(img); | |
690 | }); |
|
690 | }); | |
691 | } |
|
691 | } | |
692 | img[0].src = 'data:image/png;base64,'+ png; |
|
692 | img[0].src = 'data:image/png;base64,'+ png; | |
693 | set_width_height(img, md, 'image/png'); |
|
693 | set_width_height(img, md, 'image/png'); | |
694 | this._dblclick_to_reset_size(img); |
|
694 | this._dblclick_to_reset_size(img); | |
695 | toinsert.append(img); |
|
695 | toinsert.append(img); | |
696 | element.append(toinsert); |
|
696 | element.append(toinsert); | |
697 | return toinsert; |
|
697 | return toinsert; | |
698 | }; |
|
698 | }; | |
699 |
|
699 | |||
700 |
|
700 | |||
701 | var append_jpeg = function (jpeg, md, element, handle_inserted) { |
|
701 | var append_jpeg = function (jpeg, md, element, handle_inserted) { | |
702 | var type = 'image/jpeg'; |
|
702 | var type = 'image/jpeg'; | |
703 | var toinsert = this.create_output_subarea(md, "output_jpeg", type); |
|
703 | var toinsert = this.create_output_subarea(md, "output_jpeg", type); | |
704 | var img = $("<img/>"); |
|
704 | var img = $("<img/>"); | |
705 | if (handle_inserted !== undefined) { |
|
705 | if (handle_inserted !== undefined) { | |
706 | img.on('load', function(){ |
|
706 | img.on('load', function(){ | |
707 | handle_inserted(img); |
|
707 | handle_inserted(img); | |
708 | }); |
|
708 | }); | |
709 | } |
|
709 | } | |
710 | img[0].src = 'data:image/jpeg;base64,'+ jpeg; |
|
710 | img[0].src = 'data:image/jpeg;base64,'+ jpeg; | |
711 | set_width_height(img, md, 'image/jpeg'); |
|
711 | set_width_height(img, md, 'image/jpeg'); | |
712 | this._dblclick_to_reset_size(img); |
|
712 | this._dblclick_to_reset_size(img); | |
713 | toinsert.append(img); |
|
713 | toinsert.append(img); | |
714 | element.append(toinsert); |
|
714 | element.append(toinsert); | |
715 | return toinsert; |
|
715 | return toinsert; | |
716 | }; |
|
716 | }; | |
717 |
|
717 | |||
718 |
|
718 | |||
719 | var append_pdf = function (pdf, md, element) { |
|
719 | var append_pdf = function (pdf, md, element) { | |
720 | var type = 'application/pdf'; |
|
720 | var type = 'application/pdf'; | |
721 | var toinsert = this.create_output_subarea(md, "output_pdf", type); |
|
721 | var toinsert = this.create_output_subarea(md, "output_pdf", type); | |
722 | var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf); |
|
722 | var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf); | |
723 | a.attr('target', '_blank'); |
|
723 | a.attr('target', '_blank'); | |
724 | a.text('View PDF') |
|
724 | a.text('View PDF') | |
725 | toinsert.append(a); |
|
725 | toinsert.append(a); | |
726 | element.append(toinsert); |
|
726 | element.append(toinsert); | |
727 | return toinsert; |
|
727 | return toinsert; | |
728 | } |
|
728 | } | |
729 |
|
729 | |||
730 | var append_latex = function (latex, md, element) { |
|
730 | var append_latex = function (latex, md, element) { | |
731 | // This method cannot do the typesetting because the latex first has to |
|
731 | // This method cannot do the typesetting because the latex first has to | |
732 | // be on the page. |
|
732 | // be on the page. | |
733 | var type = 'text/latex'; |
|
733 | var type = 'text/latex'; | |
734 | var toinsert = this.create_output_subarea(md, "output_latex", type); |
|
734 | var toinsert = this.create_output_subarea(md, "output_latex", type); | |
735 | toinsert.append(latex); |
|
735 | toinsert.append(latex); | |
736 | element.append(toinsert); |
|
736 | element.append(toinsert); | |
737 | return toinsert; |
|
737 | return toinsert; | |
738 | }; |
|
738 | }; | |
739 |
|
739 | |||
740 |
|
740 | |||
741 | OutputArea.prototype.append_raw_input = function (msg) { |
|
741 | OutputArea.prototype.append_raw_input = function (msg) { | |
742 | var that = this; |
|
742 | var that = this; | |
743 | this.expand(); |
|
743 | this.expand(); | |
744 | var content = msg.content; |
|
744 | var content = msg.content; | |
745 | var area = this.create_output_area(); |
|
745 | var area = this.create_output_area(); | |
746 |
|
746 | |||
747 | // disable any other raw_inputs, if they are left around |
|
747 | // disable any other raw_inputs, if they are left around | |
748 | $("div.output_subarea.raw_input_container").remove(); |
|
748 | $("div.output_subarea.raw_input_container").remove(); | |
749 |
|
749 | |||
750 | var input_type = content.password ? 'password' : 'text'; |
|
750 | var input_type = content.password ? 'password' : 'text'; | |
751 |
|
751 | |||
752 | area.append( |
|
752 | area.append( | |
753 | $("<div/>") |
|
753 | $("<div/>") | |
754 | .addClass("box-flex1 output_subarea raw_input_container") |
|
754 | .addClass("box-flex1 output_subarea raw_input_container") | |
755 | .append( |
|
755 | .append( | |
756 | $("<span/>") |
|
756 | $("<span/>") | |
757 | .addClass("raw_input_prompt") |
|
757 | .addClass("raw_input_prompt") | |
758 | .text(content.prompt) |
|
758 | .text(content.prompt) | |
759 | ) |
|
759 | ) | |
760 | .append( |
|
760 | .append( | |
761 | $("<input/>") |
|
761 | $("<input/>") | |
762 | .addClass("raw_input") |
|
762 | .addClass("raw_input") | |
763 | .attr('type', input_type) |
|
763 | .attr('type', input_type) | |
764 | .attr("size", 47) |
|
764 | .attr("size", 47) | |
765 | .keydown(function (event, ui) { |
|
765 | .keydown(function (event, ui) { | |
766 | // make sure we submit on enter, |
|
766 | // make sure we submit on enter, | |
767 | // and don't re-execute the *cell* on shift-enter |
|
767 | // and don't re-execute the *cell* on shift-enter | |
768 | if (event.which === keyboard.keycodes.enter) { |
|
768 | if (event.which === keyboard.keycodes.enter) { | |
769 | that._submit_raw_input(); |
|
769 | that._submit_raw_input(); | |
770 | return false; |
|
770 | return false; | |
771 | } |
|
771 | } | |
772 | }) |
|
772 | }) | |
773 | ) |
|
773 | ) | |
774 | ); |
|
774 | ); | |
775 |
|
775 | |||
776 | this.element.append(area); |
|
776 | this.element.append(area); | |
777 | var raw_input = area.find('input.raw_input'); |
|
777 | var raw_input = area.find('input.raw_input'); | |
778 | // Register events that enable/disable the keyboard manager while raw |
|
778 | // Register events that enable/disable the keyboard manager while raw | |
779 | // input is focused. |
|
779 | // input is focused. | |
780 | this.keyboard_manager.register_events(raw_input); |
|
780 | this.keyboard_manager.register_events(raw_input); | |
781 | // Note, the following line used to read raw_input.focus().focus(). |
|
781 | // Note, the following line used to read raw_input.focus().focus(). | |
782 | // This seemed to be needed otherwise only the cell would be focused. |
|
782 | // This seemed to be needed otherwise only the cell would be focused. | |
783 | // But with the modal UI, this seems to work fine with one call to focus(). |
|
783 | // But with the modal UI, this seems to work fine with one call to focus(). | |
784 | raw_input.focus(); |
|
784 | raw_input.focus(); | |
785 | } |
|
785 | } | |
786 |
|
786 | |||
787 | OutputArea.prototype._submit_raw_input = function (evt) { |
|
787 | OutputArea.prototype._submit_raw_input = function (evt) { | |
788 | var container = this.element.find("div.raw_input_container"); |
|
788 | var container = this.element.find("div.raw_input_container"); | |
789 | var theprompt = container.find("span.raw_input_prompt"); |
|
789 | var theprompt = container.find("span.raw_input_prompt"); | |
790 | var theinput = container.find("input.raw_input"); |
|
790 | var theinput = container.find("input.raw_input"); | |
791 | var value = theinput.val(); |
|
791 | var value = theinput.val(); | |
792 | var echo = value; |
|
792 | var echo = value; | |
793 | // don't echo if it's a password |
|
793 | // don't echo if it's a password | |
794 | if (theinput.attr('type') == 'password') { |
|
794 | if (theinput.attr('type') == 'password') { | |
795 | echo = '········'; |
|
795 | echo = '········'; | |
796 | } |
|
796 | } | |
797 | var content = { |
|
797 | var content = { | |
798 | output_type : 'stream', |
|
798 | output_type : 'stream', | |
799 | stream : 'stdout', |
|
799 | stream : 'stdout', | |
800 | text : theprompt.text() + echo + '\n' |
|
800 | text : theprompt.text() + echo + '\n' | |
801 | } |
|
801 | } | |
802 | // remove form container |
|
802 | // remove form container | |
803 | container.parent().remove(); |
|
803 | container.parent().remove(); | |
804 | // replace with plaintext version in stdout |
|
804 | // replace with plaintext version in stdout | |
805 | this.append_output(content, false); |
|
805 | this.append_output(content, false); | |
806 | this.events.trigger('send_input_reply.Kernel', value); |
|
806 | this.events.trigger('send_input_reply.Kernel', value); | |
807 | } |
|
807 | } | |
808 |
|
808 | |||
809 |
|
809 | |||
810 | OutputArea.prototype.handle_clear_output = function (msg) { |
|
810 | OutputArea.prototype.handle_clear_output = function (msg) { | |
811 | // msg spec v4 had stdout, stderr, display keys |
|
811 | // msg spec v4 had stdout, stderr, display keys | |
812 | // v4.1 replaced these with just wait |
|
812 | // v4.1 replaced these with just wait | |
813 | // The default behavior is the same (stdout=stderr=display=True, wait=False), |
|
813 | // The default behavior is the same (stdout=stderr=display=True, wait=False), | |
814 | // so v4 messages will still be properly handled, |
|
814 | // so v4 messages will still be properly handled, | |
815 | // except for the rarely used clearing less than all output. |
|
815 | // except for the rarely used clearing less than all output. | |
816 | this.clear_output(msg.content.wait || false); |
|
816 | this.clear_output(msg.content.wait || false); | |
817 | }; |
|
817 | }; | |
818 |
|
818 | |||
819 |
|
819 | |||
820 | OutputArea.prototype.clear_output = function(wait) { |
|
820 | OutputArea.prototype.clear_output = function(wait) { | |
821 | if (wait) { |
|
821 | if (wait) { | |
822 |
|
822 | |||
823 | // If a clear is queued, clear before adding another to the queue. |
|
823 | // If a clear is queued, clear before adding another to the queue. | |
824 | if (this.clear_queued) { |
|
824 | if (this.clear_queued) { | |
825 | this.clear_output(false); |
|
825 | this.clear_output(false); | |
826 | }; |
|
826 | }; | |
827 |
|
827 | |||
828 | this.clear_queued = true; |
|
828 | this.clear_queued = true; | |
829 | } else { |
|
829 | } else { | |
830 |
|
830 | |||
831 | // Fix the output div's height if the clear_output is waiting for |
|
831 | // Fix the output div's height if the clear_output is waiting for | |
832 | // new output (it is being used in an animation). |
|
832 | // new output (it is being used in an animation). | |
833 | if (this.clear_queued) { |
|
833 | if (this.clear_queued) { | |
834 | var height = this.element.height(); |
|
834 | var height = this.element.height(); | |
835 | this.element.height(height); |
|
835 | this.element.height(height); | |
836 | this.clear_queued = false; |
|
836 | this.clear_queued = false; | |
837 | } |
|
837 | } | |
838 |
|
838 | |||
839 | // Clear all |
|
839 | // Clear all | |
840 | // Remove load event handlers from img tags because we don't want |
|
840 | // Remove load event handlers from img tags because we don't want | |
841 | // them to fire if the image is never added to the page. |
|
841 | // them to fire if the image is never added to the page. | |
842 | this.element.find('img').off('load'); |
|
842 | this.element.find('img').off('load'); | |
843 | this.element.html(""); |
|
843 | this.element.html(""); | |
844 | this.outputs = []; |
|
844 | this.outputs = []; | |
845 | this.trusted = true; |
|
845 | this.trusted = true; | |
846 | this.unscroll_area(); |
|
846 | this.unscroll_area(); | |
847 | return; |
|
847 | return; | |
848 | }; |
|
848 | }; | |
849 | }; |
|
849 | }; | |
850 |
|
850 | |||
851 |
|
851 | |||
852 | // JSON serialization |
|
852 | // JSON serialization | |
853 |
|
853 | |||
854 | OutputArea.prototype.fromJSON = function (outputs, metadata) { |
|
854 | OutputArea.prototype.fromJSON = function (outputs, metadata) { | |
855 | var len = outputs.length; |
|
855 | var len = outputs.length; | |
856 | metadata = metadata || {}; |
|
856 | metadata = metadata || {}; | |
857 |
|
857 | |||
858 | for (var i=0; i<len; i++) { |
|
858 | for (var i=0; i<len; i++) { | |
859 | this.append_output(outputs[i]); |
|
859 | this.append_output(outputs[i]); | |
860 | } |
|
860 | } | |
861 |
|
861 | |||
862 | if (metadata.collapsed !== undefined) { |
|
862 | if (metadata.collapsed !== undefined) { | |
863 | this.collapsed = metadata.collapsed; |
|
863 | this.collapsed = metadata.collapsed; | |
864 | if (metadata.collapsed) { |
|
864 | if (metadata.collapsed) { | |
865 | this.collapse_output(); |
|
865 | this.collapse_output(); | |
866 | } |
|
866 | } | |
867 | } |
|
867 | } | |
868 | if (metadata.autoscroll !== undefined) { |
|
868 | if (metadata.autoscroll !== undefined) { | |
869 | this.collapsed = metadata.collapsed; |
|
869 | this.collapsed = metadata.collapsed; | |
870 | if (metadata.collapsed) { |
|
870 | if (metadata.collapsed) { | |
871 | this.collapse_output(); |
|
871 | this.collapse_output(); | |
872 | } else { |
|
872 | } else { | |
873 | this.expand_output(); |
|
873 | this.expand_output(); | |
874 | } |
|
874 | } | |
875 | } |
|
875 | } | |
876 | }; |
|
876 | }; | |
877 |
|
877 | |||
878 |
|
878 | |||
879 | OutputArea.prototype.toJSON = function () { |
|
879 | OutputArea.prototype.toJSON = function () { | |
880 | return this.outputs; |
|
880 | return this.outputs; | |
881 | }; |
|
881 | }; | |
882 |
|
882 | |||
883 | /** |
|
883 | /** | |
884 | * Class properties |
|
884 | * Class properties | |
885 | **/ |
|
885 | **/ | |
886 |
|
886 | |||
887 | /** |
|
887 | /** | |
888 | * Threshold to trigger autoscroll when the OutputArea is resized, |
|
888 | * Threshold to trigger autoscroll when the OutputArea is resized, | |
889 | * typically when new outputs are added. |
|
889 | * typically when new outputs are added. | |
890 | * |
|
890 | * | |
891 | * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold, |
|
891 | * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold, | |
892 | * unless it is < 0, in which case autoscroll will never be triggered |
|
892 | * unless it is < 0, in which case autoscroll will never be triggered | |
893 | * |
|
893 | * | |
894 | * @property auto_scroll_threshold |
|
894 | * @property auto_scroll_threshold | |
895 | * @type Number |
|
895 | * @type Number | |
896 | * @default 100 |
|
896 | * @default 100 | |
897 | * |
|
897 | * | |
898 | **/ |
|
898 | **/ | |
899 | OutputArea.auto_scroll_threshold = 100; |
|
899 | OutputArea.auto_scroll_threshold = 100; | |
900 |
|
900 | |||
901 | /** |
|
901 | /** | |
902 | * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas |
|
902 | * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas | |
903 | * shorter than this are never scrolled. |
|
903 | * shorter than this are never scrolled. | |
904 | * |
|
904 | * | |
905 | * @property minimum_scroll_threshold |
|
905 | * @property minimum_scroll_threshold | |
906 | * @type Number |
|
906 | * @type Number | |
907 | * @default 20 |
|
907 | * @default 20 | |
908 | * |
|
908 | * | |
909 | **/ |
|
909 | **/ | |
910 | OutputArea.minimum_scroll_threshold = 20; |
|
910 | OutputArea.minimum_scroll_threshold = 20; | |
911 |
|
911 | |||
912 |
|
912 | |||
913 | OutputArea.display_order = [ |
|
913 | OutputArea.display_order = [ | |
914 | 'application/javascript', |
|
914 | 'application/javascript', | |
915 | 'text/html', |
|
915 | 'text/html', | |
916 | 'text/markdown', |
|
916 | 'text/markdown', | |
917 | 'text/latex', |
|
917 | 'text/latex', | |
918 | 'image/svg+xml', |
|
918 | 'image/svg+xml', | |
919 | 'image/png', |
|
919 | 'image/png', | |
920 | 'image/jpeg', |
|
920 | 'image/jpeg', | |
921 | 'application/pdf', |
|
921 | 'application/pdf', | |
922 | 'text/plain' |
|
922 | 'text/plain' | |
923 | ]; |
|
923 | ]; | |
924 |
|
924 | |||
925 | OutputArea.append_map = { |
|
925 | OutputArea.append_map = { | |
926 | "text/plain" : append_text, |
|
926 | "text/plain" : append_text, | |
927 | "text/html" : append_html, |
|
927 | "text/html" : append_html, | |
928 | "text/markdown": append_markdown, |
|
928 | "text/markdown": append_markdown, | |
929 | "image/svg+xml" : append_svg, |
|
929 | "image/svg+xml" : append_svg, | |
930 | "image/png" : append_png, |
|
930 | "image/png" : append_png, | |
931 | "image/jpeg" : append_jpeg, |
|
931 | "image/jpeg" : append_jpeg, | |
932 | "text/latex" : append_latex, |
|
932 | "text/latex" : append_latex, | |
933 | "application/javascript" : append_javascript, |
|
933 | "application/javascript" : append_javascript, | |
934 | "application/pdf" : append_pdf |
|
934 | "application/pdf" : append_pdf | |
935 | }; |
|
935 | }; | |
936 |
|
936 | |||
937 | // For backwards compatability. |
|
937 | // For backwards compatability. | |
938 | IPython.OutputArea = OutputArea; |
|
938 | IPython.OutputArea = OutputArea; | |
939 |
|
939 | |||
940 | return {'OutputArea': OutputArea}; |
|
940 | return {'OutputArea': OutputArea}; | |
941 | }); |
|
941 | }); |
@@ -1,23 +1,23 | |||||
1 | // |
|
1 | // | |
2 | // Test robustness about JS injection in different place |
|
2 | // Test robustness about JS injection in different place | |
3 | // |
|
3 | // | |
4 | // This assume malicious document arrive to the frontend. |
|
4 | // This assume malicious document arrive to the frontend. | |
5 | // |
|
5 | // | |
6 |
|
6 | |||
7 | casper.notebook_test(function () { |
|
7 | casper.notebook_test(function () { | |
8 | var messages = []; |
|
8 | var messages = []; | |
9 | this.on('remote.alert', function (msg) { |
|
9 | this.on('remote.alert', function (msg) { | |
10 | messages.push(msg); |
|
10 | messages.push(msg); | |
11 | }); |
|
11 | }); | |
12 |
|
12 | |||
13 | this.evaluate(function () { |
|
13 | this.evaluate(function () { | |
14 | var cell = IPython.notebook.get_cell(0); |
|
14 | var cell = IPython.notebook.get_cell(0); | |
15 | var json = cell.toJSON(); |
|
15 | var json = cell.toJSON(); | |
16 |
json. |
|
16 | json.execution_count = "<script> alert('hello from input prompts !')</script>"; | |
17 | cell.fromJSON(json); |
|
17 | cell.fromJSON(json); | |
18 | }); |
|
18 | }); | |
19 |
|
19 | |||
20 | this.then(function () { |
|
20 | this.then(function () { | |
21 | this.test.assert(messages.length == 0, "Captured log message from script tag injection !"); |
|
21 | this.test.assert(messages.length == 0, "Captured log message from script tag injection !"); | |
22 | }); |
|
22 | }); | |
23 | }); |
|
23 | }); |
@@ -1,168 +1,168 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "heading", |
|
4 | "cell_type": "heading", | |
5 | "level": 1, |
|
5 | "level": 1, | |
6 | "metadata": {}, |
|
6 | "metadata": {}, | |
7 | "source": [ |
|
7 | "source": [ | |
8 | "NumPy and Matplotlib examples" |
|
8 | "NumPy and Matplotlib examples" | |
9 | ] |
|
9 | ] | |
10 | }, |
|
10 | }, | |
11 | { |
|
11 | { | |
12 | "cell_type": "markdown", |
|
12 | "cell_type": "markdown", | |
13 | "metadata": {}, |
|
13 | "metadata": {}, | |
14 | "source": [ |
|
14 | "source": [ | |
15 | "First import NumPy and Matplotlib:" |
|
15 | "First import NumPy and Matplotlib:" | |
16 | ] |
|
16 | ] | |
17 | }, |
|
17 | }, | |
18 | { |
|
18 | { | |
19 | "cell_type": "code", |
|
19 | "cell_type": "code", | |
|
20 | "execution_count": 1, | |||
20 | "metadata": { |
|
21 | "metadata": { | |
21 | "collapsed": false |
|
22 | "collapsed": false | |
22 | }, |
|
23 | }, | |
23 | "outputs": [ |
|
24 | "outputs": [ | |
24 | { |
|
25 | { | |
25 | "metadata": {}, |
|
26 | "metadata": {}, | |
26 | "name": "stdout", |
|
27 | "name": "stdout", | |
27 | "output_type": "stream", |
|
28 | "output_type": "stream", | |
28 | "text": "\nWelcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\nFor more information, type 'help(pylab)'.\n" |
|
29 | "text": "\nWelcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\nFor more information, type 'help(pylab)'.\n" | |
29 | } |
|
30 | } | |
30 | ], |
|
31 | ], | |
31 | "prompt_number": 1, |
|
|||
32 | "source": [ |
|
32 | "source": [ | |
33 | "%pylab inline" |
|
33 | "%pylab inline" | |
34 | ] |
|
34 | ] | |
35 | }, |
|
35 | }, | |
36 | { |
|
36 | { | |
37 | "cell_type": "code", |
|
37 | "cell_type": "code", | |
|
38 | "execution_count": 2, | |||
38 | "metadata": { |
|
39 | "metadata": { | |
39 | "collapsed": false |
|
40 | "collapsed": false | |
40 | }, |
|
41 | }, | |
41 | "outputs": [], |
|
42 | "outputs": [], | |
42 | "prompt_number": 2, |
|
|||
43 | "source": [ |
|
43 | "source": [ | |
44 | "import numpy as np" |
|
44 | "import numpy as np" | |
45 | ] |
|
45 | ] | |
46 | }, |
|
46 | }, | |
47 | { |
|
47 | { | |
48 | "cell_type": "markdown", |
|
48 | "cell_type": "markdown", | |
49 | "metadata": {}, |
|
49 | "metadata": {}, | |
50 | "source": [ |
|
50 | "source": [ | |
51 | "Now we show some very basic examples of how they can be used." |
|
51 | "Now we show some very basic examples of how they can be used." | |
52 | ] |
|
52 | ] | |
53 | }, |
|
53 | }, | |
54 | { |
|
54 | { | |
55 | "cell_type": "code", |
|
55 | "cell_type": "code", | |
|
56 | "execution_count": 6, | |||
56 | "metadata": { |
|
57 | "metadata": { | |
57 | "collapsed": false |
|
58 | "collapsed": false | |
58 | }, |
|
59 | }, | |
59 | "outputs": [], |
|
60 | "outputs": [], | |
60 | "prompt_number": 6, |
|
|||
61 | "source": [ |
|
61 | "source": [ | |
62 | "a = np.random.uniform(size=(100,100))" |
|
62 | "a = np.random.uniform(size=(100,100))" | |
63 | ] |
|
63 | ] | |
64 | }, |
|
64 | }, | |
65 | { |
|
65 | { | |
66 | "cell_type": "code", |
|
66 | "cell_type": "code", | |
|
67 | "execution_count": 7, | |||
67 | "metadata": { |
|
68 | "metadata": { | |
68 | "collapsed": false |
|
69 | "collapsed": false | |
69 | }, |
|
70 | }, | |
70 | "outputs": [ |
|
71 | "outputs": [ | |
71 | { |
|
72 | { | |
|
73 | "execution_count": 7, | |||
72 | "metadata": {}, |
|
74 | "metadata": {}, | |
73 | "output_type": "execute_result", |
|
75 | "output_type": "execute_result", | |
74 | "prompt_number": 7, |
|
|||
75 | "text/plain": [ |
|
76 | "text/plain": [ | |
76 | "(100, 100)" |
|
77 | "(100, 100)" | |
77 | ] |
|
78 | ] | |
78 | } |
|
79 | } | |
79 | ], |
|
80 | ], | |
80 | "prompt_number": 7, |
|
|||
81 | "source": [ |
|
81 | "source": [ | |
82 | "a.shape" |
|
82 | "a.shape" | |
83 | ] |
|
83 | ] | |
84 | }, |
|
84 | }, | |
85 | { |
|
85 | { | |
86 | "cell_type": "code", |
|
86 | "cell_type": "code", | |
|
87 | "execution_count": 8, | |||
87 | "metadata": { |
|
88 | "metadata": { | |
88 | "collapsed": false |
|
89 | "collapsed": false | |
89 | }, |
|
90 | }, | |
90 | "outputs": [], |
|
91 | "outputs": [], | |
91 | "prompt_number": 8, |
|
|||
92 | "source": [ |
|
92 | "source": [ | |
93 | "evs = np.linalg.eigvals(a)" |
|
93 | "evs = np.linalg.eigvals(a)" | |
94 | ] |
|
94 | ] | |
95 | }, |
|
95 | }, | |
96 | { |
|
96 | { | |
97 | "cell_type": "code", |
|
97 | "cell_type": "code", | |
|
98 | "execution_count": 10, | |||
98 | "metadata": { |
|
99 | "metadata": { | |
99 | "collapsed": false |
|
100 | "collapsed": false | |
100 | }, |
|
101 | }, | |
101 | "outputs": [ |
|
102 | "outputs": [ | |
102 | { |
|
103 | { | |
|
104 | "execution_count": 10, | |||
103 | "metadata": {}, |
|
105 | "metadata": {}, | |
104 | "output_type": "execute_result", |
|
106 | "output_type": "execute_result", | |
105 | "prompt_number": 10, |
|
|||
106 | "text/plain": [ |
|
107 | "text/plain": [ | |
107 | "(100,)" |
|
108 | "(100,)" | |
108 | ] |
|
109 | ] | |
109 | } |
|
110 | } | |
110 | ], |
|
111 | ], | |
111 | "prompt_number": 10, |
|
|||
112 | "source": [ |
|
112 | "source": [ | |
113 | "evs.shape" |
|
113 | "evs.shape" | |
114 | ] |
|
114 | ] | |
115 | }, |
|
115 | }, | |
116 | { |
|
116 | { | |
117 | "cell_type": "markdown", |
|
117 | "cell_type": "markdown", | |
118 | "metadata": {}, |
|
118 | "metadata": {}, | |
119 | "source": [ |
|
119 | "source": [ | |
120 | "Here is a cell that has both text and PNG output:" |
|
120 | "Here is a cell that has both text and PNG output:" | |
121 | ] |
|
121 | ] | |
122 | }, |
|
122 | }, | |
123 | { |
|
123 | { | |
124 | "cell_type": "code", |
|
124 | "cell_type": "code", | |
|
125 | "execution_count": 14, | |||
125 | "metadata": { |
|
126 | "metadata": { | |
126 | "collapsed": false |
|
127 | "collapsed": false | |
127 | }, |
|
128 | }, | |
128 | "outputs": [ |
|
129 | "outputs": [ | |
129 | { |
|
130 | { | |
|
131 | "execution_count": 14, | |||
130 | "metadata": {}, |
|
132 | "metadata": {}, | |
131 | "output_type": "execute_result", |
|
133 | "output_type": "execute_result", | |
132 | "prompt_number": 14, |
|
|||
133 | "text/plain": [ |
|
134 | "text/plain": [ | |
134 | "(array([95, 4, 0, 0, 0, 0, 0, 0, 0, 1]),\n", |
|
135 | "(array([95, 4, 0, 0, 0, 0, 0, 0, 0, 1]),\n", | |
135 | " array([ -2.93566063, 2.35937011, 7.65440086, 12.9494316 ,\n", |
|
136 | " array([ -2.93566063, 2.35937011, 7.65440086, 12.9494316 ,\n", | |
136 | " 18.24446235, 23.53949309, 28.83452384, 34.12955458,\n", |
|
137 | " 18.24446235, 23.53949309, 28.83452384, 34.12955458,\n", | |
137 | " 39.42458533, 44.71961607, 50.01464682]),\n", |
|
138 | " 39.42458533, 44.71961607, 50.01464682]),\n", | |
138 | " <a list of 10 Patch objects>)" |
|
139 | " <a list of 10 Patch objects>)" | |
139 | ] |
|
140 | ] | |
140 | }, |
|
141 | }, | |
141 | { |
|
142 | { | |
142 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAD9CAYAAAC2l2x5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEhdJREFUeJzt3X1olfX/x/HXtVbT8CZDmsK6KmrubEu3U2xnZOpxLBnG\nOqsIE7RoE3QRZkT/yEAjcIh/LIs6i/BEGSU1CkxT0+pkFp1zMmsxZ5uUTIXoxm95lmdlef3+8Nep\ndbtz7exs16fnAw7sXNs5n/c14nmurl3naDmO4wgAYJy8sR4AADA6CDwAGIrAA4ChCDwAGIrAA4Ch\nCDwAGOofA9/U1KTCwkLNnj07vS2ZTCoUCsm2bTU2NmpgYCD9vccee0zFxcUqKyvTgQMHRm9qAMC/\n+sfA33PPPdq9e/eQbeFwWLZtq6+vT0VFRero6JAkffXVV3ryySf15ptvKhwOa/Xq1aM3NQDgX/1j\n4OfNm6dp06YN2RaPx9Xc3KyCggI1NTUpFotJkmKxmOrr62XbthYsWCDHcZRMJkdvcgDAP8r4HHwi\nkZDP55Mk+Xw+xeNxSecDX1pamv65kpKS9PcAALmXn+kDMvlkA8uyhrUNAPDvMv1kmYyP4KuqqtTT\n0yNJ6unpUVVVlSQpEAjo8OHD6Z87cuRI+nt/NaRXb+vWrRvzGZh/7Odgfu/dvDy747j7yLCMAx8I\nBBSJRJRKpRSJRFRTUyNJqq6u1p49e9Tf369oNKq8vDxNnjzZ1VAAgJH7x8AvXbpUN9xwg3p7e3X5\n5ZfrmWeeUUtLi/r7+1VSUqKTJ09q1apVkqTCwkK1tLSotrZW9957rzZv3pyTHQAA/DXLcXvs73ZB\ny3L9vxvjQTQaVTAYHOsxXGP+scX8Y8fLs0vu2kngAcAD3LSTjyoAAEMReAAwFIEHAEMReAAwFIEH\nAEP9ZwM/Zcqlsixr1G9Tplw61rsK4D/qP3uZ5PnPxMnFHONjfwF4G5dJAgDSCDwAGIrAA4ChCDwA\nGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrA\nA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChXAf+6aef1g03\n3KDrr79ea9askSQlk0mFQiHZtq3GxkYNDAxkbVAAQGZcBf7UqVPasGGD9u7dq0Qiod7eXu3Zs0fh\ncFi2bauvr09FRUXq6OjI9rwAgGFyFfiJEyfKcRx9//33SqVSOnPmjC655BLF43E1NzeroKBATU1N\nisVi2Z4XADBMrgMfDod15ZVXasaMGZo7d64CgYASiYR8Pp8kyefzKR6PZ3VYAMDw5bt50Ndff62W\nlhYdPnxY06ZN0x133KEdO3bIcZxhPX79+vXpr4PBoILBoJsxAMBY0WhU0Wh0RM9hOcOt8u/s3LlT\nW7du1bZt2yRJ4XBYx44d09GjR9Xa2iq/36+DBw+qra1NnZ2dQxe0rGG/EIwmy7Ik5WKO8bG/ALzN\nTTtdnaKZN2+ePvzwQ506dUo//vijdu3apUWLFikQCCgSiSiVSikSiaimpsbN0wMAssBV4KdMmaLW\n1lbdeuutuvHGG1VRUaGFCxeqpaVF/f39Kikp0cmTJ7Vq1apszwsAGCZXp2hGtCCnaAAgYzk7RQMA\nGP8IPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEI\nPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAY\nisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYynXgf/jhB919992a\nNWuWysrKFIvFlEwmFQqFZNu2GhsbNTAwkM1ZAQAZcB34devWybZtdXV1qaurSz6fT+FwWLZtq6+v\nT0VFRero6MjmrACADLgO/L59+7R27VpNmDBB+fn5mjp1quLxuJqbm1VQUKCmpibFYrFszgoAyICr\nwJ84cUKDg4NqaWlRIBDQxo0blUqllEgk5PP5JEk+n0/xeDyrwwIAhi/fzYMGBwfV29urTZs2qa6u\nTitXrtRLL70kx3GG9fj169envw4GgwoGg27GAABjRaNRRaPRET2H5Qy3yn9QWlqqnp4eSdKuXbv0\n3HPP6aefflJra6v8fr8OHjyotrY2dXZ2Dl3Qsob9QjCaLMuSlIs5xsf+AvA2N+10fQ6+uLhYsVhM\n586d086dO1VXV6dAIKBIJKJUKqVIJKKamhq3Tw8AGCHXR/C9vb266667NDg4qLq6Oj388MM6d+6c\nli1bpkOHDum6667T888/r0mTJg1dkCN4AMiYm3a6DrxbBB4AMpfTUzQAgPGNwAOAoQg8ABiKwAOA\n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\n", |
|
143 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAD9CAYAAAC2l2x5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEhdJREFUeJzt3X1olfX/x/HXtVbT8CZDmsK6KmrubEu3U2xnZOpxLBnG\nOqsIE7RoE3QRZkT/yEAjcIh/LIs6i/BEGSU1CkxT0+pkFp1zMmsxZ5uUTIXoxm95lmdlef3+8Nep\ndbtz7exs16fnAw7sXNs5n/c14nmurl3naDmO4wgAYJy8sR4AADA6CDwAGIrAA4ChCDwAGIrAA4Ch\nCDwAGOofA9/U1KTCwkLNnj07vS2ZTCoUCsm2bTU2NmpgYCD9vccee0zFxcUqKyvTgQMHRm9qAMC/\n+sfA33PPPdq9e/eQbeFwWLZtq6+vT0VFRero6JAkffXVV3ryySf15ptvKhwOa/Xq1aM3NQDgX/1j\n4OfNm6dp06YN2RaPx9Xc3KyCggI1NTUpFotJkmKxmOrr62XbthYsWCDHcZRMJkdvcgDAP8r4HHwi\nkZDP55Mk+Xw+xeNxSecDX1pamv65kpKS9PcAALmXn+kDMvlkA8uyhrUNAPDvMv1kmYyP4KuqqtTT\n0yNJ6unpUVVVlSQpEAjo8OHD6Z87cuRI+nt/NaRXb+vWrRvzGZh/7Odgfu/dvDy747j7yLCMAx8I\nBBSJRJRKpRSJRFRTUyNJqq6u1p49e9Tf369oNKq8vDxNnjzZ1VAAgJH7x8AvXbpUN9xwg3p7e3X5\n5ZfrmWeeUUtLi/r7+1VSUqKTJ09q1apVkqTCwkK1tLSotrZW9957rzZv3pyTHQAA/DXLcXvs73ZB\ny3L9vxvjQTQaVTAYHOsxXGP+scX8Y8fLs0vu2kngAcAD3LSTjyoAAEMReAAwFIEHAEMReAAwFIEH\nAEP9ZwM/Zcqlsixr1G9Tplw61rsK4D/qP3uZ5PnPxMnFHONjfwF4G5dJAgDSCDwAGIrAA4ChCDwA\nGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrA\nA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChXAf+6aef1g03\n3KDrr79ea9askSQlk0mFQiHZtq3GxkYNDAxkbVAAQGZcBf7UqVPasGGD9u7dq0Qiod7eXu3Zs0fh\ncFi2bauvr09FRUXq6OjI9rwAgGFyFfiJEyfKcRx9//33SqVSOnPmjC655BLF43E1NzeroKBATU1N\nisVi2Z4XADBMrgMfDod15ZVXasaMGZo7d64CgYASiYR8Pp8kyefzKR6PZ3VYAMDw5bt50Ndff62W\nlhYdPnxY06ZN0x133KEdO3bIcZxhPX79+vXpr4PBoILBoJsxAMBY0WhU0Wh0RM9hOcOt8u/s3LlT\nW7du1bZt2yRJ4XBYx44d09GjR9Xa2iq/36+DBw+qra1NnZ2dQxe0rGG/EIwmy7Ik5WKO8bG/ALzN\nTTtdnaKZN2+ePvzwQ506dUo//vijdu3apUWLFikQCCgSiSiVSikSiaimpsbN0wMAssBV4KdMmaLW\n1lbdeuutuvHGG1VRUaGFCxeqpaVF/f39Kikp0cmTJ7Vq1apszwsAGCZXp2hGtCCnaAAgYzk7RQMA\nGP8IPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEI\nPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAY\nisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYynXgf/jhB919992a\nNWuWysrKFIvFlEwmFQqFZNu2GhsbNTAwkM1ZAQAZcB34devWybZtdXV1qaurSz6fT+FwWLZtq6+v\nT0VFRero6MjmrACADLgO/L59+7R27VpNmDBB+fn5mjp1quLxuJqbm1VQUKCmpibFYrFszgoAyICr\nwJ84cUKDg4NqaWlRIBDQxo0blUqllEgk5PP5JEk+n0/xeDyrwwIAhi/fzYMGBwfV29urTZs2qa6u\nTitXrtRLL70kx3GG9fj169envw4GgwoGg27GAABjRaNRRaPRET2H5Qy3yn9QWlqqnp4eSdKuXbv0\n3HPP6aefflJra6v8fr8OHjyotrY2dXZ2Dl3Qsob9QjCaLMuSlIs5xsf+AvA2N+10fQ6+uLhYsVhM\n586d086dO1VXV6dAIKBIJKJUKqVIJKKamhq3Tw8AGCHXR/C9vb266667NDg4qLq6Oj388MM6d+6c\nli1bpkOHDum6667T888/r0mTJg1dkCN4AMiYm3a6DrxbBB4AMpfTUzQAgPGNwAOAoQg8ABiKwAOA\n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\n", | |
143 | "metadata": {}, |
|
144 | "metadata": {}, | |
144 | "output_type": "display_data", |
|
145 | "output_type": "display_data", | |
145 | "text/plain": [ |
|
146 | "text/plain": [ | |
146 | "<matplotlib.figure.Figure at 0x108c8f1d0>" |
|
147 | "<matplotlib.figure.Figure at 0x108c8f1d0>" | |
147 | ] |
|
148 | ] | |
148 | } |
|
149 | } | |
149 | ], |
|
150 | ], | |
150 | "prompt_number": 14, |
|
|||
151 | "source": [ |
|
151 | "source": [ | |
152 | "hist(evs.real)" |
|
152 | "hist(evs.real)" | |
153 | ] |
|
153 | ] | |
154 | }, |
|
154 | }, | |
155 | { |
|
155 | { | |
156 | "cell_type": "code", |
|
156 | "cell_type": "code", | |
|
157 | "execution_count": null, | |||
157 | "metadata": { |
|
158 | "metadata": { | |
158 | "collapsed": false |
|
159 | "collapsed": false | |
159 | }, |
|
160 | }, | |
160 | "outputs": [], |
|
161 | "outputs": [], | |
161 | "prompt_number": null, |
|
|||
162 | "source": [] |
|
162 | "source": [] | |
163 | } |
|
163 | } | |
164 | ], |
|
164 | ], | |
165 | "metadata": {}, |
|
165 | "metadata": {}, | |
166 | "nbformat": 4, |
|
166 | "nbformat": 4, | |
167 | "nbformat_minor": 0 |
|
167 | "nbformat_minor": 0 | |
168 | } No newline at end of file |
|
168 | } |
@@ -1,28 +1,20 | |||||
1 | """Module containing a preprocessor that removes the outputs from code cells""" |
|
1 | """Module containing a preprocessor that removes the outputs from code cells""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | #----------------------------------------------------------------------------- |
|
|||
7 | # Imports |
|
|||
8 | #----------------------------------------------------------------------------- |
|
|||
9 |
|
||||
10 | from .base import Preprocessor |
|
6 | from .base import Preprocessor | |
11 |
|
7 | |||
12 |
|
||||
13 | #----------------------------------------------------------------------------- |
|
|||
14 | # Classes |
|
|||
15 | #----------------------------------------------------------------------------- |
|
|||
16 | class ClearOutputPreprocessor(Preprocessor): |
|
8 | class ClearOutputPreprocessor(Preprocessor): | |
17 | """ |
|
9 | """ | |
18 | Removes the output from all code cells in a notebook. |
|
10 | Removes the output from all code cells in a notebook. | |
19 | """ |
|
11 | """ | |
20 |
|
12 | |||
21 | def preprocess_cell(self, cell, resources, cell_index): |
|
13 | def preprocess_cell(self, cell, resources, cell_index): | |
22 | """ |
|
14 | """ | |
23 | Apply a transformation on each cell. See base.py for details. |
|
15 | Apply a transformation on each cell. See base.py for details. | |
24 | """ |
|
16 | """ | |
25 | if cell.cell_type == 'code': |
|
17 | if cell.cell_type == 'code': | |
26 | cell.outputs = [] |
|
18 | cell.outputs = [] | |
27 |
cell. |
|
19 | cell.execution_count = None | |
28 | return cell, resources |
|
20 | return cell, resources |
@@ -1,114 +1,111 | |||||
1 | """Module containing a preprocessor that removes the outputs from code cells""" |
|
1 | """Module containing a preprocessor that removes the outputs from code cells""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | import os |
|
6 | import os | |
7 | import sys |
|
7 | import sys | |
8 |
|
8 | |||
9 | try: |
|
9 | try: | |
10 | from queue import Empty # Py 3 |
|
10 | from queue import Empty # Py 3 | |
11 | except ImportError: |
|
11 | except ImportError: | |
12 | from Queue import Empty # Py 2 |
|
12 | from Queue import Empty # Py 2 | |
13 |
|
13 | |||
14 | from IPython.utils.traitlets import List, Unicode |
|
14 | from IPython.utils.traitlets import List, Unicode | |
15 |
|
15 | |||
16 | from IPython.nbformat.current import reads, writes, output_from_msg |
|
16 | from IPython.nbformat.current import reads, writes, output_from_msg | |
17 | from .base import Preprocessor |
|
17 | from .base import Preprocessor | |
18 | from IPython.utils.traitlets import Integer |
|
18 | from IPython.utils.traitlets import Integer | |
19 |
|
19 | |||
20 | class ExecutePreprocessor(Preprocessor): |
|
20 | class ExecutePreprocessor(Preprocessor): | |
21 | """ |
|
21 | """ | |
22 | Executes all the cells in a notebook |
|
22 | Executes all the cells in a notebook | |
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
25 | timeout = Integer(30, config=True, |
|
25 | timeout = Integer(30, config=True, | |
26 | help="The time to wait (in seconds) for output from executions." |
|
26 | help="The time to wait (in seconds) for output from executions." | |
27 | ) |
|
27 | ) | |
28 |
|
28 | |||
29 | extra_arguments = List(Unicode) |
|
29 | extra_arguments = List(Unicode) | |
30 |
|
30 | |||
31 | def preprocess(self, nb, resources): |
|
31 | def preprocess(self, nb, resources): | |
32 | from IPython.kernel import run_kernel |
|
32 | from IPython.kernel import run_kernel | |
33 | kernel_name = nb.metadata.get('kernelspec', {}).get('name', 'python') |
|
33 | kernel_name = nb.metadata.get('kernelspec', {}).get('name', 'python') | |
34 | self.log.info("Executing notebook with kernel: %s" % kernel_name) |
|
34 | self.log.info("Executing notebook with kernel: %s" % kernel_name) | |
35 | with run_kernel(kernel_name=kernel_name, |
|
35 | with run_kernel(kernel_name=kernel_name, | |
36 | extra_arguments=self.extra_arguments, |
|
36 | extra_arguments=self.extra_arguments, | |
37 | stderr=open(os.devnull, 'w')) as kc: |
|
37 | stderr=open(os.devnull, 'w')) as kc: | |
38 | self.kc = kc |
|
38 | self.kc = kc | |
39 | nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources) |
|
39 | nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources) | |
40 | return nb, resources |
|
40 | return nb, resources | |
41 |
|
41 | |||
42 | def preprocess_cell(self, cell, resources, cell_index): |
|
42 | def preprocess_cell(self, cell, resources, cell_index): | |
43 | """ |
|
43 | """ | |
44 | Apply a transformation on each code cell. See base.py for details. |
|
44 | Apply a transformation on each code cell. See base.py for details. | |
45 | """ |
|
45 | """ | |
46 | if cell.cell_type != 'code': |
|
46 | if cell.cell_type != 'code': | |
47 | return cell, resources |
|
47 | return cell, resources | |
48 | try: |
|
48 | try: | |
49 | outputs = self.run_cell(self.kc.shell_channel, self.kc.iopub_channel, cell) |
|
49 | outputs = self.run_cell(self.kc.shell_channel, self.kc.iopub_channel, cell) | |
50 | except Exception as e: |
|
50 | except Exception as e: | |
51 | self.log.error("failed to run cell: " + repr(e)) |
|
51 | self.log.error("failed to run cell: " + repr(e)) | |
52 | self.log.error(str(cell.source)) |
|
52 | self.log.error(str(cell.source)) | |
53 | raise |
|
53 | raise | |
54 | cell.outputs = outputs |
|
54 | cell.outputs = outputs | |
55 | return cell, resources |
|
55 | return cell, resources | |
56 |
|
56 | |||
57 | def run_cell(self, shell, iopub, cell): |
|
57 | def run_cell(self, shell, iopub, cell): | |
58 | msg_id = shell.execute(cell.source) |
|
58 | msg_id = shell.execute(cell.source) | |
59 | self.log.debug("Executing cell:\n%s", cell.source) |
|
59 | self.log.debug("Executing cell:\n%s", cell.source) | |
60 | # wait for finish, with timeout |
|
60 | # wait for finish, with timeout | |
61 | while True: |
|
61 | while True: | |
62 | try: |
|
62 | try: | |
63 | msg = shell.get_msg(timeout=self.timeout) |
|
63 | msg = shell.get_msg(timeout=self.timeout) | |
64 | except Empty: |
|
64 | except Empty: | |
65 | self.log.error("Timeout waiting for execute reply") |
|
65 | self.log.error("Timeout waiting for execute reply") | |
66 | raise |
|
66 | raise | |
67 | if msg['parent_header'].get('msg_id') == msg_id: |
|
67 | if msg['parent_header'].get('msg_id') == msg_id: | |
68 | break |
|
68 | break | |
69 | else: |
|
69 | else: | |
70 | # not our reply |
|
70 | # not our reply | |
71 | continue |
|
71 | continue | |
72 |
|
72 | |||
73 | outs = [] |
|
73 | outs = [] | |
74 |
|
74 | |||
75 | while True: |
|
75 | while True: | |
76 | try: |
|
76 | try: | |
77 | msg = iopub.get_msg(timeout=self.timeout) |
|
77 | msg = iopub.get_msg(timeout=self.timeout) | |
78 | except Empty: |
|
78 | except Empty: | |
79 | self.log.warn("Timeout waiting for IOPub output") |
|
79 | self.log.warn("Timeout waiting for IOPub output") | |
80 | break |
|
80 | break | |
81 | if msg['parent_header'].get('msg_id') != msg_id: |
|
81 | if msg['parent_header'].get('msg_id') != msg_id: | |
82 | # not an output from our execution |
|
82 | # not an output from our execution | |
83 | continue |
|
83 | continue | |
84 |
|
84 | |||
85 | msg_type = msg['msg_type'] |
|
85 | msg_type = msg['msg_type'] | |
86 | self.log.debug("output: %s", msg_type) |
|
86 | self.log.debug("output: %s", msg_type) | |
87 | content = msg['content'] |
|
87 | content = msg['content'] | |
88 |
|
88 | |||
89 | # set the prompt number for the input and the output |
|
89 | # set the prompt number for the input and the output | |
90 | if 'execution_count' in content: |
|
90 | if 'execution_count' in content: | |
91 |
cell[' |
|
91 | cell['execution_count'] = content['execution_count'] | |
92 | out.prompt_number = content['execution_count'] |
|
|||
93 |
|
92 | |||
94 | if msg_type == 'status': |
|
93 | if msg_type == 'status': | |
95 | if content['execution_state'] == 'idle': |
|
94 | if content['execution_state'] == 'idle': | |
96 | break |
|
95 | break | |
97 | else: |
|
96 | else: | |
98 | continue |
|
97 | continue | |
99 | elif msg_type == 'execute_input': |
|
98 | elif msg_type == 'execute_input': | |
100 | continue |
|
99 | continue | |
101 | elif msg_type == 'clear_output': |
|
100 | elif msg_type == 'clear_output': | |
102 | outs = [] |
|
101 | outs = [] | |
103 | continue |
|
102 | continue | |
104 | elif msg_type == 'execute_result': |
|
|||
105 | cell['prompt_number'] = content['execution_count'] |
|
|||
106 |
|
103 | |||
107 | try: |
|
104 | try: | |
108 | out = output_from_msg(msg) |
|
105 | out = output_from_msg(msg) | |
109 | except ValueError: |
|
106 | except ValueError: | |
110 | self.log.error("unhandled iopub msg: " + msg_type) |
|
107 | self.log.error("unhandled iopub msg: " + msg_type) | |
111 | else: |
|
108 | else: | |
112 | outs.append(out) |
|
109 | outs.append(out) | |
113 |
|
110 | |||
114 | return outs |
|
111 | return outs |
@@ -1,41 +1,41 | |||||
1 | """utility functions for preprocessor tests""" |
|
1 | """utility functions for preprocessor tests""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from IPython.nbformat import current as nbformat |
|
6 | from IPython.nbformat import current as nbformat | |
7 |
|
7 | |||
8 | from ...tests.base import TestsBase |
|
8 | from ...tests.base import TestsBase | |
9 | from ...exporters.exporter import ResourcesDict |
|
9 | from ...exporters.exporter import ResourcesDict | |
10 |
|
10 | |||
11 |
|
11 | |||
12 | class PreprocessorTestsBase(TestsBase): |
|
12 | class PreprocessorTestsBase(TestsBase): | |
13 | """Contains test functions preprocessor tests""" |
|
13 | """Contains test functions preprocessor tests""" | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | def build_notebook(self): |
|
16 | def build_notebook(self): | |
17 | """Build a notebook in memory for use with preprocessor tests""" |
|
17 | """Build a notebook in memory for use with preprocessor tests""" | |
18 |
|
18 | |||
19 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a"), |
|
19 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a"), | |
20 | nbformat.new_output(output_type="display_data", mime_bundle={'text/plain': 'b'}), |
|
20 | nbformat.new_output(output_type="display_data", mime_bundle={'text/plain': 'b'}), | |
21 | nbformat.new_output(output_type="stream", name="stdout", text="c"), |
|
21 | nbformat.new_output(output_type="stream", name="stdout", text="c"), | |
22 | nbformat.new_output(output_type="stream", name="stdout", text="d"), |
|
22 | nbformat.new_output(output_type="stream", name="stdout", text="d"), | |
23 | nbformat.new_output(output_type="stream", name="stderr", text="e"), |
|
23 | nbformat.new_output(output_type="stream", name="stderr", text="e"), | |
24 | nbformat.new_output(output_type="stream", name="stderr", text="f"), |
|
24 | nbformat.new_output(output_type="stream", name="stderr", text="f"), | |
25 | nbformat.new_output(output_type="display_data", mime_bundle={'image/png': 'Zw=='})] # g |
|
25 | nbformat.new_output(output_type="display_data", mime_bundle={'image/png': 'Zw=='})] # g | |
26 | out = nbformat.new_output(output_type="display_data") |
|
26 | out = nbformat.new_output(output_type="display_data") | |
27 | out['application/pdf'] = 'aA==' |
|
27 | out['application/pdf'] = 'aA==' | |
28 | outputs.append(out) |
|
28 | outputs.append(out) | |
29 |
|
29 | |||
30 |
cells=[nbformat.new_code_cell(source="$ e $", |
|
30 | cells=[nbformat.new_code_cell(source="$ e $", execution_count=1, outputs=outputs), | |
31 | nbformat.new_markdown_cell(source="$ e $")] |
|
31 | nbformat.new_markdown_cell(source="$ e $")] | |
32 |
|
32 | |||
33 | return nbformat.new_notebook(cells=cells) |
|
33 | return nbformat.new_notebook(cells=cells) | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | def build_resources(self): |
|
36 | def build_resources(self): | |
37 | """Build an empty resources dictionary.""" |
|
37 | """Build an empty resources dictionary.""" | |
38 |
|
38 | |||
39 | res = ResourcesDict() |
|
39 | res = ResourcesDict() | |
40 | res['metadata'] = ResourcesDict() |
|
40 | res['metadata'] = ResourcesDict() | |
41 | return res |
|
41 | return res |
@@ -1,38 +1,38 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [], |
|
9 | "outputs": [], | |
9 | "prompt_number": 1, |
|
|||
10 | "source": [ |
|
10 | "source": [ | |
11 | "from IPython.display import clear_output" |
|
11 | "from IPython.display import clear_output" | |
12 | ] |
|
12 | ] | |
13 | }, |
|
13 | }, | |
14 | { |
|
14 | { | |
15 | "cell_type": "code", |
|
15 | "cell_type": "code", | |
|
16 | "execution_count": 2, | |||
16 | "metadata": { |
|
17 | "metadata": { | |
17 | "collapsed": false |
|
18 | "collapsed": false | |
18 | }, |
|
19 | }, | |
19 | "outputs": [ |
|
20 | "outputs": [ | |
20 | { |
|
21 | { | |
21 | "metadata": {}, |
|
22 | "metadata": {}, | |
22 | "name": "stdout", |
|
23 | "name": "stdout", | |
23 | "output_type": "stream", |
|
24 | "output_type": "stream", | |
24 | "text": "9\n" |
|
25 | "text": "9\n" | |
25 | } |
|
26 | } | |
26 | ], |
|
27 | ], | |
27 | "prompt_number": 2, |
|
|||
28 | "source": [ |
|
28 | "source": [ | |
29 | "for i in range(10):\n", |
|
29 | "for i in range(10):\n", | |
30 | " clear_output()\n", |
|
30 | " clear_output()\n", | |
31 | " print(i)" |
|
31 | " print(i)" | |
32 | ] |
|
32 | ] | |
33 | } |
|
33 | } | |
34 | ], |
|
34 | ], | |
35 | "metadata": {}, |
|
35 | "metadata": {}, | |
36 | "nbformat": 4, |
|
36 | "nbformat": 4, | |
37 | "nbformat_minor": 0 |
|
37 | "nbformat_minor": 0 | |
38 | } No newline at end of file |
|
38 | } |
@@ -1,38 +1,38 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [], |
|
9 | "outputs": [], | |
9 | "prompt_number": 1, |
|
|||
10 | "source": [ |
|
10 | "source": [ | |
11 | "i, j = 1, 1" |
|
11 | "i, j = 1, 1" | |
12 | ] |
|
12 | ] | |
13 | }, |
|
13 | }, | |
14 | { |
|
14 | { | |
15 | "cell_type": "code", |
|
15 | "cell_type": "code", | |
|
16 | "execution_count": 2, | |||
16 | "metadata": { |
|
17 | "metadata": { | |
17 | "collapsed": false |
|
18 | "collapsed": false | |
18 | }, |
|
19 | }, | |
19 | "outputs": [ |
|
20 | "outputs": [ | |
20 | { |
|
21 | { | |
21 | "metadata": {}, |
|
22 | "metadata": {}, | |
22 | "name": "stdout", |
|
23 | "name": "stdout", | |
23 | "output_type": "stream", |
|
24 | "output_type": "stream", | |
24 | "text": "2\n3\n5\n8\n13\n21\n34\n55\n89\n144\n" |
|
25 | "text": "2\n3\n5\n8\n13\n21\n34\n55\n89\n144\n" | |
25 | } |
|
26 | } | |
26 | ], |
|
27 | ], | |
27 | "prompt_number": 2, |
|
|||
28 | "source": [ |
|
28 | "source": [ | |
29 | "for m in range(10):\n", |
|
29 | "for m in range(10):\n", | |
30 | " i, j = j, i + j\n", |
|
30 | " i, j = j, i + j\n", | |
31 | " print(j)" |
|
31 | " print(j)" | |
32 | ] |
|
32 | ] | |
33 | } |
|
33 | } | |
34 | ], |
|
34 | ], | |
35 | "metadata": {}, |
|
35 | "metadata": {}, | |
36 | "nbformat": 4, |
|
36 | "nbformat": 4, | |
37 | "nbformat_minor": 0 |
|
37 | "nbformat_minor": 0 | |
38 | } No newline at end of file |
|
38 | } |
@@ -1,25 +1,25 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [ |
|
9 | "outputs": [ | |
9 | { |
|
10 | { | |
10 | "metadata": {}, |
|
11 | "metadata": {}, | |
11 | "name": "stdout", |
|
12 | "name": "stdout", | |
12 | "output_type": "stream", |
|
13 | "output_type": "stream", | |
13 | "text": "Hello World\n" |
|
14 | "text": "Hello World\n" | |
14 | } |
|
15 | } | |
15 | ], |
|
16 | ], | |
16 | "prompt_number": 1, |
|
|||
17 | "source": [ |
|
17 | "source": [ | |
18 | "print(\"Hello World\")" |
|
18 | "print(\"Hello World\")" | |
19 | ] |
|
19 | ] | |
20 | } |
|
20 | } | |
21 | ], |
|
21 | ], | |
22 | "metadata": {}, |
|
22 | "metadata": {}, | |
23 | "nbformat": 4, |
|
23 | "nbformat": 4, | |
24 | "nbformat_minor": 0 |
|
24 | "nbformat_minor": 0 | |
25 | } No newline at end of file |
|
25 | } |
@@ -1,29 +1,29 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [], |
|
9 | "outputs": [], | |
9 | "prompt_number": 1, |
|
|||
10 | "source": [ |
|
10 | "source": [ | |
11 | "from IPython.display import Image" |
|
11 | "from IPython.display import Image" | |
12 | ] |
|
12 | ] | |
13 | }, |
|
13 | }, | |
14 | { |
|
14 | { | |
15 | "cell_type": "code", |
|
15 | "cell_type": "code", | |
|
16 | "execution_count": 2, | |||
16 | "metadata": { |
|
17 | "metadata": { | |
17 | "collapsed": false |
|
18 | "collapsed": false | |
18 | }, |
|
19 | }, | |
19 | "outputs": [], |
|
20 | "outputs": [], | |
20 | "prompt_number": 2, |
|
|||
21 | "source": [ |
|
21 | "source": [ | |
22 | "Image('../input/python.png');" |
|
22 | "Image('../input/python.png');" | |
23 | ] |
|
23 | ] | |
24 | } |
|
24 | } | |
25 | ], |
|
25 | ], | |
26 | "metadata": {}, |
|
26 | "metadata": {}, | |
27 | "nbformat": 4, |
|
27 | "nbformat": 4, | |
28 | "nbformat_minor": 0 |
|
28 | "nbformat_minor": 0 | |
29 | } No newline at end of file |
|
29 | } |
@@ -1,46 +1,46 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [], |
|
9 | "outputs": [], | |
9 | "prompt_number": 1, |
|
|||
10 | "source": [ |
|
10 | "source": [ | |
11 | "from IPython.display import SVG" |
|
11 | "from IPython.display import SVG" | |
12 | ] |
|
12 | ] | |
13 | }, |
|
13 | }, | |
14 | { |
|
14 | { | |
15 | "cell_type": "code", |
|
15 | "cell_type": "code", | |
|
16 | "execution_count": 2, | |||
16 | "metadata": { |
|
17 | "metadata": { | |
17 | "collapsed": false |
|
18 | "collapsed": false | |
18 | }, |
|
19 | }, | |
19 | "outputs": [ |
|
20 | "outputs": [ | |
20 | { |
|
21 | { | |
|
22 | "execution_count": 2, | |||
21 | "image/svg+xml": [ |
|
23 | "image/svg+xml": [ | |
22 | "<svg height=\"100\" width=\"100\">\n", |
|
24 | "<svg height=\"100\" width=\"100\">\n", | |
23 | " <circle cx=\"50\" cy=\"50\" fill=\"red\" r=\"40\" stroke=\"black\" stroke-width=\"2\"/>\n", |
|
25 | " <circle cx=\"50\" cy=\"50\" fill=\"red\" r=\"40\" stroke=\"black\" stroke-width=\"2\"/>\n", | |
24 | "</svg>" |
|
26 | "</svg>" | |
25 | ], |
|
27 | ], | |
26 | "metadata": {}, |
|
28 | "metadata": {}, | |
27 | "output_type": "execute_result", |
|
29 | "output_type": "execute_result", | |
28 | "prompt_number": 2, |
|
|||
29 | "text/plain": [ |
|
30 | "text/plain": [ | |
30 | "<IPython.core.display.SVG object>" |
|
31 | "<IPython.core.display.SVG object>" | |
31 | ] |
|
32 | ] | |
32 | } |
|
33 | } | |
33 | ], |
|
34 | ], | |
34 | "prompt_number": 2, |
|
|||
35 | "source": [ |
|
35 | "source": [ | |
36 | "SVG(data='''\n", |
|
36 | "SVG(data='''\n", | |
37 | "<svg height=\"100\" width=\"100\">\n", |
|
37 | "<svg height=\"100\" width=\"100\">\n", | |
38 | " <circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"2\" fill=\"red\" />\n", |
|
38 | " <circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"2\" fill=\"red\" />\n", | |
39 | "</svg>''')" |
|
39 | "</svg>''')" | |
40 | ] |
|
40 | ] | |
41 | } |
|
41 | } | |
42 | ], |
|
42 | ], | |
43 | "metadata": {}, |
|
43 | "metadata": {}, | |
44 | "nbformat": 4, |
|
44 | "nbformat": 4, | |
45 | "nbformat_minor": 0 |
|
45 | "nbformat_minor": 0 | |
46 | } No newline at end of file |
|
46 | } |
@@ -1,51 +1,51 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [ |
|
9 | "outputs": [ | |
9 | { |
|
10 | { | |
10 | "ename": "Exception", |
|
11 | "ename": "Exception", | |
11 | "evalue": "message", |
|
12 | "evalue": "message", | |
12 | "metadata": {}, |
|
13 | "metadata": {}, | |
13 | "output_type": "error", |
|
14 | "output_type": "error", | |
14 | "traceback": [ |
|
15 | "traceback": [ | |
15 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", |
|
16 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", | |
16 | "\u001b[1;31mException\u001b[0m Traceback (most recent call last)", |
|
17 | "\u001b[1;31mException\u001b[0m Traceback (most recent call last)", | |
17 | "\u001b[1;32m<ipython-input-1-335814d14fc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"message\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", |
|
18 | "\u001b[1;32m<ipython-input-1-335814d14fc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"message\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", | |
18 | "\u001b[1;31mException\u001b[0m: message" |
|
19 | "\u001b[1;31mException\u001b[0m: message" | |
19 | ] |
|
20 | ] | |
20 | } |
|
21 | } | |
21 | ], |
|
22 | ], | |
22 | "prompt_number": 1, |
|
|||
23 | "source": [ |
|
23 | "source": [ | |
24 | "raise Exception(\"message\")" |
|
24 | "raise Exception(\"message\")" | |
25 | ] |
|
25 | ] | |
26 | }, |
|
26 | }, | |
27 | { |
|
27 | { | |
28 | "cell_type": "code", |
|
28 | "cell_type": "code", | |
|
29 | "execution_count": 2, | |||
29 | "metadata": { |
|
30 | "metadata": { | |
30 | "collapsed": false |
|
31 | "collapsed": false | |
31 | }, |
|
32 | }, | |
32 | "outputs": [ |
|
33 | "outputs": [ | |
33 | { |
|
34 | { | |
34 | "metadata": {}, |
|
35 | "metadata": {}, | |
35 | "name": "stdout", |
|
36 | "name": "stdout", | |
36 | "output_type": "stream", |
|
37 | "output_type": "stream", | |
37 | "text": "ok\n" |
|
38 | "text": "ok\n" | |
38 | } |
|
39 | } | |
39 | ], |
|
40 | ], | |
40 | "prompt_number": 2, |
|
|||
41 | "source": [ |
|
41 | "source": [ | |
42 | "print('ok')" |
|
42 | "print('ok')" | |
43 | ] |
|
43 | ] | |
44 | } |
|
44 | } | |
45 | ], |
|
45 | ], | |
46 | "metadata": { |
|
46 | "metadata": { | |
47 | "signature": "sha256:9d47889f0678e9685429071216d0f3354db59bb66489f3225bcadfb6a1a9bbba" |
|
47 | "signature": "sha256:9d47889f0678e9685429071216d0f3354db59bb66489f3225bcadfb6a1a9bbba" | |
48 | }, |
|
48 | }, | |
49 | "nbformat": 4, |
|
49 | "nbformat": 4, | |
50 | "nbformat_minor": 0 |
|
50 | "nbformat_minor": 0 | |
51 | } No newline at end of file |
|
51 | } |
@@ -1,25 +1,25 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "code", |
|
4 | "cell_type": "code", | |
|
5 | "execution_count": 1, | |||
5 | "metadata": { |
|
6 | "metadata": { | |
6 | "collapsed": false |
|
7 | "collapsed": false | |
7 | }, |
|
8 | }, | |
8 | "outputs": [ |
|
9 | "outputs": [ | |
9 | { |
|
10 | { | |
10 | "metadata": {}, |
|
11 | "metadata": {}, | |
11 | "name": "stdout", |
|
12 | "name": "stdout", | |
12 | "output_type": "stream", |
|
13 | "output_type": "stream", | |
13 | "text": "\u2603\n" |
|
14 | "text": "\u2603\n" | |
14 | } |
|
15 | } | |
15 | ], |
|
16 | ], | |
16 | "prompt_number": 1, |
|
|||
17 | "source": [ |
|
17 | "source": [ | |
18 | "print('\u2603')" |
|
18 | "print('\u2603')" | |
19 | ] |
|
19 | ] | |
20 | } |
|
20 | } | |
21 | ], |
|
21 | ], | |
22 | "metadata": {}, |
|
22 | "metadata": {}, | |
23 | "nbformat": 4, |
|
23 | "nbformat": 4, | |
24 | "nbformat_minor": 0 |
|
24 | "nbformat_minor": 0 | |
25 | } No newline at end of file |
|
25 | } |
@@ -1,35 +1,35 | |||||
1 | """ |
|
1 | """ | |
2 | Module with tests for the clearoutput preprocessor. |
|
2 | Module with tests for the clearoutput preprocessor. | |
3 | """ |
|
3 | """ | |
4 |
|
4 | |||
5 | # Copyright (c) IPython Development Team. |
|
5 | # Copyright (c) IPython Development Team. | |
6 | # Distributed under the terms of the Modified BSD License. |
|
6 | # Distributed under the terms of the Modified BSD License. | |
7 |
|
7 | |||
8 | from IPython.nbformat import current as nbformat |
|
8 | from IPython.nbformat import current as nbformat | |
9 |
|
9 | |||
10 | from .base import PreprocessorTestsBase |
|
10 | from .base import PreprocessorTestsBase | |
11 | from ..clearoutput import ClearOutputPreprocessor |
|
11 | from ..clearoutput import ClearOutputPreprocessor | |
12 |
|
12 | |||
13 |
|
13 | |||
14 | class TestClearOutput(PreprocessorTestsBase): |
|
14 | class TestClearOutput(PreprocessorTestsBase): | |
15 | """Contains test functions for clearoutput.py""" |
|
15 | """Contains test functions for clearoutput.py""" | |
16 |
|
16 | |||
17 |
|
17 | |||
18 | def build_preprocessor(self): |
|
18 | def build_preprocessor(self): | |
19 | """Make an instance of a preprocessor""" |
|
19 | """Make an instance of a preprocessor""" | |
20 | preprocessor = ClearOutputPreprocessor() |
|
20 | preprocessor = ClearOutputPreprocessor() | |
21 | preprocessor.enabled = True |
|
21 | preprocessor.enabled = True | |
22 | return preprocessor |
|
22 | return preprocessor | |
23 |
|
23 | |||
24 | def test_constructor(self): |
|
24 | def test_constructor(self): | |
25 | """Can a ClearOutputPreprocessor be constructed?""" |
|
25 | """Can a ClearOutputPreprocessor be constructed?""" | |
26 | self.build_preprocessor() |
|
26 | self.build_preprocessor() | |
27 |
|
27 | |||
28 | def test_output(self): |
|
28 | def test_output(self): | |
29 | """Test the output of the ClearOutputPreprocessor""" |
|
29 | """Test the output of the ClearOutputPreprocessor""" | |
30 | nb = self.build_notebook() |
|
30 | nb = self.build_notebook() | |
31 | res = self.build_resources() |
|
31 | res = self.build_resources() | |
32 | preprocessor = self.build_preprocessor() |
|
32 | preprocessor = self.build_preprocessor() | |
33 | nb, res = preprocessor(nb, res) |
|
33 | nb, res = preprocessor(nb, res) | |
34 | assert nb.cells[0].outputs == [] |
|
34 | assert nb.cells[0].outputs == [] | |
35 |
assert nb.cells[0]. |
|
35 | assert nb.cells[0].execution_count is None |
@@ -1,58 +1,58 | |||||
1 | """Tests for the coalescestreams preprocessor""" |
|
1 | """Tests for the coalescestreams preprocessor""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from IPython.nbformat import current as nbformat |
|
6 | from IPython.nbformat import current as nbformat | |
7 |
|
7 | |||
8 | from .base import PreprocessorTestsBase |
|
8 | from .base import PreprocessorTestsBase | |
9 | from ..coalescestreams import coalesce_streams |
|
9 | from ..coalescestreams import coalesce_streams | |
10 |
|
10 | |||
11 |
|
11 | |||
12 | class TestCoalesceStreams(PreprocessorTestsBase): |
|
12 | class TestCoalesceStreams(PreprocessorTestsBase): | |
13 | """Contains test functions for coalescestreams.py""" |
|
13 | """Contains test functions for coalescestreams.py""" | |
14 |
|
14 | |||
15 | def test_coalesce_streams(self): |
|
15 | def test_coalesce_streams(self): | |
16 | """coalesce_streams preprocessor output test""" |
|
16 | """coalesce_streams preprocessor output test""" | |
17 | nb = self.build_notebook() |
|
17 | nb = self.build_notebook() | |
18 | res = self.build_resources() |
|
18 | res = self.build_resources() | |
19 | nb, res = coalesce_streams(nb, res) |
|
19 | nb, res = coalesce_streams(nb, res) | |
20 | outputs = nb.cells[0].outputs |
|
20 | outputs = nb.cells[0].outputs | |
21 | self.assertEqual(outputs[0].text, "a") |
|
21 | self.assertEqual(outputs[0].text, "a") | |
22 | self.assertEqual(outputs[1].output_type, "display_data") |
|
22 | self.assertEqual(outputs[1].output_type, "display_data") | |
23 | self.assertEqual(outputs[2].text, "cd") |
|
23 | self.assertEqual(outputs[2].text, "cd") | |
24 | self.assertEqual(outputs[3].text, "ef") |
|
24 | self.assertEqual(outputs[3].text, "ef") | |
25 |
|
25 | |||
26 | def test_coalesce_sequenced_streams(self): |
|
26 | def test_coalesce_sequenced_streams(self): | |
27 | """Can the coalesce streams preprocessor merge a sequence of streams?""" |
|
27 | """Can the coalesce streams preprocessor merge a sequence of streams?""" | |
28 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="0"), |
|
28 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="0"), | |
29 | nbformat.new_output(output_type="stream", name="stdout", text="1"), |
|
29 | nbformat.new_output(output_type="stream", name="stdout", text="1"), | |
30 | nbformat.new_output(output_type="stream", name="stdout", text="2"), |
|
30 | nbformat.new_output(output_type="stream", name="stdout", text="2"), | |
31 | nbformat.new_output(output_type="stream", name="stdout", text="3"), |
|
31 | nbformat.new_output(output_type="stream", name="stdout", text="3"), | |
32 | nbformat.new_output(output_type="stream", name="stdout", text="4"), |
|
32 | nbformat.new_output(output_type="stream", name="stdout", text="4"), | |
33 | nbformat.new_output(output_type="stream", name="stdout", text="5"), |
|
33 | nbformat.new_output(output_type="stream", name="stdout", text="5"), | |
34 | nbformat.new_output(output_type="stream", name="stdout", text="6"), |
|
34 | nbformat.new_output(output_type="stream", name="stdout", text="6"), | |
35 | nbformat.new_output(output_type="stream", name="stdout", text="7")] |
|
35 | nbformat.new_output(output_type="stream", name="stdout", text="7")] | |
36 |
cells=[nbformat.new_code_cell(source="# None", |
|
36 | cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)] | |
37 |
|
37 | |||
38 | nb = nbformat.new_notebook(cells=cells) |
|
38 | nb = nbformat.new_notebook(cells=cells) | |
39 | res = self.build_resources() |
|
39 | res = self.build_resources() | |
40 | nb, res = coalesce_streams(nb, res) |
|
40 | nb, res = coalesce_streams(nb, res) | |
41 | outputs = nb.cells[0].outputs |
|
41 | outputs = nb.cells[0].outputs | |
42 | self.assertEqual(outputs[0].text, u'01234567') |
|
42 | self.assertEqual(outputs[0].text, u'01234567') | |
43 |
|
43 | |||
44 | def test_coalesce_replace_streams(self): |
|
44 | def test_coalesce_replace_streams(self): | |
45 | """Are \\r characters handled?""" |
|
45 | """Are \\r characters handled?""" | |
46 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="z"), |
|
46 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="z"), | |
47 | nbformat.new_output(output_type="stream", name="stdout", text="\ra"), |
|
47 | nbformat.new_output(output_type="stream", name="stdout", text="\ra"), | |
48 | nbformat.new_output(output_type="stream", name="stdout", text="\nz\rb"), |
|
48 | nbformat.new_output(output_type="stream", name="stdout", text="\nz\rb"), | |
49 | nbformat.new_output(output_type="stream", name="stdout", text="\nz"), |
|
49 | nbformat.new_output(output_type="stream", name="stdout", text="\nz"), | |
50 | nbformat.new_output(output_type="stream", name="stdout", text="\rc\n"), |
|
50 | nbformat.new_output(output_type="stream", name="stdout", text="\rc\n"), | |
51 | nbformat.new_output(output_type="stream", name="stdout", text="z\rz\rd")] |
|
51 | nbformat.new_output(output_type="stream", name="stdout", text="z\rz\rd")] | |
52 |
cells=[nbformat.new_code_cell(source="# None", |
|
52 | cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)] | |
53 |
|
53 | |||
54 | nb = nbformat.new_notebook(cells=cells) |
|
54 | nb = nbformat.new_notebook(cells=cells) | |
55 | res = self.build_resources() |
|
55 | res = self.build_resources() | |
56 | nb, res = coalesce_streams(nb, res) |
|
56 | nb, res = coalesce_streams(nb, res) | |
57 | outputs = nb.cells[0].outputs |
|
57 | outputs = nb.cells[0].outputs | |
58 | self.assertEqual(outputs[0].text, u'a\nb\nc\nd') |
|
58 | self.assertEqual(outputs[0].text, u'a\nb\nc\nd') |
@@ -1,88 +1,88 | |||||
1 | """ |
|
1 | """ | |
2 | Module with tests for the execute preprocessor. |
|
2 | Module with tests for the execute preprocessor. | |
3 | """ |
|
3 | """ | |
4 |
|
4 | |||
5 | # Copyright (c) IPython Development Team. |
|
5 | # Copyright (c) IPython Development Team. | |
6 | # Distributed under the terms of the Modified BSD License. |
|
6 | # Distributed under the terms of the Modified BSD License. | |
7 |
|
7 | |||
8 | import copy |
|
8 | import copy | |
9 | import glob |
|
9 | import glob | |
10 | import os |
|
10 | import os | |
11 | import re |
|
11 | import re | |
12 |
|
12 | |||
13 | from IPython.nbformat import current as nbformat |
|
13 | from IPython.nbformat import current as nbformat | |
14 |
|
14 | |||
15 | from .base import PreprocessorTestsBase |
|
15 | from .base import PreprocessorTestsBase | |
16 | from ..execute import ExecutePreprocessor |
|
16 | from ..execute import ExecutePreprocessor | |
17 |
|
17 | |||
18 | from IPython.nbconvert.filters import strip_ansi |
|
18 | from IPython.nbconvert.filters import strip_ansi | |
19 |
|
19 | |||
20 | addr_pat = re.compile(r'0x[0-9a-f]{7,9}') |
|
20 | addr_pat = re.compile(r'0x[0-9a-f]{7,9}') | |
21 |
|
21 | |||
22 | class TestExecute(PreprocessorTestsBase): |
|
22 | class TestExecute(PreprocessorTestsBase): | |
23 | """Contains test functions for execute.py""" |
|
23 | """Contains test functions for execute.py""" | |
24 |
|
24 | |||
25 | @staticmethod |
|
25 | @staticmethod | |
26 | def normalize_output(output): |
|
26 | def normalize_output(output): | |
27 | """ |
|
27 | """ | |
28 | Normalizes outputs for comparison. |
|
28 | Normalizes outputs for comparison. | |
29 | """ |
|
29 | """ | |
30 | output = dict(output) |
|
30 | output = dict(output) | |
31 | if 'metadata' in output: |
|
31 | if 'metadata' in output: | |
32 | del output['metadata'] |
|
32 | del output['metadata'] | |
33 | if 'text/plain' in output: |
|
33 | if 'text/plain' in output: | |
34 | output['text/plain'] = re.sub(addr_pat, '<HEXADDR>', output['text/plain']) |
|
34 | output['text/plain'] = re.sub(addr_pat, '<HEXADDR>', output['text/plain']) | |
35 | if 'traceback' in output: |
|
35 | if 'traceback' in output: | |
36 | tb = [] |
|
36 | tb = [] | |
37 | for line in output['traceback']: |
|
37 | for line in output['traceback']: | |
38 | tb.append(strip_ansi(line)) |
|
38 | tb.append(strip_ansi(line)) | |
39 | output['traceback'] = tb |
|
39 | output['traceback'] = tb | |
40 |
|
40 | |||
41 | return output |
|
41 | return output | |
42 |
|
42 | |||
43 |
|
43 | |||
44 | def assert_notebooks_equal(self, expected, actual): |
|
44 | def assert_notebooks_equal(self, expected, actual): | |
45 | expected_cells = expected['cells'] |
|
45 | expected_cells = expected['cells'] | |
46 | actual_cells = actual['cells'] |
|
46 | actual_cells = actual['cells'] | |
47 | assert len(expected_cells) == len(actual_cells) |
|
47 | assert len(expected_cells) == len(actual_cells) | |
48 |
|
48 | |||
49 | for expected_cell, actual_cell in zip(expected_cells, actual_cells): |
|
49 | for expected_cell, actual_cell in zip(expected_cells, actual_cells): | |
50 | expected_outputs = expected_cell.get('outputs', []) |
|
50 | expected_outputs = expected_cell.get('outputs', []) | |
51 | actual_outputs = actual_cell.get('outputs', []) |
|
51 | actual_outputs = actual_cell.get('outputs', []) | |
52 | normalized_expected_outputs = list(map(self.normalize_output, expected_outputs)) |
|
52 | normalized_expected_outputs = list(map(self.normalize_output, expected_outputs)) | |
53 | normalized_actual_outputs = list(map(self.normalize_output, actual_outputs)) |
|
53 | normalized_actual_outputs = list(map(self.normalize_output, actual_outputs)) | |
54 | assert normalized_expected_outputs == normalized_actual_outputs |
|
54 | assert normalized_expected_outputs == normalized_actual_outputs | |
55 |
|
55 | |||
56 |
expected_ |
|
56 | expected_execution_count = expected_cell.get('execution_count', None) | |
57 |
actual_ |
|
57 | actual_execution_count = actual_cell.get('execution_count', None) | |
58 |
assert expected_ |
|
58 | assert expected_execution_count == actual_execution_count | |
59 |
|
59 | |||
60 |
|
60 | |||
61 | def build_preprocessor(self): |
|
61 | def build_preprocessor(self): | |
62 | """Make an instance of a preprocessor""" |
|
62 | """Make an instance of a preprocessor""" | |
63 | preprocessor = ExecutePreprocessor() |
|
63 | preprocessor = ExecutePreprocessor() | |
64 | preprocessor.enabled = True |
|
64 | preprocessor.enabled = True | |
65 | return preprocessor |
|
65 | return preprocessor | |
66 |
|
66 | |||
67 |
|
67 | |||
68 | def test_constructor(self): |
|
68 | def test_constructor(self): | |
69 | """Can a ExecutePreprocessor be constructed?""" |
|
69 | """Can a ExecutePreprocessor be constructed?""" | |
70 | self.build_preprocessor() |
|
70 | self.build_preprocessor() | |
71 |
|
71 | |||
72 |
|
72 | |||
73 | def test_run_notebooks(self): |
|
73 | def test_run_notebooks(self): | |
74 | """Runs a series of test notebooks and compares them to their actual output""" |
|
74 | """Runs a series of test notebooks and compares them to their actual output""" | |
75 | current_dir = os.path.dirname(__file__) |
|
75 | current_dir = os.path.dirname(__file__) | |
76 | input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb')) |
|
76 | input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb')) | |
77 | for filename in input_files: |
|
77 | for filename in input_files: | |
78 | with open(os.path.join(current_dir, 'files', filename)) as f: |
|
78 | with open(os.path.join(current_dir, 'files', filename)) as f: | |
79 | input_nb = nbformat.read(f, 'ipynb') |
|
79 | input_nb = nbformat.read(f, 'ipynb') | |
80 | res = self.build_resources() |
|
80 | res = self.build_resources() | |
81 | preprocessor = self.build_preprocessor() |
|
81 | preprocessor = self.build_preprocessor() | |
82 | cleaned_input_nb = copy.deepcopy(input_nb) |
|
82 | cleaned_input_nb = copy.deepcopy(input_nb) | |
83 | for cell in cleaned_input_nb.cells: |
|
83 | for cell in cleaned_input_nb.cells: | |
84 |
if ' |
|
84 | if 'execution_count' in cell: | |
85 |
del cell[' |
|
85 | del cell['execution_count'] | |
86 | cell['outputs'] = [] |
|
86 | cell['outputs'] = [] | |
87 | output_nb, _ = preprocessor(cleaned_input_nb, res) |
|
87 | output_nb, _ = preprocessor(cleaned_input_nb, res) | |
88 | self.assert_notebooks_equal(output_nb, input_nb) |
|
88 | self.assert_notebooks_equal(output_nb, input_nb) |
@@ -1,78 +1,78 | |||||
1 | """Tests for the revealhelp preprocessor""" |
|
1 | """Tests for the revealhelp preprocessor""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from IPython.nbformat import current as nbformat |
|
6 | from IPython.nbformat import current as nbformat | |
7 |
|
7 | |||
8 | from .base import PreprocessorTestsBase |
|
8 | from .base import PreprocessorTestsBase | |
9 | from ..revealhelp import RevealHelpPreprocessor |
|
9 | from ..revealhelp import RevealHelpPreprocessor | |
10 |
|
10 | |||
11 |
|
11 | |||
12 | class Testrevealhelp(PreprocessorTestsBase): |
|
12 | class Testrevealhelp(PreprocessorTestsBase): | |
13 | """Contains test functions for revealhelp.py""" |
|
13 | """Contains test functions for revealhelp.py""" | |
14 |
|
14 | |||
15 | def build_notebook(self): |
|
15 | def build_notebook(self): | |
16 | """Build a reveal slides notebook in memory for use with tests. |
|
16 | """Build a reveal slides notebook in memory for use with tests. | |
17 | Overrides base in PreprocessorTestsBase""" |
|
17 | Overrides base in PreprocessorTestsBase""" | |
18 |
|
18 | |||
19 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a")] |
|
19 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a")] | |
20 |
|
20 | |||
21 | slide_metadata = {'slideshow' : {'slide_type': 'slide'}} |
|
21 | slide_metadata = {'slideshow' : {'slide_type': 'slide'}} | |
22 | subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}} |
|
22 | subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}} | |
23 |
|
23 | |||
24 |
cells=[nbformat.new_code_cell(source="", |
|
24 | cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs), | |
25 | nbformat.new_markdown_cell(source="", metadata=slide_metadata), |
|
25 | nbformat.new_markdown_cell(source="", metadata=slide_metadata), | |
26 |
nbformat.new_code_cell(source="", |
|
26 | nbformat.new_code_cell(source="", execution_count=2, outputs=outputs), | |
27 | nbformat.new_markdown_cell(source="", metadata=slide_metadata), |
|
27 | nbformat.new_markdown_cell(source="", metadata=slide_metadata), | |
28 | nbformat.new_markdown_cell(source="", metadata=subslide_metadata)] |
|
28 | nbformat.new_markdown_cell(source="", metadata=subslide_metadata)] | |
29 |
|
29 | |||
30 | return nbformat.new_notebook(cells=cells) |
|
30 | return nbformat.new_notebook(cells=cells) | |
31 |
|
31 | |||
32 |
|
32 | |||
33 | def build_preprocessor(self): |
|
33 | def build_preprocessor(self): | |
34 | """Make an instance of a preprocessor""" |
|
34 | """Make an instance of a preprocessor""" | |
35 | preprocessor = RevealHelpPreprocessor() |
|
35 | preprocessor = RevealHelpPreprocessor() | |
36 | preprocessor.enabled = True |
|
36 | preprocessor.enabled = True | |
37 | return preprocessor |
|
37 | return preprocessor | |
38 |
|
38 | |||
39 |
|
39 | |||
40 | def test_constructor(self): |
|
40 | def test_constructor(self): | |
41 | """Can a RevealHelpPreprocessor be constructed?""" |
|
41 | """Can a RevealHelpPreprocessor be constructed?""" | |
42 | self.build_preprocessor() |
|
42 | self.build_preprocessor() | |
43 |
|
43 | |||
44 |
|
44 | |||
45 | def test_reveal_attribute(self): |
|
45 | def test_reveal_attribute(self): | |
46 | """Make sure the reveal url_prefix resources is set""" |
|
46 | """Make sure the reveal url_prefix resources is set""" | |
47 | nb = self.build_notebook() |
|
47 | nb = self.build_notebook() | |
48 | res = self.build_resources() |
|
48 | res = self.build_resources() | |
49 | preprocessor = self.build_preprocessor() |
|
49 | preprocessor = self.build_preprocessor() | |
50 | nb, res = preprocessor(nb, res) |
|
50 | nb, res = preprocessor(nb, res) | |
51 | assert 'reveal' in res |
|
51 | assert 'reveal' in res | |
52 | assert 'url_prefix' in res['reveal'] |
|
52 | assert 'url_prefix' in res['reveal'] | |
53 |
|
53 | |||
54 |
|
54 | |||
55 | def test_reveal_output(self): |
|
55 | def test_reveal_output(self): | |
56 | """Make sure that the reveal preprocessor """ |
|
56 | """Make sure that the reveal preprocessor """ | |
57 | nb = self.build_notebook() |
|
57 | nb = self.build_notebook() | |
58 | res = self.build_resources() |
|
58 | res = self.build_resources() | |
59 | preprocessor = self.build_preprocessor() |
|
59 | preprocessor = self.build_preprocessor() | |
60 | nb, res = preprocessor(nb, res) |
|
60 | nb, res = preprocessor(nb, res) | |
61 | cells = nb.cells |
|
61 | cells = nb.cells | |
62 |
|
62 | |||
63 | # Make sure correct metadata tags are available on every cell. |
|
63 | # Make sure correct metadata tags are available on every cell. | |
64 | for cell in cells: |
|
64 | for cell in cells: | |
65 | assert 'slide_type' in cell.metadata |
|
65 | assert 'slide_type' in cell.metadata | |
66 |
|
66 | |||
67 | # Make sure slide end is only applied to the cells preceeding slide |
|
67 | # Make sure slide end is only applied to the cells preceeding slide | |
68 | # cells. |
|
68 | # cells. | |
69 | assert 'slide_helper' in cells[1].metadata |
|
69 | assert 'slide_helper' in cells[1].metadata | |
70 | self.assertEqual(cells[1].metadata['slide_helper'], '-') |
|
70 | self.assertEqual(cells[1].metadata['slide_helper'], '-') | |
71 |
|
71 | |||
72 | # Verify 'slide-end' |
|
72 | # Verify 'slide-end' | |
73 | assert 'slide_helper' in cells[0].metadata |
|
73 | assert 'slide_helper' in cells[0].metadata | |
74 | self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end') |
|
74 | self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end') | |
75 | assert 'slide_helper' in cells[2].metadata |
|
75 | assert 'slide_helper' in cells[2].metadata | |
76 | self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end') |
|
76 | self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end') | |
77 | assert 'slide_helper' in cells[3].metadata |
|
77 | assert 'slide_helper' in cells[3].metadata | |
78 | self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end') |
|
78 | self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end') |
@@ -1,74 +1,74 | |||||
1 | """Tests for the svg2pdf preprocessor""" |
|
1 | """Tests for the svg2pdf preprocessor""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from IPython.testing import decorators as dec |
|
6 | from IPython.testing import decorators as dec | |
7 | from IPython.nbformat import current as nbformat |
|
7 | from IPython.nbformat import current as nbformat | |
8 |
|
8 | |||
9 | from .base import PreprocessorTestsBase |
|
9 | from .base import PreprocessorTestsBase | |
10 | from ..svg2pdf import SVG2PDFPreprocessor |
|
10 | from ..svg2pdf import SVG2PDFPreprocessor | |
11 |
|
11 | |||
12 |
|
12 | |||
13 | class Testsvg2pdf(PreprocessorTestsBase): |
|
13 | class Testsvg2pdf(PreprocessorTestsBase): | |
14 | """Contains test functions for svg2pdf.py""" |
|
14 | """Contains test functions for svg2pdf.py""" | |
15 |
|
15 | |||
16 | simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
16 | simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
17 | <!-- Created with Inkscape (http://www.inkscape.org/) --> |
|
17 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | |
18 | <svg |
|
18 | <svg | |
19 | xmlns:svg="http://www.w3.org/2000/svg" |
|
19 | xmlns:svg="http://www.w3.org/2000/svg" | |
20 | xmlns="http://www.w3.org/2000/svg" |
|
20 | xmlns="http://www.w3.org/2000/svg" | |
21 | version="1.0" |
|
21 | version="1.0" | |
22 | x="0.00000000" |
|
22 | x="0.00000000" | |
23 | y="0.00000000" |
|
23 | y="0.00000000" | |
24 | width="500.00000" |
|
24 | width="500.00000" | |
25 | height="500.00000" |
|
25 | height="500.00000" | |
26 | id="svg2"> |
|
26 | id="svg2"> | |
27 | <defs |
|
27 | <defs | |
28 | id="defs4" /> |
|
28 | id="defs4" /> | |
29 | <g |
|
29 | <g | |
30 | id="layer1"> |
|
30 | id="layer1"> | |
31 | <rect |
|
31 | <rect | |
32 | width="300.00000" |
|
32 | width="300.00000" | |
33 | height="300.00000" |
|
33 | height="300.00000" | |
34 | x="100.00000" |
|
34 | x="100.00000" | |
35 | y="100.00000" |
|
35 | y="100.00000" | |
36 | style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000" |
|
36 | style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000" | |
37 | id="rect5719" /> |
|
37 | id="rect5719" /> | |
38 | </g> |
|
38 | </g> | |
39 | </svg>""" |
|
39 | </svg>""" | |
40 |
|
40 | |||
41 | def build_notebook(self): |
|
41 | def build_notebook(self): | |
42 | """Build a reveal slides notebook in memory for use with tests. |
|
42 | """Build a reveal slides notebook in memory for use with tests. | |
43 | Overrides base in PreprocessorTestsBase""" |
|
43 | Overrides base in PreprocessorTestsBase""" | |
44 |
|
44 | |||
45 | outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)] |
|
45 | outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)] | |
46 |
|
46 | |||
47 | slide_metadata = {'slideshow' : {'slide_type': 'slide'}} |
|
47 | slide_metadata = {'slideshow' : {'slide_type': 'slide'}} | |
48 | subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}} |
|
48 | subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}} | |
49 |
|
49 | |||
50 |
cells=[nbformat.new_code_cell(source="", |
|
50 | cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs)] | |
51 |
|
51 | |||
52 | return nbformat.new_notebook(cells=cells) |
|
52 | return nbformat.new_notebook(cells=cells) | |
53 |
|
53 | |||
54 |
|
54 | |||
55 | def build_preprocessor(self): |
|
55 | def build_preprocessor(self): | |
56 | """Make an instance of a preprocessor""" |
|
56 | """Make an instance of a preprocessor""" | |
57 | preprocessor = SVG2PDFPreprocessor() |
|
57 | preprocessor = SVG2PDFPreprocessor() | |
58 | preprocessor.enabled = True |
|
58 | preprocessor.enabled = True | |
59 | return preprocessor |
|
59 | return preprocessor | |
60 |
|
60 | |||
61 |
|
61 | |||
62 | def test_constructor(self): |
|
62 | def test_constructor(self): | |
63 | """Can a SVG2PDFPreprocessor be constructed?""" |
|
63 | """Can a SVG2PDFPreprocessor be constructed?""" | |
64 | self.build_preprocessor() |
|
64 | self.build_preprocessor() | |
65 |
|
65 | |||
66 |
|
66 | |||
67 | @dec.onlyif_cmds_exist('inkscape') |
|
67 | @dec.onlyif_cmds_exist('inkscape') | |
68 | def test_output(self): |
|
68 | def test_output(self): | |
69 | """Test the output of the SVG2PDFPreprocessor""" |
|
69 | """Test the output of the SVG2PDFPreprocessor""" | |
70 | nb = self.build_notebook() |
|
70 | nb = self.build_notebook() | |
71 | res = self.build_resources() |
|
71 | res = self.build_resources() | |
72 | preprocessor = self.build_preprocessor() |
|
72 | preprocessor = self.build_preprocessor() | |
73 | nb, res = preprocessor(nb, res) |
|
73 | nb, res = preprocessor(nb, res) | |
74 | assert 'svg' in nb.cells[0].outputs[0] |
|
74 | assert 'svg' in nb.cells[0].outputs[0] |
@@ -1,203 +1,203 | |||||
1 | {%- extends 'display_priority.tpl' -%} |
|
1 | {%- extends 'display_priority.tpl' -%} | |
2 |
|
2 | |||
3 |
|
3 | |||
4 | {% block codecell %} |
|
4 | {% block codecell %} | |
5 | <div class="cell border-box-sizing code_cell rendered"> |
|
5 | <div class="cell border-box-sizing code_cell rendered"> | |
6 | {{ super() }} |
|
6 | {{ super() }} | |
7 | </div> |
|
7 | </div> | |
8 | {%- endblock codecell %} |
|
8 | {%- endblock codecell %} | |
9 |
|
9 | |||
10 | {% block input_group -%} |
|
10 | {% block input_group -%} | |
11 | <div class="input"> |
|
11 | <div class="input"> | |
12 | {{ super() }} |
|
12 | {{ super() }} | |
13 | </div> |
|
13 | </div> | |
14 | {% endblock input_group %} |
|
14 | {% endblock input_group %} | |
15 |
|
15 | |||
16 | {% block output_group %} |
|
16 | {% block output_group %} | |
17 | <div class="output_wrapper"> |
|
17 | <div class="output_wrapper"> | |
18 | <div class="output"> |
|
18 | <div class="output"> | |
19 | {{ super() }} |
|
19 | {{ super() }} | |
20 | </div> |
|
20 | </div> | |
21 | </div> |
|
21 | </div> | |
22 | {% endblock output_group %} |
|
22 | {% endblock output_group %} | |
23 |
|
23 | |||
24 | {% block in_prompt -%} |
|
24 | {% block in_prompt -%} | |
25 | <div class="prompt input_prompt"> |
|
25 | <div class="prompt input_prompt"> | |
26 |
{%- if cell. |
|
26 | {%- if cell.execution_count is defined -%} | |
27 |
In [{{ cell. |
|
27 | In [{{ cell.execution_count|replace(None, " ") }}]: | |
28 | {%- else -%} |
|
28 | {%- else -%} | |
29 | In [ ]: |
|
29 | In [ ]: | |
30 | {%- endif -%} |
|
30 | {%- endif -%} | |
31 | </div> |
|
31 | </div> | |
32 | {%- endblock in_prompt %} |
|
32 | {%- endblock in_prompt %} | |
33 |
|
33 | |||
34 | {% block empty_in_prompt -%} |
|
34 | {% block empty_in_prompt -%} | |
35 | <div class="prompt input_prompt"> |
|
35 | <div class="prompt input_prompt"> | |
36 | </div> |
|
36 | </div> | |
37 | {%- endblock empty_in_prompt %} |
|
37 | {%- endblock empty_in_prompt %} | |
38 |
|
38 | |||
39 | {# |
|
39 | {# | |
40 | output_prompt doesn't do anything in HTML, |
|
40 | output_prompt doesn't do anything in HTML, | |
41 | because there is a prompt div in each output area (see output block) |
|
41 | because there is a prompt div in each output area (see output block) | |
42 | #} |
|
42 | #} | |
43 | {% block output_prompt %} |
|
43 | {% block output_prompt %} | |
44 | {% endblock output_prompt %} |
|
44 | {% endblock output_prompt %} | |
45 |
|
45 | |||
46 | {% block input %} |
|
46 | {% block input %} | |
47 | <div class="inner_cell"> |
|
47 | <div class="inner_cell"> | |
48 | <div class="input_area"> |
|
48 | <div class="input_area"> | |
49 | {{ cell.source | highlight_code(metadata=cell.metadata) }} |
|
49 | {{ cell.source | highlight_code(metadata=cell.metadata) }} | |
50 | </div> |
|
50 | </div> | |
51 | </div> |
|
51 | </div> | |
52 | {%- endblock input %} |
|
52 | {%- endblock input %} | |
53 |
|
53 | |||
54 | {% block output %} |
|
54 | {% block output %} | |
55 | <div class="output_area"> |
|
55 | <div class="output_area"> | |
56 | {%- if output.output_type == 'execute_result' -%} |
|
56 | {%- if output.output_type == 'execute_result' -%} | |
57 | <div class="prompt output_prompt"> |
|
57 | <div class="prompt output_prompt"> | |
58 |
{%- if cell. |
|
58 | {%- if cell.execution_count is defined -%} | |
59 |
Out[{{ cell. |
|
59 | Out[{{ cell.execution_count|replace(None, " ") }}]: | |
60 | {%- else -%} |
|
60 | {%- else -%} | |
61 | Out[ ]: |
|
61 | Out[ ]: | |
62 | {%- endif -%} |
|
62 | {%- endif -%} | |
63 | {%- else -%} |
|
63 | {%- else -%} | |
64 | <div class="prompt"> |
|
64 | <div class="prompt"> | |
65 | {%- endif -%} |
|
65 | {%- endif -%} | |
66 | </div> |
|
66 | </div> | |
67 | {{ super() }} |
|
67 | {{ super() }} | |
68 | </div> |
|
68 | </div> | |
69 | {% endblock output %} |
|
69 | {% endblock output %} | |
70 |
|
70 | |||
71 | {% block markdowncell scoped %} |
|
71 | {% block markdowncell scoped %} | |
72 | <div class="cell border-box-sizing text_cell rendered"> |
|
72 | <div class="cell border-box-sizing text_cell rendered"> | |
73 | {{ self.empty_in_prompt() }} |
|
73 | {{ self.empty_in_prompt() }} | |
74 | <div class="inner_cell"> |
|
74 | <div class="inner_cell"> | |
75 | <div class="text_cell_render border-box-sizing rendered_html"> |
|
75 | <div class="text_cell_render border-box-sizing rendered_html"> | |
76 | {{ cell.source | markdown2html | strip_files_prefix }} |
|
76 | {{ cell.source | markdown2html | strip_files_prefix }} | |
77 | </div> |
|
77 | </div> | |
78 | </div> |
|
78 | </div> | |
79 | </div> |
|
79 | </div> | |
80 | {%- endblock markdowncell %} |
|
80 | {%- endblock markdowncell %} | |
81 |
|
81 | |||
82 | {% block headingcell scoped %} |
|
82 | {% block headingcell scoped %} | |
83 | <div class="cell border-box-sizing text_cell rendered"> |
|
83 | <div class="cell border-box-sizing text_cell rendered"> | |
84 | {{ self.empty_in_prompt() }} |
|
84 | {{ self.empty_in_prompt() }} | |
85 | <div class="inner_cell"> |
|
85 | <div class="inner_cell"> | |
86 | <div class="text_cell_render border-box-sizing rendered_html"> |
|
86 | <div class="text_cell_render border-box-sizing rendered_html"> | |
87 | {{ ("#" * cell.level + cell.source) | replace('\n', ' ') | markdown2html | strip_files_prefix | add_anchor }} |
|
87 | {{ ("#" * cell.level + cell.source) | replace('\n', ' ') | markdown2html | strip_files_prefix | add_anchor }} | |
88 | </div> |
|
88 | </div> | |
89 | </div> |
|
89 | </div> | |
90 | </div> |
|
90 | </div> | |
91 | {% endblock headingcell %} |
|
91 | {% endblock headingcell %} | |
92 |
|
92 | |||
93 | {% block unknowncell scoped %} |
|
93 | {% block unknowncell scoped %} | |
94 | unknown type {{ cell.type }} |
|
94 | unknown type {{ cell.type }} | |
95 | {% endblock unknowncell %} |
|
95 | {% endblock unknowncell %} | |
96 |
|
96 | |||
97 | {% block execute_result -%} |
|
97 | {% block execute_result -%} | |
98 | {%- set extra_class="output_execute_result" -%} |
|
98 | {%- set extra_class="output_execute_result" -%} | |
99 | {% block data_priority scoped %} |
|
99 | {% block data_priority scoped %} | |
100 | {{ super() }} |
|
100 | {{ super() }} | |
101 | {% endblock %} |
|
101 | {% endblock %} | |
102 | {%- set extra_class="" -%} |
|
102 | {%- set extra_class="" -%} | |
103 | {%- endblock execute_result %} |
|
103 | {%- endblock execute_result %} | |
104 |
|
104 | |||
105 | {% block stream_stdout -%} |
|
105 | {% block stream_stdout -%} | |
106 | <div class="output_subarea output_stream output_stdout output_text"> |
|
106 | <div class="output_subarea output_stream output_stdout output_text"> | |
107 | <pre> |
|
107 | <pre> | |
108 | {{- output.text | ansi2html -}} |
|
108 | {{- output.text | ansi2html -}} | |
109 | </pre> |
|
109 | </pre> | |
110 | </div> |
|
110 | </div> | |
111 | {%- endblock stream_stdout %} |
|
111 | {%- endblock stream_stdout %} | |
112 |
|
112 | |||
113 | {% block stream_stderr -%} |
|
113 | {% block stream_stderr -%} | |
114 | <div class="output_subarea output_stream output_stderr output_text"> |
|
114 | <div class="output_subarea output_stream output_stderr output_text"> | |
115 | <pre> |
|
115 | <pre> | |
116 | {{- output.text | ansi2html -}} |
|
116 | {{- output.text | ansi2html -}} | |
117 | </pre> |
|
117 | </pre> | |
118 | </div> |
|
118 | </div> | |
119 | {%- endblock stream_stderr %} |
|
119 | {%- endblock stream_stderr %} | |
120 |
|
120 | |||
121 | {% block data_svg scoped -%} |
|
121 | {% block data_svg scoped -%} | |
122 | <div class="output_svg output_subarea {{extra_class}}"> |
|
122 | <div class="output_svg output_subarea {{extra_class}}"> | |
123 | {%- if output.svg_filename %} |
|
123 | {%- if output.svg_filename %} | |
124 | <img src="{{output.svg_filename | posix_path}}" |
|
124 | <img src="{{output.svg_filename | posix_path}}" | |
125 | {%- else %} |
|
125 | {%- else %} | |
126 | {{ output.svg }} |
|
126 | {{ output.svg }} | |
127 | {%- endif %} |
|
127 | {%- endif %} | |
128 | </div> |
|
128 | </div> | |
129 | {%- endblock data_svg %} |
|
129 | {%- endblock data_svg %} | |
130 |
|
130 | |||
131 | {% block data_html scoped -%} |
|
131 | {% block data_html scoped -%} | |
132 | <div class="output_html rendered_html output_subarea {{extra_class}}"> |
|
132 | <div class="output_html rendered_html output_subarea {{extra_class}}"> | |
133 | {{ output.html }} |
|
133 | {{ output.html }} | |
134 | </div> |
|
134 | </div> | |
135 | {%- endblock data_html %} |
|
135 | {%- endblock data_html %} | |
136 |
|
136 | |||
137 | {% block data_png scoped %} |
|
137 | {% block data_png scoped %} | |
138 | <div class="output_png output_subarea {{extra_class}}"> |
|
138 | <div class="output_png output_subarea {{extra_class}}"> | |
139 | {%- if output.png_filename %} |
|
139 | {%- if output.png_filename %} | |
140 | <img src="{{output.png_filename | posix_path}}" |
|
140 | <img src="{{output.png_filename | posix_path}}" | |
141 | {%- else %} |
|
141 | {%- else %} | |
142 | <img src="data:image/png;base64,{{ output.png }}" |
|
142 | <img src="data:image/png;base64,{{ output.png }}" | |
143 | {%- endif %} |
|
143 | {%- endif %} | |
144 | {%- if 'metadata' in output and 'width' in output.metadata.get('png', {}) %} |
|
144 | {%- if 'metadata' in output and 'width' in output.metadata.get('png', {}) %} | |
145 | width={{output.metadata['png']['width']}} |
|
145 | width={{output.metadata['png']['width']}} | |
146 | {%- endif %} |
|
146 | {%- endif %} | |
147 | {%- if 'metadata' in output and 'height' in output.metadata.get('png', {}) %} |
|
147 | {%- if 'metadata' in output and 'height' in output.metadata.get('png', {}) %} | |
148 | height={{output.metadata['png']['height']}} |
|
148 | height={{output.metadata['png']['height']}} | |
149 | {%- endif %} |
|
149 | {%- endif %} | |
150 | > |
|
150 | > | |
151 | </div> |
|
151 | </div> | |
152 | {%- endblock data_png %} |
|
152 | {%- endblock data_png %} | |
153 |
|
153 | |||
154 | {% block data_jpg scoped %} |
|
154 | {% block data_jpg scoped %} | |
155 | <div class="output_jpeg output_subarea {{extra_class}}"> |
|
155 | <div class="output_jpeg output_subarea {{extra_class}}"> | |
156 | {%- if output.jpeg_filename %} |
|
156 | {%- if output.jpeg_filename %} | |
157 | <img src="{{output.jpeg_filename | posix_path}}" |
|
157 | <img src="{{output.jpeg_filename | posix_path}}" | |
158 | {%- else %} |
|
158 | {%- else %} | |
159 | <img src="data:image/jpeg;base64,{{ output.jpeg }}" |
|
159 | <img src="data:image/jpeg;base64,{{ output.jpeg }}" | |
160 | {%- endif %} |
|
160 | {%- endif %} | |
161 | {%- if 'metadata' in output and 'width' in output.metadata.get('jpeg', {}) %} |
|
161 | {%- if 'metadata' in output and 'width' in output.metadata.get('jpeg', {}) %} | |
162 | width={{output.metadata['jpeg']['width']}} |
|
162 | width={{output.metadata['jpeg']['width']}} | |
163 | {%- endif %} |
|
163 | {%- endif %} | |
164 | {%- if 'metadata' in output and 'height' in output.metadata.get('jpeg', {}) %} |
|
164 | {%- if 'metadata' in output and 'height' in output.metadata.get('jpeg', {}) %} | |
165 | height={{output.metadata['jpeg']['height']}} |
|
165 | height={{output.metadata['jpeg']['height']}} | |
166 | {%- endif %} |
|
166 | {%- endif %} | |
167 | > |
|
167 | > | |
168 | </div> |
|
168 | </div> | |
169 | {%- endblock data_jpg %} |
|
169 | {%- endblock data_jpg %} | |
170 |
|
170 | |||
171 | {% block data_latex scoped %} |
|
171 | {% block data_latex scoped %} | |
172 | <div class="output_latex output_subarea {{extra_class}}"> |
|
172 | <div class="output_latex output_subarea {{extra_class}}"> | |
173 | {{ output.latex }} |
|
173 | {{ output.latex }} | |
174 | </div> |
|
174 | </div> | |
175 | {%- endblock data_latex %} |
|
175 | {%- endblock data_latex %} | |
176 |
|
176 | |||
177 | {% block error -%} |
|
177 | {% block error -%} | |
178 | <div class="output_subarea output_text output_error"> |
|
178 | <div class="output_subarea output_text output_error"> | |
179 | <pre> |
|
179 | <pre> | |
180 | {{- super() -}} |
|
180 | {{- super() -}} | |
181 | </pre> |
|
181 | </pre> | |
182 | </div> |
|
182 | </div> | |
183 | {%- endblock error %} |
|
183 | {%- endblock error %} | |
184 |
|
184 | |||
185 | {%- block traceback_line %} |
|
185 | {%- block traceback_line %} | |
186 | {{ line | ansi2html }} |
|
186 | {{ line | ansi2html }} | |
187 | {%- endblock traceback_line %} |
|
187 | {%- endblock traceback_line %} | |
188 |
|
188 | |||
189 | {%- block data_text scoped %} |
|
189 | {%- block data_text scoped %} | |
190 | <div class="output_text output_subarea {{extra_class}}"> |
|
190 | <div class="output_text output_subarea {{extra_class}}"> | |
191 | <pre> |
|
191 | <pre> | |
192 | {{- output.text | ansi2html -}} |
|
192 | {{- output.text | ansi2html -}} | |
193 | </pre> |
|
193 | </pre> | |
194 | </div> |
|
194 | </div> | |
195 | {%- endblock -%} |
|
195 | {%- endblock -%} | |
196 |
|
196 | |||
197 | {%- block data_javascript scoped %} |
|
197 | {%- block data_javascript scoped %} | |
198 | <div class="output_subarea output_javascript {{extra_class}}"> |
|
198 | <div class="output_subarea output_javascript {{extra_class}}"> | |
199 | <script type="text/javascript"> |
|
199 | <script type="text/javascript"> | |
200 | {{ output.javascript }} |
|
200 | {{ output.javascript }} | |
201 | </script> |
|
201 | </script> | |
202 | </div> |
|
202 | </div> | |
203 | {%- endblock -%} |
|
203 | {%- endblock -%} |
@@ -1,45 +1,45 | |||||
1 | ((= Black&white ipython input/output style =)) |
|
1 | ((= Black&white ipython input/output style =)) | |
2 |
|
2 | |||
3 | ((*- extends 'base.tplx' -*)) |
|
3 | ((*- extends 'base.tplx' -*)) | |
4 |
|
4 | |||
5 | %=============================================================================== |
|
5 | %=============================================================================== | |
6 | % Input |
|
6 | % Input | |
7 | %=============================================================================== |
|
7 | %=============================================================================== | |
8 |
|
8 | |||
9 | ((* block input scoped *)) |
|
9 | ((* block input scoped *)) | |
10 | ((( add_prompt(cell.source, cell, 'In ') ))) |
|
10 | ((( add_prompt(cell.source, cell, 'In ') ))) | |
11 | ((* endblock input *)) |
|
11 | ((* endblock input *)) | |
12 |
|
12 | |||
13 |
|
13 | |||
14 | %=============================================================================== |
|
14 | %=============================================================================== | |
15 | % Output |
|
15 | % Output | |
16 | %=============================================================================== |
|
16 | %=============================================================================== | |
17 |
|
17 | |||
18 | ((* block execute_result scoped *)) |
|
18 | ((* block execute_result scoped *)) | |
19 | ((*- for type in output | filter_data_type -*)) |
|
19 | ((*- for type in output | filter_data_type -*)) | |
20 | ((*- if type in ['text']*)) |
|
20 | ((*- if type in ['text']*)) | |
21 | ((( add_prompt(output.text, cell, 'Out') ))) |
|
21 | ((( add_prompt(output.text, cell, 'Out') ))) | |
22 | ((*- else -*)) |
|
22 | ((*- else -*)) | |
23 |
\verb+Out[((( cell. |
|
23 | \verb+Out[((( cell.execution_count )))]:+((( super() ))) | |
24 | ((*- endif -*)) |
|
24 | ((*- endif -*)) | |
25 | ((*- endfor -*)) |
|
25 | ((*- endfor -*)) | |
26 | ((* endblock execute_result *)) |
|
26 | ((* endblock execute_result *)) | |
27 |
|
27 | |||
28 |
|
28 | |||
29 | %============================================================================== |
|
29 | %============================================================================== | |
30 | % Support Macros |
|
30 | % Support Macros | |
31 | %============================================================================== |
|
31 | %============================================================================== | |
32 |
|
32 | |||
33 | % Name: draw_prompt |
|
33 | % Name: draw_prompt | |
34 | % Purpose: Renders an output/input prompt |
|
34 | % Purpose: Renders an output/input prompt | |
35 | ((* macro add_prompt(text, cell, prompt) -*)) |
|
35 | ((* macro add_prompt(text, cell, prompt) -*)) | |
36 |
((*- if cell. |
|
36 | ((*- if cell.execution_count is defined -*)) | |
37 |
((*- set |
|
37 | ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*)) | |
38 | ((*- else -*)) |
|
38 | ((*- else -*)) | |
39 |
((*- set |
|
39 | ((*- set execution_count = " " -*)) | |
40 | ((*- endif -*)) |
|
40 | ((*- endif -*)) | |
41 |
((*- set indentation = " " * ( |
|
41 | ((*- set indentation = " " * (execution_count | length + 7) -*)) | |
42 | \begin{verbatim} |
|
42 | \begin{verbatim} | |
43 |
(((- text | add_prompts(first=prompt ~ '[' ~ |
|
43 | (((- text | add_prompts(first=prompt ~ '[' ~ execution_count ~ ']: ', cont=indentation) -))) | |
44 | \end{verbatim} |
|
44 | \end{verbatim} | |
45 | ((*- endmacro *)) |
|
45 | ((*- endmacro *)) |
@@ -1,58 +1,58 | |||||
1 | ((= IPython input/output style =)) |
|
1 | ((= IPython input/output style =)) | |
2 |
|
2 | |||
3 | ((*- extends 'base.tplx' -*)) |
|
3 | ((*- extends 'base.tplx' -*)) | |
4 |
|
4 | |||
5 | % Custom definitions |
|
5 | % Custom definitions | |
6 | ((* block definitions *)) |
|
6 | ((* block definitions *)) | |
7 | ((( super() ))) |
|
7 | ((( super() ))) | |
8 |
|
8 | |||
9 | % Pygments definitions |
|
9 | % Pygments definitions | |
10 | ((( resources.latex.pygments_definitions ))) |
|
10 | ((( resources.latex.pygments_definitions ))) | |
11 |
|
11 | |||
12 | % Exact colors from NB |
|
12 | % Exact colors from NB | |
13 | \definecolor{incolor}{rgb}{0.0, 0.0, 0.5} |
|
13 | \definecolor{incolor}{rgb}{0.0, 0.0, 0.5} | |
14 | \definecolor{outcolor}{rgb}{0.545, 0.0, 0.0} |
|
14 | \definecolor{outcolor}{rgb}{0.545, 0.0, 0.0} | |
15 |
|
15 | |||
16 | ((* endblock definitions *)) |
|
16 | ((* endblock definitions *)) | |
17 |
|
17 | |||
18 | %=============================================================================== |
|
18 | %=============================================================================== | |
19 | % Input |
|
19 | % Input | |
20 | %=============================================================================== |
|
20 | %=============================================================================== | |
21 |
|
21 | |||
22 | ((* block input scoped *)) |
|
22 | ((* block input scoped *)) | |
23 | ((( add_prompt(cell.source | highlight_code(strip_verbatim=True), cell, 'In ', 'incolor') ))) |
|
23 | ((( add_prompt(cell.source | highlight_code(strip_verbatim=True), cell, 'In ', 'incolor') ))) | |
24 | ((* endblock input *)) |
|
24 | ((* endblock input *)) | |
25 |
|
25 | |||
26 |
|
26 | |||
27 | %=============================================================================== |
|
27 | %=============================================================================== | |
28 | % Output |
|
28 | % Output | |
29 | %=============================================================================== |
|
29 | %=============================================================================== | |
30 |
|
30 | |||
31 | ((* block execute_result scoped *)) |
|
31 | ((* block execute_result scoped *)) | |
32 | ((*- for type in output | filter_data_type -*)) |
|
32 | ((*- for type in output | filter_data_type -*)) | |
33 | ((*- if type in ['text']*)) |
|
33 | ((*- if type in ['text']*)) | |
34 | ((( add_prompt(output.text | escape_latex, cell, 'Out', 'outcolor') ))) |
|
34 | ((( add_prompt(output.text | escape_latex, cell, 'Out', 'outcolor') ))) | |
35 | ((* else -*)) |
|
35 | ((* else -*)) | |
36 |
\texttt{\color{outcolor}Out[{\color{outcolor}((( cell. |
|
36 | \texttt{\color{outcolor}Out[{\color{outcolor}((( cell.execution_count )))}]:}((( super() ))) | |
37 | ((*- endif -*)) |
|
37 | ((*- endif -*)) | |
38 | ((*- endfor -*)) |
|
38 | ((*- endfor -*)) | |
39 | ((* endblock execute_result *)) |
|
39 | ((* endblock execute_result *)) | |
40 |
|
40 | |||
41 |
|
41 | |||
42 | %============================================================================== |
|
42 | %============================================================================== | |
43 | % Support Macros |
|
43 | % Support Macros | |
44 | %============================================================================== |
|
44 | %============================================================================== | |
45 |
|
45 | |||
46 | % Name: draw_prompt |
|
46 | % Name: draw_prompt | |
47 | % Purpose: Renders an output/input prompt |
|
47 | % Purpose: Renders an output/input prompt | |
48 | ((* macro add_prompt(text, cell, prompt, prompt_color) -*)) |
|
48 | ((* macro add_prompt(text, cell, prompt, prompt_color) -*)) | |
49 |
((*- if cell. |
|
49 | ((*- if cell.execution_count is defined -*)) | |
50 |
((*- set |
|
50 | ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*)) | |
51 | ((*- else -*)) |
|
51 | ((*- else -*)) | |
52 |
((*- set |
|
52 | ((*- set execution_count = " " -*)) | |
53 | ((*- endif -*)) |
|
53 | ((*- endif -*)) | |
54 |
((*- set indention = " " * ( |
|
54 | ((*- set indention = " " * (execution_count | length + 7) -*)) | |
55 | \begin{Verbatim}[commandchars=\\\{\}] |
|
55 | \begin{Verbatim}[commandchars=\\\{\}] | |
56 |
((( text | add_prompts(first='{\color{' ~ prompt_color ~ '}' ~ prompt ~ '[{\\color{' ~ prompt_color ~ '}' ~ |
|
56 | ((( text | add_prompts(first='{\color{' ~ prompt_color ~ '}' ~ prompt ~ '[{\\color{' ~ prompt_color ~ '}' ~ execution_count ~ '}]:} ', cont=indention) ))) | |
57 | \end{Verbatim} |
|
57 | \end{Verbatim} | |
58 | ((*- endmacro *)) |
|
58 | ((*- endmacro *)) |
@@ -1,21 +1,21 | |||||
1 | {%- extends 'null.tpl' -%} |
|
1 | {%- extends 'null.tpl' -%} | |
2 |
|
2 | |||
3 | {% block header %} |
|
3 | {% block header %} | |
4 | # coding: utf-8 |
|
4 | # coding: utf-8 | |
5 | {% endblock header %} |
|
5 | {% endblock header %} | |
6 |
|
6 | |||
7 | {% block in_prompt %} |
|
7 | {% block in_prompt %} | |
8 |
# In[{{ cell. |
|
8 | # In[{{ cell.execution_count if cell.execution_count else ' ' }}]: | |
9 | {% endblock in_prompt %} |
|
9 | {% endblock in_prompt %} | |
10 |
|
10 | |||
11 | {% block input %} |
|
11 | {% block input %} | |
12 | {{ cell.source | ipython2python }} |
|
12 | {{ cell.source | ipython2python }} | |
13 | {% endblock input %} |
|
13 | {% endblock input %} | |
14 |
|
14 | |||
15 | {% block markdowncell scoped %} |
|
15 | {% block markdowncell scoped %} | |
16 | {{ cell.source | comment_lines }} |
|
16 | {{ cell.source | comment_lines }} | |
17 | {% endblock markdowncell %} |
|
17 | {% endblock markdowncell %} | |
18 |
|
18 | |||
19 | {% block headingcell scoped %} |
|
19 | {% block headingcell scoped %} | |
20 | {{ '#' * cell.level }}{{ cell.source | replace('\n', ' ') | comment_lines }} |
|
20 | {{ '#' * cell.level }}{{ cell.source | replace('\n', ' ') | comment_lines }} | |
21 | {% endblock headingcell %} |
|
21 | {% endblock headingcell %} |
@@ -1,143 +1,143 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "heading", |
|
4 | "cell_type": "heading", | |
5 | "level": 1, |
|
5 | "level": 1, | |
6 | "metadata": {}, |
|
6 | "metadata": {}, | |
7 | "source": [ |
|
7 | "source": [ | |
8 | "A simple SymPy example" |
|
8 | "A simple SymPy example" | |
9 | ] |
|
9 | ] | |
10 | }, |
|
10 | }, | |
11 | { |
|
11 | { | |
12 | "cell_type": "markdown", |
|
12 | "cell_type": "markdown", | |
13 | "metadata": {}, |
|
13 | "metadata": {}, | |
14 | "source": [ |
|
14 | "source": [ | |
15 | "First we import SymPy and initialize printing:" |
|
15 | "First we import SymPy and initialize printing:" | |
16 | ] |
|
16 | ] | |
17 | }, |
|
17 | }, | |
18 | { |
|
18 | { | |
19 | "cell_type": "code", |
|
19 | "cell_type": "code", | |
|
20 | "execution_count": 2, | |||
20 | "metadata": { |
|
21 | "metadata": { | |
21 | "collapsed": false |
|
22 | "collapsed": false | |
22 | }, |
|
23 | }, | |
23 | "outputs": [], |
|
24 | "outputs": [], | |
24 | "prompt_number": 2, |
|
|||
25 | "source": [ |
|
25 | "source": [ | |
26 | "from sympy import init_printing\n", |
|
26 | "from sympy import init_printing\n", | |
27 | "from sympy import *\n", |
|
27 | "from sympy import *\n", | |
28 | " init_printing()" |
|
28 | " init_printing()" | |
29 | ] |
|
29 | ] | |
30 | }, |
|
30 | }, | |
31 | { |
|
31 | { | |
32 | "cell_type": "markdown", |
|
32 | "cell_type": "markdown", | |
33 | "metadata": {}, |
|
33 | "metadata": {}, | |
34 | "source": [ |
|
34 | "source": [ | |
35 | "Create a few symbols:" |
|
35 | "Create a few symbols:" | |
36 | ] |
|
36 | ] | |
37 | }, |
|
37 | }, | |
38 | { |
|
38 | { | |
39 | "cell_type": "code", |
|
39 | "cell_type": "code", | |
|
40 | "execution_count": 4, | |||
40 | "metadata": { |
|
41 | "metadata": { | |
41 | "collapsed": false |
|
42 | "collapsed": false | |
42 | }, |
|
43 | }, | |
43 | "outputs": [], |
|
44 | "outputs": [], | |
44 | "prompt_number": 4, |
|
|||
45 | "source": [ |
|
45 | "source": [ | |
46 | "x,y,z = symbols('x y z')" |
|
46 | "x,y,z = symbols('x y z')" | |
47 | ] |
|
47 | ] | |
48 | }, |
|
48 | }, | |
49 | { |
|
49 | { | |
50 | "cell_type": "markdown", |
|
50 | "cell_type": "markdown", | |
51 | "metadata": {}, |
|
51 | "metadata": {}, | |
52 | "source": [ |
|
52 | "source": [ | |
53 | "Here is a basic expression:" |
|
53 | "Here is a basic expression:" | |
54 | ] |
|
54 | ] | |
55 | }, |
|
55 | }, | |
56 | { |
|
56 | { | |
57 | "cell_type": "code", |
|
57 | "cell_type": "code", | |
|
58 | "execution_count": 6, | |||
58 | "metadata": { |
|
59 | "metadata": { | |
59 | "collapsed": false |
|
60 | "collapsed": false | |
60 | }, |
|
61 | }, | |
61 | "outputs": [ |
|
62 | "outputs": [ | |
62 | { |
|
63 | { | |
|
64 | "execution_count": 6, | |||
63 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKMAAAAZBAMAAACvE4OgAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAACz0lEQVRIDa1UTWjUQBT+ZpvdzW7TGlrxItjYSg/C6vbiDwjmoCgUpHioPYhdqig9\nFJYiPYmW4klB14NgFGnw4EHpj7UgUtTFXhSEBgVBxIOFggWVrrUqiMY3mZkkLNIK7oN575vvvfky\n8yYJIGzgkSlRrULKrivVSkvq6LbxtcaSjV3aSo0lgWyl5pK69V+SRlEsPxNTGYhhDrV3M2Ue2etc\nEDmuMmM+IjolrCuHXNoLoQDNSAXdzbjsfFVKTY1vCgFXFIxenG4cFSSzRewAPnN0FugXjPDr45MQ\nJwoKtitgXL9zT+CsJeIHYG+Z4H1gwhRU4G/FcAQbbYU3KdDo+0sCK8lRU0guA72uKqMYk9RehHxP\niDIu0NS2v90KGShJYi7T7tgvkrQ2vIT2XtRISWNra6lzGc8/PW3ji4PL7Vmge095YIX0iB71NCaZ\n5N3XyM0VCuNIyFNIyY3AMG/KDUvjn90DGmwq9wpIl5AyU5WsTYy0aJf6JFGB5An3Der5jExKHjNR\n4JKPge/EXqDBoOXpkxkmkJHFfAFRVhDIveWA0S57N2Me6yw+DSX1n1uCq3sIfCF2IcjNkjeWyKli\nginHubboOB4vSNAjyaiXE26ygrkyTfod55Lj3CTE+n2P73ImJpnk6wJJKjYJSwt3OQbNJu4icM5s\nKGGbzMuD70N6JSbJD44x7pLDyJrbkfiLpOEhYVMJSVEj83x5YFLyNrAzJsmvJ+uhLrieXvcJDshy\nHtQuD54c2IWWEnSXfUTDZJJfAjcpOW5imp9aHvw4ZZ4NDV4FGjw0tzadKgbFwinJUd//AT0P1tdW\nBtuRU39oKdk9ONQ163fM+nvu/s4D/FX30otdQIZGlSnJKpq6KUxKVqV1WxGHFIhishjhEO1Gi3r4\nkZCMg+hH1henV8EjmFoly1PTMs/Uadaox+FceY2STpmvt9co/Pe0Jvt1GvgDK/Osw/4jQ4wAAAAA\nSUVORK5CYII=\n", |
|
65 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKMAAAAZBAMAAACvE4OgAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAACz0lEQVRIDa1UTWjUQBT+ZpvdzW7TGlrxItjYSg/C6vbiDwjmoCgUpHioPYhdqig9\nFJYiPYmW4klB14NgFGnw4EHpj7UgUtTFXhSEBgVBxIOFggWVrrUqiMY3mZkkLNIK7oN575vvvfky\n8yYJIGzgkSlRrULKrivVSkvq6LbxtcaSjV3aSo0lgWyl5pK69V+SRlEsPxNTGYhhDrV3M2Ue2etc\nEDmuMmM+IjolrCuHXNoLoQDNSAXdzbjsfFVKTY1vCgFXFIxenG4cFSSzRewAPnN0FugXjPDr45MQ\nJwoKtitgXL9zT+CsJeIHYG+Z4H1gwhRU4G/FcAQbbYU3KdDo+0sCK8lRU0guA72uKqMYk9RehHxP\niDIu0NS2v90KGShJYi7T7tgvkrQ2vIT2XtRISWNra6lzGc8/PW3ji4PL7Vmge095YIX0iB71NCaZ\n5N3XyM0VCuNIyFNIyY3AMG/KDUvjn90DGmwq9wpIl5AyU5WsTYy0aJf6JFGB5An3Der5jExKHjNR\n4JKPge/EXqDBoOXpkxkmkJHFfAFRVhDIveWA0S57N2Me6yw+DSX1n1uCq3sIfCF2IcjNkjeWyKli\nginHubboOB4vSNAjyaiXE26ygrkyTfod55Lj3CTE+n2P73ImJpnk6wJJKjYJSwt3OQbNJu4icM5s\nKGGbzMuD70N6JSbJD44x7pLDyJrbkfiLpOEhYVMJSVEj83x5YFLyNrAzJsmvJ+uhLrieXvcJDshy\nHtQuD54c2IWWEnSXfUTDZJJfAjcpOW5imp9aHvw4ZZ4NDV4FGjw0tzadKgbFwinJUd//AT0P1tdW\nBtuRU39oKdk9ONQ163fM+nvu/s4D/FX30otdQIZGlSnJKpq6KUxKVqV1WxGHFIhishjhEO1Gi3r4\nkZCMg+hH1henV8EjmFoly1PTMs/Uadaox+FceY2STpmvt9co/Pe0Jvt1GvgDK/Osw/4jQ4wAAAAA\nSUVORK5CYII=\n", | |
64 | "metadata": {}, |
|
66 | "metadata": {}, | |
65 | "output_type": "execute_result", |
|
67 | "output_type": "execute_result", | |
66 | "prompt_number": 6, |
|
|||
67 | "text/latex": [ |
|
68 | "text/latex": [ | |
68 | "$$x^{2} + 2.0 y + \\sin{\\left (z \\right )}$$" |
|
69 | "$$x^{2} + 2.0 y + \\sin{\\left (z \\right )}$$" | |
69 | ], |
|
70 | ], | |
70 | "text/plain": [ |
|
71 | "text/plain": [ | |
71 | " 2 \n", |
|
72 | " 2 \n", | |
72 | "x + 2.0\u22c5y + sin(z)" |
|
73 | "x + 2.0\u22c5y + sin(z)" | |
73 | ] |
|
74 | ] | |
74 | } |
|
75 | } | |
75 | ], |
|
76 | ], | |
76 | "prompt_number": 6, |
|
|||
77 | "source": [ |
|
77 | "source": [ | |
78 | "e = x**2 + 2.0*y + sin(z); e" |
|
78 | "e = x**2 + 2.0*y + sin(z); e" | |
79 | ] |
|
79 | ] | |
80 | }, |
|
80 | }, | |
81 | { |
|
81 | { | |
82 | "cell_type": "code", |
|
82 | "cell_type": "code", | |
|
83 | "execution_count": 7, | |||
83 | "metadata": { |
|
84 | "metadata": { | |
84 | "collapsed": false |
|
85 | "collapsed": false | |
85 | }, |
|
86 | }, | |
86 | "outputs": [ |
|
87 | "outputs": [ | |
87 | { |
|
88 | { | |
|
89 | "execution_count": 7, | |||
88 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAOBAMAAADd6iHDAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIpm7MhCriUTv3c12\nVGZoascqAAAAgElEQVQIHWNgVDJ2YICAMAb2H1BmKgPDTChzFgNDvgOEvT8AzgQKrA9gPZPYUwNk\ncXxnCGd4dWA1kMllwFDKUB9wEchUZmAIYNgMZDDwJIDIPyDiEgOjAAPLFwZWBhYFBh6BqzwfGI4y\nSJUXZXH8Zf7A+IBh////v1hzjh5/xwAAW80hUDE8HYkAAAAASUVORK5CYII=\n", |
|
90 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAOBAMAAADd6iHDAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIpm7MhCriUTv3c12\nVGZoascqAAAAgElEQVQIHWNgVDJ2YICAMAb2H1BmKgPDTChzFgNDvgOEvT8AzgQKrA9gPZPYUwNk\ncXxnCGd4dWA1kMllwFDKUB9wEchUZmAIYNgMZDDwJIDIPyDiEgOjAAPLFwZWBhYFBh6BqzwfGI4y\nSJUXZXH8Zf7A+IBh////v1hzjh5/xwAAW80hUDE8HYkAAAAASUVORK5CYII=\n", | |
89 | "metadata": {}, |
|
91 | "metadata": {}, | |
90 | "output_type": "execute_result", |
|
92 | "output_type": "execute_result", | |
91 | "prompt_number": 7, |
|
|||
92 | "text/latex": [ |
|
93 | "text/latex": [ | |
93 | "$$2 x$$" |
|
94 | "$$2 x$$" | |
94 | ], |
|
95 | ], | |
95 | "text/plain": [ |
|
96 | "text/plain": [ | |
96 | "2\u22c5x" |
|
97 | "2\u22c5x" | |
97 | ] |
|
98 | ] | |
98 | } |
|
99 | } | |
99 | ], |
|
100 | ], | |
100 | "prompt_number": 7, |
|
|||
101 | "source": [ |
|
101 | "source": [ | |
102 | "diff(e, x)" |
|
102 | "diff(e, x)" | |
103 | ] |
|
103 | ] | |
104 | }, |
|
104 | }, | |
105 | { |
|
105 | { | |
106 | "cell_type": "code", |
|
106 | "cell_type": "code", | |
|
107 | "execution_count": 8, | |||
107 | "metadata": { |
|
108 | "metadata": { | |
108 | "collapsed": false |
|
109 | "collapsed": false | |
109 | }, |
|
110 | }, | |
110 | "outputs": [ |
|
111 | "outputs": [ | |
111 | { |
|
112 | { | |
|
113 | "execution_count": 8, | |||
112 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAALsAAAAZBAMAAACbakK8AAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAADAklEQVRIDbVVS2gTURQ90/wmk0k6tCJCsR1SKShIsxE3CgNWBKUxq9qFmqFqShfF\nUKQrkaDiF0pcCKYgBBcuBLV+wIWKARe6kQ4UhNKKWdiF4KIptmA/xPvmzZuMxdYUzIPcd+655568\nvLlJAL6G32oOasQWNHz5Rvg6nrKh/mygfSzlX2ygPaBUGmov6//NXs1yq4sex2EPrsHemTd2snNg\ntkb+Cx1zBL6SqwxZLvQAKYHzKZaPY4fh4TeHd0S5Nox9OClItm/jiU9DrEwwVEawpiVis9VkimqX\nAOr4o2cCs/0BT2I5+FYJRhJbePQxgzcD7QLEqtV5gdnu2Icr3L45gcCyt74Z7neL4SLQ0nm4S+dM\nYCz1gSPHnhKZDWyHhcCCNKwjqaF/TkwGl0L6nClie/wc1D1xdoNsSLhT0IJkhi7Lzr22xb8keE/N\nPm0Sc9yEuhRUyuiG9HzvFNeImCyq39SriOhtQI7IV/TiTqE8glqwohjE0NJwiANxOZTdZoxtfzSa\nx2tI8DtHcKQoQFmV6f1XT2swibxFL+6k5EgenhBCqKLTPX3ULnaYdDlaTMcCSd8zuXTvBq2bJUJr\nlE4WgSV5ZRdBzLFgO6nzhJp1ltvrlB2HCoWxQuG+jTvt2GxBWUZaU2mMApZNuSHA3vJpCliRhqqs\nZtvbTrb9ZIk+i70Ut1OcnpgeKskTCFUwjaYy8Jhr3eiefq0HIfa7yC6HOwVyULRuNDn21JngbcL+\nE8A+MNnSxb+w59+Cj2tELJBbjEZr8SGwn0j2aLkTPdp08R2OcKV6fXB3ikPH3n8tM5WTfrETtZcw\ng3QWH0dH7nKNiMkszqo/EDafaHhJ5Bm6ee4UtdAabxnMcmUUl0SnYx+uVqs5XAGN9QGgdeCrASv0\n3TmCsJcOdhnozexD38goK9HXynEKr1OKDs9guhQD039kGySyIQpJAdbvJ9YTlPvyUl3/aLUf34G/\nuGxIyXpE37DoLbAHwJaU53t9MRCfrU8o/k4iRn36Lar8Wd5wAfgN4R6xelyy/ssAAAAASUVORK5C\nYII=\n", |
|
114 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAALsAAAAZBAMAAACbakK8AAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAADAklEQVRIDbVVS2gTURQ90/wmk0k6tCJCsR1SKShIsxE3CgNWBKUxq9qFmqFqShfF\nUKQrkaDiF0pcCKYgBBcuBLV+wIWKARe6kQ4UhNKKWdiF4KIptmA/xPvmzZuMxdYUzIPcd+655568\nvLlJAL6G32oOasQWNHz5Rvg6nrKh/mygfSzlX2ygPaBUGmov6//NXs1yq4sex2EPrsHemTd2snNg\ntkb+Cx1zBL6SqwxZLvQAKYHzKZaPY4fh4TeHd0S5Nox9OClItm/jiU9DrEwwVEawpiVis9VkimqX\nAOr4o2cCs/0BT2I5+FYJRhJbePQxgzcD7QLEqtV5gdnu2Icr3L45gcCyt74Z7neL4SLQ0nm4S+dM\nYCz1gSPHnhKZDWyHhcCCNKwjqaF/TkwGl0L6nClie/wc1D1xdoNsSLhT0IJkhi7Lzr22xb8keE/N\nPm0Sc9yEuhRUyuiG9HzvFNeImCyq39SriOhtQI7IV/TiTqE8glqwohjE0NJwiANxOZTdZoxtfzSa\nx2tI8DtHcKQoQFmV6f1XT2swibxFL+6k5EgenhBCqKLTPX3ULnaYdDlaTMcCSd8zuXTvBq2bJUJr\nlE4WgSV5ZRdBzLFgO6nzhJp1ltvrlB2HCoWxQuG+jTvt2GxBWUZaU2mMApZNuSHA3vJpCliRhqqs\nZtvbTrb9ZIk+i70Ut1OcnpgeKskTCFUwjaYy8Jhr3eiefq0HIfa7yC6HOwVyULRuNDn21JngbcL+\nE8A+MNnSxb+w59+Cj2tELJBbjEZr8SGwn0j2aLkTPdp08R2OcKV6fXB3ikPH3n8tM5WTfrETtZcw\ng3QWH0dH7nKNiMkszqo/EDafaHhJ5Bm6ee4UtdAabxnMcmUUl0SnYx+uVqs5XAGN9QGgdeCrASv0\n3TmCsJcOdhnozexD38goK9HXynEKr1OKDs9guhQD039kGySyIQpJAdbvJ9YTlPvyUl3/aLUf34G/\nuGxIyXpE37DoLbAHwJaU53t9MRCfrU8o/k4iRn36Lar8Wd5wAfgN4R6xelyy/ssAAAAASUVORK5C\nYII=\n", | |
113 | "metadata": {}, |
|
115 | "metadata": {}, | |
114 | "output_type": "execute_result", |
|
116 | "output_type": "execute_result", | |
115 | "prompt_number": 8, |
|
|||
116 | "text/latex": [ |
|
117 | "text/latex": [ | |
117 | "$$x^{2} z + 2.0 y z - \\cos{\\left (z \\right )}$$" |
|
118 | "$$x^{2} z + 2.0 y z - \\cos{\\left (z \\right )}$$" | |
118 | ], |
|
119 | ], | |
119 | "text/plain": [ |
|
120 | "text/plain": [ | |
120 | " 2 \n", |
|
121 | " 2 \n", | |
121 | "x \u22c5z + 2.0\u22c5y\u22c5z - cos(z)" |
|
122 | "x \u22c5z + 2.0\u22c5y\u22c5z - cos(z)" | |
122 | ] |
|
123 | ] | |
123 | } |
|
124 | } | |
124 | ], |
|
125 | ], | |
125 | "prompt_number": 8, |
|
|||
126 | "source": [ |
|
126 | "source": [ | |
127 | "integrate(e, z)" |
|
127 | "integrate(e, z)" | |
128 | ] |
|
128 | ] | |
129 | }, |
|
129 | }, | |
130 | { |
|
130 | { | |
131 | "cell_type": "code", |
|
131 | "cell_type": "code", | |
|
132 | "execution_count": null, | |||
132 | "metadata": { |
|
133 | "metadata": { | |
133 | "collapsed": false |
|
134 | "collapsed": false | |
134 | }, |
|
135 | }, | |
135 | "outputs": [], |
|
136 | "outputs": [], | |
136 | "prompt_number": null, |
|
|||
137 | "source": [] |
|
137 | "source": [] | |
138 | } |
|
138 | } | |
139 | ], |
|
139 | ], | |
140 | "metadata": {}, |
|
140 | "metadata": {}, | |
141 | "nbformat": 4, |
|
141 | "nbformat": 4, | |
142 | "nbformat_minor": 0 |
|
142 | "nbformat_minor": 0 | |
143 | } No newline at end of file |
|
143 | } |
@@ -1,215 +1,215 | |||||
1 | { |
|
1 | { | |
2 | "cells": [ |
|
2 | "cells": [ | |
3 | { |
|
3 | { | |
4 | "cell_type": "heading", |
|
4 | "cell_type": "heading", | |
5 | "level": 1, |
|
5 | "level": 1, | |
6 | "metadata": {}, |
|
6 | "metadata": {}, | |
7 | "source": [ |
|
7 | "source": [ | |
8 | "NumPy and Matplotlib examples" |
|
8 | "NumPy and Matplotlib examples" | |
9 | ] |
|
9 | ] | |
10 | }, |
|
10 | }, | |
11 | { |
|
11 | { | |
12 | "cell_type": "markdown", |
|
12 | "cell_type": "markdown", | |
13 | "metadata": {}, |
|
13 | "metadata": {}, | |
14 | "source": [ |
|
14 | "source": [ | |
15 | "First import NumPy and Matplotlib:" |
|
15 | "First import NumPy and Matplotlib:" | |
16 | ] |
|
16 | ] | |
17 | }, |
|
17 | }, | |
18 | { |
|
18 | { | |
19 | "cell_type": "code", |
|
19 | "cell_type": "code", | |
|
20 | "execution_count": 1, | |||
20 | "metadata": { |
|
21 | "metadata": { | |
21 | "collapsed": false |
|
22 | "collapsed": false | |
22 | }, |
|
23 | }, | |
23 | "outputs": [ |
|
24 | "outputs": [ | |
24 | { |
|
25 | { | |
25 | "metadata": {}, |
|
26 | "metadata": {}, | |
26 | "name": "stdout", |
|
27 | "name": "stdout", | |
27 | "output_type": "stream", |
|
28 | "output_type": "stream", | |
28 | "text": "module://IPython.kernel.zmq.pylab.backend_inline\n" |
|
29 | "text": "module://IPython.kernel.zmq.pylab.backend_inline\n" | |
29 | } |
|
30 | } | |
30 | ], |
|
31 | ], | |
31 | "prompt_number": 1, |
|
|||
32 | "source": [ |
|
32 | "source": [ | |
33 | "%matplotlib inline\n", |
|
33 | "%matplotlib inline\n", | |
34 | "import matplotlib\n", |
|
34 | "import matplotlib\n", | |
35 | "import matplotlib.pyplot as plt\n", |
|
35 | "import matplotlib.pyplot as plt\n", | |
36 | "print(matplotlib.backends.backend)" |
|
36 | "print(matplotlib.backends.backend)" | |
37 | ] |
|
37 | ] | |
38 | }, |
|
38 | }, | |
39 | { |
|
39 | { | |
40 | "cell_type": "code", |
|
40 | "cell_type": "code", | |
|
41 | "execution_count": 2, | |||
41 | "metadata": { |
|
42 | "metadata": { | |
42 | "collapsed": false |
|
43 | "collapsed": false | |
43 | }, |
|
44 | }, | |
44 | "outputs": [], |
|
45 | "outputs": [], | |
45 | "prompt_number": 2, |
|
|||
46 | "source": [ |
|
46 | "source": [ | |
47 | "from IPython.display import set_matplotlib_formats\n", |
|
47 | "from IPython.display import set_matplotlib_formats\n", | |
48 | "set_matplotlib_formats('png', 'pdf')\n", |
|
48 | "set_matplotlib_formats('png', 'pdf')\n", | |
49 | "matplotlib.rcParams['figure.figsize'] = (2,1)" |
|
49 | "matplotlib.rcParams['figure.figsize'] = (2,1)" | |
50 | ] |
|
50 | ] | |
51 | }, |
|
51 | }, | |
52 | { |
|
52 | { | |
53 | "cell_type": "code", |
|
53 | "cell_type": "code", | |
|
54 | "execution_count": 3, | |||
54 | "metadata": { |
|
55 | "metadata": { | |
55 | "collapsed": false |
|
56 | "collapsed": false | |
56 | }, |
|
57 | }, | |
57 | "outputs": [ |
|
58 | "outputs": [ | |
58 | { |
|
59 | { | |
|
60 | "execution_count": 3, | |||
59 | "metadata": {}, |
|
61 | "metadata": {}, | |
60 | "output_type": "execute_result", |
|
62 | "output_type": "execute_result", | |
61 | "prompt_number": 3, |
|
|||
62 | "text/plain": [ |
|
63 | "text/plain": [ | |
63 | "{matplotlib.figure.Figure: <function IPython.core.pylabtools.<lambda>>}" |
|
64 | "{matplotlib.figure.Figure: <function IPython.core.pylabtools.<lambda>>}" | |
64 | ] |
|
65 | ] | |
65 | } |
|
66 | } | |
66 | ], |
|
67 | ], | |
67 | "prompt_number": 3, |
|
|||
68 | "source": [ |
|
68 | "source": [ | |
69 | "ip.display_formatter.formatters['application/pdf'].type_printers" |
|
69 | "ip.display_formatter.formatters['application/pdf'].type_printers" | |
70 | ] |
|
70 | ] | |
71 | }, |
|
71 | }, | |
72 | { |
|
72 | { | |
73 | "cell_type": "code", |
|
73 | "cell_type": "code", | |
|
74 | "execution_count": 4, | |||
74 | "metadata": { |
|
75 | "metadata": { | |
75 | "collapsed": false |
|
76 | "collapsed": false | |
76 | }, |
|
77 | }, | |
77 | "outputs": [], |
|
78 | "outputs": [], | |
78 | "prompt_number": 4, |
|
|||
79 | "source": [ |
|
79 | "source": [ | |
80 | "import numpy as np" |
|
80 | "import numpy as np" | |
81 | ] |
|
81 | ] | |
82 | }, |
|
82 | }, | |
83 | { |
|
83 | { | |
84 | "cell_type": "markdown", |
|
84 | "cell_type": "markdown", | |
85 | "metadata": {}, |
|
85 | "metadata": {}, | |
86 | "source": [ |
|
86 | "source": [ | |
87 | "Now we show some very basic examples of how they can be used." |
|
87 | "Now we show some very basic examples of how they can be used." | |
88 | ] |
|
88 | ] | |
89 | }, |
|
89 | }, | |
90 | { |
|
90 | { | |
91 | "cell_type": "code", |
|
91 | "cell_type": "code", | |
|
92 | "execution_count": 5, | |||
92 | "metadata": { |
|
93 | "metadata": { | |
93 | "collapsed": false |
|
94 | "collapsed": false | |
94 | }, |
|
95 | }, | |
95 | "outputs": [], |
|
96 | "outputs": [], | |
96 | "prompt_number": 5, |
|
|||
97 | "source": [ |
|
97 | "source": [ | |
98 | "a = np.random.uniform(size=(100,100))" |
|
98 | "a = np.random.uniform(size=(100,100))" | |
99 | ] |
|
99 | ] | |
100 | }, |
|
100 | }, | |
101 | { |
|
101 | { | |
102 | "cell_type": "code", |
|
102 | "cell_type": "code", | |
|
103 | "execution_count": 6, | |||
103 | "metadata": { |
|
104 | "metadata": { | |
104 | "collapsed": false |
|
105 | "collapsed": false | |
105 | }, |
|
106 | }, | |
106 | "outputs": [ |
|
107 | "outputs": [ | |
107 | { |
|
108 | { | |
|
109 | "execution_count": 6, | |||
108 | "metadata": {}, |
|
110 | "metadata": {}, | |
109 | "output_type": "execute_result", |
|
111 | "output_type": "execute_result", | |
110 | "prompt_number": 6, |
|
|||
111 | "text/plain": [ |
|
112 | "text/plain": [ | |
112 | "(100, 100)" |
|
113 | "(100, 100)" | |
113 | ] |
|
114 | ] | |
114 | } |
|
115 | } | |
115 | ], |
|
116 | ], | |
116 | "prompt_number": 6, |
|
|||
117 | "source": [ |
|
117 | "source": [ | |
118 | "a.shape" |
|
118 | "a.shape" | |
119 | ] |
|
119 | ] | |
120 | }, |
|
120 | }, | |
121 | { |
|
121 | { | |
122 | "cell_type": "code", |
|
122 | "cell_type": "code", | |
|
123 | "execution_count": 7, | |||
123 | "metadata": { |
|
124 | "metadata": { | |
124 | "collapsed": false |
|
125 | "collapsed": false | |
125 | }, |
|
126 | }, | |
126 | "outputs": [], |
|
127 | "outputs": [], | |
127 | "prompt_number": 7, |
|
|||
128 | "source": [ |
|
128 | "source": [ | |
129 | "evs = np.linalg.eigvals(a)" |
|
129 | "evs = np.linalg.eigvals(a)" | |
130 | ] |
|
130 | ] | |
131 | }, |
|
131 | }, | |
132 | { |
|
132 | { | |
133 | "cell_type": "code", |
|
133 | "cell_type": "code", | |
|
134 | "execution_count": 8, | |||
134 | "metadata": { |
|
135 | "metadata": { | |
135 | "collapsed": false |
|
136 | "collapsed": false | |
136 | }, |
|
137 | }, | |
137 | "outputs": [ |
|
138 | "outputs": [ | |
138 | { |
|
139 | { | |
|
140 | "execution_count": 8, | |||
139 | "metadata": {}, |
|
141 | "metadata": {}, | |
140 | "output_type": "execute_result", |
|
142 | "output_type": "execute_result", | |
141 | "prompt_number": 8, |
|
|||
142 | "text/plain": [ |
|
143 | "text/plain": [ | |
143 | "(100,)" |
|
144 | "(100,)" | |
144 | ] |
|
145 | ] | |
145 | } |
|
146 | } | |
146 | ], |
|
147 | ], | |
147 | "prompt_number": 8, |
|
|||
148 | "source": [ |
|
148 | "source": [ | |
149 | "evs.shape" |
|
149 | "evs.shape" | |
150 | ] |
|
150 | ] | |
151 | }, |
|
151 | }, | |
152 | { |
|
152 | { | |
153 | "cell_type": "heading", |
|
153 | "cell_type": "heading", | |
154 | "level": 2, |
|
154 | "level": 2, | |
155 | "metadata": {}, |
|
155 | "metadata": {}, | |
156 | "source": [ |
|
156 | "source": [ | |
157 | "Here is a very long heading that pandoc will wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap" |
|
157 | "Here is a very long heading that pandoc will wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap" | |
158 | ] |
|
158 | ] | |
159 | }, |
|
159 | }, | |
160 | { |
|
160 | { | |
161 | "cell_type": "markdown", |
|
161 | "cell_type": "markdown", | |
162 | "metadata": {}, |
|
162 | "metadata": {}, | |
163 | "source": [ |
|
163 | "source": [ | |
164 | "Here is a cell that has both text and PNG output:" |
|
164 | "Here is a cell that has both text and PNG output:" | |
165 | ] |
|
165 | ] | |
166 | }, |
|
166 | }, | |
167 | { |
|
167 | { | |
168 | "cell_type": "code", |
|
168 | "cell_type": "code", | |
|
169 | "execution_count": 9, | |||
169 | "metadata": { |
|
170 | "metadata": { | |
170 | "collapsed": false |
|
171 | "collapsed": false | |
171 | }, |
|
172 | }, | |
172 | "outputs": [ |
|
173 | "outputs": [ | |
173 | { |
|
174 | { | |
|
175 | "execution_count": 9, | |||
174 | "metadata": {}, |
|
176 | "metadata": {}, | |
175 | "output_type": "execute_result", |
|
177 | "output_type": "execute_result", | |
176 | "prompt_number": 9, |
|
|||
177 | "text/plain": [ |
|
178 | "text/plain": [ | |
178 | "(array([97, 2, 0, 0, 0, 0, 0, 0, 0, 1]),\n", |
|
179 | "(array([97, 2, 0, 0, 0, 0, 0, 0, 0, 1]),\n", | |
179 | " array([ -2.59479443, 2.67371141, 7.94221725, 13.21072308,\n", |
|
180 | " array([ -2.59479443, 2.67371141, 7.94221725, 13.21072308,\n", | |
180 | " 18.47922892, 23.74773476, 29.0162406 , 34.28474644,\n", |
|
181 | " 18.47922892, 23.74773476, 29.0162406 , 34.28474644,\n", | |
181 | " 39.55325228, 44.82175812, 50.09026395]),\n", |
|
182 | " 39.55325228, 44.82175812, 50.09026395]),\n", | |
182 | " <a list of 10 Patch objects>)" |
|
183 | " <a list of 10 Patch objects>)" | |
183 | ] |
|
184 | ] | |
184 | }, |
|
185 | }, | |
185 | { |
|
186 | { | |
186 | "application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSID4+\nCmVuZG9iago4IDAgb2JqCjw8IC9YT2JqZWN0IDcgMCBSIC9QYXR0ZXJuIDUgMCBSCi9Qcm9jU2V0\nIFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9FeHRHU3RhdGUgNCAwIFIK\nL1NoYWRpbmcgNiAwIFIgL0ZvbnQgMyAwIFIgPj4KZW5kb2JqCjEwIDAgb2JqCjw8IC9Hcm91cCA8\nPCAvQ1MgL0RldmljZVJHQiAvUyAvVHJhbnNwYXJlbmN5IC9UeXBlIC9Hcm91cCA+PiAvUGFyZW50\nIDIgMCBSCi9NZWRpYUJveCBbIDAgMCAxNTIuMzk4NDM3NSA4Ny4xOTIxODc1IF0gL1Jlc291cmNl\ncyA4IDAgUiAvVHlwZSAvUGFnZQovQ29udGVudHMgOSAwIFIgPj4KZW5kb2JqCjkgMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAxMSAwIFIgPj4Kc3RyZWFtCnicxZi/btwwDMYz\na+wTCJ3aRSEpiZLGHtAG6FbkgL5AmwTBXYCmQ16/dJycRcWq7SV3k81Pf76fzyZpo703l1/Q3v61\nZL9bsE8W7ZUBOTpajOR8ycGnKOcHdZ6Tw0KY5fAgojq9Mw+yKA2Lgiv+9WdvZeCVoewCR6ZoCVyk\njHIkewVw0IYPdTix8y/hao0qKvveiHOhcF5t6qJgqWDPRRXlkwmzm92vHp1g8rYzzf5on8xuby+/\noUWw+xsjO2L0w+gk06Ld/zKfPn64wAv4bPf39uu+XeGZwITgAuSQCQMVZbtRlHWt1fYbZRNCIAdA\n5F/mnjAWEFiiEb0vlGNSCI2iELRWIzTKJoQYXSglJU7PcyeEpf9BDFAJWDhQZgXRKApCazVEo2yC\nSOiQ0efhCnANQQsQhRz5BNHHhEFBNIqC0FoN0SibICR5QCjxde4E4RcgELLDVAqCTPQ6nzSSwmjE\nmqOVNoEgkCuFwuvkiSQskVBwSDTejKhJGkmTaFGRNNI2Esyu5PLyp9QkcYlkLpHr/K4J5jK8Gr/R\nuQ9Sc8bxlW1esL1YD6BjermIrTGdHI8VAXm47sDr8unkz6Pj/Mb1FG1c18Nnw6tcyzM/bIahMryU\neCZzUkOk+rSWp2hjuR4+G15pGUazvjgPle+lJ3RyGIPUvje+p2jjux4+G159qSPIZpXl9fc0RykT\nbyxP0cZyPXw2vNby8yy5p6hynVe77vRaXKeDFemDNxVUuc6JXKqfQWkIJs9/ZpMColBaaSmyffxt\nf9qHsZ12BFKZMbIUZxkbEBOHBCw20unEPk49atUtXxlhoITscwhNv5cdJ5TWC1TVO2ghBUkqYQRX\nS1WC9Mw788O+J9S896ON0gXIxBDZqwp4aBUxFQb3puE9CefA6rk/Dk+NzJQcSZLgFZdSzH+IK+Xd\nwXr2pW/1LnNhOaeowZRiusjnBevZP9o8ZK4i60pTrp8vpZgu8nnBevalSQfHsiYDSJekTCrFdJHP\nC9azL2BFsn2W/MaQGrBaMV3kM4N17A+vI0k8JOZEgM2nESWZLvR50boAwoaylaTvBEneMzSbkkwf\n+8xwPYLx7YtYXAafC2s4JRkpW5B5jtvW0gg3mk4+UZSmm9SHrBX9z/WKNxc9fsvXuu7w+ebt2ph/\nACMXFgplbmRzdHJlYW0KZW5kb2JqCjExIDAgb2JqCjg3MAplbmRvYmoKMTYgMCBvYmoKPDwgL0Zp\nbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aDEgMTkgMCBSIC9MZW5ndGggMjAgMCBSID4+CnN0cmVh\nbQp4nNS9eYAdVZ0vfurudavq3rr7vvftvdOdTtIJi6QTsnQATdhCgsYECRAWIVFAwAUGWQL6JjDj\nAEEQRJYAvsnNnbZZxjfkzVMExhl7HImgeZBRCIn6BnUcRudB8vt8zqm66QScef/+DqnvreXUWb6f\n73pO2QpNCBEH8Ynq8iVLlwleawdAhLl81cozz//y80lcm0LoZyw/8+zFIiXCQvvNBj5feebw6M3v\n9H4RL+zA9YbzP3ne5v959xPrhTj9QSEC2fOvvrIaXKRVhTj3RDyvXrj5ok9etDjUI8Q5T+Od0y+6\n7NoLR5ee8b+EWLdJaGdt2LTxk9fkfn3RLCFCWSFWbN10wXkbn8ze+XPUHcT7Y5twIzjoXYPrjbju\n2vTJK68pvnny6UJ4QujPvvSCT12+7NTTbxHarheEqC+57Irzz1v629+uRv8fE8Ib/uR512z23hfG\n2LWtHM/l533ygq985Ml/EdqPMD/jbzdf8ekr77zla3cJ7fVpjGHW5k9dsPmkX106T4i1eK4NKd6I\n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\nc+tTOz5911Weq+KfyX7mK9f4ru2/9t5rv3Pdjs+e9Lmxz09d/+ANX/uTxTce/8W5N+Vv+sub/vam\nvTcdutm+uf/m3bc8sXXktk/dduNtk7d/4kuXfelzX/7Uf3vov/3sT/N/etmffvtPX9n2uW3T2/Zv\ne/eO+p32nVfe+fCdu+985c5Df9b1Zz/88xu+kv/K1r84/i+uu2vwbnH3GXdfdvef3f303b+455R7\n7tpe3X7a9s9tv2P7S9v3bP/ZvcvuPePej997yb1X33vjV6/56k1fveOr9311x32R+/L3dd83et9J\n951y30P3/eV9z973/P3x+8v3998/dv/i+z9y/7n3X3j/p+7/wv2333/X/Q/d/5f3P3v/8/f/8P7X\nvrb7a9//2itfe+Nrv35g9IGTHjjlgdUPfOKByx+MPJh/sPvB0QdPevCUB1d/fcnXV339Y1/f9PUr\nv37DQ2se2vjQ5oc+99DWb4x848RvTHzjrG9s+MZl3/jdw+Jh8+GtD08/vPfhAw//7hHxiPlI9pGu\nR0YeOfGRiUfOemTDI5c9cs0jNz1yxyP3PbLj0Tseve/RHY9OPrr7sfHHTntszWMbH9v82Od29O6Y\nu2N8x2k71uzYuGPzjjt23PH4xidGGLbLSFJ4/gGetwHbPiBGW4PDraHh1qDd6p5udQ/vSvvebQ3Z\nrebeXUXfu+KvvFqXb+CvmloO1KdpvoGR2fPnzUn19MydPzY2/yTvvLndjXog2DM2Nmc0nUryLwIG\nUplYLabheG3BPI8VTMfsZNg3VKkMBUaDp4yNLct1NwOB5w5t1P7hkLjq5JOvii3IWaVYNJOI6V2z\nB+eEJhYtP7E6r1FLJOc+7bn4vbs99703iiELoaJ1z196P+3phucXWhBe6XXEDh9qX2Fo6yYXGisN\nzxbajS2TO6PPRT3rpnZHp6P7ot51grZmHe3UOhqhdbQruETNkdlH2r240+5G2e6YbLe90NC2jFsP\nGDuN54wfGK8bbxuBde0rSnxSkk9KO0vPlX5Qer30dimwbmT2B4zzetneQPsKC29xgKJ9mKdvcxgL\n3bF0RoVGZs73nk47fyvbWdleFUPtK2KofQPIlIjZsWrMu2Vqd2w6ti/mxZ2aXavWvKhUY481Dc9q\n07V9NS9ewS3RXp9kX8Vj+/pop69/lH012wvz6Atk3dQD+Z355/Jo4Yq8bKGCFg73qha8sLDCczzs\n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\neZnDvTDnpW15FMecizPZO9u9Le+ZJTtX3t783qOrMa9dC84q3FMTcg5yLytRVqPgq8w9vknuOmc/\nPR5lys63JNwR8+s1z9HZPwdhKHH7aW+r6GPj97OSu8K2X3Fa2ae3o0xbVLqupgrbKrRY99j4tDtj\nszhbi6jkd5v8Ph2TI+ZOMtF/8p5ds0iViz6cPx2Sjntotbi/7rZPlYiNdpxxoLjDn8lFuYhrw2Je\nZ2udK6mzrvmTIOGekF89w7S0DL/j19QeWqQrtV5cDS2uvtZppQ1yXP+pe0bnPS1/+i+gju98rx4v\n7czeXuL+0ijin9cn7+Nv/9TQ2TKOUizWcO/Tc6sMS4nLn1z59Zt1PA/PFsu8VhWOKNP+t8+9rojO\nROTG823graNFjdtWyxJvS1WiP/EsnMM7Tctas9Bpve97vRP973J/lFrpOjj9uah+2dmO8beXQp/v\n3Mln3Hx3lv/5++0zyXJ1ud+2CP+8necX3Ifch638K91VVt7vuOPud93fuI+4q901drWccL/nft/9\ngb0hzbHa/BlvVXusbP0jwn9otflj9/3uF+2NaoG73t3g/sLeGv/enstfdS9bS1+xp/RCu3Pc5P7W\nPedudn9lb0S6Nz1k7f2ivV1Mtdr3WYxnug9YW5e5j7md7i63y93iFrk33Dfcg9bn/tTa9XV3v40V\n3uvOdZ9zx6zHjLkvu0/buOtZqavdq9Z7honI3e497in3K+6Xjatv2ojhp6xHf8ld6n7T/Yy7xD3v\nVrvPGIfvt3fcJ91vuBesl71p7/prLbojxkLb3Wq9Yb17n3vC/bnb4LvcP7gfcf/oNrrLrYd027vo\nqLvH3et+yb1ld6eL3L+4f3X/5A67R91PuvvcZhsTTrdRRK873092L7pzbOy7xe5Uj9to5bfcr7pn\nbGz4a+4rbprbaiOfP3G3ub90D7hZ7jL3bhsXvWTjytvdt9zF7t/cP7vX3efdu9y33R3uE+6T7lPu\ngPF7p9vmPu62u79zR90Pux3ur92Fforv9j2+10/10/x0P8PP9Of4c/15/nx/gb/QX+Tf5S92j/lL\n/KXuJ/y7bWT3AzYS/4L7afdjNhb/df8eG7P+rI3Ofshf7t/rZ/n3+ZL7L/9+d9Jf4T/gP+g/5D/s\nr7QR1Uf81e7f/TV+tr/Wz/Ef9XP9PD/fX+cX+Ov9DT7woY/8Qn+jv8nf7G/xH/OLfJ9f7Je4//RL\n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\n0ALYRzoAqQCkAZACQOv/B6ys2f+vd9C1/wd3UY3cZ2lVVmuyWpHVeqxWY7UWy0qs1mG1Cqs1WK3A\nav1Vq69l2jyL+/BLeBQm0WrV+EJ8E3JNyDMhx4T8EnJLyCshp4R8Ep1PSa2uam1VK6taV9WqqtZU\n8xXV/J1Kf+5/AIGHtqIKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago3MDc0OQplbmRvYmoKMTkg\nMCBvYmoKMTI3MzQwCmVuZG9iagoxNSAwIG9iago8PCAvRmlsdGVyIC9GbGF0ZURlY29kZSAvTGVu\nZ3RoIDY3ID4+CnN0cmVhbQp4nO3NMQ0AIQAEwVNMTYKOV4AZKhosIOQxQUNmuq02uWynZ2WmpWac\nLreHAAAAAAAAAAAAAAAAAAAAAPCY7weB+gXnCmVuZHN0cmVhbQplbmRvYmoKMTggMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAyNjEgPj4Kc3RyZWFtCnicXVE9b8MgEN35FTem\nQ0Rst5UHC6lKFw9Jq7qdogw2HBZSDQjjwf++fCRu1ZPg6T7ece+gx/a11coDfXeGd+hBKi0czmZx\nHGHAUWlSlCAU9zcv3XzqLaGB3K2zx6nV0pCmAfoRkrN3K+xehBnwgQAAfXMCndIj7L6OXQ51i7Xf\nOKH2cCCMgUAZ2p16e+4nBJrI+1aEvPLrPtB+Kz5Xi1Amv8gjcSNwtj1H1+sRSXMIxqCRwRhBLf7l\nq8wa5FZexfIAzwwuf9wiQ5mhyvCY4enOuKYGdXbrW4M6hsuyiNQMl4zXOM/95Tha3OOmmy/OBclp\n2UlrVKk0bv9hjY2seH4AHtCFLgplbmRzdHJlYW0KZW5kb2JqCjEzIDAgb2JqCjw8IC9DSURUb0dJ\nRE1hcCAxNSAwIFIgL0ZvbnREZXNjcmlwdG9yIDEyIDAgUiAvQmFzZUZvbnQgL0F2ZW5pci1Cb29r\nCi9DSURTeXN0ZW1JbmZvIDw8IC9PcmRlcmluZyAoSWRlbnRpdHkpIC9TdXBwbGVtZW50IDAgL1Jl\nZ2lzdHJ5IChBZG9iZSkgPj4KL1N1YnR5cGUgL0NJREZvbnRUeXBlMiAvVyAxNyAwIFIgL1R5cGUg\nL0ZvbnQgPj4KZW5kb2JqCjE0IDAgb2JqCjw8IC9FbmNvZGluZyAvSWRlbnRpdHktSCAvQmFzZUZv\nbnQgL0F2ZW5pci1Cb29rCi9EZXNjZW5kYW50Rm9udHMgWyAxMyAwIFIgXSAvU3VidHlwZSAvVHlw\nZTAgL1RvVW5pY29kZSAxOCAwIFIgL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjEyIDAgb2JqCjw8IC9E\nZXNjZW50IC0zNjYgL0ZvbnRCQm94IFsgLTE2NyAtMjg4IDEwMDAgOTQwIF0gL1N0ZW1WIDAgL0Zs\nYWdzIDMyCi9YSGVpZ2h0IDAgL1R5cGUgL0ZvbnREZXNjcmlwdG9yIC9Gb250RmlsZTIgMTYgMCBS\nIC9Gb250TmFtZSAvQXZlbmlyLUJvb2sKL01heFdpZHRoIDY4MiAvQ2FwSGVpZ2h0IDAgL0l0YWxp\nY0FuZ2xlIDAgL0FzY2VudCAxMDAwID4+CmVuZG9iagoxNyAwIG9iagpbIDQ4ClsgNTY5LjMzMzMz\nMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMKNTY5LjMz\nMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgXQo1NiBbIDU2OS4zMzMzMzMz\nMzMzIF0gODcyMiBbIDY4MiBdIF0KZW5kb2JqCjMgMCBvYmoKPDwgL0YxIDE0IDAgUiA+PgplbmRv\nYmoKNCAwIG9iago8PCAvQTEgPDwgL0NBIDAgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMCA+PgovQTIg\nPDwgL0NBIDEgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMSA+PiA+PgplbmRvYmoKNSAwIG9iago8PCA+\nPgplbmRvYmoKNiAwIG9iago8PCA+PgplbmRvYmoKNyAwIG9iago8PCA+PgplbmRvYmoKMiAwIG9i\nago8PCAvQ291bnQgMSAvS2lkcyBbIDEwIDAgUiBdIC9UeXBlIC9QYWdlcyA+PgplbmRvYmoKMjEg\nMCBvYmoKPDwgL0NyZWF0aW9uRGF0ZSAoRDoyMDE0MDIyMDE3NTMyNS0wNycwMCcpCi9Qcm9kdWNl\nciAobWF0cGxvdGxpYiBwZGYgYmFja2VuZCkKL0NyZWF0b3IgKG1hdHBsb3RsaWIgMS4xLjEsIGh0\ndHA6Ly9tYXRwbG90bGliLnNmLm5ldCkgPj4KZW5kb2JqCnhyZWYKMCAyMgowMDAwMDAwMDAwIDY1\nNTM1IGYgCjAwMDAwMDAwMTYgMDAwMDAgbiAKMDAwMDA3MzYzOCAwMDAwMCBuIAowMDAwMDczNDQ0\nIDAwMDAwIG4gCjAwMDAwNzM0NzYgMDAwMDAgbiAKMDAwMDA3MzU3NSAwMDAwMCBuIAowMDAwMDcz\nNTk2IDAwMDAwIG4gCjAwMDAwNzM2MTcgMDAwMDAgbiAKMDAwMDAwMDA2NSAwMDAwMCBuIAowMDAw\nMDAwMzg4IDAwMDAwIG4gCjAwMDAwMDAyMDggMDAwMDAgbiAKMDAwMDAwMTMzMyAwMDAwMCBuIAow\nMDAwMDczMDYwIDAwMDAwIG4gCjAwMDAwNzI3MTIgMDAwMDAgbiAKMDAwMDA3MjkxOSAwMDAwMCBu\nIAowMDAwMDcyMjM5IDAwMDAwIG4gCjAwMDAwMDEzNTMgMDAwMDAgbiAKMDAwMDA3MzI3NyAwMDAw\nMCBuIAowMDAwMDcyMzc4IDAwMDAwIG4gCjAwMDAwNzIyMTYgMDAwMDAgbiAKMDAwMDA3MjE5NCAw\nMDAwMCBuIAowMDAwMDczNjk4IDAwMDAwIG4gCnRyYWlsZXIKPDwgL0luZm8gMjEgMCBSIC9Sb290\nIDEgMCBSIC9TaXplIDIyID4+CnN0YXJ0eHJlZgo3Mzg0OQolJUVPRgo=\n", |
|
187 | "application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSID4+\nCmVuZG9iago4IDAgb2JqCjw8IC9YT2JqZWN0IDcgMCBSIC9QYXR0ZXJuIDUgMCBSCi9Qcm9jU2V0\nIFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9FeHRHU3RhdGUgNCAwIFIK\nL1NoYWRpbmcgNiAwIFIgL0ZvbnQgMyAwIFIgPj4KZW5kb2JqCjEwIDAgb2JqCjw8IC9Hcm91cCA8\nPCAvQ1MgL0RldmljZVJHQiAvUyAvVHJhbnNwYXJlbmN5IC9UeXBlIC9Hcm91cCA+PiAvUGFyZW50\nIDIgMCBSCi9NZWRpYUJveCBbIDAgMCAxNTIuMzk4NDM3NSA4Ny4xOTIxODc1IF0gL1Jlc291cmNl\ncyA4IDAgUiAvVHlwZSAvUGFnZQovQ29udGVudHMgOSAwIFIgPj4KZW5kb2JqCjkgMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAxMSAwIFIgPj4Kc3RyZWFtCnicxZi/btwwDMYz\na+wTCJ3aRSEpiZLGHtAG6FbkgL5AmwTBXYCmQ16/dJycRcWq7SV3k81Pf76fzyZpo703l1/Q3v61\nZL9bsE8W7ZUBOTpajOR8ycGnKOcHdZ6Tw0KY5fAgojq9Mw+yKA2Lgiv+9WdvZeCVoewCR6ZoCVyk\njHIkewVw0IYPdTix8y/hao0qKvveiHOhcF5t6qJgqWDPRRXlkwmzm92vHp1g8rYzzf5on8xuby+/\noUWw+xsjO2L0w+gk06Ld/zKfPn64wAv4bPf39uu+XeGZwITgAuSQCQMVZbtRlHWt1fYbZRNCIAdA\n5F/mnjAWEFiiEb0vlGNSCI2iELRWIzTKJoQYXSglJU7PcyeEpf9BDFAJWDhQZgXRKApCazVEo2yC\nSOiQ0efhCnANQQsQhRz5BNHHhEFBNIqC0FoN0SibICR5QCjxde4E4RcgELLDVAqCTPQ6nzSSwmjE\nmqOVNoEgkCuFwuvkiSQskVBwSDTejKhJGkmTaFGRNNI2Esyu5PLyp9QkcYlkLpHr/K4J5jK8Gr/R\nuQ9Sc8bxlW1esL1YD6BjermIrTGdHI8VAXm47sDr8unkz6Pj/Mb1FG1c18Nnw6tcyzM/bIahMryU\neCZzUkOk+rSWp2hjuR4+G15pGUazvjgPle+lJ3RyGIPUvje+p2jjux4+G159qSPIZpXl9fc0RykT\nbyxP0cZyPXw2vNby8yy5p6hynVe77vRaXKeDFemDNxVUuc6JXKqfQWkIJs9/ZpMColBaaSmyffxt\nf9qHsZ12BFKZMbIUZxkbEBOHBCw20unEPk49atUtXxlhoITscwhNv5cdJ5TWC1TVO2ghBUkqYQRX\nS1WC9Mw788O+J9S896ON0gXIxBDZqwp4aBUxFQb3puE9CefA6rk/Dk+NzJQcSZLgFZdSzH+IK+Xd\nwXr2pW/1LnNhOaeowZRiusjnBevZP9o8ZK4i60pTrp8vpZgu8nnBevalSQfHsiYDSJekTCrFdJHP\nC9azL2BFsn2W/MaQGrBaMV3kM4N17A+vI0k8JOZEgM2nESWZLvR50boAwoaylaTvBEneMzSbkkwf\n+8xwPYLx7YtYXAafC2s4JRkpW5B5jtvW0gg3mk4+UZSmm9SHrBX9z/WKNxc9fsvXuu7w+ebt2ph/\nACMXFgplbmRzdHJlYW0KZW5kb2JqCjExIDAgb2JqCjg3MAplbmRvYmoKMTYgMCBvYmoKPDwgL0Zp\nbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aDEgMTkgMCBSIC9MZW5ndGggMjAgMCBSID4+CnN0cmVh\nbQp4nNS9eYAdVZ0vfurudavq3rr7vvftvdOdTtIJi6QTsnQATdhCgsYECRAWIVFAwAUGWQL6JjDj\nAEEQRJYAvsnNnbZZxjfkzVMExhl7HImgeZBRCIn6BnUcRudB8vt8zqm66QScef/+DqnvreXUWb6f\n73pO2QpNCBEH8Ynq8iVLlwleawdAhLl81cozz//y80lcm0LoZyw/8+zFIiXCQvvNBj5feebw6M3v\n9H4RL+zA9YbzP3ne5v959xPrhTj9QSEC2fOvvrIaXKRVhTj3RDyvXrj5ok9etDjUI8Q5T+Od0y+6\n7NoLR5ee8b+EWLdJaGdt2LTxk9fkfn3RLCFCWSFWbN10wXkbn8ze+XPUHcT7Y5twIzjoXYPrjbju\n2vTJK68pvnny6UJ4QujPvvSCT12+7NTTbxHarheEqC+57Irzz1v629+uRv8fE8Ib/uR512z23hfG\n2LWtHM/l533ygq985Ml/EdqPMD/jbzdf8ekr77zla3cJ7fVpjGHW5k9dsPmkX106T4i1eK4NKd6I\n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\nc+tTOz5911Weq+KfyX7mK9f4ru2/9t5rv3Pdjs+e9Lmxz09d/+ANX/uTxTce/8W5N+Vv+sub/vam\nvTcdutm+uf/m3bc8sXXktk/dduNtk7d/4kuXfelzX/7Uf3vov/3sT/N/etmffvtPX9n2uW3T2/Zv\ne/eO+p32nVfe+fCdu+985c5Df9b1Zz/88xu+kv/K1r84/i+uu2vwbnH3GXdfdvef3f303b+455R7\n7tpe3X7a9s9tv2P7S9v3bP/ZvcvuPePej997yb1X33vjV6/56k1fveOr9311x32R+/L3dd83et9J\n951y30P3/eV9z973/P3x+8v3998/dv/i+z9y/7n3X3j/p+7/wv2333/X/Q/d/5f3P3v/8/f/8P7X\nvrb7a9//2itfe+Nrv35g9IGTHjjlgdUPfOKByx+MPJh/sPvB0QdPevCUB1d/fcnXV339Y1/f9PUr\nv37DQ2se2vjQ5oc+99DWb4x848RvTHzjrG9s+MZl3/jdw+Jh8+GtD08/vPfhAw//7hHxiPlI9pGu\nR0YeOfGRiUfOemTDI5c9cs0jNz1yxyP3PbLj0Tseve/RHY9OPrr7sfHHTntszWMbH9v82Od29O6Y\nu2N8x2k71uzYuGPzjjt23PH4xidGGLbLSFJ4/gGetwHbPiBGW4PDraHh1qDd6p5udQ/vSvvebQ3Z\nrebeXUXfu+KvvFqXb+CvmloO1KdpvoGR2fPnzUn19MydPzY2/yTvvLndjXog2DM2Nmc0nUryLwIG\nUplYLabheG3BPI8VTMfsZNg3VKkMBUaDp4yNLct1NwOB5w5t1P7hkLjq5JOvii3IWaVYNJOI6V2z\nB+eEJhYtP7E6r1FLJOc+7bn4vbs99703iiELoaJ1z196P+3phucXWhBe6XXEDh9qX2Fo6yYXGisN\nzxbajS2TO6PPRT3rpnZHp6P7ot51grZmHe3UOhqhdbQruETNkdlH2r240+5G2e6YbLe90NC2jFsP\nGDuN54wfGK8bbxuBde0rSnxSkk9KO0vPlX5Qer30dimwbmT2B4zzetneQPsKC29xgKJ9mKdvcxgL\n3bF0RoVGZs73nk47fyvbWdleFUPtK2KofQPIlIjZsWrMu2Vqd2w6ti/mxZ2aXavWvKhUY481Dc9q\n07V9NS9ewS3RXp9kX8Vj+/pop69/lH012wvz6Atk3dQD+Z355/Jo4Yq8bKGCFg73qha8sLDCczzs\n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\neZnDvTDnpW15FMecizPZO9u9Le+ZJTtX3t783qOrMa9dC84q3FMTcg5yLytRVqPgq8w9vknuOmc/\nPR5lys63JNwR8+s1z9HZPwdhKHH7aW+r6GPj97OSu8K2X3Fa2ae3o0xbVLqupgrbKrRY99j4tDtj\nszhbi6jkd5v8Ph2TI+ZOMtF/8p5ds0iViz6cPx2Sjntotbi/7rZPlYiNdpxxoLjDn8lFuYhrw2Je\nZ2udK6mzrvmTIOGekF89w7S0DL/j19QeWqQrtV5cDS2uvtZppQ1yXP+pe0bnPS1/+i+gju98rx4v\n7czeXuL+0ijin9cn7+Nv/9TQ2TKOUizWcO/Tc6sMS4nLn1z59Zt1PA/PFsu8VhWOKNP+t8+9rojO\nROTG823graNFjdtWyxJvS1WiP/EsnMM7Tctas9Bpve97vRP973J/lFrpOjj9uah+2dmO8beXQp/v\n3Mln3Hx3lv/5++0zyXJ1ud+2CP+8necX3Ifch638K91VVt7vuOPud93fuI+4q901drWccL/nft/9\ngb0hzbHa/BlvVXusbP0jwn9otflj9/3uF+2NaoG73t3g/sLeGv/enstfdS9bS1+xp/RCu3Pc5P7W\nPedudn9lb0S6Nz1k7f2ivV1Mtdr3WYxnug9YW5e5j7md7i63y93iFrk33Dfcg9bn/tTa9XV3v40V\n3uvOdZ9zx6zHjLkvu0/buOtZqavdq9Z7honI3e497in3K+6Xjatv2ojhp6xHf8ld6n7T/Yy7xD3v\nVrvPGIfvt3fcJ91vuBesl71p7/prLbojxkLb3Wq9Yb17n3vC/bnb4LvcP7gfcf/oNrrLrYd027vo\nqLvH3et+yb1ld6eL3L+4f3X/5A67R91PuvvcZhsTTrdRRK873092L7pzbOy7xe5Uj9to5bfcr7pn\nbGz4a+4rbprbaiOfP3G3ub90D7hZ7jL3bhsXvWTjytvdt9zF7t/cP7vX3efdu9y33R3uE+6T7lPu\ngPF7p9vmPu62u79zR90Pux3ur92Fforv9j2+10/10/x0P8PP9Of4c/15/nx/gb/QX+Tf5S92j/lL\n/KXuJ/y7bWT3AzYS/4L7afdjNhb/df8eG7P+rI3Ofshf7t/rZ/n3+ZL7L/9+d9Jf4T/gP+g/5D/s\nr7QR1Uf81e7f/TV+tr/Wz/Ef9XP9PD/fX+cX+Ov9DT7woY/8Qn+jv8nf7G/xH/OLfJ9f7Je4//RL\n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\n0ALYRzoAqQCkAZACQOv/B6ys2f+vd9C1/wd3UY3cZ2lVVmuyWpHVeqxWY7UWy0qs1mG1Cqs1WK3A\nav1Vq69l2jyL+/BLeBQm0WrV+EJ8E3JNyDMhx4T8EnJLyCshp4R8Ep1PSa2uam1VK6taV9WqqtZU\n8xXV/J1Kf+5/AIGHtqIKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago3MDc0OQplbmRvYmoKMTkg\nMCBvYmoKMTI3MzQwCmVuZG9iagoxNSAwIG9iago8PCAvRmlsdGVyIC9GbGF0ZURlY29kZSAvTGVu\nZ3RoIDY3ID4+CnN0cmVhbQp4nO3NMQ0AIQAEwVNMTYKOV4AZKhosIOQxQUNmuq02uWynZ2WmpWac\nLreHAAAAAAAAAAAAAAAAAAAAAPCY7weB+gXnCmVuZHN0cmVhbQplbmRvYmoKMTggMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAyNjEgPj4Kc3RyZWFtCnicXVE9b8MgEN35FTem\nQ0Rst5UHC6lKFw9Jq7qdogw2HBZSDQjjwf++fCRu1ZPg6T7ece+gx/a11coDfXeGd+hBKi0czmZx\nHGHAUWlSlCAU9zcv3XzqLaGB3K2zx6nV0pCmAfoRkrN3K+xehBnwgQAAfXMCndIj7L6OXQ51i7Xf\nOKH2cCCMgUAZ2p16e+4nBJrI+1aEvPLrPtB+Kz5Xi1Amv8gjcSNwtj1H1+sRSXMIxqCRwRhBLf7l\nq8wa5FZexfIAzwwuf9wiQ5mhyvCY4enOuKYGdXbrW4M6hsuyiNQMl4zXOM/95Tha3OOmmy/OBclp\n2UlrVKk0bv9hjY2seH4AHtCFLgplbmRzdHJlYW0KZW5kb2JqCjEzIDAgb2JqCjw8IC9DSURUb0dJ\nRE1hcCAxNSAwIFIgL0ZvbnREZXNjcmlwdG9yIDEyIDAgUiAvQmFzZUZvbnQgL0F2ZW5pci1Cb29r\nCi9DSURTeXN0ZW1JbmZvIDw8IC9PcmRlcmluZyAoSWRlbnRpdHkpIC9TdXBwbGVtZW50IDAgL1Jl\nZ2lzdHJ5IChBZG9iZSkgPj4KL1N1YnR5cGUgL0NJREZvbnRUeXBlMiAvVyAxNyAwIFIgL1R5cGUg\nL0ZvbnQgPj4KZW5kb2JqCjE0IDAgb2JqCjw8IC9FbmNvZGluZyAvSWRlbnRpdHktSCAvQmFzZUZv\nbnQgL0F2ZW5pci1Cb29rCi9EZXNjZW5kYW50Rm9udHMgWyAxMyAwIFIgXSAvU3VidHlwZSAvVHlw\nZTAgL1RvVW5pY29kZSAxOCAwIFIgL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjEyIDAgb2JqCjw8IC9E\nZXNjZW50IC0zNjYgL0ZvbnRCQm94IFsgLTE2NyAtMjg4IDEwMDAgOTQwIF0gL1N0ZW1WIDAgL0Zs\nYWdzIDMyCi9YSGVpZ2h0IDAgL1R5cGUgL0ZvbnREZXNjcmlwdG9yIC9Gb250RmlsZTIgMTYgMCBS\nIC9Gb250TmFtZSAvQXZlbmlyLUJvb2sKL01heFdpZHRoIDY4MiAvQ2FwSGVpZ2h0IDAgL0l0YWxp\nY0FuZ2xlIDAgL0FzY2VudCAxMDAwID4+CmVuZG9iagoxNyAwIG9iagpbIDQ4ClsgNTY5LjMzMzMz\nMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMKNTY5LjMz\nMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgXQo1NiBbIDU2OS4zMzMzMzMz\nMzMzIF0gODcyMiBbIDY4MiBdIF0KZW5kb2JqCjMgMCBvYmoKPDwgL0YxIDE0IDAgUiA+PgplbmRv\nYmoKNCAwIG9iago8PCAvQTEgPDwgL0NBIDAgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMCA+PgovQTIg\nPDwgL0NBIDEgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMSA+PiA+PgplbmRvYmoKNSAwIG9iago8PCA+\nPgplbmRvYmoKNiAwIG9iago8PCA+PgplbmRvYmoKNyAwIG9iago8PCA+PgplbmRvYmoKMiAwIG9i\nago8PCAvQ291bnQgMSAvS2lkcyBbIDEwIDAgUiBdIC9UeXBlIC9QYWdlcyA+PgplbmRvYmoKMjEg\nMCBvYmoKPDwgL0NyZWF0aW9uRGF0ZSAoRDoyMDE0MDIyMDE3NTMyNS0wNycwMCcpCi9Qcm9kdWNl\nciAobWF0cGxvdGxpYiBwZGYgYmFja2VuZCkKL0NyZWF0b3IgKG1hdHBsb3RsaWIgMS4xLjEsIGh0\ndHA6Ly9tYXRwbG90bGliLnNmLm5ldCkgPj4KZW5kb2JqCnhyZWYKMCAyMgowMDAwMDAwMDAwIDY1\nNTM1IGYgCjAwMDAwMDAwMTYgMDAwMDAgbiAKMDAwMDA3MzYzOCAwMDAwMCBuIAowMDAwMDczNDQ0\nIDAwMDAwIG4gCjAwMDAwNzM0NzYgMDAwMDAgbiAKMDAwMDA3MzU3NSAwMDAwMCBuIAowMDAwMDcz\nNTk2IDAwMDAwIG4gCjAwMDAwNzM2MTcgMDAwMDAgbiAKMDAwMDAwMDA2NSAwMDAwMCBuIAowMDAw\nMDAwMzg4IDAwMDAwIG4gCjAwMDAwMDAyMDggMDAwMDAgbiAKMDAwMDAwMTMzMyAwMDAwMCBuIAow\nMDAwMDczMDYwIDAwMDAwIG4gCjAwMDAwNzI3MTIgMDAwMDAgbiAKMDAwMDA3MjkxOSAwMDAwMCBu\nIAowMDAwMDcyMjM5IDAwMDAwIG4gCjAwMDAwMDEzNTMgMDAwMDAgbiAKMDAwMDA3MzI3NyAwMDAw\nMCBuIAowMDAwMDcyMzc4IDAwMDAwIG4gCjAwMDAwNzIyMTYgMDAwMDAgbiAKMDAwMDA3MjE5NCAw\nMDAwMCBuIAowMDAwMDczNjk4IDAwMDAwIG4gCnRyYWlsZXIKPDwgL0luZm8gMjEgMCBSIC9Sb290\nIDEgMCBSIC9TaXplIDIyID4+CnN0YXJ0eHJlZgo3Mzg0OQolJUVPRgo=\n", | |
187 | "image/png": "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\n", |
|
188 | "image/png": "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\n", | |
188 | "metadata": {}, |
|
189 | "metadata": {}, | |
189 | "output_type": "display_data", |
|
190 | "output_type": "display_data", | |
190 | "text/plain": [ |
|
191 | "text/plain": [ | |
191 | "<matplotlib.figure.Figure at 0x10b0ecf10>" |
|
192 | "<matplotlib.figure.Figure at 0x10b0ecf10>" | |
192 | ] |
|
193 | ] | |
193 | } |
|
194 | } | |
194 | ], |
|
195 | ], | |
195 | "prompt_number": 9, |
|
|||
196 | "source": [ |
|
196 | "source": [ | |
197 | "plt.hist(evs.real)" |
|
197 | "plt.hist(evs.real)" | |
198 | ] |
|
198 | ] | |
199 | }, |
|
199 | }, | |
200 | { |
|
200 | { | |
201 | "cell_type": "markdown", |
|
201 | "cell_type": "markdown", | |
202 | "metadata": {}, |
|
202 | "metadata": {}, | |
203 | "source": [ |
|
203 | "source": [ | |
204 | "```python\n", |
|
204 | "```python\n", | |
205 | "def foo(bar=1):\n", |
|
205 | "def foo(bar=1):\n", | |
206 | " \"\"\"docstring\"\"\"\n", |
|
206 | " \"\"\"docstring\"\"\"\n", | |
207 | " raise Exception(\"message\")\n", |
|
207 | " raise Exception(\"message\")\n", | |
208 | "```" |
|
208 | "```" | |
209 | ] |
|
209 | ] | |
210 | } |
|
210 | } | |
211 | ], |
|
211 | ], | |
212 | "metadata": {}, |
|
212 | "metadata": {}, | |
213 | "nbformat": 4, |
|
213 | "nbformat": 4, | |
214 | "nbformat_minor": 0 |
|
214 | "nbformat_minor": 0 | |
215 | } No newline at end of file |
|
215 | } |
@@ -1,310 +1,310 | |||||
1 | """Functions for signing notebooks""" |
|
1 | """Functions for signing notebooks""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | import base64 |
|
6 | import base64 | |
7 | from contextlib import contextmanager |
|
7 | from contextlib import contextmanager | |
8 | import hashlib |
|
8 | import hashlib | |
9 | from hmac import HMAC |
|
9 | from hmac import HMAC | |
10 | import io |
|
10 | import io | |
11 | import os |
|
11 | import os | |
12 |
|
12 | |||
13 | from IPython.utils.py3compat import string_types, unicode_type, cast_bytes |
|
13 | from IPython.utils.py3compat import string_types, unicode_type, cast_bytes | |
14 | from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool |
|
14 | from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool | |
15 | from IPython.config import LoggingConfigurable, MultipleInstanceError |
|
15 | from IPython.config import LoggingConfigurable, MultipleInstanceError | |
16 | from IPython.core.application import BaseIPythonApplication, base_flags |
|
16 | from IPython.core.application import BaseIPythonApplication, base_flags | |
17 |
|
17 | |||
18 | from .current import read, write |
|
18 | from .current import read, write | |
19 |
|
19 | |||
20 | try: |
|
20 | try: | |
21 | # Python 3 |
|
21 | # Python 3 | |
22 | algorithms = hashlib.algorithms_guaranteed |
|
22 | algorithms = hashlib.algorithms_guaranteed | |
23 | except AttributeError: |
|
23 | except AttributeError: | |
24 | algorithms = hashlib.algorithms |
|
24 | algorithms = hashlib.algorithms | |
25 |
|
25 | |||
26 |
|
26 | |||
27 | def yield_everything(obj): |
|
27 | def yield_everything(obj): | |
28 | """Yield every item in a container as bytes |
|
28 | """Yield every item in a container as bytes | |
29 |
|
29 | |||
30 | Allows any JSONable object to be passed to an HMAC digester |
|
30 | Allows any JSONable object to be passed to an HMAC digester | |
31 | without having to serialize the whole thing. |
|
31 | without having to serialize the whole thing. | |
32 | """ |
|
32 | """ | |
33 | if isinstance(obj, dict): |
|
33 | if isinstance(obj, dict): | |
34 | for key in sorted(obj): |
|
34 | for key in sorted(obj): | |
35 | value = obj[key] |
|
35 | value = obj[key] | |
36 | yield cast_bytes(key) |
|
36 | yield cast_bytes(key) | |
37 | for b in yield_everything(value): |
|
37 | for b in yield_everything(value): | |
38 | yield b |
|
38 | yield b | |
39 | elif isinstance(obj, (list, tuple)): |
|
39 | elif isinstance(obj, (list, tuple)): | |
40 | for element in obj: |
|
40 | for element in obj: | |
41 | for b in yield_everything(element): |
|
41 | for b in yield_everything(element): | |
42 | yield b |
|
42 | yield b | |
43 | elif isinstance(obj, unicode_type): |
|
43 | elif isinstance(obj, unicode_type): | |
44 | yield obj.encode('utf8') |
|
44 | yield obj.encode('utf8') | |
45 | else: |
|
45 | else: | |
46 | yield unicode_type(obj).encode('utf8') |
|
46 | yield unicode_type(obj).encode('utf8') | |
47 |
|
47 | |||
48 |
|
48 | |||
49 | @contextmanager |
|
49 | @contextmanager | |
50 | def signature_removed(nb): |
|
50 | def signature_removed(nb): | |
51 | """Context manager for operating on a notebook with its signature removed |
|
51 | """Context manager for operating on a notebook with its signature removed | |
52 |
|
52 | |||
53 | Used for excluding the previous signature when computing a notebook's signature. |
|
53 | Used for excluding the previous signature when computing a notebook's signature. | |
54 | """ |
|
54 | """ | |
55 | save_signature = nb['metadata'].pop('signature', None) |
|
55 | save_signature = nb['metadata'].pop('signature', None) | |
56 | try: |
|
56 | try: | |
57 | yield |
|
57 | yield | |
58 | finally: |
|
58 | finally: | |
59 | if save_signature is not None: |
|
59 | if save_signature is not None: | |
60 | nb['metadata']['signature'] = save_signature |
|
60 | nb['metadata']['signature'] = save_signature | |
61 |
|
61 | |||
62 |
|
62 | |||
63 | class NotebookNotary(LoggingConfigurable): |
|
63 | class NotebookNotary(LoggingConfigurable): | |
64 | """A class for computing and verifying notebook signatures.""" |
|
64 | """A class for computing and verifying notebook signatures.""" | |
65 |
|
65 | |||
66 | profile_dir = Instance("IPython.core.profiledir.ProfileDir") |
|
66 | profile_dir = Instance("IPython.core.profiledir.ProfileDir") | |
67 | def _profile_dir_default(self): |
|
67 | def _profile_dir_default(self): | |
68 | from IPython.core.application import BaseIPythonApplication |
|
68 | from IPython.core.application import BaseIPythonApplication | |
69 | app = None |
|
69 | app = None | |
70 | try: |
|
70 | try: | |
71 | if BaseIPythonApplication.initialized(): |
|
71 | if BaseIPythonApplication.initialized(): | |
72 | app = BaseIPythonApplication.instance() |
|
72 | app = BaseIPythonApplication.instance() | |
73 | except MultipleInstanceError: |
|
73 | except MultipleInstanceError: | |
74 | pass |
|
74 | pass | |
75 | if app is None: |
|
75 | if app is None: | |
76 | # create an app, without the global instance |
|
76 | # create an app, without the global instance | |
77 | app = BaseIPythonApplication() |
|
77 | app = BaseIPythonApplication() | |
78 | app.initialize(argv=[]) |
|
78 | app.initialize(argv=[]) | |
79 | return app.profile_dir |
|
79 | return app.profile_dir | |
80 |
|
80 | |||
81 | algorithm = Enum(algorithms, default_value='sha256', config=True, |
|
81 | algorithm = Enum(algorithms, default_value='sha256', config=True, | |
82 | help="""The hashing algorithm used to sign notebooks.""" |
|
82 | help="""The hashing algorithm used to sign notebooks.""" | |
83 | ) |
|
83 | ) | |
84 | def _algorithm_changed(self, name, old, new): |
|
84 | def _algorithm_changed(self, name, old, new): | |
85 | self.digestmod = getattr(hashlib, self.algorithm) |
|
85 | self.digestmod = getattr(hashlib, self.algorithm) | |
86 |
|
86 | |||
87 | digestmod = Any() |
|
87 | digestmod = Any() | |
88 | def _digestmod_default(self): |
|
88 | def _digestmod_default(self): | |
89 | return getattr(hashlib, self.algorithm) |
|
89 | return getattr(hashlib, self.algorithm) | |
90 |
|
90 | |||
91 | secret_file = Unicode(config=True, |
|
91 | secret_file = Unicode(config=True, | |
92 | help="""The file where the secret key is stored.""" |
|
92 | help="""The file where the secret key is stored.""" | |
93 | ) |
|
93 | ) | |
94 | def _secret_file_default(self): |
|
94 | def _secret_file_default(self): | |
95 | if self.profile_dir is None: |
|
95 | if self.profile_dir is None: | |
96 | return '' |
|
96 | return '' | |
97 | return os.path.join(self.profile_dir.security_dir, 'notebook_secret') |
|
97 | return os.path.join(self.profile_dir.security_dir, 'notebook_secret') | |
98 |
|
98 | |||
99 | secret = Bytes(config=True, |
|
99 | secret = Bytes(config=True, | |
100 | help="""The secret key with which notebooks are signed.""" |
|
100 | help="""The secret key with which notebooks are signed.""" | |
101 | ) |
|
101 | ) | |
102 | def _secret_default(self): |
|
102 | def _secret_default(self): | |
103 | # note : this assumes an Application is running |
|
103 | # note : this assumes an Application is running | |
104 | if os.path.exists(self.secret_file): |
|
104 | if os.path.exists(self.secret_file): | |
105 | with io.open(self.secret_file, 'rb') as f: |
|
105 | with io.open(self.secret_file, 'rb') as f: | |
106 | return f.read() |
|
106 | return f.read() | |
107 | else: |
|
107 | else: | |
108 | secret = base64.encodestring(os.urandom(1024)) |
|
108 | secret = base64.encodestring(os.urandom(1024)) | |
109 | self._write_secret_file(secret) |
|
109 | self._write_secret_file(secret) | |
110 | return secret |
|
110 | return secret | |
111 |
|
111 | |||
112 | def _write_secret_file(self, secret): |
|
112 | def _write_secret_file(self, secret): | |
113 | """write my secret to my secret_file""" |
|
113 | """write my secret to my secret_file""" | |
114 | self.log.info("Writing notebook-signing key to %s", self.secret_file) |
|
114 | self.log.info("Writing notebook-signing key to %s", self.secret_file) | |
115 | with io.open(self.secret_file, 'wb') as f: |
|
115 | with io.open(self.secret_file, 'wb') as f: | |
116 | f.write(secret) |
|
116 | f.write(secret) | |
117 | try: |
|
117 | try: | |
118 | os.chmod(self.secret_file, 0o600) |
|
118 | os.chmod(self.secret_file, 0o600) | |
119 | except OSError: |
|
119 | except OSError: | |
120 | self.log.warn( |
|
120 | self.log.warn( | |
121 | "Could not set permissions on %s", |
|
121 | "Could not set permissions on %s", | |
122 | self.secret_file |
|
122 | self.secret_file | |
123 | ) |
|
123 | ) | |
124 | return secret |
|
124 | return secret | |
125 |
|
125 | |||
126 | def compute_signature(self, nb): |
|
126 | def compute_signature(self, nb): | |
127 | """Compute a notebook's signature |
|
127 | """Compute a notebook's signature | |
128 |
|
128 | |||
129 | by hashing the entire contents of the notebook via HMAC digest. |
|
129 | by hashing the entire contents of the notebook via HMAC digest. | |
130 | """ |
|
130 | """ | |
131 | hmac = HMAC(self.secret, digestmod=self.digestmod) |
|
131 | hmac = HMAC(self.secret, digestmod=self.digestmod) | |
132 | # don't include the previous hash in the content to hash |
|
132 | # don't include the previous hash in the content to hash | |
133 | with signature_removed(nb): |
|
133 | with signature_removed(nb): | |
134 | # sign the whole thing |
|
134 | # sign the whole thing | |
135 | for b in yield_everything(nb): |
|
135 | for b in yield_everything(nb): | |
136 | hmac.update(b) |
|
136 | hmac.update(b) | |
137 |
|
137 | |||
138 | return hmac.hexdigest() |
|
138 | return hmac.hexdigest() | |
139 |
|
139 | |||
140 | def check_signature(self, nb): |
|
140 | def check_signature(self, nb): | |
141 | """Check a notebook's stored signature |
|
141 | """Check a notebook's stored signature | |
142 |
|
142 | |||
143 | If a signature is stored in the notebook's metadata, |
|
143 | If a signature is stored in the notebook's metadata, | |
144 | a new signature is computed and compared with the stored value. |
|
144 | a new signature is computed and compared with the stored value. | |
145 |
|
145 | |||
146 | Returns True if the signature is found and matches, False otherwise. |
|
146 | Returns True if the signature is found and matches, False otherwise. | |
147 |
|
147 | |||
148 | The following conditions must all be met for a notebook to be trusted: |
|
148 | The following conditions must all be met for a notebook to be trusted: | |
149 | - a signature is stored in the form 'scheme:hexdigest' |
|
149 | - a signature is stored in the form 'scheme:hexdigest' | |
150 | - the stored scheme matches the requested scheme |
|
150 | - the stored scheme matches the requested scheme | |
151 | - the requested scheme is available from hashlib |
|
151 | - the requested scheme is available from hashlib | |
152 | - the computed hash from notebook_signature matches the stored hash |
|
152 | - the computed hash from notebook_signature matches the stored hash | |
153 | """ |
|
153 | """ | |
154 | stored_signature = nb['metadata'].get('signature', None) |
|
154 | stored_signature = nb['metadata'].get('signature', None) | |
155 | if not stored_signature \ |
|
155 | if not stored_signature \ | |
156 | or not isinstance(stored_signature, string_types) \ |
|
156 | or not isinstance(stored_signature, string_types) \ | |
157 | or ':' not in stored_signature: |
|
157 | or ':' not in stored_signature: | |
158 | return False |
|
158 | return False | |
159 | stored_algo, sig = stored_signature.split(':', 1) |
|
159 | stored_algo, sig = stored_signature.split(':', 1) | |
160 | if self.algorithm != stored_algo: |
|
160 | if self.algorithm != stored_algo: | |
161 | return False |
|
161 | return False | |
162 | my_signature = self.compute_signature(nb) |
|
162 | my_signature = self.compute_signature(nb) | |
163 | return my_signature == sig |
|
163 | return my_signature == sig | |
164 |
|
164 | |||
165 | def sign(self, nb): |
|
165 | def sign(self, nb): | |
166 | """Sign a notebook, indicating that its output is trusted |
|
166 | """Sign a notebook, indicating that its output is trusted | |
167 |
|
167 | |||
168 | stores 'algo:hmac-hexdigest' in notebook.metadata.signature |
|
168 | stores 'algo:hmac-hexdigest' in notebook.metadata.signature | |
169 |
|
169 | |||
170 | e.g. 'sha256:deadbeef123...' |
|
170 | e.g. 'sha256:deadbeef123...' | |
171 | """ |
|
171 | """ | |
172 | signature = self.compute_signature(nb) |
|
172 | signature = self.compute_signature(nb) | |
173 | nb['metadata']['signature'] = "%s:%s" % (self.algorithm, signature) |
|
173 | nb['metadata']['signature'] = "%s:%s" % (self.algorithm, signature) | |
174 |
|
174 | |||
175 | def mark_cells(self, nb, trusted): |
|
175 | def mark_cells(self, nb, trusted): | |
176 | """Mark cells as trusted if the notebook's signature can be verified |
|
176 | """Mark cells as trusted if the notebook's signature can be verified | |
177 |
|
177 | |||
178 | Sets ``cell.metadata.trusted = True | False`` on all code cells, |
|
178 | Sets ``cell.metadata.trusted = True | False`` on all code cells, | |
179 | depending on whether the stored signature can be verified. |
|
179 | depending on whether the stored signature can be verified. | |
180 |
|
180 | |||
181 | This function is the inverse of check_cells |
|
181 | This function is the inverse of check_cells | |
182 | """ |
|
182 | """ | |
183 | if not nb['cells']: |
|
183 | if not nb['cells']: | |
184 | # nothing to mark if there are no cells |
|
184 | # nothing to mark if there are no cells | |
185 | return |
|
185 | return | |
186 | for cell in nb['cells']: |
|
186 | for cell in nb['cells']: | |
187 | if cell['cell_type'] == 'code': |
|
187 | if cell['cell_type'] == 'code': | |
188 | cell['metadata']['trusted'] = trusted |
|
188 | cell['metadata']['trusted'] = trusted | |
189 |
|
189 | |||
190 | def _check_cell(self, cell): |
|
190 | def _check_cell(self, cell): | |
191 | """Do we trust an individual cell? |
|
191 | """Do we trust an individual cell? | |
192 |
|
192 | |||
193 | Return True if: |
|
193 | Return True if: | |
194 |
|
194 | |||
195 | - cell is explicitly trusted |
|
195 | - cell is explicitly trusted | |
196 | - cell has no potentially unsafe rich output |
|
196 | - cell has no potentially unsafe rich output | |
197 |
|
197 | |||
198 | If a cell has no output, or only simple print statements, |
|
198 | If a cell has no output, or only simple print statements, | |
199 | it will always be trusted. |
|
199 | it will always be trusted. | |
200 | """ |
|
200 | """ | |
201 | # explicitly trusted |
|
201 | # explicitly trusted | |
202 | if cell['metadata'].pop("trusted", False): |
|
202 | if cell['metadata'].pop("trusted", False): | |
203 | return True |
|
203 | return True | |
204 |
|
204 | |||
205 | # explicitly safe output |
|
205 | # explicitly safe output | |
206 | safe = { |
|
206 | safe = { | |
207 | 'text/plain', 'image/png', 'image/jpeg', |
|
207 | 'text/plain', 'image/png', 'image/jpeg', | |
208 | } |
|
208 | } | |
209 |
|
209 | |||
210 | for output in cell['outputs']: |
|
210 | for output in cell['outputs']: | |
211 | output_type = output['output_type'] |
|
211 | output_type = output['output_type'] | |
212 | if output_type in {'execute_result', 'display_data'}: |
|
212 | if output_type in {'execute_result', 'display_data'}: | |
213 | # if there are any data keys not in the safe whitelist |
|
213 | # if there are any data keys not in the safe whitelist | |
214 |
output_keys = set(output).difference({"output_type", " |
|
214 | output_keys = set(output).difference({"output_type", "execution_count", "metadata"}) | |
215 | if output_keys.difference(safe): |
|
215 | if output_keys.difference(safe): | |
216 | return False |
|
216 | return False | |
217 |
|
217 | |||
218 | return True |
|
218 | return True | |
219 |
|
219 | |||
220 | def check_cells(self, nb): |
|
220 | def check_cells(self, nb): | |
221 | """Return whether all code cells are trusted |
|
221 | """Return whether all code cells are trusted | |
222 |
|
222 | |||
223 | If there are no code cells, return True. |
|
223 | If there are no code cells, return True. | |
224 |
|
224 | |||
225 | This function is the inverse of mark_cells. |
|
225 | This function is the inverse of mark_cells. | |
226 | """ |
|
226 | """ | |
227 | if not nb['cells']: |
|
227 | if not nb['cells']: | |
228 | return True |
|
228 | return True | |
229 | trusted = True |
|
229 | trusted = True | |
230 | for cell in nb['cells']: |
|
230 | for cell in nb['cells']: | |
231 | if cell['cell_type'] != 'code': |
|
231 | if cell['cell_type'] != 'code': | |
232 | continue |
|
232 | continue | |
233 | # only distrust a cell if it actually has some output to distrust |
|
233 | # only distrust a cell if it actually has some output to distrust | |
234 | if not self._check_cell(cell): |
|
234 | if not self._check_cell(cell): | |
235 | trusted = False |
|
235 | trusted = False | |
236 |
|
236 | |||
237 | return trusted |
|
237 | return trusted | |
238 |
|
238 | |||
239 |
|
239 | |||
240 | trust_flags = { |
|
240 | trust_flags = { | |
241 | 'reset' : ( |
|
241 | 'reset' : ( | |
242 | {'TrustNotebookApp' : { 'reset' : True}}, |
|
242 | {'TrustNotebookApp' : { 'reset' : True}}, | |
243 | """Generate a new key for notebook signature. |
|
243 | """Generate a new key for notebook signature. | |
244 | All previously signed notebooks will become untrusted. |
|
244 | All previously signed notebooks will become untrusted. | |
245 | """ |
|
245 | """ | |
246 | ), |
|
246 | ), | |
247 | } |
|
247 | } | |
248 | trust_flags.update(base_flags) |
|
248 | trust_flags.update(base_flags) | |
249 | trust_flags.pop('init') |
|
249 | trust_flags.pop('init') | |
250 |
|
250 | |||
251 |
|
251 | |||
252 | class TrustNotebookApp(BaseIPythonApplication): |
|
252 | class TrustNotebookApp(BaseIPythonApplication): | |
253 |
|
253 | |||
254 | description="""Sign one or more IPython notebooks with your key, |
|
254 | description="""Sign one or more IPython notebooks with your key, | |
255 | to trust their dynamic (HTML, Javascript) output. |
|
255 | to trust their dynamic (HTML, Javascript) output. | |
256 |
|
256 | |||
257 | Trusting a notebook only applies to the current IPython profile. |
|
257 | Trusting a notebook only applies to the current IPython profile. | |
258 | To trust a notebook for use with a profile other than default, |
|
258 | To trust a notebook for use with a profile other than default, | |
259 | add `--profile [profile name]`. |
|
259 | add `--profile [profile name]`. | |
260 |
|
260 | |||
261 | Otherwise, you will have to re-execute the notebook to see output. |
|
261 | Otherwise, you will have to re-execute the notebook to see output. | |
262 | """ |
|
262 | """ | |
263 |
|
263 | |||
264 | examples = """ |
|
264 | examples = """ | |
265 | ipython trust mynotebook.ipynb and_this_one.ipynb |
|
265 | ipython trust mynotebook.ipynb and_this_one.ipynb | |
266 | ipython trust --profile myprofile mynotebook.ipynb |
|
266 | ipython trust --profile myprofile mynotebook.ipynb | |
267 | """ |
|
267 | """ | |
268 |
|
268 | |||
269 | flags = trust_flags |
|
269 | flags = trust_flags | |
270 |
|
270 | |||
271 | reset = Bool(False, config=True, |
|
271 | reset = Bool(False, config=True, | |
272 | help="""If True, generate a new key for notebook signature. |
|
272 | help="""If True, generate a new key for notebook signature. | |
273 | After reset, all previously signed notebooks will become untrusted. |
|
273 | After reset, all previously signed notebooks will become untrusted. | |
274 | """ |
|
274 | """ | |
275 | ) |
|
275 | ) | |
276 |
|
276 | |||
277 | notary = Instance(NotebookNotary) |
|
277 | notary = Instance(NotebookNotary) | |
278 | def _notary_default(self): |
|
278 | def _notary_default(self): | |
279 | return NotebookNotary(parent=self, profile_dir=self.profile_dir) |
|
279 | return NotebookNotary(parent=self, profile_dir=self.profile_dir) | |
280 |
|
280 | |||
281 | def sign_notebook(self, notebook_path): |
|
281 | def sign_notebook(self, notebook_path): | |
282 | if not os.path.exists(notebook_path): |
|
282 | if not os.path.exists(notebook_path): | |
283 | self.log.error("Notebook missing: %s" % notebook_path) |
|
283 | self.log.error("Notebook missing: %s" % notebook_path) | |
284 | self.exit(1) |
|
284 | self.exit(1) | |
285 | with io.open(notebook_path, encoding='utf8') as f: |
|
285 | with io.open(notebook_path, encoding='utf8') as f: | |
286 | nb = read(f, 'json') |
|
286 | nb = read(f, 'json') | |
287 | if self.notary.check_signature(nb): |
|
287 | if self.notary.check_signature(nb): | |
288 | print("Notebook already signed: %s" % notebook_path) |
|
288 | print("Notebook already signed: %s" % notebook_path) | |
289 | else: |
|
289 | else: | |
290 | print("Signing notebook: %s" % notebook_path) |
|
290 | print("Signing notebook: %s" % notebook_path) | |
291 | self.notary.sign(nb) |
|
291 | self.notary.sign(nb) | |
292 | with io.open(notebook_path, 'w', encoding='utf8') as f: |
|
292 | with io.open(notebook_path, 'w', encoding='utf8') as f: | |
293 | write(nb, f, 'json') |
|
293 | write(nb, f, 'json') | |
294 |
|
294 | |||
295 | def generate_new_key(self): |
|
295 | def generate_new_key(self): | |
296 | """Generate a new notebook signature key""" |
|
296 | """Generate a new notebook signature key""" | |
297 | print("Generating new notebook key: %s" % self.notary.secret_file) |
|
297 | print("Generating new notebook key: %s" % self.notary.secret_file) | |
298 | self.notary._write_secret_file(os.urandom(1024)) |
|
298 | self.notary._write_secret_file(os.urandom(1024)) | |
299 |
|
299 | |||
300 | def start(self): |
|
300 | def start(self): | |
301 | if self.reset: |
|
301 | if self.reset: | |
302 | self.generate_new_key() |
|
302 | self.generate_new_key() | |
303 | return |
|
303 | return | |
304 | if not self.extra_args: |
|
304 | if not self.extra_args: | |
305 | self.log.critical("Specify at least one notebook to sign.") |
|
305 | self.log.critical("Specify at least one notebook to sign.") | |
306 | self.exit(1) |
|
306 | self.exit(1) | |
307 |
|
307 | |||
308 | for notebook_path in self.extra_args: |
|
308 | for notebook_path in self.extra_args: | |
309 | self.sign_notebook(notebook_path) |
|
309 | self.sign_notebook(notebook_path) | |
310 |
|
310 |
@@ -1,155 +1,155 | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
3 | "cell_tags": ["<None>", null], |
|
3 | "cell_tags": ["<None>", null], | |
4 | "name": "", |
|
4 | "name": "", | |
5 | "kernel_info": { |
|
5 | "kernel_info": { | |
6 | "name": "python", |
|
6 | "name": "python", | |
7 | "language": "python" |
|
7 | "language": "python" | |
8 | } |
|
8 | } | |
9 | }, |
|
9 | }, | |
10 | "nbformat": 4, |
|
10 | "nbformat": 4, | |
11 | "nbformat_minor": 0, |
|
11 | "nbformat_minor": 0, | |
12 | "cells": [ |
|
12 | "cells": [ | |
13 | { |
|
13 | { | |
14 | "cell_type": "heading", |
|
14 | "cell_type": "heading", | |
15 | "level": 1, |
|
15 | "level": 1, | |
16 | "metadata": {}, |
|
16 | "metadata": {}, | |
17 | "source": [ |
|
17 | "source": [ | |
18 | "nbconvert latex test" |
|
18 | "nbconvert latex test" | |
19 | ] |
|
19 | ] | |
20 | }, |
|
20 | }, | |
21 | { |
|
21 | { | |
22 | "cell_type": "markdown", |
|
22 | "cell_type": "markdown", | |
23 | "metadata": {}, |
|
23 | "metadata": {}, | |
24 | "source": [ |
|
24 | "source": [ | |
25 | "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." |
|
25 | "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." | |
26 | ] |
|
26 | ] | |
27 | }, |
|
27 | }, | |
28 | { |
|
28 | { | |
29 | "cell_type": "heading", |
|
29 | "cell_type": "heading", | |
30 | "level": 2, |
|
30 | "level": 2, | |
31 | "metadata": {}, |
|
31 | "metadata": {}, | |
32 | "source": [ |
|
32 | "source": [ | |
33 | "Printed Using Python" |
|
33 | "Printed Using Python" | |
34 | ] |
|
34 | ] | |
35 | }, |
|
35 | }, | |
36 | { |
|
36 | { | |
37 | "cell_type": "code", |
|
37 | "cell_type": "code", | |
38 | "source": [ |
|
38 | "source": [ | |
39 | "print(\"hello\")" |
|
39 | "print(\"hello\")" | |
40 | ], |
|
40 | ], | |
41 | "metadata": { |
|
41 | "metadata": { | |
42 | "collapsed": false, |
|
42 | "collapsed": false, | |
43 | "autoscroll": false |
|
43 | "autoscroll": false | |
44 | }, |
|
44 | }, | |
45 | "outputs": [ |
|
45 | "outputs": [ | |
46 | { |
|
46 | { | |
47 | "output_type": "stream", |
|
47 | "output_type": "stream", | |
48 | "metadata": {}, |
|
48 | "metadata": {}, | |
49 | "name": "stdout", |
|
49 | "name": "stdout", | |
50 | "text": [ |
|
50 | "text": [ | |
51 | "hello\n" |
|
51 | "hello\n" | |
52 | ] |
|
52 | ] | |
53 | } |
|
53 | } | |
54 | ], |
|
54 | ], | |
55 |
" |
|
55 | "execution_count": 1 | |
56 | }, |
|
56 | }, | |
57 | { |
|
57 | { | |
58 | "cell_type": "heading", |
|
58 | "cell_type": "heading", | |
59 | "level": 2, |
|
59 | "level": 2, | |
60 | "metadata": {}, |
|
60 | "metadata": {}, | |
61 | "source": [ |
|
61 | "source": [ | |
62 | "Pyout" |
|
62 | "Pyout" | |
63 | ] |
|
63 | ] | |
64 | }, |
|
64 | }, | |
65 | { |
|
65 | { | |
66 | "cell_type": "code", |
|
66 | "cell_type": "code", | |
67 | "source": [ |
|
67 | "source": [ | |
68 | "from IPython.display import HTML\n", |
|
68 | "from IPython.display import HTML\n", | |
69 | "HTML(\"\"\"\n", |
|
69 | "HTML(\"\"\"\n", | |
70 | "<script>\n", |
|
70 | "<script>\n", | |
71 | "console.log(\"hello\");\n", |
|
71 | "console.log(\"hello\");\n", | |
72 | "</script>\n", |
|
72 | "</script>\n", | |
73 | "<b>HTML</b>\n", |
|
73 | "<b>HTML</b>\n", | |
74 | "\"\"\")" |
|
74 | "\"\"\")" | |
75 | ], |
|
75 | ], | |
76 | "metadata": { |
|
76 | "metadata": { | |
77 | "collapsed": false, |
|
77 | "collapsed": false, | |
78 | "autoscroll": false |
|
78 | "autoscroll": false | |
79 | }, |
|
79 | }, | |
80 | "outputs": [ |
|
80 | "outputs": [ | |
81 | { |
|
81 | { | |
82 | "text/html": [ |
|
82 | "text/html": [ | |
83 | "\n", |
|
83 | "\n", | |
84 | "<script>\n", |
|
84 | "<script>\n", | |
85 | "console.log(\"hello\");\n", |
|
85 | "console.log(\"hello\");\n", | |
86 | "</script>\n", |
|
86 | "</script>\n", | |
87 | "<b>HTML</b>\n" |
|
87 | "<b>HTML</b>\n" | |
88 | ], |
|
88 | ], | |
89 | "metadata": {}, |
|
89 | "metadata": {}, | |
90 | "output_type": "execute_result", |
|
90 | "output_type": "execute_result", | |
91 |
" |
|
91 | "execution_count": 3, | |
92 | "text/plain": [ |
|
92 | "text/plain": [ | |
93 | "<IPython.core.display.HTML at 0x1112757d0>" |
|
93 | "<IPython.core.display.HTML at 0x1112757d0>" | |
94 | ] |
|
94 | ] | |
95 | } |
|
95 | } | |
96 | ], |
|
96 | ], | |
97 |
" |
|
97 | "execution_count": 3 | |
98 | }, |
|
98 | }, | |
99 | { |
|
99 | { | |
100 | "cell_type": "code", |
|
100 | "cell_type": "code", | |
101 | "source": [ |
|
101 | "source": [ | |
102 | "%%javascript\n", |
|
102 | "%%javascript\n", | |
103 | "console.log(\"hi\");" |
|
103 | "console.log(\"hi\");" | |
104 | ], |
|
104 | ], | |
105 | "metadata": { |
|
105 | "metadata": { | |
106 | "collapsed": false, |
|
106 | "collapsed": false, | |
107 | "autoscroll": false |
|
107 | "autoscroll": false | |
108 | }, |
|
108 | }, | |
109 | "outputs": [ |
|
109 | "outputs": [ | |
110 | { |
|
110 | { | |
111 | "text/javascript": [ |
|
111 | "text/javascript": [ | |
112 | "console.log(\"hi\");" |
|
112 | "console.log(\"hi\");" | |
113 | ], |
|
113 | ], | |
114 | "metadata": {}, |
|
114 | "metadata": {}, | |
115 | "output_type": "display_data", |
|
115 | "output_type": "display_data", | |
116 | "text/plain": [ |
|
116 | "text/plain": [ | |
117 | "<IPython.core.display.Javascript at 0x1112b4b50>" |
|
117 | "<IPython.core.display.Javascript at 0x1112b4b50>" | |
118 | ] |
|
118 | ] | |
119 | } |
|
119 | } | |
120 | ], |
|
120 | ], | |
121 |
" |
|
121 | "execution_count": 7 | |
122 | }, |
|
122 | }, | |
123 | { |
|
123 | { | |
124 | "cell_type": "heading", |
|
124 | "cell_type": "heading", | |
125 | "level": 3, |
|
125 | "level": 3, | |
126 | "metadata": {}, |
|
126 | "metadata": {}, | |
127 | "source": [ |
|
127 | "source": [ | |
128 | "Image" |
|
128 | "Image" | |
129 | ] |
|
129 | ] | |
130 | }, |
|
130 | }, | |
131 | { |
|
131 | { | |
132 | "cell_type": "code", |
|
132 | "cell_type": "code", | |
133 | "source": [ |
|
133 | "source": [ | |
134 | "from IPython.display import Image\n", |
|
134 | "from IPython.display import Image\n", | |
135 | "Image(\"http://ipython.org/_static/IPy_header.png\")" |
|
135 | "Image(\"http://ipython.org/_static/IPy_header.png\")" | |
136 | ], |
|
136 | ], | |
137 | "metadata": { |
|
137 | "metadata": { | |
138 | "collapsed": false, |
|
138 | "collapsed": false, | |
139 | "autoscroll": false |
|
139 | "autoscroll": false | |
140 | }, |
|
140 | }, | |
141 | "outputs": [ |
|
141 | "outputs": [ | |
142 | { |
|
142 | { | |
143 | "metadata": {}, |
|
143 | "metadata": {}, | |
144 | "output_type": "execute_result", |
|
144 | "output_type": "execute_result", | |
145 | "image/png": "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\n", |
|
145 | "image/png": "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\n", | |
146 |
" |
|
146 | "execution_count": 6, | |
147 | "text/plain": [ |
|
147 | "text/plain": [ | |
148 | "<IPython.core.display.Image at 0x111275490>" |
|
148 | "<IPython.core.display.Image at 0x111275490>" | |
149 | ] |
|
149 | ] | |
150 | } |
|
150 | } | |
151 | ], |
|
151 | ], | |
152 |
" |
|
152 | "execution_count": 6 | |
153 | } |
|
153 | } | |
154 | ] |
|
154 | ] | |
155 | } |
|
155 | } |
@@ -1,209 +1,221 | |||||
1 | """Code for converting notebooks to and from v3.""" |
|
1 | """Code for converting notebooks to and from v3.""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | import json |
|
6 | import json | |
7 |
|
7 | |||
8 | from .nbbase import ( |
|
8 | from .nbbase import ( | |
9 | nbformat, nbformat_minor, |
|
9 | nbformat, nbformat_minor, | |
10 | NotebookNode, |
|
10 | NotebookNode, | |
11 | ) |
|
11 | ) | |
12 |
|
12 | |||
13 | from IPython.nbformat import v3 |
|
13 | from IPython.nbformat import v3 | |
14 | from IPython.utils.log import get_logger |
|
14 | from IPython.utils.log import get_logger | |
15 |
|
15 | |||
16 |
|
16 | |||
17 | def upgrade(nb, from_version=3, from_minor=0): |
|
17 | def upgrade(nb, from_version=3, from_minor=0): | |
18 | """Convert a notebook to v4. |
|
18 | """Convert a notebook to v4. | |
19 |
|
19 | |||
20 | Parameters |
|
20 | Parameters | |
21 | ---------- |
|
21 | ---------- | |
22 | nb : NotebookNode |
|
22 | nb : NotebookNode | |
23 | The Python representation of the notebook to convert. |
|
23 | The Python representation of the notebook to convert. | |
24 | from_version : int |
|
24 | from_version : int | |
25 | The original version of the notebook to convert. |
|
25 | The original version of the notebook to convert. | |
26 | from_minor : int |
|
26 | from_minor : int | |
27 | The original minor version of the notebook to convert (only relevant for v >= 3). |
|
27 | The original minor version of the notebook to convert (only relevant for v >= 3). | |
28 | """ |
|
28 | """ | |
29 | from IPython.nbformat.current import validate, ValidationError |
|
29 | from IPython.nbformat.current import validate, ValidationError | |
30 | if from_version == 3: |
|
30 | if from_version == 3: | |
31 | # Validate the notebook before conversion |
|
31 | # Validate the notebook before conversion | |
32 | try: |
|
32 | try: | |
33 | validate(nb, version=from_version) |
|
33 | validate(nb, version=from_version) | |
34 | except ValidationError as e: |
|
34 | except ValidationError as e: | |
35 | get_logger().error("Notebook JSON is not valid v%i: %s", from_version, e) |
|
35 | get_logger().error("Notebook JSON is not valid v%i: %s", from_version, e) | |
36 |
|
36 | |||
37 | # Mark the original nbformat so consumers know it has been converted |
|
37 | # Mark the original nbformat so consumers know it has been converted | |
38 | orig_nbformat = nb.pop('orig_nbformat', None) |
|
38 | orig_nbformat = nb.pop('orig_nbformat', None) | |
39 | nb.metadata.orig_nbformat = orig_nbformat or 3 |
|
39 | nb.metadata.orig_nbformat = orig_nbformat or 3 | |
40 |
|
40 | |||
41 | # Mark the new format |
|
41 | # Mark the new format | |
42 | nb.nbformat = nbformat |
|
42 | nb.nbformat = nbformat | |
43 | nb.nbformat_minor = nbformat_minor |
|
43 | nb.nbformat_minor = nbformat_minor | |
44 |
|
44 | |||
45 | # remove worksheet(s) |
|
45 | # remove worksheet(s) | |
46 | nb['cells'] = cells = [] |
|
46 | nb['cells'] = cells = [] | |
47 | # In the unlikely event of multiple worksheets, |
|
47 | # In the unlikely event of multiple worksheets, | |
48 | # they will be flattened |
|
48 | # they will be flattened | |
49 | for ws in nb.pop('worksheets', []): |
|
49 | for ws in nb.pop('worksheets', []): | |
50 | # upgrade each cell |
|
50 | # upgrade each cell | |
51 | for cell in ws['cells']: |
|
51 | for cell in ws['cells']: | |
52 | cells.append(upgrade_cell(cell)) |
|
52 | cells.append(upgrade_cell(cell)) | |
53 | # upgrade metadata |
|
53 | # upgrade metadata | |
54 | nb.metadata.pop('name', '') |
|
54 | nb.metadata.pop('name', '') | |
55 | # Validate the converted notebook before returning it |
|
55 | # Validate the converted notebook before returning it | |
56 | try: |
|
56 | try: | |
57 | validate(nb, version=nbformat) |
|
57 | validate(nb, version=nbformat) | |
58 | except ValidationError as e: |
|
58 | except ValidationError as e: | |
59 | get_logger().error("Notebook JSON is not valid v%i: %s", nbformat, e) |
|
59 | get_logger().error("Notebook JSON is not valid v%i: %s", nbformat, e) | |
60 | return nb |
|
60 | return nb | |
61 | elif from_version == 4: |
|
61 | elif from_version == 4: | |
62 | # nothing to do |
|
62 | # nothing to do | |
63 | if from_minor != nbformat_minor: |
|
63 | if from_minor != nbformat_minor: | |
64 | nb.metadata.orig_nbformat_minor = from_minor |
|
64 | nb.metadata.orig_nbformat_minor = from_minor | |
65 | nb.nbformat_minor = nbformat_minor |
|
65 | nb.nbformat_minor = nbformat_minor | |
66 |
|
66 | |||
67 | return nb |
|
67 | return nb | |
68 | else: |
|
68 | else: | |
69 | raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \ |
|
69 | raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \ | |
70 | 'Try using the IPython.nbformat.convert module.' % from_version) |
|
70 | 'Try using the IPython.nbformat.convert module.' % from_version) | |
71 |
|
71 | |||
72 | def upgrade_cell(cell): |
|
72 | def upgrade_cell(cell): | |
73 | """upgrade a cell from v3 to v4 |
|
73 | """upgrade a cell from v3 to v4 | |
74 |
|
74 | |||
75 | code cell: |
|
75 | code cell: | |
76 | - remove language metadata |
|
76 | - remove language metadata | |
77 | - cell.input -> cell.source |
|
77 | - cell.input -> cell.source | |
|
78 | - cell.prompt_number -> cell.execution_count | |||
78 | - update outputs |
|
79 | - update outputs | |
79 | """ |
|
80 | """ | |
80 | cell.setdefault('metadata', NotebookNode()) |
|
81 | cell.setdefault('metadata', NotebookNode()) | |
81 | if cell.cell_type == 'code': |
|
82 | if cell.cell_type == 'code': | |
82 | cell.pop('language', '') |
|
83 | cell.pop('language', '') | |
83 | cell.metadata.collapsed = cell.pop('collapsed') |
|
84 | cell.metadata.collapsed = cell.pop('collapsed') | |
84 | cell.source = cell.pop('input') |
|
85 | cell.source = cell.pop('input') | |
85 |
cell. |
|
86 | cell.execution_count = cell.pop('prompt_number', None) | |
86 | cell.outputs = upgrade_outputs(cell.outputs) |
|
87 | cell.outputs = upgrade_outputs(cell.outputs) | |
87 | elif cell.cell_type == 'html': |
|
88 | elif cell.cell_type == 'html': | |
88 | # Technically, this exists. It will never happen in practice. |
|
89 | # Technically, this exists. It will never happen in practice. | |
89 | cell.cell_type = 'markdown' |
|
90 | cell.cell_type = 'markdown' | |
90 | return cell |
|
91 | return cell | |
91 |
|
92 | |||
92 | def downgrade_cell(cell): |
|
93 | def downgrade_cell(cell): | |
|
94 | """downgrade a cell from v4 to v3 | |||
|
95 | ||||
|
96 | code cell: | |||
|
97 | - set cell.language | |||
|
98 | - cell.input <- cell.source | |||
|
99 | - cell.prompt_number <- cell.execution_count | |||
|
100 | - update outputs | |||
|
101 | """ | |||
93 | if cell.cell_type == 'code': |
|
102 | if cell.cell_type == 'code': | |
94 | cell.language = 'python' |
|
103 | cell.language = 'python' | |
95 | cell.input = cell.pop('source', '') |
|
104 | cell.input = cell.pop('source', '') | |
|
105 | cell.prompt_number = cell.pop('execution_count', None) | |||
96 | cell.collapsed = cell.metadata.pop('collapsed', False) |
|
106 | cell.collapsed = cell.metadata.pop('collapsed', False) | |
97 | cell.outputs = downgrade_outputs(cell.outputs) |
|
107 | cell.outputs = downgrade_outputs(cell.outputs) | |
98 | return cell |
|
108 | return cell | |
99 |
|
109 | |||
100 | _mime_map = { |
|
110 | _mime_map = { | |
101 | "text" : "text/plain", |
|
111 | "text" : "text/plain", | |
102 | "html" : "text/html", |
|
112 | "html" : "text/html", | |
103 | "svg" : "image/svg+xml", |
|
113 | "svg" : "image/svg+xml", | |
104 | "png" : "image/png", |
|
114 | "png" : "image/png", | |
105 | "jpeg" : "image/jpeg", |
|
115 | "jpeg" : "image/jpeg", | |
106 | "latex" : "text/latex", |
|
116 | "latex" : "text/latex", | |
107 | "json" : "application/json", |
|
117 | "json" : "application/json", | |
108 | "javascript" : "application/javascript", |
|
118 | "javascript" : "application/javascript", | |
109 | }; |
|
119 | }; | |
110 |
|
120 | |||
111 | def to_mime_key(d): |
|
121 | def to_mime_key(d): | |
112 | """convert dict with v3 aliases to plain mime-type keys""" |
|
122 | """convert dict with v3 aliases to plain mime-type keys""" | |
113 | for alias, mime in _mime_map.items(): |
|
123 | for alias, mime in _mime_map.items(): | |
114 | if alias in d: |
|
124 | if alias in d: | |
115 | d[mime] = d.pop(alias) |
|
125 | d[mime] = d.pop(alias) | |
116 | return d |
|
126 | return d | |
117 |
|
127 | |||
118 | def from_mime_key(d): |
|
128 | def from_mime_key(d): | |
119 | """convert dict with mime-type keys to v3 aliases""" |
|
129 | """convert dict with mime-type keys to v3 aliases""" | |
120 | for alias, mime in _mime_map.items(): |
|
130 | for alias, mime in _mime_map.items(): | |
121 | if mime in d: |
|
131 | if mime in d: | |
122 | d[alias] = d.pop(mime) |
|
132 | d[alias] = d.pop(mime) | |
123 | return d |
|
133 | return d | |
124 |
|
134 | |||
125 | def upgrade_output(output): |
|
135 | def upgrade_output(output): | |
126 | """upgrade a single code cell output from v3 to v4 |
|
136 | """upgrade a single code cell output from v3 to v4 | |
127 |
|
137 | |||
128 | - pyout -> execute_result |
|
138 | - pyout -> execute_result | |
129 | - pyerr -> error |
|
139 | - pyerr -> error | |
130 | - mime-type keys |
|
140 | - mime-type keys | |
131 | - stream.stream -> stream.name |
|
141 | - stream.stream -> stream.name | |
132 | """ |
|
142 | """ | |
133 | output.setdefault('metadata', NotebookNode()) |
|
143 | output.setdefault('metadata', NotebookNode()) | |
134 | if output['output_type'] in {'pyout', 'display_data'}: |
|
144 | if output['output_type'] in {'pyout', 'display_data'}: | |
135 | if output['output_type'] == 'pyout': |
|
145 | if output['output_type'] == 'pyout': | |
136 | output['output_type'] = 'execute_result' |
|
146 | output['output_type'] = 'execute_result' | |
|
147 | output['execution_count'] = output.pop('prompt_number', None) | |||
137 | to_mime_key(output) |
|
148 | to_mime_key(output) | |
138 | to_mime_key(output.metadata) |
|
149 | to_mime_key(output.metadata) | |
139 | if 'application/json' in output: |
|
150 | if 'application/json' in output: | |
140 | output['application/json'] = json.loads(output['application/json']) |
|
151 | output['application/json'] = json.loads(output['application/json']) | |
141 | # promote ascii bytes (from v2) to unicode |
|
152 | # promote ascii bytes (from v2) to unicode | |
142 | for key in ('image/png', 'image/jpeg'): |
|
153 | for key in ('image/png', 'image/jpeg'): | |
143 | if key in output and isinstance(output[key], bytes): |
|
154 | if key in output and isinstance(output[key], bytes): | |
144 | output[key] = output[key].decode('ascii') |
|
155 | output[key] = output[key].decode('ascii') | |
145 | elif output['output_type'] == 'pyerr': |
|
156 | elif output['output_type'] == 'pyerr': | |
146 | output['output_type'] = 'error' |
|
157 | output['output_type'] = 'error' | |
147 | elif output['output_type'] == 'stream': |
|
158 | elif output['output_type'] == 'stream': | |
148 | output['name'] = output.pop('stream') |
|
159 | output['name'] = output.pop('stream') | |
149 | return output |
|
160 | return output | |
150 |
|
161 | |||
151 | def downgrade_output(output): |
|
162 | def downgrade_output(output): | |
152 | """downgrade a single code cell output to v3 from v4 |
|
163 | """downgrade a single code cell output to v3 from v4 | |
153 |
|
164 | |||
154 | - pyout <- execute_result |
|
165 | - pyout <- execute_result | |
155 | - pyerr <- error |
|
166 | - pyerr <- error | |
156 | - un-mime-type keys |
|
167 | - un-mime-type keys | |
157 | - stream.stream <- stream.name |
|
168 | - stream.stream <- stream.name | |
158 | """ |
|
169 | """ | |
159 | if output['output_type'] == 'execute_result': |
|
170 | if output['output_type'] == 'execute_result': | |
160 | output['output_type'] = 'pyout' |
|
171 | output['output_type'] = 'pyout' | |
|
172 | output['prompt_number'] = output.pop('execution_count', None) | |||
161 | if 'application/json' in output: |
|
173 | if 'application/json' in output: | |
162 | output['application/json'] = json.dumps(output['application/json']) |
|
174 | output['application/json'] = json.dumps(output['application/json']) | |
163 | from_mime_key(output) |
|
175 | from_mime_key(output) | |
164 | from_mime_key(output.get('metadata', {})) |
|
176 | from_mime_key(output.get('metadata', {})) | |
165 | elif output['output_type'] == 'error': |
|
177 | elif output['output_type'] == 'error': | |
166 | output['output_type'] = 'pyerr' |
|
178 | output['output_type'] = 'pyerr' | |
167 | elif output['output_type'] == 'display_data': |
|
179 | elif output['output_type'] == 'display_data': | |
168 | if 'application/json' in output: |
|
180 | if 'application/json' in output: | |
169 | output['application/json'] = json.dumps(output['application/json']) |
|
181 | output['application/json'] = json.dumps(output['application/json']) | |
170 | from_mime_key(output) |
|
182 | from_mime_key(output) | |
171 | from_mime_key(output.get('metadata', {})) |
|
183 | from_mime_key(output.get('metadata', {})) | |
172 | elif output['output_type'] == 'stream': |
|
184 | elif output['output_type'] == 'stream': | |
173 | output['stream'] = output.pop('name') |
|
185 | output['stream'] = output.pop('name') | |
174 | output.pop('metadata') |
|
186 | output.pop('metadata') | |
175 | return output |
|
187 | return output | |
176 |
|
188 | |||
177 | def upgrade_outputs(outputs): |
|
189 | def upgrade_outputs(outputs): | |
178 | """upgrade outputs of a code cell from v3 to v4""" |
|
190 | """upgrade outputs of a code cell from v3 to v4""" | |
179 | return [upgrade_output(op) for op in outputs] |
|
191 | return [upgrade_output(op) for op in outputs] | |
180 |
|
192 | |||
181 | def downgrade_outputs(outputs): |
|
193 | def downgrade_outputs(outputs): | |
182 | """downgrade outputs of a code cell to v3 from v4""" |
|
194 | """downgrade outputs of a code cell to v3 from v4""" | |
183 | return [downgrade_output(op) for op in outputs] |
|
195 | return [downgrade_output(op) for op in outputs] | |
184 |
|
196 | |||
185 | def downgrade(nb): |
|
197 | def downgrade(nb): | |
186 | """Convert a v4 notebook to v3. |
|
198 | """Convert a v4 notebook to v3. | |
187 |
|
199 | |||
188 | Parameters |
|
200 | Parameters | |
189 | ---------- |
|
201 | ---------- | |
190 | nb : NotebookNode |
|
202 | nb : NotebookNode | |
191 | The Python representation of the notebook to convert. |
|
203 | The Python representation of the notebook to convert. | |
192 | """ |
|
204 | """ | |
193 | from IPython.nbformat.current import validate |
|
205 | from IPython.nbformat.current import validate | |
194 | # Validate the notebook before conversion |
|
206 | # Validate the notebook before conversion | |
195 | validate(nb, version=nbformat) |
|
207 | validate(nb, version=nbformat) | |
196 |
|
208 | |||
197 | if nb.nbformat != 4: |
|
209 | if nb.nbformat != 4: | |
198 | return nb |
|
210 | return nb | |
199 | nb.nbformat = v3.nbformat |
|
211 | nb.nbformat = v3.nbformat | |
200 | nb.nbformat_minor = v3.nbformat_minor |
|
212 | nb.nbformat_minor = v3.nbformat_minor | |
201 | cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ] |
|
213 | cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ] | |
202 | nb.worksheets = [v3.new_worksheet(cells=cells)] |
|
214 | nb.worksheets = [v3.new_worksheet(cells=cells)] | |
203 | nb.metadata.setdefault('name', '') |
|
215 | nb.metadata.setdefault('name', '') | |
204 | nb.metadata.pop('orig_nbformat', None) |
|
216 | nb.metadata.pop('orig_nbformat', None) | |
205 | nb.metadata.pop('orig_nbformat_minor', None) |
|
217 | nb.metadata.pop('orig_nbformat_minor', None) | |
206 |
|
218 | |||
207 | # Validate the converted notebook before returning it |
|
219 | # Validate the converted notebook before returning it | |
208 | validate(nb, version=v3.nbformat) |
|
220 | validate(nb, version=v3.nbformat) | |
209 | return nb |
|
221 | return nb |
@@ -1,148 +1,148 | |||||
1 | """Python API for composing notebook elements |
|
1 | """Python API for composing notebook elements | |
2 |
|
2 | |||
3 | The Python representation of a notebook is a nested structure of |
|
3 | The Python representation of a notebook is a nested structure of | |
4 | dictionary subclasses that support attribute access |
|
4 | dictionary subclasses that support attribute access | |
5 | (IPython.utils.ipstruct.Struct). The functions in this module are merely |
|
5 | (IPython.utils.ipstruct.Struct). The functions in this module are merely | |
6 | helpers to build the structs in the right form. |
|
6 | helpers to build the structs in the right form. | |
7 | """ |
|
7 | """ | |
8 |
|
8 | |||
9 | # Copyright (c) IPython Development Team. |
|
9 | # Copyright (c) IPython Development Team. | |
10 | # Distributed under the terms of the Modified BSD License. |
|
10 | # Distributed under the terms of the Modified BSD License. | |
11 |
|
11 | |||
12 | from IPython.utils.ipstruct import Struct |
|
12 | from IPython.utils.ipstruct import Struct | |
13 |
|
13 | |||
14 | # Change this when incrementing the nbformat version |
|
14 | # Change this when incrementing the nbformat version | |
15 | nbformat = 4 |
|
15 | nbformat = 4 | |
16 | nbformat_minor = 0 |
|
16 | nbformat_minor = 0 | |
17 | nbformat_schema = 'nbformat.v4.schema.json' |
|
17 | nbformat_schema = 'nbformat.v4.schema.json' | |
18 |
|
18 | |||
19 |
|
19 | |||
20 | def validate(node, ref=None): |
|
20 | def validate(node, ref=None): | |
21 | """validate a v4 node""" |
|
21 | """validate a v4 node""" | |
22 | from ..current import validate |
|
22 | from ..current import validate | |
23 | return validate(node, ref=ref, version=nbformat) |
|
23 | return validate(node, ref=ref, version=nbformat) | |
24 |
|
24 | |||
25 |
|
25 | |||
26 | class NotebookNode(Struct): |
|
26 | class NotebookNode(Struct): | |
27 | pass |
|
27 | pass | |
28 |
|
28 | |||
29 | def from_dict(d): |
|
29 | def from_dict(d): | |
30 | if isinstance(d, dict): |
|
30 | if isinstance(d, dict): | |
31 | newd = NotebookNode() |
|
31 | newd = NotebookNode() | |
32 | for k,v in d.items(): |
|
32 | for k,v in d.items(): | |
33 | newd[k] = from_dict(v) |
|
33 | newd[k] = from_dict(v) | |
34 | return newd |
|
34 | return newd | |
35 | elif isinstance(d, (tuple, list)): |
|
35 | elif isinstance(d, (tuple, list)): | |
36 | return [from_dict(i) for i in d] |
|
36 | return [from_dict(i) for i in d] | |
37 | else: |
|
37 | else: | |
38 | return d |
|
38 | return d | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | def new_output(output_type, mime_bundle=None, **kwargs): |
|
41 | def new_output(output_type, mime_bundle=None, **kwargs): | |
42 | """Create a new output, to go in the ``cell.outputs`` list of a code cell.""" |
|
42 | """Create a new output, to go in the ``cell.outputs`` list of a code cell.""" | |
43 | output = NotebookNode(output_type=output_type) |
|
43 | output = NotebookNode(output_type=output_type) | |
44 | output.update(from_dict(kwargs)) |
|
44 | output.update(from_dict(kwargs)) | |
45 | if mime_bundle: |
|
45 | if mime_bundle: | |
46 | output.update(mime_bundle) |
|
46 | output.update(mime_bundle) | |
47 | # populate defaults: |
|
47 | # populate defaults: | |
48 | output.setdefault('metadata', NotebookNode()) |
|
48 | output.setdefault('metadata', NotebookNode()) | |
49 | if output_type == 'stream': |
|
49 | if output_type == 'stream': | |
50 | output.setdefault('name', 'stdout') |
|
50 | output.setdefault('name', 'stdout') | |
51 | output.setdefault('text', '') |
|
51 | output.setdefault('text', '') | |
52 | validate(output, output_type) |
|
52 | validate(output, output_type) | |
53 | return output |
|
53 | return output | |
54 |
|
54 | |||
55 |
|
55 | |||
56 | def output_from_msg(msg): |
|
56 | def output_from_msg(msg): | |
57 | """Create a NotebookNode for an output from a kernel's IOPub message. |
|
57 | """Create a NotebookNode for an output from a kernel's IOPub message. | |
58 |
|
58 | |||
59 | Returns |
|
59 | Returns | |
60 | ------- |
|
60 | ------- | |
61 |
|
61 | |||
62 | NotebookNode: the output as a notebook node. |
|
62 | NotebookNode: the output as a notebook node. | |
63 |
|
63 | |||
64 | Raises |
|
64 | Raises | |
65 | ------ |
|
65 | ------ | |
66 |
|
66 | |||
67 | ValueError: if the message is not an output message. |
|
67 | ValueError: if the message is not an output message. | |
68 |
|
68 | |||
69 | """ |
|
69 | """ | |
70 | msg_type = msg['header']['msg_type'] |
|
70 | msg_type = msg['header']['msg_type'] | |
71 | content = msg['content'] |
|
71 | content = msg['content'] | |
72 |
|
72 | |||
73 | if msg_type == 'execute_result': |
|
73 | if msg_type == 'execute_result': | |
74 | return new_output(output_type=msg_type, |
|
74 | return new_output(output_type=msg_type, | |
75 | metadata=content['metadata'], |
|
75 | metadata=content['metadata'], | |
76 | mime_bundle=content['data'], |
|
76 | mime_bundle=content['data'], | |
77 |
|
|
77 | execution_count=content['execution_count'], | |
78 | ) |
|
78 | ) | |
79 |
|
79 | |||
80 | elif msg_type == 'stream': |
|
80 | elif msg_type == 'stream': | |
81 | return new_output(output_type=msg_type, |
|
81 | return new_output(output_type=msg_type, | |
82 | name=content['name'], |
|
82 | name=content['name'], | |
83 | data=content['data'], |
|
83 | data=content['data'], | |
84 | ) |
|
84 | ) | |
85 | elif msg_type == 'display_data': |
|
85 | elif msg_type == 'display_data': | |
86 | return new_output(output_type=msg_type, |
|
86 | return new_output(output_type=msg_type, | |
87 | metadata=content['metadata'], |
|
87 | metadata=content['metadata'], | |
88 | mime_bundle=content['data'], |
|
88 | mime_bundle=content['data'], | |
89 | ) |
|
89 | ) | |
90 | elif msg_type == 'error': |
|
90 | elif msg_type == 'error': | |
91 | return new_output(output_type=msg_type, |
|
91 | return new_output(output_type=msg_type, | |
92 | ename=content['ename'], |
|
92 | ename=content['ename'], | |
93 | evalue=content['evalue'], |
|
93 | evalue=content['evalue'], | |
94 | traceback=content['traceback'], |
|
94 | traceback=content['traceback'], | |
95 | ) |
|
95 | ) | |
96 | else: |
|
96 | else: | |
97 | raise ValueError("Unrecognized output msg type: %r" % msg_type) |
|
97 | raise ValueError("Unrecognized output msg type: %r" % msg_type) | |
98 |
|
98 | |||
99 |
|
99 | |||
100 | def new_code_cell(source='', **kwargs): |
|
100 | def new_code_cell(source='', **kwargs): | |
101 | """Create a new code cell""" |
|
101 | """Create a new code cell""" | |
102 | cell = NotebookNode(cell_type='code', source=source) |
|
102 | cell = NotebookNode(cell_type='code', source=source) | |
103 | cell.update(from_dict(kwargs)) |
|
103 | cell.update(from_dict(kwargs)) | |
104 | cell.setdefault('metadata', NotebookNode()) |
|
104 | cell.setdefault('metadata', NotebookNode()) | |
105 | cell.setdefault('source', '') |
|
105 | cell.setdefault('source', '') | |
106 |
cell.setdefault(' |
|
106 | cell.setdefault('execution_count', None) | |
107 | cell.setdefault('outputs', []) |
|
107 | cell.setdefault('outputs', []) | |
108 |
|
108 | |||
109 | validate(cell, 'code_cell') |
|
109 | validate(cell, 'code_cell') | |
110 | return cell |
|
110 | return cell | |
111 |
|
111 | |||
112 | def new_markdown_cell(source='', **kwargs): |
|
112 | def new_markdown_cell(source='', **kwargs): | |
113 | """Create a new markdown cell""" |
|
113 | """Create a new markdown cell""" | |
114 | cell = NotebookNode(cell_type='markdown', source=source) |
|
114 | cell = NotebookNode(cell_type='markdown', source=source) | |
115 | cell.update(from_dict(kwargs)) |
|
115 | cell.update(from_dict(kwargs)) | |
116 | cell.setdefault('metadata', NotebookNode()) |
|
116 | cell.setdefault('metadata', NotebookNode()) | |
117 |
|
117 | |||
118 | validate(cell, 'markdown_cell') |
|
118 | validate(cell, 'markdown_cell') | |
119 | return cell |
|
119 | return cell | |
120 |
|
120 | |||
121 | def new_heading_cell(source='', **kwargs): |
|
121 | def new_heading_cell(source='', **kwargs): | |
122 | """Create a new heading cell""" |
|
122 | """Create a new heading cell""" | |
123 | cell = NotebookNode(cell_type='heading', source=source) |
|
123 | cell = NotebookNode(cell_type='heading', source=source) | |
124 | cell.update(from_dict(kwargs)) |
|
124 | cell.update(from_dict(kwargs)) | |
125 | cell.setdefault('metadata', NotebookNode()) |
|
125 | cell.setdefault('metadata', NotebookNode()) | |
126 | cell.setdefault('level', 1) |
|
126 | cell.setdefault('level', 1) | |
127 |
|
127 | |||
128 | validate(cell, 'heading_cell') |
|
128 | validate(cell, 'heading_cell') | |
129 | return cell |
|
129 | return cell | |
130 |
|
130 | |||
131 | def new_raw_cell(source='', **kwargs): |
|
131 | def new_raw_cell(source='', **kwargs): | |
132 | """Create a new raw cell""" |
|
132 | """Create a new raw cell""" | |
133 | cell = NotebookNode(cell_type='raw', source=source) |
|
133 | cell = NotebookNode(cell_type='raw', source=source) | |
134 | cell.update(from_dict(kwargs)) |
|
134 | cell.update(from_dict(kwargs)) | |
135 | cell.setdefault('metadata', NotebookNode()) |
|
135 | cell.setdefault('metadata', NotebookNode()) | |
136 |
|
136 | |||
137 | validate(cell, 'raw_cell') |
|
137 | validate(cell, 'raw_cell') | |
138 | return cell |
|
138 | return cell | |
139 |
|
139 | |||
140 | def new_notebook(**kwargs): |
|
140 | def new_notebook(**kwargs): | |
141 | """Create a new notebook""" |
|
141 | """Create a new notebook""" | |
142 | nb = from_dict(kwargs) |
|
142 | nb = from_dict(kwargs) | |
143 | nb.nbformat = nbformat |
|
143 | nb.nbformat = nbformat | |
144 | nb.nbformat_minor = nbformat_minor |
|
144 | nb.nbformat_minor = nbformat_minor | |
145 | nb.setdefault('cells', []) |
|
145 | nb.setdefault('cells', []) | |
146 | nb.setdefault('metadata', NotebookNode()) |
|
146 | nb.setdefault('metadata', NotebookNode()) | |
147 | validate(nb) |
|
147 | validate(nb) | |
148 | return nb |
|
148 | return nb |
@@ -1,346 +1,346 | |||||
1 | { |
|
1 | { | |
2 | "$schema": "http://json-schema.org/draft-04/schema#", |
|
2 | "$schema": "http://json-schema.org/draft-04/schema#", | |
3 | "description": "IPython Notebook v4.0 JSON schema.", |
|
3 | "description": "IPython Notebook v4.0 JSON schema.", | |
4 | "type": "object", |
|
4 | "type": "object", | |
5 | "additionalProperties": false, |
|
5 | "additionalProperties": false, | |
6 | "required": ["metadata", "nbformat_minor", "nbformat", "cells"], |
|
6 | "required": ["metadata", "nbformat_minor", "nbformat", "cells"], | |
7 | "properties": { |
|
7 | "properties": { | |
8 | "metadata": { |
|
8 | "metadata": { | |
9 | "description": "Notebook root-level metadata.", |
|
9 | "description": "Notebook root-level metadata.", | |
10 | "type": "object", |
|
10 | "type": "object", | |
11 | "additionalProperties": true, |
|
11 | "additionalProperties": true, | |
12 | "properties": { |
|
12 | "properties": { | |
13 | "kernel_info": { |
|
13 | "kernel_info": { | |
14 | "description": "Kernel information.", |
|
14 | "description": "Kernel information.", | |
15 | "type": "object", |
|
15 | "type": "object", | |
16 | "required": ["name", "language"], |
|
16 | "required": ["name", "language"], | |
17 | "properties": { |
|
17 | "properties": { | |
18 | "name": { |
|
18 | "name": { | |
19 | "description": "Name of the kernel specification.", |
|
19 | "description": "Name of the kernel specification.", | |
20 | "type": "string" |
|
20 | "type": "string" | |
21 | }, |
|
21 | }, | |
22 | "language": { |
|
22 | "language": { | |
23 | "description": "The programming language which this kernel runs.", |
|
23 | "description": "The programming language which this kernel runs.", | |
24 | "type": "string" |
|
24 | "type": "string" | |
25 | }, |
|
25 | }, | |
26 | "codemirror_mode": { |
|
26 | "codemirror_mode": { | |
27 | "description": "The codemirror mode to use for code in this language.", |
|
27 | "description": "The codemirror mode to use for code in this language.", | |
28 | "type": "string" |
|
28 | "type": "string" | |
29 | } |
|
29 | } | |
30 | } |
|
30 | } | |
31 | }, |
|
31 | }, | |
32 | "signature": { |
|
32 | "signature": { | |
33 | "description": "Hash of the notebook.", |
|
33 | "description": "Hash of the notebook.", | |
34 | "type": "string" |
|
34 | "type": "string" | |
35 | }, |
|
35 | }, | |
36 | "orig_nbformat": { |
|
36 | "orig_nbformat": { | |
37 | "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.", |
|
37 | "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.", | |
38 | "type": "integer", |
|
38 | "type": "integer", | |
39 | "minimum": 1 |
|
39 | "minimum": 1 | |
40 | } |
|
40 | } | |
41 | } |
|
41 | } | |
42 | }, |
|
42 | }, | |
43 | "nbformat_minor": { |
|
43 | "nbformat_minor": { | |
44 | "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.", |
|
44 | "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.", | |
45 | "type": "integer", |
|
45 | "type": "integer", | |
46 | "minimum": 0 |
|
46 | "minimum": 0 | |
47 | }, |
|
47 | }, | |
48 | "nbformat": { |
|
48 | "nbformat": { | |
49 | "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.", |
|
49 | "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.", | |
50 | "type": "integer", |
|
50 | "type": "integer", | |
51 | "minimum": 4, |
|
51 | "minimum": 4, | |
52 | "maximum": 4 |
|
52 | "maximum": 4 | |
53 | }, |
|
53 | }, | |
54 | "cells": { |
|
54 | "cells": { | |
55 | "description": "Array of cells of the current notebook.", |
|
55 | "description": "Array of cells of the current notebook.", | |
56 | "type": "array", |
|
56 | "type": "array", | |
57 | "items": { |
|
57 | "items": { | |
58 | "type": "object", |
|
58 | "type": "object", | |
59 | "oneOf": [ |
|
59 | "oneOf": [ | |
60 | {"$ref": "#/definitions/raw_cell"}, |
|
60 | {"$ref": "#/definitions/raw_cell"}, | |
61 | {"$ref": "#/definitions/markdown_cell"}, |
|
61 | {"$ref": "#/definitions/markdown_cell"}, | |
62 | {"$ref": "#/definitions/heading_cell"}, |
|
62 | {"$ref": "#/definitions/heading_cell"}, | |
63 | {"$ref": "#/definitions/code_cell"} |
|
63 | {"$ref": "#/definitions/code_cell"} | |
64 | ] |
|
64 | ] | |
65 | } |
|
65 | } | |
66 | } |
|
66 | } | |
67 | }, |
|
67 | }, | |
68 |
|
68 | |||
69 | "definitions": { |
|
69 | "definitions": { | |
70 |
|
70 | |||
71 | "raw_cell": { |
|
71 | "raw_cell": { | |
72 | "description": "Notebook raw nbconvert cell.", |
|
72 | "description": "Notebook raw nbconvert cell.", | |
73 | "type": "object", |
|
73 | "type": "object", | |
74 | "additionalProperties": false, |
|
74 | "additionalProperties": false, | |
75 | "required": ["cell_type", "metadata", "source"], |
|
75 | "required": ["cell_type", "metadata", "source"], | |
76 | "properties": { |
|
76 | "properties": { | |
77 | "cell_type": { |
|
77 | "cell_type": { | |
78 | "description": "String identifying the type of cell.", |
|
78 | "description": "String identifying the type of cell.", | |
79 | "enum": ["raw"] |
|
79 | "enum": ["raw"] | |
80 | }, |
|
80 | }, | |
81 | "metadata": { |
|
81 | "metadata": { | |
82 | "description": "Cell-level metadata.", |
|
82 | "description": "Cell-level metadata.", | |
83 | "type": "object", |
|
83 | "type": "object", | |
84 | "additionalProperties": true, |
|
84 | "additionalProperties": true, | |
85 | "properties": { |
|
85 | "properties": { | |
86 | "format": { |
|
86 | "format": { | |
87 | "description": "Raw cell metadata format for nbconvert.", |
|
87 | "description": "Raw cell metadata format for nbconvert.", | |
88 | "type": "string" |
|
88 | "type": "string" | |
89 | }, |
|
89 | }, | |
90 | "name": {"$ref": "#/definitions/misc/metadata_name"}, |
|
90 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |
91 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} |
|
91 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |
92 | } |
|
92 | } | |
93 | }, |
|
93 | }, | |
94 | "source": {"$ref": "#/definitions/misc/source"} |
|
94 | "source": {"$ref": "#/definitions/misc/source"} | |
95 | } |
|
95 | } | |
96 | }, |
|
96 | }, | |
97 |
|
97 | |||
98 | "markdown_cell": { |
|
98 | "markdown_cell": { | |
99 | "description": "Notebook markdown cell.", |
|
99 | "description": "Notebook markdown cell.", | |
100 | "type": "object", |
|
100 | "type": "object", | |
101 | "additionalProperties": false, |
|
101 | "additionalProperties": false, | |
102 | "required": ["cell_type", "metadata", "source"], |
|
102 | "required": ["cell_type", "metadata", "source"], | |
103 | "properties": { |
|
103 | "properties": { | |
104 | "cell_type": { |
|
104 | "cell_type": { | |
105 | "description": "String identifying the type of cell.", |
|
105 | "description": "String identifying the type of cell.", | |
106 | "enum": ["markdown"] |
|
106 | "enum": ["markdown"] | |
107 | }, |
|
107 | }, | |
108 | "metadata": { |
|
108 | "metadata": { | |
109 | "description": "Cell-level metadata.", |
|
109 | "description": "Cell-level metadata.", | |
110 | "type": "object", |
|
110 | "type": "object", | |
111 | "properties": { |
|
111 | "properties": { | |
112 | "name": {"$ref": "#/definitions/misc/metadata_name"}, |
|
112 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |
113 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} |
|
113 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |
114 | }, |
|
114 | }, | |
115 | "additionalProperties": true |
|
115 | "additionalProperties": true | |
116 | }, |
|
116 | }, | |
117 | "source": {"$ref": "#/definitions/misc/source"} |
|
117 | "source": {"$ref": "#/definitions/misc/source"} | |
118 | } |
|
118 | } | |
119 | }, |
|
119 | }, | |
120 |
|
120 | |||
121 | "heading_cell": { |
|
121 | "heading_cell": { | |
122 | "description": "Notebook heading cell.", |
|
122 | "description": "Notebook heading cell.", | |
123 | "type": "object", |
|
123 | "type": "object", | |
124 | "additionalProperties": false, |
|
124 | "additionalProperties": false, | |
125 | "required": ["cell_type", "metadata", "source", "level"], |
|
125 | "required": ["cell_type", "metadata", "source", "level"], | |
126 | "properties": { |
|
126 | "properties": { | |
127 | "cell_type": { |
|
127 | "cell_type": { | |
128 | "description": "String identifying the type of cell.", |
|
128 | "description": "String identifying the type of cell.", | |
129 | "enum": ["heading"] |
|
129 | "enum": ["heading"] | |
130 | }, |
|
130 | }, | |
131 | "metadata": { |
|
131 | "metadata": { | |
132 | "description": "Cell-level metadata.", |
|
132 | "description": "Cell-level metadata.", | |
133 | "type": "object", |
|
133 | "type": "object", | |
134 | "properties": { |
|
134 | "properties": { | |
135 | "name": {"$ref": "#/definitions/misc/metadata_name"}, |
|
135 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |
136 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} |
|
136 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |
137 | }, |
|
137 | }, | |
138 | "additionalProperties": true |
|
138 | "additionalProperties": true | |
139 | }, |
|
139 | }, | |
140 | "source": {"$ref": "#/definitions/misc/source"}, |
|
140 | "source": {"$ref": "#/definitions/misc/source"}, | |
141 | "level": { |
|
141 | "level": { | |
142 | "description": "Level of heading cells.", |
|
142 | "description": "Level of heading cells.", | |
143 | "type": "integer", |
|
143 | "type": "integer", | |
144 | "minimum": 1 |
|
144 | "minimum": 1 | |
145 | } |
|
145 | } | |
146 | } |
|
146 | } | |
147 | }, |
|
147 | }, | |
148 |
|
148 | |||
149 | "code_cell": { |
|
149 | "code_cell": { | |
150 | "description": "Notebook code cell.", |
|
150 | "description": "Notebook code cell.", | |
151 | "type": "object", |
|
151 | "type": "object", | |
152 | "additionalProperties": false, |
|
152 | "additionalProperties": false, | |
153 |
"required": ["cell_type", "metadata", "source", "outputs", " |
|
153 | "required": ["cell_type", "metadata", "source", "outputs", "execution_count"], | |
154 | "properties": { |
|
154 | "properties": { | |
155 | "cell_type": { |
|
155 | "cell_type": { | |
156 | "description": "String identifying the type of cell.", |
|
156 | "description": "String identifying the type of cell.", | |
157 | "enum": ["code"] |
|
157 | "enum": ["code"] | |
158 | }, |
|
158 | }, | |
159 | "metadata": { |
|
159 | "metadata": { | |
160 | "description": "Cell-level metadata.", |
|
160 | "description": "Cell-level metadata.", | |
161 | "type": "object", |
|
161 | "type": "object", | |
162 | "additionalProperties": true, |
|
162 | "additionalProperties": true, | |
163 | "properties": { |
|
163 | "properties": { | |
164 | "collapsed": { |
|
164 | "collapsed": { | |
165 | "description": "Whether the cell is collapsed/expanded.", |
|
165 | "description": "Whether the cell is collapsed/expanded.", | |
166 | "type": "boolean" |
|
166 | "type": "boolean" | |
167 | }, |
|
167 | }, | |
168 | "autoscroll": { |
|
168 | "autoscroll": { | |
169 | "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.", |
|
169 | "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.", | |
170 | "enum": [true, false, "auto"] |
|
170 | "enum": [true, false, "auto"] | |
171 | }, |
|
171 | }, | |
172 | "name": {"$ref": "#/definitions/misc/metadata_name"}, |
|
172 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |
173 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} |
|
173 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |
174 | } |
|
174 | } | |
175 | }, |
|
175 | }, | |
176 | "source": {"$ref": "#/definitions/misc/source"}, |
|
176 | "source": {"$ref": "#/definitions/misc/source"}, | |
177 | "outputs": { |
|
177 | "outputs": { | |
178 | "description": "Execution, display, or stream outputs.", |
|
178 | "description": "Execution, display, or stream outputs.", | |
179 | "type": "array", |
|
179 | "type": "array", | |
180 | "items": {"$ref": "#/definitions/output"} |
|
180 | "items": {"$ref": "#/definitions/output"} | |
181 | }, |
|
181 | }, | |
182 |
" |
|
182 | "execution_count": { | |
183 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", |
|
183 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", | |
184 | "type": ["integer", "null"], |
|
184 | "type": ["integer", "null"], | |
185 | "minimum": 0 |
|
185 | "minimum": 0 | |
186 | } |
|
186 | } | |
187 | } |
|
187 | } | |
188 | }, |
|
188 | }, | |
189 | "output": { |
|
189 | "output": { | |
190 | "type": "object", |
|
190 | "type": "object", | |
191 | "oneOf": [ |
|
191 | "oneOf": [ | |
192 | {"$ref": "#/definitions/execute_result"}, |
|
192 | {"$ref": "#/definitions/execute_result"}, | |
193 | {"$ref": "#/definitions/display_data"}, |
|
193 | {"$ref": "#/definitions/display_data"}, | |
194 | {"$ref": "#/definitions/stream"}, |
|
194 | {"$ref": "#/definitions/stream"}, | |
195 | {"$ref": "#/definitions/error"} |
|
195 | {"$ref": "#/definitions/error"} | |
196 | ] |
|
196 | ] | |
197 | }, |
|
197 | }, | |
198 | "execute_result": { |
|
198 | "execute_result": { | |
199 | "description": "Result of executing a code cell.", |
|
199 | "description": "Result of executing a code cell.", | |
200 | "type": "object", |
|
200 | "type": "object", | |
201 | "additionalProperties": false, |
|
201 | "additionalProperties": false, | |
202 |
"required": ["output_type", "metadata", " |
|
202 | "required": ["output_type", "metadata", "execution_count"], | |
203 | "properties": { |
|
203 | "properties": { | |
204 | "output_type": { |
|
204 | "output_type": { | |
205 | "description": "Type of cell output.", |
|
205 | "description": "Type of cell output.", | |
206 | "enum": ["execute_result"] |
|
206 | "enum": ["execute_result"] | |
207 | }, |
|
207 | }, | |
208 |
" |
|
208 | "execution_count": { | |
209 | "description": "A result's prompt number.", |
|
209 | "description": "A result's prompt number.", | |
210 | "type": ["integer"], |
|
210 | "type": ["integer", "null"], | |
211 | "minimum": 0 |
|
211 | "minimum": 0 | |
212 | }, |
|
212 | }, | |
213 | "application/json": { |
|
213 | "application/json": { | |
214 | "type": "object" |
|
214 | "type": "object" | |
215 | }, |
|
215 | }, | |
216 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} |
|
216 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} | |
217 | }, |
|
217 | }, | |
218 | "patternProperties": { |
|
218 | "patternProperties": { | |
219 | "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { |
|
219 | "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { | |
220 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", |
|
220 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |
221 | "$ref": "#/definitions/misc/multiline_string" |
|
221 | "$ref": "#/definitions/misc/multiline_string" | |
222 | } |
|
222 | } | |
223 | } |
|
223 | } | |
224 | }, |
|
224 | }, | |
225 |
|
225 | |||
226 | "display_data": { |
|
226 | "display_data": { | |
227 | "description": "Data displayed as a result of code cell execution.", |
|
227 | "description": "Data displayed as a result of code cell execution.", | |
228 | "type": "object", |
|
228 | "type": "object", | |
229 | "additionalProperties": false, |
|
229 | "additionalProperties": false, | |
230 | "required": ["output_type", "metadata"], |
|
230 | "required": ["output_type", "metadata"], | |
231 | "properties": { |
|
231 | "properties": { | |
232 | "output_type": { |
|
232 | "output_type": { | |
233 | "description": "Type of cell output.", |
|
233 | "description": "Type of cell output.", | |
234 | "enum": ["display_data"] |
|
234 | "enum": ["display_data"] | |
235 | }, |
|
235 | }, | |
236 | "application/json": { |
|
236 | "application/json": { | |
237 | "type": "object" |
|
237 | "type": "object" | |
238 | }, |
|
238 | }, | |
239 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} |
|
239 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} | |
240 | }, |
|
240 | }, | |
241 | "patternProperties": { |
|
241 | "patternProperties": { | |
242 | "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { |
|
242 | "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { | |
243 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", |
|
243 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |
244 | "$ref": "#/definitions/misc/multiline_string" |
|
244 | "$ref": "#/definitions/misc/multiline_string" | |
245 | } |
|
245 | } | |
246 | } |
|
246 | } | |
247 | }, |
|
247 | }, | |
248 |
|
248 | |||
249 | "stream": { |
|
249 | "stream": { | |
250 | "description": "Stream output from a code cell.", |
|
250 | "description": "Stream output from a code cell.", | |
251 | "type": "object", |
|
251 | "type": "object", | |
252 | "additionalProperties": false, |
|
252 | "additionalProperties": false, | |
253 | "required": ["output_type", "metadata", "name", "text"], |
|
253 | "required": ["output_type", "metadata", "name", "text"], | |
254 | "properties": { |
|
254 | "properties": { | |
255 | "output_type": { |
|
255 | "output_type": { | |
256 | "description": "Type of cell output.", |
|
256 | "description": "Type of cell output.", | |
257 | "enum": ["stream"] |
|
257 | "enum": ["stream"] | |
258 | }, |
|
258 | }, | |
259 | "metadata": {"$ref": "#/definitions/misc/output_metadata"}, |
|
259 | "metadata": {"$ref": "#/definitions/misc/output_metadata"}, | |
260 | "name": { |
|
260 | "name": { | |
261 | "description": "The name of the stream (stdout, stderr).", |
|
261 | "description": "The name of the stream (stdout, stderr).", | |
262 | "type": "string" |
|
262 | "type": "string" | |
263 | }, |
|
263 | }, | |
264 | "text": { |
|
264 | "text": { | |
265 | "description": "The stream's text output, represented as an array of strings.", |
|
265 | "description": "The stream's text output, represented as an array of strings.", | |
266 | "$ref": "#/definitions/misc/multiline_string" |
|
266 | "$ref": "#/definitions/misc/multiline_string" | |
267 | } |
|
267 | } | |
268 | } |
|
268 | } | |
269 | }, |
|
269 | }, | |
270 |
|
270 | |||
271 | "error": { |
|
271 | "error": { | |
272 | "description": "Output of an error that occurred during code cell execution.", |
|
272 | "description": "Output of an error that occurred during code cell execution.", | |
273 | "type": "object", |
|
273 | "type": "object", | |
274 | "additionalProperties": false, |
|
274 | "additionalProperties": false, | |
275 | "required": ["output_type", "metadata", "ename", "evalue", "traceback"], |
|
275 | "required": ["output_type", "metadata", "ename", "evalue", "traceback"], | |
276 | "properties": { |
|
276 | "properties": { | |
277 | "output_type": { |
|
277 | "output_type": { | |
278 | "description": "Type of cell output.", |
|
278 | "description": "Type of cell output.", | |
279 | "enum": ["error"] |
|
279 | "enum": ["error"] | |
280 | }, |
|
280 | }, | |
281 | "metadata": {"$ref": "#/definitions/misc/output_metadata"}, |
|
281 | "metadata": {"$ref": "#/definitions/misc/output_metadata"}, | |
282 | "ename": { |
|
282 | "ename": { | |
283 | "description": "The name of the error.", |
|
283 | "description": "The name of the error.", | |
284 | "type": "string" |
|
284 | "type": "string" | |
285 | }, |
|
285 | }, | |
286 | "evalue": { |
|
286 | "evalue": { | |
287 | "description": "The value, or message, of the error.", |
|
287 | "description": "The value, or message, of the error.", | |
288 | "type": "string" |
|
288 | "type": "string" | |
289 | }, |
|
289 | }, | |
290 | "traceback": { |
|
290 | "traceback": { | |
291 | "description": "The error's traceback, represented as an array of strings.", |
|
291 | "description": "The error's traceback, represented as an array of strings.", | |
292 | "type": "array", |
|
292 | "type": "array", | |
293 | "items": {"type": "string"} |
|
293 | "items": {"type": "string"} | |
294 | } |
|
294 | } | |
295 | } |
|
295 | } | |
296 | }, |
|
296 | }, | |
297 |
|
297 | |||
298 | "misc": { |
|
298 | "misc": { | |
299 | "metadata_name": { |
|
299 | "metadata_name": { | |
300 | "description": "The cell's name. If present, must be a non-empty string.", |
|
300 | "description": "The cell's name. If present, must be a non-empty string.", | |
301 | "type": "string", |
|
301 | "type": "string", | |
302 | "pattern": "^.+$" |
|
302 | "pattern": "^.+$" | |
303 | }, |
|
303 | }, | |
304 | "metadata_tags": { |
|
304 | "metadata_tags": { | |
305 | "description": "The cell's tags. Tags must be unique, and must not contain commas.", |
|
305 | "description": "The cell's tags. Tags must be unique, and must not contain commas.", | |
306 | "type": "array", |
|
306 | "type": "array", | |
307 | "uniqueItems": true, |
|
307 | "uniqueItems": true, | |
308 | "items": { |
|
308 | "items": { | |
309 | "type": "string", |
|
309 | "type": "string", | |
310 | "pattern": "^[^,]+$" |
|
310 | "pattern": "^[^,]+$" | |
311 | } |
|
311 | } | |
312 | }, |
|
312 | }, | |
313 | "source": { |
|
313 | "source": { | |
314 | "description": "Contents of the cell, represented as an array of lines.", |
|
314 | "description": "Contents of the cell, represented as an array of lines.", | |
315 | "$ref": "#/definitions/misc/multiline_string" |
|
315 | "$ref": "#/definitions/misc/multiline_string" | |
316 | }, |
|
316 | }, | |
317 |
" |
|
317 | "execution_count": { | |
318 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", |
|
318 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", | |
319 | "type": ["integer", "null"], |
|
319 | "type": ["integer", "null"], | |
320 | "minimum": 0 |
|
320 | "minimum": 0 | |
321 | }, |
|
321 | }, | |
322 | "mimetype": { |
|
322 | "mimetype": { | |
323 | "patternProperties": { |
|
323 | "patternProperties": { | |
324 | "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": { |
|
324 | "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": { | |
325 | "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.", |
|
325 | "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |
326 | "$ref": "#/definitions/misc/multiline_string" |
|
326 | "$ref": "#/definitions/misc/multiline_string" | |
327 | } |
|
327 | } | |
328 | } |
|
328 | } | |
329 | }, |
|
329 | }, | |
330 | "output_metadata": { |
|
330 | "output_metadata": { | |
331 | "description": "Cell output metadata.", |
|
331 | "description": "Cell output metadata.", | |
332 | "type": "object", |
|
332 | "type": "object", | |
333 | "additionalProperties": true |
|
333 | "additionalProperties": true | |
334 | }, |
|
334 | }, | |
335 | "multiline_string": { |
|
335 | "multiline_string": { | |
336 | "oneOf" : [ |
|
336 | "oneOf" : [ | |
337 | {"type": "string"}, |
|
337 | {"type": "string"}, | |
338 | { |
|
338 | { | |
339 | "type": "array", |
|
339 | "type": "array", | |
340 | "items": {"type": "string"} |
|
340 | "items": {"type": "string"} | |
341 | } |
|
341 | } | |
342 | ] |
|
342 | ] | |
343 | } |
|
343 | } | |
344 | } |
|
344 | } | |
345 | } |
|
345 | } | |
346 | } |
|
346 | } |
@@ -1,105 +1,105 | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | import os |
|
3 | import os | |
4 | from base64 import encodestring |
|
4 | from base64 import encodestring | |
5 |
|
5 | |||
6 | from ..nbbase import ( |
|
6 | from ..nbbase import ( | |
7 | new_code_cell, new_heading_cell, new_markdown_cell, new_notebook, |
|
7 | new_code_cell, new_heading_cell, new_markdown_cell, new_notebook, | |
8 | new_output, new_raw_cell |
|
8 | new_output, new_raw_cell | |
9 | ) |
|
9 | ) | |
10 |
|
10 | |||
11 | # some random base64-encoded *text* |
|
11 | # some random base64-encoded *text* | |
12 | png = encodestring(os.urandom(5)).decode('ascii') |
|
12 | png = encodestring(os.urandom(5)).decode('ascii') | |
13 | jpeg = encodestring(os.urandom(6)).decode('ascii') |
|
13 | jpeg = encodestring(os.urandom(6)).decode('ascii') | |
14 |
|
14 | |||
15 | cells = [] |
|
15 | cells = [] | |
16 | cells.append(new_markdown_cell( |
|
16 | cells.append(new_markdown_cell( | |
17 | source='Some NumPy Examples', |
|
17 | source='Some NumPy Examples', | |
18 | )) |
|
18 | )) | |
19 |
|
19 | |||
20 |
|
20 | |||
21 | cells.append(new_code_cell( |
|
21 | cells.append(new_code_cell( | |
22 | source='import numpy', |
|
22 | source='import numpy', | |
23 | prompt_number=1, |
|
23 | execution_count=1, | |
24 | )) |
|
24 | )) | |
25 |
|
25 | |||
26 | cells.append(new_markdown_cell( |
|
26 | cells.append(new_markdown_cell( | |
27 | source='A random array', |
|
27 | source='A random array', | |
28 | )) |
|
28 | )) | |
29 |
|
29 | |||
30 | cells.append(new_raw_cell( |
|
30 | cells.append(new_raw_cell( | |
31 | source='A random array', |
|
31 | source='A random array', | |
32 | )) |
|
32 | )) | |
33 |
|
33 | |||
34 | cells.append(new_heading_cell( |
|
34 | cells.append(new_heading_cell( | |
35 | source=u'My Heading', |
|
35 | source=u'My Heading', | |
36 | level=2, |
|
36 | level=2, | |
37 | )) |
|
37 | )) | |
38 |
|
38 | |||
39 | cells.append(new_code_cell( |
|
39 | cells.append(new_code_cell( | |
40 | source='a = numpy.random.rand(100)', |
|
40 | source='a = numpy.random.rand(100)', | |
41 | prompt_number=2, |
|
41 | execution_count=2, | |
42 | )) |
|
42 | )) | |
43 | cells.append(new_code_cell( |
|
43 | cells.append(new_code_cell( | |
44 | source='a = 10\nb = 5\n', |
|
44 | source='a = 10\nb = 5\n', | |
45 | prompt_number=3, |
|
45 | execution_count=3, | |
46 | )) |
|
46 | )) | |
47 | cells.append(new_code_cell( |
|
47 | cells.append(new_code_cell( | |
48 | source='a = 10\nb = 5', |
|
48 | source='a = 10\nb = 5', | |
49 | prompt_number=4, |
|
49 | execution_count=4, | |
50 | )) |
|
50 | )) | |
51 |
|
51 | |||
52 | cells.append(new_code_cell( |
|
52 | cells.append(new_code_cell( | |
53 | source=u'print "ünîcødé"', |
|
53 | source=u'print "ünîcødé"', | |
54 | prompt_number=3, |
|
54 | execution_count=3, | |
55 | outputs=[new_output( |
|
55 | outputs=[new_output( | |
56 | output_type=u'execute_result', |
|
56 | output_type=u'execute_result', | |
57 | mime_bundle={ |
|
57 | mime_bundle={ | |
58 | 'text/plain': u'<array a>', |
|
58 | 'text/plain': u'<array a>', | |
59 | 'text/html': u'The HTML rep', |
|
59 | 'text/html': u'The HTML rep', | |
60 | 'text/latex': u'$a$', |
|
60 | 'text/latex': u'$a$', | |
61 | 'image/png': png, |
|
61 | 'image/png': png, | |
62 | 'image/jpeg': jpeg, |
|
62 | 'image/jpeg': jpeg, | |
63 | 'image/svg+xml': u'<svg>', |
|
63 | 'image/svg+xml': u'<svg>', | |
64 | 'application/json': { |
|
64 | 'application/json': { | |
65 | 'key': 'value' |
|
65 | 'key': 'value' | |
66 | }, |
|
66 | }, | |
67 | 'application/javascript': u'var i=0;' |
|
67 | 'application/javascript': u'var i=0;' | |
68 | }, |
|
68 | }, | |
69 | prompt_number=3 |
|
69 | execution_count=3 | |
70 | ),new_output( |
|
70 | ),new_output( | |
71 | output_type=u'display_data', |
|
71 | output_type=u'display_data', | |
72 | mime_bundle={ |
|
72 | mime_bundle={ | |
73 | 'text/plain': u'<array a>', |
|
73 | 'text/plain': u'<array a>', | |
74 | 'text/html': u'The HTML rep', |
|
74 | 'text/html': u'The HTML rep', | |
75 | 'text/latex': u'$a$', |
|
75 | 'text/latex': u'$a$', | |
76 | 'image/png': png, |
|
76 | 'image/png': png, | |
77 | 'image/jpeg': jpeg, |
|
77 | 'image/jpeg': jpeg, | |
78 | 'image/svg+xml': u'<svg>', |
|
78 | 'image/svg+xml': u'<svg>', | |
79 | 'application/json': { |
|
79 | 'application/json': { | |
80 | 'key': 'value' |
|
80 | 'key': 'value' | |
81 | }, |
|
81 | }, | |
82 | 'application/javascript': u'var i=0;' |
|
82 | 'application/javascript': u'var i=0;' | |
83 | }, |
|
83 | }, | |
84 | ),new_output( |
|
84 | ),new_output( | |
85 | output_type=u'error', |
|
85 | output_type=u'error', | |
86 | ename=u'NameError', |
|
86 | ename=u'NameError', | |
87 | evalue=u'NameError was here', |
|
87 | evalue=u'NameError was here', | |
88 | traceback=[u'frame 0', u'frame 1', u'frame 2'] |
|
88 | traceback=[u'frame 0', u'frame 1', u'frame 2'] | |
89 | ),new_output( |
|
89 | ),new_output( | |
90 | output_type=u'stream', |
|
90 | output_type=u'stream', | |
91 | text='foo\rbar\r\n' |
|
91 | text='foo\rbar\r\n' | |
92 | ),new_output( |
|
92 | ),new_output( | |
93 | output_type=u'stream', |
|
93 | output_type=u'stream', | |
94 | name='stderr', |
|
94 | name='stderr', | |
95 | text='\rfoo\rbar\n' |
|
95 | text='\rfoo\rbar\n' | |
96 | )] |
|
96 | )] | |
97 | )) |
|
97 | )) | |
98 |
|
98 | |||
99 | nb0 = new_notebook(cells=cells, |
|
99 | nb0 = new_notebook(cells=cells, | |
100 | metadata={ |
|
100 | metadata={ | |
101 | 'language': 'python', |
|
101 | 'language': 'python', | |
102 | } |
|
102 | } | |
103 | ) |
|
103 | ) | |
104 |
|
104 | |||
105 |
|
105 |
@@ -1,112 +1,112 | |||||
1 | # coding: utf-8 |
|
1 | # coding: utf-8 | |
2 | """Tests for the Python API for composing notebook elements""" |
|
2 | """Tests for the Python API for composing notebook elements""" | |
3 |
|
3 | |||
4 | import nose.tools as nt |
|
4 | import nose.tools as nt | |
5 |
|
5 | |||
6 | from IPython.nbformat.validator import isvalid, validate, ValidationError |
|
6 | from IPython.nbformat.validator import isvalid, validate, ValidationError | |
7 | from ..nbbase import ( |
|
7 | from ..nbbase import ( | |
8 | NotebookNode, nbformat, |
|
8 | NotebookNode, nbformat, | |
9 | new_code_cell, new_heading_cell, new_markdown_cell, new_notebook, |
|
9 | new_code_cell, new_heading_cell, new_markdown_cell, new_notebook, | |
10 | new_output, new_raw_cell, |
|
10 | new_output, new_raw_cell, | |
11 | ) |
|
11 | ) | |
12 |
|
12 | |||
13 | def test_empty_notebook(): |
|
13 | def test_empty_notebook(): | |
14 | nb = new_notebook() |
|
14 | nb = new_notebook() | |
15 | nt.assert_equal(nb.cells, []) |
|
15 | nt.assert_equal(nb.cells, []) | |
16 | nt.assert_equal(nb.metadata, NotebookNode()) |
|
16 | nt.assert_equal(nb.metadata, NotebookNode()) | |
17 | nt.assert_equal(nb.nbformat, nbformat) |
|
17 | nt.assert_equal(nb.nbformat, nbformat) | |
18 |
|
18 | |||
19 | def test_empty_markdown_cell(): |
|
19 | def test_empty_markdown_cell(): | |
20 | cell = new_markdown_cell() |
|
20 | cell = new_markdown_cell() | |
21 | nt.assert_equal(cell.cell_type, 'markdown') |
|
21 | nt.assert_equal(cell.cell_type, 'markdown') | |
22 | nt.assert_equal(cell.source, '') |
|
22 | nt.assert_equal(cell.source, '') | |
23 |
|
23 | |||
24 | def test_markdown_cell(): |
|
24 | def test_markdown_cell(): | |
25 | cell = new_markdown_cell(u'* Søme markdown') |
|
25 | cell = new_markdown_cell(u'* Søme markdown') | |
26 | nt.assert_equal(cell.source, u'* Søme markdown') |
|
26 | nt.assert_equal(cell.source, u'* Søme markdown') | |
27 |
|
27 | |||
28 | def test_empty_raw_cell(): |
|
28 | def test_empty_raw_cell(): | |
29 | cell = new_raw_cell() |
|
29 | cell = new_raw_cell() | |
30 | nt.assert_equal(cell.cell_type, u'raw') |
|
30 | nt.assert_equal(cell.cell_type, u'raw') | |
31 | nt.assert_equal(cell.source, '') |
|
31 | nt.assert_equal(cell.source, '') | |
32 |
|
32 | |||
33 | def test_raw_cell(): |
|
33 | def test_raw_cell(): | |
34 | cell = new_raw_cell('hi') |
|
34 | cell = new_raw_cell('hi') | |
35 | nt.assert_equal(cell.source, u'hi') |
|
35 | nt.assert_equal(cell.source, u'hi') | |
36 |
|
36 | |||
37 | def test_empty_heading_cell(): |
|
37 | def test_empty_heading_cell(): | |
38 | cell = new_heading_cell() |
|
38 | cell = new_heading_cell() | |
39 | nt.assert_equal(cell.cell_type, u'heading') |
|
39 | nt.assert_equal(cell.cell_type, u'heading') | |
40 | nt.assert_equal(cell.source, '') |
|
40 | nt.assert_equal(cell.source, '') | |
41 | nt.assert_equal(cell.level, 1) |
|
41 | nt.assert_equal(cell.level, 1) | |
42 |
|
42 | |||
43 | def test_heading_cell(): |
|
43 | def test_heading_cell(): | |
44 | cell = new_heading_cell(u'hi', level=2) |
|
44 | cell = new_heading_cell(u'hi', level=2) | |
45 | nt.assert_equal(cell.source, u'hi') |
|
45 | nt.assert_equal(cell.source, u'hi') | |
46 | nt.assert_equal(cell.level, 2) |
|
46 | nt.assert_equal(cell.level, 2) | |
47 |
|
47 | |||
48 | def test_empty_code_cell(): |
|
48 | def test_empty_code_cell(): | |
49 | cell = new_code_cell('hi') |
|
49 | cell = new_code_cell('hi') | |
50 | nt.assert_equal(cell.cell_type, 'code') |
|
50 | nt.assert_equal(cell.cell_type, 'code') | |
51 | nt.assert_equal(cell.source, u'hi') |
|
51 | nt.assert_equal(cell.source, u'hi') | |
52 |
|
52 | |||
53 | def test_empty_display_data(): |
|
53 | def test_empty_display_data(): | |
54 | output = new_output('display_data') |
|
54 | output = new_output('display_data') | |
55 | nt.assert_equal(output.output_type, 'display_data') |
|
55 | nt.assert_equal(output.output_type, 'display_data') | |
56 |
|
56 | |||
57 | def test_empty_stream(): |
|
57 | def test_empty_stream(): | |
58 | output = new_output('stream') |
|
58 | output = new_output('stream') | |
59 | nt.assert_equal(output.output_type, 'stream') |
|
59 | nt.assert_equal(output.output_type, 'stream') | |
60 | nt.assert_equal(output.name, 'stdout') |
|
60 | nt.assert_equal(output.name, 'stdout') | |
61 | nt.assert_equal(output.text, '') |
|
61 | nt.assert_equal(output.text, '') | |
62 |
|
62 | |||
63 | def test_empty_execute_result(): |
|
63 | def test_empty_execute_result(): | |
64 |
output = new_output('execute_result', |
|
64 | output = new_output('execute_result', execution_count=1) | |
65 | nt.assert_equal(output.output_type, 'execute_result') |
|
65 | nt.assert_equal(output.output_type, 'execute_result') | |
66 |
|
66 | |||
67 | mimebundle = { |
|
67 | mimebundle = { | |
68 | 'text/plain': "some text", |
|
68 | 'text/plain': "some text", | |
69 | "application/json": { |
|
69 | "application/json": { | |
70 | "key": "value" |
|
70 | "key": "value" | |
71 | }, |
|
71 | }, | |
72 | "image/svg+xml": 'ABCDEF', |
|
72 | "image/svg+xml": 'ABCDEF', | |
73 | "application/octet-stream": 'ABC-123', |
|
73 | "application/octet-stream": 'ABC-123', | |
74 | "application/vnd.foo+bar": "Some other stuff", |
|
74 | "application/vnd.foo+bar": "Some other stuff", | |
75 | } |
|
75 | } | |
76 |
|
76 | |||
77 | def test_display_data(): |
|
77 | def test_display_data(): | |
78 | output = new_output('display_data', mimebundle) |
|
78 | output = new_output('display_data', mimebundle) | |
79 | for key, expected in mimebundle.items(): |
|
79 | for key, expected in mimebundle.items(): | |
80 | nt.assert_equal(output[key], expected) |
|
80 | nt.assert_equal(output[key], expected) | |
81 |
|
81 | |||
82 | def test_execute_result(): |
|
82 | def test_execute_result(): | |
83 |
output = new_output('execute_result', mimebundle, |
|
83 | output = new_output('execute_result', mimebundle, execution_count=10) | |
84 |
nt.assert_equal(output. |
|
84 | nt.assert_equal(output.execution_count, 10) | |
85 | for key, expected in mimebundle.items(): |
|
85 | for key, expected in mimebundle.items(): | |
86 | nt.assert_equal(output[key], expected) |
|
86 | nt.assert_equal(output[key], expected) | |
87 |
|
87 | |||
88 | def test_error(): |
|
88 | def test_error(): | |
89 | o = new_output(output_type=u'error', ename=u'NameError', |
|
89 | o = new_output(output_type=u'error', ename=u'NameError', | |
90 | evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] |
|
90 | evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] | |
91 | ) |
|
91 | ) | |
92 | nt.assert_equal(o.output_type, u'error') |
|
92 | nt.assert_equal(o.output_type, u'error') | |
93 | nt.assert_equal(o.ename, u'NameError') |
|
93 | nt.assert_equal(o.ename, u'NameError') | |
94 | nt.assert_equal(o.evalue, u'Name not found') |
|
94 | nt.assert_equal(o.evalue, u'Name not found') | |
95 | nt.assert_equal(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) |
|
95 | nt.assert_equal(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) | |
96 |
|
96 | |||
97 | def test_code_cell_with_outputs(): |
|
97 | def test_code_cell_with_outputs(): | |
98 |
cell = new_code_cell( |
|
98 | cell = new_code_cell(execution_count=10, outputs=[ | |
99 | new_output('display_data', mimebundle), |
|
99 | new_output('display_data', mimebundle), | |
100 | new_output('stream', text='hello'), |
|
100 | new_output('stream', text='hello'), | |
101 |
new_output('execute_result', mimebundle, |
|
101 | new_output('execute_result', mimebundle, execution_count=10), | |
102 | ]) |
|
102 | ]) | |
103 |
nt.assert_equal(cell. |
|
103 | nt.assert_equal(cell.execution_count, 10) | |
104 | nt.assert_equal(len(cell.outputs), 3) |
|
104 | nt.assert_equal(len(cell.outputs), 3) | |
105 | er = cell.outputs[-1] |
|
105 | er = cell.outputs[-1] | |
106 |
nt.assert_equal(er. |
|
106 | nt.assert_equal(er.execution_count, 10) | |
107 | nt.assert_equal(er['output_type'], 'execute_result') |
|
107 | nt.assert_equal(er['output_type'], 'execute_result') | |
108 |
|
108 | |||
109 | def test_stream(): |
|
109 | def test_stream(): | |
110 | output = new_output('stream', name='stderr', text='hello there') |
|
110 | output = new_output('stream', name='stderr', text='hello there') | |
111 | nt.assert_equal(output.name, 'stderr') |
|
111 | nt.assert_equal(output.name, 'stderr') | |
112 | nt.assert_equal(output.text, 'hello there') |
|
112 | nt.assert_equal(output.text, 'hello there') |
General Comments 0
You need to be logged in to leave comments.
Login now