Improve the span and message for return types of pymethod/functions (#4220)
* Improve the span and message for return types of pymethod/functions * Don't pass the span * fixup trybuild output --------- Co-authored-by: David Hewitt <mail@davidhewitt.dev>
This commit is contained in:
parent
e6b2216b04
commit
b25b3b3a7b
|
@ -32,7 +32,7 @@ impl<'ctx> Deprecations<'ctx> {
|
|||
|
||||
impl<'ctx> ToTokens for Deprecations<'ctx> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self(deprecations, Ctx { pyo3_path }) = self;
|
||||
let Self(deprecations, Ctx { pyo3_path, .. }) = self;
|
||||
|
||||
for (deprecation, span) in deprecations {
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
|
||||
|
|
|
@ -45,7 +45,7 @@ impl<'a> Enum<'a> {
|
|||
|
||||
/// Build derivation body for enums.
|
||||
fn build(&self, ctx: &Ctx) -> (TokenStream, TokenStream) {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let mut var_extracts = Vec::new();
|
||||
let mut variant_names = Vec::new();
|
||||
let mut error_names = Vec::new();
|
||||
|
@ -263,7 +263,7 @@ impl<'a> Container<'a> {
|
|||
from_py_with: &Option<FromPyWithAttribute>,
|
||||
ctx: &Ctx,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_ty = &self.path;
|
||||
let struct_name = self.name();
|
||||
if let Some(ident) = field_ident {
|
||||
|
@ -329,7 +329,7 @@ impl<'a> Container<'a> {
|
|||
struct_fields: &[TupleStructField],
|
||||
ctx: &Ctx,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_ty = &self.path;
|
||||
let struct_name = &self.name();
|
||||
let field_idents: Vec<_> = (0..struct_fields.len())
|
||||
|
@ -382,7 +382,7 @@ impl<'a> Container<'a> {
|
|||
struct_fields: &[NamedStructField<'_>],
|
||||
ctx: &Ctx,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_ty = &self.path;
|
||||
let struct_name = &self.name();
|
||||
let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new();
|
||||
|
@ -670,8 +670,8 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
|
|||
.push(parse_quote!(#gen_ident: FromPyObject<#lt_param>))
|
||||
}
|
||||
let options = ContainerOptions::from_attrs(&tokens.attrs)?;
|
||||
let ctx = &Ctx::new(&options.krate);
|
||||
let Ctx { pyo3_path } = &ctx;
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let Ctx { pyo3_path, .. } = &ctx;
|
||||
|
||||
let (derives, from_py_with_deprecations) = match &tokens.data {
|
||||
syn::Data::Enum(en) => {
|
||||
|
|
|
@ -30,7 +30,7 @@ impl ConstSpec<'_> {
|
|||
|
||||
/// Null-terminated Python name
|
||||
pub fn null_terminated_python_name(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let name = self.python_name().to_string();
|
||||
quote!(#pyo3_path::ffi::c_str!(#name))
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ impl FnType {
|
|||
holders: &mut Holders,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
match self {
|
||||
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) => {
|
||||
let mut receiver = st.receiver(
|
||||
|
@ -281,7 +281,7 @@ pub enum ExtractErrorMode {
|
|||
|
||||
impl ExtractErrorMode {
|
||||
pub fn handle_error(self, extract: TokenStream, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
match self {
|
||||
ExtractErrorMode::Raise => quote! { #extract? },
|
||||
ExtractErrorMode::NotImplemented => quote! {
|
||||
|
@ -306,7 +306,7 @@ impl SelfType {
|
|||
// main macro callsite.
|
||||
let py = syn::Ident::new("py", Span::call_site());
|
||||
let slf = syn::Ident::new("_slf", Span::call_site());
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
match self {
|
||||
SelfType::Receiver { span, mutable } => {
|
||||
let method = if *mutable {
|
||||
|
@ -473,7 +473,7 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
|
||||
pub fn null_terminated_python_name(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let span = self.python_name.span();
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(span);
|
||||
let name = self.python_name.to_string();
|
||||
|
@ -600,7 +600,10 @@ impl<'a> FnSpec<'a> {
|
|||
cls: Option<&syn::Type>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx {
|
||||
pyo3_path,
|
||||
output_span,
|
||||
} = ctx;
|
||||
let mut cancel_handle_iter = self
|
||||
.signature
|
||||
.arguments
|
||||
|
@ -703,7 +706,18 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
}
|
||||
};
|
||||
quotes::map_result_into_ptr(quotes::ok_wrap(call, ctx), ctx)
|
||||
|
||||
// We must assign the output_span to the return value of the call,
|
||||
// but *not* of the call itself otherwise the spans get really weird
|
||||
let ret_expr = quote! { let ret = #call; };
|
||||
let ret_var = quote_spanned! {*output_span=> ret };
|
||||
let return_conversion = quotes::map_result_into_ptr(quotes::ok_wrap(ret_var, ctx), ctx);
|
||||
quote! {
|
||||
{
|
||||
#ret_expr
|
||||
#return_conversion
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let func_name = &self.name;
|
||||
|
@ -731,7 +745,6 @@ impl<'a> FnSpec<'a> {
|
|||
let call = rust_call(args, &mut holders);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
py: #pyo3_path::Python<'py>,
|
||||
|
@ -804,7 +817,7 @@ impl<'a> FnSpec<'a> {
|
|||
let self_arg = self
|
||||
.tp
|
||||
.self_arg(cls, ExtractErrorMode::Raise, &mut holders, ctx);
|
||||
let call = quote! { #rust_name(#self_arg #(#args),*) };
|
||||
let call = quote_spanned! {*output_span=> #rust_name(#self_arg #(#args),*) };
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
quote! {
|
||||
|
@ -833,7 +846,7 @@ impl<'a> FnSpec<'a> {
|
|||
/// Return a `PyMethodDef` constructor for this function, matching the selected
|
||||
/// calling convention.
|
||||
pub fn get_methoddef(&self, wrapper: impl ToTokens, doc: &PythonDoc, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let python_name = self.null_terminated_python_name(ctx);
|
||||
match self.convention {
|
||||
CallingConvention::Noargs => quote! {
|
||||
|
|
|
@ -90,8 +90,8 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
|
|||
bail_spanned!(module.span() => "`#[pymodule]` can only be used on inline modules")
|
||||
};
|
||||
let options = PyModuleOptions::from_attrs(attrs)?;
|
||||
let ctx = &Ctx::new(&options.krate);
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let doc = get_doc(attrs, None, ctx);
|
||||
let name = options.name.unwrap_or_else(|| ident.unraw());
|
||||
let full_name = if let Some(module) = &options.module {
|
||||
|
@ -326,9 +326,9 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
|
|||
pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream> {
|
||||
let options = PyModuleOptions::from_attrs(&mut function.attrs)?;
|
||||
process_functions_in_module(&options, &mut function)?;
|
||||
let ctx = &Ctx::new(&options.krate);
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let stmts = std::mem::take(&mut function.block.stmts);
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let ident = &function.sig.ident;
|
||||
let name = options.name.unwrap_or_else(|| ident.unraw());
|
||||
let vis = &function.vis;
|
||||
|
@ -400,7 +400,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
|
|||
}
|
||||
|
||||
fn module_initialization(name: &syn::Ident, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let pyinit_symbol = format!("PyInit_{}", name);
|
||||
let name = name.to_string();
|
||||
|
||||
|
@ -424,8 +424,8 @@ fn module_initialization(name: &syn::Ident, ctx: &Ctx) -> TokenStream {
|
|||
|
||||
/// Finds and takes care of the #[pyfn(...)] in `#[pymodule]`
|
||||
fn process_functions_in_module(options: &PyModuleOptions, func: &mut syn::ItemFn) -> Result<()> {
|
||||
let ctx = &Ctx::new(&options.krate);
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let mut stmts: Vec<syn::Stmt> = Vec::new();
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
|
|
|
@ -48,7 +48,7 @@ impl Holders {
|
|||
}
|
||||
|
||||
pub fn init_holders(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let holders = &self.holders;
|
||||
let gil_refs_checkers = self.gil_refs_checkers.iter().map(|checker| match checker {
|
||||
GilRefChecker::FunctionArg(ident) => ident,
|
||||
|
@ -94,7 +94,7 @@ pub(crate) fn check_arg_for_gil_refs(
|
|||
gil_refs_checker: syn::Ident,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
quote! {
|
||||
#pyo3_path::impl_::deprecations::inspect_type(#tokens, &#gil_refs_checker)
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ pub fn impl_arg_params(
|
|||
ctx: &Ctx,
|
||||
) -> (TokenStream, Vec<TokenStream>) {
|
||||
let args_array = syn::Ident::new("output", Span::call_site());
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let from_py_with = spec
|
||||
.signature
|
||||
|
@ -242,7 +242,7 @@ fn impl_arg_param(
|
|||
holders: &mut Holders,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let args_array = syn::Ident::new("output", Span::call_site());
|
||||
|
||||
match arg {
|
||||
|
@ -290,7 +290,7 @@ pub(crate) fn impl_regular_arg_param(
|
|||
holders: &mut Holders,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(arg.ty.span());
|
||||
|
||||
// Use this macro inside this function, to ensure that all code generated here is associated
|
||||
|
|
|
@ -227,7 +227,7 @@ pub fn build_py_class(
|
|||
) -> syn::Result<TokenStream> {
|
||||
args.options.take_pyo3_options(&mut class.attrs)?;
|
||||
|
||||
let ctx = &Ctx::new(&args.options.krate);
|
||||
let ctx = &Ctx::new(&args.options.krate, None);
|
||||
let doc = utils::get_doc(&class.attrs, None, ctx);
|
||||
|
||||
if let Some(lt) = class.generics.lifetimes().next() {
|
||||
|
@ -383,7 +383,7 @@ fn impl_class(
|
|||
methods_type: PyClassMethodsType,
|
||||
ctx: &Ctx,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let pytypeinfo_impl = impl_pytypeinfo(cls, args, None, ctx);
|
||||
|
||||
let (default_richcmp, default_richcmp_slot) =
|
||||
|
@ -457,7 +457,7 @@ pub fn build_py_enum(
|
|||
) -> syn::Result<TokenStream> {
|
||||
args.options.take_pyo3_options(&mut enum_.attrs)?;
|
||||
|
||||
let ctx = &Ctx::new(&args.options.krate);
|
||||
let ctx = &Ctx::new(&args.options.krate, None);
|
||||
if let Some(extends) = &args.options.extends {
|
||||
bail_spanned!(extends.span() => "enums can't extend from other classes");
|
||||
} else if let Some(subclass) = &args.options.subclass {
|
||||
|
@ -872,7 +872,7 @@ fn impl_complex_enum(
|
|||
methods_type: PyClassMethodsType,
|
||||
ctx: &Ctx,
|
||||
) -> Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = complex_enum.ident;
|
||||
let ty: syn::Type = syn::parse_quote!(#cls);
|
||||
|
||||
|
@ -886,7 +886,7 @@ fn impl_complex_enum(
|
|||
rigged_args
|
||||
};
|
||||
|
||||
let ctx = &Ctx::new(&args.options.krate);
|
||||
let ctx = &Ctx::new(&args.options.krate, None);
|
||||
let cls = complex_enum.ident;
|
||||
let variants = complex_enum.variants;
|
||||
let pytypeinfo = impl_pytypeinfo(cls, &args, None, ctx);
|
||||
|
@ -1071,7 +1071,7 @@ fn impl_complex_enum_struct_variant_cls(
|
|||
variant: &PyClassEnumStructVariant<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<(TokenStream, Vec<MethodAndMethodDef>, Vec<MethodAndSlotDef>)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let variant_ident = &variant.ident;
|
||||
let variant_cls = gen_complex_enum_variant_class_ident(enum_name, variant.ident);
|
||||
let variant_cls_type = parse_quote!(#variant_cls);
|
||||
|
@ -1135,7 +1135,7 @@ fn impl_complex_enum_tuple_variant_field_getters(
|
|||
field_names: &mut Vec<Ident>,
|
||||
fields_types: &mut Vec<syn::Type>,
|
||||
) -> Result<(Vec<MethodAndMethodDef>, Vec<syn::ImplItemFn>)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let mut field_getters = vec![];
|
||||
let mut field_getter_impls = vec![];
|
||||
|
@ -1182,7 +1182,7 @@ fn impl_complex_enum_tuple_variant_len(
|
|||
variant_cls_type: &syn::Type,
|
||||
num_fields: usize,
|
||||
) -> Result<(MethodAndSlotDef, syn::ImplItemFn)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let mut len_method_impl: syn::ImplItemFn = parse_quote! {
|
||||
fn __len__(slf: #pyo3_path::PyRef<Self>) -> #pyo3_path::PyResult<usize> {
|
||||
|
@ -1202,7 +1202,7 @@ fn impl_complex_enum_tuple_variant_getitem(
|
|||
variant_cls_type: &syn::Type,
|
||||
num_fields: usize,
|
||||
) -> Result<(MethodAndSlotDef, syn::ImplItemFn)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let match_arms: Vec<_> = (0..num_fields)
|
||||
.map(|i| {
|
||||
|
@ -1243,7 +1243,7 @@ fn impl_complex_enum_tuple_variant_cls(
|
|||
variant: &PyClassEnumTupleVariant<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<(TokenStream, Vec<MethodAndMethodDef>, Vec<MethodAndSlotDef>)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let variant_ident = &variant.ident;
|
||||
let variant_cls = gen_complex_enum_variant_class_ident(enum_name, variant.ident);
|
||||
let variant_cls_type = parse_quote!(#variant_cls);
|
||||
|
@ -1400,7 +1400,7 @@ pub fn gen_complex_enum_variant_attr(
|
|||
spec: &ConstSpec<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> MethodAndMethodDef {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let member = &spec.rust_ident;
|
||||
let wrapper_ident = format_ident!("__pymethod_variant_cls_{}__", member);
|
||||
let deprecations = &spec.attributes.deprecations;
|
||||
|
@ -1449,7 +1449,7 @@ fn complex_enum_struct_variant_new<'a>(
|
|||
variant: PyClassEnumStructVariant<'a>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndSlotDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let variant_cls = format_ident!("{}_{}", cls, variant.ident);
|
||||
let variant_cls_type: syn::Type = parse_quote!(#variant_cls);
|
||||
|
||||
|
@ -1506,7 +1506,7 @@ fn complex_enum_tuple_variant_new<'a>(
|
|||
variant: PyClassEnumTupleVariant<'a>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndSlotDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let variant_cls: Ident = format_ident!("{}_{}", cls, variant.ident);
|
||||
let variant_cls_type: syn::Type = parse_quote!(#variant_cls);
|
||||
|
@ -1645,7 +1645,7 @@ fn impl_pytypeinfo(
|
|||
deprecations: Option<&Deprecations<'_>>,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls_name = get_class_python_name(cls, attr).to_string();
|
||||
|
||||
let module = if let Some(ModuleAttribute { value, .. }) = &attr.options.module {
|
||||
|
@ -1689,7 +1689,7 @@ fn pyclass_richcmp_arms(
|
|||
options: &PyClassPyO3Options,
|
||||
ctx: &Ctx,
|
||||
) -> std::result::Result<TokenStream, syn::Error> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let eq_arms = options
|
||||
.eq
|
||||
|
@ -1743,7 +1743,7 @@ fn pyclass_richcmp_simple_enum(
|
|||
repr_type: &syn::Ident,
|
||||
ctx: &Ctx,
|
||||
) -> Result<(Option<syn::ImplItemFn>, Option<MethodAndSlotDef>)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
if let Some(eq_int) = options.eq_int {
|
||||
ensure_spanned!(options.eq.is_some(), eq_int.span() => "The `eq_int` option requires the `eq` option.");
|
||||
|
@ -1827,7 +1827,7 @@ fn pyclass_richcmp(
|
|||
cls: &syn::Type,
|
||||
ctx: &Ctx,
|
||||
) -> Result<(Option<syn::ImplItemFn>, Option<MethodAndSlotDef>)> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
if let Some(eq_int) = options.eq_int {
|
||||
bail_spanned!(eq_int.span() => "`eq_int` can only be used on simple enums.")
|
||||
}
|
||||
|
@ -1940,7 +1940,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
|
||||
fn impl_pyclass(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = self.cls;
|
||||
|
||||
let frozen = if self.attr.options.frozen.is_some() {
|
||||
|
@ -1956,7 +1956,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
}
|
||||
fn impl_extractext(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = self.cls;
|
||||
if self.attr.options.frozen.is_some() {
|
||||
quote! {
|
||||
|
@ -1996,7 +1996,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
|
||||
fn impl_into_py(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = self.cls;
|
||||
let attr = self.attr;
|
||||
// If #cls is not extended type, we allow Self->PyObject conversion
|
||||
|
@ -2013,7 +2013,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
}
|
||||
fn impl_pyclassimpl(&self, ctx: &Ctx) -> Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = self.cls;
|
||||
let doc = self.doc.as_ref().map_or(
|
||||
quote! {#pyo3_path::ffi::c_str!("")},
|
||||
|
@ -2184,7 +2184,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
|
||||
fn impl_add_to_module(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = self.cls;
|
||||
quote! {
|
||||
impl #cls {
|
||||
|
@ -2196,7 +2196,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
|
||||
fn impl_freelist(&self, ctx: &Ctx) -> TokenStream {
|
||||
let cls = self.cls;
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
self.attr.options.freelist.as_ref().map_or(quote!{}, |freelist| {
|
||||
let freelist = &freelist.value;
|
||||
|
@ -2219,7 +2219,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
|
||||
fn freelist_slots(&self, ctx: &Ctx) -> Vec<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls = self.cls;
|
||||
|
||||
if self.attr.options.freelist.is_some() {
|
||||
|
@ -2244,7 +2244,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
|
||||
fn define_inventory_class(inventory_class_name: &syn::Ident, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
pub struct #inventory_class_name {
|
||||
|
|
|
@ -205,8 +205,8 @@ pub fn impl_wrap_pyfunction(
|
|||
krate,
|
||||
} = options;
|
||||
|
||||
let ctx = &Ctx::new(&krate);
|
||||
let Ctx { pyo3_path } = &ctx;
|
||||
let ctx = &Ctx::new(&krate, Some(&func.sig));
|
||||
let Ctx { pyo3_path, .. } = &ctx;
|
||||
|
||||
let python_name = name
|
||||
.as_ref()
|
||||
|
|
|
@ -90,7 +90,6 @@ pub fn impl_methods(
|
|||
methods_type: PyClassMethodsType,
|
||||
options: PyImplOptions,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let ctx = &Ctx::new(&options.krate);
|
||||
let mut trait_impls = Vec::new();
|
||||
let mut proto_impls = Vec::new();
|
||||
let mut methods = Vec::new();
|
||||
|
@ -101,6 +100,7 @@ pub fn impl_methods(
|
|||
for iimpl in impls {
|
||||
match iimpl {
|
||||
syn::ImplItem::Fn(meth) => {
|
||||
let ctx = &Ctx::new(&options.krate, Some(&meth.sig));
|
||||
let mut fun_options = PyFunctionOptions::from_attrs(&mut meth.attrs)?;
|
||||
fun_options.krate = fun_options.krate.or_else(|| options.krate.clone());
|
||||
match pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs, fun_options, ctx)?
|
||||
|
@ -129,6 +129,7 @@ pub fn impl_methods(
|
|||
}
|
||||
}
|
||||
syn::ImplItem::Const(konst) => {
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let attributes = ConstAttributes::from_attrs(&mut konst.attrs, ctx)?;
|
||||
if attributes.is_class_attr {
|
||||
let spec = ConstSpec {
|
||||
|
@ -159,11 +160,10 @@ pub fn impl_methods(
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
|
||||
add_shared_proto_slots(ty, &mut proto_impls, implemented_proto_fragments, ctx);
|
||||
|
||||
let ctx = &Ctx::new(&options.krate);
|
||||
|
||||
let items = match methods_type {
|
||||
PyClassMethodsType::Specialization => impl_py_methods(ty, methods, proto_impls, ctx),
|
||||
PyClassMethodsType::Inventory => submit_methods_inventory(ty, methods, proto_impls, ctx),
|
||||
|
@ -187,7 +187,7 @@ pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec<'_>, ctx: &Ctx) -> MethodA
|
|||
let wrapper_ident = format_ident!("__pymethod_{}__", member);
|
||||
let deprecations = &spec.attributes.deprecations;
|
||||
let python_name = spec.null_terminated_python_name(ctx);
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let associated_method = quote! {
|
||||
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
|
||||
|
@ -217,7 +217,7 @@ fn impl_py_methods(
|
|||
proto_impls: Vec<TokenStream>,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
quote! {
|
||||
#[allow(unknown_lints, non_local_definitions)]
|
||||
impl #pyo3_path::impl_::pyclass::PyMethods<#ty>
|
||||
|
@ -240,7 +240,7 @@ fn add_shared_proto_slots(
|
|||
mut implemented_proto_fragments: HashSet<String>,
|
||||
ctx: &Ctx,
|
||||
) {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
macro_rules! try_add_shared_slot {
|
||||
($slot:ident, $($fragments:literal),*) => {{
|
||||
let mut implemented = false;
|
||||
|
@ -298,7 +298,7 @@ fn submit_methods_inventory(
|
|||
proto_impls: Vec<TokenStream>,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
quote! {
|
||||
#pyo3_path::inventory::submit! {
|
||||
type Inventory = <#ty as #pyo3_path::impl_::pyclass::PyClassImpl>::Inventory;
|
||||
|
|
|
@ -196,7 +196,7 @@ pub fn gen_py_method(
|
|||
ensure_function_options_valid(&options)?;
|
||||
let method = PyMethod::parse(sig, meth_attrs, options, ctx)?;
|
||||
let spec = &method.spec;
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
Ok(match (method.kind, &spec.tp) {
|
||||
// Class attributes go before protos so that class attributes can be used to set proto
|
||||
|
@ -318,7 +318,7 @@ pub fn impl_py_method_def(
|
|||
flags: Option<TokenStream>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndMethodDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let wrapper_ident = format_ident!("__pymethod_{}__", spec.python_name);
|
||||
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls), ctx)?;
|
||||
let add_flags = flags.map(|flags| quote!(.flags(#flags)));
|
||||
|
@ -343,7 +343,7 @@ pub fn impl_py_method_def_new(
|
|||
spec: &FnSpec<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndSlotDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let wrapper_ident = syn::Ident::new("__pymethod___new____", Span::call_site());
|
||||
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls), ctx)?;
|
||||
// Use just the text_signature_call_signature() because the class' Python name
|
||||
|
@ -393,7 +393,7 @@ pub fn impl_py_method_def_new(
|
|||
}
|
||||
|
||||
fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>, ctx: &Ctx) -> Result<MethodAndSlotDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
// HACK: __call__ proto slot must always use varargs calling convention, so change the spec.
|
||||
// Probably indicates there's a refactoring opportunity somewhere.
|
||||
|
@ -433,7 +433,7 @@ fn impl_traverse_slot(
|
|||
spec: &FnSpec<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> syn::Result<MethodAndSlotDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
if let (Some(py_arg), _) = split_off_python_arg(&spec.signature.arguments) {
|
||||
return Err(syn::Error::new_spanned(py_arg.ty, "__traverse__ may not take `Python`. \
|
||||
Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` \
|
||||
|
@ -484,7 +484,7 @@ fn impl_py_class_attribute(
|
|||
spec: &FnSpec<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> syn::Result<MethodAndMethodDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
||||
ensure_spanned!(
|
||||
args.is_empty(),
|
||||
|
@ -559,7 +559,7 @@ pub fn impl_py_setter_def(
|
|||
property_type: PropertyType<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndMethodDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let python_name = property_type.null_terminated_python_name(ctx)?;
|
||||
let doc = property_type.doc(ctx);
|
||||
let mut holders = Holders::new();
|
||||
|
@ -745,7 +745,7 @@ pub fn impl_py_getter_def(
|
|||
property_type: PropertyType<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndMethodDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let python_name = property_type.null_terminated_python_name(ctx)?;
|
||||
let doc = property_type.doc(ctx);
|
||||
|
||||
|
@ -871,7 +871,7 @@ pub enum PropertyType<'a> {
|
|||
|
||||
impl PropertyType<'_> {
|
||||
fn null_terminated_python_name(&self, ctx: &Ctx) -> Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
match self {
|
||||
PropertyType::Descriptor {
|
||||
field,
|
||||
|
@ -913,7 +913,7 @@ pub const __REPR__: SlotDef = SlotDef::new("Py_tp_repr", "reprfunc");
|
|||
pub const __HASH__: SlotDef = SlotDef::new("Py_tp_hash", "hashfunc")
|
||||
.ret_ty(Ty::PyHashT)
|
||||
.return_conversion(TokenGenerator(
|
||||
|Ctx { pyo3_path }: &Ctx| quote! { #pyo3_path::callback::HashCallbackOutput },
|
||||
|Ctx { pyo3_path, .. }: &Ctx| quote! { #pyo3_path::callback::HashCallbackOutput },
|
||||
));
|
||||
pub const __RICHCMP__: SlotDef = SlotDef::new("Py_tp_richcompare", "richcmpfunc")
|
||||
.extract_error_mode(ExtractErrorMode::NotImplemented)
|
||||
|
@ -1036,7 +1036,11 @@ enum Ty {
|
|||
|
||||
impl Ty {
|
||||
fn ffi_type(self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx {
|
||||
pyo3_path,
|
||||
output_span,
|
||||
} = ctx;
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(*output_span);
|
||||
match self {
|
||||
Ty::Object | Ty::MaybeNullObject => quote! { *mut #pyo3_path::ffi::PyObject },
|
||||
Ty::NonNullObject => quote! { ::std::ptr::NonNull<#pyo3_path::ffi::PyObject> },
|
||||
|
@ -1057,7 +1061,7 @@ impl Ty {
|
|||
holders: &mut Holders,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
match self {
|
||||
Ty::Object => extract_object(
|
||||
extract_error_mode,
|
||||
|
@ -1122,7 +1126,7 @@ fn extract_object(
|
|||
source_ptr: TokenStream,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let gil_refs_checker = holders.push_gil_refs_checker(arg.ty().span());
|
||||
let name = arg.name().unraw().to_string();
|
||||
|
||||
|
@ -1162,7 +1166,7 @@ enum ReturnMode {
|
|||
|
||||
impl ReturnMode {
|
||||
fn return_call_output(&self, call: TokenStream, ctx: &Ctx, holders: &Holders) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
match self {
|
||||
ReturnMode::Conversion(conversion) => {
|
||||
|
@ -1265,7 +1269,7 @@ impl SlotDef {
|
|||
method_name: &str,
|
||||
ctx: &Ctx,
|
||||
) -> Result<MethodAndSlotDef> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let SlotDef {
|
||||
slot,
|
||||
func_ty,
|
||||
|
@ -1345,7 +1349,7 @@ fn generate_method_body(
|
|||
return_mode: Option<&ReturnMode>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_arg = spec
|
||||
.tp
|
||||
.self_arg(Some(cls), extract_error_mode, holders, ctx);
|
||||
|
@ -1397,7 +1401,7 @@ impl SlotFragmentDef {
|
|||
spec: &FnSpec<'_>,
|
||||
ctx: &Ctx,
|
||||
) -> Result<TokenStream> {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let SlotFragmentDef {
|
||||
fragment,
|
||||
arguments,
|
||||
|
|
|
@ -1,23 +1,31 @@
|
|||
use crate::utils::Ctx;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use quote::{quote, quote_spanned};
|
||||
|
||||
pub(crate) fn some_wrap(obj: TokenStream, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
quote! {
|
||||
#pyo3_path::impl_::wrap::SomeWrap::wrap(#obj)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn ok_wrap(obj: TokenStream, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
quote! {
|
||||
let Ctx {
|
||||
pyo3_path,
|
||||
output_span,
|
||||
} = ctx;
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(*output_span);
|
||||
quote_spanned! {*output_span=>
|
||||
#pyo3_path::impl_::wrap::OkWrap::wrap(#obj)
|
||||
.map_err(::core::convert::Into::<#pyo3_path::PyErr>::into)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map_result_into_ptr(result: TokenStream, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
quote! { #pyo3_path::impl_::wrap::map_result_into_ptr(py, #result) }
|
||||
let Ctx {
|
||||
pyo3_path,
|
||||
output_span,
|
||||
} = ctx;
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(*output_span);
|
||||
quote_spanned! {*output_span=> #pyo3_path::impl_::wrap::map_result_into_ptr(py, #result) }
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::attributes::{CrateAttribute, RenamingRule};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{punctuated::Punctuated, Token};
|
||||
|
||||
use crate::attributes::{CrateAttribute, RenamingRule};
|
||||
|
||||
/// Macro inspired by `anyhow::anyhow!` to create a compiler error with the given span.
|
||||
macro_rules! err_spanned {
|
||||
($span:expr => $msg:expr) => {
|
||||
|
@ -86,7 +86,7 @@ pub fn get_doc(
|
|||
mut text_signature: Option<String>,
|
||||
ctx: &Ctx,
|
||||
) -> PythonDoc {
|
||||
let Ctx { pyo3_path } = ctx;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
// insert special divider between `__text_signature__` and doc
|
||||
// (assume text_signature is itself well-formed)
|
||||
if let Some(text_signature) = &mut text_signature {
|
||||
|
@ -162,17 +162,35 @@ pub fn unwrap_ty_group(mut ty: &syn::Type) -> &syn::Type {
|
|||
}
|
||||
|
||||
pub struct Ctx {
|
||||
/// Where we can find the pyo3 crate
|
||||
pub pyo3_path: PyO3CratePath,
|
||||
|
||||
/// If we are in a pymethod or pyfunction,
|
||||
/// this will be the span of the return type
|
||||
pub output_span: Span,
|
||||
}
|
||||
|
||||
impl Ctx {
|
||||
pub(crate) fn new(attr: &Option<CrateAttribute>) -> Self {
|
||||
pub(crate) fn new(attr: &Option<CrateAttribute>, signature: Option<&syn::Signature>) -> Self {
|
||||
let pyo3_path = match attr {
|
||||
Some(attr) => PyO3CratePath::Given(attr.value.0.clone()),
|
||||
None => PyO3CratePath::Default,
|
||||
};
|
||||
|
||||
Self { pyo3_path }
|
||||
let output_span = if let Some(syn::Signature {
|
||||
output: syn::ReturnType::Type(_, output_type),
|
||||
..
|
||||
}) = &signature
|
||||
{
|
||||
output_type.span()
|
||||
} else {
|
||||
Span::call_site()
|
||||
};
|
||||
|
||||
Self {
|
||||
pyo3_path,
|
||||
output_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,7 +152,15 @@ pub trait ToPyObject {
|
|||
/// # }
|
||||
/// ```
|
||||
/// Python code will see this as any of the `int`, `string` or `None` objects.
|
||||
#[doc(alias = "IntoPyCallbackOutput")]
|
||||
#[cfg_attr(
|
||||
diagnostic_namespace,
|
||||
diagnostic::on_unimplemented(
|
||||
message = "`{Self}` cannot be converted to a Python object",
|
||||
note = "`IntoPy` is automatically implemented by the `#[pyclass]` macro",
|
||||
note = "if you do not wish to have a corresponding Python type, implement it manually",
|
||||
note = "if you do not own `{Self}` you can perform a manual conversion to one of the types in `pyo3::types::*`"
|
||||
)
|
||||
)]
|
||||
pub trait IntoPy<T>: Sized {
|
||||
/// Performs the conversion.
|
||||
fn into_py(self, py: Python<'_>) -> T;
|
||||
|
|
|
@ -20,6 +20,15 @@ impl<T> SomeWrap<T> for Option<T> {
|
|||
}
|
||||
|
||||
/// Used to wrap the result of `#[pyfunction]` and `#[pymethods]`.
|
||||
#[cfg_attr(
|
||||
diagnostic_namespace,
|
||||
diagnostic::on_unimplemented(
|
||||
message = "`{Self}` cannot be converted to a Python object",
|
||||
note = "`IntoPy` is automatically implemented by the `#[pyclass]` macro",
|
||||
note = "if you do not wish to have a corresponding Python type, implement `IntoPy` manually",
|
||||
note = "if you do not own `{Self}` you can perform a manual conversion to one of the types in `pyo3::types::*`"
|
||||
)
|
||||
)]
|
||||
pub trait OkWrap<T> {
|
||||
type Error;
|
||||
fn wrap(self) -> Result<T, Self::Error>;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `PyErr: From<MyError>` is not satisfied
|
||||
--> tests/ui/invalid_result_conversion.rs:21:1
|
||||
--> tests/ui/invalid_result_conversion.rs:22:25
|
||||
|
|
||||
21 | #[pyfunction]
|
||||
| ^^^^^^^^^^^^^ the trait `From<MyError>` is not implemented for `PyErr`, which is required by `MyError: Into<PyErr>`
|
||||
22 | fn should_not_work() -> Result<(), MyError> {
|
||||
| ^^^^^^ the trait `From<MyError>` is not implemented for `PyErr`, which is required by `MyError: Into<PyErr>`
|
||||
|
|
||||
= help: the following other types implement trait `From<T>`:
|
||||
<PyErr as From<AddrParseError>>
|
||||
|
@ -15,4 +15,3 @@ error[E0277]: the trait bound `PyErr: From<MyError>` is not satisfied
|
|||
<PyErr as From<IntoInnerError<W>>>
|
||||
and $N others
|
||||
= note: required for `MyError` to implement `Into<PyErr>`
|
||||
= note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
error[E0277]: the trait bound `Blah: OkWrap<Blah>` is not satisfied
|
||||
--> tests/ui/missing_intopy.rs:3:1
|
||||
error[E0277]: `Blah` cannot be converted to a Python object
|
||||
--> tests/ui/missing_intopy.rs:4:14
|
||||
|
|
||||
3 | #[pyo3::pyfunction]
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `IntoPy<Py<PyAny>>` is not implemented for `Blah`, which is required by `Blah: OkWrap<_>`
|
||||
4 | fn blah() -> Blah{
|
||||
| ^^^^ the trait `IntoPy<Py<PyAny>>` is not implemented for `Blah`, which is required by `Blah: OkWrap<_>`
|
||||
|
|
||||
= note: `IntoPy` is automatically implemented by the `#[pyclass]` macro
|
||||
= note: if you do not wish to have a corresponding Python type, implement `IntoPy` manually
|
||||
= note: if you do not own `Blah` you can perform a manual conversion to one of the types in `pyo3::types::*`
|
||||
= help: the trait `OkWrap<T>` is implemented for `Result<T, E>`
|
||||
= note: required for `Blah` to implement `OkWrap<Blah>`
|
||||
= note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
Loading…
Reference in New Issue