Add super object (#2486)
This commit is contained in:
parent
17742dc766
commit
1cd1dbfe8b
|
@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Add `CompareOp::matches` to easily implement `__richcmp__` as the result of a
|
||||
Rust `std::cmp::Ordering` comparison. [#2460](https://github.com/PyO3/pyo3/pull/2460)
|
||||
- Supprt `#[pyo3(name)]` on enum variants [#2457](https://github.com/PyO3/pyo3/pull/2457)
|
||||
- Add `PySuper` object [#2049](https://github.com/PyO3/pyo3/issues/2049)
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use crate::conversion::{AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyTryF
|
|||
use crate::err::{PyDowncastError, PyErr, PyResult};
|
||||
use crate::exceptions::PyTypeError;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
#[cfg(not(PyPy))]
|
||||
use crate::types::PySuper;
|
||||
use crate::types::{PyDict, PyIterator, PyList, PyString, PyTuple, PyType};
|
||||
use crate::{err, ffi, Py, PyNativeType, PyObject, Python};
|
||||
use std::cell::UnsafeCell;
|
||||
|
@ -883,6 +885,14 @@ impl PyAny {
|
|||
pub fn py(&self) -> Python<'_> {
|
||||
PyNativeType::py(self)
|
||||
}
|
||||
|
||||
/// Return a proxy object that delegates method calls to a parent or sibling class of type.
|
||||
///
|
||||
/// This is equivalent to the Python expression `super()`
|
||||
#[cfg(not(PyPy))]
|
||||
pub fn py_super(&self) -> PyResult<&PySuper> {
|
||||
PySuper::new(self.get_type(), self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -27,6 +27,8 @@ pub use self::mapping::PyMapping;
|
|||
pub use self::module::PyModule;
|
||||
pub use self::num::PyLong;
|
||||
pub use self::num::PyLong as PyInt;
|
||||
#[cfg(not(PyPy))]
|
||||
pub use self::pysuper::PySuper;
|
||||
pub use self::sequence::PySequence;
|
||||
pub use self::set::PySet;
|
||||
pub use self::slice::{PySlice, PySliceIndices};
|
||||
|
@ -277,6 +279,8 @@ mod list;
|
|||
mod mapping;
|
||||
mod module;
|
||||
mod num;
|
||||
#[cfg(not(PyPy))]
|
||||
mod pysuper;
|
||||
mod sequence;
|
||||
mod set;
|
||||
mod slice;
|
||||
|
|
61
src/types/pysuper.rs
Normal file
61
src/types/pysuper.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
use crate::ffi;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
use crate::types::PyType;
|
||||
use crate::{PyAny, PyResult};
|
||||
|
||||
/// Represents a Python `super` object.
|
||||
///
|
||||
/// This type is immutable.
|
||||
#[repr(transparent)]
|
||||
pub struct PySuper(PyAny);
|
||||
|
||||
pyobject_native_type_core!(PySuper, ffi::PySuper_Type);
|
||||
|
||||
impl PySuper {
|
||||
/// Constructs a new super object. More read about super object: [docs](https://docs.python.org/3/library/functions.html#super)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use pyo3::prelude::*;
|
||||
///
|
||||
///#[pyclass(subclass)]
|
||||
/// struct BaseClass {
|
||||
/// val1: usize,
|
||||
/// }
|
||||
///
|
||||
/// #[pymethods]
|
||||
/// impl BaseClass {
|
||||
/// #[new]
|
||||
/// fn new() -> Self {
|
||||
/// BaseClass { val1: 10 }
|
||||
/// }
|
||||
///
|
||||
/// pub fn method(&self) -> usize {
|
||||
/// self.val1
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[pyclass(extends=BaseClass)]
|
||||
/// struct SubClass {}
|
||||
///
|
||||
/// #[pymethods]
|
||||
/// impl SubClass {
|
||||
/// #[new]
|
||||
/// fn new() -> (Self, BaseClass) {
|
||||
/// (SubClass {}, BaseClass::new())
|
||||
/// }
|
||||
///
|
||||
/// fn method(self_: &PyCell<Self>) -> PyResult<&PyAny> {
|
||||
/// let super_ = self_.py_super()?;
|
||||
/// super_.call_method("method", (), None)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn new<'py>(ty: &'py PyType, obj: &'py PyAny) -> PyResult<&'py PySuper> {
|
||||
let py = ty.py();
|
||||
let super_ = PySuper::type_object(py).call1((ty, obj))?;
|
||||
let super_ = super_.downcast::<PySuper>()?;
|
||||
Ok(super_)
|
||||
}
|
||||
}
|
51
tests/test_super.rs
Normal file
51
tests/test_super.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
#![cfg(all(feature = "macros", not(PyPy)))]
|
||||
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pyclass(subclass)]
|
||||
struct BaseClass {
|
||||
val1: usize,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl BaseClass {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
BaseClass { val1: 10 }
|
||||
}
|
||||
|
||||
pub fn method(&self) -> usize {
|
||||
self.val1
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends=BaseClass)]
|
||||
struct SubClass {}
|
||||
|
||||
#[pymethods]
|
||||
impl SubClass {
|
||||
#[new]
|
||||
fn new() -> (Self, BaseClass) {
|
||||
(SubClass {}, BaseClass::new())
|
||||
}
|
||||
|
||||
fn method(self_: &PyCell<Self>) -> PyResult<&PyAny> {
|
||||
let super_ = self_.py_super()?;
|
||||
super_.call_method("method", (), None)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call_super_method() {
|
||||
Python::with_gil(|py| {
|
||||
let cls = py.get_type::<SubClass>();
|
||||
pyo3::py_run!(
|
||||
py,
|
||||
cls,
|
||||
r#"
|
||||
obj = cls()
|
||||
assert obj.method() == 10
|
||||
"#
|
||||
)
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue