I'm new to Rust and I have a problem. I have list in Python. It is a list of objects implemented in PyO3 Rust. I want to pass it to a function to make some changes to the elements.
This is minimal reproducible example:
use pyo3::prelude::*;
#[pyclass]
pub struct ListElement {
pub value_sum: f32
}
#[pymethods]
impl ListElement {
#[new]
fn new(value_sum: f32) -> Self {
ListElement { value_sum }
}
fn add_value(&mut self, value: f32) {
self.value_sum += value;
}
}
#[pyfunction]
fn modify_list_elements(list: Vec<&ListElement>, value: f32){
for mut elem in list {
elem.add_value(value);
}
}
#[pymodule]
fn my_rust_module(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<ListElement>()?;
m.add_function(wrap_pyfunction!(modify_list_elements, m)?)?;
Ok(())
}
this is my Cargo.toml
[package]
name = "my_rust_module"
version = "0.1.0"
edition = "2018"
[lib]
# The name of the native library. This is the name which will be used in Python to import the
# library (i.e. `import string_sum`). If you change this, you must also change the name of the
# `#[pymodule]` in `src/lib.rs`.
name = "my_rust_module"
# "cdylib" is necessary to produce a shared library for Python to import from.
#
# Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
# to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:
# crate-type = ["cdylib", "rlib"]
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.19.0", features = ["extension-module"] }
This is error that I get when I use
maturin develop
🔗 Found pyo3 bindings
🐍 Found CPython 3.7 at C:\my_paths\python.exe
📡 Using build options features from pyproject.toml
Compiling my_rust_module v0.1.0 (C:\my_paths\my_rust_module)
error[E0277]: the trait bound `Vec<&ListElement>: FromPyObject<'_>` is not satisfied
--> src\lib.rs:22:31
|
22 | fn modify_list_elements(list: Vec<&ListElement>, value: f32){
| ^^^ the trait `FromPyObject<'_>` is not implemented for `Vec<&ListElement>`
|
= help: the trait `FromPyObject<'a>` is implemented for `Vec<T>`
= note: required for `Vec<&ListElement>` to implement `PyFunctionArgument<'_, '_>`
note: required by a bound in `extract_argument`
--> C:\my_paths\.cargo\registry\src\index.crates.io-6f17d22bba15001f\pyo3-0.19.0\src\impl_\extract_argument.rs:86:8
|
86 | T: PyFunctionArgument<'a, 'py>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument`
For more information about this error, try `rustc --explain E0277`.
I tried to google it, understand output of rustc --explain E0277, but I still dont know how to do it. Any help would be appreciated.
The problem here is that Vec<T>
only implements FromPyObject
if T
also does so, but &ListElement
doesn't implement that trait.
You can fix it in one of two ways:
#[pyclass]
#[derive(FromPyObject)]
pub struct ListElement {
pub value_sum: f32
}
Vec<PyRefMut<ListElement>>
instead for which FromPyObject
is automatically implemented by the pyclass
attribute:
#[pyfunction]
fn modify_list_elements(list: Vec<PyRefMut<ListElement>>, value: f32){
for mut elem in list {
elem.add_value(value);
}
}