How to use Rust structs as parameters in pyfunction #3242
-
I've defined some type in Rust that I want to use to interface with Python but when trying to use a pyfunction that consumes the type I receive this error.
This is the code to reproduce the issue. use pyo3::prelude::*;
use pyo3::types::IntoPyDict;
#[pyclass]
#[derive(FromPyObject)]
struct ComponentHandle {
system: u32,
component: u32,
}
#[pymethods]
impl ComponentHandle {
#[new]
fn init() -> Self {
ComponentHandle { system: 0, component: 0 }
}
fn __repr__(&self) -> String {
format!(
"ComponentHandle({}, {})",
self.system, self.component
)
}
fn __str__(&self) -> String {
self.__repr__()
}
}
#[pyfunction]
fn print_component_handle(component_handle: ComponentHandle) {
println!("Component handle: {} {}", component_handle.system, component_handle.component);
}
#[pymodule]
fn my_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<ComponentHandle>()?;
m.add_function(wrap_pyfunction!(print_component_handle, m)?)?;
Ok(())
}
fn main() -> PyResult<()> {
pyo3::append_to_inittab!(my_module);
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let handle = ComponentHandle { system: 7, component: 8 };
let pyhandle = Py::new(py, handle)?;
let locals = vec![("handle", pyhandle)].into_py_dict(py);
let code = "import my_module; print(handle); my_module.print_component_handle(handle);";
Python::run(py, code, None, Some(locals))?;
Ok(())
})
} The |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 4 replies
-
I think the problem is the (The derived (Maybe we should prevent that compiling but theoretically it could be used.) |
Beta Was this translation helpful? Give feedback.
I think the problem is the
#[derive(FromPyObject)]
which usually doesn't make sense for a#[pyclass]
because it does not need to be converted from its Python representation as it can be accessed as it is. But not as a plain type, but rather by acceptingPy<ComponentHandle>
orPyRef(Mut)<ComponentHandle>
which will give you access to the instance in-place stored on the Python heap.(The derived
FromPyObject
actually tries to create a newComponentHandle
by filling in its field from attributes of any given Python object which is where the confusing error comes from.)(Maybe we should prevent that compiling but theoretically it could be used.)