Allow use of `#[pyo3(get, set)]` with `Py<T>`
This commit is contained in:
parent
dcab478d66
commit
3008528fa6
|
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
* `PyObject` and `Py<T>` reference counts are now decremented sooner after `drop()`. [#851](https://github.com/PyO3/pyo3/pull/851)
|
* `PyObject` and `Py<T>` reference counts are now decremented sooner after `drop()`. [#851](https://github.com/PyO3/pyo3/pull/851)
|
||||||
* When the GIL is held, the refcount is now decreased immediately on drop. (Previously would wait until just before releasing the GIL.)
|
* When the GIL is held, the refcount is now decreased immediately on drop. (Previously would wait until just before releasing the GIL.)
|
||||||
* When the GIL is not held, the refcount is now decreased when the GIL is next acquired. (Previously would wait until next time the GIL was released.)
|
* When the GIL is not held, the refcount is now decreased when the GIL is next acquired. (Previously would wait until next time the GIL was released.)
|
||||||
|
* `FromPyObject` for `Py<T>` now works for a wider range of `T`, in particular for `T: PyClass`. [#880](https://github.com/PyO3/pyo3/pull/880)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* `_PyDict_NewPresized`. [#849](https://github.com/PyO3/pyo3/pull/849)
|
* `_PyDict_NewPresized`. [#849](https://github.com/PyO3/pyo3/pull/849)
|
||||||
|
@ -21,6 +22,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
* `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839)
|
* `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839)
|
||||||
* Garbage Collector causing random panics when traversing objects that were mutably borrowed. [#855](https://github.com/PyO3/pyo3/pull/855)
|
* Garbage Collector causing random panics when traversing objects that were mutably borrowed. [#855](https://github.com/PyO3/pyo3/pull/855)
|
||||||
* `&'static Py~` being allowed as arguments. [#869](https://github.com/PyO3/pyo3/pull/869)
|
* `&'static Py~` being allowed as arguments. [#869](https://github.com/PyO3/pyo3/pull/869)
|
||||||
|
* `#[pyo3(get)]` for `Py<T>`. [#880](https://github.com/PyO3/pyo3/pull/880)
|
||||||
|
|
||||||
|
|
||||||
## [0.9.2]
|
## [0.9.2]
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::instance::PyNativeType;
|
||||||
use crate::pyclass::PyClass;
|
use crate::pyclass::PyClass;
|
||||||
use crate::pyclass_init::PyClassInitializer;
|
use crate::pyclass_init::PyClassInitializer;
|
||||||
use crate::types::{PyAny, PyDict, PyModule, PyTuple};
|
use crate::types::{PyAny, PyDict, PyModule, PyTuple};
|
||||||
use crate::{ffi, GILPool, IntoPy, PyCell, PyObject, Python};
|
use crate::{ffi, GILPool, IntoPy, Py, PyCell, PyObject, Python};
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
/// Description of a python parameter; used for `parse_args()`.
|
/// Description of a python parameter; used for `parse_args()`.
|
||||||
|
@ -215,6 +215,12 @@ impl GetPropertyValue for PyObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> GetPropertyValue for Py<T> {
|
||||||
|
fn get_property_value(&self, py: Python) -> PyObject {
|
||||||
|
self.clone_ref(py).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Utilities for basetype
|
/// Utilities for basetype
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait PyBaseTypeUtils {
|
pub trait PyBaseTypeUtils {
|
||||||
|
|
|
@ -295,13 +295,14 @@ where
|
||||||
|
|
||||||
impl<'a, T> FromPyObject<'a> for Py<T>
|
impl<'a, T> FromPyObject<'a> for Py<T>
|
||||||
where
|
where
|
||||||
T: AsPyPointer,
|
T: PyTypeInfo,
|
||||||
&'a T: 'a + FromPyObject<'a>,
|
&'a T::AsRefTarget: FromPyObject<'a>,
|
||||||
|
T::AsRefTarget: 'a + AsPyPointer,
|
||||||
{
|
{
|
||||||
/// Extracts `Self` from the source `PyObject`.
|
/// Extracts `Self` from the source `PyObject`.
|
||||||
fn extract(ob: &'a PyAny) -> PyResult<Self> {
|
fn extract(ob: &'a PyAny) -> PyResult<Self> {
|
||||||
unsafe {
|
unsafe {
|
||||||
ob.extract::<&T>()
|
ob.extract::<&T::AsRefTarget>()
|
||||||
.map(|val| Py::from_borrowed_ptr(val.as_ptr()))
|
.map(|val| Py::from_borrowed_ptr(val.as_ptr()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::{ObjectProtocol, ToPyObject};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod common;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -25,3 +29,95 @@ fn test_cloneable_pyclass() {
|
||||||
let mrc: PyRefMut<Cloneable> = py_c.extract(py).unwrap();
|
let mrc: PyRefMut<Cloneable> = py_c.extract(py).unwrap();
|
||||||
assert_eq!(&c, &*mrc);
|
assert_eq!(&c, &*mrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
struct BaseClass {}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl BaseClass {
|
||||||
|
fn foo(&self) -> &'static str {
|
||||||
|
"BaseClass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(extends=BaseClass)]
|
||||||
|
struct SubClass {}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl SubClass {
|
||||||
|
fn foo(&self) -> &'static str {
|
||||||
|
"SubClass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
struct PolymorphicContainer {
|
||||||
|
#[pyo3(get, set)]
|
||||||
|
inner: Py<BaseClass>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_polymorphic_container_stores_base_class() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let p = PyCell::new(
|
||||||
|
py,
|
||||||
|
PolymorphicContainer {
|
||||||
|
inner: Py::new(py, BaseClass {}).unwrap(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_object(py);
|
||||||
|
|
||||||
|
py_assert!(py, p, "p.inner.foo() == 'BaseClass'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_polymorphic_container_stores_sub_class() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let p = PyCell::new(
|
||||||
|
py,
|
||||||
|
PolymorphicContainer {
|
||||||
|
inner: Py::new(py, BaseClass {}).unwrap(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_object(py);
|
||||||
|
|
||||||
|
p.as_ref(py)
|
||||||
|
.setattr(
|
||||||
|
"inner",
|
||||||
|
PyCell::new(
|
||||||
|
py,
|
||||||
|
PyClassInitializer::from(BaseClass {}).add_subclass(SubClass {}),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
py_assert!(py, p, "p.inner.foo() == 'SubClass'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_polymorphic_container_does_not_accept_other_types() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let p = PyCell::new(
|
||||||
|
py,
|
||||||
|
PolymorphicContainer {
|
||||||
|
inner: Py::new(py, BaseClass {}).unwrap(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_object(py);
|
||||||
|
|
||||||
|
let setattr = |value: PyObject| p.as_ref(py).setattr("inner", value);
|
||||||
|
|
||||||
|
assert!(setattr(1i32.into_py(py)).is_err());
|
||||||
|
assert!(setattr(py.None()).is_err());
|
||||||
|
assert!(setattr((1i32, 2i32).into_py(py)).is_err());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue