jupyter_client/
commands.rs

1/*! Available commands to send to the kernel.
2
3These should be constructed, and then sent to the kernel via
4[`Client::send_shell_command`][send-shell-command] or
5[`Client::send_control_command`][send-control-command].
6
7[send-shell-command]: ../struct.Client.html#method.send_shell_command
8[send-control-command]: ../struct.Client.html#method.send_control_command
9*/
10use errors::Result;
11use header::Header;
12use hmac::Mac;
13use log::trace;
14use serde::{Serialize as SerdeSerialize, Serializer};
15use serde_derive::Serialize;
16use serde_json::json;
17use std::collections::HashMap;
18use std::fmt::Debug;
19use wire::WireMessage;
20
21/** Available commands.
22 */
23#[derive(Serialize, Debug)]
24#[serde(untagged)]
25pub enum Command {
26    /// Ask for information about the running kernel
27    KernelInfo,
28    /// Execute a specific command
29    Execute {
30        /// Source code to be executed by the kernel, one or more lines.
31        code: String,
32        /** A boolean flag which, if `true`, signals the kernel to execute
33        this code as quietly as possible.  `silent=true` forces `store_history` to be `false`, and
34        will *not*:
35        - broadcast output on the IOPub channel
36        - have an execute_result
37        The default is `false`.
38        */
39        silent: bool,
40        /** A boolean flag which, if `true`, signals the kernel to populate history
41        The default is `true` if silent is `false`.  If silent is `true`, `store_history` is forced
42        to be `false`.
43        */
44        store_history: bool,
45        /** A `HashMap` mapping names to expressions to be evaluated in the
46        user's `HashMap`. The rich display-data representation of each will be evaluated after
47        execution.  See the `display_data` content for the structure of the representation data.
48        */
49        user_expressions: HashMap<String, String>,
50        /** Some frontends do not support stdin requests.
51        If this is true, code running in the kernel can prompt the user for input with an
52        `input_request` message. If it is `false`, the kernel should not send these messages.
53        */
54        allow_stdin: bool,
55        /** A boolean flag, which, if `true`, does not abort the execution queue, if an exception
56         * is encountered.
57        This allows the queued execution of multiple `execute_requests`, even if they generate
58        exceptions.
59        */
60        stop_on_error: bool,
61    },
62    /// Perform introspection into a piece of code.
63    Inspect {
64        /** The code context in which introspection is requested
65        this may be up to an entire multiline cell.
66        */
67        code: String,
68
69        /** The cursor position within 'code' (in unicode characters) where inspection is requested
70         */
71        cursor_pos: u64,
72
73        /** The level of detail desired.  In IPython, the default (0) is equivalent to typing
74        'x?' at the prompt, 1 is equivalent to 'x??'.
75        The difference is up to kernels, but in IPython level 1 includes the source code
76        if available.
77        */
78        detail_level: DetailLevel,
79    },
80    /// Ask the kernel to complete the code at the cursor.
81    Complete {
82        /** The code context in which completion is requested
83        this may be up to an entire multiline cell, such as
84        'foo = a.isal'
85        */
86        code: String,
87
88        /** The cursor position within 'code' (in unicode characters) where completion is requested
89         */
90        cursor_pos: u64,
91    },
92    /// Fetch history from the kernel.
93    History {
94        /// If True, also return output history in the resulting dict.
95        output: bool,
96
97        /// If True, return the raw input history, else the transformed input.
98        raw: bool,
99
100        /** So far, this can be `range`, `tail` or `search`.
101        If `hist_access_type` is `range`, get a range of input cells. session
102        is a number counting up each time the kernel starts; you can give
103        a positive session number, or a negative number to count back from
104        the current session.
105        `start` and `stop` are line (cell) numbers within that session.
106        If `hist_access_type` is 'tail' or 'search', get the last n cells.
107        If `hist_access_type` is 'search', get cells matching the specified glob
108        pattern (with * and ? as wildcards).
109        */
110        hist_access_type: HistoryAccessType,
111
112        /** If `hist_access_type` is 'search' and unique is true, do not
113          include duplicated history.  Default is false.
114          */
115        unique: bool,
116    },
117    /// Ask the kernel if the current code is complete
118    IsComplete {
119        /// The code entered so far as a multiline string
120        code: String,
121    },
122    /// Tell the kernel to shutdown.
123    Shutdown {
124        /// False if final shutdown, or True if shutdown precedes a restart
125        restart: bool,
126    },
127    /// Fetch comm info.
128    CommInfo {
129        /// The target name
130        target_name: Option<String>,
131    },
132}
133
134impl Command {
135    pub(crate) fn into_wire<M: Mac + Debug>(self, auth: M) -> Result<WireMessage<M>> {
136        let msg = match self {
137            Command::KernelInfo => {
138                let header = Header::new("kernel_info_request");
139                let header_bytes = header.to_bytes()?;
140                Ok(WireMessage {
141                    header: header_bytes.to_vec(),
142                    parent_header: b"{}".to_vec(),
143                    metadata: b"{}".to_vec(),
144                    content: b"{}".to_vec(),
145                    auth,
146                })
147            }
148            r @ Command::Execute { .. } => {
149                let header = Header::new("execute_request");
150                let header_bytes = header.to_bytes()?;
151                let content_str = serde_json::to_string(&r)?;
152                let content = content_str.into_bytes();
153
154                Ok(WireMessage {
155                    header: header_bytes.to_vec(),
156                    parent_header: b"{}".to_vec(),
157                    metadata: b"{}".to_vec(),
158                    content,
159                    auth,
160                })
161            }
162            r @ Command::Inspect { .. } => {
163                let header = Header::new("inspect_request");
164                let header_bytes = header.to_bytes()?;
165                let content_str = serde_json::to_string(&r)?;
166                let content = content_str.into_bytes();
167
168                Ok(WireMessage {
169                    header: header_bytes.to_vec(),
170                    parent_header: b"{}".to_vec(),
171                    metadata: b"{}".to_vec(),
172                    content,
173                    auth,
174                })
175            }
176            r @ Command::Complete { .. } => {
177                let header = Header::new("complete_request");
178                let header_bytes = header.to_bytes()?;
179                let content_str = serde_json::to_string(&r)?;
180                let content = content_str.into_bytes();
181
182                Ok(WireMessage {
183                    header: header_bytes.to_vec(),
184                    parent_header: b"{}".to_vec(),
185                    metadata: b"{}".to_vec(),
186                    content,
187                    auth,
188                })
189            }
190            Command::History {
191                output,
192                raw,
193                hist_access_type,
194                unique,
195            } => {
196                let header = Header::new("history_request");
197                let header_bytes = header.to_bytes()?;
198
199                let content = match hist_access_type {
200                    HistoryAccessType::Tail { n } => json!({
201                        "output": output,
202                        "raw": raw,
203                        "unique": unique,
204                        "hist_access_type": "tail",
205                        "session": null,
206                        "start": null,
207                        "stop": null,
208                        "n": n,
209                        "pattern": null,
210                    }),
211                    HistoryAccessType::Range {
212                        session,
213                        start,
214                        stop,
215                    } => json!({
216                            "output": output,
217                            "raw": raw,
218                            "unique": unique,
219                            "hist_access_type": "tail",
220                            "session": session,
221                            "start": start,
222                            "stop": stop,
223                            "n": null,
224                            "pattern": null,
225                    }),
226                    HistoryAccessType::Search { pattern } => json!({
227                            "output": output,
228                            "raw": raw,
229                            "unique": unique,
230                            "hist_access_type": "tail",
231                            "session": null,
232                            "start": null,
233                            "stop": null,
234                            "n": null,
235                            "pattern": pattern,
236                    }),
237                };
238
239                let content_str = serde_json::to_string(&content)?;
240                let content = content_str.into_bytes();
241
242                Ok(WireMessage {
243                    header: header_bytes.to_vec(),
244                    parent_header: b"{}".to_vec(),
245                    metadata: b"{}".to_vec(),
246                    content,
247                    auth,
248                })
249            }
250            Command::IsComplete { code } => {
251                let header = Header::new("is_complete_request");
252                let header_bytes = header.to_bytes()?;
253
254                let content_json = json!({
255                    "code": code,
256                });
257                let content_str = serde_json::to_string(&content_json)?;
258                let content = content_str.into_bytes();
259
260                Ok(WireMessage {
261                    header: header_bytes.to_vec(),
262                    parent_header: b"{}".to_vec(),
263                    metadata: b"{}".to_vec(),
264                    content: content,
265                    auth,
266                })
267            }
268            Command::Shutdown { restart } => {
269                let header = Header::new("shutdown_request");
270                let header_bytes = header.to_bytes()?;
271                let content_json = json!({
272                    "restart": restart,
273                });
274                let content_str = serde_json::to_string(&content_json)?;
275                let content = content_str.into_bytes();
276
277                Ok(WireMessage {
278                    header: header_bytes.to_vec(),
279                    parent_header: b"{}".to_vec(),
280                    metadata: b"{}".to_vec(),
281                    content,
282                    auth,
283                })
284            }
285            Command::CommInfo { target_name } => {
286                let header = Header::new("comm_info_request");
287                let header_bytes = header.to_bytes()?;
288                let content_json = match target_name {
289                    Some(target_name) => json!({
290                        "target_name": target_name,
291                    }),
292                    None => json!({}),
293                };
294                let content_str = serde_json::to_string(&content_json)?;
295                let content = content_str.into_bytes();
296
297                Ok(WireMessage {
298                    header: header_bytes.to_vec(),
299                    parent_header: b"{}".to_vec(),
300                    metadata: b"{}".to_vec(),
301                    content,
302                    auth,
303                })
304            }
305        };
306
307        trace!("creating message {:?}", msg);
308        msg
309    }
310}
311
312/// Type of history requested.
313#[derive(Serialize, Debug)]
314pub enum HistoryAccessType {
315    /// Get the last `n` cells.
316    Tail {
317        /// Number of cells requested.
318        n: u64,
319    },
320    /// Get the range of cells associated with a session within a range.
321    Range {
322        /// Session to query for.
323        session: i64,
324        /// Start of the range
325        start: u64,
326        /// End of the range.
327        stop: u64,
328    },
329    /// Search for history items matching a pattern.
330    Search {
331        /// Pattern to search for.
332        pattern: String,
333    },
334}
335
336/// Level of detail requested when requesting code introspection
337#[derive(Debug)]
338pub enum DetailLevel {
339    /** Equivalent to IPython's `?` operator.
340
341    Typically fetches the documentation.
342    */
343    Zero,
344    /** Equivalent to IPython's `??` operator.
345
346    Typically fetches the source code.
347    */
348    One,
349}
350
351impl SerdeSerialize for DetailLevel {
352    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
353    where
354        S: Serializer,
355    {
356        match *self {
357            DetailLevel::Zero => serializer.serialize_i32(0),
358            DetailLevel::One => serializer.serialize_i32(1),
359        }
360    }
361}