I am trying to implement a cache for the private variable of any python class.
Let's suppose I have this:
#[pyclass]
struct ClassA {
pv: Py<PyAny>, // GIL independent type, storable in another #[pyclass]
field_a: Py<PyAny>,
}
#[pyclass]
struct ClassB {
class_a: Py<ClassA>,
field_b: Py<PyAny>,
}
In the impls of ClassA, I have a method attempting to 'put' a reference of the ClassA object into the ClassB's class_a field. And return a newly instantiated ClassB object.
#[pymethods]
impl ClassA {
fn ret_class_b {&self, field_b: &PyAny) -> PyResult<ClassB> {
let class_a: Py<ClassA> = Py::clone_ref(self, field_b.py());
ClassB {
class_a: class_a,
field_b: field_b.into_py(),
}
}
}
The above does not compile.
The issue is how do I get &Py<ClassA> from the receiver of the method so as to return another object where the receiver is referred to as a field in that object?
Edit / Update
Thanks to @cafce25 for his reminder on giving fully reproducible codes and the error from the compiler.
Here is it:
use pyo3::{
prelude::{*, Py, PyAny},
};
#[pymodule]
fn stackoverflowqn(py: Python, pymod: &PyModule) -> PyResult<()> {
#[pyclass(name = "class_a")]
#[derive(Clone, Debug)]
pub struct ClassA {
pv: Option<Py<PyAny>>, // private value
field_a: Py<PyAny>,
}
#[pyclass]
#[derive(Clone, Debug)]
pub struct ClassB {
class_a: Py<ClassA>,
field_b: Py<PyAny>,
}
#[pymethods]
impl ClassA {
#[new]
pub fn __new__(_slf: PyRef<'_, Self>, field_a: PyObject) -> PyResult<ClassA> {
Ok(ClassA {
pv: None,
field_a: field_a,
})
}
fn ret_class_b {&self, field_b: &PyAny) -> PyResult<ClassB> {
let class_a: Py<ClassA> = Py::clone_ref(self, field_b.py());
Ok(ClassB {
class_a: class_a,
field_b: field_b.into_py(),
})
}
}
}
Here is the compiler error:
error[E0277]: the trait bound `ClassA: pyo3::IntoPy<pyo3::Py<ClassA>>` is not satisfied
--> crates\cached-property\src\stackoverflow.rs:36:53
|
36 | pyo3::IntoPy::<Py<ClassA>>::into_py(pty_getter, py);
| ----------------------------------- ^^^^^^^^^^ the trait `pyo3::IntoPy<pyo3::Py<ClassA>>` is not implemented for `ClassA`
| |
| required by a bound introduced by this call
|
= help: the trait `pyo3::IntoPy<pyo3::Py<PyAny>>` is implemented for `ClassA`
If I understood correctly your problem is constructing
Py<ClassA>from&ClassAavailable in your method through&self. I think what you are looking for is a change in your method signature. There is little documentation on this in the user guide, but if you look at the examples inPyRefyou see that you can pass an instance ofPyRef<'_, Self>into your method instead of&self:You can convert
PyRefinto aPypointer simply by calling.into().I've made some changes to your example and this compiles on my computer: