Pyo3: [More documentation] Loading and using python functions

Created on 14 Sep 2019  Â·  10Comments  Â·  Source: PyO3/pyo3

Can someone help me put together a full minimal example ?

I think it would be great to include it in the Readme in the "using python from rust" section which clearly lacks content.

It would create the basis for an app with the logic written in rust which rely on a few python functions. An example use case could be a machine learning (where almost everything is done with python libs) based app with some heavy post treatment that would benefit from being done in rust.

Here's my failed attempt :

main.rs

use std::include_str;
use pyo3::prelude::*;

fn main() -> PyResult<()> {
    let python_functions = include_str!("python-functions.py");

    let gil = Python::acquire_gil();
    let py = gil.python();

    py.eval(python_functions, None, None)?;

    let code = "test()";
    let res : String = py.eval(code, None, None)?.extract()?;


    println!("{}", res);

    Ok(())
}

python_functions.py

def test():
    return "hello"

it gives me Error: PyErr { type: Py(0x7ff14324ed60, PhantomData) } which isn't really a workable error.

The next step is to make a function that takes parameters and we'll be set !

All 10 comments

I think rust-numpy crate has a better example, but yeah, we need good examples in this area.

Thanks for pointing this out, it explains how to correctly output errors and that's useful.

However I think something is still off: when the code in the script relies on multiple lines it fails with a syntax error even though there is none (the script is correct and runs with python).

eval only accepts Python's expression(≒ one liner).
So if you want to run long code, you can use py_run or so but it returns None.

That's exactly the type of thing that the documentation is lacking, explaining basic high level stuff on what is used to do what. Thanks !

I'll make a PR as soon as I get some free time.

Also, I wrote an example to get an Python object using Python::run.

    use pyo3::types::{IntoPyDict, PyDict, PyList};
    let gil = Python::acquire_gil();
    let py = gil.python();
    let ret_dict = [("ret", py.None())].into_py_dict(py);
    py.run(
        r#"
l = [8, 7, 3, 4, 5]
l.sort()
ret = l
"#,
        None,
        Some(ret_dict),
    );
    let list: &PyList = ret_dict.get_item("ret").unwrap().downcast_ref().unwrap();
    let ret: Vec<i32> = list.extract().unwrap();
    assert_eq!(&ret, &[3, 4, 5, 7, 8]);

I think might actually want PyModule::from_code instead of eval or run. I'd be happy if someone contributed examples to the guide on how to use PyModule::import and PyModule::from_code.

@konstin
I updated #603 to include PyModule::from_code, please check it.

Hello guys I also has trouble in the example of using PyModule.
The piece of code is not work properly.

use pyo3::{prelude::*, types::{IntoPyDict, PyModule}};
let gil = Python::acquire_gil();
let py = gil.python();
let activators = PyModule::from_code(py, "
def relu(x):
    return max(0.0, x)

def leaky_relu(x, slope=0.01):
    return x if x >= 0 else x * slope
", "activators.py", "activators")?;
let relu_result: f64 = activators.call1("relu", (-1.0,))?.extract()?;
assert_eq!(relu_result, 0.0);
let kwargs = [("slope", 0.2)].into_py_dict(py);
let lrelu_result: f64 = activators
    .call("leaky_relu", (-1.0,), Some(kwargs))?
    .extract()?;
assert_eq!(lrelu_result, -0.2);

And I'm keep getting this error message, do I miss something?

螢幕快照 2019-10-06 20 01 00

I changed in this way but is still not working.

fn main() -> Result<(), ()> {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let activators = PyModule::from_code(py, "
    def relu(x):
        return max(0.0, x)

    def leaky_relu(x, slope=0.01):
        return x if x >= 0 else x * slope
    ", "activators.py", "activators")?;
    let relu_result: f64 = activators.call1("relu", (-1.0,))?.extract()?;
    assert_eq!(relu_result, 0.0);
    let kwargs = [("slope", 0.2)].into_py_dict(py);
    let lrelu_result: f64 = activators
        .call("leaky_relu", (-1.0,), Some(kwargs))?
        .extract()?;
    assert_eq!(lrelu_result, -0.2);
}

Please use PyResult<()> instead of Result<(), ()> and return Ok(()).

Closed by #603.

Was this page helpful?
0 / 5 - 0 ratings