Add super object (#2486)

This commit is contained in:
Ivan Krivosheev 2022-07-03 21:21:15 +03:00 committed by GitHub
parent 17742dc766
commit 1cd1dbfe8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 0 deletions

View file

@ -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

View file

@ -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)]

View file

@ -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
View 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
View 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
"#
)
});
}