Pyo3 switch to stable now gives error for method arguments: Vec<Mypyclass>

I made a pyo3 "wrapper" for the rust version of the python module I've ended up maintaining. (See rust_pi3d and the pyo3_module) I got this to work quite well, however there was no way I could see pyo3 being rolled out while it depended on nightly Rust. Now, however it doesn't, so I thought I would revisit the project and get it to compile with stable Rust.

I had to make a few changes because of things that had disappeared or been added to pyo3 but now I'm down to one compiler error which is:

error[E0277]: the trait bound `std::vec::Vec<&core::Texture>: pyo3::FromPyObject<'_>` is not satisfied
  --> src/shapes.rs:23:1
   |
23 | #[pymethods]
   | ^^^^^^^^^^^^ the trait `pyo3::FromPyObject<'_>` is not implemented for `std::vec::Vec<&core::Texture>`
   |
   = help: the following implementations were found:
             <std::vec::Vec<T> as pyo3::FromPyObject<'a>>
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

This happens several times where I have a class method that takes a list of one of my defined pyo3 classes as an argument. i.e. for the above error Texture is defined

#[pyclass]
//#[derive(FromPyObject)] // gives error: cannot find derive macro `FromPyObject` in this scope
pub struct Texture {
    pub r_texture: pi3d::texture::Texture,
}

(I tried to derive FromPyObject for Texture but the compiler didn't like that (use pyo3::prelude::* at the top)) The code generating the error above is

#[pymethods]
impl Shape {
...
    fn set_textures(&mut self, textures: Vec<&::core::Texture>) {
        let texlist = textures.iter().map(|t| t.r_texture.id).collect();
        self.r_shape.set_textures(&texlist);
    }
...

I've had a couple of goes at impl FromPyObject for Texture but all seem to generate a lot more errors. Other method arguments such as Vec<f32> don't seem to cause a problem. Is there something obvious I'm missing here?

As a stop-gap, I have managed to get the module to compile by doing something like:

    fn set_textures(&mut self, textures: &PyList) {
        let texlist = textures.iter().map(|t| t.extract::<::core::Texture>().unwrap().r_texture.id).collect();
        self.r_shape.set_textures(&texlist);
    }

However I had to impl Clone for Texture and the compiled code no longer works correctly. I suspect I need to return to just getting references as extract() scrambles the Textures.

EDIT - I have found that
a) I can compile the code and get the same scrambled effect as with PyList => extract() by switching to Vec<Texture> rather than Vec<&Texture> as the method argument.
b) The method compiles and works as it's supposed to if I pass individual Texture instances rather than a list of them (but obviously that's a breaking change on the python side):

    fn set_textures(&mut self, tex0: &::core::Texture, tex1: &::core::Texture) {
        let texlist = vec![tex0.r_texture.id, tex1.r_texture.id];
        self.r_shape.set_textures(&texlist);
    }

I feel this should be very easy to do, and probably obvious to someone involved with the latest improvements to pyo3 that allowed it to work without specialization!

2nd EDIT and ANSWER:

Thanks to David Hewitt see pyo3 question 1177 the answer is to use Vec<PyRef<Texture>>

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.