How can I test rust functions wrapped by pyo3 in rust, before building and installing in python?

28 Views Asked by At

I have functionality written in rust, which I am exposing to python via pyo3. I would like to test that the python functions are correctly exposed and handle python types correctly.

I already have tests in place to validate the actual functional implementation (in rust) and the end-to-end integration (in python).

How can I test the pyo3 python functions in rust?

1

There are 1 best solutions below

0
MusicalNinja On

This is covered in the pyo3 documentation in 3.4 Executing existing Python code - Want to embed Python in Rust with additional modules? and the preceding sections although the documentation does not contain a complete example.

Within lib.rs which contains the #[pymodule] and #[pyfunction] you can add:

#[cfg(test)]
mod tests {
    use pyo3::exceptions::PyTypeError;

    use super::*;

    #[test]
    fn test_fizzbuzz() {
        pyo3::append_to_inittab!(py_fizzbuzzo3);
        pyo3::prepare_freethreaded_python();
        Python::with_gil(|py| {
            let fizzbuzzo3 = py
                .import_bound("fizzbuzzo3")
                .expect("Failed to import fizzbuzzo3");
            let fizzbuzz = fizzbuzzo3
                .getattr("fizzbuzz")
                .expect("Failed to get fizzbuzz function");
            let result: PyResult<String> = match fizzbuzz.call1((1i32,)) {
                Ok(r) => r.extract(),
                Err(e) => Err(e),
            };
            let result = result.unwrap();
            let expected_result = "1";
            assert_eq!(result, expected_result);
        });
    }
}
  • pyo3::append_to_inittab!(py_fizzbuzzo3); makes the python module from the same file available and must be called before initialising the python interpreter
  • let fizzbuzzo3 = py.import_bound("fizzbuzzo3").expect("Failed to import fizzbuzzo3"); then imports the module
  • let fizzbuzz = fizzbuzzo3.getattr("fizzbuzz").expect("Failed to get fizzbuzz function"); assigns the python function to a variable so that:
  • fizzbuzz.call1((1i32,)) can then be used to call the function