Day 58 — I miss the Python standard library
01 November 2020 · recurse-center TweetToday I worked on translating cutypr to Rust.
I found that I could use pyo3 to start the IPython kernel from Rust! So I wrote a start_kernel()
Python function to start the IPython kernel, returned some useful information (the key required to sign messages + ports for all kernel channels) from it, and then called it from Rust using pyo3
!
fn start_kernel(py: Python) -> Value {
let locals = [("jupyterm", py.import("jupyterm").unwrap())].into_py_dict(py);
let code = "jupyterm.start_kernel()";
let kernel_info_str: &str = py
.eval(code, None, Some(&locals))
.unwrap()
.extract()
.unwrap();
let kernel_info: Value = serde_json::from_str(kernel_info_str).unwrap();
kernel_info
}
fn main() {
let mut kernel_info: Value = serde_json::from_str("{}").unwrap();
// start the Python kernel
// TODO: also shut it down
Python::with_gil(|py| {
kernel_info = start_kernel(py);
});
}
I still need to figure out how to shutdown the kernel after everything is done though!
After that I looked into how to create a REPL in Rust. These are some things I missed from Python and its standard library:
- The
input()
function: Getting user input in Python is very straightforward with theinput()
function. It also supports adding prompts, likeinput(">>> ")
. I couldn't find something similar (maybe aninput!
macro?) in Rust. There are multiple crates that implement some form of this though. I foundread-human
in this forum answer, and reused its code directly.
If you want to get user input (and also print a prompt), you need to first print the prompt using theprint!
macro, and then get the input usingio::stdin().read_line
:
use std::io::{self, Write};
fn main() {
let mut code = String::new();
loop {
code.clear();
print!(">>> ");
io::stdout().flush().unwrap();
io::stdin().read_line(&mut code).unwrap();
}
}
dir()
andtype()
functions: When debugging Python code, I usually fire up the REPL and usedir()
to look at all the things an object provides, andtype()
to check types of variables.
I found this Rust REPL, thisprint_type_of()
function, and the:?
formatting marker forprintln!
pretty useful for debugging though!
fn print_type_of(_: &T) {
println!("{}", std::any::type_name::())
}
-
json
anddatetime
modules: In Rust, serde seems to be the most widely used crate to serialize/deserialize data. I need to look for a nice alternative to the Pythondatetime
module. (os
andpathlib
modules too!) -
hmac
andhashlib
modules: I used these modules yesterday to sign messages before sending them to the IPython kernel.
I found thehmac
andsha2
crates, but their final result does not seem to be a primitive Rust type. It's something called aGenericArray
, which comes from another crate! I need to figure out how to use it.
>> print_type_of(&code_bytes);
generic_array::GenericArray, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>>