deprecate gil-refs in `from_py_with` (Part 2) (#3972)
* deprecate `from_py_with` in `#[derive(FromPyObject)]` (NewType) * deprecate `from_py_with` in `#[derive(FromPyObject)]` (Enum, Struct)
This commit is contained in:
parent
caf80eca66
commit
2736cf670c
|
@ -1,7 +1,7 @@
|
||||||
use crate::attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute};
|
use crate::attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute};
|
||||||
use crate::utils::Ctx;
|
use crate::utils::Ctx;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
use syn::{
|
use syn::{
|
||||||
parenthesized,
|
parenthesized,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
|
@ -44,13 +44,16 @@ impl<'a> Enum<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build derivation body for enums.
|
/// Build derivation body for enums.
|
||||||
fn build(&self, ctx: &Ctx) -> TokenStream {
|
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 var_extracts = Vec::new();
|
||||||
let mut variant_names = Vec::new();
|
let mut variant_names = Vec::new();
|
||||||
let mut error_names = Vec::new();
|
let mut error_names = Vec::new();
|
||||||
|
|
||||||
|
let mut deprecations = TokenStream::new();
|
||||||
for var in &self.variants {
|
for var in &self.variants {
|
||||||
let struct_derive = var.build(ctx);
|
let (struct_derive, dep) = var.build(ctx);
|
||||||
|
deprecations.extend(dep);
|
||||||
let ext = quote!({
|
let ext = quote!({
|
||||||
let maybe_ret = || -> #pyo3_path::PyResult<Self> {
|
let maybe_ret = || -> #pyo3_path::PyResult<Self> {
|
||||||
#struct_derive
|
#struct_derive
|
||||||
|
@ -67,19 +70,22 @@ impl<'a> Enum<'a> {
|
||||||
error_names.push(&var.err_name);
|
error_names.push(&var.err_name);
|
||||||
}
|
}
|
||||||
let ty_name = self.enum_ident.to_string();
|
let ty_name = self.enum_ident.to_string();
|
||||||
quote!(
|
(
|
||||||
let errors = [
|
quote!(
|
||||||
#(#var_extracts),*
|
let errors = [
|
||||||
];
|
#(#var_extracts),*
|
||||||
::std::result::Result::Err(
|
];
|
||||||
#pyo3_path::impl_::frompyobject::failed_to_extract_enum(
|
::std::result::Result::Err(
|
||||||
obj.py(),
|
#pyo3_path::impl_::frompyobject::failed_to_extract_enum(
|
||||||
#ty_name,
|
obj.py(),
|
||||||
&[#(#variant_names),*],
|
#ty_name,
|
||||||
&[#(#error_names),*],
|
&[#(#variant_names),*],
|
||||||
&errors
|
&[#(#error_names),*],
|
||||||
|
&errors
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
|
deprecations,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,7 +244,7 @@ impl<'a> Container<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build derivation body for a struct.
|
/// Build derivation body for a struct.
|
||||||
fn build(&self, ctx: &Ctx) -> TokenStream {
|
fn build(&self, ctx: &Ctx) -> (TokenStream, TokenStream) {
|
||||||
match &self.ty {
|
match &self.ty {
|
||||||
ContainerType::StructNewtype(ident, from_py_with) => {
|
ContainerType::StructNewtype(ident, from_py_with) => {
|
||||||
self.build_newtype_struct(Some(ident), from_py_with, ctx)
|
self.build_newtype_struct(Some(ident), from_py_with, ctx)
|
||||||
|
@ -256,41 +262,73 @@ impl<'a> Container<'a> {
|
||||||
field_ident: Option<&Ident>,
|
field_ident: Option<&Ident>,
|
||||||
from_py_with: &Option<FromPyWithAttribute>,
|
from_py_with: &Option<FromPyWithAttribute>,
|
||||||
ctx: &Ctx,
|
ctx: &Ctx,
|
||||||
) -> TokenStream {
|
) -> (TokenStream, TokenStream) {
|
||||||
let Ctx { pyo3_path } = ctx;
|
let Ctx { pyo3_path } = ctx;
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let struct_name = self.name();
|
let struct_name = self.name();
|
||||||
if let Some(ident) = field_ident {
|
if let Some(ident) = field_ident {
|
||||||
let field_name = ident.to_string();
|
let field_name = ident.to_string();
|
||||||
match from_py_with {
|
match from_py_with {
|
||||||
None => quote! {
|
None => (
|
||||||
Ok(#self_ty {
|
quote! {
|
||||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
|
Ok(#self_ty {
|
||||||
})
|
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
|
||||||
},
|
})
|
||||||
Some(FromPyWithAttribute {
|
},
|
||||||
value: expr_path, ..
|
TokenStream::new(),
|
||||||
}) => quote! {
|
|
||||||
Ok(#self_ty {
|
|
||||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)?
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match from_py_with {
|
|
||||||
None => quote!(
|
|
||||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty)
|
|
||||||
),
|
),
|
||||||
Some(FromPyWithAttribute {
|
Some(FromPyWithAttribute {
|
||||||
value: expr_path, ..
|
value: expr_path, ..
|
||||||
}) => quote! (
|
}) => (
|
||||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty)
|
quote! {
|
||||||
|
Ok(#self_ty {
|
||||||
|
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)?
|
||||||
|
})
|
||||||
|
},
|
||||||
|
quote_spanned! { expr_path.span() =>
|
||||||
|
const _: () = {
|
||||||
|
fn check_from_py_with() {
|
||||||
|
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||||
|
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||||
|
e.from_py_with_arg();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match from_py_with {
|
||||||
|
None => (
|
||||||
|
quote!(
|
||||||
|
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty)
|
||||||
|
),
|
||||||
|
TokenStream::new(),
|
||||||
|
),
|
||||||
|
Some(FromPyWithAttribute {
|
||||||
|
value: expr_path, ..
|
||||||
|
}) => (
|
||||||
|
quote! (
|
||||||
|
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty)
|
||||||
|
),
|
||||||
|
quote_spanned! { expr_path.span() =>
|
||||||
|
const _: () = {
|
||||||
|
fn check_from_py_with() {
|
||||||
|
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||||
|
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||||
|
e.from_py_with_arg();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_tuple_struct(&self, struct_fields: &[TupleStructField], ctx: &Ctx) -> TokenStream {
|
fn build_tuple_struct(
|
||||||
|
&self,
|
||||||
|
struct_fields: &[TupleStructField],
|
||||||
|
ctx: &Ctx,
|
||||||
|
) -> (TokenStream, TokenStream) {
|
||||||
let Ctx { pyo3_path } = ctx;
|
let Ctx { pyo3_path } = ctx;
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let struct_name = &self.name();
|
let struct_name = &self.name();
|
||||||
|
@ -309,15 +347,41 @@ impl<'a> Container<'a> {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
quote!(
|
|
||||||
match #pyo3_path::types::PyAnyMethods::extract(obj) {
|
let deprecations = struct_fields
|
||||||
::std::result::Result::Ok((#(#field_idents),*)) => ::std::result::Result::Ok(#self_ty(#(#fields),*)),
|
.iter()
|
||||||
::std::result::Result::Err(err) => ::std::result::Result::Err(err),
|
.filter_map(|field| {
|
||||||
}
|
let FromPyWithAttribute {
|
||||||
|
value: expr_path, ..
|
||||||
|
} = field.from_py_with.as_ref()?;
|
||||||
|
Some(quote_spanned! { expr_path.span() =>
|
||||||
|
const _: () = {
|
||||||
|
fn check_from_py_with() {
|
||||||
|
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||||
|
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||||
|
e.from_py_with_arg();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<TokenStream>();
|
||||||
|
|
||||||
|
(
|
||||||
|
quote!(
|
||||||
|
match #pyo3_path::types::PyAnyMethods::extract(obj) {
|
||||||
|
::std::result::Result::Ok((#(#field_idents),*)) => ::std::result::Result::Ok(#self_ty(#(#fields),*)),
|
||||||
|
::std::result::Result::Err(err) => ::std::result::Result::Err(err),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
deprecations,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_struct(&self, struct_fields: &[NamedStructField<'_>], ctx: &Ctx) -> TokenStream {
|
fn build_struct(
|
||||||
|
&self,
|
||||||
|
struct_fields: &[NamedStructField<'_>],
|
||||||
|
ctx: &Ctx,
|
||||||
|
) -> (TokenStream, TokenStream) {
|
||||||
let Ctx { pyo3_path } = ctx;
|
let Ctx { pyo3_path } = ctx;
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let struct_name = &self.name();
|
let struct_name = &self.name();
|
||||||
|
@ -355,7 +419,29 @@ impl<'a> Container<'a> {
|
||||||
|
|
||||||
fields.push(quote!(#ident: #extractor));
|
fields.push(quote!(#ident: #extractor));
|
||||||
}
|
}
|
||||||
quote!(::std::result::Result::Ok(#self_ty{#fields}))
|
|
||||||
|
let deprecations = struct_fields
|
||||||
|
.iter()
|
||||||
|
.filter_map(|field| {
|
||||||
|
let FromPyWithAttribute {
|
||||||
|
value: expr_path, ..
|
||||||
|
} = field.from_py_with.as_ref()?;
|
||||||
|
Some(quote_spanned! { expr_path.span() =>
|
||||||
|
const _: () = {
|
||||||
|
fn check_from_py_with() {
|
||||||
|
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||||
|
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||||
|
e.from_py_with_arg();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<TokenStream>();
|
||||||
|
|
||||||
|
(
|
||||||
|
quote!(::std::result::Result::Ok(#self_ty{#fields})),
|
||||||
|
deprecations,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,7 +673,7 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
|
||||||
let ctx = &Ctx::new(&options.krate);
|
let ctx = &Ctx::new(&options.krate);
|
||||||
let Ctx { pyo3_path } = &ctx;
|
let Ctx { pyo3_path } = &ctx;
|
||||||
|
|
||||||
let derives = match &tokens.data {
|
let (derives, from_py_with_deprecations) = match &tokens.data {
|
||||||
syn::Data::Enum(en) => {
|
syn::Data::Enum(en) => {
|
||||||
if options.transparent || options.annotation.is_some() {
|
if options.transparent || options.annotation.is_some() {
|
||||||
bail_spanned!(tokens.span() => "`transparent` or `annotation` is not supported \
|
bail_spanned!(tokens.span() => "`transparent` or `annotation` is not supported \
|
||||||
|
@ -617,5 +703,7 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
|
||||||
#derives
|
#derives
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#from_py_with_deprecations
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,45 @@ fn pyfunction_from_py_with(
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPyObject)]
|
||||||
|
pub struct Zap {
|
||||||
|
#[pyo3(item)]
|
||||||
|
name: String,
|
||||||
|
|
||||||
|
#[pyo3(from_py_with = "PyAny::len", item("my_object"))]
|
||||||
|
some_object_length: usize,
|
||||||
|
|
||||||
|
#[pyo3(from_py_with = "extract_bound")]
|
||||||
|
some_number: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPyObject)]
|
||||||
|
pub struct ZapTuple(
|
||||||
|
String,
|
||||||
|
#[pyo3(from_py_with = "PyAny::len")] usize,
|
||||||
|
#[pyo3(from_py_with = "extract_bound")] i32,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, FromPyObject, PartialEq, Eq)]
|
||||||
|
pub enum ZapEnum {
|
||||||
|
Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32),
|
||||||
|
Zap(String, #[pyo3(from_py_with = "extract_bound")] i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPyObject, PartialEq, Eq)]
|
||||||
|
#[pyo3(transparent)]
|
||||||
|
pub struct TransparentFromPyWithGilRef {
|
||||||
|
#[pyo3(from_py_with = "extract_gil_ref")]
|
||||||
|
len: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPyObject, PartialEq, Eq)]
|
||||||
|
#[pyo3(transparent)]
|
||||||
|
pub struct TransparentFromPyWithBound {
|
||||||
|
#[pyo3(from_py_with = "extract_bound")]
|
||||||
|
len: i32,
|
||||||
|
}
|
||||||
|
|
||||||
fn test_wrap_pyfunction(py: Python<'_>, m: &Bound<'_, PyModule>) {
|
fn test_wrap_pyfunction(py: Python<'_>, m: &Bound<'_, PyModule>) {
|
||||||
// should lint
|
// should lint
|
||||||
let _ = wrap_pyfunction!(double, py);
|
let _ = wrap_pyfunction!(double, py);
|
||||||
|
|
|
@ -52,10 +52,34 @@ error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_
|
||||||
87 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32,
|
87 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32,
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||||
|
--> tests/ui/deprecations.rs:97:27
|
||||||
|
|
|
||||||
|
97 | #[pyo3(from_py_with = "PyAny::len", item("my_object"))]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||||
|
--> tests/ui/deprecations.rs:107:27
|
||||||
|
|
|
||||||
|
107 | #[pyo3(from_py_with = "PyAny::len")] usize,
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||||
|
--> tests/ui/deprecations.rs:113:31
|
||||||
|
|
|
||||||
|
113 | Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32),
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||||
|
--> tests/ui/deprecations.rs:120:27
|
||||||
|
|
|
||||||
|
120 | #[pyo3(from_py_with = "extract_gil_ref")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<pyo3::Python<'_>>::is_python`: use `wrap_pyfunction_bound!` instead
|
error: use of deprecated method `pyo3::deprecations::GilRefs::<pyo3::Python<'_>>::is_python`: use `wrap_pyfunction_bound!` instead
|
||||||
--> tests/ui/deprecations.rs:94:13
|
--> tests/ui/deprecations.rs:133:13
|
||||||
|
|
|
|
||||||
94 | let _ = wrap_pyfunction!(double, py);
|
133 | let _ = wrap_pyfunction!(double, py);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: this error originates in the macro `wrap_pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `wrap_pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
Loading…
Reference in New Issue