Skip to content

Commit

Permalink
Merge #3014
Browse files Browse the repository at this point in the history
3014: feat: add #[pyo3(get, set)] for Cell r=davidhewitt a=AntoineRR

This fixes #2659.
The types for which `#[pyo3(get, set)]` should now work are `Cell`, `Arc` and `Box`.

There is one issue regarding `Box`, the implementation of `FromPyObject` conflicts with another one. I could not find what the issue was, especially since the other implementations for `Arc` and `Cell` work as expected. The related code and test has been commented out for now. Maybe someone could help me fix this issue if I don't figure it out myself? There is also the possibility to remove the implementation for `Box` of course.


Co-authored-by: Antoine Romero-Romero <ant.romero2@orange.fr>
  • Loading branch information
bors[bot] and AntoineRR authored Mar 10, 2023
2 parents b8bf93b + a629e82 commit dd64981
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 0 deletions.
2 changes: 2 additions & 0 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ To use these annotations, your field type must implement some conversion traits:
- For `get` the field type must implement both `IntoPy<PyObject>` and `Clone`.
- For `set` the field type must implement `FromPyObject`.

For example, implementations of those traits are provided for the `Cell` type, if the inner type also implements the trait. This means you can use `#[pyo3(get, set)]` on fields wrapped in a `Cell`.

### Object properties using `#[getter]` and `#[setter]`

For cases which don't satisfy the `#[pyo3(get, set)]` trait requirements, or need side effects, descriptor methods can be defined in a `#[pymethods]` `impl` block.
Expand Down
1 change: 1 addition & 0 deletions newsfragments/3014.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add an `IntoPy<PyObject>`, `ToPyObject` and `FromPyObject` impl for `Cell`.
19 changes: 19 additions & 0 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::types::PyTuple;
use crate::{
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
};
use std::cell::Cell;
use std::ptr::NonNull;

/// Returns a borrowed pointer to a Python object.
Expand Down Expand Up @@ -370,6 +371,24 @@ where
}
}

impl<T: Copy + ToPyObject> ToPyObject for Cell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
self.get().to_object(py)
}
}

impl<T: Copy + IntoPy<PyObject>> IntoPy<PyObject> for Cell<T> {
fn into_py(self, py: Python<'_>) -> PyObject {
self.get().into_py(py)
}
}

impl<'a, T: FromPyObject<'a>> FromPyObject<'a> for Cell<T> {
fn extract(ob: &'a PyAny) -> PyResult<Self> {
T::extract(ob).map(Cell::new)
}
}

impl<'a, T> FromPyObject<'a> for &'a PyCell<T>
where
T: PyClass,
Expand Down
27 changes: 27 additions & 0 deletions tests/test_getter_setter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![cfg(feature = "macros")]

use std::cell::Cell;

use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyList};
Expand Down Expand Up @@ -189,3 +191,28 @@ fn get_all_and_set() {
py_run!(py, inst, "inst.num = 20; assert inst.num == 20");
});
}

#[pyclass]
struct CellGetterSetter {
#[pyo3(get, set)]
cell_inner: Cell<i32>,
}

#[test]
fn cell_getter_setter() {
let c = CellGetterSetter {
cell_inner: Cell::new(10),
};
Python::with_gil(|py| {
let inst = Py::new(py, c).unwrap().to_object(py);
let cell = Cell::new(20).to_object(py);

py_run!(py, cell, "assert cell == 20");
py_run!(py, inst, "assert inst.cell_inner == 10");
py_run!(
py,
inst,
"inst.cell_inner = 20; assert inst.cell_inner == 20"
);
});
}

0 comments on commit dd64981

Please sign in to comment.