##// END OF EJS Templates
Merge pull request #3186 from maximsch2/fix_etype_ename...
Min RK -
r10271:9456b7ca merge
parent child Browse files
Show More
@@ -1,209 +1,209 b''
1 """The basic dict based notebook format.
1 """The basic dict based notebook format.
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 Authors:
8 Authors:
9
9
10 * Brian Granger
10 * Brian Granger
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import pprint
24 import pprint
25 import uuid
25 import uuid
26
26
27 from IPython.utils.ipstruct import Struct
27 from IPython.utils.ipstruct import Struct
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Code
30 # Code
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # Change this when incrementing the nbformat version
33 # Change this when incrementing the nbformat version
34 nbformat = 3
34 nbformat = 3
35 nbformat_minor = 0
35 nbformat_minor = 0
36
36
37 class NotebookNode(Struct):
37 class NotebookNode(Struct):
38 pass
38 pass
39
39
40
40
41 def from_dict(d):
41 def from_dict(d):
42 if isinstance(d, dict):
42 if isinstance(d, dict):
43 newd = NotebookNode()
43 newd = NotebookNode()
44 for k,v in d.items():
44 for k,v in d.items():
45 newd[k] = from_dict(v)
45 newd[k] = from_dict(v)
46 return newd
46 return newd
47 elif isinstance(d, (tuple, list)):
47 elif isinstance(d, (tuple, list)):
48 return [from_dict(i) for i in d]
48 return [from_dict(i) for i in d]
49 else:
49 else:
50 return d
50 return d
51
51
52
52
53 def new_output(output_type=None, output_text=None, output_png=None,
53 def new_output(output_type=None, output_text=None, output_png=None,
54 output_html=None, output_svg=None, output_latex=None, output_json=None,
54 output_html=None, output_svg=None, output_latex=None, output_json=None,
55 output_javascript=None, output_jpeg=None, prompt_number=None,
55 output_javascript=None, output_jpeg=None, prompt_number=None,
56 etype=None, evalue=None, traceback=None, stream=None):
56 ename=None, evalue=None, traceback=None, stream=None):
57 """Create a new code cell with input and output"""
57 """Create a new code cell with input and output"""
58 output = NotebookNode()
58 output = NotebookNode()
59 if output_type is not None:
59 if output_type is not None:
60 output.output_type = unicode(output_type)
60 output.output_type = unicode(output_type)
61
61
62 if output_type != 'pyerr':
62 if output_type != 'pyerr':
63 if output_text is not None:
63 if output_text is not None:
64 output.text = unicode(output_text)
64 output.text = unicode(output_text)
65 if output_png is not None:
65 if output_png is not None:
66 output.png = bytes(output_png)
66 output.png = bytes(output_png)
67 if output_jpeg is not None:
67 if output_jpeg is not None:
68 output.jpeg = bytes(output_jpeg)
68 output.jpeg = bytes(output_jpeg)
69 if output_html is not None:
69 if output_html is not None:
70 output.html = unicode(output_html)
70 output.html = unicode(output_html)
71 if output_svg is not None:
71 if output_svg is not None:
72 output.svg = unicode(output_svg)
72 output.svg = unicode(output_svg)
73 if output_latex is not None:
73 if output_latex is not None:
74 output.latex = unicode(output_latex)
74 output.latex = unicode(output_latex)
75 if output_json is not None:
75 if output_json is not None:
76 output.json = unicode(output_json)
76 output.json = unicode(output_json)
77 if output_javascript is not None:
77 if output_javascript is not None:
78 output.javascript = unicode(output_javascript)
78 output.javascript = unicode(output_javascript)
79
79
80 if output_type == u'pyout':
80 if output_type == u'pyout':
81 if prompt_number is not None:
81 if prompt_number is not None:
82 output.prompt_number = int(prompt_number)
82 output.prompt_number = int(prompt_number)
83
83
84 if output_type == u'pyerr':
84 if output_type == u'pyerr':
85 if etype is not None:
85 if ename is not None:
86 output.etype = unicode(etype)
86 output.ename = unicode(ename)
87 if evalue is not None:
87 if evalue is not None:
88 output.evalue = unicode(evalue)
88 output.evalue = unicode(evalue)
89 if traceback is not None:
89 if traceback is not None:
90 output.traceback = [unicode(frame) for frame in list(traceback)]
90 output.traceback = [unicode(frame) for frame in list(traceback)]
91
91
92 if output_type == u'stream':
92 if output_type == u'stream':
93 output.stream = 'stdout' if stream is None else unicode(stream)
93 output.stream = 'stdout' if stream is None else unicode(stream)
94
94
95 return output
95 return output
96
96
97
97
98 def new_code_cell(input=None, prompt_number=None, outputs=None,
98 def new_code_cell(input=None, prompt_number=None, outputs=None,
99 language=u'python', collapsed=False, metadata=None):
99 language=u'python', collapsed=False, metadata=None):
100 """Create a new code cell with input and output"""
100 """Create a new code cell with input and output"""
101 cell = NotebookNode()
101 cell = NotebookNode()
102 cell.cell_type = u'code'
102 cell.cell_type = u'code'
103 if language is not None:
103 if language is not None:
104 cell.language = unicode(language)
104 cell.language = unicode(language)
105 if input is not None:
105 if input is not None:
106 cell.input = unicode(input)
106 cell.input = unicode(input)
107 if prompt_number is not None:
107 if prompt_number is not None:
108 cell.prompt_number = int(prompt_number)
108 cell.prompt_number = int(prompt_number)
109 if outputs is None:
109 if outputs is None:
110 cell.outputs = []
110 cell.outputs = []
111 else:
111 else:
112 cell.outputs = outputs
112 cell.outputs = outputs
113 if collapsed is not None:
113 if collapsed is not None:
114 cell.collapsed = bool(collapsed)
114 cell.collapsed = bool(collapsed)
115 cell.metadata = NotebookNode(metadata or {})
115 cell.metadata = NotebookNode(metadata or {})
116
116
117 return cell
117 return cell
118
118
119 def new_text_cell(cell_type, source=None, rendered=None, metadata=None):
119 def new_text_cell(cell_type, source=None, rendered=None, metadata=None):
120 """Create a new text cell."""
120 """Create a new text cell."""
121 cell = NotebookNode()
121 cell = NotebookNode()
122 # VERSIONHACK: plaintext -> raw
122 # VERSIONHACK: plaintext -> raw
123 # handle never-released plaintext name for raw cells
123 # handle never-released plaintext name for raw cells
124 if cell_type == 'plaintext':
124 if cell_type == 'plaintext':
125 cell_type = 'raw'
125 cell_type = 'raw'
126 if source is not None:
126 if source is not None:
127 cell.source = unicode(source)
127 cell.source = unicode(source)
128 if rendered is not None:
128 if rendered is not None:
129 cell.rendered = unicode(rendered)
129 cell.rendered = unicode(rendered)
130 cell.metadata = NotebookNode(metadata or {})
130 cell.metadata = NotebookNode(metadata or {})
131 cell.cell_type = cell_type
131 cell.cell_type = cell_type
132 return cell
132 return cell
133
133
134
134
135 def new_heading_cell(source=None, rendered=None, level=1, metadata=None):
135 def new_heading_cell(source=None, rendered=None, level=1, metadata=None):
136 """Create a new section cell with a given integer level."""
136 """Create a new section cell with a given integer level."""
137 cell = NotebookNode()
137 cell = NotebookNode()
138 cell.cell_type = u'heading'
138 cell.cell_type = u'heading'
139 if source is not None:
139 if source is not None:
140 cell.source = unicode(source)
140 cell.source = unicode(source)
141 if rendered is not None:
141 if rendered is not None:
142 cell.rendered = unicode(rendered)
142 cell.rendered = unicode(rendered)
143 cell.level = int(level)
143 cell.level = int(level)
144 cell.metadata = NotebookNode(metadata or {})
144 cell.metadata = NotebookNode(metadata or {})
145 return cell
145 return cell
146
146
147
147
148 def new_worksheet(name=None, cells=None, metadata=None):
148 def new_worksheet(name=None, cells=None, metadata=None):
149 """Create a worksheet by name with with a list of cells."""
149 """Create a worksheet by name with with a list of cells."""
150 ws = NotebookNode()
150 ws = NotebookNode()
151 if name is not None:
151 if name is not None:
152 ws.name = unicode(name)
152 ws.name = unicode(name)
153 if cells is None:
153 if cells is None:
154 ws.cells = []
154 ws.cells = []
155 else:
155 else:
156 ws.cells = list(cells)
156 ws.cells = list(cells)
157 ws.metadata = NotebookNode(metadata or {})
157 ws.metadata = NotebookNode(metadata or {})
158 return ws
158 return ws
159
159
160
160
161 def new_notebook(name=None, metadata=None, worksheets=None):
161 def new_notebook(name=None, metadata=None, worksheets=None):
162 """Create a notebook by name, id and a list of worksheets."""
162 """Create a notebook by name, id and a list of worksheets."""
163 nb = NotebookNode()
163 nb = NotebookNode()
164 nb.nbformat = nbformat
164 nb.nbformat = nbformat
165 nb.nbformat_minor = nbformat_minor
165 nb.nbformat_minor = nbformat_minor
166 if worksheets is None:
166 if worksheets is None:
167 nb.worksheets = []
167 nb.worksheets = []
168 else:
168 else:
169 nb.worksheets = list(worksheets)
169 nb.worksheets = list(worksheets)
170 if metadata is None:
170 if metadata is None:
171 nb.metadata = new_metadata()
171 nb.metadata = new_metadata()
172 else:
172 else:
173 nb.metadata = NotebookNode(metadata)
173 nb.metadata = NotebookNode(metadata)
174 if name is not None:
174 if name is not None:
175 nb.metadata.name = unicode(name)
175 nb.metadata.name = unicode(name)
176 return nb
176 return nb
177
177
178
178
179 def new_metadata(name=None, authors=None, license=None, created=None,
179 def new_metadata(name=None, authors=None, license=None, created=None,
180 modified=None, gistid=None):
180 modified=None, gistid=None):
181 """Create a new metadata node."""
181 """Create a new metadata node."""
182 metadata = NotebookNode()
182 metadata = NotebookNode()
183 if name is not None:
183 if name is not None:
184 metadata.name = unicode(name)
184 metadata.name = unicode(name)
185 if authors is not None:
185 if authors is not None:
186 metadata.authors = list(authors)
186 metadata.authors = list(authors)
187 if created is not None:
187 if created is not None:
188 metadata.created = unicode(created)
188 metadata.created = unicode(created)
189 if modified is not None:
189 if modified is not None:
190 metadata.modified = unicode(modified)
190 metadata.modified = unicode(modified)
191 if license is not None:
191 if license is not None:
192 metadata.license = unicode(license)
192 metadata.license = unicode(license)
193 if gistid is not None:
193 if gistid is not None:
194 metadata.gistid = unicode(gistid)
194 metadata.gistid = unicode(gistid)
195 return metadata
195 return metadata
196
196
197 def new_author(name=None, email=None, affiliation=None, url=None):
197 def new_author(name=None, email=None, affiliation=None, url=None):
198 """Create a new author."""
198 """Create a new author."""
199 author = NotebookNode()
199 author = NotebookNode()
200 if name is not None:
200 if name is not None:
201 author.name = unicode(name)
201 author.name = unicode(name)
202 if email is not None:
202 if email is not None:
203 author.email = unicode(email)
203 author.email = unicode(email)
204 if affiliation is not None:
204 if affiliation is not None:
205 author.affiliation = unicode(affiliation)
205 author.affiliation = unicode(affiliation)
206 if url is not None:
206 if url is not None:
207 author.url = unicode(url)
207 author.url = unicode(url)
208 return author
208 return author
209
209
@@ -1,154 +1,154 b''
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 NotebookNode,
7 NotebookNode,
8 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
8 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
9 new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor
9 new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor
10 )
10 )
11
11
12 # some random base64-encoded *bytes*
12 # some random base64-encoded *bytes*
13 png = encodestring(os.urandom(5))
13 png = encodestring(os.urandom(5))
14 jpeg = encodestring(os.urandom(6))
14 jpeg = encodestring(os.urandom(6))
15
15
16 ws = new_worksheet(name='worksheet1')
16 ws = new_worksheet(name='worksheet1')
17
17
18 ws.cells.append(new_text_cell(
18 ws.cells.append(new_text_cell(
19 u'html',
19 u'html',
20 source='Some NumPy Examples',
20 source='Some NumPy Examples',
21 rendered='Some NumPy Examples'
21 rendered='Some NumPy Examples'
22 ))
22 ))
23
23
24
24
25 ws.cells.append(new_code_cell(
25 ws.cells.append(new_code_cell(
26 input='import numpy',
26 input='import numpy',
27 prompt_number=1,
27 prompt_number=1,
28 collapsed=False
28 collapsed=False
29 ))
29 ))
30
30
31 ws.cells.append(new_text_cell(
31 ws.cells.append(new_text_cell(
32 u'markdown',
32 u'markdown',
33 source='A random array',
33 source='A random array',
34 rendered='A random array'
34 rendered='A random array'
35 ))
35 ))
36
36
37 ws.cells.append(new_text_cell(
37 ws.cells.append(new_text_cell(
38 u'raw',
38 u'raw',
39 source='A random array',
39 source='A random array',
40 ))
40 ))
41
41
42 ws.cells.append(new_heading_cell(
42 ws.cells.append(new_heading_cell(
43 u'My Heading',
43 u'My Heading',
44 level=2
44 level=2
45 ))
45 ))
46
46
47 ws.cells.append(new_code_cell(
47 ws.cells.append(new_code_cell(
48 input='a = numpy.random.rand(100)',
48 input='a = numpy.random.rand(100)',
49 prompt_number=2,
49 prompt_number=2,
50 collapsed=True
50 collapsed=True
51 ))
51 ))
52 ws.cells.append(new_code_cell(
52 ws.cells.append(new_code_cell(
53 input='a = 10\nb = 5\n',
53 input='a = 10\nb = 5\n',
54 prompt_number=3,
54 prompt_number=3,
55 ))
55 ))
56 ws.cells.append(new_code_cell(
56 ws.cells.append(new_code_cell(
57 input='a = 10\nb = 5',
57 input='a = 10\nb = 5',
58 prompt_number=4,
58 prompt_number=4,
59 ))
59 ))
60
60
61 ws.cells.append(new_code_cell(
61 ws.cells.append(new_code_cell(
62 input=u'print "ünîcødé"',
62 input=u'print "ünîcødé"',
63 prompt_number=3,
63 prompt_number=3,
64 collapsed=False,
64 collapsed=False,
65 outputs=[new_output(
65 outputs=[new_output(
66 output_type=u'pyout',
66 output_type=u'pyout',
67 output_text=u'<array a>',
67 output_text=u'<array a>',
68 output_html=u'The HTML rep',
68 output_html=u'The HTML rep',
69 output_latex=u'$a$',
69 output_latex=u'$a$',
70 output_png=png,
70 output_png=png,
71 output_jpeg=jpeg,
71 output_jpeg=jpeg,
72 output_svg=u'<svg>',
72 output_svg=u'<svg>',
73 output_json=u'json data',
73 output_json=u'json data',
74 output_javascript=u'var i=0;',
74 output_javascript=u'var i=0;',
75 prompt_number=3
75 prompt_number=3
76 ),new_output(
76 ),new_output(
77 output_type=u'display_data',
77 output_type=u'display_data',
78 output_text=u'<array a>',
78 output_text=u'<array a>',
79 output_html=u'The HTML rep',
79 output_html=u'The HTML rep',
80 output_latex=u'$a$',
80 output_latex=u'$a$',
81 output_png=png,
81 output_png=png,
82 output_jpeg=jpeg,
82 output_jpeg=jpeg,
83 output_svg=u'<svg>',
83 output_svg=u'<svg>',
84 output_json=u'json data',
84 output_json=u'json data',
85 output_javascript=u'var i=0;'
85 output_javascript=u'var i=0;'
86 ),new_output(
86 ),new_output(
87 output_type=u'pyerr',
87 output_type=u'pyerr',
88 etype=u'NameError',
88 ename=u'NameError',
89 evalue=u'NameError was here',
89 evalue=u'NameError was here',
90 traceback=[u'frame 0', u'frame 1', u'frame 2']
90 traceback=[u'frame 0', u'frame 1', u'frame 2']
91 ),new_output(
91 ),new_output(
92 output_type=u'stream',
92 output_type=u'stream',
93 output_text='foo\rbar\r\n'
93 output_text='foo\rbar\r\n'
94 ),new_output(
94 ),new_output(
95 output_type=u'stream',
95 output_type=u'stream',
96 stream='stderr',
96 stream='stderr',
97 output_text='\rfoo\rbar\n'
97 output_text='\rfoo\rbar\n'
98 )]
98 )]
99 ))
99 ))
100
100
101 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com',
101 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com',
102 affiliation=u'Fox',url=u'http://www.fox.com')]
102 affiliation=u'Fox',url=u'http://www.fox.com')]
103 md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here',
103 md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here',
104 modified=u'8601_goes_here',gistid=u'21341231',authors=authors)
104 modified=u'8601_goes_here',gistid=u'21341231',authors=authors)
105
105
106 nb0 = new_notebook(
106 nb0 = new_notebook(
107 worksheets=[ws, new_worksheet(name='worksheet2')],
107 worksheets=[ws, new_worksheet(name='worksheet2')],
108 metadata=md
108 metadata=md
109 )
109 )
110
110
111 nb0_py = u"""# -*- coding: utf-8 -*-
111 nb0_py = u"""# -*- coding: utf-8 -*-
112 # <nbformat>%i.%i</nbformat>
112 # <nbformat>%i.%i</nbformat>
113
113
114 # <htmlcell>
114 # <htmlcell>
115
115
116 # Some NumPy Examples
116 # Some NumPy Examples
117
117
118 # <codecell>
118 # <codecell>
119
119
120 import numpy
120 import numpy
121
121
122 # <markdowncell>
122 # <markdowncell>
123
123
124 # A random array
124 # A random array
125
125
126 # <rawcell>
126 # <rawcell>
127
127
128 # A random array
128 # A random array
129
129
130 # <headingcell level=2>
130 # <headingcell level=2>
131
131
132 # My Heading
132 # My Heading
133
133
134 # <codecell>
134 # <codecell>
135
135
136 a = numpy.random.rand(100)
136 a = numpy.random.rand(100)
137
137
138 # <codecell>
138 # <codecell>
139
139
140 a = 10
140 a = 10
141 b = 5
141 b = 5
142
142
143 # <codecell>
143 # <codecell>
144
144
145 a = 10
145 a = 10
146 b = 5
146 b = 5
147
147
148 # <codecell>
148 # <codecell>
149
149
150 print "ünîcødé"
150 print "ünîcødé"
151
151
152 """ % (nbformat, nbformat_minor)
152 """ % (nbformat, nbformat_minor)
153
153
154
154
@@ -1,143 +1,143 b''
1 from unittest import TestCase
1 from unittest import TestCase
2
2
3 from ..nbbase import (
3 from ..nbbase import (
4 NotebookNode,
4 NotebookNode,
5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
6 new_author, new_metadata, new_heading_cell, nbformat
6 new_author, new_metadata, new_heading_cell, nbformat
7 )
7 )
8
8
9 class TestCell(TestCase):
9 class TestCell(TestCase):
10
10
11 def test_empty_code_cell(self):
11 def test_empty_code_cell(self):
12 cc = new_code_cell()
12 cc = new_code_cell()
13 self.assertEqual(cc.cell_type,u'code')
13 self.assertEqual(cc.cell_type,u'code')
14 self.assertEqual(u'input' not in cc, True)
14 self.assertEqual(u'input' not in cc, True)
15 self.assertEqual(u'prompt_number' not in cc, True)
15 self.assertEqual(u'prompt_number' not in cc, True)
16 self.assertEqual(cc.outputs, [])
16 self.assertEqual(cc.outputs, [])
17 self.assertEqual(cc.collapsed, False)
17 self.assertEqual(cc.collapsed, False)
18
18
19 def test_code_cell(self):
19 def test_code_cell(self):
20 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
20 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
21 cc.outputs = [new_output(output_type=u'pyout',
21 cc.outputs = [new_output(output_type=u'pyout',
22 output_svg=u'foo',output_text=u'10',prompt_number=0)]
22 output_svg=u'foo',output_text=u'10',prompt_number=0)]
23 self.assertEqual(cc.input, u'a=10')
23 self.assertEqual(cc.input, u'a=10')
24 self.assertEqual(cc.prompt_number, 0)
24 self.assertEqual(cc.prompt_number, 0)
25 self.assertEqual(cc.language, u'python')
25 self.assertEqual(cc.language, u'python')
26 self.assertEqual(cc.outputs[0].svg, u'foo')
26 self.assertEqual(cc.outputs[0].svg, u'foo')
27 self.assertEqual(cc.outputs[0].text, u'10')
27 self.assertEqual(cc.outputs[0].text, u'10')
28 self.assertEqual(cc.outputs[0].prompt_number, 0)
28 self.assertEqual(cc.outputs[0].prompt_number, 0)
29 self.assertEqual(cc.collapsed, True)
29 self.assertEqual(cc.collapsed, True)
30
30
31 def test_pyerr(self):
31 def test_pyerr(self):
32 o = new_output(output_type=u'pyerr', etype=u'NameError',
32 o = new_output(output_type=u'pyerr', ename=u'NameError',
33 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
33 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
34 )
34 )
35 self.assertEqual(o.output_type, u'pyerr')
35 self.assertEqual(o.output_type, u'pyerr')
36 self.assertEqual(o.etype, u'NameError')
36 self.assertEqual(o.ename, u'NameError')
37 self.assertEqual(o.evalue, u'Name not found')
37 self.assertEqual(o.evalue, u'Name not found')
38 self.assertEqual(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
38 self.assertEqual(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
39
39
40 def test_empty_html_cell(self):
40 def test_empty_html_cell(self):
41 tc = new_text_cell(u'html')
41 tc = new_text_cell(u'html')
42 self.assertEqual(tc.cell_type, u'html')
42 self.assertEqual(tc.cell_type, u'html')
43 self.assertEqual(u'source' not in tc, True)
43 self.assertEqual(u'source' not in tc, True)
44 self.assertEqual(u'rendered' not in tc, True)
44 self.assertEqual(u'rendered' not in tc, True)
45
45
46 def test_html_cell(self):
46 def test_html_cell(self):
47 tc = new_text_cell(u'html', 'hi', 'hi')
47 tc = new_text_cell(u'html', 'hi', 'hi')
48 self.assertEqual(tc.source, u'hi')
48 self.assertEqual(tc.source, u'hi')
49 self.assertEqual(tc.rendered, u'hi')
49 self.assertEqual(tc.rendered, u'hi')
50
50
51 def test_empty_markdown_cell(self):
51 def test_empty_markdown_cell(self):
52 tc = new_text_cell(u'markdown')
52 tc = new_text_cell(u'markdown')
53 self.assertEqual(tc.cell_type, u'markdown')
53 self.assertEqual(tc.cell_type, u'markdown')
54 self.assertEqual(u'source' not in tc, True)
54 self.assertEqual(u'source' not in tc, True)
55 self.assertEqual(u'rendered' not in tc, True)
55 self.assertEqual(u'rendered' not in tc, True)
56
56
57 def test_markdown_cell(self):
57 def test_markdown_cell(self):
58 tc = new_text_cell(u'markdown', 'hi', 'hi')
58 tc = new_text_cell(u'markdown', 'hi', 'hi')
59 self.assertEqual(tc.source, u'hi')
59 self.assertEqual(tc.source, u'hi')
60 self.assertEqual(tc.rendered, u'hi')
60 self.assertEqual(tc.rendered, u'hi')
61
61
62 def test_empty_raw_cell(self):
62 def test_empty_raw_cell(self):
63 tc = new_text_cell(u'raw')
63 tc = new_text_cell(u'raw')
64 self.assertEqual(tc.cell_type, u'raw')
64 self.assertEqual(tc.cell_type, u'raw')
65 self.assertEqual(u'source' not in tc, True)
65 self.assertEqual(u'source' not in tc, True)
66 self.assertEqual(u'rendered' not in tc, True)
66 self.assertEqual(u'rendered' not in tc, True)
67
67
68 def test_raw_cell(self):
68 def test_raw_cell(self):
69 tc = new_text_cell(u'raw', 'hi', 'hi')
69 tc = new_text_cell(u'raw', 'hi', 'hi')
70 self.assertEqual(tc.source, u'hi')
70 self.assertEqual(tc.source, u'hi')
71 self.assertEqual(tc.rendered, u'hi')
71 self.assertEqual(tc.rendered, u'hi')
72
72
73 def test_empty_heading_cell(self):
73 def test_empty_heading_cell(self):
74 tc = new_heading_cell()
74 tc = new_heading_cell()
75 self.assertEqual(tc.cell_type, u'heading')
75 self.assertEqual(tc.cell_type, u'heading')
76 self.assertEqual(u'source' not in tc, True)
76 self.assertEqual(u'source' not in tc, True)
77 self.assertEqual(u'rendered' not in tc, True)
77 self.assertEqual(u'rendered' not in tc, True)
78
78
79 def test_heading_cell(self):
79 def test_heading_cell(self):
80 tc = new_heading_cell(u'hi', u'hi', level=2)
80 tc = new_heading_cell(u'hi', u'hi', level=2)
81 self.assertEqual(tc.source, u'hi')
81 self.assertEqual(tc.source, u'hi')
82 self.assertEqual(tc.rendered, u'hi')
82 self.assertEqual(tc.rendered, u'hi')
83 self.assertEqual(tc.level, 2)
83 self.assertEqual(tc.level, 2)
84
84
85
85
86 class TestWorksheet(TestCase):
86 class TestWorksheet(TestCase):
87
87
88 def test_empty_worksheet(self):
88 def test_empty_worksheet(self):
89 ws = new_worksheet()
89 ws = new_worksheet()
90 self.assertEqual(ws.cells,[])
90 self.assertEqual(ws.cells,[])
91 self.assertEqual(u'name' not in ws, True)
91 self.assertEqual(u'name' not in ws, True)
92
92
93 def test_worksheet(self):
93 def test_worksheet(self):
94 cells = [new_code_cell(), new_text_cell(u'html')]
94 cells = [new_code_cell(), new_text_cell(u'html')]
95 ws = new_worksheet(cells=cells,name=u'foo')
95 ws = new_worksheet(cells=cells,name=u'foo')
96 self.assertEqual(ws.cells,cells)
96 self.assertEqual(ws.cells,cells)
97 self.assertEqual(ws.name,u'foo')
97 self.assertEqual(ws.name,u'foo')
98
98
99 class TestNotebook(TestCase):
99 class TestNotebook(TestCase):
100
100
101 def test_empty_notebook(self):
101 def test_empty_notebook(self):
102 nb = new_notebook()
102 nb = new_notebook()
103 self.assertEqual(nb.worksheets, [])
103 self.assertEqual(nb.worksheets, [])
104 self.assertEqual(nb.metadata, NotebookNode())
104 self.assertEqual(nb.metadata, NotebookNode())
105 self.assertEqual(nb.nbformat,nbformat)
105 self.assertEqual(nb.nbformat,nbformat)
106
106
107 def test_notebook(self):
107 def test_notebook(self):
108 worksheets = [new_worksheet(),new_worksheet()]
108 worksheets = [new_worksheet(),new_worksheet()]
109 metadata = new_metadata(name=u'foo')
109 metadata = new_metadata(name=u'foo')
110 nb = new_notebook(metadata=metadata,worksheets=worksheets)
110 nb = new_notebook(metadata=metadata,worksheets=worksheets)
111 self.assertEqual(nb.metadata.name,u'foo')
111 self.assertEqual(nb.metadata.name,u'foo')
112 self.assertEqual(nb.worksheets,worksheets)
112 self.assertEqual(nb.worksheets,worksheets)
113 self.assertEqual(nb.nbformat,nbformat)
113 self.assertEqual(nb.nbformat,nbformat)
114
114
115 def test_notebook_name(self):
115 def test_notebook_name(self):
116 worksheets = [new_worksheet(),new_worksheet()]
116 worksheets = [new_worksheet(),new_worksheet()]
117 nb = new_notebook(name='foo',worksheets=worksheets)
117 nb = new_notebook(name='foo',worksheets=worksheets)
118 self.assertEqual(nb.metadata.name,u'foo')
118 self.assertEqual(nb.metadata.name,u'foo')
119 self.assertEqual(nb.worksheets,worksheets)
119 self.assertEqual(nb.worksheets,worksheets)
120 self.assertEqual(nb.nbformat,nbformat)
120 self.assertEqual(nb.nbformat,nbformat)
121
121
122 class TestMetadata(TestCase):
122 class TestMetadata(TestCase):
123
123
124 def test_empty_metadata(self):
124 def test_empty_metadata(self):
125 md = new_metadata()
125 md = new_metadata()
126 self.assertEqual(u'name' not in md, True)
126 self.assertEqual(u'name' not in md, True)
127 self.assertEqual(u'authors' not in md, True)
127 self.assertEqual(u'authors' not in md, True)
128 self.assertEqual(u'license' not in md, True)
128 self.assertEqual(u'license' not in md, True)
129 self.assertEqual(u'saved' not in md, True)
129 self.assertEqual(u'saved' not in md, True)
130 self.assertEqual(u'modified' not in md, True)
130 self.assertEqual(u'modified' not in md, True)
131 self.assertEqual(u'gistid' not in md, True)
131 self.assertEqual(u'gistid' not in md, True)
132
132
133 def test_metadata(self):
133 def test_metadata(self):
134 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')]
134 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')]
135 md = new_metadata(name=u'foo',license=u'BSD',created=u'today',
135 md = new_metadata(name=u'foo',license=u'BSD',created=u'today',
136 modified=u'now',gistid=u'21341231',authors=authors)
136 modified=u'now',gistid=u'21341231',authors=authors)
137 self.assertEqual(md.name, u'foo')
137 self.assertEqual(md.name, u'foo')
138 self.assertEqual(md.license, u'BSD')
138 self.assertEqual(md.license, u'BSD')
139 self.assertEqual(md.created, u'today')
139 self.assertEqual(md.created, u'today')
140 self.assertEqual(md.modified, u'now')
140 self.assertEqual(md.modified, u'now')
141 self.assertEqual(md.gistid, u'21341231')
141 self.assertEqual(md.gistid, u'21341231')
142 self.assertEqual(md.authors, authors)
142 self.assertEqual(md.authors, authors)
143
143
@@ -1,1050 +1,1050 b''
1 .. _messaging:
1 .. _messaging:
2
2
3 ======================
3 ======================
4 Messaging in IPython
4 Messaging in IPython
5 ======================
5 ======================
6
6
7
7
8 Introduction
8 Introduction
9 ============
9 ============
10
10
11 This document explains the basic communications design and messaging
11 This document explains the basic communications design and messaging
12 specification for how the various IPython objects interact over a network
12 specification for how the various IPython objects interact over a network
13 transport. The current implementation uses the ZeroMQ_ library for messaging
13 transport. The current implementation uses the ZeroMQ_ library for messaging
14 within and between hosts.
14 within and between hosts.
15
15
16 .. Note::
16 .. Note::
17
17
18 This document should be considered the authoritative description of the
18 This document should be considered the authoritative description of the
19 IPython messaging protocol, and all developers are strongly encouraged to
19 IPython messaging protocol, and all developers are strongly encouraged to
20 keep it updated as the implementation evolves, so that we have a single
20 keep it updated as the implementation evolves, so that we have a single
21 common reference for all protocol details.
21 common reference for all protocol details.
22
22
23 The basic design is explained in the following diagram:
23 The basic design is explained in the following diagram:
24
24
25 .. image:: figs/frontend-kernel.png
25 .. image:: figs/frontend-kernel.png
26 :width: 450px
26 :width: 450px
27 :alt: IPython kernel/frontend messaging architecture.
27 :alt: IPython kernel/frontend messaging architecture.
28 :align: center
28 :align: center
29 :target: ../_images/frontend-kernel.png
29 :target: ../_images/frontend-kernel.png
30
30
31 A single kernel can be simultaneously connected to one or more frontends. The
31 A single kernel can be simultaneously connected to one or more frontends. The
32 kernel has three sockets that serve the following functions:
32 kernel has three sockets that serve the following functions:
33
33
34 1. stdin: this ROUTER socket is connected to all frontends, and it allows
34 1. stdin: this ROUTER socket is connected to all frontends, and it allows
35 the kernel to request input from the active frontend when :func:`raw_input` is called.
35 the kernel to request input from the active frontend when :func:`raw_input` is called.
36 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
36 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
37 for the kernel while this communication is happening (illustrated in the
37 for the kernel while this communication is happening (illustrated in the
38 figure by the black outline around the central keyboard). In practice,
38 figure by the black outline around the central keyboard). In practice,
39 frontends may display such kernel requests using a special input widget or
39 frontends may display such kernel requests using a special input widget or
40 otherwise indicating that the user is to type input for the kernel instead
40 otherwise indicating that the user is to type input for the kernel instead
41 of normal commands in the frontend.
41 of normal commands in the frontend.
42
42
43 2. Shell: this single ROUTER socket allows multiple incoming connections from
43 2. Shell: this single ROUTER socket allows multiple incoming connections from
44 frontends, and this is the socket where requests for code execution, object
44 frontends, and this is the socket where requests for code execution, object
45 information, prompts, etc. are made to the kernel by any frontend. The
45 information, prompts, etc. are made to the kernel by any frontend. The
46 communication on this socket is a sequence of request/reply actions from
46 communication on this socket is a sequence of request/reply actions from
47 each frontend and the kernel.
47 each frontend and the kernel.
48
48
49 3. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
49 3. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
50 side effects (stdout, stderr, etc.) as well as the requests coming from any
50 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 client over the shell socket and its own requests on the stdin socket. There
51 client over the shell socket and its own requests on the stdin socket. There
52 are a number of actions in Python which generate side effects: :func:`print`
52 are a number of actions in Python which generate side effects: :func:`print`
53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 a multi-client scenario, we want all frontends to be able to know what each
54 a multi-client scenario, we want all frontends to be able to know what each
55 other has sent to the kernel (this can be useful in collaborative scenarios,
55 other has sent to the kernel (this can be useful in collaborative scenarios,
56 for example). This socket allows both side effects and the information
56 for example). This socket allows both side effects and the information
57 about communications taking place with one client over the shell channel
57 about communications taking place with one client over the shell channel
58 to be made available to all clients in a uniform manner.
58 to be made available to all clients in a uniform manner.
59
59
60 All messages are tagged with enough information (details below) for clients
60 All messages are tagged with enough information (details below) for clients
61 to know which messages come from their own interaction with the kernel and
61 to know which messages come from their own interaction with the kernel and
62 which ones are from other clients, so they can display each type
62 which ones are from other clients, so they can display each type
63 appropriately.
63 appropriately.
64
64
65 The actual format of the messages allowed on each of these channels is
65 The actual format of the messages allowed on each of these channels is
66 specified below. Messages are dicts of dicts with string keys and values that
66 specified below. Messages are dicts of dicts with string keys and values that
67 are reasonably representable in JSON. Our current implementation uses JSON
67 are reasonably representable in JSON. Our current implementation uses JSON
68 explicitly as its message format, but this shouldn't be considered a permanent
68 explicitly as its message format, but this shouldn't be considered a permanent
69 feature. As we've discovered that JSON has non-trivial performance issues due
69 feature. As we've discovered that JSON has non-trivial performance issues due
70 to excessive copying, we may in the future move to a pure pickle-based raw
70 to excessive copying, we may in the future move to a pure pickle-based raw
71 message format. However, it should be possible to easily convert from the raw
71 message format. However, it should be possible to easily convert from the raw
72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 As long as it's easy to make a JSON version of the objects that is a faithful
73 As long as it's easy to make a JSON version of the objects that is a faithful
74 representation of all the data, we can communicate with such clients.
74 representation of all the data, we can communicate with such clients.
75
75
76 .. Note::
76 .. Note::
77
77
78 Not all of these have yet been fully fleshed out, but the key ones are, see
78 Not all of these have yet been fully fleshed out, but the key ones are, see
79 kernel and frontend files for actual implementation details.
79 kernel and frontend files for actual implementation details.
80
80
81 General Message Format
81 General Message Format
82 ======================
82 ======================
83
83
84 A message is defined by the following four-dictionary structure::
84 A message is defined by the following four-dictionary structure::
85
85
86 {
86 {
87 # The message header contains a pair of unique identifiers for the
87 # The message header contains a pair of unique identifiers for the
88 # originating session and the actual message id, in addition to the
88 # originating session and the actual message id, in addition to the
89 # username for the process that generated the message. This is useful in
89 # username for the process that generated the message. This is useful in
90 # collaborative settings where multiple users may be interacting with the
90 # collaborative settings where multiple users may be interacting with the
91 # same kernel simultaneously, so that frontends can label the various
91 # same kernel simultaneously, so that frontends can label the various
92 # messages in a meaningful way.
92 # messages in a meaningful way.
93 'header' : {
93 'header' : {
94 'msg_id' : uuid,
94 'msg_id' : uuid,
95 'username' : str,
95 'username' : str,
96 'session' : uuid
96 'session' : uuid
97 # All recognized message type strings are listed below.
97 # All recognized message type strings are listed below.
98 'msg_type' : str,
98 'msg_type' : str,
99 },
99 },
100
100
101 # In a chain of messages, the header from the parent is copied so that
101 # In a chain of messages, the header from the parent is copied so that
102 # clients can track where messages come from.
102 # clients can track where messages come from.
103 'parent_header' : dict,
103 'parent_header' : dict,
104
104
105 # The actual content of the message must be a dict, whose structure
105 # The actual content of the message must be a dict, whose structure
106 # depends on the message type.
106 # depends on the message type.
107 'content' : dict,
107 'content' : dict,
108
108
109 # Any metadata associated with the message.
109 # Any metadata associated with the message.
110 'metadata' : dict,
110 'metadata' : dict,
111 }
111 }
112
112
113
113
114 Python functional API
114 Python functional API
115 =====================
115 =====================
116
116
117 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
117 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
118 should develop, at a few key points, functional forms of all the requests that
118 should develop, at a few key points, functional forms of all the requests that
119 take arguments in this manner and automatically construct the necessary dict
119 take arguments in this manner and automatically construct the necessary dict
120 for sending.
120 for sending.
121
121
122 In addition, the Python implementation of the message specification extends
122 In addition, the Python implementation of the message specification extends
123 messages upon deserialization to the following form for convenience::
123 messages upon deserialization to the following form for convenience::
124
124
125 {
125 {
126 'header' : dict,
126 'header' : dict,
127 # The msg's unique identifier and type are always stored in the header,
127 # The msg's unique identifier and type are always stored in the header,
128 # but the Python implementation copies them to the top level.
128 # but the Python implementation copies them to the top level.
129 'msg_id' : uuid,
129 'msg_id' : uuid,
130 'msg_type' : str,
130 'msg_type' : str,
131 'parent_header' : dict,
131 'parent_header' : dict,
132 'content' : dict,
132 'content' : dict,
133 'metadata' : dict,
133 'metadata' : dict,
134 }
134 }
135
135
136 All messages sent to or received by any IPython process should have this
136 All messages sent to or received by any IPython process should have this
137 extended structure.
137 extended structure.
138
138
139
139
140 Messages on the shell ROUTER/DEALER sockets
140 Messages on the shell ROUTER/DEALER sockets
141 ===========================================
141 ===========================================
142
142
143 .. _execute:
143 .. _execute:
144
144
145 Execute
145 Execute
146 -------
146 -------
147
147
148 This message type is used by frontends to ask the kernel to execute code on
148 This message type is used by frontends to ask the kernel to execute code on
149 behalf of the user, in a namespace reserved to the user's variables (and thus
149 behalf of the user, in a namespace reserved to the user's variables (and thus
150 separate from the kernel's own internal code and variables).
150 separate from the kernel's own internal code and variables).
151
151
152 Message type: ``execute_request``::
152 Message type: ``execute_request``::
153
153
154 content = {
154 content = {
155 # Source code to be executed by the kernel, one or more lines.
155 # Source code to be executed by the kernel, one or more lines.
156 'code' : str,
156 'code' : str,
157
157
158 # A boolean flag which, if True, signals the kernel to execute
158 # A boolean flag which, if True, signals the kernel to execute
159 # this code as quietly as possible. This means that the kernel
159 # this code as quietly as possible. This means that the kernel
160 # will compile the code with 'exec' instead of 'single' (so
160 # will compile the code with 'exec' instead of 'single' (so
161 # sys.displayhook will not fire), forces store_history to be False,
161 # sys.displayhook will not fire), forces store_history to be False,
162 # and will *not*:
162 # and will *not*:
163 # - broadcast exceptions on the PUB socket
163 # - broadcast exceptions on the PUB socket
164 # - do any logging
164 # - do any logging
165 #
165 #
166 # The default is False.
166 # The default is False.
167 'silent' : bool,
167 'silent' : bool,
168
168
169 # A boolean flag which, if True, signals the kernel to populate history
169 # A boolean flag which, if True, signals the kernel to populate history
170 # The default is True if silent is False. If silent is True, store_history
170 # The default is True if silent is False. If silent is True, store_history
171 # is forced to be False.
171 # is forced to be False.
172 'store_history' : bool,
172 'store_history' : bool,
173
173
174 # A list of variable names from the user's namespace to be retrieved. What
174 # A list of variable names from the user's namespace to be retrieved. What
175 # returns is a JSON string of the variable's repr(), not a python object.
175 # returns is a JSON string of the variable's repr(), not a python object.
176 'user_variables' : list,
176 'user_variables' : list,
177
177
178 # Similarly, a dict mapping names to expressions to be evaluated in the
178 # Similarly, a dict mapping names to expressions to be evaluated in the
179 # user's dict.
179 # user's dict.
180 'user_expressions' : dict,
180 'user_expressions' : dict,
181
181
182 # Some frontends (e.g. the Notebook) do not support stdin requests. If
182 # Some frontends (e.g. the Notebook) do not support stdin requests. If
183 # raw_input is called from code executed from such a frontend, a
183 # raw_input is called from code executed from such a frontend, a
184 # StdinNotImplementedError will be raised.
184 # StdinNotImplementedError will be raised.
185 'allow_stdin' : True,
185 'allow_stdin' : True,
186
186
187 }
187 }
188
188
189 The ``code`` field contains a single string (possibly multiline). The kernel
189 The ``code`` field contains a single string (possibly multiline). The kernel
190 is responsible for splitting this into one or more independent execution blocks
190 is responsible for splitting this into one or more independent execution blocks
191 and deciding whether to compile these in 'single' or 'exec' mode (see below for
191 and deciding whether to compile these in 'single' or 'exec' mode (see below for
192 detailed execution semantics).
192 detailed execution semantics).
193
193
194 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
194 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
195 the notion of a prompt string that allowed arbitrary code to be evaluated, and
195 the notion of a prompt string that allowed arbitrary code to be evaluated, and
196 this was put to good use by many in creating prompts that displayed system
196 this was put to good use by many in creating prompts that displayed system
197 status, path information, and even more esoteric uses like remote instrument
197 status, path information, and even more esoteric uses like remote instrument
198 status aqcuired over the network. But now that IPython has a clean separation
198 status aqcuired over the network. But now that IPython has a clean separation
199 between the kernel and the clients, the kernel has no prompt knowledge; prompts
199 between the kernel and the clients, the kernel has no prompt knowledge; prompts
200 are a frontend-side feature, and it should be even possible for different
200 are a frontend-side feature, and it should be even possible for different
201 frontends to display different prompts while interacting with the same kernel.
201 frontends to display different prompts while interacting with the same kernel.
202
202
203 The kernel now provides the ability to retrieve data from the user's namespace
203 The kernel now provides the ability to retrieve data from the user's namespace
204 after the execution of the main ``code``, thanks to two fields in the
204 after the execution of the main ``code``, thanks to two fields in the
205 ``execute_request`` message:
205 ``execute_request`` message:
206
206
207 - ``user_variables``: If only variables from the user's namespace are needed, a
207 - ``user_variables``: If only variables from the user's namespace are needed, a
208 list of variable names can be passed and a dict with these names as keys and
208 list of variable names can be passed and a dict with these names as keys and
209 their :func:`repr()` as values will be returned.
209 their :func:`repr()` as values will be returned.
210
210
211 - ``user_expressions``: For more complex expressions that require function
211 - ``user_expressions``: For more complex expressions that require function
212 evaluations, a dict can be provided with string keys and arbitrary python
212 evaluations, a dict can be provided with string keys and arbitrary python
213 expressions as values. The return message will contain also a dict with the
213 expressions as values. The return message will contain also a dict with the
214 same keys and the :func:`repr()` of the evaluated expressions as value.
214 same keys and the :func:`repr()` of the evaluated expressions as value.
215
215
216 With this information, frontends can display any status information they wish
216 With this information, frontends can display any status information they wish
217 in the form that best suits each frontend (a status line, a popup, inline for a
217 in the form that best suits each frontend (a status line, a popup, inline for a
218 terminal, etc).
218 terminal, etc).
219
219
220 .. Note::
220 .. Note::
221
221
222 In order to obtain the current execution counter for the purposes of
222 In order to obtain the current execution counter for the purposes of
223 displaying input prompts, frontends simply make an execution request with an
223 displaying input prompts, frontends simply make an execution request with an
224 empty code string and ``silent=True``.
224 empty code string and ``silent=True``.
225
225
226 Execution semantics
226 Execution semantics
227 ~~~~~~~~~~~~~~~~~~~
227 ~~~~~~~~~~~~~~~~~~~
228
228
229 When the silent flag is false, the execution of use code consists of the
229 When the silent flag is false, the execution of use code consists of the
230 following phases (in silent mode, only the ``code`` field is executed):
230 following phases (in silent mode, only the ``code`` field is executed):
231
231
232 1. Run the ``pre_runcode_hook``.
232 1. Run the ``pre_runcode_hook``.
233
233
234 2. Execute the ``code`` field, see below for details.
234 2. Execute the ``code`` field, see below for details.
235
235
236 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
236 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
237 computed. This ensures that any error in the latter don't harm the main
237 computed. This ensures that any error in the latter don't harm the main
238 code execution.
238 code execution.
239
239
240 4. Call any method registered with :meth:`register_post_execute`.
240 4. Call any method registered with :meth:`register_post_execute`.
241
241
242 .. warning::
242 .. warning::
243
243
244 The API for running code before/after the main code block is likely to
244 The API for running code before/after the main code block is likely to
245 change soon. Both the ``pre_runcode_hook`` and the
245 change soon. Both the ``pre_runcode_hook`` and the
246 :meth:`register_post_execute` are susceptible to modification, as we find a
246 :meth:`register_post_execute` are susceptible to modification, as we find a
247 consistent model for both.
247 consistent model for both.
248
248
249 To understand how the ``code`` field is executed, one must know that Python
249 To understand how the ``code`` field is executed, one must know that Python
250 code can be compiled in one of three modes (controlled by the ``mode`` argument
250 code can be compiled in one of three modes (controlled by the ``mode`` argument
251 to the :func:`compile` builtin):
251 to the :func:`compile` builtin):
252
252
253 *single*
253 *single*
254 Valid for a single interactive statement (though the source can contain
254 Valid for a single interactive statement (though the source can contain
255 multiple lines, such as a for loop). When compiled in this mode, the
255 multiple lines, such as a for loop). When compiled in this mode, the
256 generated bytecode contains special instructions that trigger the calling of
256 generated bytecode contains special instructions that trigger the calling of
257 :func:`sys.displayhook` for any expression in the block that returns a value.
257 :func:`sys.displayhook` for any expression in the block that returns a value.
258 This means that a single statement can actually produce multiple calls to
258 This means that a single statement can actually produce multiple calls to
259 :func:`sys.displayhook`, if for example it contains a loop where each
259 :func:`sys.displayhook`, if for example it contains a loop where each
260 iteration computes an unassigned expression would generate 10 calls::
260 iteration computes an unassigned expression would generate 10 calls::
261
261
262 for i in range(10):
262 for i in range(10):
263 i**2
263 i**2
264
264
265 *exec*
265 *exec*
266 An arbitrary amount of source code, this is how modules are compiled.
266 An arbitrary amount of source code, this is how modules are compiled.
267 :func:`sys.displayhook` is *never* implicitly called.
267 :func:`sys.displayhook` is *never* implicitly called.
268
268
269 *eval*
269 *eval*
270 A single expression that returns a value. :func:`sys.displayhook` is *never*
270 A single expression that returns a value. :func:`sys.displayhook` is *never*
271 implicitly called.
271 implicitly called.
272
272
273
273
274 The ``code`` field is split into individual blocks each of which is valid for
274 The ``code`` field is split into individual blocks each of which is valid for
275 execution in 'single' mode, and then:
275 execution in 'single' mode, and then:
276
276
277 - If there is only a single block: it is executed in 'single' mode.
277 - If there is only a single block: it is executed in 'single' mode.
278
278
279 - If there is more than one block:
279 - If there is more than one block:
280
280
281 * if the last one is a single line long, run all but the last in 'exec' mode
281 * if the last one is a single line long, run all but the last in 'exec' mode
282 and the very last one in 'single' mode. This makes it easy to type simple
282 and the very last one in 'single' mode. This makes it easy to type simple
283 expressions at the end to see computed values.
283 expressions at the end to see computed values.
284
284
285 * if the last one is no more than two lines long, run all but the last in
285 * if the last one is no more than two lines long, run all but the last in
286 'exec' mode and the very last one in 'single' mode. This makes it easy to
286 'exec' mode and the very last one in 'single' mode. This makes it easy to
287 type simple expressions at the end to see computed values. - otherwise
287 type simple expressions at the end to see computed values. - otherwise
288 (last one is also multiline), run all in 'exec' mode
288 (last one is also multiline), run all in 'exec' mode
289
289
290 * otherwise (last one is also multiline), run all in 'exec' mode as a single
290 * otherwise (last one is also multiline), run all in 'exec' mode as a single
291 unit.
291 unit.
292
292
293 Any error in retrieving the ``user_variables`` or evaluating the
293 Any error in retrieving the ``user_variables`` or evaluating the
294 ``user_expressions`` will result in a simple error message in the return fields
294 ``user_expressions`` will result in a simple error message in the return fields
295 of the form::
295 of the form::
296
296
297 [ERROR] ExceptionType: Exception message
297 [ERROR] ExceptionType: Exception message
298
298
299 The user can simply send the same variable name or expression for evaluation to
299 The user can simply send the same variable name or expression for evaluation to
300 see a regular traceback.
300 see a regular traceback.
301
301
302 Errors in any registered post_execute functions are also reported similarly,
302 Errors in any registered post_execute functions are also reported similarly,
303 and the failing function is removed from the post_execution set so that it does
303 and the failing function is removed from the post_execution set so that it does
304 not continue triggering failures.
304 not continue triggering failures.
305
305
306 Upon completion of the execution request, the kernel *always* sends a reply,
306 Upon completion of the execution request, the kernel *always* sends a reply,
307 with a status code indicating what happened and additional data depending on
307 with a status code indicating what happened and additional data depending on
308 the outcome. See :ref:`below <execution_results>` for the possible return
308 the outcome. See :ref:`below <execution_results>` for the possible return
309 codes and associated data.
309 codes and associated data.
310
310
311
311
312 Execution counter (old prompt number)
312 Execution counter (old prompt number)
313 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
313 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
314
314
315 The kernel has a single, monotonically increasing counter of all execution
315 The kernel has a single, monotonically increasing counter of all execution
316 requests that are made with ``store_history=True``. This counter is used to populate
316 requests that are made with ``store_history=True``. This counter is used to populate
317 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
317 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
318 display it in some form to the user, which will typically (but not necessarily)
318 display it in some form to the user, which will typically (but not necessarily)
319 be done in the prompts. The value of this counter will be returned as the
319 be done in the prompts. The value of this counter will be returned as the
320 ``execution_count`` field of all ``execute_reply`` messages.
320 ``execution_count`` field of all ``execute_reply`` messages.
321
321
322 .. _execution_results:
322 .. _execution_results:
323
323
324 Execution results
324 Execution results
325 ~~~~~~~~~~~~~~~~~
325 ~~~~~~~~~~~~~~~~~
326
326
327 Message type: ``execute_reply``::
327 Message type: ``execute_reply``::
328
328
329 content = {
329 content = {
330 # One of: 'ok' OR 'error' OR 'abort'
330 # One of: 'ok' OR 'error' OR 'abort'
331 'status' : str,
331 'status' : str,
332
332
333 # The global kernel counter that increases by one with each request that
333 # The global kernel counter that increases by one with each request that
334 # stores history. This will typically be used by clients to display
334 # stores history. This will typically be used by clients to display
335 # prompt numbers to the user. If the request did not store history, this will
335 # prompt numbers to the user. If the request did not store history, this will
336 # be the current value of the counter in the kernel.
336 # be the current value of the counter in the kernel.
337 'execution_count' : int,
337 'execution_count' : int,
338 }
338 }
339
339
340 When status is 'ok', the following extra fields are present::
340 When status is 'ok', the following extra fields are present::
341
341
342 {
342 {
343 # 'payload' will be a list of payload dicts.
343 # 'payload' will be a list of payload dicts.
344 # Each execution payload is a dict with string keys that may have been
344 # Each execution payload is a dict with string keys that may have been
345 # produced by the code being executed. It is retrieved by the kernel at
345 # produced by the code being executed. It is retrieved by the kernel at
346 # the end of the execution and sent back to the front end, which can take
346 # the end of the execution and sent back to the front end, which can take
347 # action on it as needed. See main text for further details.
347 # action on it as needed. See main text for further details.
348 'payload' : list(dict),
348 'payload' : list(dict),
349
349
350 # Results for the user_variables and user_expressions.
350 # Results for the user_variables and user_expressions.
351 'user_variables' : dict,
351 'user_variables' : dict,
352 'user_expressions' : dict,
352 'user_expressions' : dict,
353 }
353 }
354
354
355 .. admonition:: Execution payloads
355 .. admonition:: Execution payloads
356
356
357 The notion of an 'execution payload' is different from a return value of a
357 The notion of an 'execution payload' is different from a return value of a
358 given set of code, which normally is just displayed on the pyout stream
358 given set of code, which normally is just displayed on the pyout stream
359 through the PUB socket. The idea of a payload is to allow special types of
359 through the PUB socket. The idea of a payload is to allow special types of
360 code, typically magics, to populate a data container in the IPython kernel
360 code, typically magics, to populate a data container in the IPython kernel
361 that will be shipped back to the caller via this channel. The kernel
361 that will be shipped back to the caller via this channel. The kernel
362 has an API for this in the PayloadManager::
362 has an API for this in the PayloadManager::
363
363
364 ip.payload_manager.write_payload(payload_dict)
364 ip.payload_manager.write_payload(payload_dict)
365
365
366 which appends a dictionary to the list of payloads.
366 which appends a dictionary to the list of payloads.
367
367
368
368
369 When status is 'error', the following extra fields are present::
369 When status is 'error', the following extra fields are present::
370
370
371 {
371 {
372 'ename' : str, # Exception name, as a string
372 'ename' : str, # Exception name, as a string
373 'evalue' : str, # Exception value, as a string
373 'evalue' : str, # Exception value, as a string
374
374
375 # The traceback will contain a list of frames, represented each as a
375 # The traceback will contain a list of frames, represented each as a
376 # string. For now we'll stick to the existing design of ultraTB, which
376 # string. For now we'll stick to the existing design of ultraTB, which
377 # controls exception level of detail statefully. But eventually we'll
377 # controls exception level of detail statefully. But eventually we'll
378 # want to grow into a model where more information is collected and
378 # want to grow into a model where more information is collected and
379 # packed into the traceback object, with clients deciding how little or
379 # packed into the traceback object, with clients deciding how little or
380 # how much of it to unpack. But for now, let's start with a simple list
380 # how much of it to unpack. But for now, let's start with a simple list
381 # of strings, since that requires only minimal changes to ultratb as
381 # of strings, since that requires only minimal changes to ultratb as
382 # written.
382 # written.
383 'traceback' : list,
383 'traceback' : list,
384 }
384 }
385
385
386
386
387 When status is 'abort', there are for now no additional data fields. This
387 When status is 'abort', there are for now no additional data fields. This
388 happens when the kernel was interrupted by a signal.
388 happens when the kernel was interrupted by a signal.
389
389
390 Kernel attribute access
390 Kernel attribute access
391 -----------------------
391 -----------------------
392
392
393 .. warning::
393 .. warning::
394
394
395 This part of the messaging spec is not actually implemented in the kernel
395 This part of the messaging spec is not actually implemented in the kernel
396 yet.
396 yet.
397
397
398 While this protocol does not specify full RPC access to arbitrary methods of
398 While this protocol does not specify full RPC access to arbitrary methods of
399 the kernel object, the kernel does allow read (and in some cases write) access
399 the kernel object, the kernel does allow read (and in some cases write) access
400 to certain attributes.
400 to certain attributes.
401
401
402 The policy for which attributes can be read is: any attribute of the kernel, or
402 The policy for which attributes can be read is: any attribute of the kernel, or
403 its sub-objects, that belongs to a :class:`Configurable` object and has been
403 its sub-objects, that belongs to a :class:`Configurable` object and has been
404 declared at the class-level with Traits validation, is in principle accessible
404 declared at the class-level with Traits validation, is in principle accessible
405 as long as its name does not begin with a leading underscore. The attribute
405 as long as its name does not begin with a leading underscore. The attribute
406 itself will have metadata indicating whether it allows remote read and/or write
406 itself will have metadata indicating whether it allows remote read and/or write
407 access. The message spec follows for attribute read and write requests.
407 access. The message spec follows for attribute read and write requests.
408
408
409 Message type: ``getattr_request``::
409 Message type: ``getattr_request``::
410
410
411 content = {
411 content = {
412 # The (possibly dotted) name of the attribute
412 # The (possibly dotted) name of the attribute
413 'name' : str,
413 'name' : str,
414 }
414 }
415
415
416 When a ``getattr_request`` fails, there are two possible error types:
416 When a ``getattr_request`` fails, there are two possible error types:
417
417
418 - AttributeError: this type of error was raised when trying to access the
418 - AttributeError: this type of error was raised when trying to access the
419 given name by the kernel itself. This means that the attribute likely
419 given name by the kernel itself. This means that the attribute likely
420 doesn't exist.
420 doesn't exist.
421
421
422 - AccessError: the attribute exists but its value is not readable remotely.
422 - AccessError: the attribute exists but its value is not readable remotely.
423
423
424
424
425 Message type: ``getattr_reply``::
425 Message type: ``getattr_reply``::
426
426
427 content = {
427 content = {
428 # One of ['ok', 'AttributeError', 'AccessError'].
428 # One of ['ok', 'AttributeError', 'AccessError'].
429 'status' : str,
429 'status' : str,
430 # If status is 'ok', a JSON object.
430 # If status is 'ok', a JSON object.
431 'value' : object,
431 'value' : object,
432 }
432 }
433
433
434 Message type: ``setattr_request``::
434 Message type: ``setattr_request``::
435
435
436 content = {
436 content = {
437 # The (possibly dotted) name of the attribute
437 # The (possibly dotted) name of the attribute
438 'name' : str,
438 'name' : str,
439
439
440 # A JSON-encoded object, that will be validated by the Traits
440 # A JSON-encoded object, that will be validated by the Traits
441 # information in the kernel
441 # information in the kernel
442 'value' : object,
442 'value' : object,
443 }
443 }
444
444
445 When a ``setattr_request`` fails, there are also two possible error types with
445 When a ``setattr_request`` fails, there are also two possible error types with
446 similar meanings as those of the ``getattr_request`` case, but for writing.
446 similar meanings as those of the ``getattr_request`` case, but for writing.
447
447
448 Message type: ``setattr_reply``::
448 Message type: ``setattr_reply``::
449
449
450 content = {
450 content = {
451 # One of ['ok', 'AttributeError', 'AccessError'].
451 # One of ['ok', 'AttributeError', 'AccessError'].
452 'status' : str,
452 'status' : str,
453 }
453 }
454
454
455
455
456
456
457 Object information
457 Object information
458 ------------------
458 ------------------
459
459
460 One of IPython's most used capabilities is the introspection of Python objects
460 One of IPython's most used capabilities is the introspection of Python objects
461 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
461 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
462 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
462 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
463 enough that it warrants an explicit message type, especially because frontends
463 enough that it warrants an explicit message type, especially because frontends
464 may want to get object information in response to user keystrokes (like Tab or
464 may want to get object information in response to user keystrokes (like Tab or
465 F1) besides from the user explicitly typing code like ``x??``.
465 F1) besides from the user explicitly typing code like ``x??``.
466
466
467 Message type: ``object_info_request``::
467 Message type: ``object_info_request``::
468
468
469 content = {
469 content = {
470 # The (possibly dotted) name of the object to be searched in all
470 # The (possibly dotted) name of the object to be searched in all
471 # relevant namespaces
471 # relevant namespaces
472 'name' : str,
472 'name' : str,
473
473
474 # The level of detail desired. The default (0) is equivalent to typing
474 # The level of detail desired. The default (0) is equivalent to typing
475 # 'x?' at the prompt, 1 is equivalent to 'x??'.
475 # 'x?' at the prompt, 1 is equivalent to 'x??'.
476 'detail_level' : int,
476 'detail_level' : int,
477 }
477 }
478
478
479 The returned information will be a dictionary with keys very similar to the
479 The returned information will be a dictionary with keys very similar to the
480 field names that IPython prints at the terminal.
480 field names that IPython prints at the terminal.
481
481
482 Message type: ``object_info_reply``::
482 Message type: ``object_info_reply``::
483
483
484 content = {
484 content = {
485 # The name the object was requested under
485 # The name the object was requested under
486 'name' : str,
486 'name' : str,
487
487
488 # Boolean flag indicating whether the named object was found or not. If
488 # Boolean flag indicating whether the named object was found or not. If
489 # it's false, all other fields will be empty.
489 # it's false, all other fields will be empty.
490 'found' : bool,
490 'found' : bool,
491
491
492 # Flags for magics and system aliases
492 # Flags for magics and system aliases
493 'ismagic' : bool,
493 'ismagic' : bool,
494 'isalias' : bool,
494 'isalias' : bool,
495
495
496 # The name of the namespace where the object was found ('builtin',
496 # The name of the namespace where the object was found ('builtin',
497 # 'magics', 'alias', 'interactive', etc.)
497 # 'magics', 'alias', 'interactive', etc.)
498 'namespace' : str,
498 'namespace' : str,
499
499
500 # The type name will be type.__name__ for normal Python objects, but it
500 # The type name will be type.__name__ for normal Python objects, but it
501 # can also be a string like 'Magic function' or 'System alias'
501 # can also be a string like 'Magic function' or 'System alias'
502 'type_name' : str,
502 'type_name' : str,
503
503
504 # The string form of the object, possibly truncated for length if
504 # The string form of the object, possibly truncated for length if
505 # detail_level is 0
505 # detail_level is 0
506 'string_form' : str,
506 'string_form' : str,
507
507
508 # For objects with a __class__ attribute this will be set
508 # For objects with a __class__ attribute this will be set
509 'base_class' : str,
509 'base_class' : str,
510
510
511 # For objects with a __len__ attribute this will be set
511 # For objects with a __len__ attribute this will be set
512 'length' : int,
512 'length' : int,
513
513
514 # If the object is a function, class or method whose file we can find,
514 # If the object is a function, class or method whose file we can find,
515 # we give its full path
515 # we give its full path
516 'file' : str,
516 'file' : str,
517
517
518 # For pure Python callable objects, we can reconstruct the object
518 # For pure Python callable objects, we can reconstruct the object
519 # definition line which provides its call signature. For convenience this
519 # definition line which provides its call signature. For convenience this
520 # is returned as a single 'definition' field, but below the raw parts that
520 # is returned as a single 'definition' field, but below the raw parts that
521 # compose it are also returned as the argspec field.
521 # compose it are also returned as the argspec field.
522 'definition' : str,
522 'definition' : str,
523
523
524 # The individual parts that together form the definition string. Clients
524 # The individual parts that together form the definition string. Clients
525 # with rich display capabilities may use this to provide a richer and more
525 # with rich display capabilities may use this to provide a richer and more
526 # precise representation of the definition line (e.g. by highlighting
526 # precise representation of the definition line (e.g. by highlighting
527 # arguments based on the user's cursor position). For non-callable
527 # arguments based on the user's cursor position). For non-callable
528 # objects, this field is empty.
528 # objects, this field is empty.
529 'argspec' : { # The names of all the arguments
529 'argspec' : { # The names of all the arguments
530 args : list,
530 args : list,
531 # The name of the varargs (*args), if any
531 # The name of the varargs (*args), if any
532 varargs : str,
532 varargs : str,
533 # The name of the varkw (**kw), if any
533 # The name of the varkw (**kw), if any
534 varkw : str,
534 varkw : str,
535 # The values (as strings) of all default arguments. Note
535 # The values (as strings) of all default arguments. Note
536 # that these must be matched *in reverse* with the 'args'
536 # that these must be matched *in reverse* with the 'args'
537 # list above, since the first positional args have no default
537 # list above, since the first positional args have no default
538 # value at all.
538 # value at all.
539 defaults : list,
539 defaults : list,
540 },
540 },
541
541
542 # For instances, provide the constructor signature (the definition of
542 # For instances, provide the constructor signature (the definition of
543 # the __init__ method):
543 # the __init__ method):
544 'init_definition' : str,
544 'init_definition' : str,
545
545
546 # Docstrings: for any object (function, method, module, package) with a
546 # Docstrings: for any object (function, method, module, package) with a
547 # docstring, we show it. But in addition, we may provide additional
547 # docstring, we show it. But in addition, we may provide additional
548 # docstrings. For example, for instances we will show the constructor
548 # docstrings. For example, for instances we will show the constructor
549 # and class docstrings as well, if available.
549 # and class docstrings as well, if available.
550 'docstring' : str,
550 'docstring' : str,
551
551
552 # For instances, provide the constructor and class docstrings
552 # For instances, provide the constructor and class docstrings
553 'init_docstring' : str,
553 'init_docstring' : str,
554 'class_docstring' : str,
554 'class_docstring' : str,
555
555
556 # If it's a callable object whose call method has a separate docstring and
556 # If it's a callable object whose call method has a separate docstring and
557 # definition line:
557 # definition line:
558 'call_def' : str,
558 'call_def' : str,
559 'call_docstring' : str,
559 'call_docstring' : str,
560
560
561 # If detail_level was 1, we also try to find the source code that
561 # If detail_level was 1, we also try to find the source code that
562 # defines the object, if possible. The string 'None' will indicate
562 # defines the object, if possible. The string 'None' will indicate
563 # that no source was found.
563 # that no source was found.
564 'source' : str,
564 'source' : str,
565 }
565 }
566
566
567
567
568 Complete
568 Complete
569 --------
569 --------
570
570
571 Message type: ``complete_request``::
571 Message type: ``complete_request``::
572
572
573 content = {
573 content = {
574 # The text to be completed, such as 'a.is'
574 # The text to be completed, such as 'a.is'
575 'text' : str,
575 'text' : str,
576
576
577 # The full line, such as 'print a.is'. This allows completers to
577 # The full line, such as 'print a.is'. This allows completers to
578 # make decisions that may require information about more than just the
578 # make decisions that may require information about more than just the
579 # current word.
579 # current word.
580 'line' : str,
580 'line' : str,
581
581
582 # The entire block of text where the line is. This may be useful in the
582 # The entire block of text where the line is. This may be useful in the
583 # case of multiline completions where more context may be needed. Note: if
583 # case of multiline completions where more context may be needed. Note: if
584 # in practice this field proves unnecessary, remove it to lighten the
584 # in practice this field proves unnecessary, remove it to lighten the
585 # messages.
585 # messages.
586
586
587 'block' : str,
587 'block' : str,
588
588
589 # The position of the cursor where the user hit 'TAB' on the line.
589 # The position of the cursor where the user hit 'TAB' on the line.
590 'cursor_pos' : int,
590 'cursor_pos' : int,
591 }
591 }
592
592
593 Message type: ``complete_reply``::
593 Message type: ``complete_reply``::
594
594
595 content = {
595 content = {
596 # The list of all matches to the completion request, such as
596 # The list of all matches to the completion request, such as
597 # ['a.isalnum', 'a.isalpha'] for the above example.
597 # ['a.isalnum', 'a.isalpha'] for the above example.
598 'matches' : list
598 'matches' : list
599 }
599 }
600
600
601
601
602 History
602 History
603 -------
603 -------
604
604
605 For clients to explicitly request history from a kernel. The kernel has all
605 For clients to explicitly request history from a kernel. The kernel has all
606 the actual execution history stored in a single location, so clients can
606 the actual execution history stored in a single location, so clients can
607 request it from the kernel when needed.
607 request it from the kernel when needed.
608
608
609 Message type: ``history_request``::
609 Message type: ``history_request``::
610
610
611 content = {
611 content = {
612
612
613 # If True, also return output history in the resulting dict.
613 # If True, also return output history in the resulting dict.
614 'output' : bool,
614 'output' : bool,
615
615
616 # If True, return the raw input history, else the transformed input.
616 # If True, return the raw input history, else the transformed input.
617 'raw' : bool,
617 'raw' : bool,
618
618
619 # So far, this can be 'range', 'tail' or 'search'.
619 # So far, this can be 'range', 'tail' or 'search'.
620 'hist_access_type' : str,
620 'hist_access_type' : str,
621
621
622 # If hist_access_type is 'range', get a range of input cells. session can
622 # If hist_access_type is 'range', get a range of input cells. session can
623 # be a positive session number, or a negative number to count back from
623 # be a positive session number, or a negative number to count back from
624 # the current session.
624 # the current session.
625 'session' : int,
625 'session' : int,
626 # start and stop are line numbers within that session.
626 # start and stop are line numbers within that session.
627 'start' : int,
627 'start' : int,
628 'stop' : int,
628 'stop' : int,
629
629
630 # If hist_access_type is 'tail' or 'search', get the last n cells.
630 # If hist_access_type is 'tail' or 'search', get the last n cells.
631 'n' : int,
631 'n' : int,
632
632
633 # If hist_access_type is 'search', get cells matching the specified glob
633 # If hist_access_type is 'search', get cells matching the specified glob
634 # pattern (with * and ? as wildcards).
634 # pattern (with * and ? as wildcards).
635 'pattern' : str,
635 'pattern' : str,
636
636
637 # If hist_access_type is 'search' and unique is true, do not
637 # If hist_access_type is 'search' and unique is true, do not
638 # include duplicated history. Default is false.
638 # include duplicated history. Default is false.
639 'unique' : bool,
639 'unique' : bool,
640
640
641 }
641 }
642
642
643 .. versionadded:: 4.0
643 .. versionadded:: 4.0
644 The key ``unique`` for ``history_request``.
644 The key ``unique`` for ``history_request``.
645
645
646 Message type: ``history_reply``::
646 Message type: ``history_reply``::
647
647
648 content = {
648 content = {
649 # A list of 3 tuples, either:
649 # A list of 3 tuples, either:
650 # (session, line_number, input) or
650 # (session, line_number, input) or
651 # (session, line_number, (input, output)),
651 # (session, line_number, (input, output)),
652 # depending on whether output was False or True, respectively.
652 # depending on whether output was False or True, respectively.
653 'history' : list,
653 'history' : list,
654 }
654 }
655
655
656
656
657 Connect
657 Connect
658 -------
658 -------
659
659
660 When a client connects to the request/reply socket of the kernel, it can issue
660 When a client connects to the request/reply socket of the kernel, it can issue
661 a connect request to get basic information about the kernel, such as the ports
661 a connect request to get basic information about the kernel, such as the ports
662 the other ZeroMQ sockets are listening on. This allows clients to only have
662 the other ZeroMQ sockets are listening on. This allows clients to only have
663 to know about a single port (the shell channel) to connect to a kernel.
663 to know about a single port (the shell channel) to connect to a kernel.
664
664
665 Message type: ``connect_request``::
665 Message type: ``connect_request``::
666
666
667 content = {
667 content = {
668 }
668 }
669
669
670 Message type: ``connect_reply``::
670 Message type: ``connect_reply``::
671
671
672 content = {
672 content = {
673 'shell_port' : int # The port the shell ROUTER socket is listening on.
673 'shell_port' : int # The port the shell ROUTER socket is listening on.
674 'iopub_port' : int # The port the PUB socket is listening on.
674 'iopub_port' : int # The port the PUB socket is listening on.
675 'stdin_port' : int # The port the stdin ROUTER socket is listening on.
675 'stdin_port' : int # The port the stdin ROUTER socket is listening on.
676 'hb_port' : int # The port the heartbeat socket is listening on.
676 'hb_port' : int # The port the heartbeat socket is listening on.
677 }
677 }
678
678
679
679
680 Kernel info
680 Kernel info
681 -----------
681 -----------
682
682
683 If a client needs to know what protocol the kernel supports, it can
683 If a client needs to know what protocol the kernel supports, it can
684 ask version number of the messaging protocol supported by the kernel.
684 ask version number of the messaging protocol supported by the kernel.
685 This message can be used to fetch other core information of the
685 This message can be used to fetch other core information of the
686 kernel, including language (e.g., Python), language version number and
686 kernel, including language (e.g., Python), language version number and
687 IPython version number.
687 IPython version number.
688
688
689 Message type: ``kernel_info_request``::
689 Message type: ``kernel_info_request``::
690
690
691 content = {
691 content = {
692 }
692 }
693
693
694 Message type: ``kernel_info_reply``::
694 Message type: ``kernel_info_reply``::
695
695
696 content = {
696 content = {
697 # Version of messaging protocol (mandatory).
697 # Version of messaging protocol (mandatory).
698 # The first integer indicates major version. It is incremented when
698 # The first integer indicates major version. It is incremented when
699 # there is any backward incompatible change.
699 # there is any backward incompatible change.
700 # The second integer indicates minor version. It is incremented when
700 # The second integer indicates minor version. It is incremented when
701 # there is any backward compatible change.
701 # there is any backward compatible change.
702 'protocol_version': [int, int],
702 'protocol_version': [int, int],
703
703
704 # IPython version number (optional).
704 # IPython version number (optional).
705 # Non-python kernel backend may not have this version number.
705 # Non-python kernel backend may not have this version number.
706 # The last component is an extra field, which may be 'dev' or
706 # The last component is an extra field, which may be 'dev' or
707 # 'rc1' in development version. It is an empty string for
707 # 'rc1' in development version. It is an empty string for
708 # released version.
708 # released version.
709 'ipython_version': [int, int, int, str],
709 'ipython_version': [int, int, int, str],
710
710
711 # Language version number (mandatory).
711 # Language version number (mandatory).
712 # It is Python version number (e.g., [2, 7, 3]) for the kernel
712 # It is Python version number (e.g., [2, 7, 3]) for the kernel
713 # included in IPython.
713 # included in IPython.
714 'language_version': [int, ...],
714 'language_version': [int, ...],
715
715
716 # Programming language in which kernel is implemented (mandatory).
716 # Programming language in which kernel is implemented (mandatory).
717 # Kernel included in IPython returns 'python'.
717 # Kernel included in IPython returns 'python'.
718 'language': str,
718 'language': str,
719 }
719 }
720
720
721
721
722 Kernel shutdown
722 Kernel shutdown
723 ---------------
723 ---------------
724
724
725 The clients can request the kernel to shut itself down; this is used in
725 The clients can request the kernel to shut itself down; this is used in
726 multiple cases:
726 multiple cases:
727
727
728 - when the user chooses to close the client application via a menu or window
728 - when the user chooses to close the client application via a menu or window
729 control.
729 control.
730 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
730 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
731 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
731 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
732 IPythonQt client) to force a kernel restart to get a clean kernel without
732 IPythonQt client) to force a kernel restart to get a clean kernel without
733 losing client-side state like history or inlined figures.
733 losing client-side state like history or inlined figures.
734
734
735 The client sends a shutdown request to the kernel, and once it receives the
735 The client sends a shutdown request to the kernel, and once it receives the
736 reply message (which is otherwise empty), it can assume that the kernel has
736 reply message (which is otherwise empty), it can assume that the kernel has
737 completed shutdown safely.
737 completed shutdown safely.
738
738
739 Upon their own shutdown, client applications will typically execute a last
739 Upon their own shutdown, client applications will typically execute a last
740 minute sanity check and forcefully terminate any kernel that is still alive, to
740 minute sanity check and forcefully terminate any kernel that is still alive, to
741 avoid leaving stray processes in the user's machine.
741 avoid leaving stray processes in the user's machine.
742
742
743 For both shutdown request and reply, there is no actual content that needs to
743 For both shutdown request and reply, there is no actual content that needs to
744 be sent, so the content dict is empty.
744 be sent, so the content dict is empty.
745
745
746 Message type: ``shutdown_request``::
746 Message type: ``shutdown_request``::
747
747
748 content = {
748 content = {
749 'restart' : bool # whether the shutdown is final, or precedes a restart
749 'restart' : bool # whether the shutdown is final, or precedes a restart
750 }
750 }
751
751
752 Message type: ``shutdown_reply``::
752 Message type: ``shutdown_reply``::
753
753
754 content = {
754 content = {
755 'restart' : bool # whether the shutdown is final, or precedes a restart
755 'restart' : bool # whether the shutdown is final, or precedes a restart
756 }
756 }
757
757
758 .. Note::
758 .. Note::
759
759
760 When the clients detect a dead kernel thanks to inactivity on the heartbeat
760 When the clients detect a dead kernel thanks to inactivity on the heartbeat
761 socket, they simply send a forceful process termination signal, since a dead
761 socket, they simply send a forceful process termination signal, since a dead
762 process is unlikely to respond in any useful way to messages.
762 process is unlikely to respond in any useful way to messages.
763
763
764
764
765 Messages on the PUB/SUB socket
765 Messages on the PUB/SUB socket
766 ==============================
766 ==============================
767
767
768 Streams (stdout, stderr, etc)
768 Streams (stdout, stderr, etc)
769 ------------------------------
769 ------------------------------
770
770
771 Message type: ``stream``::
771 Message type: ``stream``::
772
772
773 content = {
773 content = {
774 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
774 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
775 'name' : str,
775 'name' : str,
776
776
777 # The data is an arbitrary string to be written to that stream
777 # The data is an arbitrary string to be written to that stream
778 'data' : str,
778 'data' : str,
779 }
779 }
780
780
781 When a kernel receives a raw_input call, it should also broadcast it on the pub
781 When a kernel receives a raw_input call, it should also broadcast it on the pub
782 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
782 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
783 to monitor/display kernel interactions and possibly replay them to their user
783 to monitor/display kernel interactions and possibly replay them to their user
784 or otherwise expose them.
784 or otherwise expose them.
785
785
786 Display Data
786 Display Data
787 ------------
787 ------------
788
788
789 This type of message is used to bring back data that should be diplayed (text,
789 This type of message is used to bring back data that should be diplayed (text,
790 html, svg, etc.) in the frontends. This data is published to all frontends.
790 html, svg, etc.) in the frontends. This data is published to all frontends.
791 Each message can have multiple representations of the data; it is up to the
791 Each message can have multiple representations of the data; it is up to the
792 frontend to decide which to use and how. A single message should contain all
792 frontend to decide which to use and how. A single message should contain all
793 possible representations of the same information. Each representation should
793 possible representations of the same information. Each representation should
794 be a JSON'able data structure, and should be a valid MIME type.
794 be a JSON'able data structure, and should be a valid MIME type.
795
795
796 Some questions remain about this design:
796 Some questions remain about this design:
797
797
798 * Do we use this message type for pyout/displayhook? Probably not, because
798 * Do we use this message type for pyout/displayhook? Probably not, because
799 the displayhook also has to handle the Out prompt display. On the other hand
799 the displayhook also has to handle the Out prompt display. On the other hand
800 we could put that information into the metadata secion.
800 we could put that information into the metadata secion.
801
801
802 Message type: ``display_data``::
802 Message type: ``display_data``::
803
803
804 content = {
804 content = {
805
805
806 # Who create the data
806 # Who create the data
807 'source' : str,
807 'source' : str,
808
808
809 # The data dict contains key/value pairs, where the kids are MIME
809 # The data dict contains key/value pairs, where the kids are MIME
810 # types and the values are the raw data of the representation in that
810 # types and the values are the raw data of the representation in that
811 # format. The data dict must minimally contain the ``text/plain``
811 # format. The data dict must minimally contain the ``text/plain``
812 # MIME type which is used as a backup representation.
812 # MIME type which is used as a backup representation.
813 'data' : dict,
813 'data' : dict,
814
814
815 # Any metadata that describes the data
815 # Any metadata that describes the data
816 'metadata' : dict
816 'metadata' : dict
817 }
817 }
818
818
819
819
820 Raw Data Publication
820 Raw Data Publication
821 --------------------
821 --------------------
822
822
823 ``display_data`` lets you publish *representations* of data, such as images and html.
823 ``display_data`` lets you publish *representations* of data, such as images and html.
824 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
824 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
825
825
826 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
826 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
827
827
828 .. sourcecode:: python
828 .. sourcecode:: python
829
829
830 from IPython.kernel.zmq.datapub import publish_data
830 from IPython.kernel.zmq.datapub import publish_data
831 ns = dict(x=my_array)
831 ns = dict(x=my_array)
832 publish_data(ns)
832 publish_data(ns)
833
833
834
834
835 Message type: ``data_pub``::
835 Message type: ``data_pub``::
836
836
837 content = {
837 content = {
838 # the keys of the data dict, after it has been unserialized
838 # the keys of the data dict, after it has been unserialized
839 keys = ['a', 'b']
839 keys = ['a', 'b']
840 }
840 }
841 # the namespace dict will be serialized in the message buffers,
841 # the namespace dict will be serialized in the message buffers,
842 # which will have a length of at least one
842 # which will have a length of at least one
843 buffers = ['pdict', ...]
843 buffers = ['pdict', ...]
844
844
845
845
846 The interpretation of a sequence of data_pub messages for a given parent request should be
846 The interpretation of a sequence of data_pub messages for a given parent request should be
847 to update a single namespace with subsequent results.
847 to update a single namespace with subsequent results.
848
848
849 .. note::
849 .. note::
850
850
851 No frontends directly handle data_pub messages at this time.
851 No frontends directly handle data_pub messages at this time.
852 It is currently only used by the client/engines in :mod:`IPython.parallel`,
852 It is currently only used by the client/engines in :mod:`IPython.parallel`,
853 where engines may publish *data* to the Client,
853 where engines may publish *data* to the Client,
854 of which the Client can then publish *representations* via ``display_data``
854 of which the Client can then publish *representations* via ``display_data``
855 to various frontends.
855 to various frontends.
856
856
857 Python inputs
857 Python inputs
858 -------------
858 -------------
859
859
860 These messages are the re-broadcast of the ``execute_request``.
860 These messages are the re-broadcast of the ``execute_request``.
861
861
862 Message type: ``pyin``::
862 Message type: ``pyin``::
863
863
864 content = {
864 content = {
865 'code' : str, # Source code to be executed, one or more lines
865 'code' : str, # Source code to be executed, one or more lines
866
866
867 # The counter for this execution is also provided so that clients can
867 # The counter for this execution is also provided so that clients can
868 # display it, since IPython automatically creates variables called _iN
868 # display it, since IPython automatically creates variables called _iN
869 # (for input prompt In[N]).
869 # (for input prompt In[N]).
870 'execution_count' : int
870 'execution_count' : int
871 }
871 }
872
872
873 Python outputs
873 Python outputs
874 --------------
874 --------------
875
875
876 When Python produces output from code that has been compiled in with the
876 When Python produces output from code that has been compiled in with the
877 'single' flag to :func:`compile`, any expression that produces a value (such as
877 'single' flag to :func:`compile`, any expression that produces a value (such as
878 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
878 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
879 this value whatever it wants. The default behavior of ``sys.displayhook`` in
879 this value whatever it wants. The default behavior of ``sys.displayhook`` in
880 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
880 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
881 the value as long as it is not ``None`` (which isn't printed at all). In our
881 the value as long as it is not ``None`` (which isn't printed at all). In our
882 case, the kernel instantiates as ``sys.displayhook`` an object which has
882 case, the kernel instantiates as ``sys.displayhook`` an object which has
883 similar behavior, but which instead of printing to stdout, broadcasts these
883 similar behavior, but which instead of printing to stdout, broadcasts these
884 values as ``pyout`` messages for clients to display appropriately.
884 values as ``pyout`` messages for clients to display appropriately.
885
885
886 IPython's displayhook can handle multiple simultaneous formats depending on its
886 IPython's displayhook can handle multiple simultaneous formats depending on its
887 configuration. The default pretty-printed repr text is always given with the
887 configuration. The default pretty-printed repr text is always given with the
888 ``data`` entry in this message. Any other formats are provided in the
888 ``data`` entry in this message. Any other formats are provided in the
889 ``extra_formats`` list. Frontends are free to display any or all of these
889 ``extra_formats`` list. Frontends are free to display any or all of these
890 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
890 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
891 string, a type string, and the data. The ID is unique to the formatter
891 string, a type string, and the data. The ID is unique to the formatter
892 implementation that created the data. Frontends will typically ignore the ID
892 implementation that created the data. Frontends will typically ignore the ID
893 unless if it has requested a particular formatter. The type string tells the
893 unless if it has requested a particular formatter. The type string tells the
894 frontend how to interpret the data. It is often, but not always a MIME type.
894 frontend how to interpret the data. It is often, but not always a MIME type.
895 Frontends should ignore types that it does not understand. The data itself is
895 Frontends should ignore types that it does not understand. The data itself is
896 any JSON object and depends on the format. It is often, but not always a string.
896 any JSON object and depends on the format. It is often, but not always a string.
897
897
898 Message type: ``pyout``::
898 Message type: ``pyout``::
899
899
900 content = {
900 content = {
901
901
902 # The counter for this execution is also provided so that clients can
902 # The counter for this execution is also provided so that clients can
903 # display it, since IPython automatically creates variables called _N
903 # display it, since IPython automatically creates variables called _N
904 # (for prompt N).
904 # (for prompt N).
905 'execution_count' : int,
905 'execution_count' : int,
906
906
907 # The data dict contains key/value pairs, where the kids are MIME
907 # The data dict contains key/value pairs, where the kids are MIME
908 # types and the values are the raw data of the representation in that
908 # types and the values are the raw data of the representation in that
909 # format. The data dict must minimally contain the ``text/plain``
909 # format. The data dict must minimally contain the ``text/plain``
910 # MIME type which is used as a backup representation.
910 # MIME type which is used as a backup representation.
911 'data' : dict,
911 'data' : dict,
912
912
913 }
913 }
914
914
915 Python errors
915 Python errors
916 -------------
916 -------------
917
917
918 When an error occurs during code execution
918 When an error occurs during code execution
919
919
920 Message type: ``pyerr``::
920 Message type: ``pyerr``::
921
921
922 content = {
922 content = {
923 # Similar content to the execute_reply messages for the 'error' case,
923 # Similar content to the execute_reply messages for the 'error' case,
924 # except the 'status' field is omitted.
924 # except the 'status' field is omitted.
925 }
925 }
926
926
927 Kernel status
927 Kernel status
928 -------------
928 -------------
929
929
930 This message type is used by frontends to monitor the status of the kernel.
930 This message type is used by frontends to monitor the status of the kernel.
931
931
932 Message type: ``status``::
932 Message type: ``status``::
933
933
934 content = {
934 content = {
935 # When the kernel starts to execute code, it will enter the 'busy'
935 # When the kernel starts to execute code, it will enter the 'busy'
936 # state and when it finishes, it will enter the 'idle' state.
936 # state and when it finishes, it will enter the 'idle' state.
937 execution_state : ('busy', 'idle')
937 execution_state : ('busy', 'idle')
938 }
938 }
939
939
940 Kernel crashes
940 Kernel crashes
941 --------------
941 --------------
942
942
943 When the kernel has an unexpected exception, caught by the last-resort
943 When the kernel has an unexpected exception, caught by the last-resort
944 sys.excepthook, we should broadcast the crash handler's output before exiting.
944 sys.excepthook, we should broadcast the crash handler's output before exiting.
945 This will allow clients to notice that a kernel died, inform the user and
945 This will allow clients to notice that a kernel died, inform the user and
946 propose further actions.
946 propose further actions.
947
947
948 Message type: ``crash``::
948 Message type: ``crash``::
949
949
950 content = {
950 content = {
951 # Similarly to the 'error' case for execute_reply messages, this will
951 # Similarly to the 'error' case for execute_reply messages, this will
952 # contain ename, etype and traceback fields.
952 # contain ename, evalue and traceback fields.
953
953
954 # An additional field with supplementary information such as where to
954 # An additional field with supplementary information such as where to
955 # send the crash message
955 # send the crash message
956 'info' : str,
956 'info' : str,
957 }
957 }
958
958
959
959
960 Future ideas
960 Future ideas
961 ------------
961 ------------
962
962
963 Other potential message types, currently unimplemented, listed below as ideas.
963 Other potential message types, currently unimplemented, listed below as ideas.
964
964
965 Message type: ``file``::
965 Message type: ``file``::
966
966
967 content = {
967 content = {
968 'path' : 'cool.jpg',
968 'path' : 'cool.jpg',
969 'mimetype' : str,
969 'mimetype' : str,
970 'data' : str,
970 'data' : str,
971 }
971 }
972
972
973
973
974 Messages on the stdin ROUTER/DEALER sockets
974 Messages on the stdin ROUTER/DEALER sockets
975 ===========================================
975 ===========================================
976
976
977 This is a socket where the request/reply pattern goes in the opposite direction:
977 This is a socket where the request/reply pattern goes in the opposite direction:
978 from the kernel to a *single* frontend, and its purpose is to allow
978 from the kernel to a *single* frontend, and its purpose is to allow
979 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
979 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
980 to be fulfilled by the client. The request should be made to the frontend that
980 to be fulfilled by the client. The request should be made to the frontend that
981 made the execution request that prompted ``raw_input`` to be called. For now we
981 made the execution request that prompted ``raw_input`` to be called. For now we
982 will keep these messages as simple as possible, since they only mean to convey
982 will keep these messages as simple as possible, since they only mean to convey
983 the ``raw_input(prompt)`` call.
983 the ``raw_input(prompt)`` call.
984
984
985 Message type: ``input_request``::
985 Message type: ``input_request``::
986
986
987 content = { 'prompt' : str }
987 content = { 'prompt' : str }
988
988
989 Message type: ``input_reply``::
989 Message type: ``input_reply``::
990
990
991 content = { 'value' : str }
991 content = { 'value' : str }
992
992
993 .. Note::
993 .. Note::
994
994
995 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
995 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
996 practice the kernel should behave like an interactive program. When a
996 practice the kernel should behave like an interactive program. When a
997 program is opened on the console, the keyboard effectively takes over the
997 program is opened on the console, the keyboard effectively takes over the
998 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
998 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
999 Since the IPython kernel effectively behaves like a console program (albeit
999 Since the IPython kernel effectively behaves like a console program (albeit
1000 one whose "keyboard" is actually living in a separate process and
1000 one whose "keyboard" is actually living in a separate process and
1001 transported over the zmq connection), raw ``stdin`` isn't expected to be
1001 transported over the zmq connection), raw ``stdin`` isn't expected to be
1002 available.
1002 available.
1003
1003
1004
1004
1005 Heartbeat for kernels
1005 Heartbeat for kernels
1006 =====================
1006 =====================
1007
1007
1008 Initially we had considered using messages like those above over ZMQ for a
1008 Initially we had considered using messages like those above over ZMQ for a
1009 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
1009 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
1010 alive at all, even if it may be busy executing user code). But this has the
1010 alive at all, even if it may be busy executing user code). But this has the
1011 problem that if the kernel is locked inside extension code, it wouldn't execute
1011 problem that if the kernel is locked inside extension code, it wouldn't execute
1012 the python heartbeat code. But it turns out that we can implement a basic
1012 the python heartbeat code. But it turns out that we can implement a basic
1013 heartbeat with pure ZMQ, without using any Python messaging at all.
1013 heartbeat with pure ZMQ, without using any Python messaging at all.
1014
1014
1015 The monitor sends out a single zmq message (right now, it is a str of the
1015 The monitor sends out a single zmq message (right now, it is a str of the
1016 monitor's lifetime in seconds), and gets the same message right back, prefixed
1016 monitor's lifetime in seconds), and gets the same message right back, prefixed
1017 with the zmq identity of the DEALER socket in the heartbeat process. This can be
1017 with the zmq identity of the DEALER socket in the heartbeat process. This can be
1018 a uuid, or even a full message, but there doesn't seem to be a need for packing
1018 a uuid, or even a full message, but there doesn't seem to be a need for packing
1019 up a message when the sender and receiver are the exact same Python object.
1019 up a message when the sender and receiver are the exact same Python object.
1020
1020
1021 The model is this::
1021 The model is this::
1022
1022
1023 monitor.send(str(self.lifetime)) # '1.2345678910'
1023 monitor.send(str(self.lifetime)) # '1.2345678910'
1024
1024
1025 and the monitor receives some number of messages of the form::
1025 and the monitor receives some number of messages of the form::
1026
1026
1027 ['uuid-abcd-dead-beef', '1.2345678910']
1027 ['uuid-abcd-dead-beef', '1.2345678910']
1028
1028
1029 where the first part is the zmq.IDENTITY of the heart's DEALER on the engine, and
1029 where the first part is the zmq.IDENTITY of the heart's DEALER on the engine, and
1030 the rest is the message sent by the monitor. No Python code ever has any
1030 the rest is the message sent by the monitor. No Python code ever has any
1031 access to the message between the monitor's send, and the monitor's recv.
1031 access to the message between the monitor's send, and the monitor's recv.
1032
1032
1033
1033
1034 ToDo
1034 ToDo
1035 ====
1035 ====
1036
1036
1037 Missing things include:
1037 Missing things include:
1038
1038
1039 * Important: finish thinking through the payload concept and API.
1039 * Important: finish thinking through the payload concept and API.
1040
1040
1041 * Important: ensure that we have a good solution for magics like %edit. It's
1041 * Important: ensure that we have a good solution for magics like %edit. It's
1042 likely that with the payload concept we can build a full solution, but not
1042 likely that with the payload concept we can build a full solution, but not
1043 100% clear yet.
1043 100% clear yet.
1044
1044
1045 * Finishing the details of the heartbeat protocol.
1045 * Finishing the details of the heartbeat protocol.
1046
1046
1047 * Signal handling: specify what kind of information kernel should broadcast (or
1047 * Signal handling: specify what kind of information kernel should broadcast (or
1048 not) when it receives signals.
1048 not) when it receives signals.
1049
1049
1050 .. include:: ../links.rst
1050 .. include:: ../links.rst
General Comments 0
You need to be logged in to leave comments. Login now