Relax return type requirements
Allows returning essentially arbitrary types by wrapping them into a PyResult. This is done with a conversion trait that specializes for PyResult.
This commit is contained in:
parent
ced4eb532c
commit
45bb09b3e8
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Argument {
|
pub enum Argument {
|
||||||
VarArgsSeparator,
|
VarArgsSeparator,
|
||||||
VarArgs(String),
|
VarArgs(String),
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use syn;
|
|
||||||
use quote::{Tokens, Ident};
|
|
||||||
|
|
||||||
use args::{Argument, parse_arguments};
|
use args::{Argument, parse_arguments};
|
||||||
|
use quote::{Ident, Tokens};
|
||||||
|
use syn;
|
||||||
use utils::for_err_msg;
|
use utils::for_err_msg;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct FnArg<'a> {
|
pub struct FnArg<'a> {
|
||||||
pub name: &'a syn::Ident,
|
pub name: &'a syn::Ident,
|
||||||
pub mode: &'a syn::BindingMode,
|
pub mode: &'a syn::BindingMode,
|
||||||
|
@ -29,6 +28,7 @@ pub enum FnType {
|
||||||
FnStatic,
|
FnStatic,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct FnSpec<'a> {
|
pub struct FnSpec<'a> {
|
||||||
pub tp: FnType,
|
pub tp: FnType,
|
||||||
pub attrs: Vec<Argument>,
|
pub attrs: Vec<Argument>,
|
||||||
|
@ -36,8 +36,14 @@ pub struct FnSpec<'a> {
|
||||||
pub output: syn::Ty,
|
pub output: syn::Ty,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FnSpec<'a> {
|
pub fn get_return_info(output: &syn::FunctionRetTy) -> syn::Ty {
|
||||||
|
match output {
|
||||||
|
syn::FunctionRetTy::Default => syn::Ty::Tup(vec![]),
|
||||||
|
syn::FunctionRetTy::Ty(ref ty) => ty.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FnSpec<'a> {
|
||||||
/// Parser function signature and function attributes
|
/// Parser function signature and function attributes
|
||||||
pub fn parse(name: &'a syn::Ident,
|
pub fn parse(name: &'a syn::Ident,
|
||||||
sig: &'a syn::MethodSig,
|
sig: &'a syn::MethodSig,
|
||||||
|
@ -96,10 +102,7 @@ impl<'a> FnSpec<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = match sig.decl.output {
|
let ty = get_return_info(&sig.decl.output);
|
||||||
syn::FunctionRetTy::Default => syn::Ty::Infer,
|
|
||||||
syn::FunctionRetTy::Ty(ref ty) => ty.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
FnSpec {
|
FnSpec {
|
||||||
tp: fn_type,
|
tp: fn_type,
|
||||||
|
|
|
@ -227,22 +227,21 @@ fn wrap_fn(item: &mut syn::Item) -> Option<Box<syn::Block>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt = method::check_arg_ty_and_optional(&name, ty);
|
let opt = method::check_arg_ty_and_optional(&name, ty);
|
||||||
arguments.push(method::FnArg {name: ident,
|
arguments.push(method::FnArg {
|
||||||
mode: mode,
|
name: ident,
|
||||||
ty: ty,
|
mode: mode,
|
||||||
optional: opt,
|
ty: ty,
|
||||||
py: py,
|
optional: opt,
|
||||||
reference: method::is_ref(&name, ty)});
|
py: py,
|
||||||
|
reference: method::is_ref(&name, ty),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
&syn::FnArg::Ignored(_) =>
|
&syn::FnArg::Ignored(_) =>
|
||||||
panic!("ignored argument: {:?}", name),
|
panic!("ignored argument: {:?}", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = match decl.output {
|
let ty = method::get_return_info(&decl.output);
|
||||||
syn::FunctionRetTy::Default => syn::Ty::Infer,
|
|
||||||
syn::FunctionRetTy::Ty(ref ty) => ty.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let spec = method::FnSpec {
|
let spec = method::FnSpec {
|
||||||
tp: method::FnType::Fn,
|
tp: method::FnType::Fn,
|
||||||
|
@ -309,11 +308,11 @@ pub fn impl_wrap(name: &syn::Ident, spec: &method::FnSpec) -> Tokens {
|
||||||
|item| if item.1.py {syn::Ident::from("_py")} else {
|
|item| if item.1.py {syn::Ident::from("_py")} else {
|
||||||
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
||||||
let cb = quote! {{
|
let cb = quote! {{
|
||||||
#name(#(#names),*)
|
#name(#(#names),*).return_type_into_py_result()
|
||||||
}};
|
}};
|
||||||
|
|
||||||
let body = py_method::impl_arg_params(spec, cb);
|
let body = py_method::impl_arg_params(spec, cb);
|
||||||
let output = &spec.output;
|
let body_to_result = py_method::body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(unused_variables, unused_imports)]
|
#[allow(unused_variables, unused_imports)]
|
||||||
|
@ -329,9 +328,7 @@ pub fn impl_wrap(name: &syn::Ident, spec: &method::FnSpec) -> Tokens {
|
||||||
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
||||||
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
||||||
|
|
||||||
let _result: #output = {
|
#body_to_result
|
||||||
#body
|
|
||||||
};
|
|
||||||
_pyo3::callback::cb_convert(
|
_pyo3::callback::cb_convert(
|
||||||
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,7 +337,7 @@ fn impl_descriptors(cls: &syn::Ty, descriptors: Vec<(syn::Field, Vec<FnType>)>)
|
||||||
py: true,
|
py: true,
|
||||||
reference: false
|
reference: false
|
||||||
}],
|
}],
|
||||||
output: syn::parse::ty("PyResult<()>").expect("error parse PyResult<()>")
|
output: syn::parse::ty("PyResult<()>").expect("error parse PyResult<()>"),
|
||||||
};
|
};
|
||||||
impl_py_setter_def(&name, doc, setter, &impl_wrap_setter(&Box::new(cls.clone()), &setter_name, &spec))
|
impl_py_setter_def(&name, doc, setter, &impl_wrap_setter(&Box::new(cls.clone()), &setter_name, &spec))
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,12 +43,23 @@ fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn body_to_result(body: &Tokens, spec: &FnSpec) -> Tokens {
|
||||||
|
let output = &spec.output;
|
||||||
|
quote! {
|
||||||
|
use pyo3::ReturnTypeIntoPyResult;
|
||||||
|
let _result: PyResult<<#output as ReturnTypeIntoPyResult>::Inner> = {
|
||||||
|
#body
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: bool) -> Tokens {
|
pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: bool) -> Tokens {
|
||||||
let cb = impl_call(cls, name, &spec);
|
let body = impl_call(cls, name, &spec);
|
||||||
let output = &spec.output;
|
|
||||||
|
|
||||||
if spec.args.is_empty() && noargs {
|
if spec.args.is_empty() && noargs {
|
||||||
|
let body_to_result = body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe extern "C" fn __wrap(
|
unsafe extern "C" fn __wrap(
|
||||||
_slf: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
|
_slf: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
|
||||||
|
@ -59,15 +70,14 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: b
|
||||||
let _py = _pyo3::Python::assume_gil_acquired();
|
let _py = _pyo3::Python::assume_gil_acquired();
|
||||||
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
|
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);
|
||||||
|
|
||||||
let _result: #output = {
|
#body_to_result
|
||||||
#cb
|
|
||||||
};
|
|
||||||
_pyo3::callback::cb_convert(
|
_pyo3::callback::cb_convert(
|
||||||
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let body = impl_arg_params(&spec, cb);
|
let body = impl_arg_params(&spec, body);
|
||||||
|
let body_to_result = body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe extern "C" fn __wrap(
|
unsafe extern "C" fn __wrap(
|
||||||
|
@ -84,9 +94,7 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: b
|
||||||
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
||||||
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
||||||
|
|
||||||
let _result: #output = {
|
#body_to_result
|
||||||
#body
|
|
||||||
};
|
|
||||||
_pyo3::callback::cb_convert(
|
_pyo3::callback::cb_convert(
|
||||||
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
||||||
}
|
}
|
||||||
|
@ -128,11 +136,11 @@ pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> To
|
||||||
|item| if item.1.py {syn::Ident::from("_py")} else {
|
|item| if item.1.py {syn::Ident::from("_py")} else {
|
||||||
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
||||||
let cb = quote! {{
|
let cb = quote! {{
|
||||||
#cls::#name(&_obj, #(#names),*)
|
#cls::#name(&_obj, #(#names),*).return_type_into_py_result()
|
||||||
}};
|
}};
|
||||||
|
|
||||||
let body = impl_arg_params(spec, cb);
|
let body = impl_arg_params(spec, cb);
|
||||||
let output = &spec.output;
|
let body_to_result = body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
@ -152,9 +160,7 @@ pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> To
|
||||||
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
||||||
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
||||||
|
|
||||||
let _result: #output = {
|
#body_to_result
|
||||||
#body
|
|
||||||
};
|
|
||||||
|
|
||||||
match _result {
|
match _result {
|
||||||
Ok(_) => _obj.into_ptr(),
|
Ok(_) => _obj.into_ptr(),
|
||||||
|
@ -176,7 +182,13 @@ pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> To
|
||||||
/// Generate function wrapper for ffi::initproc
|
/// Generate function wrapper for ffi::initproc
|
||||||
fn impl_wrap_init(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
|
fn impl_wrap_init(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
|
||||||
let cb = impl_call(cls, name, &spec);
|
let cb = impl_call(cls, name, &spec);
|
||||||
|
let output = &spec.output;
|
||||||
|
if quote! {#output} != quote! {PyResult<()>} || quote! {#output} != quote! {()}{
|
||||||
|
panic!("Constructor must return PyResult<()> or a ()");
|
||||||
|
}
|
||||||
|
|
||||||
let body = impl_arg_params(&spec, cb);
|
let body = impl_arg_params(&spec, cb);
|
||||||
|
let body_to_result = body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
@ -192,9 +204,7 @@ fn impl_wrap_init(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Token
|
||||||
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
||||||
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
||||||
|
|
||||||
let _result: PyResult<()> = {
|
#body_to_result
|
||||||
#body
|
|
||||||
};
|
|
||||||
match _result {
|
match _result {
|
||||||
Ok(_) => 0,
|
Ok(_) => 0,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -212,10 +222,11 @@ pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
|
||||||
|item| if item.1.py {syn::Ident::from("_py")} else {
|
|item| if item.1.py {syn::Ident::from("_py")} else {
|
||||||
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
||||||
let cb = quote! {{
|
let cb = quote! {{
|
||||||
#cls::#name(&_cls, #(#names),*)
|
#cls::#name(&_cls, #(#names),*).return_type_into_py_result()
|
||||||
}};
|
}};
|
||||||
|
|
||||||
let body = impl_arg_params(spec, cb);
|
let body = impl_arg_params(spec, cb);
|
||||||
let output = &spec.output;
|
let body_to_result = body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
@ -231,9 +242,7 @@ pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
|
||||||
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
||||||
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
||||||
|
|
||||||
let _result: #output = {
|
#body_to_result
|
||||||
#body
|
|
||||||
};
|
|
||||||
_pyo3::callback::cb_convert(
|
_pyo3::callback::cb_convert(
|
||||||
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
||||||
}
|
}
|
||||||
|
@ -246,11 +255,11 @@ pub fn impl_wrap_static(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
|
||||||
|item| if item.1.py {syn::Ident::from("_py")} else {
|
|item| if item.1.py {syn::Ident::from("_py")} else {
|
||||||
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
syn::Ident::from(format!("arg{}", item.0))}).collect();
|
||||||
let cb = quote! {{
|
let cb = quote! {{
|
||||||
#cls::#name(#(#names),*)
|
#cls::#name(#(#names),*).return_type_into_py_result()
|
||||||
}};
|
}};
|
||||||
|
|
||||||
let body = impl_arg_params(spec, cb);
|
let body = impl_arg_params(spec, cb);
|
||||||
let output = &spec.output;
|
let body_to_result = body_to_result(&body, spec);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
@ -265,9 +274,7 @@ pub fn impl_wrap_static(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
|
||||||
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
let _args = _py.from_borrowed_ptr::<_pyo3::PyTuple>(_args);
|
||||||
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
let _kwargs = _pyo3::argparse::get_kwargs(_py, _kwargs);
|
||||||
|
|
||||||
let _result: #output = {
|
#body_to_result
|
||||||
#body
|
|
||||||
};
|
|
||||||
_pyo3::callback::cb_convert(
|
_pyo3::callback::cb_convert(
|
||||||
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
_pyo3::callback::PyObjectCallbackConverter, _py, _result)
|
||||||
}
|
}
|
||||||
|
@ -344,7 +351,7 @@ fn impl_call(_cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens {
|
||||||
}
|
}
|
||||||
).collect();
|
).collect();
|
||||||
quote! {{
|
quote! {{
|
||||||
_slf.#fname(#(#names),*)
|
_slf.#fname(#(#names),*).return_type_into_py_result()
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,6 +400,7 @@ pub fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
|
||||||
let mut rargs = spec.args.clone();
|
let mut rargs = spec.args.clone();
|
||||||
rargs.reverse();
|
rargs.reverse();
|
||||||
let mut body = body;
|
let mut body = body;
|
||||||
|
|
||||||
for (idx, arg) in rargs.iter().enumerate() {
|
for (idx, arg) in rargs.iter().enumerate() {
|
||||||
body = impl_arg_param(&arg, &spec, &body, len-idx-1);
|
body = impl_arg_param(&arg, &spec, &body, len-idx-1);
|
||||||
}
|
}
|
||||||
|
@ -424,7 +432,7 @@ pub fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
|
||||||
|
|
||||||
fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens, idx: usize) -> Tokens {
|
fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens, idx: usize) -> Tokens {
|
||||||
if arg.py {
|
if arg.py {
|
||||||
return body.clone()
|
return body.clone();
|
||||||
}
|
}
|
||||||
let ty = arg.ty;
|
let ty = arg.ty;
|
||||||
let name = arg.name;
|
let name = arg.name;
|
||||||
|
@ -444,19 +452,17 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens, idx: usize) -> Toke
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if spec.is_kwargs(&name) {
|
||||||
else if spec.is_kwargs(&name) {
|
|
||||||
quote! {{
|
quote! {{
|
||||||
let #arg_name = _kwargs;
|
let #arg_name = _kwargs;
|
||||||
#body
|
#body
|
||||||
}}
|
}}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if let Some(_) = arg.optional {
|
if let Some(_) = arg.optional {
|
||||||
// default value
|
// default value
|
||||||
let mut default = Tokens::new();
|
let mut default = Tokens::new();
|
||||||
if let Some(d) = spec.default_value(name) {
|
if let Some(d) = spec.default_value(name) {
|
||||||
let dt = quote!{ Some(#d) };
|
let dt = quote! { Some(#d) };
|
||||||
dt.to_tokens(&mut default);
|
dt.to_tokens(&mut default);
|
||||||
} else {
|
} else {
|
||||||
syn::Ident::from("None").to_tokens(&mut default);
|
syn::Ident::from("None").to_tokens(&mut default);
|
||||||
|
@ -500,8 +506,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens, idx: usize) -> Toke
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
quote! {
|
quote! {
|
||||||
match _iter.next().unwrap().as_ref().unwrap().extract() {
|
match _iter.next().unwrap().as_ref().unwrap().extract() {
|
||||||
Ok(#arg_name) => {
|
Ok(#arg_name) => {
|
||||||
|
|
|
@ -301,3 +301,31 @@ impl<T> PyTryFrom for T where T: PyTypeInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// This trait wraps a T: IntoPyObject into PyResult<T> while PyResult<T> remains PyResult<T>.
|
||||||
|
///
|
||||||
|
/// This is necessaty because proc macros run before typechecking and can't decide
|
||||||
|
/// whether a return type is a (possibly aliased) PyResult or not. It is also quite handy because
|
||||||
|
/// the codegen is currently built on the assumption that all functions return a PyResult.
|
||||||
|
pub trait ReturnTypeIntoPyResult {
|
||||||
|
type Inner: ToPyObject;
|
||||||
|
|
||||||
|
fn return_type_into_py_result(self) -> PyResult<Self::Inner>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ToPyObject> ReturnTypeIntoPyResult for T {
|
||||||
|
type Inner = T;
|
||||||
|
|
||||||
|
default fn return_type_into_py_result(self) -> PyResult<Self::Inner> {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ToPyObject> ReturnTypeIntoPyResult for PyResult<T> {
|
||||||
|
type Inner = T;
|
||||||
|
|
||||||
|
fn return_type_into_py_result(self) -> PyResult<Self::Inner> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
|
@ -140,7 +140,7 @@ pub struct PyDowncastError;
|
||||||
/// Helper conversion trait that allows to use custom arguments for exception constructor.
|
/// Helper conversion trait that allows to use custom arguments for exception constructor.
|
||||||
pub trait PyErrArguments {
|
pub trait PyErrArguments {
|
||||||
/// Arguments for exception
|
/// Arguments for exception
|
||||||
fn arguments(&self, Python) -> PyObject;
|
fn arguments(&self, _: Python) -> PyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyErr {
|
impl PyErr {
|
||||||
|
|
|
@ -165,7 +165,8 @@ pub use python::{Python, ToPyPointer, IntoPyPointer, IntoPyDictPointer};
|
||||||
pub use pythonrun::{GILGuard, GILPool, prepare_freethreaded_python, prepare_pyo3_library};
|
pub use pythonrun::{GILGuard, GILPool, prepare_freethreaded_python, prepare_pyo3_library};
|
||||||
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
|
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
|
||||||
pub use conversion::{FromPyObject, PyTryFrom, PyTryInto,
|
pub use conversion::{FromPyObject, PyTryFrom, PyTryInto,
|
||||||
ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple};
|
ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple,
|
||||||
|
ReturnTypeIntoPyResult};
|
||||||
pub mod class;
|
pub mod class;
|
||||||
pub use class::*;
|
pub use class::*;
|
||||||
|
|
||||||
|
|
|
@ -396,6 +396,11 @@ impl StaticMethod {
|
||||||
fn method(py: Python) -> PyResult<&'static str> {
|
fn method(py: Python) -> PyResult<&'static str> {
|
||||||
Ok("StaticMethod.method()!")
|
Ok("StaticMethod.method()!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[staticmethod]
|
||||||
|
fn no_parameters() -> PyResult<&'static str> {
|
||||||
|
Ok("StaticMethod.no_parameters()!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -408,6 +413,7 @@ fn static_method() {
|
||||||
d.set_item("C", py.get_type::<StaticMethod>()).unwrap();
|
d.set_item("C", py.get_type::<StaticMethod>()).unwrap();
|
||||||
py.run("assert C.method() == 'StaticMethod.method()!'", None, Some(d)).unwrap();
|
py.run("assert C.method() == 'StaticMethod.method()!'", None, Some(d)).unwrap();
|
||||||
py.run("assert C().method() == 'StaticMethod.method()!'", None, Some(d)).unwrap();
|
py.run("assert C().method() == 'StaticMethod.method()!'", None, Some(d)).unwrap();
|
||||||
|
py.run("assert C.no_parameters() == 'StaticMethod.no_parameters()!'", None, Some(d)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[py::class]
|
#[py::class]
|
||||||
|
@ -1444,4 +1450,4 @@ fn mut_ref_arg() {
|
||||||
|
|
||||||
py.run("inst1.set_other(inst2)", None, Some(d)).unwrap();
|
py.run("inst1.set_other(inst2)", None, Some(d)).unwrap();
|
||||||
assert_eq!(inst2.as_ref(py).n, 100);
|
assert_eq!(inst2.as_ref(py).n, 100);
|
||||||
}
|
}
|
Loading…
Reference in New Issue