Show More
@@ -1,106 +1,284 b'' | |||
|
1 | 1 | ===================== |
|
2 | 2 | Message Specification |
|
3 | 3 | ===================== |
|
4 | 4 | |
|
5 | 5 | Note: not all of these have yet been fully fleshed out, but the key ones are, |
|
6 | 6 | see kernel and frontend files for actual implementation details. |
|
7 | 7 | |
|
8 | Messages are dicts of dicts with string keys and values that are reasonably | |
|
9 | representable in JSON. Our current implementation uses JSON explicitly as its | |
|
10 | message format, but this shouldn't be considered a permanent feature. As we've | |
|
11 | discovered that JSON has non-trivial performance issues due to excessive | |
|
12 | copying, we may in the future move to a pure pickle-based raw message format. | |
|
13 | However, it should be possible to easily convert from the raw objects to JSON, | |
|
14 | since we may have non-python clients (e.g. a web frontend). As long as it's | |
|
15 | easy to make a JSON version of the objects that is a faithful representation of | |
|
16 | all the data, we can communicate with such clients. | |
|
17 | ||
|
18 | ||
|
19 | Python functional API | |
|
20 | ===================== | |
|
21 | ||
|
22 | As messages are dicts, they map naturally to a ``func(**kw)`` call form. We | |
|
23 | should develop, at a few key points, functional forms of all the requests that | |
|
24 | take arguments in this manner and automatically construct the necessary dict | |
|
25 | for sending. | |
|
26 | ||
|
27 | ||
|
8 | 28 | General Message Format |
|
9 | 29 | ===================== |
|
10 | 30 | |
|
11 | 31 | General message format:: |
|
12 | 32 | |
|
13 | 33 | { |
|
14 | 34 | header : { 'msg_id' : 10, # start with 0 |
|
15 | 35 | 'username' : 'name', |
|
16 | 36 | 'session' : uuid |
|
17 | 37 | }, |
|
18 | 38 | parent_header : dict, |
|
19 | 39 | msg_type : 'string_message_type', |
|
20 | 40 | content : blackbox_dict , # Must be a dict |
|
21 | 41 | } |
|
22 | 42 | |
|
43 | ||
|
44 | Request/Reply going from kernel for stdin | |
|
45 | ========================================= | |
|
46 | ||
|
47 | This is a socket that goes in the opposite direction: from the kernel to a | |
|
48 | *single* frontend, and its purpose is to allow ``raw_input`` and similar | |
|
49 | operations that read from ``sys.stdin`` on the kernel to be fulfilled by the | |
|
50 | client. For now we will keep these messages as simple as possible, since they | |
|
51 | basically only mean to convey the ``raw_input(prompt)`` call. | |
|
52 | ||
|
53 | Message type: 'input_request':: | |
|
54 | ||
|
55 | content = { prompt : string } | |
|
56 | ||
|
57 | Message type: 'input_reply':: | |
|
58 | ||
|
59 | content = { value : string } | |
|
60 | ||
|
61 | ||
|
23 | 62 | Side effect: (PUB/SUB) |
|
24 | 63 | ====================== |
|
25 | 64 | |
|
26 |
|
|
|
65 | Message type: 'stream':: | |
|
27 | 66 | |
|
28 | 67 | content = { |
|
29 | 68 | name : 'stdout', |
|
30 | 69 | data : 'blob', |
|
31 | 70 | } |
|
32 | 71 | |
|
33 | # msg_type = 'pyin':: | |
|
72 | When a kernel receives a raw_input call, it should also broadcast it on the pub | |
|
73 | socket with the names 'stdin' and 'stdin_reply'. This will allow other clients | |
|
74 | to monitor/display kernel interactions and possibly replay them to their user | |
|
75 | or otherwise expose them. | |
|
76 | ||
|
77 | Message type: 'pyin':: | |
|
34 | 78 | |
|
35 | 79 | content = { |
|
36 | 80 | code = 'x=1', |
|
37 | 81 | } |
|
38 | 82 | |
|
39 |
|
|
|
83 | Message type: 'pyout':: | |
|
40 | 84 | |
|
41 | 85 | content = { |
|
42 | 86 | data = 'repr(obj)', |
|
43 | 87 | prompt_number = 10 |
|
44 | 88 | } |
|
45 | 89 | |
|
46 |
|
|
|
90 | Message type: 'pyerr':: | |
|
91 | ||
|
92 | content = { | |
|
93 | # Same as the data payload of a code execute_reply, minus the 'status' | |
|
94 | # field. See below. | |
|
95 | } | |
|
96 | ||
|
97 | When the kernel has an unexpected exception, caught by the last-resort | |
|
98 | sys.excepthook, we should broadcast the crash handler's output before exiting. | |
|
99 | This will allow clients to notice that a kernel died, inform the user and | |
|
100 | propose further actions. | |
|
101 | ||
|
102 | Message type: 'crash':: | |
|
47 | 103 | |
|
48 | 104 | content = { |
|
49 | 105 | traceback : 'full traceback', |
|
50 | 106 | exc_type : 'TypeError', |
|
51 | 107 | exc_value : 'msg' |
|
52 | 108 | } |
|
53 | 109 | |
|
54 | # msg_type = 'file': | |
|
110 | ||
|
111 | Other potential message types, currently unimplemented, listed below as ideas. | |
|
112 | ||
|
113 | Message type: 'file':: | |
|
55 | 114 | content = { |
|
56 |
path |
|
|
115 | path : 'cool.jpg', | |
|
116 | mimetype : string | |
|
57 | 117 | data : 'blob' |
|
58 | 118 | } |
|
59 | 119 | |
|
120 | ||
|
60 | 121 | Request/Reply |
|
61 | 122 | ============= |
|
62 | 123 | |
|
63 | 124 | Execute |
|
64 | 125 | ------- |
|
65 | 126 | |
|
66 | Request: | |
|
127 | The execution request contains a single string, but this may be a multiline | |
|
128 | string. The kernel is responsible for splitting this into possibly more than | |
|
129 | one block and deciding whether to compile these in 'single' or 'exec' mode. | |
|
130 | We're still sorting out this policy. The current inputsplitter is capable of | |
|
131 | splitting the input for blocks that can all be run as 'single', but in the long | |
|
132 | run it may prove cleaner to only use 'single' mode for truly single-line | |
|
133 | inputs, and run all multiline input in 'exec' mode. This would preserve the | |
|
134 | natural behavior of single-line inputs while allowing long cells to behave more | |
|
135 | likea a script. Some thought is still required here... | |
|
67 | 136 | |
|
68 |
|
|
|
137 | Message type: 'execute_request':: | |
|
69 | 138 | |
|
70 | 139 | content = { |
|
71 | 140 | code : 'a = 10', |
|
72 | 141 | } |
|
73 | 142 | |
|
74 | 143 | Reply: |
|
75 | 144 | |
|
76 |
|
|
|
145 | Message type: 'execute_reply':: | |
|
77 | 146 | |
|
78 | 147 | content = { |
|
79 | 148 | 'status' : 'ok' OR 'error' OR 'abort' |
|
80 | # data depends on status value | |
|
149 | # Any additional data depends on status value | |
|
150 | } | |
|
151 | ||
|
152 | When status is 'ok', the following extra fields are present:: | |
|
153 | ||
|
154 | { | |
|
155 | # This has the same structure as the output of a prompt request, but is | |
|
156 | # for the client to set up the *next* prompt (with identical limitations | |
|
157 | # to a prompt request) | |
|
158 | 'next_prompt' : { | |
|
159 | prompt_string : string | |
|
160 | prompt_number : int | |
|
161 | } | |
|
162 | ||
|
163 | # The prompt number of the actual execution for this code, which may be | |
|
164 | # different from the one used when the code was typed, which was the | |
|
165 | # 'next_prompt' field of the *previous* request. They will differ in the | |
|
166 | # case where there is more than one client talking simultaneously to a | |
|
167 | # kernel, since the numbers can go out of sync. GUI clients can use this | |
|
168 | # to correct the previously written number in-place, terminal ones may | |
|
169 | # re-print a corrected one if desired. | |
|
170 | 'prompt_number' : number | |
|
171 | ||
|
172 | # The kernel will often transform the input provided to it. This | |
|
173 | # contains the transformed code, which is what was actually executed. | |
|
174 | 'transformed_code' : new_code | |
|
175 | ||
|
176 | # This 'payload' needs a bit more thinking. The basic idea is that | |
|
177 | # certain actions will want to return additional information, such as | |
|
178 | # magics producing data output for display by the clients. We may need | |
|
179 | # to define a few types of payload, or specify a syntax for the, not sure | |
|
180 | # yet... FIXME here. | |
|
181 | 'payload' : things from page(), for example. | |
|
182 | } | |
|
183 | ||
|
184 | When status is 'error', the following extra fields are present:: | |
|
185 | ||
|
186 | { | |
|
187 | etype : str # Exception type, as a string | |
|
188 | evalue : str # Exception value, as a string | |
|
189 | ||
|
190 | # The traceback will contain a list of frames, represented each as a | |
|
191 | # string. For now we'll stick to the existing design of ultraTB, which | |
|
192 | # controls exception level of detail statefully. But eventually we'll | |
|
193 | # want to grow into a model where more information is collected and | |
|
194 | # packed into the traceback object, with clients deciding how little or | |
|
195 | # how much of it to unpack. But for now, let's start with a simple list | |
|
196 | # of strings, since that requires only minimal changes to ultratb as | |
|
197 | # written. | |
|
198 | traceback : list of strings | |
|
199 | } | |
|
200 | ||
|
201 | ||
|
202 | When status is 'abort', there are for now no additional data fields. | |
|
203 | ||
|
204 | ||
|
205 | Prompt | |
|
206 | ------ | |
|
207 | ||
|
208 | A simple request for a current prompt string. | |
|
209 | ||
|
210 | Message type: 'prompt_request':: | |
|
211 | ||
|
212 | content = {} | |
|
213 | ||
|
214 | In the reply, the prompt string comes back with the prompt number placeholder | |
|
215 | *unevaluated*. The message format is: | |
|
216 | ||
|
217 | Message type: 'prompt_reply':: | |
|
218 | ||
|
219 | content = { | |
|
220 | prompt_string : string | |
|
221 | prompt_number : int | |
|
81 | 222 | } |
|
82 | 223 | |
|
224 | Clients can produce a prompt with ``prompt_string.format(prompt_number)``, but | |
|
225 | they should be aware that the actual prompt number for that input could change | |
|
226 | later, in the case where multiple clients are interacting with a single | |
|
227 | kernel. | |
|
228 | ||
|
229 | ||
|
83 | 230 | Complete |
|
84 | 231 | -------- |
|
85 | 232 | |
|
86 |
|
|
|
233 | Message type: 'complete_request':: | |
|
87 | 234 | |
|
88 | 235 | content = { |
|
89 | 236 | text : 'a.f', # complete on this |
|
90 | 237 | line : 'print a.f' # full line |
|
91 | 238 | } |
|
92 | 239 | |
|
93 |
|
|
|
240 | Message type: 'complete_reply':: | |
|
94 | 241 | |
|
95 | 242 | content = { |
|
96 | 243 | matches : ['a.foo', 'a.bar'] |
|
97 | 244 | } |
|
98 | 245 | |
|
246 | ||
|
247 | History | |
|
248 | ------- | |
|
249 | ||
|
250 | For clients to explicitly request history from a kernel | |
|
251 | ||
|
252 | Message type: 'history_request':: | |
|
253 | ||
|
254 | content = { | |
|
255 | output : boolean. If true, also return output history in the resulting | |
|
256 | dict. | |
|
257 | ||
|
258 | range : optional. A number, a pair of numbers, 'all' | |
|
259 | If not given, last 40 are returned. | |
|
260 | - number n: return the last n entries. | |
|
261 | - pair n1, n2: return entries in the range(n1, n2). | |
|
262 | - 'all': return all history | |
|
263 | ||
|
264 | filter : optional, string | |
|
265 | If given, treated as a regular expression and only matching entries are | |
|
266 | returned. re.search() is used to find matches. | |
|
267 | } | |
|
268 | ||
|
269 | Message type: 'history_reply':: | |
|
270 | ||
|
271 | content = { | |
|
272 | input : list of pairs (number, input) | |
|
273 | output : list of pairs (number, output). Empty if not requested. | |
|
274 | } | |
|
275 | ||
|
276 | ||
|
99 | 277 | Control |
|
100 | 278 | ------- |
|
101 | 279 | |
|
102 |
|
|
|
280 | Message type: 'heartbeat':: | |
|
103 | 281 | |
|
104 | 282 | content = { |
|
105 | 283 | # XXX - unfinished |
|
106 | 284 | } |
General Comments 0
You need to be logged in to leave comments.
Login now