use pyo3::prelude::*; use pyo3::py_run; use pyo3::types::{IntoPyDict, PyList}; use std::isize; mod common; #[pyclass] struct ClassWithProperties { num: i32, } #[pymethods] impl ClassWithProperties { fn get_num(&self) -> PyResult { Ok(self.num) } #[getter(DATA)] /// a getter for data fn get_data(&self) -> PyResult { Ok(self.num) } #[setter(DATA)] fn set_data(&mut self, value: i32) -> PyResult<()> { self.num = value; Ok(()) } #[getter] /// a getter with a type un-wrapped by PyResult fn get_unwrapped(&self) -> i32 { self.num } #[setter] fn set_unwrapped(&mut self, value: i32) { self.num = value; } #[getter] fn get_data_list<'py>(&self, py: Python<'py>) -> &'py PyList { PyList::new(py, &[self.num]) } } #[test] fn class_with_properties() { let gil = Python::acquire_gil(); let py = gil.python(); let inst = Py::new(py, ClassWithProperties { num: 10 }).unwrap(); py_run!(py, inst, "assert inst.get_num() == 10"); py_run!(py, inst, "assert inst.get_num() == inst.DATA"); py_run!(py, inst, "inst.DATA = 20"); py_run!(py, inst, "assert inst.get_num() == 20 == inst.DATA"); py_run!(py, inst, "assert inst.get_num() == inst.unwrapped == 20"); py_run!(py, inst, "inst.unwrapped = 42"); py_run!(py, inst, "assert inst.get_num() == inst.unwrapped == 42"); py_run!(py, inst, "assert inst.data_list == [42]"); let d = [("C", py.get_type::())].into_py_dict(py); py.run( "assert C.DATA.__doc__ == 'a getter for data'", None, Some(d), ) .unwrap(); } #[pyclass] struct GetterSetter { #[pyo3(get, set)] num: i32, #[pyo3(get, set)] text: String, } #[pymethods] impl GetterSetter { fn get_num2(&self) -> PyResult { Ok(self.num) } } #[test] fn getter_setter_autogen() { let gil = Python::acquire_gil(); let py = gil.python(); let inst = Py::new( py, GetterSetter { num: 10, text: "Hello".to_string(), }, ) .unwrap(); py_run!(py, inst, "assert inst.num == 10"); py_run!(py, inst, "inst.num = 20; assert inst.num == 20"); py_run!( py, inst, "assert inst.text == 'Hello'; inst.text = 'There'; assert inst.text == 'There'" ); }