Add tuple and unit struct support for pyclass macro
This commit is contained in:
parent
20452a7c09
commit
773a371ba5
|
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- Add FFI definition `PyCFunction_CheckExact` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425)
|
||||
- Add FFI definition `Py_IS_TYPE`. [#1429](https://github.com/PyO3/pyo3/pull/1429)
|
||||
- Add FFI definition `_Py_InitializeMain`. [#1473](https://github.com/PyO3/pyo3/pull/1473)
|
||||
- Add tuple and unit struct support for `#[pyclass]` macro. [#1504](https://github.com/PyO3/pyo3/pull/1504)
|
||||
|
||||
### Changed
|
||||
- Change `PyTimeAcces::get_fold()` to return a `bool` instead of a `u8`. [#1397](https://github.com/PyO3/pyo3/pull/1397)
|
||||
|
|
|
@ -179,15 +179,24 @@ pub fn build_py_class(
|
|||
class.generics.span() => "#[pyclass] cannot have generic parameters"
|
||||
);
|
||||
|
||||
if let syn::Fields::Named(fields) = &mut class.fields {
|
||||
for field in fields.named.iter_mut() {
|
||||
let field_descs = parse_descriptors(field)?;
|
||||
if !field_descs.is_empty() {
|
||||
descriptors.push((field.clone(), field_descs));
|
||||
match &mut class.fields {
|
||||
syn::Fields::Named(fields) => {
|
||||
for field in fields.named.iter_mut() {
|
||||
let field_descs = parse_descriptors(field)?;
|
||||
if !field_descs.is_empty() {
|
||||
descriptors.push((field.clone(), field_descs));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bail_spanned!(class.fields.span() => "#[pyclass] can only be used with C-style structs");
|
||||
syn::Fields::Unnamed(fields) => {
|
||||
for field in fields.unnamed.iter_mut() {
|
||||
let field_descs = parse_descriptors(field)?;
|
||||
if !field_descs.is_empty() {
|
||||
descriptors.push((field.clone(), field_descs));
|
||||
}
|
||||
}
|
||||
}
|
||||
syn::Fields::Unit => { /* No fields for unit struct */ }
|
||||
}
|
||||
|
||||
impl_class(&class.ident, &attr, doc, descriptors, methods_type)
|
||||
|
|
|
@ -18,6 +18,20 @@ fn empty_class() {
|
|||
py_assert!(py, typeobj, "typeobj.__name__ == 'EmptyClass'");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct UnitClass;
|
||||
|
||||
#[test]
|
||||
fn unit_class() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let typeobj = py.get_type::<UnitClass>();
|
||||
// By default, don't allow creating instances from python.
|
||||
assert!(typeobj.call((), None).is_err());
|
||||
|
||||
py_assert!(py, typeobj, "typeobj.__name__ == 'UnitClass'");
|
||||
}
|
||||
|
||||
/// Line1
|
||||
///Line2
|
||||
/// Line3
|
||||
|
@ -289,3 +303,16 @@ fn test_pymethods_from_py_with() {
|
|||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct TupleClass(i32);
|
||||
|
||||
#[test]
|
||||
fn test_tuple_struct_class() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let typeobj = py.get_type::<TupleClass>();
|
||||
assert!(typeobj.call((), None).is_err());
|
||||
|
||||
py_assert!(py, typeobj, "typeobj.__name__ == 'TupleClass'");
|
||||
}
|
||||
|
|
|
@ -24,6 +24,51 @@ fn empty_class_with_new() {
|
|||
.is_ok());
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct UnitClassWithNew;
|
||||
|
||||
#[pymethods]
|
||||
impl UnitClassWithNew {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_class_with_new() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let typeobj = py.get_type::<UnitClassWithNew>();
|
||||
assert!(typeobj
|
||||
.call((), None)
|
||||
.unwrap()
|
||||
.cast_as::<PyCell<UnitClassWithNew>>()
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct TupleClassWithNew(i32);
|
||||
|
||||
#[pymethods]
|
||||
impl TupleClassWithNew {
|
||||
#[new]
|
||||
fn new(arg: i32) -> Self {
|
||||
Self(arg)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuple_class_with_new() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let typeobj = py.get_type::<TupleClassWithNew>();
|
||||
let wrp = typeobj.call((42,), None).unwrap();
|
||||
let obj = wrp.cast_as::<PyCell<TupleClassWithNew>>().unwrap();
|
||||
let obj_ref = obj.borrow();
|
||||
assert_eq!(obj_ref.0, 42);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
struct NewWithOneArg {
|
||||
|
|
|
@ -130,3 +130,31 @@ fn ref_getter_setter() {
|
|||
py_run!(py, inst, "assert inst.num == 10");
|
||||
py_run!(py, inst, "inst.num = 20; assert inst.num == 20");
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct TupleClassGetterSetter(i32);
|
||||
|
||||
#[pymethods]
|
||||
impl TupleClassGetterSetter {
|
||||
#[getter(num)]
|
||||
fn get_num(&self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[setter(num)]
|
||||
fn set_num(&mut self, value: i32) {
|
||||
self.0 = value;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuple_struct_getter_setter() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let inst = Py::new(py, TupleClassGetterSetter(10)).unwrap();
|
||||
|
||||
py_run!(py, inst, "assert inst.num == 10");
|
||||
py_run!(py, inst, "inst.num = 20");
|
||||
py_run!(py, inst, "assert inst.num == 20");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue