Refactor `#[pyproto]` Result types

This commit is contained in:
David Hewitt 2020-06-23 10:07:16 +01:00
parent 4c04268bdb
commit c7a4b4770f
16 changed files with 305 additions and 528 deletions

View File

@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Update `num-bigint` optional dependendency from `0.2` to `0.3`. [#978](https://github.com/PyO3/pyo3/pull/978)
- `#[pyproto]` is re-implemented without specialization. [#961](https://github.com/PyO3/pyo3/pull/961)
- `PyClassAlloc::alloc` is renamed to `PyClassAlloc::new`. [#990](https://github.com/PyO3/pyo3/pull/990)
- `#[pyproto]` methods can now have return value `T` or `PyResult<T>` (previously only `PyResult<T>` was supported). [#996](https://github.com/PyO3/pyo3/pull/996)
### Removed
- Remove `ManagedPyRef` (unused, and needs specialization) [#930](https://github.com/PyO3/pyo3/pull/930)
@ -34,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed
- Fix passing explicit `None` to `Option<T>` argument `#[pyfunction]` with a default value. [#936](https://github.com/PyO3/pyo3/pull/936)
- Fix `PyClass.__new__`'s not respecting subclasses when inherited by a Python class. [#990](https://github.com/PyO3/pyo3/pull/990)
- Fix returning `Option<T>` from `#[pyproto]` methods. [#996](https://github.com/PyO3/pyo3/pull/996)
## [0.10.1] - 2020-05-14
### Fixed

View File

@ -688,6 +688,9 @@ mapping or number protocols. PyO3 defines separate traits for each of them. To p
Python object behavior, you need to implement the specific trait for your struct. Important note,
each protocol implementation block has to be annotated with the `#[pyproto]` attribute.
All `#[pyproto]` methods which can be defined below can return `T` instead of `PyResult<T>` if the
method implementation is infallible.
### Basic object customization
The [`PyObjectProtocol`] trait provides several basic customizations.
@ -823,11 +826,11 @@ struct MyIterator {
#[pyproto]
impl PyIterProtocol for MyIterator {
fn __iter__(slf: PyRef<Self>) -> PyResult<Py<MyIterator>> {
Ok(slf.into())
fn __iter__(slf: PyRef<Self>) -> Py<MyIterator> {
slf.into()
}
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<PyObject>> {
Ok(slf.iter.next())
fn __next__(mut slf: PyRefMut<Self>) -> Option<PyObject> {
slf.iter.next()
}
}
```
@ -848,12 +851,12 @@ struct Iter {
#[pyproto]
impl PyIterProtocol for Iter {
fn __iter__(slf: PyRefMut<Self>) -> PyResult<Py<Iter>> {
Ok(slf.into())
fn __iter__(slf: PyRefMut<Self>) -> Py<Iter> {
slf.into()
}
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<usize>> {
Ok(slf.inner.next())
fn __next__(mut slf: PyRefMut<Self>) -> Option<usize> {
slf.inner.next()
}
}
@ -868,7 +871,7 @@ impl PyIterProtocol for Container {
let iter = Iter {
inner: slf.iter.clone().into_iter(),
};
PyCell::new(slf.py(), iter).map(Into::into)
Py::new(slf.py(), iter)
}
}

View File

@ -89,57 +89,47 @@ pub const OBJECT: Proto = Proto {
MethodProto::Binary {
name: "__getattr__",
arg: "Name",
pyres: true,
proto: "pyo3::class::basic::PyObjectGetAttrProtocol",
},
MethodProto::Ternary {
name: "__setattr__",
arg1: "Name",
arg2: "Value",
pyres: false,
proto: "pyo3::class::basic::PyObjectSetAttrProtocol",
},
MethodProto::Binary {
name: "__delattr__",
arg: "Name",
pyres: false,
proto: "pyo3::class::basic::PyObjectDelAttrProtocol",
},
MethodProto::Unary {
name: "__str__",
pyres: true,
proto: "pyo3::class::basic::PyObjectStrProtocol",
},
MethodProto::Unary {
name: "__repr__",
pyres: true,
proto: "pyo3::class::basic::PyObjectReprProtocol",
},
MethodProto::Binary {
name: "__format__",
arg: "Format",
pyres: true,
proto: "pyo3::class::basic::PyObjectFormatProtocol",
},
MethodProto::Unary {
name: "__hash__",
pyres: false,
proto: "pyo3::class::basic::PyObjectHashProtocol",
},
MethodProto::Unary {
name: "__bytes__",
pyres: true,
proto: "pyo3::class::basic::PyObjectBytesProtocol",
},
MethodProto::Binary {
name: "__richcmp__",
arg: "Other",
pyres: true,
proto: "pyo3::class::basic::PyObjectRichcmpProtocol",
},
MethodProto::Unary {
name: "__bool__",
pyres: false,
proto: "pyo3::class::basic::PyObjectBoolProtocol",
},
],
@ -173,24 +163,20 @@ pub const ASYNC: Proto = Proto {
MethodProto::UnaryS {
name: "__await__",
arg: "Receiver",
pyres: true,
proto: "pyo3::class::pyasync::PyAsyncAwaitProtocol",
},
MethodProto::UnaryS {
name: "__aiter__",
arg: "Receiver",
pyres: true,
proto: "pyo3::class::pyasync::PyAsyncAiterProtocol",
},
MethodProto::UnaryS {
name: "__anext__",
arg: "Receiver",
pyres: true,
proto: "pyo3::class::pyasync::PyAsyncAnextProtocol",
},
MethodProto::Unary {
name: "__aenter__",
pyres: true,
proto: "pyo3::class::pyasync::PyAsyncAenterProtocol",
},
MethodProto::Quaternary {
@ -225,12 +211,10 @@ pub const BUFFER: Proto = Proto {
methods: &[
MethodProto::Unary {
name: "bf_getbuffer",
pyres: false,
proto: "pyo3::class::buffer::PyBufferGetBufferProtocol",
},
MethodProto::Unary {
name: "bf_releasebuffer",
pyres: false,
proto: "pyo3::class::buffer::PyBufferReleaseBufferProtocol",
},
],
@ -248,7 +232,6 @@ pub const CONTEXT: Proto = Proto {
methods: &[
MethodProto::Unary {
name: "__enter__",
pyres: true,
proto: "pyo3::class::context::PyContextEnterProtocol",
},
MethodProto::Quaternary {
@ -303,7 +286,6 @@ pub const DESCR: Proto = Proto {
arg1: "Receiver",
arg2: "Inst",
arg3: "Owner",
pyres: true,
proto: "pyo3::class::descr::PyDescrGetProtocol",
},
MethodProto::TernaryS {
@ -311,19 +293,16 @@ pub const DESCR: Proto = Proto {
arg1: "Receiver",
arg2: "Inst",
arg3: "Value",
pyres: false,
proto: "pyo3::class::descr::PyDescrSetProtocol",
},
MethodProto::Binary {
name: "__det__",
arg: "Inst",
pyres: false,
proto: "pyo3::class::descr::PyDescrDelProtocol",
},
MethodProto::Binary {
name: "__set_name__",
arg: "Inst",
pyres: false,
proto: "pyo3::class::descr::PyDescrSetNameProtocol",
},
],
@ -349,13 +328,11 @@ pub const ITER: Proto = Proto {
MethodProto::UnaryS {
name: "__iter__",
arg: "Receiver",
pyres: true,
proto: "pyo3::class::iter::PyIterIterProtocol",
},
MethodProto::UnaryS {
name: "__next__",
arg: "Receiver",
pyres: true,
proto: "pyo3::class::iter::PyIterNextProtocol",
},
],
@ -372,31 +349,26 @@ pub const MAPPING: Proto = Proto {
methods: &[
MethodProto::Unary {
name: "__len__",
pyres: false,
proto: "pyo3::class::mapping::PyMappingLenProtocol",
},
MethodProto::Binary {
name: "__getitem__",
arg: "Key",
pyres: true,
proto: "pyo3::class::mapping::PyMappingGetItemProtocol",
},
MethodProto::Ternary {
name: "__setitem__",
arg1: "Key",
arg2: "Value",
pyres: false,
proto: "pyo3::class::mapping::PyMappingSetItemProtocol",
},
MethodProto::Binary {
name: "__delitem__",
arg: "Key",
pyres: false,
proto: "pyo3::class::mapping::PyMappingDelItemProtocol",
},
MethodProto::Unary {
name: "__reversed__",
pyres: true,
proto: "pyo3::class::mapping::PyMappingReversedProtocol",
},
],
@ -424,56 +396,47 @@ pub const SEQ: Proto = Proto {
methods: &[
MethodProto::Unary {
name: "__len__",
pyres: false,
proto: "pyo3::class::sequence::PySequenceLenProtocol",
},
MethodProto::Binary {
name: "__getitem__",
arg: "Index",
pyres: true,
proto: "pyo3::class::sequence::PySequenceGetItemProtocol",
},
MethodProto::Ternary {
name: "__setitem__",
arg1: "Index",
arg2: "Value",
pyres: false,
proto: "pyo3::class::sequence::PySequenceSetItemProtocol",
},
MethodProto::Binary {
name: "__delitem__",
arg: "Index",
pyres: false,
proto: "pyo3::class::sequence::PySequenceDelItemProtocol",
},
MethodProto::Binary {
name: "__contains__",
arg: "Item",
pyres: false,
proto: "pyo3::class::sequence::PySequenceContainsProtocol",
},
MethodProto::Binary {
name: "__concat__",
arg: "Other",
pyres: true,
proto: "pyo3::class::sequence::PySequenceConcatProtocol",
},
MethodProto::Binary {
name: "__repeat__",
arg: "Index",
pyres: true,
proto: "pyo3::class::sequence::PySequenceRepeatProtocol",
},
MethodProto::Binary {
name: "__inplace_concat__",
arg: "Other",
pyres: true,
proto: "pyo3::class::sequence::PySequenceInplaceConcatProtocol",
},
MethodProto::Binary {
name: "__inplace_repeat__",
arg: "Index",
pyres: true,
proto: "pyo3::class::sequence::PySequenceInplaceRepeatProtocol",
},
],
@ -505,56 +468,48 @@ pub const NUM: Proto = Proto {
name: "__add__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberAddProtocol",
},
MethodProto::BinaryS {
name: "__sub__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberSubProtocol",
},
MethodProto::BinaryS {
name: "__mul__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberMulProtocol",
},
MethodProto::BinaryS {
name: "__matmul__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberMatmulProtocol",
},
MethodProto::BinaryS {
name: "__truediv__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberTruedivProtocol",
},
MethodProto::BinaryS {
name: "__floordiv__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberFloordivProtocol",
},
MethodProto::BinaryS {
name: "__mod__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberModProtocol",
},
MethodProto::BinaryS {
name: "__divmod__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberDivmodProtocol",
},
MethodProto::TernaryS {
@ -562,251 +517,209 @@ pub const NUM: Proto = Proto {
arg1: "Left",
arg2: "Right",
arg3: "Modulo",
pyres: true,
proto: "pyo3::class::number::PyNumberPowProtocol",
},
MethodProto::BinaryS {
name: "__lshift__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberLShiftProtocol",
},
MethodProto::BinaryS {
name: "__rshift__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberRShiftProtocol",
},
MethodProto::BinaryS {
name: "__and__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberAndProtocol",
},
MethodProto::BinaryS {
name: "__xor__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberXorProtocol",
},
MethodProto::BinaryS {
name: "__or__",
arg1: "Left",
arg2: "Right",
pyres: true,
proto: "pyo3::class::number::PyNumberOrProtocol",
},
MethodProto::Binary {
name: "__radd__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRAddProtocol",
},
MethodProto::Binary {
name: "__rsub__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRSubProtocol",
},
MethodProto::Binary {
name: "__rmul__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRMulProtocol",
},
MethodProto::Binary {
name: "__rmatmul__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRMatmulProtocol",
},
MethodProto::Binary {
name: "__rtruediv__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRTruedivProtocol",
},
MethodProto::Binary {
name: "__rfloordiv__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRFloordivProtocol",
},
MethodProto::Binary {
name: "__rmod__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRModProtocol",
},
MethodProto::Binary {
name: "__rdivmod__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRDivmodProtocol",
},
MethodProto::Ternary {
name: "__rpow__",
arg1: "Other",
arg2: "Modulo",
pyres: true,
proto: "pyo3::class::number::PyNumberRPowProtocol",
},
MethodProto::Binary {
name: "__rlshift__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRLShiftProtocol",
},
MethodProto::Binary {
name: "__rrshift__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRRShiftProtocol",
},
MethodProto::Binary {
name: "__rand__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRAndProtocol",
},
MethodProto::Binary {
name: "__rxor__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberRXorProtocol",
},
MethodProto::Binary {
name: "__ror__",
arg: "Other",
pyres: true,
proto: "pyo3::class::number::PyNumberROrProtocol",
},
MethodProto::Binary {
name: "__iadd__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIAddProtocol",
},
MethodProto::Binary {
name: "__isub__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberISubProtocol",
},
MethodProto::Binary {
name: "__imul__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIMulProtocol",
},
MethodProto::Binary {
name: "__imatmul__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIMatmulProtocol",
},
MethodProto::Binary {
name: "__itruediv__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberITruedivProtocol",
},
MethodProto::Binary {
name: "__ifloordiv__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIFloordivProtocol",
},
MethodProto::Binary {
name: "__imod__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIModProtocol",
},
MethodProto::Binary {
name: "__ipow__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIPowProtocol",
},
MethodProto::Binary {
name: "__ilshift__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberILShiftProtocol",
},
MethodProto::Binary {
name: "__irshift__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIRShiftProtocol",
},
MethodProto::Binary {
name: "__iand__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIAndProtocol",
},
MethodProto::Binary {
name: "__ixor__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIXorProtocol",
},
MethodProto::Binary {
name: "__ior__",
arg: "Other",
pyres: false,
proto: "pyo3::class::number::PyNumberIOrProtocol",
},
MethodProto::Unary {
name: "__neg__",
pyres: true,
proto: "pyo3::class::number::PyNumberNegProtocol",
},
MethodProto::Unary {
name: "__pos__",
pyres: true,
proto: "pyo3::class::number::PyNumberPosProtocol",
},
MethodProto::Unary {
name: "__abs__",
pyres: true,
proto: "pyo3::class::number::PyNumberAbsProtocol",
},
MethodProto::Unary {
name: "__invert__",
pyres: true,
proto: "pyo3::class::number::PyNumberInvertProtocol",
},
MethodProto::Unary {
name: "__complex__",
pyres: true,
proto: "pyo3::class::number::PyNumberComplexProtocol",
},
MethodProto::Unary {
name: "__int__",
pyres: true,
proto: "pyo3::class::number::PyNumberIntProtocol",
},
MethodProto::Unary {
name: "__float__",
pyres: true,
proto: "pyo3::class::number::PyNumberFloatProtocol",
},
MethodProto::Unary {
name: "__index__",
pyres: true,
proto: "pyo3::class::number::PyNumberIndexProtocol",
},
MethodProto::Binary {
name: "__round__",
arg: "NDigits",
pyres: true,
proto: "pyo3::class::number::PyNumberRoundProtocol",
},
],

View File

@ -15,33 +15,28 @@ pub enum MethodProto {
},
Unary {
name: &'static str,
pyres: bool,
proto: &'static str,
},
UnaryS {
name: &'static str,
arg: &'static str,
pyres: bool,
proto: &'static str,
},
Binary {
name: &'static str,
arg: &'static str,
pyres: bool,
proto: &'static str,
},
BinaryS {
name: &'static str,
arg1: &'static str,
arg2: &'static str,
pyres: bool,
proto: &'static str,
},
Ternary {
name: &'static str,
arg1: &'static str,
arg2: &'static str,
pyres: bool,
proto: &'static str,
},
TernaryS {
@ -49,7 +44,6 @@ pub enum MethodProto {
arg1: &'static str,
arg2: &'static str,
arg3: &'static str,
pyres: bool,
proto: &'static str,
},
Quaternary {
@ -88,7 +82,7 @@ pub(crate) fn impl_method_proto(
};
}
let ty = &*if let syn::ReturnType::Type(_, ref ty) = sig.output {
let ret_ty = &*if let syn::ReturnType::Type(_, ref ty) = sig.output {
ty.clone()
} else {
panic!("fn return type is not supported")
@ -96,9 +90,8 @@ pub(crate) fn impl_method_proto(
match *meth {
MethodProto::Free { .. } => unreachable!(),
MethodProto::Unary { pyres, proto, .. } => {
MethodProto::Unary { proto, .. } => {
let p: syn::Path = syn::parse_str(proto).unwrap();
let (ty, succ) = get_res_success(ty);
let tmp: syn::ItemFn = syn::parse_quote! {
fn test(&self) -> <#cls as #p<'p>>::Result {}
@ -106,26 +99,14 @@ pub(crate) fn impl_method_proto(
sig.output = tmp.sig.output;
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type Result = #ty;
type Result = #ret_ty;
}
}
}
}
MethodProto::UnaryS {
pyres, proto, arg, ..
} => {
MethodProto::UnaryS { proto, arg, .. } => {
let p: syn::Path = syn::parse_str(proto).unwrap();
let (ty, succ) = get_res_success(ty);
let slf_name = syn::Ident::new(arg, Span::call_site());
let mut slf_ty = get_arg_ty(sig, 0);
@ -156,29 +137,14 @@ pub(crate) fn impl_method_proto(
});
}
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #slf_name = #slf_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #slf_name = #slf_ty;
type Result = #ty;
type Result = #ret_ty;
}
}
}
}
MethodProto::Binary {
name,
arg,
pyres,
proto,
} => {
MethodProto::Binary { name, arg, proto } => {
if sig.inputs.len() <= 1 {
println!("Not enough arguments for {}", name);
return TokenStream::new();
@ -187,7 +153,6 @@ pub(crate) fn impl_method_proto(
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg_name = syn::Ident::new(arg, Span::call_site());
let arg_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
let tmp = extract_decl(syn::parse_quote! {
fn test(&self,arg: <#cls as #p<'p>>::#arg_name)-> <#cls as #p<'p>>::Result {}
@ -200,20 +165,10 @@ pub(crate) fn impl_method_proto(
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg_name = #arg_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg_name = #arg_ty;
type Result = #ty;
}
type Result = #ret_ty;
}
}
}
@ -221,7 +176,6 @@ pub(crate) fn impl_method_proto(
name,
arg1,
arg2,
pyres,
proto,
} => {
if sig.inputs.len() <= 1 {
@ -233,7 +187,6 @@ pub(crate) fn impl_method_proto(
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::new(arg2, Span::call_site());
let arg2_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_quote! {fn test(
@ -247,22 +200,11 @@ pub(crate) fn impl_method_proto(
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Result = #ty;
}
type Result = #ret_ty;
}
}
}
@ -270,7 +212,6 @@ pub(crate) fn impl_method_proto(
name,
arg1,
arg2,
pyres,
proto,
} => {
if sig.inputs.len() <= 2 {
@ -282,7 +223,6 @@ pub(crate) fn impl_method_proto(
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::new(arg2, Span::call_site());
let arg2_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_quote! {fn test(
@ -299,22 +239,11 @@ pub(crate) fn impl_method_proto(
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_self_ty(sig);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type Result = #ty;
}
type Result = #ret_ty;
}
}
}
@ -323,7 +252,6 @@ pub(crate) fn impl_method_proto(
arg1,
arg2,
arg3,
pyres,
proto,
} => {
if sig.inputs.len() <= 2 {
@ -337,7 +265,6 @@ pub(crate) fn impl_method_proto(
let arg2_ty = get_arg_ty(sig, 1);
let arg3_name = syn::Ident::new(arg3, Span::call_site());
let arg3_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_quote! {fn test(
@ -354,24 +281,12 @@ pub(crate) fn impl_method_proto(
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
if pyres {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Success = #succ;
type Result = #ty;
}
}
} else {
quote! {
impl<'p> #p<'p> for #cls {
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Result = #ty;
}
type Result = #ret_ty;
}
}
}
@ -393,7 +308,6 @@ pub(crate) fn impl_method_proto(
let arg2_ty = get_arg_ty(sig, 2);
let arg3_name = syn::Ident::new(arg3, Span::call_site());
let arg3_ty = get_arg_ty(sig, 3);
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_quote! {fn test(
@ -418,8 +332,7 @@ pub(crate) fn impl_method_proto(
type #arg1_name = #arg1_ty;
type #arg2_name = #arg2_ty;
type #arg3_name = #arg3_ty;
type Success = #succ;
type Result = #ty;
type Result = #ret_ty;
}
}
}
@ -460,62 +373,6 @@ fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type {
ty
}
// Success
fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
let mut result;
let mut succ;
match ty {
syn::Type::Path(ref typath) => {
if let Some(segment) = typath.path.segments.last() {
match segment.ident.to_string().as_str() {
// check for PyResult<T>
"PyResult" => match segment.arguments {
syn::PathArguments::AngleBracketed(ref data) => {
result = true;
succ = data.args[0].clone();
// check for PyResult<Option<T>>
if let syn::GenericArgument::Type(syn::Type::Path(ref typath)) =
data.args[0]
{
if let Some(segment) = typath.path.segments.last() {
if "Option" == segment.ident.to_string().as_str() {
// get T from Option<T>
if let syn::PathArguments::AngleBracketed(ref data) =
segment.arguments
{
result = false;
succ = data.args[0].clone();
}
}
}
}
}
_ => panic!("fn result type is not supported"),
},
_ => panic!(
"fn result type has to be PyResult or (), got {:?}",
segment.ident
),
}
} else {
panic!("fn result is not supported {:?}", typath)
}
}
_ => panic!("not supported: {:?}", ty),
};
// result
let res = if result {
quote! {PyResult<#succ>}
} else {
quote! {#ty}
};
(res, succ)
}
fn extract_decl(spec: syn::Item) -> syn::Signature {
match spec {
syn::Item::Fn(f) => f.sig,

View File

@ -79,19 +79,40 @@ impl IntoPyCallbackOutput<()> for () {
}
}
pub struct LenCallbackOutput(pub usize);
impl IntoPyCallbackOutput<ffi::Py_ssize_t> for LenCallbackOutput {
impl IntoPyCallbackOutput<ffi::Py_ssize_t> for usize {
#[inline]
fn convert(self, _py: Python) -> PyResult<ffi::Py_ssize_t> {
if self.0 <= (isize::MAX as usize) {
Ok(self.0 as isize)
if self <= (isize::MAX as usize) {
Ok(self as isize)
} else {
Err(OverflowError::py_err(()))
}
}
}
// Converters needed for `#[pyproto]` implementations
impl IntoPyCallbackOutput<bool> for bool {
fn convert(self, _: Python) -> PyResult<bool> {
Ok(self)
}
}
impl IntoPyCallbackOutput<usize> for usize {
fn convert(self, _: Python) -> PyResult<usize> {
Ok(self)
}
}
impl<T> IntoPyCallbackOutput<PyObject> for T
where
T: IntoPy<PyObject>,
{
fn convert(self, py: Python) -> PyResult<PyObject> {
Ok(self.into_py(py))
}
}
pub trait WrappingCastTo<T> {
fn wrapping_cast(self) -> T;
}
@ -117,15 +138,12 @@ wrapping_cast!(i32, Py_hash_t);
wrapping_cast!(isize, Py_hash_t);
wrapping_cast!(i64, Py_hash_t);
pub struct HashCallbackOutput<T>(pub T);
pub struct HashCallbackOutput(Py_hash_t);
impl<T> IntoPyCallbackOutput<Py_hash_t> for HashCallbackOutput<T>
where
T: WrappingCastTo<Py_hash_t>,
{
impl IntoPyCallbackOutput<Py_hash_t> for HashCallbackOutput {
#[inline]
fn convert(self, _py: Python) -> PyResult<Py_hash_t> {
let hash = self.0.wrapping_cast();
let hash = self.0;
if hash == -1 {
Ok(-2)
} else {
@ -134,6 +152,16 @@ where
}
}
impl<T> IntoPyCallbackOutput<HashCallbackOutput> for T
where
T: WrappingCastTo<Py_hash_t>,
{
#[inline]
fn convert(self, _py: Python) -> PyResult<HashCallbackOutput> {
Ok(HashCallbackOutput(self.wrapping_cast()))
}
}
#[doc(hidden)]
#[inline]
pub fn convert<T, U>(py: Python, value: T) -> PyResult<U>

View File

@ -8,10 +8,8 @@
//! Parts of the documentation are copied from the respective methods from the
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
use crate::callback::HashCallbackOutput;
use crate::{
exceptions, ffi, FromPyObject, IntoPy, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult,
};
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult};
use std::os::raw::c_int;
/// Operators for the __richcmp__ method
@ -100,45 +98,39 @@ pub trait PyObjectProtocol<'p>: PyClass {
pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
type Name: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> {
type Name: FromPyObject<'p>;
type Value: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> {
type Name: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyObjectStrProtocol<'p>: PyObjectProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyObjectReprProtocol<'p>: PyObjectProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyObjectFormatProtocol<'p>: PyObjectProtocol<'p> {
type Format: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyObjectHashProtocol<'p>: PyObjectProtocol<'p> {
type Result: Into<PyResult<isize>>;
type Result: IntoPyCallbackOutput<HashCallbackOutput>;
}
pub trait PyObjectBoolProtocol<'p>: PyObjectProtocol<'p> {
type Result: Into<PyResult<bool>>;
type Result: IntoPyCallbackOutput<bool>;
}
pub trait PyObjectBytesProtocol<'p>: PyObjectProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
/// All FFI functions for basic protocols.
@ -180,12 +172,7 @@ impl PyObjectMethods {
where
T: for<'p> PyObjectHashProtocol<'p>,
{
self.tp_hash = py_unary_func!(
PyObjectHashProtocol,
T::__hash__,
ffi::Py_hash_t,
HashCallbackOutput
);
self.tp_hash = py_unary_func!(PyObjectHashProtocol, T::__hash__, ffi::Py_hash_t);
}
pub fn set_getattr<T>(&mut self)
where
@ -255,7 +242,7 @@ where
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg);
call_ref!(slf, __getattr__, arg)
call_ref!(slf, __getattr__, arg).convert(py)
})
}
Some(wrap::<T>)
@ -293,7 +280,7 @@ where
let op = extract_op(op)?;
let arg = arg.extract()?;
slf.try_borrow()?.__richcmp__(arg, op).into()
slf.try_borrow()?.__richcmp__(arg, op).convert(py)
})
}
Some(wrap::<T>)

View File

@ -4,7 +4,7 @@
//!
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
//! c-api
use crate::err::PyResult;
use crate::callback::IntoPyCallbackOutput;
use crate::{
ffi::{self, PyBufferProcs},
PyCell, PyClass, PyRefMut,
@ -33,11 +33,11 @@ pub trait PyBufferProtocol<'p>: PyClass {
}
pub trait PyBufferGetBufferProtocol<'p>: PyBufferProtocol<'p> {
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
/// Set functions used by `#[pyproto]`.
@ -71,7 +71,7 @@ where
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into()
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py)
})
}
Some(wrap::<T>)
@ -87,7 +87,7 @@ where
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into()
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py)
})
}
Some(wrap::<T>)

View File

@ -4,7 +4,7 @@
//! Trait and support implementation for context manager api
//!
use crate::err::PyResult;
use crate::callback::IntoPyCallbackOutput;
use crate::{PyClass, PyObject};
/// Context manager interface
@ -31,14 +31,12 @@ pub trait PyContextProtocol<'p>: PyClass {
}
pub trait PyContextEnterProtocol<'p>: PyContextProtocol<'p> {
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyContextExitProtocol<'p>: PyContextProtocol<'p> {
type ExcType: crate::FromPyObject<'p>;
type ExcValue: crate::FromPyObject<'p>;
type Traceback: crate::FromPyObject<'p>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}

View File

@ -5,9 +5,9 @@
//! [Python information](
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
use crate::err::PyResult;
use crate::callback::IntoPyCallbackOutput;
use crate::types::PyAny;
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
use crate::{ffi, FromPyObject, PyClass, PyObject};
use std::os::raw::c_int;
/// Descriptor interface
@ -50,25 +50,24 @@ pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> {
type Receiver: crate::derive_utils::TryFromPyCell<'p, Self>;
type Inst: FromPyObject<'p>;
type Owner: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyDescrSetProtocol<'p>: PyDescrProtocol<'p> {
type Receiver: crate::derive_utils::TryFromPyCell<'p, Self>;
type Inst: FromPyObject<'p>;
type Value: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyDescrDeleteProtocol<'p>: PyDescrProtocol<'p> {
type Inst: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
type Inst: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
/// All FFI functions for description protocols.

View File

@ -30,14 +30,12 @@ pub trait PyIterProtocol<'p>: PyClass {
pub trait PyIterIterProtocol<'p>: PyIterProtocol<'p> {
type Receiver: TryFromPyCell<'p, Self>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
type Receiver: TryFromPyCell<'p, Self>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Option<Self::Success>>>;
type Result: IntoPyCallbackOutput<IterNextOutput>;
}
#[derive(Default)]
@ -62,20 +60,26 @@ impl PyIterMethods {
where
T: for<'p> PyIterNextProtocol<'p>,
{
self.tp_iternext = py_unarys_func!(PyIterNextProtocol, T::__next__, IterNextConverter);
self.tp_iternext = py_unarys_func!(PyIterNextProtocol, T::__next__);
}
}
struct IterNextConverter<T>(Option<T>);
pub struct IterNextOutput(Option<PyObject>);
impl<T> IntoPyCallbackOutput<*mut ffi::PyObject> for IterNextConverter<T>
where
T: IntoPy<PyObject>,
{
fn convert(self, py: Python) -> PyResult<*mut ffi::PyObject> {
impl IntoPyCallbackOutput<*mut ffi::PyObject> for IterNextOutput {
fn convert(self, _py: Python) -> PyResult<*mut ffi::PyObject> {
match self.0 {
Some(val) => Ok(val.into_py(py).into_ptr()),
Some(o) => Ok(o.into_ptr()),
None => Err(crate::exceptions::StopIteration::py_err(())),
}
}
}
impl<T> IntoPyCallbackOutput<IterNextOutput> for Option<T>
where
T: IntoPy<PyObject>,
{
fn convert(self, py: Python) -> PyResult<IterNextOutput> {
Ok(IterNextOutput(self.map(|o| o.into_py(py))))
}
}

View File

@ -3,31 +3,31 @@
#[macro_export]
#[doc(hidden)]
macro_rules! py_unary_func {
($trait: ident, $class:ident :: $f:ident, $call:ident, $ret_type: ty $(, $conv:expr)?) => {{
($trait: ident, $class:ident :: $f:ident, $call:ident, $ret_type: ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
where
T: for<'p> $trait<'p>,
{
$crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
$call!(slf, $f)$(.map($conv))?
$call!(slf, $f).convert(py)
})
}
Some(wrap::<$class>)
}};
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $ret_type:ty $(, $conv:expr)?) => {
py_unary_func!($trait, $class::$f, call_ref, $ret_type $(, $conv)?);
($trait:ident, $class:ident :: $f:ident, $ret_type:ty) => {
py_unary_func!($trait, $class::$f, call_ref, $ret_type);
};
($trait:ident, $class:ident :: $f:ident $(, $conv:expr)?) => {
py_unary_func!($trait, $class::$f, call_ref, *mut $crate::ffi::PyObject $(, $conv)?);
($trait:ident, $class:ident :: $f:ident) => {
py_unary_func!($trait, $class::$f, call_ref, *mut $crate::ffi::PyObject);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_unarys_func {
($trait:ident, $class:ident :: $f:ident $(, $conv:expr)?) => {{
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> *mut $crate::ffi::PyObject
where
T: for<'p> $trait<'p>,
@ -38,7 +38,7 @@ macro_rules! py_unarys_func {
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
.map_err(|e| e.into())?;
$class::$f(borrow).into()$(.map($conv))?
$class::$f(borrow).convert(py)
})
}
Some(wrap::<$class>)
@ -49,12 +49,7 @@ macro_rules! py_unarys_func {
#[doc(hidden)]
macro_rules! py_len_func {
($trait:ident, $class:ident :: $f:ident) => {
py_unary_func!(
$trait,
$class::$f,
$crate::ffi::Py_ssize_t,
$crate::callback::LenCallbackOutput
)
py_unary_func!($trait, $class::$f, $crate::ffi::Py_ssize_t)
};
}
@ -62,7 +57,7 @@ macro_rules! py_len_func {
#[doc(hidden)]
macro_rules! py_binary_func {
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $return:ty, $call:ident $(, $conv:expr)?) => {{
($trait:ident, $class:ident :: $f:ident, $return:ty, $call:ident) => {{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg: *mut ffi::PyObject) -> $return
where
T: for<'p> $trait<'p>,
@ -70,16 +65,16 @@ macro_rules! py_binary_func {
$crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
$call!(slf, $f, arg)$(.map($conv))?
$call!(slf, $f, arg).convert(py)
})
}
Some(wrap::<$class>)
}};
($trait:ident, $class:ident :: $f:ident, $return:ty $(, $conv:expr)?) => {
py_binary_func!($trait, $class::$f, $return, call_ref $(, $conv)?)
($trait:ident, $class:ident :: $f:ident, $return:ty) => {
py_binary_func!($trait, $class::$f, $return, call_ref)
};
($trait:ident, $class:ident :: $f:ident $(, $conv:expr)?) => {
py_binary_func!($trait, $class::$f, *mut $crate::ffi::PyObject $(, $conv)?)
($trait:ident, $class:ident :: $f:ident) => {
py_binary_func!($trait, $class::$f, *mut $crate::ffi::PyObject)
};
}
@ -98,7 +93,7 @@ macro_rules! py_binary_num_func {
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs);
$class::$f(lhs.extract()?, rhs.extract()?).into()
$class::$f(lhs.extract()?, rhs.extract()?).convert(py)
})
}
Some(wrap::<$class>)
@ -121,7 +116,7 @@ macro_rules! py_binary_reversed_num_func {
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(rhs);
let arg = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
$class::$f(&*slf.try_borrow()?, arg.extract()?).into()
$class::$f(&*slf.try_borrow()?, arg.extract()?).convert(py)
})
}
Some(wrap::<$class>)
@ -143,7 +138,7 @@ macro_rules! py_binary_self_func {
$crate::callback_body!(py, {
let slf_ = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
call_mut!(slf_, $f, arg)?;
call_mut!(slf_, $f, arg).convert(py)?;
ffi::Py_INCREF(slf);
Ok(slf)
})
@ -169,7 +164,7 @@ macro_rules! py_ssizearg_func {
{
$crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
$call!(slf, $f; arg.into())
$call!(slf, $f; arg.into()).convert(py)
})
}
Some(wrap::<$class>)
@ -200,7 +195,7 @@ macro_rules! py_ternarys_func {
.from_borrowed_ptr::<$crate::types::PyAny>(arg2)
.extract()?;
$class::$f(slf, arg1, arg2).into()
$class::$f(slf, arg1, arg2).convert(py)
})
}
@ -234,7 +229,7 @@ macro_rules! py_ternary_num_func {
.from_borrowed_ptr::<$crate::types::PyAny>(arg3)
.extract()?;
$class::$f(arg1, arg2, arg3).into()
$class::$f(arg1, arg2, arg3).convert(py)
})
}
@ -260,7 +255,7 @@ macro_rules! py_ternary_reversed_num_func {
let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1);
let arg2 = py.from_borrowed_ptr::<$crate::PyAny>(arg3);
$class::$f(&*slf.try_borrow()?, arg1.extract()?, arg2.extract()?).into()
$class::$f(&*slf.try_borrow()?, arg1.extract()?, arg2.extract()?).convert(py)
})
}
Some(wrap::<$class>)
@ -284,7 +279,7 @@ macro_rules! py_dummy_ternary_self_func {
$crate::callback_body!(py, {
let slf_cell = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1);
call_mut!(slf_cell, $f, arg1)?;
call_mut!(slf_cell, $f, arg1).convert(py)?;
ffi::Py_INCREF(slf);
Ok(slf)
})
@ -316,7 +311,7 @@ macro_rules! py_func_set {
} else {
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
let value = py.from_borrowed_ptr::<$crate::PyAny>(value);
call_mut!(slf, $fn_set, name, value)
call_mut!(slf, $fn_set, name, value).convert(py)
}
})
}
@ -341,7 +336,7 @@ macro_rules! py_func_del {
let name = py
.from_borrowed_ptr::<$crate::types::PyAny>(name)
.extract()?;
slf.try_borrow_mut()?.$fn_del(name).into()
slf.try_borrow_mut()?.$fn_del(name).convert(py)
} else {
Err(PyErr::new::<exceptions::NotImplementedError, _>(
"Subscript assignment not supported",
@ -369,10 +364,10 @@ macro_rules! py_func_set_del {
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
if value.is_null() {
call_mut!(slf, $fn_del, name)
call_mut!(slf, $fn_del, name).convert(py)
} else {
let value = py.from_borrowed_ptr::<$crate::PyAny>(value);
call_mut!(slf, $fn_set, name, value)
call_mut!(slf, $fn_set, name, value).convert(py)
}
})
}
@ -382,7 +377,7 @@ macro_rules! py_func_set_del {
macro_rules! _call_impl {
($slf: expr, $fn: ident $(; $args: expr)*) => {
$slf.$fn($($args,)*).into()
$slf.$fn($($args,)*)
};
($slf: expr, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => {
_call_impl!($slf, $fn $(,$raw_args)* $(;$args)* ;$raw_arg.extract()?)

View File

@ -3,8 +3,9 @@
//! Python Mapping Interface
//! Trait and support implementation for implementing mapping support
use crate::err::{PyErr, PyResult};
use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject};
use crate::callback::IntoPyCallbackOutput;
use crate::err::PyErr;
use crate::{exceptions, ffi, FromPyObject, PyClass, PyObject};
/// Mapping interface
#[allow(unused_variables)]
@ -49,29 +50,27 @@ pub trait PyMappingProtocol<'p>: PyClass {
// the existance of a slotted method.
pub trait PyMappingLenProtocol<'p>: PyMappingProtocol<'p> {
type Result: Into<PyResult<usize>>;
type Result: IntoPyCallbackOutput<usize>;
}
pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> {
type Key: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> {
type Key: FromPyObject<'p>;
type Value: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> {
type Key: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
#[doc(hidden)]

View File

@ -3,8 +3,8 @@
//! Python Number Interface
//! Trait and support implementation for implementing number protocol
use crate::err::PyResult;
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
use crate::callback::IntoPyCallbackOutput;
use crate::{ffi, FromPyObject, PyClass, PyObject};
/// Number interface
#[allow(unused_variables)]
@ -318,301 +318,264 @@ pub trait PyNumberProtocol<'p>: PyClass {
pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberMulProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberMatmulProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberTruedivProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberFloordivProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberModProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberDivmodProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberPowProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Modulo: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberLShiftProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRShiftProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberAndProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberXorProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberOrProtocol<'p>: PyNumberProtocol<'p> {
type Left: FromPyObject<'p>;
type Right: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRAddProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRSubProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRMulProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRMatmulProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRTruedivProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRFloordivProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRModProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRDivmodProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRPowProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Modulo: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRLShiftProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRRShiftProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRAndProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRXorProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyNumberNegProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberPosProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberAbsProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberInvertProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberComplexProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberIntProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberFloatProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberRoundProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type NDigits: FromPyObject<'p>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
#[doc(hidden)]

View File

@ -8,9 +8,10 @@
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
//!
use crate::callback::IntoPyCallbackOutput;
use crate::derive_utils::TryFromPyCell;
use crate::err::PyResult;
use crate::{ffi, PyClass, PyObject};
use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python};
/// Python Async/Await support interface.
///
@ -60,33 +61,28 @@ pub trait PyAsyncProtocol<'p>: PyClass {
pub trait PyAsyncAwaitProtocol<'p>: PyAsyncProtocol<'p> {
type Receiver: TryFromPyCell<'p, Self>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyAsyncAiterProtocol<'p>: PyAsyncProtocol<'p> {
type Receiver: TryFromPyCell<'p, Self>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyAsyncAnextProtocol<'p>: PyAsyncProtocol<'p> {
type Receiver: TryFromPyCell<'p, Self>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Option<Self::Success>>>;
type Result: IntoPyCallbackOutput<IterANextOutput>;
}
pub trait PyAsyncAenterProtocol<'p>: PyAsyncProtocol<'p> {
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
type ExcType: crate::FromPyObject<'p>;
type ExcValue: crate::FromPyObject<'p>;
type Traceback: crate::FromPyObject<'p>;
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
#[doc(hidden)]
@ -107,37 +103,34 @@ impl ffi::PyAsyncMethods {
where
T: for<'p> PyAsyncAnextProtocol<'p>,
{
self.am_anext = anext::am_anext::<T>();
self.am_anext = am_anext::<T>();
}
}
mod anext {
use super::PyAsyncAnextProtocol;
use crate::callback::IntoPyCallbackOutput;
use crate::err::PyResult;
use crate::IntoPyPointer;
use crate::Python;
use crate::{ffi, IntoPy, PyObject};
pub struct IterANextOutput(Option<PyObject>);
struct IterANextOutput<T>(Option<T>);
impl<T> IntoPyCallbackOutput<*mut ffi::PyObject> for IterANextOutput<T>
where
T: IntoPy<PyObject>,
{
fn convert(self, py: Python) -> PyResult<*mut ffi::PyObject> {
impl IntoPyCallbackOutput<*mut ffi::PyObject> for IterANextOutput {
fn convert(self, _py: Python) -> PyResult<*mut ffi::PyObject> {
match self.0 {
Some(val) => Ok(val.into_py(py).into_ptr()),
Some(o) => Ok(o.into_ptr()),
None => Err(crate::exceptions::StopAsyncIteration::py_err(())),
}
}
}
}
#[inline]
pub(super) fn am_anext<T>() -> Option<ffi::unaryfunc>
where
T: for<'p> PyAsyncAnextProtocol<'p>,
{
py_unarys_func!(PyAsyncAnextProtocol, T::__anext__, IterANextOutput)
impl<T> IntoPyCallbackOutput<IterANextOutput> for Option<T>
where
T: IntoPy<PyObject>,
{
fn convert(self, py: Python) -> PyResult<IterANextOutput> {
Ok(IterANextOutput(self.map(|o| o.into_py(py))))
}
}
#[inline]
fn am_anext<T>() -> Option<ffi::unaryfunc>
where
T: for<'p> PyAsyncAnextProtocol<'p>,
{
py_unarys_func!(PyAsyncAnextProtocol, T::__anext__)
}

View File

@ -3,8 +3,9 @@
//! Python Sequence Interface
//! Trait and support implementation for implementing sequence
use crate::callback::IntoPyCallbackOutput;
use crate::conversion::{FromPyObject, IntoPy};
use crate::err::{PyErr, PyResult};
use crate::err::PyErr;
use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject};
use std::os::raw::c_int;
@ -79,51 +80,52 @@ pub trait PySequenceProtocol<'p>: PyClass + Sized {
// the existance of a slotted method.
pub trait PySequenceLenProtocol<'p>: PySequenceProtocol<'p> {
type Result: Into<PyResult<usize>>;
type Result: IntoPyCallbackOutput<usize>;
}
pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> {
type Index: FromPyObject<'p> + From<isize>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> {
type Index: FromPyObject<'p> + From<isize>;
type Value: FromPyObject<'p>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> {
type Index: FromPyObject<'p> + From<isize>;
type Result: Into<PyResult<()>>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PySequenceContainsProtocol<'p>: PySequenceProtocol<'p> {
type Item: FromPyObject<'p>;
type Result: Into<PyResult<bool>>;
type Result: IntoPyCallbackOutput<bool>;
}
pub trait PySequenceConcatProtocol<'p>: PySequenceProtocol<'p> {
type Other: FromPyObject<'p>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
type Index: FromPyObject<'p> + From<isize>;
type Success: IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PySequenceInplaceConcatProtocol<'p>: PySequenceProtocol<'p> + IntoPy<PyObject> {
pub trait PySequenceInplaceConcatProtocol<'p>:
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
{
type Other: FromPyObject<'p>;
type Result: Into<PyResult<Self>>;
type Result: IntoPyCallbackOutput<Self>;
}
pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + IntoPy<PyObject> {
pub trait PySequenceInplaceRepeatProtocol<'p>:
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
{
type Index: FromPyObject<'p> + From<isize>;
type Result: Into<PyResult<Self>>;
type Result: IntoPyCallbackOutput<Self>;
}
#[doc(hidden)]
@ -230,7 +232,7 @@ mod sq_ass_item_impl {
let mut slf = slf.try_borrow_mut()?;
let value = py.from_borrowed_ptr::<PyAny>(value);
let value = value.extract()?;
slf.__setitem__(key.into(), value).into()
crate::callback::convert(py, slf.__setitem__(key.into(), value))
})
}
Some(wrap::<T>)
@ -252,7 +254,7 @@ mod sq_ass_item_impl {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
if value.is_null() {
slf.borrow_mut().__delitem__(key.into()).into()
crate::callback::convert(py, slf.borrow_mut().__delitem__(key.into()))
} else {
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
"Item assignment not supported by {:?}",
@ -280,12 +282,12 @@ mod sq_ass_item_impl {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
if value.is_null() {
call_mut!(slf, __delitem__; key.into())
call_mut!(slf, __delitem__; key.into()).convert(py)
} else {
let value = py.from_borrowed_ptr::<PyAny>(value);
let mut slf_ = slf.try_borrow_mut()?;
let value = value.extract()?;
slf_.__setitem__(key.into(), value).into()
slf_.__setitem__(key.into(), value).convert(py)
}
})
}

View File

@ -1,6 +1,5 @@
use pyo3::class::PySequenceProtocol;
use pyo3::exceptions::IndexError;
use pyo3::exceptions::ValueError;
use pyo3::exceptions::{IndexError, ValueError};
use pyo3::prelude::*;
use pyo3::types::{IntoPyDict, PyList};
@ -232,3 +231,38 @@ fn test_generic_list_set() {
vec![1.to_object(py), 2.to_object(py), 3.to_object(py)]
);
}
#[pyclass]
struct OptionList {
#[pyo3(get, set)]
items: Vec<Option<i64>>,
}
#[pyproto]
impl PySequenceProtocol for OptionList {
fn __getitem__(&self, idx: isize) -> PyResult<Option<i64>> {
match self.items.get(idx as usize) {
Some(x) => Ok(*x),
None => Err(PyErr::new::<IndexError, _>("Index out of bounds")),
}
}
}
#[test]
fn test_option_list_get() {
// Regression test for #798
let gil = Python::acquire_gil();
let py = gil.python();
let list = PyCell::new(
py,
OptionList {
items: vec![Some(1), None],
},
)
.unwrap();
py_assert!(py, list, "list[0] == 1");
py_assert!(py, list, "list[1] == None");
py_expect_exception!(py, list, "list[2]", IndexError);
}