-
-
Notifications
You must be signed in to change notification settings - Fork 551
/
Copy pathmessages.ts
401 lines (373 loc) Β· 9.48 KB
/
messages.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
import uuid from "uuid/v4";
import {
BasicOutputMessageContent,
ExecuteRequest,
JupyterMessage,
JupyterMessageHeader,
MessageType,
UpdateDisplayData,
UpdateDisplayDataContent
} from "./types";
export type Channel = "shell" | "iopub" | "stdin";
/**
* Returns which channel, iopub or stdin or shell, to send a kernel message
* through.
*
* @param messageType The message type to fetch a channel for
*
* @returns The channel to send a kernel message through
*/
function whichChannel(messageType?: MessageType): Channel {
switch (messageType) {
case "execute_request":
case "inspect_request":
case "kernel_info_request":
case "complete_request":
case "history_request":
case "is_complete_request":
case "comm_info_request":
case "shutdown_request":
return "shell";
case "display_data":
case "stream":
case "update_display_data":
case "execute_input":
case "execute_result":
case "error":
case "status":
case "clear_output":
return "iopub";
case "input_request":
case "input_reply":
return "stdin";
default:
// We fallthrough to handle the comm messages separately as well as
// unknown message types
break;
}
// NOTE: The Kernel listens for COMM messages on the Shell channel,
// and the Frontend listens for them on the IOPub channel.
// HACK: Since nteract is only frontends at the moment, no kernels implemented
// we simply assume this is destined for a frontend. Revisit as needed.
if (
messageType === "comm_open" ||
messageType === "comm_msg" ||
messageType === "comm_close"
) {
return "shell";
}
// Likely safe to assume the message goes on shell
// the developer can override this otherwise
return "shell";
}
/**
* Returns a fully-formatted kernel message.
*
* @param header An object containing the message type and session information
* @param content The message type-specific contents to send in the kernel message
*
* @returns The fully-formatted kernel message
*/
export function message<MT extends MessageType>(
header: { msg_type: MT; username?: string; session?: string },
content: object = {}
): JupyterMessage<MT> {
const channel: Channel = whichChannel(header.msg_type);
return {
header: {
msg_id: uuid(),
date: new Date().toISOString(),
version: "5.2",
// These fields _should_ get overridden by those provided in `header`
// We supply them as a fallback here
username: header.username || "nteract",
msg_type: header.msg_type,
session: header.session || uuid()
},
metadata: {},
parent_header: {},
content,
channel,
buffers: new Uint8Array()
};
}
/**
* Creates a header for a kernel message of a given type.
*
* @param msg_type The message type to create a header for
*
* @returns A complete header for the message
*/
function createHeader<MT extends MessageType>(
msg_type: MT
): JupyterMessageHeader<MT> {
return {
msg_id: uuid(),
date: new Date().toISOString(),
version: "5.2",
msg_type,
// These fields get overridden by enchannel implementations, we supply them
// as a fallback here
username: "nteract",
session: uuid()
};
}
/**
* An execute request creator
*
* > executeRequest('print("hey")', { 'silent': true })
* { header:
* { msg_id: 'f344cc6b-4308-4405-a8e8-a166b0345579',
* date: 2017-10-23T22:33:39.970Z,
* version: '5.0',
* msg_type: 'execute_request',
* username: 'kyle',
* session: '123' },
* metadata: {},
* parent_header: {},
* content:
* { code: 'print("hey")',
* silent: false,
* store_history: true,
* user_expressions: {},
* allow_stdin: true,
* stop_on_error: false } }
*
* @param code The code to execute
* @param options The options for the execute request
*
* @returns A complete execute_request message
*/
export function executeRequest(
code: string = "",
options: {
silent?: boolean;
store_history?: boolean;
user_expressions?: object;
allow_stdin?: boolean;
stop_on_error?: boolean;
} = {}
): ExecuteRequest {
const channel: Channel = whichChannel("execute_request");
return {
header: createHeader("execute_request"),
metadata: {},
parent_header: {},
content: {
code,
silent: false,
store_history: true,
user_expressions: {},
allow_stdin: true,
stop_on_error: false,
...options
},
channel,
buffers: new Uint8Array()
};
}
////// OUTPUT MESSAGE TYPES //////
/**
* Creates a display_data message.
*
* ref: http://jupyter-client.readthedocs.io/en/stable/messaging.html#display-data
* > displayData({username: 'rgbkrk', session: '123'}, {data: {'text/html': '<b>sup</b>'}}, "display_data")
* { header:
* { msg_id: '24e95ce7-73d5-4c5f-9ef0-ff8547779690',
* date: 2017-10-23T22:57:58.704Z,
* version: '5.1',
* msg_type: 'display_data',
* username: 'rgbkrk',
* session: '123' },
* metadata: {},
* parent_header: {},
* content:
* { data: { 'text/html': '<b>sup</b>' },
* metadata: {},
* transient: {} } }
*/
// Overload 1: with second parameter
export function displayData<
C extends BasicOutputMessageContent,
T extends MessageType
>(content: C, msg_type: T): JupyterMessage<T, C>;
// Overload 2: without second parameter (required to get TS to behave)
export function displayData<C extends BasicOutputMessageContent>(
content: C,
msg_type?: undefined
): JupyterMessage<"display_data", C>;
// The actual displayData function; generics should infer correctly, based on
// the overloads above.
export function displayData(
content: BasicOutputMessageContent,
msg_type?: MessageType
): JupyterMessage {
if (msg_type === undefined) {
msg_type = "display_data";
}
return message(
{
msg_type
},
{
data: {},
metadata: {},
transient: {},
...content
}
);
}
/**
* Creates an update_display_data message.
*
* http://jupyter-client.readthedocs.io/en/stable/messaging.html#update-display-data
*/
export function updateDisplayData(
content: UpdateDisplayDataContent
): UpdateDisplayData {
// TODO: Enforce the transient display_id here?
return displayData(content, "update_display_data");
}
/**
* Creates a message containing information about the result of an execution.
*
* http://jupyter-client.readthedocs.io/en/stable/messaging.html#id6
*/
export function executeResult(content: {
execution_count: number;
data?: object;
metadata?: object;
transient?: object;
}) {
// TODO: Enforce the transient display_id here?
const m = displayData(content, "execute_result");
m.content.execution_count = content.execution_count;
return m;
}
/**
* Creates an error message to indicate when an exception has occurred during
* code execution.
*
* http://jupyter-client.readthedocs.io/en/stable/messaging.html#execution-errors
*/
export function error(content: {
ename?: string;
evalue?: string;
traceback?: string[];
}) {
return message(
{
msg_type: "error"
},
{
ename: "",
evalue: "",
traceback: [],
...content
}
);
}
/**
* Creates a stream message.
*
* http://jupyter-client.readthedocs.io/en/stable/messaging.html#streams-stdout-stderr-etc
*
* @param content The message type and its contents.
*/
export function stream(content: { name: "stdout" | "stderr"; text: string }) {
return message(
{
msg_type: "stream"
},
content
);
}
///// EXECUTE_REPLY /////
/**
* Creates a message containing the response from a kernel execute request.
*
* http://jupyter-client.readthedocs.io/en/stable/messaging.html#execution-results
*/
export function executeReply(content: {
status: string;
execution_count: number;
payload?: object[];
user_expressions?: object;
}) {
// TODO: This function could be better typed. It's a bit dual headed though since:
// * `status: ok` carries payloads
// * `status: error` carries error info that is also in error output
return message(
{
msg_type: "execute_reply"
},
content
);
}
/**
* Creates a status message published by the kernel to indicate its state.
*
* @param execution_state The kernel's execution state
*/
export function status(execution_state: "busy" | "idle" | "starting") {
return message(
{
msg_type: "status"
},
{
execution_state
}
);
}
/**
*
* @param content
*/
export function clearOutput(content?: { wait: boolean }) {
return message(
{
msg_type: "clear_output"
},
content
);
}
/**
*
* @param content
*/
export function executeInput(content: {
code: string;
execution_count: number;
}) {
return message(
{
msg_type: "execute_input"
},
content
);
}
/**
* Creates a message to request information about a kernel.
*
* @returns A kernel_info_request message
*/
export function kernelInfoRequest() {
return message({ msg_type: "kernel_info_request" });
}
/**
* Creates a message to request the shutdown of a kernel.
*
* @param content An options object containing whether or not to restart the kernel
*
* @returns A shutdown_request message
*/
export function shutdownRequest(
content: { restart?: boolean } = { restart: false }
): JupyterMessage<"shutdown_request", { restart?: boolean }> {
return message({ msg_type: "shutdown_request" }, content);
}
export function inputReply(content: {
value: string;
}): JupyterMessage<"input_reply"> {
return message({ msg_type: "input_reply" }, content);
}