2018-05-02 18:49:40 +00:00
|
|
|
use pyo3::prelude::*;
|
2019-06-13 09:09:17 +00:00
|
|
|
use pyo3::py_run;
|
2019-12-15 02:41:32 +00:00
|
|
|
|
2019-03-20 18:37:27 +00:00
|
|
|
use pyo3::types::IntoPyDict;
|
2018-05-02 18:49:40 +00:00
|
|
|
|
|
|
|
mod common;
|
|
|
|
|
2020-09-01 00:36:26 +00:00
|
|
|
#[pyclass(subclass)]
|
2018-05-02 18:49:40 +00:00
|
|
|
struct BaseClass {
|
2019-02-18 19:07:41 +00:00
|
|
|
#[pyo3(get)]
|
2018-05-02 18:49:40 +00:00
|
|
|
val1: usize,
|
|
|
|
}
|
|
|
|
|
2018-07-08 21:33:48 +00:00
|
|
|
#[pyclass(subclass)]
|
2018-05-02 18:49:40 +00:00
|
|
|
struct SubclassAble {}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn subclass() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
2019-03-20 18:37:27 +00:00
|
|
|
let d = [("SubclassAble", py.get_type::<SubclassAble>())].into_py_dict(py);
|
2018-05-02 18:49:40 +00:00
|
|
|
|
2018-06-15 19:21:12 +00:00
|
|
|
py.run(
|
|
|
|
"class A(SubclassAble): pass\nassert issubclass(A, SubclassAble)",
|
|
|
|
None,
|
|
|
|
Some(d),
|
2018-09-28 21:34:57 +00:00
|
|
|
)
|
|
|
|
.map_err(|e| e.print(py))
|
2018-07-30 21:01:46 +00:00
|
|
|
.unwrap();
|
2018-05-02 18:49:40 +00:00
|
|
|
}
|
|
|
|
|
2018-07-08 21:33:48 +00:00
|
|
|
#[pymethods]
|
2018-05-02 18:49:40 +00:00
|
|
|
impl BaseClass {
|
|
|
|
#[new]
|
2019-12-14 14:16:39 +00:00
|
|
|
fn new() -> Self {
|
|
|
|
BaseClass { val1: 10 }
|
2018-05-02 18:49:40 +00:00
|
|
|
}
|
2020-02-18 05:20:39 +00:00
|
|
|
fn base_method(&self, x: usize) -> usize {
|
|
|
|
x * self.val1
|
|
|
|
}
|
2020-03-18 04:31:22 +00:00
|
|
|
fn base_set(&mut self, fn_: &pyo3::PyAny) -> PyResult<()> {
|
2020-02-18 05:20:39 +00:00
|
|
|
let value: usize = fn_.call0()?.extract()?;
|
|
|
|
self.val1 = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
2018-05-02 18:49:40 +00:00
|
|
|
}
|
|
|
|
|
2018-07-15 09:58:33 +00:00
|
|
|
#[pyclass(extends=BaseClass)]
|
2018-05-02 18:49:40 +00:00
|
|
|
struct SubClass {
|
2019-02-18 19:07:41 +00:00
|
|
|
#[pyo3(get)]
|
2018-05-02 18:49:40 +00:00
|
|
|
val2: usize,
|
|
|
|
}
|
|
|
|
|
2018-07-08 21:33:48 +00:00
|
|
|
#[pymethods]
|
2018-05-02 18:49:40 +00:00
|
|
|
impl SubClass {
|
|
|
|
#[new]
|
2020-01-05 07:01:05 +00:00
|
|
|
fn new() -> (Self, BaseClass) {
|
|
|
|
(SubClass { val2: 5 }, BaseClass { val1: 10 })
|
2018-05-02 18:49:40 +00:00
|
|
|
}
|
2020-02-18 05:20:39 +00:00
|
|
|
fn sub_method(&self, x: usize) -> usize {
|
|
|
|
x * self.val2
|
|
|
|
}
|
|
|
|
fn sub_set_and_ret(&mut self, x: usize) -> usize {
|
|
|
|
self.val2 = x;
|
|
|
|
x
|
|
|
|
}
|
2018-05-02 18:49:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn inheritance_with_new_methods() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let typeobj = py.get_type::<SubClass>();
|
2019-02-23 17:01:22 +00:00
|
|
|
let inst = typeobj.call((), None).unwrap();
|
2018-05-02 18:49:40 +00:00
|
|
|
py_run!(py, inst, "assert inst.val1 == 10; assert inst.val2 == 5");
|
2018-06-15 19:21:12 +00:00
|
|
|
}
|
2019-12-15 02:41:32 +00:00
|
|
|
|
2020-02-18 05:20:39 +00:00
|
|
|
#[test]
|
|
|
|
fn call_base_and_sub_methods() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let obj = PyCell::new(py, SubClass::new()).unwrap();
|
|
|
|
py_run!(
|
|
|
|
py,
|
|
|
|
obj,
|
|
|
|
r#"
|
|
|
|
assert obj.base_method(10) == 100
|
|
|
|
assert obj.sub_method(10) == 50
|
|
|
|
"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn mutation_fails() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let obj = PyCell::new(py, SubClass::new()).unwrap();
|
|
|
|
let global = Some([("obj", obj)].into_py_dict(py));
|
|
|
|
let e = py
|
|
|
|
.run("obj.base_set(lambda: obj.sub_set_and_ret(1))", global, None)
|
|
|
|
.unwrap_err();
|
2020-07-04 15:55:26 +00:00
|
|
|
assert_eq!(
|
|
|
|
&e.instance(py).to_string(),
|
|
|
|
"RuntimeError: Already borrowed"
|
|
|
|
)
|
2020-02-18 05:20:39 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 00:36:26 +00:00
|
|
|
#[pyclass(subclass)]
|
2020-01-07 03:49:36 +00:00
|
|
|
struct BaseClassWithResult {
|
|
|
|
_val: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pymethods]
|
|
|
|
impl BaseClassWithResult {
|
|
|
|
#[new]
|
|
|
|
fn new(value: isize) -> PyResult<Self> {
|
2020-01-08 13:44:50 +00:00
|
|
|
Ok(Self {
|
|
|
|
_val: std::convert::TryFrom::try_from(value)?,
|
|
|
|
})
|
2020-01-07 03:49:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pyclass(extends=BaseClassWithResult)]
|
|
|
|
struct SubClass2 {}
|
|
|
|
|
|
|
|
#[pymethods]
|
|
|
|
impl SubClass2 {
|
|
|
|
#[new]
|
|
|
|
fn new(value: isize) -> PyResult<(Self, BaseClassWithResult)> {
|
|
|
|
let base = BaseClassWithResult::new(value)?;
|
|
|
|
Ok((Self {}, base))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_result_in_new() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let subclass = py.get_type::<SubClass2>();
|
|
|
|
py_run!(
|
|
|
|
py,
|
|
|
|
subclass,
|
|
|
|
r#"
|
|
|
|
try:
|
|
|
|
subclass(-10)
|
|
|
|
assert Fals
|
2020-01-08 13:44:50 +00:00
|
|
|
except ValueError as e:
|
2020-01-07 03:49:36 +00:00
|
|
|
pass
|
|
|
|
except Exception as e:
|
|
|
|
raise e
|
|
|
|
"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-09-19 15:42:55 +00:00
|
|
|
// Subclassing builtin types is not allowed in the LIMITED API.
|
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
mod inheriting_native_type {
|
|
|
|
use super::*;
|
|
|
|
use pyo3::types::{PyDict, PySet};
|
|
|
|
|
|
|
|
#[pyclass(extends=PySet)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct SetWithName {
|
|
|
|
#[pyo3(get(name))]
|
|
|
|
_name: &'static str,
|
|
|
|
}
|
2019-12-21 14:21:41 +00:00
|
|
|
|
2020-09-19 15:42:55 +00:00
|
|
|
#[pymethods]
|
|
|
|
impl SetWithName {
|
|
|
|
#[new]
|
|
|
|
fn new() -> Self {
|
|
|
|
SetWithName { _name: "Hello :)" }
|
|
|
|
}
|
2019-12-21 14:21:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-19 15:42:55 +00:00
|
|
|
#[test]
|
|
|
|
fn inherit_set() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let set_sub = pyo3::PyCell::new(py, SetWithName::new()).unwrap();
|
|
|
|
py_run!(
|
|
|
|
py,
|
|
|
|
set_sub,
|
|
|
|
r#"set_sub.add(10); assert list(set_sub) == [10]; assert set_sub._name == "Hello :)""#
|
|
|
|
);
|
|
|
|
}
|
2019-12-21 14:21:41 +00:00
|
|
|
|
2020-09-19 15:42:55 +00:00
|
|
|
#[pyclass(extends=PyDict)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct DictWithName {
|
|
|
|
#[pyo3(get(name))]
|
|
|
|
_name: &'static str,
|
|
|
|
}
|
2019-12-21 14:21:41 +00:00
|
|
|
|
2020-09-19 15:42:55 +00:00
|
|
|
#[pymethods]
|
|
|
|
impl DictWithName {
|
|
|
|
#[new]
|
|
|
|
fn new() -> Self {
|
|
|
|
DictWithName { _name: "Hello :)" }
|
|
|
|
}
|
2019-12-21 14:21:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-19 15:42:55 +00:00
|
|
|
#[test]
|
|
|
|
fn inherit_dict() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let dict_sub = pyo3::PyCell::new(py, DictWithName::new()).unwrap();
|
|
|
|
py_run!(
|
|
|
|
py,
|
|
|
|
dict_sub,
|
|
|
|
r#"dict_sub[0] = 1; assert dict_sub[0] == 1; assert dict_sub._name == "Hello :)""#
|
|
|
|
);
|
|
|
|
}
|
2019-12-21 14:21:41 +00:00
|
|
|
}
|