Thread pyo3's path through the builder functions (#3907)

* Thread pyo3's path through the builder functions

* preserve span of pyo3_path

---------

Co-authored-by: David Hewitt <mail@davidhewitt.dev>
This commit is contained in:
Bruno Kolenbrander 2024-03-04 08:54:04 +01:00 committed by GitHub
parent 70a7aa808d
commit 4114dcb1a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 708 additions and 513 deletions

View File

@ -1,3 +1,4 @@
use crate::utils::Ctx;
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{quote_spanned, ToTokens}; use quote::{quote_spanned, ToTokens};
@ -14,12 +15,11 @@ impl Deprecation {
} }
} }
#[derive(Default)] pub struct Deprecations<'ctx>(Vec<(Deprecation, Span)>, &'ctx Ctx);
pub struct Deprecations(Vec<(Deprecation, Span)>);
impl Deprecations { impl<'ctx> Deprecations<'ctx> {
pub fn new() -> Self { pub fn new(ctx: &'ctx Ctx) -> Self {
Deprecations(Vec::new()) Deprecations(Vec::new(), ctx)
} }
pub fn push(&mut self, deprecation: Deprecation, span: Span) { pub fn push(&mut self, deprecation: Deprecation, span: Span) {
@ -27,15 +27,18 @@ impl Deprecations {
} }
} }
impl ToTokens for Deprecations { impl<'ctx> ToTokens for Deprecations<'ctx> {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
for (deprecation, span) in &self.0 { let Self(deprecations, Ctx { pyo3_path }) = self;
for (deprecation, span) in deprecations {
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
let ident = deprecation.ident(*span); let ident = deprecation.ident(*span);
quote_spanned!( quote_spanned!(
*span => *span =>
#[allow(clippy::let_unit_value)] #[allow(clippy::let_unit_value)]
{ {
let _ = _pyo3::impl_::deprecations::#ident; let _ = #pyo3_path::impl_::deprecations::#ident;
} }
) )
.to_tokens(tokens) .to_tokens(tokens)

View File

@ -1,7 +1,5 @@
use crate::{ use crate::attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute};
attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute}, use crate::utils::Ctx;
utils::get_pyo3_crate,
};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use syn::{ use syn::{
@ -46,14 +44,15 @@ impl<'a> Enum<'a> {
} }
/// Build derivation body for enums. /// Build derivation body for enums.
fn build(&self) -> TokenStream { fn build(&self, ctx: &Ctx) -> TokenStream {
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();
for var in &self.variants { for var in &self.variants {
let struct_derive = var.build(); let struct_derive = var.build(ctx);
let ext = quote!({ let ext = quote!({
let maybe_ret = || -> _pyo3::PyResult<Self> { let maybe_ret = || -> #pyo3_path::PyResult<Self> {
#struct_derive #struct_derive
}(); }();
@ -73,7 +72,7 @@ impl<'a> Enum<'a> {
#(#var_extracts),* #(#var_extracts),*
]; ];
::std::result::Result::Err( ::std::result::Result::Err(
_pyo3::impl_::frompyobject::failed_to_extract_enum( #pyo3_path::impl_::frompyobject::failed_to_extract_enum(
obj.py(), obj.py(),
#ty_name, #ty_name,
&[#(#variant_names),*], &[#(#variant_names),*],
@ -239,16 +238,16 @@ impl<'a> Container<'a> {
} }
/// Build derivation body for a struct. /// Build derivation body for a struct.
fn build(&self) -> TokenStream { fn build(&self, ctx: &Ctx) -> 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) self.build_newtype_struct(Some(ident), from_py_with, ctx)
} }
ContainerType::TupleNewtype(from_py_with) => { ContainerType::TupleNewtype(from_py_with) => {
self.build_newtype_struct(None, from_py_with) self.build_newtype_struct(None, from_py_with, ctx)
} }
ContainerType::Tuple(tups) => self.build_tuple_struct(tups), ContainerType::Tuple(tups) => self.build_tuple_struct(tups, ctx),
ContainerType::Struct(tups) => self.build_struct(tups), ContainerType::Struct(tups) => self.build_struct(tups, ctx),
} }
} }
@ -256,7 +255,9 @@ impl<'a> Container<'a> {
&self, &self,
field_ident: Option<&Ident>, field_ident: Option<&Ident>,
from_py_with: &Option<FromPyWithAttribute>, from_py_with: &Option<FromPyWithAttribute>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
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 {
@ -264,32 +265,33 @@ impl<'a> Container<'a> {
match from_py_with { match from_py_with {
None => quote! { None => quote! {
Ok(#self_ty { Ok(#self_ty {
#ident: _pyo3::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)? #ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
}) })
}, },
Some(FromPyWithAttribute { Some(FromPyWithAttribute {
value: expr_path, .. value: expr_path, ..
}) => quote! { }) => quote! {
Ok(#self_ty { Ok(#self_ty {
#ident: _pyo3::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)? #ident: #pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)?
}) })
}, },
} }
} else { } else {
match from_py_with { match from_py_with {
None => quote!( None => quote!(
_pyo3::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty) #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! ( }) => quote! (
_pyo3::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty) #pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty)
), ),
} }
} }
} }
fn build_tuple_struct(&self, struct_fields: &[TupleStructField]) -> TokenStream { fn build_tuple_struct(&self, struct_fields: &[TupleStructField], ctx: &Ctx) -> TokenStream {
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();
let field_idents: Vec<_> = (0..struct_fields.len()) let field_idents: Vec<_> = (0..struct_fields.len())
@ -298,12 +300,12 @@ impl<'a> Container<'a> {
let fields = struct_fields.iter().zip(&field_idents).enumerate().map(|(index, (field, ident))| { let fields = struct_fields.iter().zip(&field_idents).enumerate().map(|(index, (field, ident))| {
match &field.from_py_with { match &field.from_py_with {
None => quote!( None => quote!(
_pyo3::impl_::frompyobject::extract_tuple_struct_field(&#ident, #struct_name, #index)? #pyo3_path::impl_::frompyobject::extract_tuple_struct_field(&#ident, #struct_name, #index)?
), ),
Some(FromPyWithAttribute { Some(FromPyWithAttribute {
value: expr_path, .. value: expr_path, ..
}) => quote! ( }) => quote! (
_pyo3::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, &#ident, #struct_name, #index)? #pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, &#ident, #struct_name, #index)?
), ),
} }
}); });
@ -315,7 +317,8 @@ impl<'a> Container<'a> {
) )
} }
fn build_struct(&self, struct_fields: &[NamedStructField<'_>]) -> TokenStream { fn build_struct(&self, struct_fields: &[NamedStructField<'_>], ctx: &Ctx) -> TokenStream {
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();
let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new(); let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new();
@ -324,27 +327,27 @@ impl<'a> Container<'a> {
let field_name = ident.to_string(); let field_name = ident.to_string();
let getter = match field.getter.as_ref().unwrap_or(&FieldGetter::GetAttr(None)) { let getter = match field.getter.as_ref().unwrap_or(&FieldGetter::GetAttr(None)) {
FieldGetter::GetAttr(Some(name)) => { FieldGetter::GetAttr(Some(name)) => {
quote!(getattr(_pyo3::intern!(obj.py(), #name))) quote!(getattr(#pyo3_path::intern!(obj.py(), #name)))
} }
FieldGetter::GetAttr(None) => { FieldGetter::GetAttr(None) => {
quote!(getattr(_pyo3::intern!(obj.py(), #field_name))) quote!(getattr(#pyo3_path::intern!(obj.py(), #field_name)))
} }
FieldGetter::GetItem(Some(syn::Lit::Str(key))) => { FieldGetter::GetItem(Some(syn::Lit::Str(key))) => {
quote!(get_item(_pyo3::intern!(obj.py(), #key))) quote!(get_item(#pyo3_path::intern!(obj.py(), #key)))
} }
FieldGetter::GetItem(Some(key)) => quote!(get_item(#key)), FieldGetter::GetItem(Some(key)) => quote!(get_item(#key)),
FieldGetter::GetItem(None) => { FieldGetter::GetItem(None) => {
quote!(get_item(_pyo3::intern!(obj.py(), #field_name))) quote!(get_item(#pyo3_path::intern!(obj.py(), #field_name)))
} }
}; };
let extractor = match &field.from_py_with { let extractor = match &field.from_py_with {
None => { None => {
quote!(_pyo3::impl_::frompyobject::extract_struct_field(&obj.#getter?, #struct_name, #field_name)?) quote!(#pyo3_path::impl_::frompyobject::extract_struct_field(&obj.#getter?, #struct_name, #field_name)?)
} }
Some(FromPyWithAttribute { Some(FromPyWithAttribute {
value: expr_path, .. value: expr_path, ..
}) => { }) => {
quote! (_pyo3::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, &obj.#getter?, #struct_name, #field_name)?) quote! (#pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, &obj.#getter?, #struct_name, #field_name)?)
} }
}; };
@ -579,7 +582,9 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
.push(parse_quote!(#gen_ident: FromPyObject<#lt_param>)) .push(parse_quote!(#gen_ident: FromPyObject<#lt_param>))
} }
let options = ContainerOptions::from_attrs(&tokens.attrs)?; let options = ContainerOptions::from_attrs(&tokens.attrs)?;
let krate = get_pyo3_crate(&options.krate); let ctx = &Ctx::new(&options.krate);
let Ctx { pyo3_path } = &ctx;
let derives = match &tokens.data { let derives = 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() {
@ -587,7 +592,7 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
at top level for enums"); at top level for enums");
} }
let en = Enum::new(en, &tokens.ident)?; let en = Enum::new(en, &tokens.ident)?;
en.build() en.build(ctx)
} }
syn::Data::Struct(st) => { syn::Data::Struct(st) => {
if let Some(lit_str) = &options.annotation { if let Some(lit_str) = &options.annotation {
@ -595,7 +600,7 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
} }
let ident = &tokens.ident; let ident = &tokens.ident;
let st = Container::new(&st.fields, parse_quote!(#ident), options)?; let st = Container::new(&st.fields, parse_quote!(#ident), options)?;
st.build() st.build(ctx)
} }
syn::Data::Union(_) => bail_spanned!( syn::Data::Union(_) => bail_spanned!(
tokens.span() => "#[derive(FromPyObject)] is not supported for unions" tokens.span() => "#[derive(FromPyObject)] is not supported for unions"
@ -607,12 +612,11 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate as _pyo3; use #pyo3_path::prelude::PyAnyMethods;
use _pyo3::prelude::PyAnyMethods;
#[automatically_derived] #[automatically_derived]
impl #trait_generics _pyo3::FromPyObject<#lt_param> for #ident #generics #where_clause { impl #trait_generics #pyo3_path::FromPyObject<#lt_param> for #ident #generics #where_clause {
fn extract_bound(obj: &_pyo3::Bound<#lt_param, _pyo3::PyAny>) -> _pyo3::PyResult<Self> { fn extract_bound(obj: &#pyo3_path::Bound<#lt_param, #pyo3_path::PyAny>) -> #pyo3_path::PyResult<Self> {
#derives #derives
} }
} }

View File

@ -1,5 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use crate::utils::Ctx;
use crate::{ use crate::{
attributes::{self, get_pyo3_options, take_attributes, NameAttribute}, attributes::{self, get_pyo3_options, take_attributes, NameAttribute},
deprecations::Deprecations, deprecations::Deprecations,
@ -13,12 +14,12 @@ use syn::{
Result, Result,
}; };
pub struct ConstSpec { pub struct ConstSpec<'ctx> {
pub rust_ident: syn::Ident, pub rust_ident: syn::Ident,
pub attributes: ConstAttributes, pub attributes: ConstAttributes<'ctx>,
} }
impl ConstSpec { impl ConstSpec<'_> {
pub fn python_name(&self) -> Cow<'_, Ident> { pub fn python_name(&self) -> Cow<'_, Ident> {
if let Some(name) = &self.attributes.name { if let Some(name) = &self.attributes.name {
Cow::Borrowed(&name.value.0) Cow::Borrowed(&name.value.0)
@ -34,10 +35,10 @@ impl ConstSpec {
} }
} }
pub struct ConstAttributes { pub struct ConstAttributes<'ctx> {
pub is_class_attr: bool, pub is_class_attr: bool,
pub name: Option<NameAttribute>, pub name: Option<NameAttribute>,
pub deprecations: Deprecations, pub deprecations: Deprecations<'ctx>,
} }
pub enum PyO3ConstAttribute { pub enum PyO3ConstAttribute {
@ -55,12 +56,12 @@ impl Parse for PyO3ConstAttribute {
} }
} }
impl ConstAttributes { impl<'ctx> ConstAttributes<'ctx> {
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Self> { pub fn from_attrs(attrs: &mut Vec<syn::Attribute>, ctx: &'ctx Ctx) -> syn::Result<Self> {
let mut attributes = ConstAttributes { let mut attributes = ConstAttributes {
is_class_attr: false, is_class_attr: false,
name: None, name: None,
deprecations: Deprecations::new(), deprecations: Deprecations::new(ctx),
}; };
take_attributes(attrs, |attr| { take_attributes(attrs, |attr| {

View File

@ -4,6 +4,7 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned, ToTokens};
use syn::{ext::IdentExt, spanned::Spanned, Ident, Result}; use syn::{ext::IdentExt, spanned::Spanned, Ident, Result};
use crate::utils::Ctx;
use crate::{ use crate::{
attributes::{TextSignatureAttribute, TextSignatureAttributeValue}, attributes::{TextSignatureAttribute, TextSignatureAttributeValue},
deprecations::{Deprecation, Deprecations}, deprecations::{Deprecation, Deprecations},
@ -108,13 +109,16 @@ impl FnType {
cls: Option<&syn::Type>, cls: Option<&syn::Type>,
error_mode: ExtractErrorMode, error_mode: ExtractErrorMode,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
let Ctx { pyo3_path } = ctx;
match self { match self {
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) => { FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) => {
let mut receiver = st.receiver( let mut receiver = st.receiver(
cls.expect("no class given for Fn with a \"self\" receiver"), cls.expect("no class given for Fn with a \"self\" receiver"),
error_mode, error_mode,
holders, holders,
ctx,
); );
syn::Token![,](Span::call_site()).to_tokens(&mut receiver); syn::Token![,](Span::call_site()).to_tokens(&mut receiver);
receiver receiver
@ -125,22 +129,24 @@ impl FnType {
FnType::FnClass(span) | FnType::FnNewClass(span) => { FnType::FnClass(span) | FnType::FnNewClass(span) => {
let py = syn::Ident::new("py", Span::call_site()); let py = syn::Ident::new("py", Span::call_site());
let slf: Ident = syn::Ident::new("_slf", Span::call_site()); let slf: Ident = syn::Ident::new("_slf", Span::call_site());
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
quote_spanned! { *span => quote_spanned! { *span =>
#[allow(clippy::useless_conversion)] #[allow(clippy::useless_conversion)]
::std::convert::Into::into( ::std::convert::Into::into(
_pyo3::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf.cast()) #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf.cast())
.downcast_unchecked::<_pyo3::types::PyType>() .downcast_unchecked::<#pyo3_path::types::PyType>()
), ),
} }
} }
FnType::FnModule(span) => { FnType::FnModule(span) => {
let py = syn::Ident::new("py", Span::call_site()); let py = syn::Ident::new("py", Span::call_site());
let slf: Ident = syn::Ident::new("_slf", Span::call_site()); let slf: Ident = syn::Ident::new("_slf", Span::call_site());
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
quote_spanned! { *span => quote_spanned! { *span =>
#[allow(clippy::useless_conversion)] #[allow(clippy::useless_conversion)]
::std::convert::Into::into( ::std::convert::Into::into(
_pyo3::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf.cast()) #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf.cast())
.downcast_unchecked::<_pyo3::types::PyModule>() .downcast_unchecked::<#pyo3_path::types::PyModule>()
), ),
} }
} }
@ -161,13 +167,14 @@ pub enum ExtractErrorMode {
} }
impl ExtractErrorMode { impl ExtractErrorMode {
pub fn handle_error(self, extract: TokenStream) -> TokenStream { pub fn handle_error(self, extract: TokenStream, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
match self { match self {
ExtractErrorMode::Raise => quote! { #extract? }, ExtractErrorMode::Raise => quote! { #extract? },
ExtractErrorMode::NotImplemented => quote! { ExtractErrorMode::NotImplemented => quote! {
match #extract { match #extract {
::std::result::Result::Ok(value) => value, ::std::result::Result::Ok(value) => value,
::std::result::Result::Err(_) => { return _pyo3::callback::convert(py, py.NotImplemented()); }, ::std::result::Result::Err(_) => { return #pyo3_path::callback::convert(py, py.NotImplemented()); },
} }
}, },
} }
@ -180,11 +187,13 @@ impl SelfType {
cls: &syn::Type, cls: &syn::Type,
error_mode: ExtractErrorMode, error_mode: ExtractErrorMode,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
// Due to use of quote_spanned in this function, need to bind these idents to the // Due to use of quote_spanned in this function, need to bind these idents to the
// main macro callsite. // main macro callsite.
let py = syn::Ident::new("py", Span::call_site()); let py = syn::Ident::new("py", Span::call_site());
let slf = syn::Ident::new("_slf", Span::call_site()); let slf = syn::Ident::new("_slf", Span::call_site());
let Ctx { pyo3_path } = ctx;
match self { match self {
SelfType::Receiver { span, mutable } => { SelfType::Receiver { span, mutable } => {
let method = if *mutable { let method = if *mutable {
@ -193,29 +202,35 @@ impl SelfType {
syn::Ident::new("extract_pyclass_ref", *span) syn::Ident::new("extract_pyclass_ref", *span)
}; };
let holder = syn::Ident::new(&format!("holder_{}", holders.len()), *span); let holder = syn::Ident::new(&format!("holder_{}", holders.len()), *span);
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
holders.push(quote_spanned! { *span => holders.push(quote_spanned! { *span =>
#[allow(clippy::let_unit_value)] #[allow(clippy::let_unit_value)]
let mut #holder = _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT; let mut #holder = #pyo3_path::impl_::extract_argument::FunctionArgumentHolder::INIT;
let mut #slf = _pyo3::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf); let mut #slf = #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf);
}); });
error_mode.handle_error(quote_spanned! { *span =>
_pyo3::impl_::extract_argument::#method::<#cls>(
&#slf,
&mut #holder,
)
})
}
SelfType::TryFromBoundRef(span) => {
error_mode.handle_error( error_mode.handle_error(
quote_spanned! { *span => quote_spanned! { *span =>
_pyo3::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).downcast::<#cls>() #pyo3_path::impl_::extract_argument::#method::<#cls>(
.map_err(::std::convert::Into::<_pyo3::PyErr>::into) &#slf,
&mut #holder,
)
},
ctx,
)
}
SelfType::TryFromBoundRef(span) => {
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
error_mode.handle_error(
quote_spanned! { *span =>
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).downcast::<#cls>()
.map_err(::std::convert::Into::<#pyo3_path::PyErr>::into)
.and_then( .and_then(
#[allow(unknown_lints, clippy::unnecessary_fallible_conversions)] // In case slf is Py<Self> (unknown_lints can be removed when MSRV is 1.75+) #[allow(unknown_lints, clippy::unnecessary_fallible_conversions)] // In case slf is Py<Self> (unknown_lints can be removed when MSRV is 1.75+)
|bound| ::std::convert::TryFrom::try_from(bound).map_err(::std::convert::Into::into) |bound| ::std::convert::TryFrom::try_from(bound).map_err(::std::convert::Into::into)
) )
} },
ctx
) )
} }
} }
@ -264,7 +279,7 @@ pub struct FnSpec<'a> {
pub text_signature: Option<TextSignatureAttribute>, pub text_signature: Option<TextSignatureAttribute>,
pub asyncness: Option<syn::Token![async]>, pub asyncness: Option<syn::Token![async]>,
pub unsafety: Option<syn::Token![unsafe]>, pub unsafety: Option<syn::Token![unsafe]>,
pub deprecations: Deprecations, pub deprecations: Deprecations<'a>,
} }
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type { pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
@ -303,6 +318,7 @@ impl<'a> FnSpec<'a> {
sig: &'a mut syn::Signature, sig: &'a mut syn::Signature,
meth_attrs: &mut Vec<syn::Attribute>, meth_attrs: &mut Vec<syn::Attribute>,
options: PyFunctionOptions, options: PyFunctionOptions,
ctx: &'a Ctx,
) -> Result<FnSpec<'a>> { ) -> Result<FnSpec<'a>> {
let PyFunctionOptions { let PyFunctionOptions {
text_signature, text_signature,
@ -312,7 +328,7 @@ impl<'a> FnSpec<'a> {
} = options; } = options;
let mut python_name = name.map(|name| name.value.0); let mut python_name = name.map(|name| name.value.0);
let mut deprecations = Deprecations::new(); let mut deprecations = Deprecations::new(ctx);
let fn_type = Self::parse_fn_type(sig, meth_attrs, &mut python_name, &mut deprecations)?; let fn_type = Self::parse_fn_type(sig, meth_attrs, &mut python_name, &mut deprecations)?;
ensure_signatures_on_valid_method(&fn_type, signature.as_ref(), text_signature.as_ref())?; ensure_signatures_on_valid_method(&fn_type, signature.as_ref(), text_signature.as_ref())?;
@ -366,7 +382,7 @@ impl<'a> FnSpec<'a> {
sig: &syn::Signature, sig: &syn::Signature,
meth_attrs: &mut Vec<syn::Attribute>, meth_attrs: &mut Vec<syn::Attribute>,
python_name: &mut Option<syn::Ident>, python_name: &mut Option<syn::Ident>,
deprecations: &mut Deprecations, deprecations: &mut Deprecations<'_>,
) -> Result<FnType> { ) -> Result<FnType> {
let mut method_attributes = parse_method_attributes(meth_attrs, deprecations)?; let mut method_attributes = parse_method_attributes(meth_attrs, deprecations)?;
@ -480,7 +496,9 @@ impl<'a> FnSpec<'a> {
&self, &self,
ident: &proc_macro2::Ident, ident: &proc_macro2::Ident,
cls: Option<&syn::Type>, cls: Option<&syn::Type>,
ctx: &Ctx,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let Ctx { pyo3_path } = ctx;
let mut cancel_handle_iter = self let mut cancel_handle_iter = self
.signature .signature
.arguments .arguments
@ -495,7 +513,7 @@ impl<'a> FnSpec<'a> {
} }
let rust_call = |args: Vec<TokenStream>, holders: &mut Vec<TokenStream>| { let rust_call = |args: Vec<TokenStream>, holders: &mut Vec<TokenStream>| {
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise, holders); let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise, holders, ctx);
let call = if self.asyncness.is_some() { let call = if self.asyncness.is_some() {
let throw_callback = if cancel_handle.is_some() { let throw_callback = if cancel_handle.is_some() {
@ -505,7 +523,7 @@ impl<'a> FnSpec<'a> {
}; };
let python_name = &self.python_name; let python_name = &self.python_name;
let qualname_prefix = match cls { let qualname_prefix = match cls {
Some(cls) => quote!(Some(<#cls as _pyo3::PyTypeInfo>::NAME)), Some(cls) => quote!(Some(<#cls as #pyo3_path::PyTypeInfo>::NAME)),
None => quote!(None), None => quote!(None),
}; };
let future = match self.tp { let future = match self.tp {
@ -513,7 +531,7 @@ impl<'a> FnSpec<'a> {
holders.pop().unwrap(); // does not actually use holder created by `self_arg` holders.pop().unwrap(); // does not actually use holder created by `self_arg`
quote! {{ quote! {{
let __guard = _pyo3::impl_::coroutine::RefGuard::<#cls>::new(&_pyo3::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?; let __guard = #pyo3_path::impl_::coroutine::RefGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
async move { function(&__guard, #(#args),*).await } async move { function(&__guard, #(#args),*).await }
}} }}
} }
@ -521,7 +539,7 @@ impl<'a> FnSpec<'a> {
holders.pop().unwrap(); // does not actually use holder created by `self_arg` holders.pop().unwrap(); // does not actually use holder created by `self_arg`
quote! {{ quote! {{
let mut __guard = _pyo3::impl_::coroutine::RefMutGuard::<#cls>::new(&_pyo3::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?; let mut __guard = #pyo3_path::impl_::coroutine::RefMutGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
async move { function(&mut __guard, #(#args),*).await } async move { function(&mut __guard, #(#args),*).await }
}} }}
} }
@ -529,16 +547,16 @@ impl<'a> FnSpec<'a> {
}; };
let mut call = quote! {{ let mut call = quote! {{
let future = #future; let future = #future;
_pyo3::impl_::coroutine::new_coroutine( #pyo3_path::impl_::coroutine::new_coroutine(
_pyo3::intern!(py, stringify!(#python_name)), #pyo3_path::intern!(py, stringify!(#python_name)),
#qualname_prefix, #qualname_prefix,
#throw_callback, #throw_callback,
async move { _pyo3::impl_::wrap::OkWrap::wrap(future.await) }, async move { #pyo3_path::impl_::wrap::OkWrap::wrap(future.await) },
) )
}}; }};
if cancel_handle.is_some() { if cancel_handle.is_some() {
call = quote! {{ call = quote! {{
let __cancel_handle = _pyo3::coroutine::CancelHandle::new(); let __cancel_handle = #pyo3_path::coroutine::CancelHandle::new();
let __throw_callback = __cancel_handle.throw_callback(); let __throw_callback = __cancel_handle.throw_callback();
#call #call
}}; }};
@ -547,7 +565,7 @@ impl<'a> FnSpec<'a> {
} else { } else {
quote! { function(#self_arg #(#args),*) } quote! { function(#self_arg #(#args),*) }
}; };
quotes::map_result_into_ptr(quotes::ok_wrap(call)) quotes::map_result_into_ptr(quotes::ok_wrap(call, ctx), ctx)
}; };
let func_name = &self.name; let func_name = &self.name;
@ -578,9 +596,9 @@ impl<'a> FnSpec<'a> {
quote! { quote! {
unsafe fn #ident<'py>( unsafe fn #ident<'py>(
py: _pyo3::Python<'py>, py: #pyo3_path::Python<'py>,
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> { ) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
let function = #rust_name; // Shadow the function name to avoid #3017 let function = #rust_name; // Shadow the function name to avoid #3017
#( #holders )* #( #holders )*
let result = #call; let result = #call;
@ -590,16 +608,16 @@ impl<'a> FnSpec<'a> {
} }
CallingConvention::Fastcall => { CallingConvention::Fastcall => {
let mut holders = Vec::new(); let mut holders = Vec::new();
let (arg_convert, args) = impl_arg_params(self, cls, true, &mut holders)?; let (arg_convert, args) = impl_arg_params(self, cls, true, &mut holders, ctx)?;
let call = rust_call(args, &mut holders); let call = rust_call(args, &mut holders);
quote! { quote! {
unsafe fn #ident<'py>( unsafe fn #ident<'py>(
py: _pyo3::Python<'py>, py: #pyo3_path::Python<'py>,
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
_args: *const *mut _pyo3::ffi::PyObject, _args: *const *mut #pyo3_path::ffi::PyObject,
_nargs: _pyo3::ffi::Py_ssize_t, _nargs: #pyo3_path::ffi::Py_ssize_t,
_kwnames: *mut _pyo3::ffi::PyObject _kwnames: *mut #pyo3_path::ffi::PyObject
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> { ) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
let function = #rust_name; // Shadow the function name to avoid #3017 let function = #rust_name; // Shadow the function name to avoid #3017
#arg_convert #arg_convert
#( #holders )* #( #holders )*
@ -610,15 +628,15 @@ impl<'a> FnSpec<'a> {
} }
CallingConvention::Varargs => { CallingConvention::Varargs => {
let mut holders = Vec::new(); let mut holders = Vec::new();
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders)?; let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders, ctx)?;
let call = rust_call(args, &mut holders); let call = rust_call(args, &mut holders);
quote! { quote! {
unsafe fn #ident<'py>( unsafe fn #ident<'py>(
py: _pyo3::Python<'py>, py: #pyo3_path::Python<'py>,
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
_args: *mut _pyo3::ffi::PyObject, _args: *mut #pyo3_path::ffi::PyObject,
_kwargs: *mut _pyo3::ffi::PyObject _kwargs: *mut #pyo3_path::ffi::PyObject
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> { ) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
let function = #rust_name; // Shadow the function name to avoid #3017 let function = #rust_name; // Shadow the function name to avoid #3017
#arg_convert #arg_convert
#( #holders )* #( #holders )*
@ -629,23 +647,25 @@ impl<'a> FnSpec<'a> {
} }
CallingConvention::TpNew => { CallingConvention::TpNew => {
let mut holders = Vec::new(); let mut holders = Vec::new();
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders)?; let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders, ctx)?;
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise, &mut holders); let self_arg = self
.tp
.self_arg(cls, ExtractErrorMode::Raise, &mut holders, ctx);
let call = quote! { #rust_name(#self_arg #(#args),*) }; let call = quote! { #rust_name(#self_arg #(#args),*) };
quote! { quote! {
unsafe fn #ident( unsafe fn #ident(
py: _pyo3::Python<'_>, py: #pyo3_path::Python<'_>,
_slf: *mut _pyo3::ffi::PyTypeObject, _slf: *mut #pyo3_path::ffi::PyTypeObject,
_args: *mut _pyo3::ffi::PyObject, _args: *mut #pyo3_path::ffi::PyObject,
_kwargs: *mut _pyo3::ffi::PyObject _kwargs: *mut #pyo3_path::ffi::PyObject
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> { ) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
use _pyo3::callback::IntoPyCallbackOutput; use #pyo3_path::callback::IntoPyCallbackOutput;
let function = #rust_name; // Shadow the function name to avoid #3017 let function = #rust_name; // Shadow the function name to avoid #3017
#arg_convert #arg_convert
#( #holders )* #( #holders )*
let result = #call; let result = #call;
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(py)?; let initializer: #pyo3_path::PyClassInitializer::<#cls> = result.convert(py)?;
_pyo3::impl_::pymethods::tp_new_impl(py, initializer, _slf) #pyo3_path::impl_::pymethods::tp_new_impl(py, initializer, _slf)
} }
} }
} }
@ -654,19 +674,20 @@ impl<'a> FnSpec<'a> {
/// Return a `PyMethodDef` constructor for this function, matching the selected /// Return a `PyMethodDef` constructor for this function, matching the selected
/// calling convention. /// calling convention.
pub fn get_methoddef(&self, wrapper: impl ToTokens, doc: &PythonDoc) -> TokenStream { pub fn get_methoddef(&self, wrapper: impl ToTokens, doc: &PythonDoc, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let python_name = self.null_terminated_python_name(); let python_name = self.null_terminated_python_name();
match self.convention { match self.convention {
CallingConvention::Noargs => quote! { CallingConvention::Noargs => quote! {
_pyo3::impl_::pymethods::PyMethodDef::noargs( #pyo3_path::impl_::pymethods::PyMethodDef::noargs(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyCFunction({ #pyo3_path::impl_::pymethods::PyCFunction({
unsafe extern "C" fn trampoline( unsafe extern "C" fn trampoline(
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
_args: *mut _pyo3::ffi::PyObject, _args: *mut #pyo3_path::ffi::PyObject,
) -> *mut _pyo3::ffi::PyObject ) -> *mut #pyo3_path::ffi::PyObject
{ {
_pyo3::impl_::trampoline::noargs( #pyo3_path::impl_::trampoline::noargs(
_slf, _slf,
_args, _args,
#wrapper #wrapper
@ -678,17 +699,17 @@ impl<'a> FnSpec<'a> {
) )
}, },
CallingConvention::Fastcall => quote! { CallingConvention::Fastcall => quote! {
_pyo3::impl_::pymethods::PyMethodDef::fastcall_cfunction_with_keywords( #pyo3_path::impl_::pymethods::PyMethodDef::fastcall_cfunction_with_keywords(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyCFunctionFastWithKeywords({ #pyo3_path::impl_::pymethods::PyCFunctionFastWithKeywords({
unsafe extern "C" fn trampoline( unsafe extern "C" fn trampoline(
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
_args: *const *mut _pyo3::ffi::PyObject, _args: *const *mut #pyo3_path::ffi::PyObject,
_nargs: _pyo3::ffi::Py_ssize_t, _nargs: #pyo3_path::ffi::Py_ssize_t,
_kwnames: *mut _pyo3::ffi::PyObject _kwnames: *mut #pyo3_path::ffi::PyObject
) -> *mut _pyo3::ffi::PyObject ) -> *mut #pyo3_path::ffi::PyObject
{ {
_pyo3::impl_::trampoline::fastcall_with_keywords( #pyo3_path::impl_::trampoline::fastcall_with_keywords(
_slf, _slf,
_args, _args,
_nargs, _nargs,
@ -702,16 +723,16 @@ impl<'a> FnSpec<'a> {
) )
}, },
CallingConvention::Varargs => quote! { CallingConvention::Varargs => quote! {
_pyo3::impl_::pymethods::PyMethodDef::cfunction_with_keywords( #pyo3_path::impl_::pymethods::PyMethodDef::cfunction_with_keywords(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyCFunctionWithKeywords({ #pyo3_path::impl_::pymethods::PyCFunctionWithKeywords({
unsafe extern "C" fn trampoline( unsafe extern "C" fn trampoline(
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
_args: *mut _pyo3::ffi::PyObject, _args: *mut #pyo3_path::ffi::PyObject,
_kwargs: *mut _pyo3::ffi::PyObject, _kwargs: *mut #pyo3_path::ffi::PyObject,
) -> *mut _pyo3::ffi::PyObject ) -> *mut #pyo3_path::ffi::PyObject
{ {
_pyo3::impl_::trampoline::cfunction_with_keywords( #pyo3_path::impl_::trampoline::cfunction_with_keywords(
_slf, _slf,
_args, _args,
_kwargs, _kwargs,
@ -783,7 +804,7 @@ impl MethodTypeAttribute {
/// Otherwise will either return a parse error or the attribute. /// Otherwise will either return a parse error or the attribute.
fn parse_if_matching_attribute( fn parse_if_matching_attribute(
attr: &syn::Attribute, attr: &syn::Attribute,
deprecations: &mut Deprecations, deprecations: &mut Deprecations<'_>,
) -> Result<Option<Self>> { ) -> Result<Option<Self>> {
fn ensure_no_arguments(meta: &syn::Meta, ident: &str) -> syn::Result<()> { fn ensure_no_arguments(meta: &syn::Meta, ident: &str) -> syn::Result<()> {
match meta { match meta {
@ -869,7 +890,7 @@ impl Display for MethodTypeAttribute {
fn parse_method_attributes( fn parse_method_attributes(
attrs: &mut Vec<syn::Attribute>, attrs: &mut Vec<syn::Attribute>,
deprecations: &mut Deprecations, deprecations: &mut Deprecations<'_>,
) -> Result<Vec<MethodTypeAttribute>> { ) -> Result<Vec<MethodTypeAttribute>> {
let mut new_attrs = Vec::new(); let mut new_attrs = Vec::new();
let mut found_attrs = Vec::new(); let mut found_attrs = Vec::new();

View File

@ -1,10 +1,10 @@
//! Code generation for the function that initializes a python module and adds classes and function. //! Code generation for the function that initializes a python module and adds classes and function.
use crate::utils::Ctx;
use crate::{ use crate::{
attributes::{self, take_attributes, take_pyo3_options, CrateAttribute, NameAttribute}, attributes::{self, take_attributes, take_pyo3_options, CrateAttribute, NameAttribute},
get_doc, get_doc,
pyfunction::{impl_wrap_pyfunction, PyFunctionOptions}, pyfunction::{impl_wrap_pyfunction, PyFunctionOptions},
utils::get_pyo3_crate,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
@ -73,7 +73,8 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
bail_spanned!(module.span() => "`#[pymodule]` can only be used on inline modules") bail_spanned!(module.span() => "`#[pymodule]` can only be used on inline modules")
}; };
let options = PyModuleOptions::from_attrs(attrs)?; let options = PyModuleOptions::from_attrs(attrs)?;
let krate = get_pyo3_crate(&options.krate); let ctx = &Ctx::new(&options.krate);
let Ctx { pyo3_path } = ctx;
let doc = get_doc(attrs, None); let doc = get_doc(attrs, None);
let mut module_items = Vec::new(); let mut module_items = Vec::new();
@ -164,8 +165,8 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
#initialization #initialization
impl MakeDef { impl MakeDef {
const fn make_def() -> #krate::impl_::pymodule::ModuleDef { const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef {
use #krate::impl_::pymodule as impl_; use #pyo3_path::impl_::pymodule as impl_;
const INITIALIZER: impl_::ModuleInitializer = impl_::ModuleInitializer(__pyo3_pymodule); const INITIALIZER: impl_::ModuleInitializer = impl_::ModuleInitializer(__pyo3_pymodule);
unsafe { unsafe {
impl_::ModuleDef::new( impl_::ModuleDef::new(
@ -177,8 +178,8 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
} }
} }
fn __pyo3_pymodule(module: &#krate::Bound<'_, #krate::types::PyModule>) -> #krate::PyResult<()> { fn __pyo3_pymodule(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> {
use #krate::impl_::pymodule::PyAddToModule; use #pyo3_path::impl_::pymodule::PyAddToModule;
#( #(
#(#module_items_cfg_attrs)* #(#module_items_cfg_attrs)*
#module_items::add_to_module(module)?; #module_items::add_to_module(module)?;
@ -195,7 +196,8 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream> { pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream> {
let options = PyModuleOptions::from_attrs(&mut function.attrs)?; let options = PyModuleOptions::from_attrs(&mut function.attrs)?;
process_functions_in_module(&options, &mut function)?; process_functions_in_module(&options, &mut function)?;
let krate = get_pyo3_crate(&options.krate); let ctx = &Ctx::new(&options.krate);
let Ctx { pyo3_path } = ctx;
let ident = &function.sig.ident; let ident = &function.sig.ident;
let vis = &function.vis; let vis = &function.vis;
let doc = get_doc(&function.attrs, None); let doc = get_doc(&function.attrs, None);
@ -222,10 +224,10 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate::impl_::pymodule as impl_; use #pyo3_path::impl_::pymodule as impl_;
use #krate::impl_::pymethods::BoundRef; use #pyo3_path::impl_::pymethods::BoundRef;
fn __pyo3_pymodule(module: &#krate::Bound<'_, #krate::types::PyModule>) -> #krate::PyResult<()> { fn __pyo3_pymodule(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> {
#ident(#(#module_args),*) #ident(#(#module_args),*)
} }
@ -247,36 +249,37 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
fn module_initialization(options: PyModuleOptions, ident: &syn::Ident) -> TokenStream { fn module_initialization(options: PyModuleOptions, ident: &syn::Ident) -> TokenStream {
let name = options.name.unwrap_or_else(|| ident.unraw()); let name = options.name.unwrap_or_else(|| ident.unraw());
let krate = get_pyo3_crate(&options.krate); let ctx = &Ctx::new(&options.krate);
let Ctx { pyo3_path } = ctx;
let pyinit_symbol = format!("PyInit_{}", name); let pyinit_symbol = format!("PyInit_{}", name);
quote! { quote! {
pub const __PYO3_NAME: &'static str = concat!(stringify!(#name), "\0"); pub const __PYO3_NAME: &'static str = concat!(stringify!(#name), "\0");
pub(super) struct MakeDef; pub(super) struct MakeDef;
pub static DEF: #krate::impl_::pymodule::ModuleDef = MakeDef::make_def(); pub static DEF: #pyo3_path::impl_::pymodule::ModuleDef = MakeDef::make_def();
pub fn add_to_module(module: &#krate::Bound<'_, #krate::types::PyModule>) -> #krate::PyResult<()> { pub fn add_to_module(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> {
use #krate::prelude::PyModuleMethods; use #pyo3_path::prelude::PyModuleMethods;
module.add_submodule(DEF.make_module(module.py())?.bind(module.py())) module.add_submodule(DEF.make_module(module.py())?.bind(module.py()))
} }
/// This autogenerated function is called by the python interpreter when importing /// This autogenerated function is called by the python interpreter when importing
/// the module. /// the module.
#[export_name = #pyinit_symbol] #[export_name = #pyinit_symbol]
pub unsafe extern "C" fn __pyo3_init() -> *mut #krate::ffi::PyObject { pub unsafe extern "C" fn __pyo3_init() -> *mut #pyo3_path::ffi::PyObject {
#krate::impl_::trampoline::module_init(|py| DEF.make_module(py)) #pyo3_path::impl_::trampoline::module_init(|py| DEF.make_module(py))
} }
} }
} }
/// Finds and takes care of the #[pyfn(...)] in `#[pymodule]` /// Finds and takes care of the #[pyfn(...)] in `#[pymodule]`
fn process_functions_in_module(options: &PyModuleOptions, func: &mut syn::ItemFn) -> Result<()> { fn process_functions_in_module(options: &PyModuleOptions, func: &mut syn::ItemFn) -> Result<()> {
let krate = get_pyo3_crate(&options.krate); let ctx = &Ctx::new(&options.krate);
let Ctx { pyo3_path } = ctx;
let mut stmts: Vec<syn::Stmt> = vec![syn::parse_quote!( let mut stmts: Vec<syn::Stmt> = vec![syn::parse_quote!(
#[allow(unknown_lints, unused_imports, redundant_imports)] #[allow(unknown_lints, unused_imports, redundant_imports)]
use #krate::{PyNativeType, types::PyModuleMethods}; use #pyo3_path::{PyNativeType, types::PyModuleMethods};
)]; )];
for mut stmt in func.block.stmts.drain(..) { for mut stmt in func.block.stmts.drain(..) {
@ -287,7 +290,7 @@ fn process_functions_in_module(options: &PyModuleOptions, func: &mut syn::ItemFn
let name = &func.sig.ident; let name = &func.sig.ident;
let statements: Vec<syn::Stmt> = syn::parse_quote! { let statements: Vec<syn::Stmt> = syn::parse_quote! {
#wrapped_function #wrapped_function
#module_name.as_borrowed().add_function(#krate::wrap_pyfunction!(#name, #module_name.as_borrowed())?)?; #module_name.as_borrowed().add_function(#pyo3_path::wrap_pyfunction!(#name, #module_name.as_borrowed())?)?;
}; };
stmts.extend(statements); stmts.extend(statements);
} }

View File

@ -1,3 +1,4 @@
use crate::utils::Ctx;
use crate::{ use crate::{
method::{FnArg, FnSpec}, method::{FnArg, FnSpec},
pyfunction::FunctionSignature, pyfunction::FunctionSignature,
@ -30,8 +31,10 @@ pub fn impl_arg_params(
self_: Option<&syn::Type>, self_: Option<&syn::Type>,
fastcall: bool, fastcall: bool,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> Result<(TokenStream, Vec<TokenStream>)> { ) -> Result<(TokenStream, Vec<TokenStream>)> {
let args_array = syn::Ident::new("output", Span::call_site()); let args_array = syn::Ident::new("output", Span::call_site());
let Ctx { pyo3_path } = ctx;
if !fastcall && is_forwarded_args(&spec.signature) { if !fastcall && is_forwarded_args(&spec.signature) {
// In the varargs convention, we can just pass though if the signature // In the varargs convention, we can just pass though if the signature
@ -40,12 +43,12 @@ pub fn impl_arg_params(
.signature .signature
.arguments .arguments
.iter() .iter()
.map(|arg| impl_arg_param(arg, &mut 0, &args_array, holders)) .map(|arg| impl_arg_param(arg, &mut 0, &args_array, holders, ctx))
.collect::<Result<_>>()?; .collect::<Result<_>>()?;
return Ok(( return Ok((
quote! { quote! {
let _args = _pyo3::impl_::pymethods::BoundRef::ref_from_ptr(py, &_args); let _args = #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_args);
let _kwargs = _pyo3::impl_::pymethods::BoundRef::ref_from_ptr_or_opt(py, &_kwargs); let _kwargs = #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr_or_opt(py, &_kwargs);
}, },
arg_convert, arg_convert,
)); ));
@ -64,7 +67,7 @@ pub fn impl_arg_params(
.iter() .iter()
.map(|(name, required)| { .map(|(name, required)| {
quote! { quote! {
_pyo3::impl_::extract_argument::KeywordOnlyParameterDescription { #pyo3_path::impl_::extract_argument::KeywordOnlyParameterDescription {
name: #name, name: #name,
required: #required, required: #required,
} }
@ -78,22 +81,22 @@ pub fn impl_arg_params(
.signature .signature
.arguments .arguments
.iter() .iter()
.map(|arg| impl_arg_param(arg, &mut option_pos, &args_array, holders)) .map(|arg| impl_arg_param(arg, &mut option_pos, &args_array, holders, ctx))
.collect::<Result<_>>()?; .collect::<Result<_>>()?;
let args_handler = if spec.signature.python_signature.varargs.is_some() { let args_handler = if spec.signature.python_signature.varargs.is_some() {
quote! { _pyo3::impl_::extract_argument::TupleVarargs } quote! { #pyo3_path::impl_::extract_argument::TupleVarargs }
} else { } else {
quote! { _pyo3::impl_::extract_argument::NoVarargs } quote! { #pyo3_path::impl_::extract_argument::NoVarargs }
}; };
let kwargs_handler = if spec.signature.python_signature.kwargs.is_some() { let kwargs_handler = if spec.signature.python_signature.kwargs.is_some() {
quote! { _pyo3::impl_::extract_argument::DictVarkeywords } quote! { #pyo3_path::impl_::extract_argument::DictVarkeywords }
} else { } else {
quote! { _pyo3::impl_::extract_argument::NoVarkeywords } quote! { #pyo3_path::impl_::extract_argument::NoVarkeywords }
}; };
let cls_name = if let Some(cls) = self_ { let cls_name = if let Some(cls) = self_ {
quote! { ::std::option::Option::Some(<#cls as _pyo3::type_object::PyTypeInfo>::NAME) } quote! { ::std::option::Option::Some(<#cls as #pyo3_path::type_object::PyTypeInfo>::NAME) }
} else { } else {
quote! { ::std::option::Option::None } quote! { ::std::option::Option::None }
}; };
@ -123,7 +126,7 @@ pub fn impl_arg_params(
// create array of arguments, and then parse // create array of arguments, and then parse
Ok(( Ok((
quote! { quote! {
const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription = _pyo3::impl_::extract_argument::FunctionDescription { const DESCRIPTION: #pyo3_path::impl_::extract_argument::FunctionDescription = #pyo3_path::impl_::extract_argument::FunctionDescription {
cls_name: #cls_name, cls_name: #cls_name,
func_name: stringify!(#python_name), func_name: stringify!(#python_name),
positional_parameter_names: &[#(#positional_parameter_names),*], positional_parameter_names: &[#(#positional_parameter_names),*],
@ -145,7 +148,11 @@ fn impl_arg_param(
option_pos: &mut usize, option_pos: &mut usize,
args_array: &syn::Ident, args_array: &syn::Ident,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
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 // Use this macro inside this function, to ensure that all code generated here is associated
// with the function argument // with the function argument
macro_rules! quote_arg_span { macro_rules! quote_arg_span {
@ -167,7 +174,7 @@ fn impl_arg_param(
let holder = syn::Ident::new(&format!("holder_{}", holders.len()), arg.ty.span()); let holder = syn::Ident::new(&format!("holder_{}", holders.len()), arg.ty.span());
holders.push(quote_arg_span! { holders.push(quote_arg_span! {
#[allow(clippy::let_unit_value)] #[allow(clippy::let_unit_value)]
let mut #holder = _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT; let mut #holder = #pyo3_path::impl_::extract_argument::FunctionArgumentHolder::INIT;
}); });
holder holder
}; };
@ -179,7 +186,7 @@ fn impl_arg_param(
); );
let holder = push_holder(); let holder = push_holder();
return Ok(quote_arg_span! { return Ok(quote_arg_span! {
_pyo3::impl_::extract_argument::extract_argument( #pyo3_path::impl_::extract_argument::extract_argument(
&_args, &_args,
&mut #holder, &mut #holder,
#name_str #name_str
@ -192,7 +199,7 @@ fn impl_arg_param(
); );
let holder = push_holder(); let holder = push_holder();
return Ok(quote_arg_span! { return Ok(quote_arg_span! {
_pyo3::impl_::extract_argument::extract_optional_argument( #pyo3_path::impl_::extract_argument::extract_optional_argument(
_kwargs.as_deref(), _kwargs.as_deref(),
&mut #holder, &mut #holder,
#name_str, #name_str,
@ -209,14 +216,17 @@ fn impl_arg_param(
// Option<T> arguments have special treatment: the default should be specified _without_ the // Option<T> arguments have special treatment: the default should be specified _without_ the
// Some() wrapper. Maybe this should be changed in future?! // Some() wrapper. Maybe this should be changed in future?!
if arg.optional.is_some() { if arg.optional.is_some() {
default = Some(default.map_or_else(|| quote!(::std::option::Option::None), some_wrap)); default = Some(default.map_or_else(
|| quote!(::std::option::Option::None),
|tokens| some_wrap(tokens, ctx),
));
} }
let tokens = if let Some(expr_path) = arg.attrs.from_py_with.as_ref().map(|attr| &attr.value) { let tokens = if let Some(expr_path) = arg.attrs.from_py_with.as_ref().map(|attr| &attr.value) {
if let Some(default) = default { if let Some(default) = default {
quote_arg_span! { quote_arg_span! {
#[allow(clippy::redundant_closure)] #[allow(clippy::redundant_closure)]
_pyo3::impl_::extract_argument::from_py_with_with_default( #pyo3_path::impl_::extract_argument::from_py_with_with_default(
#arg_value.as_deref(), #arg_value.as_deref(),
#name_str, #name_str,
#expr_path as fn(_) -> _, #expr_path as fn(_) -> _,
@ -225,8 +235,8 @@ fn impl_arg_param(
} }
} else { } else {
quote_arg_span! { quote_arg_span! {
_pyo3::impl_::extract_argument::from_py_with( #pyo3_path::impl_::extract_argument::from_py_with(
&_pyo3::impl_::extract_argument::unwrap_required_argument(#arg_value), &#pyo3_path::impl_::extract_argument::unwrap_required_argument(#arg_value),
#name_str, #name_str,
#expr_path as fn(_) -> _, #expr_path as fn(_) -> _,
)? )?
@ -236,7 +246,7 @@ fn impl_arg_param(
let holder = push_holder(); let holder = push_holder();
quote_arg_span! { quote_arg_span! {
#[allow(clippy::redundant_closure)] #[allow(clippy::redundant_closure)]
_pyo3::impl_::extract_argument::extract_optional_argument( #pyo3_path::impl_::extract_argument::extract_optional_argument(
#arg_value.as_deref(), #arg_value.as_deref(),
&mut #holder, &mut #holder,
#name_str, #name_str,
@ -247,7 +257,7 @@ fn impl_arg_param(
let holder = push_holder(); let holder = push_holder();
quote_arg_span! { quote_arg_span! {
#[allow(clippy::redundant_closure)] #[allow(clippy::redundant_closure)]
_pyo3::impl_::extract_argument::extract_argument_with_default( #pyo3_path::impl_::extract_argument::extract_argument_with_default(
#arg_value.as_deref(), #arg_value.as_deref(),
&mut #holder, &mut #holder,
#name_str, #name_str,
@ -257,8 +267,8 @@ fn impl_arg_param(
} else { } else {
let holder = push_holder(); let holder = push_holder();
quote_arg_span! { quote_arg_span! {
_pyo3::impl_::extract_argument::extract_argument( #pyo3_path::impl_::extract_argument::extract_argument(
&_pyo3::impl_::extract_argument::unwrap_required_argument(#arg_value), &#pyo3_path::impl_::extract_argument::unwrap_required_argument(#arg_value),
&mut #holder, &mut #holder,
#name_str #name_str
)? )?

View File

@ -13,7 +13,8 @@ use crate::pymethod::{
impl_py_getter_def, impl_py_setter_def, MethodAndMethodDef, MethodAndSlotDef, PropertyType, impl_py_getter_def, impl_py_setter_def, MethodAndMethodDef, MethodAndSlotDef, PropertyType,
SlotDef, __INT__, __REPR__, __RICHCMP__, SlotDef, __INT__, __REPR__, __RICHCMP__,
}; };
use crate::utils::{self, apply_renaming_rule, get_pyo3_crate, PythonDoc}; use crate::utils::Ctx;
use crate::utils::{self, apply_renaming_rule, PythonDoc};
use crate::PyFunctionOptions; use crate::PyFunctionOptions;
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -189,7 +190,8 @@ pub fn build_py_class(
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
args.options.take_pyo3_options(&mut class.attrs)?; args.options.take_pyo3_options(&mut class.attrs)?;
let doc = utils::get_doc(&class.attrs, None); let doc = utils::get_doc(&class.attrs, None);
let krate = get_pyo3_crate(&args.options.krate);
let ctx = &Ctx::new(&args.options.krate);
if let Some(lt) = class.generics.lifetimes().next() { if let Some(lt) = class.generics.lifetimes().next() {
bail_spanned!( bail_spanned!(
@ -251,7 +253,7 @@ pub fn build_py_class(
} }
} }
impl_class(&class.ident, &args, doc, field_options, methods_type, krate) impl_class(&class.ident, &args, doc, field_options, methods_type, ctx)
} }
enum Annotated<X, Y> { enum Annotated<X, Y> {
@ -342,9 +344,10 @@ fn impl_class(
doc: PythonDoc, doc: PythonDoc,
field_options: Vec<(&syn::Field, FieldPyO3Options)>, field_options: Vec<(&syn::Field, FieldPyO3Options)>,
methods_type: PyClassMethodsType, methods_type: PyClassMethodsType,
krate: syn::Path, ctx: &Ctx,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let pytypeinfo_impl = impl_pytypeinfo(cls, args, None); let Ctx { pyo3_path } = ctx;
let pytypeinfo_impl = impl_pytypeinfo(cls, args, None, ctx);
let py_class_impl = PyClassImplsBuilder::new( let py_class_impl = PyClassImplsBuilder::new(
cls, cls,
@ -355,19 +358,18 @@ fn impl_class(
args.options.rename_all.as_ref(), args.options.rename_all.as_ref(),
args.options.frozen, args.options.frozen,
field_options, field_options,
ctx,
)?, )?,
vec![], vec![],
) )
.doc(doc) .doc(doc)
.impl_all()?; .impl_all(ctx)?;
Ok(quote! { Ok(quote! {
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate as _pyo3; impl #pyo3_path::types::DerefToPyAny for #cls {}
impl _pyo3::types::DerefToPyAny for #cls {}
#pytypeinfo_impl #pytypeinfo_impl
@ -405,6 +407,7 @@ pub fn build_py_enum(
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
args.options.take_pyo3_options(&mut enum_.attrs)?; args.options.take_pyo3_options(&mut enum_.attrs)?;
let ctx = &Ctx::new(&args.options.krate);
if let Some(extends) = &args.options.extends { if let Some(extends) = &args.options.extends {
bail_spanned!(extends.span() => "enums can't extend from other classes"); bail_spanned!(extends.span() => "enums can't extend from other classes");
} else if let Some(subclass) = &args.options.subclass { } else if let Some(subclass) = &args.options.subclass {
@ -415,7 +418,7 @@ pub fn build_py_enum(
let doc = utils::get_doc(&enum_.attrs, None); let doc = utils::get_doc(&enum_.attrs, None);
let enum_ = PyClassEnum::new(enum_)?; let enum_ = PyClassEnum::new(enum_)?;
impl_enum(enum_, &args, doc, method_type) impl_enum(enum_, &args, doc, method_type, ctx)
} }
struct PyClassSimpleEnum<'a> { struct PyClassSimpleEnum<'a> {
@ -665,11 +668,14 @@ fn impl_enum(
args: &PyClassArgs, args: &PyClassArgs,
doc: PythonDoc, doc: PythonDoc,
methods_type: PyClassMethodsType, methods_type: PyClassMethodsType,
ctx: &Ctx,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
match enum_ { match enum_ {
PyClassEnum::Simple(simple_enum) => impl_simple_enum(simple_enum, args, doc, methods_type), PyClassEnum::Simple(simple_enum) => {
impl_simple_enum(simple_enum, args, doc, methods_type, ctx)
}
PyClassEnum::Complex(complex_enum) => { PyClassEnum::Complex(complex_enum) => {
impl_complex_enum(complex_enum, args, doc, methods_type) impl_complex_enum(complex_enum, args, doc, methods_type, ctx)
} }
} }
} }
@ -679,12 +685,13 @@ fn impl_simple_enum(
args: &PyClassArgs, args: &PyClassArgs,
doc: PythonDoc, doc: PythonDoc,
methods_type: PyClassMethodsType, methods_type: PyClassMethodsType,
ctx: &Ctx,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let krate = get_pyo3_crate(&args.options.krate); let Ctx { pyo3_path } = ctx;
let cls = simple_enum.ident; let cls = simple_enum.ident;
let ty: syn::Type = syn::parse_quote!(#cls); let ty: syn::Type = syn::parse_quote!(#cls);
let variants = simple_enum.variants; let variants = simple_enum.variants;
let pytypeinfo = impl_pytypeinfo(cls, args, None); let pytypeinfo = impl_pytypeinfo(cls, args, None, ctx);
let (default_repr, default_repr_slot) = { let (default_repr, default_repr_slot) = {
let variants_repr = variants.iter().map(|variant| { let variants_repr = variants.iter().map(|variant| {
@ -704,7 +711,8 @@ fn impl_simple_enum(
} }
} }
}; };
let repr_slot = generate_default_protocol_slot(&ty, &mut repr_impl, &__REPR__).unwrap(); let repr_slot =
generate_default_protocol_slot(&ty, &mut repr_impl, &__REPR__, ctx).unwrap();
(repr_impl, repr_slot) (repr_impl, repr_slot)
}; };
@ -723,7 +731,7 @@ fn impl_simple_enum(
} }
} }
}; };
let int_slot = generate_default_protocol_slot(&ty, &mut int_impl, &__INT__).unwrap(); let int_slot = generate_default_protocol_slot(&ty, &mut int_impl, &__INT__, ctx).unwrap();
(int_impl, int_slot) (int_impl, int_slot)
}; };
@ -731,30 +739,30 @@ fn impl_simple_enum(
let mut richcmp_impl: syn::ImplItemFn = syn::parse_quote! { let mut richcmp_impl: syn::ImplItemFn = syn::parse_quote! {
fn __pyo3__richcmp__( fn __pyo3__richcmp__(
&self, &self,
py: _pyo3::Python, py: #pyo3_path::Python,
other: &_pyo3::PyAny, other: &#pyo3_path::PyAny,
op: _pyo3::basic::CompareOp op: #pyo3_path::basic::CompareOp
) -> _pyo3::PyResult<_pyo3::PyObject> { ) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
use _pyo3::conversion::ToPyObject; use #pyo3_path::conversion::ToPyObject;
use ::core::result::Result::*; use ::core::result::Result::*;
match op { match op {
_pyo3::basic::CompareOp::Eq => { #pyo3_path::basic::CompareOp::Eq => {
let self_val = self.__pyo3__int__(); let self_val = self.__pyo3__int__();
if let Ok(i) = other.extract::<#repr_type>() { if let Ok(i) = other.extract::<#repr_type>() {
return Ok((self_val == i).to_object(py)); return Ok((self_val == i).to_object(py));
} }
if let Ok(other) = other.extract::<_pyo3::PyRef<Self>>() { if let Ok(other) = other.extract::<#pyo3_path::PyRef<Self>>() {
return Ok((self_val == other.__pyo3__int__()).to_object(py)); return Ok((self_val == other.__pyo3__int__()).to_object(py));
} }
return Ok(py.NotImplemented()); return Ok(py.NotImplemented());
} }
_pyo3::basic::CompareOp::Ne => { #pyo3_path::basic::CompareOp::Ne => {
let self_val = self.__pyo3__int__(); let self_val = self.__pyo3__int__();
if let Ok(i) = other.extract::<#repr_type>() { if let Ok(i) = other.extract::<#repr_type>() {
return Ok((self_val != i).to_object(py)); return Ok((self_val != i).to_object(py));
} }
if let Ok(other) = other.extract::<_pyo3::PyRef<Self>>() { if let Ok(other) = other.extract::<#pyo3_path::PyRef<Self>>() {
return Ok((self_val != other.__pyo3__int__()).to_object(py)); return Ok((self_val != other.__pyo3__int__()).to_object(py));
} }
@ -765,7 +773,7 @@ fn impl_simple_enum(
} }
}; };
let richcmp_slot = let richcmp_slot =
generate_default_protocol_slot(&ty, &mut richcmp_impl, &__RICHCMP__).unwrap(); generate_default_protocol_slot(&ty, &mut richcmp_impl, &__RICHCMP__, ctx).unwrap();
(richcmp_impl, richcmp_slot) (richcmp_impl, richcmp_slot)
}; };
@ -778,18 +786,17 @@ fn impl_simple_enum(
simple_enum_default_methods( simple_enum_default_methods(
cls, cls,
variants.iter().map(|v| (v.ident, v.get_python_name(args))), variants.iter().map(|v| (v.ident, v.get_python_name(args))),
ctx,
), ),
default_slots, default_slots,
) )
.doc(doc) .doc(doc)
.impl_all()?; .impl_all(ctx)?;
Ok(quote! { Ok(quote! {
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate as _pyo3;
#pytypeinfo #pytypeinfo
#pyclass_impls #pyclass_impls
@ -810,7 +817,10 @@ fn impl_complex_enum(
args: &PyClassArgs, args: &PyClassArgs,
doc: PythonDoc, doc: PythonDoc,
methods_type: PyClassMethodsType, methods_type: PyClassMethodsType,
ctx: &Ctx,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let Ctx { pyo3_path } = ctx;
// Need to rig the enum PyClass options // Need to rig the enum PyClass options
let args = { let args = {
let mut rigged_args = args.clone(); let mut rigged_args = args.clone();
@ -821,10 +831,10 @@ fn impl_complex_enum(
rigged_args rigged_args
}; };
let krate = get_pyo3_crate(&args.options.krate); let ctx = &Ctx::new(&args.options.krate);
let cls = complex_enum.ident; let cls = complex_enum.ident;
let variants = complex_enum.variants; let variants = complex_enum.variants;
let pytypeinfo = impl_pytypeinfo(cls, &args, None); let pytypeinfo = impl_pytypeinfo(cls, &args, None, ctx);
let default_slots = vec![]; let default_slots = vec![];
@ -837,6 +847,7 @@ fn impl_complex_enum(
variants variants
.iter() .iter()
.map(|v| (v.get_ident(), v.get_python_name(&args))), .map(|v| (v.get_ident(), v.get_python_name(&args))),
ctx,
), ),
default_slots, default_slots,
) )
@ -851,17 +862,17 @@ fn impl_complex_enum(
let variant_cls = gen_complex_enum_variant_class_ident(cls, variant.get_ident()); let variant_cls = gen_complex_enum_variant_class_ident(cls, variant.get_ident());
quote! { quote! {
#cls::#variant_ident { .. } => { #cls::#variant_ident { .. } => {
let pyclass_init = _pyo3::PyClassInitializer::from(self).add_subclass(#variant_cls); let pyclass_init = #pyo3_path::PyClassInitializer::from(self).add_subclass(#variant_cls);
let variant_value = _pyo3::Py::new(py, pyclass_init).unwrap(); let variant_value = #pyo3_path::Py::new(py, pyclass_init).unwrap();
_pyo3::IntoPy::into_py(variant_value, py) #pyo3_path::IntoPy::into_py(variant_value, py)
} }
} }
}) })
.collect(); .collect();
quote! { quote! {
impl _pyo3::IntoPy<_pyo3::PyObject> for #cls { impl #pyo3_path::IntoPy<#pyo3_path::PyObject> for #cls {
fn into_py(self, py: _pyo3::Python) -> _pyo3::PyObject { fn into_py(self, py: #pyo3_path::Python) -> #pyo3_path::PyObject {
match self { match self {
#(#match_arms)* #(#match_arms)*
} }
@ -871,11 +882,11 @@ fn impl_complex_enum(
}; };
let pyclass_impls: TokenStream = vec![ let pyclass_impls: TokenStream = vec![
impl_builder.impl_pyclass(), impl_builder.impl_pyclass(ctx),
impl_builder.impl_extractext(), impl_builder.impl_extractext(ctx),
enum_into_py_impl, enum_into_py_impl,
impl_builder.impl_pyclassimpl()?, impl_builder.impl_pyclassimpl(ctx)?,
impl_builder.impl_freelist(), impl_builder.impl_freelist(ctx),
] ]
.into_iter() .into_iter()
.collect(); .collect();
@ -900,12 +911,12 @@ fn impl_complex_enum(
options: parse_quote!(extends = #cls, frozen), options: parse_quote!(extends = #cls, frozen),
}; };
let variant_cls_pytypeinfo = impl_pytypeinfo(&variant_cls, &variant_args, None); let variant_cls_pytypeinfo = impl_pytypeinfo(&variant_cls, &variant_args, None, ctx);
variant_cls_pytypeinfos.push(variant_cls_pytypeinfo); variant_cls_pytypeinfos.push(variant_cls_pytypeinfo);
let variant_new = complex_enum_variant_new(cls, variant)?; let variant_new = complex_enum_variant_new(cls, variant, ctx)?;
let (variant_cls_impl, field_getters) = impl_complex_enum_variant_cls(cls, variant)?; let (variant_cls_impl, field_getters) = impl_complex_enum_variant_cls(cls, variant, ctx)?;
variant_cls_impls.push(variant_cls_impl); variant_cls_impls.push(variant_cls_impl);
let pyclass_impl = PyClassImplsBuilder::new( let pyclass_impl = PyClassImplsBuilder::new(
@ -915,7 +926,7 @@ fn impl_complex_enum(
field_getters, field_getters,
vec![variant_new], vec![variant_new],
) )
.impl_all()?; .impl_all(ctx)?;
variant_cls_pyclass_impls.push(pyclass_impl); variant_cls_pyclass_impls.push(pyclass_impl);
} }
@ -924,8 +935,6 @@ fn impl_complex_enum(
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate as _pyo3;
#pytypeinfo #pytypeinfo
#pyclass_impls #pyclass_impls
@ -948,10 +957,11 @@ fn impl_complex_enum(
fn impl_complex_enum_variant_cls( fn impl_complex_enum_variant_cls(
enum_name: &syn::Ident, enum_name: &syn::Ident,
variant: &PyClassEnumVariant<'_>, variant: &PyClassEnumVariant<'_>,
ctx: &Ctx,
) -> Result<(TokenStream, Vec<MethodAndMethodDef>)> { ) -> Result<(TokenStream, Vec<MethodAndMethodDef>)> {
match variant { match variant {
PyClassEnumVariant::Struct(struct_variant) => { PyClassEnumVariant::Struct(struct_variant) => {
impl_complex_enum_struct_variant_cls(enum_name, struct_variant) impl_complex_enum_struct_variant_cls(enum_name, struct_variant, ctx)
} }
} }
} }
@ -959,7 +969,9 @@ fn impl_complex_enum_variant_cls(
fn impl_complex_enum_struct_variant_cls( fn impl_complex_enum_struct_variant_cls(
enum_name: &syn::Ident, enum_name: &syn::Ident,
variant: &PyClassEnumStructVariant<'_>, variant: &PyClassEnumStructVariant<'_>,
ctx: &Ctx,
) -> Result<(TokenStream, Vec<MethodAndMethodDef>)> { ) -> Result<(TokenStream, Vec<MethodAndMethodDef>)> {
let Ctx { pyo3_path } = ctx;
let variant_ident = &variant.ident; let variant_ident = &variant.ident;
let variant_cls = gen_complex_enum_variant_class_ident(enum_name, variant.ident); let variant_cls = gen_complex_enum_variant_class_ident(enum_name, variant.ident);
let variant_cls_type = parse_quote!(#variant_cls); let variant_cls_type = parse_quote!(#variant_cls);
@ -978,10 +990,11 @@ fn impl_complex_enum_struct_variant_cls(
field_name, field_name,
field_type, field_type,
field.span, field.span,
ctx,
)?; )?;
let field_getter_impl = quote! { let field_getter_impl = quote! {
fn #field_name(slf: _pyo3::PyRef<Self>) -> _pyo3::PyResult<#field_type> { fn #field_name(slf: #pyo3_path::PyRef<Self>) -> #pyo3_path::PyResult<#field_type> {
match &*slf.into_super() { match &*slf.into_super() {
#enum_name::#variant_ident { #field_name, .. } => Ok(#field_name.clone()), #enum_name::#variant_ident { #field_name, .. } => Ok(#field_name.clone()),
_ => unreachable!("Wrong complex enum variant found in variant wrapper PyClass"), _ => unreachable!("Wrong complex enum variant found in variant wrapper PyClass"),
@ -999,9 +1012,9 @@ fn impl_complex_enum_struct_variant_cls(
#[doc(hidden)] #[doc(hidden)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
impl #variant_cls { impl #variant_cls {
fn __pymethod_constructor__(py: _pyo3::Python<'_>, #(#fields_with_types,)*) -> _pyo3::PyClassInitializer<#variant_cls> { fn __pymethod_constructor__(py: #pyo3_path::Python<'_>, #(#fields_with_types,)*) -> #pyo3_path::PyClassInitializer<#variant_cls> {
let base_value = #enum_name::#variant_ident { #(#field_names,)* }; let base_value = #enum_name::#variant_ident { #(#field_names,)* };
_pyo3::PyClassInitializer::from(base_value).add_subclass(#variant_cls) #pyo3_path::PyClassInitializer::from(base_value).add_subclass(#variant_cls)
} }
#(#field_getter_impls)* #(#field_getter_impls)*
@ -1019,11 +1032,13 @@ fn generate_default_protocol_slot(
cls: &syn::Type, cls: &syn::Type,
method: &mut syn::ImplItemFn, method: &mut syn::ImplItemFn,
slot: &SlotDef, slot: &SlotDef,
ctx: &Ctx,
) -> syn::Result<MethodAndSlotDef> { ) -> syn::Result<MethodAndSlotDef> {
let spec = FnSpec::parse( let spec = FnSpec::parse(
&mut method.sig, &mut method.sig,
&mut Vec::new(), &mut Vec::new(),
PyFunctionOptions::default(), PyFunctionOptions::default(),
ctx,
) )
.unwrap(); .unwrap();
let name = spec.name.to_string(); let name = spec.name.to_string();
@ -1031,12 +1046,14 @@ fn generate_default_protocol_slot(
&syn::parse_quote!(#cls), &syn::parse_quote!(#cls),
&spec, &spec,
&format!("__default_{}__", name), &format!("__default_{}__", name),
ctx,
) )
} }
fn simple_enum_default_methods<'a>( fn simple_enum_default_methods<'a>(
cls: &'a syn::Ident, cls: &'a syn::Ident,
unit_variant_names: impl IntoIterator<Item = (&'a syn::Ident, Cow<'a, syn::Ident>)>, unit_variant_names: impl IntoIterator<Item = (&'a syn::Ident, Cow<'a, syn::Ident>)>,
ctx: &Ctx,
) -> Vec<MethodAndMethodDef> { ) -> Vec<MethodAndMethodDef> {
let cls_type = syn::parse_quote!(#cls); let cls_type = syn::parse_quote!(#cls);
let variant_to_attribute = |var_ident: &syn::Ident, py_ident: &syn::Ident| ConstSpec { let variant_to_attribute = |var_ident: &syn::Ident, py_ident: &syn::Ident| ConstSpec {
@ -1047,18 +1064,19 @@ fn simple_enum_default_methods<'a>(
kw: syn::parse_quote! { name }, kw: syn::parse_quote! { name },
value: NameLitStr(py_ident.clone()), value: NameLitStr(py_ident.clone()),
}), }),
deprecations: Default::default(), deprecations: Deprecations::new(ctx),
}, },
}; };
unit_variant_names unit_variant_names
.into_iter() .into_iter()
.map(|(var, py_name)| gen_py_const(&cls_type, &variant_to_attribute(var, &py_name))) .map(|(var, py_name)| gen_py_const(&cls_type, &variant_to_attribute(var, &py_name), ctx))
.collect() .collect()
} }
fn complex_enum_default_methods<'a>( fn complex_enum_default_methods<'a>(
cls: &'a syn::Ident, cls: &'a syn::Ident,
variant_names: impl IntoIterator<Item = (&'a syn::Ident, Cow<'a, syn::Ident>)>, variant_names: impl IntoIterator<Item = (&'a syn::Ident, Cow<'a, syn::Ident>)>,
ctx: &Ctx,
) -> Vec<MethodAndMethodDef> { ) -> Vec<MethodAndMethodDef> {
let cls_type = syn::parse_quote!(#cls); let cls_type = syn::parse_quote!(#cls);
let variant_to_attribute = |var_ident: &syn::Ident, py_ident: &syn::Ident| ConstSpec { let variant_to_attribute = |var_ident: &syn::Ident, py_ident: &syn::Ident| ConstSpec {
@ -1069,13 +1087,13 @@ fn complex_enum_default_methods<'a>(
kw: syn::parse_quote! { name }, kw: syn::parse_quote! { name },
value: NameLitStr(py_ident.clone()), value: NameLitStr(py_ident.clone()),
}), }),
deprecations: Default::default(), deprecations: Deprecations::new(ctx),
}, },
}; };
variant_names variant_names
.into_iter() .into_iter()
.map(|(var, py_name)| { .map(|(var, py_name)| {
gen_complex_enum_variant_attr(cls, &cls_type, &variant_to_attribute(var, &py_name)) gen_complex_enum_variant_attr(cls, &cls_type, &variant_to_attribute(var, &py_name), ctx)
}) })
.collect() .collect()
} }
@ -1083,8 +1101,10 @@ fn complex_enum_default_methods<'a>(
pub fn gen_complex_enum_variant_attr( pub fn gen_complex_enum_variant_attr(
cls: &syn::Ident, cls: &syn::Ident,
cls_type: &syn::Type, cls_type: &syn::Type,
spec: &ConstSpec, spec: &ConstSpec<'_>,
ctx: &Ctx,
) -> MethodAndMethodDef { ) -> MethodAndMethodDef {
let Ctx { pyo3_path } = ctx;
let member = &spec.rust_ident; let member = &spec.rust_ident;
let wrapper_ident = format_ident!("__pymethod_variant_cls_{}__", member); let wrapper_ident = format_ident!("__pymethod_variant_cls_{}__", member);
let deprecations = &spec.attributes.deprecations; let deprecations = &spec.attributes.deprecations;
@ -1092,17 +1112,17 @@ pub fn gen_complex_enum_variant_attr(
let variant_cls = format_ident!("{}_{}", cls, member); let variant_cls = format_ident!("{}_{}", cls, member);
let associated_method = quote! { let associated_method = quote! {
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> { fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
#deprecations #deprecations
::std::result::Result::Ok(py.get_type_bound::<#variant_cls>().into_any().unbind()) ::std::result::Result::Ok(py.get_type_bound::<#variant_cls>().into_any().unbind())
} }
}; };
let method_def = quote! { let method_def = quote! {
_pyo3::class::PyMethodDefType::ClassAttribute({ #pyo3_path::class::PyMethodDefType::ClassAttribute({
_pyo3::class::PyClassAttributeDef::new( #pyo3_path::class::PyClassAttributeDef::new(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyClassAttributeFactory(#cls_type::#wrapper_ident) #pyo3_path::impl_::pymethods::PyClassAttributeFactory(#cls_type::#wrapper_ident)
) )
}) })
}; };
@ -1116,10 +1136,11 @@ pub fn gen_complex_enum_variant_attr(
fn complex_enum_variant_new<'a>( fn complex_enum_variant_new<'a>(
cls: &'a syn::Ident, cls: &'a syn::Ident,
variant: &'a PyClassEnumVariant<'a>, variant: &'a PyClassEnumVariant<'a>,
ctx: &Ctx,
) -> Result<MethodAndSlotDef> { ) -> Result<MethodAndSlotDef> {
match variant { match variant {
PyClassEnumVariant::Struct(struct_variant) => { PyClassEnumVariant::Struct(struct_variant) => {
complex_enum_struct_variant_new(cls, struct_variant) complex_enum_struct_variant_new(cls, struct_variant, ctx)
} }
} }
} }
@ -1127,12 +1148,14 @@ fn complex_enum_variant_new<'a>(
fn complex_enum_struct_variant_new<'a>( fn complex_enum_struct_variant_new<'a>(
cls: &'a syn::Ident, cls: &'a syn::Ident,
variant: &'a PyClassEnumStructVariant<'a>, variant: &'a PyClassEnumStructVariant<'a>,
ctx: &Ctx,
) -> Result<MethodAndSlotDef> { ) -> Result<MethodAndSlotDef> {
let Ctx { pyo3_path } = ctx;
let variant_cls = format_ident!("{}_{}", cls, variant.ident); let variant_cls = format_ident!("{}_{}", cls, variant.ident);
let variant_cls_type: syn::Type = parse_quote!(#variant_cls); let variant_cls_type: syn::Type = parse_quote!(#variant_cls);
let arg_py_ident: syn::Ident = parse_quote!(py); let arg_py_ident: syn::Ident = parse_quote!(py);
let arg_py_type: syn::Type = parse_quote!(_pyo3::Python<'_>); let arg_py_type: syn::Type = parse_quote!(#pyo3_path::Python<'_>);
let args = { let args = {
let mut no_pyo3_attrs = vec![]; let mut no_pyo3_attrs = vec![];
@ -1180,10 +1203,10 @@ fn complex_enum_struct_variant_new<'a>(
text_signature: None, text_signature: None,
asyncness: None, asyncness: None,
unsafety: None, unsafety: None,
deprecations: Deprecations::default(), deprecations: Deprecations::new(ctx),
}; };
crate::pymethod::impl_py_method_def_new(&variant_cls_type, &spec) crate::pymethod::impl_py_method_def_new(&variant_cls_type, &spec, ctx)
} }
fn complex_enum_variant_field_getter<'a>( fn complex_enum_variant_field_getter<'a>(
@ -1191,6 +1214,7 @@ fn complex_enum_variant_field_getter<'a>(
field_name: &'a syn::Ident, field_name: &'a syn::Ident,
field_type: &'a syn::Type, field_type: &'a syn::Type,
field_span: Span, field_span: Span,
ctx: &Ctx,
) -> Result<MethodAndMethodDef> { ) -> Result<MethodAndMethodDef> {
let signature = crate::pyfunction::FunctionSignature::from_arguments(vec![])?; let signature = crate::pyfunction::FunctionSignature::from_arguments(vec![])?;
@ -1206,7 +1230,7 @@ fn complex_enum_variant_field_getter<'a>(
text_signature: None, text_signature: None,
asyncness: None, asyncness: None,
unsafety: None, unsafety: None,
deprecations: Deprecations::default(), deprecations: Deprecations::new(ctx),
}; };
let property_type = crate::pymethod::PropertyType::Function { let property_type = crate::pymethod::PropertyType::Function {
@ -1215,7 +1239,7 @@ fn complex_enum_variant_field_getter<'a>(
doc: crate::get_doc(&[], None), doc: crate::get_doc(&[], None),
}; };
let getter = crate::pymethod::impl_py_getter_def(variant_cls_type, property_type)?; let getter = crate::pymethod::impl_py_getter_def(variant_cls_type, property_type, ctx)?;
Ok(getter) Ok(getter)
} }
@ -1224,6 +1248,7 @@ fn descriptors_to_items(
rename_all: Option<&RenameAllAttribute>, rename_all: Option<&RenameAllAttribute>,
frozen: Option<frozen>, frozen: Option<frozen>,
field_options: Vec<(&syn::Field, FieldPyO3Options)>, field_options: Vec<(&syn::Field, FieldPyO3Options)>,
ctx: &Ctx,
) -> syn::Result<Vec<MethodAndMethodDef>> { ) -> syn::Result<Vec<MethodAndMethodDef>> {
let ty = syn::parse_quote!(#cls); let ty = syn::parse_quote!(#cls);
let mut items = Vec::new(); let mut items = Vec::new();
@ -1246,6 +1271,7 @@ fn descriptors_to_items(
python_name: options.name.as_ref(), python_name: options.name.as_ref(),
renaming_rule: rename_all.map(|rename_all| rename_all.value.rule), renaming_rule: rename_all.map(|rename_all| rename_all.value.rule),
}, },
ctx,
)?; )?;
items.push(getter); items.push(getter);
} }
@ -1260,6 +1286,7 @@ fn descriptors_to_items(
python_name: options.name.as_ref(), python_name: options.name.as_ref(),
renaming_rule: rename_all.map(|rename_all| rename_all.value.rule), renaming_rule: rename_all.map(|rename_all| rename_all.value.rule),
}, },
ctx,
)?; )?;
items.push(setter); items.push(setter);
}; };
@ -1270,8 +1297,10 @@ fn descriptors_to_items(
fn impl_pytypeinfo( fn impl_pytypeinfo(
cls: &syn::Ident, cls: &syn::Ident,
attr: &PyClassArgs, attr: &PyClassArgs,
deprecations: Option<&Deprecations>, deprecations: Option<&Deprecations<'_>>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let cls_name = get_class_python_name(cls, attr).to_string(); let cls_name = get_class_python_name(cls, attr).to_string();
let module = if let Some(ModuleAttribute { value, .. }) = &attr.options.module { let module = if let Some(ModuleAttribute { value, .. }) = &attr.options.module {
@ -1282,20 +1311,20 @@ fn impl_pytypeinfo(
quote! { quote! {
#[allow(deprecated)] #[allow(deprecated)]
unsafe impl _pyo3::type_object::HasPyGilRef for #cls { unsafe impl #pyo3_path::type_object::HasPyGilRef for #cls {
type AsRefTarget = _pyo3::PyCell<Self>; type AsRefTarget = #pyo3_path::PyCell<Self>;
} }
unsafe impl _pyo3::type_object::PyTypeInfo for #cls { unsafe impl #pyo3_path::type_object::PyTypeInfo for #cls {
const NAME: &'static str = #cls_name; const NAME: &'static str = #cls_name;
const MODULE: ::std::option::Option<&'static str> = #module; const MODULE: ::std::option::Option<&'static str> = #module;
#[inline] #[inline]
fn type_object_raw(py: _pyo3::Python<'_>) -> *mut _pyo3::ffi::PyTypeObject { fn type_object_raw(py: #pyo3_path::Python<'_>) -> *mut #pyo3_path::ffi::PyTypeObject {
use _pyo3::prelude::PyTypeMethods; use #pyo3_path::prelude::PyTypeMethods;
#deprecations #deprecations
<#cls as _pyo3::impl_::pyclass::PyClassImpl>::lazy_type_object() <#cls as #pyo3_path::impl_::pyclass::PyClassImpl>::lazy_type_object()
.get_or_init(py) .get_or_init(py)
.as_type_ptr() .as_type_ptr()
} }
@ -1342,82 +1371,85 @@ impl<'a> PyClassImplsBuilder<'a> {
} }
} }
fn impl_all(&self) -> Result<TokenStream> { fn impl_all(&self, ctx: &Ctx) -> Result<TokenStream> {
let tokens = vec![ let tokens = vec![
self.impl_pyclass(), self.impl_pyclass(ctx),
self.impl_extractext(), self.impl_extractext(ctx),
self.impl_into_py(), self.impl_into_py(ctx),
self.impl_pyclassimpl()?, self.impl_pyclassimpl(ctx)?,
self.impl_freelist(), self.impl_freelist(ctx),
] ]
.into_iter() .into_iter()
.collect(); .collect();
Ok(tokens) Ok(tokens)
} }
fn impl_pyclass(&self) -> TokenStream { fn impl_pyclass(&self, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let cls = self.cls; let cls = self.cls;
let frozen = if self.attr.options.frozen.is_some() { let frozen = if self.attr.options.frozen.is_some() {
quote! { _pyo3::pyclass::boolean_struct::True } quote! { #pyo3_path::pyclass::boolean_struct::True }
} else { } else {
quote! { _pyo3::pyclass::boolean_struct::False } quote! { #pyo3_path::pyclass::boolean_struct::False }
}; };
quote! { quote! {
impl _pyo3::PyClass for #cls { impl #pyo3_path::PyClass for #cls {
type Frozen = #frozen; type Frozen = #frozen;
} }
} }
} }
fn impl_extractext(&self) -> TokenStream { fn impl_extractext(&self, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let cls = self.cls; let cls = self.cls;
if self.attr.options.frozen.is_some() { if self.attr.options.frozen.is_some() {
quote! { quote! {
impl<'a, 'py> _pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a #cls impl<'a, 'py> #pyo3_path::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a #cls
{ {
type Holder = ::std::option::Option<_pyo3::PyRef<'py, #cls>>; type Holder = ::std::option::Option<#pyo3_path::PyRef<'py, #cls>>;
#[inline] #[inline]
fn extract(obj: &'a _pyo3::Bound<'py, _pyo3::PyAny>, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> { fn extract(obj: &'a #pyo3_path::Bound<'py, #pyo3_path::PyAny>, holder: &'a mut Self::Holder) -> #pyo3_path::PyResult<Self> {
_pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder) #pyo3_path::impl_::extract_argument::extract_pyclass_ref(obj, holder)
} }
} }
} }
} else { } else {
quote! { quote! {
impl<'a, 'py> _pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a #cls impl<'a, 'py> #pyo3_path::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a #cls
{ {
type Holder = ::std::option::Option<_pyo3::PyRef<'py, #cls>>; type Holder = ::std::option::Option<#pyo3_path::PyRef<'py, #cls>>;
#[inline] #[inline]
fn extract(obj: &'a _pyo3::Bound<'py, _pyo3::PyAny>, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> { fn extract(obj: &'a #pyo3_path::Bound<'py, #pyo3_path::PyAny>, holder: &'a mut Self::Holder) -> #pyo3_path::PyResult<Self> {
_pyo3::impl_::extract_argument::extract_pyclass_ref(obj, holder) #pyo3_path::impl_::extract_argument::extract_pyclass_ref(obj, holder)
} }
} }
impl<'a, 'py> _pyo3::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a mut #cls impl<'a, 'py> #pyo3_path::impl_::extract_argument::PyFunctionArgument<'a, 'py> for &'a mut #cls
{ {
type Holder = ::std::option::Option<_pyo3::PyRefMut<'py, #cls>>; type Holder = ::std::option::Option<#pyo3_path::PyRefMut<'py, #cls>>;
#[inline] #[inline]
fn extract(obj: &'a _pyo3::Bound<'py, _pyo3::PyAny>, holder: &'a mut Self::Holder) -> _pyo3::PyResult<Self> { fn extract(obj: &'a #pyo3_path::Bound<'py, #pyo3_path::PyAny>, holder: &'a mut Self::Holder) -> #pyo3_path::PyResult<Self> {
_pyo3::impl_::extract_argument::extract_pyclass_ref_mut(obj, holder) #pyo3_path::impl_::extract_argument::extract_pyclass_ref_mut(obj, holder)
} }
} }
} }
} }
} }
fn impl_into_py(&self) -> TokenStream { fn impl_into_py(&self, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let cls = self.cls; let cls = self.cls;
let attr = self.attr; let attr = self.attr;
// If #cls is not extended type, we allow Self->PyObject conversion // If #cls is not extended type, we allow Self->PyObject conversion
if attr.options.extends.is_none() { if attr.options.extends.is_none() {
quote! { quote! {
impl _pyo3::IntoPy<_pyo3::PyObject> for #cls { impl #pyo3_path::IntoPy<#pyo3_path::PyObject> for #cls {
fn into_py(self, py: _pyo3::Python) -> _pyo3::PyObject { fn into_py(self, py: #pyo3_path::Python) -> #pyo3_path::PyObject {
_pyo3::IntoPy::into_py(_pyo3::Py::new(py, self).unwrap(), py) #pyo3_path::IntoPy::into_py(#pyo3_path::Py::new(py, self).unwrap(), py)
} }
} }
} }
@ -1425,13 +1457,14 @@ impl<'a> PyClassImplsBuilder<'a> {
quote! {} quote! {}
} }
} }
fn impl_pyclassimpl(&self) -> Result<TokenStream> { fn impl_pyclassimpl(&self, ctx: &Ctx) -> Result<TokenStream> {
let Ctx { pyo3_path } = ctx;
let cls = self.cls; let cls = self.cls;
let doc = self.doc.as_ref().map_or(quote! {"\0"}, |doc| quote! {#doc}); let doc = self.doc.as_ref().map_or(quote! {"\0"}, |doc| quote! {#doc});
let is_basetype = self.attr.options.subclass.is_some(); let is_basetype = self.attr.options.subclass.is_some();
let base = match &self.attr.options.extends { let base = match &self.attr.options.extends {
Some(extends_attr) => extends_attr.value.clone(), Some(extends_attr) => extends_attr.value.clone(),
None => parse_quote! { _pyo3::PyAny }, None => parse_quote! { #pyo3_path::PyAny },
}; };
let is_subclass = self.attr.options.extends.is_some(); let is_subclass = self.attr.options.extends.is_some();
let is_mapping: bool = self.attr.options.mapping.is_some(); let is_mapping: bool = self.attr.options.mapping.is_some();
@ -1444,8 +1477,8 @@ impl<'a> PyClassImplsBuilder<'a> {
let dict_offset = if self.attr.options.dict.is_some() { let dict_offset = if self.attr.options.dict.is_some() {
quote! { quote! {
fn dict_offset() -> ::std::option::Option<_pyo3::ffi::Py_ssize_t> { fn dict_offset() -> ::std::option::Option<#pyo3_path::ffi::Py_ssize_t> {
::std::option::Option::Some(_pyo3::impl_::pyclass::dict_offset::<Self>()) ::std::option::Option::Some(#pyo3_path::impl_::pyclass::dict_offset::<Self>())
} }
} }
} else { } else {
@ -1455,8 +1488,8 @@ impl<'a> PyClassImplsBuilder<'a> {
// insert space for weak ref // insert space for weak ref
let weaklist_offset = if self.attr.options.weakref.is_some() { let weaklist_offset = if self.attr.options.weakref.is_some() {
quote! { quote! {
fn weaklist_offset() -> ::std::option::Option<_pyo3::ffi::Py_ssize_t> { fn weaklist_offset() -> ::std::option::Option<#pyo3_path::ffi::Py_ssize_t> {
::std::option::Option::Some(_pyo3::impl_::pyclass::weaklist_offset::<Self>()) ::std::option::Option::Some(#pyo3_path::impl_::pyclass::weaklist_offset::<Self>())
} }
} }
} else { } else {
@ -1464,9 +1497,9 @@ impl<'a> PyClassImplsBuilder<'a> {
}; };
let thread_checker = if self.attr.options.unsendable.is_some() { let thread_checker = if self.attr.options.unsendable.is_some() {
quote! { _pyo3::impl_::pyclass::ThreadCheckerImpl } quote! { #pyo3_path::impl_::pyclass::ThreadCheckerImpl }
} else { } else {
quote! { _pyo3::impl_::pyclass::SendablePyClass<#cls> } quote! { #pyo3_path::impl_::pyclass::SendablePyClass<#cls> }
}; };
let (pymethods_items, inventory, inventory_class) = match self.methods_type { let (pymethods_items, inventory, inventory_class) = match self.methods_type {
@ -1481,13 +1514,13 @@ impl<'a> PyClassImplsBuilder<'a> {
quote! { quote! {
::std::boxed::Box::new( ::std::boxed::Box::new(
::std::iter::Iterator::map( ::std::iter::Iterator::map(
_pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>(), #pyo3_path::inventory::iter::<<Self as #pyo3_path::impl_::pyclass::PyClassImpl>::Inventory>(),
_pyo3::impl_::pyclass::PyClassInventory::items #pyo3_path::impl_::pyclass::PyClassInventory::items
) )
) )
}, },
Some(quote! { type Inventory = #inventory_class_name; }), Some(quote! { type Inventory = #inventory_class_name; }),
Some(define_inventory_class(&inventory_class_name)), Some(define_inventory_class(&inventory_class_name, ctx)),
) )
} }
}; };
@ -1504,7 +1537,7 @@ impl<'a> PyClassImplsBuilder<'a> {
let default_method_defs = self.default_methods.iter().map(|meth| &meth.method_def); let default_method_defs = self.default_methods.iter().map(|meth| &meth.method_def);
let default_slot_defs = self.default_slots.iter().map(|slot| &slot.slot_def); let default_slot_defs = self.default_slots.iter().map(|slot| &slot.slot_def);
let freelist_slots = self.freelist_slots(); let freelist_slots = self.freelist_slots(ctx);
let class_mutability = if self.attr.options.frozen.is_some() { let class_mutability = if self.attr.options.frozen.is_some() {
quote! { quote! {
@ -1519,26 +1552,26 @@ impl<'a> PyClassImplsBuilder<'a> {
let cls = self.cls; let cls = self.cls;
let attr = self.attr; let attr = self.attr;
let dict = if attr.options.dict.is_some() { let dict = if attr.options.dict.is_some() {
quote! { _pyo3::impl_::pyclass::PyClassDictSlot } quote! { #pyo3_path::impl_::pyclass::PyClassDictSlot }
} else { } else {
quote! { _pyo3::impl_::pyclass::PyClassDummySlot } quote! { #pyo3_path::impl_::pyclass::PyClassDummySlot }
}; };
// insert space for weak ref // insert space for weak ref
let weakref = if attr.options.weakref.is_some() { let weakref = if attr.options.weakref.is_some() {
quote! { _pyo3::impl_::pyclass::PyClassWeakRefSlot } quote! { #pyo3_path::impl_::pyclass::PyClassWeakRefSlot }
} else { } else {
quote! { _pyo3::impl_::pyclass::PyClassDummySlot } quote! { #pyo3_path::impl_::pyclass::PyClassDummySlot }
}; };
let base_nativetype = if attr.options.extends.is_some() { let base_nativetype = if attr.options.extends.is_some() {
quote! { <Self::BaseType as _pyo3::impl_::pyclass::PyClassBaseType>::BaseNativeType } quote! { <Self::BaseType as #pyo3_path::impl_::pyclass::PyClassBaseType>::BaseNativeType }
} else { } else {
quote! { _pyo3::PyAny } quote! { #pyo3_path::PyAny }
}; };
Ok(quote! { Ok(quote! {
impl _pyo3::impl_::pyclass::PyClassImpl for #cls { impl #pyo3_path::impl_::pyclass::PyClassImpl for #cls {
const IS_BASETYPE: bool = #is_basetype; const IS_BASETYPE: bool = #is_basetype;
const IS_SUBCLASS: bool = #is_subclass; const IS_SUBCLASS: bool = #is_subclass;
const IS_MAPPING: bool = #is_mapping; const IS_MAPPING: bool = #is_mapping;
@ -1547,13 +1580,13 @@ impl<'a> PyClassImplsBuilder<'a> {
type BaseType = #base; type BaseType = #base;
type ThreadChecker = #thread_checker; type ThreadChecker = #thread_checker;
#inventory #inventory
type PyClassMutability = <<#base as _pyo3::impl_::pyclass::PyClassBaseType>::PyClassMutability as _pyo3::impl_::pycell::PyClassMutability>::#class_mutability; type PyClassMutability = <<#base as #pyo3_path::impl_::pyclass::PyClassBaseType>::PyClassMutability as #pyo3_path::impl_::pycell::PyClassMutability>::#class_mutability;
type Dict = #dict; type Dict = #dict;
type WeakRef = #weakref; type WeakRef = #weakref;
type BaseNativeType = #base_nativetype; type BaseNativeType = #base_nativetype;
fn items_iter() -> _pyo3::impl_::pyclass::PyClassItemsIter { fn items_iter() -> #pyo3_path::impl_::pyclass::PyClassItemsIter {
use _pyo3::impl_::pyclass::*; use #pyo3_path::impl_::pyclass::*;
let collector = PyClassImplCollector::<Self>::new(); let collector = PyClassImplCollector::<Self>::new();
static INTRINSIC_ITEMS: PyClassItems = PyClassItems { static INTRINSIC_ITEMS: PyClassItems = PyClassItems {
methods: &[#(#default_method_defs),*], methods: &[#(#default_method_defs),*],
@ -1562,12 +1595,12 @@ impl<'a> PyClassImplsBuilder<'a> {
PyClassItemsIter::new(&INTRINSIC_ITEMS, #pymethods_items) PyClassItemsIter::new(&INTRINSIC_ITEMS, #pymethods_items)
} }
fn doc(py: _pyo3::Python<'_>) -> _pyo3::PyResult<&'static ::std::ffi::CStr> { fn doc(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<&'static ::std::ffi::CStr> {
use _pyo3::impl_::pyclass::*; use #pyo3_path::impl_::pyclass::*;
static DOC: _pyo3::sync::GILOnceCell<::std::borrow::Cow<'static, ::std::ffi::CStr>> = _pyo3::sync::GILOnceCell::new(); static DOC: #pyo3_path::sync::GILOnceCell<::std::borrow::Cow<'static, ::std::ffi::CStr>> = #pyo3_path::sync::GILOnceCell::new();
DOC.get_or_try_init(py, || { DOC.get_or_try_init(py, || {
let collector = PyClassImplCollector::<Self>::new(); let collector = PyClassImplCollector::<Self>::new();
build_pyclass_doc(<#cls as _pyo3::PyTypeInfo>::NAME, #doc, collector.new_text_signature()) build_pyclass_doc(<#cls as #pyo3_path::PyTypeInfo>::NAME, #doc, collector.new_text_signature())
}).map(::std::ops::Deref::deref) }).map(::std::ops::Deref::deref)
} }
@ -1575,8 +1608,8 @@ impl<'a> PyClassImplsBuilder<'a> {
#weaklist_offset #weaklist_offset
fn lazy_type_object() -> &'static _pyo3::impl_::pyclass::LazyTypeObject<Self> { fn lazy_type_object() -> &'static #pyo3_path::impl_::pyclass::LazyTypeObject<Self> {
use _pyo3::impl_::pyclass::LazyTypeObject; use #pyo3_path::impl_::pyclass::LazyTypeObject;
static TYPE_OBJECT: LazyTypeObject<#cls> = LazyTypeObject::new(); static TYPE_OBJECT: LazyTypeObject<#cls> = LazyTypeObject::new();
&TYPE_OBJECT &TYPE_OBJECT
} }
@ -1592,20 +1625,21 @@ impl<'a> PyClassImplsBuilder<'a> {
}) })
} }
fn impl_freelist(&self) -> TokenStream { fn impl_freelist(&self, ctx: &Ctx) -> TokenStream {
let cls = self.cls; let cls = self.cls;
let Ctx { pyo3_path } = ctx;
self.attr.options.freelist.as_ref().map_or(quote!{}, |freelist| { self.attr.options.freelist.as_ref().map_or(quote!{}, |freelist| {
let freelist = &freelist.value; let freelist = &freelist.value;
quote! { quote! {
impl _pyo3::impl_::pyclass::PyClassWithFreeList for #cls { impl #pyo3_path::impl_::pyclass::PyClassWithFreeList for #cls {
#[inline] #[inline]
fn get_free_list(py: _pyo3::Python<'_>) -> &mut _pyo3::impl_::freelist::FreeList<*mut _pyo3::ffi::PyObject> { fn get_free_list(py: #pyo3_path::Python<'_>) -> &mut #pyo3_path::impl_::freelist::FreeList<*mut #pyo3_path::ffi::PyObject> {
static mut FREELIST: *mut _pyo3::impl_::freelist::FreeList<*mut _pyo3::ffi::PyObject> = 0 as *mut _; static mut FREELIST: *mut #pyo3_path::impl_::freelist::FreeList<*mut #pyo3_path::ffi::PyObject> = 0 as *mut _;
unsafe { unsafe {
if FREELIST.is_null() { if FREELIST.is_null() {
FREELIST = ::std::boxed::Box::into_raw(::std::boxed::Box::new( FREELIST = ::std::boxed::Box::into_raw(::std::boxed::Box::new(
_pyo3::impl_::freelist::FreeList::with_capacity(#freelist))); #pyo3_path::impl_::freelist::FreeList::with_capacity(#freelist)));
} }
&mut *FREELIST &mut *FREELIST
} }
@ -1615,21 +1649,22 @@ impl<'a> PyClassImplsBuilder<'a> {
}) })
} }
fn freelist_slots(&self) -> Vec<TokenStream> { fn freelist_slots(&self, ctx: &Ctx) -> Vec<TokenStream> {
let Ctx { pyo3_path } = ctx;
let cls = self.cls; let cls = self.cls;
if self.attr.options.freelist.is_some() { if self.attr.options.freelist.is_some() {
vec![ vec![
quote! { quote! {
_pyo3::ffi::PyType_Slot { #pyo3_path::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_alloc, slot: #pyo3_path::ffi::Py_tp_alloc,
pfunc: _pyo3::impl_::pyclass::alloc_with_freelist::<#cls> as *mut _, pfunc: #pyo3_path::impl_::pyclass::alloc_with_freelist::<#cls> as *mut _,
} }
}, },
quote! { quote! {
_pyo3::ffi::PyType_Slot { #pyo3_path::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_free, slot: #pyo3_path::ffi::Py_tp_free,
pfunc: _pyo3::impl_::pyclass::free_with_freelist::<#cls> as *mut _, pfunc: #pyo3_path::impl_::pyclass::free_with_freelist::<#cls> as *mut _,
} }
}, },
] ]
@ -1639,25 +1674,26 @@ impl<'a> PyClassImplsBuilder<'a> {
} }
} }
fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream { fn define_inventory_class(inventory_class_name: &syn::Ident, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
quote! { quote! {
#[doc(hidden)] #[doc(hidden)]
pub struct #inventory_class_name { pub struct #inventory_class_name {
items: _pyo3::impl_::pyclass::PyClassItems, items: #pyo3_path::impl_::pyclass::PyClassItems,
} }
impl #inventory_class_name { impl #inventory_class_name {
pub const fn new(items: _pyo3::impl_::pyclass::PyClassItems) -> Self { pub const fn new(items: #pyo3_path::impl_::pyclass::PyClassItems) -> Self {
Self { items } Self { items }
} }
} }
impl _pyo3::impl_::pyclass::PyClassInventory for #inventory_class_name { impl #pyo3_path::impl_::pyclass::PyClassInventory for #inventory_class_name {
fn items(&self) -> &_pyo3::impl_::pyclass::PyClassItems { fn items(&self) -> &#pyo3_path::impl_::pyclass::PyClassItems {
&self.items &self.items
} }
} }
_pyo3::inventory::collect!(#inventory_class_name); #pyo3_path::inventory::collect!(#inventory_class_name);
} }
} }

View File

@ -1,3 +1,4 @@
use crate::utils::Ctx;
use crate::{ use crate::{
attributes::{ attributes::{
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute, self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
@ -6,7 +7,6 @@ use crate::{
deprecations::Deprecations, deprecations::Deprecations,
method::{self, CallingConvention, FnArg}, method::{self, CallingConvention, FnArg},
pymethod::check_generic, pymethod::check_generic,
utils::get_pyo3_crate,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -205,6 +205,9 @@ pub fn impl_wrap_pyfunction(
krate, krate,
} = options; } = options;
let ctx = &Ctx::new(&krate);
let Ctx { pyo3_path } = &ctx;
let python_name = name.map_or_else(|| func.sig.ident.unraw(), |name| name.value.0); let python_name = name.map_or_else(|| func.sig.ident.unraw(), |name| name.value.0);
let tp = if pass_module.is_some() { let tp = if pass_module.is_some() {
@ -249,17 +252,15 @@ pub fn impl_wrap_pyfunction(
text_signature, text_signature,
asyncness: func.sig.asyncness, asyncness: func.sig.asyncness,
unsafety: func.sig.unsafety, unsafety: func.sig.unsafety,
deprecations: Deprecations::new(), deprecations: Deprecations::new(ctx),
}; };
let krate = get_pyo3_crate(&krate);
let vis = &func.vis; let vis = &func.vis;
let name = &func.sig.ident; let name = &func.sig.ident;
let wrapper_ident = format_ident!("__pyfunction_{}", spec.name); let wrapper_ident = format_ident!("__pyfunction_{}", spec.name);
let wrapper = spec.get_wrapper_function(&wrapper_ident, None)?; let wrapper = spec.get_wrapper_function(&wrapper_ident, None, ctx)?;
let methoddef = spec.get_methoddef(wrapper_ident, &spec.get_doc(&func.attrs)); let methoddef = spec.get_methoddef(wrapper_ident, &spec.get_doc(&func.attrs), ctx);
let wrapped_pyfunction = quote! { let wrapped_pyfunction = quote! {
@ -268,12 +269,12 @@ pub fn impl_wrap_pyfunction(
#[doc(hidden)] #[doc(hidden)]
#vis mod #name { #vis mod #name {
pub(crate) struct MakeDef; pub(crate) struct MakeDef;
pub const DEF: #krate::impl_::pymethods::PyMethodDef = MakeDef::DEF; pub const DEF: #pyo3_path::impl_::pymethods::PyMethodDef = MakeDef::DEF;
pub fn add_to_module(module: &#krate::Bound<'_, #krate::types::PyModule>) -> #krate::PyResult<()> { pub fn add_to_module(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> {
use #krate::prelude::PyModuleMethods; use #pyo3_path::prelude::PyModuleMethods;
use ::std::convert::Into; use ::std::convert::Into;
module.add_function(#krate::types::PyCFunction::internal_new(module.py(), &DEF, module.into())?) module.add_function(#pyo3_path::types::PyCFunction::internal_new(module.py(), &DEF, module.into())?)
} }
} }
@ -284,10 +285,8 @@ pub fn impl_wrap_pyfunction(
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate as _pyo3;
impl #name::MakeDef { impl #name::MakeDef {
const DEF: #krate::impl_::pymethods::PyMethodDef = #methoddef; const DEF: #pyo3_path::impl_::pymethods::PyMethodDef = #methoddef;
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]

View File

@ -1,11 +1,11 @@
use std::collections::HashSet; use std::collections::HashSet;
use crate::utils::Ctx;
use crate::{ use crate::{
attributes::{take_pyo3_options, CrateAttribute}, attributes::{take_pyo3_options, CrateAttribute},
konst::{ConstAttributes, ConstSpec}, konst::{ConstAttributes, ConstSpec},
pyfunction::PyFunctionOptions, pyfunction::PyFunctionOptions,
pymethod::{self, is_proto_method, MethodAndMethodDef, MethodAndSlotDef}, pymethod::{self, is_proto_method, MethodAndMethodDef, MethodAndSlotDef},
utils::get_pyo3_crate,
}; };
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use pymethod::GeneratedPyMethod; use pymethod::GeneratedPyMethod;
@ -90,6 +90,7 @@ pub fn impl_methods(
methods_type: PyClassMethodsType, methods_type: PyClassMethodsType,
options: PyImplOptions, options: PyImplOptions,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let ctx = &Ctx::new(&options.krate);
let mut trait_impls = Vec::new(); let mut trait_impls = Vec::new();
let mut proto_impls = Vec::new(); let mut proto_impls = Vec::new();
let mut methods = Vec::new(); let mut methods = Vec::new();
@ -102,7 +103,8 @@ pub fn impl_methods(
syn::ImplItem::Fn(meth) => { syn::ImplItem::Fn(meth) => {
let mut fun_options = PyFunctionOptions::from_attrs(&mut meth.attrs)?; let mut fun_options = PyFunctionOptions::from_attrs(&mut meth.attrs)?;
fun_options.krate = fun_options.krate.or_else(|| options.krate.clone()); 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)? { match pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs, fun_options, ctx)?
{
GeneratedPyMethod::Method(MethodAndMethodDef { GeneratedPyMethod::Method(MethodAndMethodDef {
associated_method, associated_method,
method_def, method_def,
@ -127,7 +129,7 @@ pub fn impl_methods(
} }
} }
syn::ImplItem::Const(konst) => { syn::ImplItem::Const(konst) => {
let attributes = ConstAttributes::from_attrs(&mut konst.attrs)?; let attributes = ConstAttributes::from_attrs(&mut konst.attrs, ctx)?;
if attributes.is_class_attr { if attributes.is_class_attr {
let spec = ConstSpec { let spec = ConstSpec {
rust_ident: konst.ident.clone(), rust_ident: konst.ident.clone(),
@ -137,7 +139,7 @@ pub fn impl_methods(
let MethodAndMethodDef { let MethodAndMethodDef {
associated_method, associated_method,
method_def, method_def,
} = gen_py_const(ty, &spec); } = gen_py_const(ty, &spec, ctx);
methods.push(quote!(#(#attrs)* #method_def)); methods.push(quote!(#(#attrs)* #method_def));
associated_methods.push(quote!(#(#attrs)* #associated_method)); associated_methods.push(quote!(#(#attrs)* #associated_method));
if is_proto_method(&spec.python_name().to_string()) { if is_proto_method(&spec.python_name().to_string()) {
@ -158,21 +160,19 @@ pub fn impl_methods(
} }
} }
add_shared_proto_slots(ty, &mut proto_impls, implemented_proto_fragments); add_shared_proto_slots(ty, &mut proto_impls, implemented_proto_fragments, ctx);
let krate = get_pyo3_crate(&options.krate); let ctx = &Ctx::new(&options.krate);
let items = match methods_type { let items = match methods_type {
PyClassMethodsType::Specialization => impl_py_methods(ty, methods, proto_impls), PyClassMethodsType::Specialization => impl_py_methods(ty, methods, proto_impls, ctx),
PyClassMethodsType::Inventory => submit_methods_inventory(ty, methods, proto_impls), PyClassMethodsType::Inventory => submit_methods_inventory(ty, methods, proto_impls, ctx),
}; };
Ok(quote! { Ok(quote! {
// FIXME https://github.com/PyO3/pyo3/issues/3903 // FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)] #[allow(unknown_lints, non_local_definitions)]
const _: () = { const _: () = {
use #krate as _pyo3;
#(#trait_impls)* #(#trait_impls)*
#items #items
@ -186,24 +186,25 @@ pub fn impl_methods(
}) })
} }
pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec) -> MethodAndMethodDef { pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec<'_>, ctx: &Ctx) -> MethodAndMethodDef {
let member = &spec.rust_ident; let member = &spec.rust_ident;
let wrapper_ident = format_ident!("__pymethod_{}__", member); let wrapper_ident = format_ident!("__pymethod_{}__", member);
let deprecations = &spec.attributes.deprecations; let deprecations = &spec.attributes.deprecations;
let python_name = &spec.null_terminated_python_name(); let python_name = &spec.null_terminated_python_name();
let Ctx { pyo3_path } = ctx;
let associated_method = quote! { let associated_method = quote! {
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> { fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
#deprecations #deprecations
::std::result::Result::Ok(_pyo3::IntoPy::into_py(#cls::#member, py)) ::std::result::Result::Ok(#pyo3_path::IntoPy::into_py(#cls::#member, py))
} }
}; };
let method_def = quote! { let method_def = quote! {
_pyo3::class::PyMethodDefType::ClassAttribute({ #pyo3_path::class::PyMethodDefType::ClassAttribute({
_pyo3::class::PyClassAttributeDef::new( #pyo3_path::class::PyClassAttributeDef::new(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyClassAttributeFactory(#cls::#wrapper_ident) #pyo3_path::impl_::pymethods::PyClassAttributeFactory(#cls::#wrapper_ident)
) )
}) })
}; };
@ -218,13 +219,15 @@ fn impl_py_methods(
ty: &syn::Type, ty: &syn::Type,
methods: Vec<TokenStream>, methods: Vec<TokenStream>,
proto_impls: Vec<TokenStream>, proto_impls: Vec<TokenStream>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
let Ctx { pyo3_path } = ctx;
quote! { quote! {
impl _pyo3::impl_::pyclass::PyMethods<#ty> impl #pyo3_path::impl_::pyclass::PyMethods<#ty>
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty> for #pyo3_path::impl_::pyclass::PyClassImplCollector<#ty>
{ {
fn py_methods(self) -> &'static _pyo3::impl_::pyclass::PyClassItems { fn py_methods(self) -> &'static #pyo3_path::impl_::pyclass::PyClassItems {
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems { static ITEMS: #pyo3_path::impl_::pyclass::PyClassItems = #pyo3_path::impl_::pyclass::PyClassItems {
methods: &[#(#methods),*], methods: &[#(#methods),*],
slots: &[#(#proto_impls),*] slots: &[#(#proto_impls),*]
}; };
@ -238,13 +241,15 @@ fn add_shared_proto_slots(
ty: &syn::Type, ty: &syn::Type,
proto_impls: &mut Vec<TokenStream>, proto_impls: &mut Vec<TokenStream>,
mut implemented_proto_fragments: HashSet<String>, mut implemented_proto_fragments: HashSet<String>,
ctx: &Ctx,
) { ) {
let Ctx { pyo3_path } = ctx;
macro_rules! try_add_shared_slot { macro_rules! try_add_shared_slot {
($slot:ident, $($fragments:literal),*) => {{ ($slot:ident, $($fragments:literal),*) => {{
let mut implemented = false; let mut implemented = false;
$(implemented |= implemented_proto_fragments.remove($fragments));*; $(implemented |= implemented_proto_fragments.remove($fragments));*;
if implemented { if implemented {
proto_impls.push(quote! { _pyo3::impl_::pyclass::$slot!(#ty) }) proto_impls.push(quote! { #pyo3_path::impl_::pyclass::$slot!(#ty) })
} }
}}; }};
} }
@ -294,11 +299,13 @@ fn submit_methods_inventory(
ty: &syn::Type, ty: &syn::Type,
methods: Vec<TokenStream>, methods: Vec<TokenStream>,
proto_impls: Vec<TokenStream>, proto_impls: Vec<TokenStream>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
let Ctx { pyo3_path } = ctx;
quote! { quote! {
_pyo3::inventory::submit! { #pyo3_path::inventory::submit! {
type Inventory = <#ty as _pyo3::impl_::pyclass::PyClassImpl>::Inventory; type Inventory = <#ty as #pyo3_path::impl_::pyclass::PyClassImpl>::Inventory;
Inventory::new(_pyo3::impl_::pyclass::PyClassItems { methods: &[#(#methods),*], slots: &[#(#proto_impls),*] }) Inventory::new(#pyo3_path::impl_::pyclass::PyClassItems { methods: &[#(#methods),*], slots: &[#(#proto_impls),*] })
} }
} }
} }

View File

@ -2,6 +2,7 @@ use std::borrow::Cow;
use crate::attributes::{NameAttribute, RenamingRule}; use crate::attributes::{NameAttribute, RenamingRule};
use crate::method::{CallingConvention, ExtractErrorMode}; use crate::method::{CallingConvention, ExtractErrorMode};
use crate::utils::Ctx;
use crate::utils::PythonDoc; use crate::utils::PythonDoc;
use crate::{ use crate::{
method::{FnArg, FnSpec, FnType, SelfType}, method::{FnArg, FnSpec, FnType, SelfType},
@ -160,8 +161,9 @@ impl<'a> PyMethod<'a> {
sig: &'a mut syn::Signature, sig: &'a mut syn::Signature,
meth_attrs: &mut Vec<syn::Attribute>, meth_attrs: &mut Vec<syn::Attribute>,
options: PyFunctionOptions, options: PyFunctionOptions,
ctx: &'a Ctx,
) -> Result<Self> { ) -> Result<Self> {
let spec = FnSpec::parse(sig, meth_attrs, options)?; let spec = FnSpec::parse(sig, meth_attrs, options, ctx)?;
let method_name = spec.python_name.to_string(); let method_name = spec.python_name.to_string();
let kind = PyMethodKind::from_name(&method_name); let kind = PyMethodKind::from_name(&method_name);
@ -186,33 +188,35 @@ pub fn gen_py_method(
sig: &mut syn::Signature, sig: &mut syn::Signature,
meth_attrs: &mut Vec<syn::Attribute>, meth_attrs: &mut Vec<syn::Attribute>,
options: PyFunctionOptions, options: PyFunctionOptions,
ctx: &Ctx,
) -> Result<GeneratedPyMethod> { ) -> Result<GeneratedPyMethod> {
check_generic(sig)?; check_generic(sig)?;
ensure_function_options_valid(&options)?; ensure_function_options_valid(&options)?;
let method = PyMethod::parse(sig, meth_attrs, options)?; let method = PyMethod::parse(sig, meth_attrs, options, ctx)?;
let spec = &method.spec; let spec = &method.spec;
let Ctx { pyo3_path } = ctx;
Ok(match (method.kind, &spec.tp) { Ok(match (method.kind, &spec.tp) {
// Class attributes go before protos so that class attributes can be used to set proto // Class attributes go before protos so that class attributes can be used to set proto
// method to None. // method to None.
(_, FnType::ClassAttribute) => { (_, FnType::ClassAttribute) => {
GeneratedPyMethod::Method(impl_py_class_attribute(cls, spec)?) GeneratedPyMethod::Method(impl_py_class_attribute(cls, spec, ctx)?)
} }
(PyMethodKind::Proto(proto_kind), _) => { (PyMethodKind::Proto(proto_kind), _) => {
ensure_no_forbidden_protocol_attributes(&proto_kind, spec, &method.method_name)?; ensure_no_forbidden_protocol_attributes(&proto_kind, spec, &method.method_name)?;
match proto_kind { match proto_kind {
PyMethodProtoKind::Slot(slot_def) => { PyMethodProtoKind::Slot(slot_def) => {
let slot = slot_def.generate_type_slot(cls, spec, &method.method_name)?; let slot = slot_def.generate_type_slot(cls, spec, &method.method_name, ctx)?;
GeneratedPyMethod::Proto(slot) GeneratedPyMethod::Proto(slot)
} }
PyMethodProtoKind::Call => { PyMethodProtoKind::Call => {
GeneratedPyMethod::Proto(impl_call_slot(cls, method.spec)?) GeneratedPyMethod::Proto(impl_call_slot(cls, method.spec, ctx)?)
} }
PyMethodProtoKind::Traverse => { PyMethodProtoKind::Traverse => {
GeneratedPyMethod::Proto(impl_traverse_slot(cls, spec)?) GeneratedPyMethod::Proto(impl_traverse_slot(cls, spec, ctx)?)
} }
PyMethodProtoKind::SlotFragment(slot_fragment_def) => { PyMethodProtoKind::SlotFragment(slot_fragment_def) => {
let proto = slot_fragment_def.generate_pyproto_fragment(cls, spec)?; let proto = slot_fragment_def.generate_pyproto_fragment(cls, spec, ctx)?;
GeneratedPyMethod::SlotTraitImpl(method.method_name, proto) GeneratedPyMethod::SlotTraitImpl(method.method_name, proto)
} }
} }
@ -223,22 +227,25 @@ pub fn gen_py_method(
spec, spec,
&spec.get_doc(meth_attrs), &spec.get_doc(meth_attrs),
None, None,
ctx,
)?), )?),
(_, FnType::FnClass(_)) => GeneratedPyMethod::Method(impl_py_method_def( (_, FnType::FnClass(_)) => GeneratedPyMethod::Method(impl_py_method_def(
cls, cls,
spec, spec,
&spec.get_doc(meth_attrs), &spec.get_doc(meth_attrs),
Some(quote!(_pyo3::ffi::METH_CLASS)), Some(quote!(#pyo3_path::ffi::METH_CLASS)),
ctx,
)?), )?),
(_, FnType::FnStatic) => GeneratedPyMethod::Method(impl_py_method_def( (_, FnType::FnStatic) => GeneratedPyMethod::Method(impl_py_method_def(
cls, cls,
spec, spec,
&spec.get_doc(meth_attrs), &spec.get_doc(meth_attrs),
Some(quote!(_pyo3::ffi::METH_STATIC)), Some(quote!(#pyo3_path::ffi::METH_STATIC)),
ctx,
)?), )?),
// special prototypes // special prototypes
(_, FnType::FnNew) | (_, FnType::FnNewClass(_)) => { (_, FnType::FnNew) | (_, FnType::FnNewClass(_)) => {
GeneratedPyMethod::Proto(impl_py_method_def_new(cls, spec)?) GeneratedPyMethod::Proto(impl_py_method_def_new(cls, spec, ctx)?)
} }
(_, FnType::Getter(self_type)) => GeneratedPyMethod::Method(impl_py_getter_def( (_, FnType::Getter(self_type)) => GeneratedPyMethod::Method(impl_py_getter_def(
@ -248,6 +255,7 @@ pub fn gen_py_method(
spec, spec,
doc: spec.get_doc(meth_attrs), doc: spec.get_doc(meth_attrs),
}, },
ctx,
)?), )?),
(_, FnType::Setter(self_type)) => GeneratedPyMethod::Method(impl_py_setter_def( (_, FnType::Setter(self_type)) => GeneratedPyMethod::Method(impl_py_setter_def(
cls, cls,
@ -256,6 +264,7 @@ pub fn gen_py_method(
spec, spec,
doc: spec.get_doc(meth_attrs), doc: spec.get_doc(meth_attrs),
}, },
ctx,
)?), )?),
(_, FnType::FnModule(_)) => { (_, FnType::FnModule(_)) => {
unreachable!("methods cannot be FnModule") unreachable!("methods cannot be FnModule")
@ -305,18 +314,20 @@ pub fn impl_py_method_def(
spec: &FnSpec<'_>, spec: &FnSpec<'_>,
doc: &PythonDoc, doc: &PythonDoc,
flags: Option<TokenStream>, flags: Option<TokenStream>,
ctx: &Ctx,
) -> Result<MethodAndMethodDef> { ) -> Result<MethodAndMethodDef> {
let Ctx { pyo3_path } = ctx;
let wrapper_ident = format_ident!("__pymethod_{}__", spec.python_name); let wrapper_ident = format_ident!("__pymethod_{}__", spec.python_name);
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls))?; let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls), ctx)?;
let add_flags = flags.map(|flags| quote!(.flags(#flags))); let add_flags = flags.map(|flags| quote!(.flags(#flags)));
let methoddef_type = match spec.tp { let methoddef_type = match spec.tp {
FnType::FnStatic => quote!(Static), FnType::FnStatic => quote!(Static),
FnType::FnClass(_) => quote!(Class), FnType::FnClass(_) => quote!(Class),
_ => quote!(Method), _ => quote!(Method),
}; };
let methoddef = spec.get_methoddef(quote! { #cls::#wrapper_ident }, doc); let methoddef = spec.get_methoddef(quote! { #cls::#wrapper_ident }, doc, ctx);
let method_def = quote! { let method_def = quote! {
_pyo3::class::PyMethodDefType::#methoddef_type(#methoddef #add_flags) #pyo3_path::class::PyMethodDefType::#methoddef_type(#methoddef #add_flags)
}; };
Ok(MethodAndMethodDef { Ok(MethodAndMethodDef {
associated_method, associated_method,
@ -325,9 +336,14 @@ pub fn impl_py_method_def(
} }
/// Also used by pyclass. /// Also used by pyclass.
pub fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<MethodAndSlotDef> { pub fn impl_py_method_def_new(
cls: &syn::Type,
spec: &FnSpec<'_>,
ctx: &Ctx,
) -> Result<MethodAndSlotDef> {
let Ctx { pyo3_path } = ctx;
let wrapper_ident = syn::Ident::new("__pymethod___new____", Span::call_site()); let wrapper_ident = syn::Ident::new("__pymethod___new____", Span::call_site());
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls))?; let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls), ctx)?;
// Use just the text_signature_call_signature() because the class' Python name // Use just the text_signature_call_signature() because the class' Python name
// isn't known to `#[pymethods]` - that has to be attached at runtime from the PyClassImpl // isn't known to `#[pymethods]` - that has to be attached at runtime from the PyClassImpl
// trait implementation created by `#[pyclass]`. // trait implementation created by `#[pyclass]`.
@ -337,18 +353,18 @@ pub fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<Meth
); );
let deprecations = &spec.deprecations; let deprecations = &spec.deprecations;
let slot_def = quote! { let slot_def = quote! {
_pyo3::ffi::PyType_Slot { #pyo3_path::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_new, slot: #pyo3_path::ffi::Py_tp_new,
pfunc: { pfunc: {
unsafe extern "C" fn trampoline( unsafe extern "C" fn trampoline(
subtype: *mut _pyo3::ffi::PyTypeObject, subtype: *mut #pyo3_path::ffi::PyTypeObject,
args: *mut _pyo3::ffi::PyObject, args: *mut #pyo3_path::ffi::PyObject,
kwargs: *mut _pyo3::ffi::PyObject, kwargs: *mut #pyo3_path::ffi::PyObject,
) -> *mut _pyo3::ffi::PyObject ) -> *mut #pyo3_path::ffi::PyObject
{ {
#deprecations #deprecations
use _pyo3::impl_::pyclass::*; use #pyo3_path::impl_::pyclass::*;
impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> { impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> {
#[inline] #[inline]
fn new_text_signature(self) -> ::std::option::Option<&'static str> { fn new_text_signature(self) -> ::std::option::Option<&'static str> {
@ -356,7 +372,7 @@ pub fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<Meth
} }
} }
_pyo3::impl_::trampoline::newfunc( #pyo3_path::impl_::trampoline::newfunc(
subtype, subtype,
args, args,
kwargs, kwargs,
@ -364,7 +380,7 @@ pub fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<Meth
) )
} }
trampoline trampoline
} as _pyo3::ffi::newfunc as _ } as #pyo3_path::ffi::newfunc as _
} }
}; };
Ok(MethodAndSlotDef { Ok(MethodAndSlotDef {
@ -373,24 +389,26 @@ pub fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec<'_>) -> Result<Meth
}) })
} }
fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>) -> Result<MethodAndSlotDef> { fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>, ctx: &Ctx) -> Result<MethodAndSlotDef> {
let Ctx { pyo3_path } = ctx;
// HACK: __call__ proto slot must always use varargs calling convention, so change the spec. // HACK: __call__ proto slot must always use varargs calling convention, so change the spec.
// Probably indicates there's a refactoring opportunity somewhere. // Probably indicates there's a refactoring opportunity somewhere.
spec.convention = CallingConvention::Varargs; spec.convention = CallingConvention::Varargs;
let wrapper_ident = syn::Ident::new("__pymethod___call____", Span::call_site()); let wrapper_ident = syn::Ident::new("__pymethod___call____", Span::call_site());
let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls))?; let associated_method = spec.get_wrapper_function(&wrapper_ident, Some(cls), ctx)?;
let slot_def = quote! { let slot_def = quote! {
_pyo3::ffi::PyType_Slot { #pyo3_path::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_call, slot: #pyo3_path::ffi::Py_tp_call,
pfunc: { pfunc: {
unsafe extern "C" fn trampoline( unsafe extern "C" fn trampoline(
slf: *mut _pyo3::ffi::PyObject, slf: *mut #pyo3_path::ffi::PyObject,
args: *mut _pyo3::ffi::PyObject, args: *mut #pyo3_path::ffi::PyObject,
kwargs: *mut _pyo3::ffi::PyObject, kwargs: *mut #pyo3_path::ffi::PyObject,
) -> *mut _pyo3::ffi::PyObject ) -> *mut #pyo3_path::ffi::PyObject
{ {
_pyo3::impl_::trampoline::ternaryfunc( #pyo3_path::impl_::trampoline::ternaryfunc(
slf, slf,
args, args,
kwargs, kwargs,
@ -398,7 +416,7 @@ fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>) -> Result<MethodAndSlot
) )
} }
trampoline trampoline
} as _pyo3::ffi::ternaryfunc as _ } as #pyo3_path::ffi::ternaryfunc as _
} }
}; };
Ok(MethodAndSlotDef { Ok(MethodAndSlotDef {
@ -407,7 +425,12 @@ fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec<'_>) -> Result<MethodAndSlot
}) })
} }
fn impl_traverse_slot(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodAndSlotDef> { fn impl_traverse_slot(
cls: &syn::Type,
spec: &FnSpec<'_>,
ctx: &Ctx,
) -> syn::Result<MethodAndSlotDef> {
let Ctx { pyo3_path } = ctx;
if let (Some(py_arg), _) = split_off_python_arg(&spec.signature.arguments) { 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`. \ return Err(syn::Error::new_spanned(py_arg.ty, "__traverse__ may not take `Python`. \
Usually, an implementation of `__traverse__` should do nothing but calls to `visit.call`. \ Usually, an implementation of `__traverse__` should do nothing but calls to `visit.call`. \
@ -419,17 +442,17 @@ fn impl_traverse_slot(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodA
let associated_method = quote! { let associated_method = quote! {
pub unsafe extern "C" fn __pymethod_traverse__( pub unsafe extern "C" fn __pymethod_traverse__(
slf: *mut _pyo3::ffi::PyObject, slf: *mut #pyo3_path::ffi::PyObject,
visit: _pyo3::ffi::visitproc, visit: #pyo3_path::ffi::visitproc,
arg: *mut ::std::os::raw::c_void, arg: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int { ) -> ::std::os::raw::c_int {
_pyo3::impl_::pymethods::_call_traverse::<#cls>(slf, #cls::#rust_fn_ident, visit, arg) #pyo3_path::impl_::pymethods::_call_traverse::<#cls>(slf, #cls::#rust_fn_ident, visit, arg)
} }
}; };
let slot_def = quote! { let slot_def = quote! {
_pyo3::ffi::PyType_Slot { #pyo3_path::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_traverse, slot: #pyo3_path::ffi::Py_tp_traverse,
pfunc: #cls::__pymethod_traverse__ as _pyo3::ffi::traverseproc as _ pfunc: #cls::__pymethod_traverse__ as #pyo3_path::ffi::traverseproc as _
} }
}; };
Ok(MethodAndSlotDef { Ok(MethodAndSlotDef {
@ -438,7 +461,12 @@ fn impl_traverse_slot(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodA
}) })
} }
fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodAndMethodDef> { fn impl_py_class_attribute(
cls: &syn::Type,
spec: &FnSpec<'_>,
ctx: &Ctx,
) -> syn::Result<MethodAndMethodDef> {
let Ctx { pyo3_path } = ctx;
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments); let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
ensure_spanned!( ensure_spanned!(
args.is_empty(), args.is_empty(),
@ -454,20 +482,20 @@ fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<Me
let wrapper_ident = format_ident!("__pymethod_{}__", name); let wrapper_ident = format_ident!("__pymethod_{}__", name);
let python_name = spec.null_terminated_python_name(); let python_name = spec.null_terminated_python_name();
let body = quotes::ok_wrap(fncall); let body = quotes::ok_wrap(fncall, ctx);
let associated_method = quote! { let associated_method = quote! {
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> { fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
let function = #cls::#name; // Shadow the method name to avoid #3017 let function = #cls::#name; // Shadow the method name to avoid #3017
_pyo3::impl_::wrap::map_result_into_py(py, #body) #pyo3_path::impl_::wrap::map_result_into_py(py, #body)
} }
}; };
let method_def = quote! { let method_def = quote! {
_pyo3::class::PyMethodDefType::ClassAttribute({ #pyo3_path::class::PyMethodDefType::ClassAttribute({
_pyo3::class::PyClassAttributeDef::new( #pyo3_path::class::PyClassAttributeDef::new(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyClassAttributeFactory(#cls::#wrapper_ident) #pyo3_path::impl_::pymethods::PyClassAttributeFactory(#cls::#wrapper_ident)
) )
}) })
}; };
@ -483,9 +511,10 @@ fn impl_call_setter(
spec: &FnSpec<'_>, spec: &FnSpec<'_>,
self_type: &SelfType, self_type: &SelfType,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments); let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
let slf = self_type.receiver(cls, ExtractErrorMode::Raise, holders); let slf = self_type.receiver(cls, ExtractErrorMode::Raise, holders, ctx);
if args.is_empty() { if args.is_empty() {
bail_spanned!(spec.name.span() => "setter function expected to have one argument"); bail_spanned!(spec.name.span() => "setter function expected to have one argument");
@ -510,7 +539,9 @@ fn impl_call_setter(
pub fn impl_py_setter_def( pub fn impl_py_setter_def(
cls: &syn::Type, cls: &syn::Type,
property_type: PropertyType<'_>, property_type: PropertyType<'_>,
ctx: &Ctx,
) -> Result<MethodAndMethodDef> { ) -> Result<MethodAndMethodDef> {
let Ctx { pyo3_path } = ctx;
let python_name = property_type.null_terminated_python_name()?; let python_name = property_type.null_terminated_python_name()?;
let doc = property_type.doc(); let doc = property_type.doc();
let mut holders = Vec::new(); let mut holders = Vec::new();
@ -522,7 +553,7 @@ pub fn impl_py_setter_def(
mutable: true, mutable: true,
span: Span::call_site(), span: Span::call_site(),
} }
.receiver(cls, ExtractErrorMode::Raise, &mut holders); .receiver(cls, ExtractErrorMode::Raise, &mut holders, ctx);
if let Some(ident) = &field.ident { if let Some(ident) = &field.ident {
// named struct field // named struct field
quote!({ #slf.#ident = _val; }) quote!({ #slf.#ident = _val; })
@ -534,7 +565,7 @@ pub fn impl_py_setter_def(
} }
PropertyType::Function { PropertyType::Function {
spec, self_type, .. spec, self_type, ..
} => impl_call_setter(cls, spec, self_type, &mut holders)?, } => impl_call_setter(cls, spec, self_type, &mut holders, ctx)?,
}; };
let wrapper_ident = match property_type { let wrapper_ident = match property_type {
@ -568,27 +599,27 @@ pub fn impl_py_setter_def(
let associated_method = quote! { let associated_method = quote! {
#cfg_attrs #cfg_attrs
unsafe fn #wrapper_ident( unsafe fn #wrapper_ident(
py: _pyo3::Python<'_>, py: #pyo3_path::Python<'_>,
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
_value: *mut _pyo3::ffi::PyObject, _value: *mut #pyo3_path::ffi::PyObject,
) -> _pyo3::PyResult<::std::os::raw::c_int> { ) -> #pyo3_path::PyResult<::std::os::raw::c_int> {
use ::std::convert::Into; use ::std::convert::Into;
let _value = _pyo3::impl_::pymethods::BoundRef::ref_from_ptr_or_opt(py, &_value) let _value = #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr_or_opt(py, &_value)
.ok_or_else(|| { .ok_or_else(|| {
_pyo3::exceptions::PyAttributeError::new_err("can't delete attribute") #pyo3_path::exceptions::PyAttributeError::new_err("can't delete attribute")
})?; })?;
let _val = _pyo3::FromPyObject::extract_bound(_value.into())?; let _val = #pyo3_path::FromPyObject::extract_bound(_value.into())?;
#( #holders )* #( #holders )*
_pyo3::callback::convert(py, #setter_impl) #pyo3_path::callback::convert(py, #setter_impl)
} }
}; };
let method_def = quote! { let method_def = quote! {
#cfg_attrs #cfg_attrs
_pyo3::class::PyMethodDefType::Setter( #pyo3_path::class::PyMethodDefType::Setter(
_pyo3::class::PySetterDef::new( #pyo3_path::class::PySetterDef::new(
#python_name, #python_name,
_pyo3::impl_::pymethods::PySetter(#cls::#wrapper_ident), #pyo3_path::impl_::pymethods::PySetter(#cls::#wrapper_ident),
#doc #doc
) )
) )
@ -605,9 +636,10 @@ fn impl_call_getter(
spec: &FnSpec<'_>, spec: &FnSpec<'_>,
self_type: &SelfType, self_type: &SelfType,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments); let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
let slf = self_type.receiver(cls, ExtractErrorMode::Raise, holders); let slf = self_type.receiver(cls, ExtractErrorMode::Raise, holders, ctx);
ensure_spanned!( ensure_spanned!(
args.is_empty(), args.is_empty(),
args[0].ty.span() => "getter function can only have one argument (of type pyo3::Python)" args[0].ty.span() => "getter function can only have one argument (of type pyo3::Python)"
@ -627,7 +659,9 @@ fn impl_call_getter(
pub fn impl_py_getter_def( pub fn impl_py_getter_def(
cls: &syn::Type, cls: &syn::Type,
property_type: PropertyType<'_>, property_type: PropertyType<'_>,
ctx: &Ctx,
) -> Result<MethodAndMethodDef> { ) -> Result<MethodAndMethodDef> {
let Ctx { pyo3_path } = ctx;
let python_name = property_type.null_terminated_python_name()?; let python_name = property_type.null_terminated_python_name()?;
let doc = property_type.doc(); let doc = property_type.doc();
@ -640,7 +674,7 @@ pub fn impl_py_getter_def(
mutable: false, mutable: false,
span: Span::call_site(), span: Span::call_site(),
} }
.receiver(cls, ExtractErrorMode::Raise, &mut holders); .receiver(cls, ExtractErrorMode::Raise, &mut holders, ctx);
let field_token = if let Some(ident) = &field.ident { let field_token = if let Some(ident) = &field.ident {
// named struct field // named struct field
ident.to_token_stream() ident.to_token_stream()
@ -648,17 +682,23 @@ pub fn impl_py_getter_def(
// tuple struct field // tuple struct field
syn::Index::from(field_index).to_token_stream() syn::Index::from(field_index).to_token_stream()
}; };
quotes::map_result_into_ptr(quotes::ok_wrap(quote! { quotes::map_result_into_ptr(
::std::clone::Clone::clone(&(#slf.#field_token)) quotes::ok_wrap(
})) quote! {
::std::clone::Clone::clone(&(#slf.#field_token))
},
ctx,
),
ctx,
)
} }
// Forward to `IntoPyCallbackOutput`, to handle `#[getter]`s returning results. // Forward to `IntoPyCallbackOutput`, to handle `#[getter]`s returning results.
PropertyType::Function { PropertyType::Function {
spec, self_type, .. spec, self_type, ..
} => { } => {
let call = impl_call_getter(cls, spec, self_type, &mut holders)?; let call = impl_call_getter(cls, spec, self_type, &mut holders, ctx)?;
quote! { quote! {
_pyo3::callback::convert(py, #call) #pyo3_path::callback::convert(py, #call)
} }
} }
}; };
@ -694,9 +734,9 @@ pub fn impl_py_getter_def(
let associated_method = quote! { let associated_method = quote! {
#cfg_attrs #cfg_attrs
unsafe fn #wrapper_ident( unsafe fn #wrapper_ident(
py: _pyo3::Python<'_>, py: #pyo3_path::Python<'_>,
_slf: *mut _pyo3::ffi::PyObject _slf: *mut #pyo3_path::ffi::PyObject
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> { ) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
#( #holders )* #( #holders )*
let result = #body; let result = #body;
result result
@ -705,10 +745,10 @@ pub fn impl_py_getter_def(
let method_def = quote! { let method_def = quote! {
#cfg_attrs #cfg_attrs
_pyo3::class::PyMethodDefType::Getter( #pyo3_path::class::PyMethodDefType::Getter(
_pyo3::class::PyGetterDef::new( #pyo3_path::class::PyGetterDef::new(
#python_name, #python_name,
_pyo3::impl_::pymethods::PyGetter(#cls::#wrapper_ident), #pyo3_path::impl_::pymethods::PyGetter(#cls::#wrapper_ident),
#doc #doc
) )
) )
@ -786,7 +826,7 @@ pub const __REPR__: SlotDef = SlotDef::new("Py_tp_repr", "reprfunc");
const __HASH__: SlotDef = SlotDef::new("Py_tp_hash", "hashfunc") const __HASH__: SlotDef = SlotDef::new("Py_tp_hash", "hashfunc")
.ret_ty(Ty::PyHashT) .ret_ty(Ty::PyHashT)
.return_conversion(TokenGenerator( .return_conversion(TokenGenerator(
|| quote! { _pyo3::callback::HashCallbackOutput }, |Ctx { pyo3_path }: &Ctx| quote! { #pyo3_path::callback::HashCallbackOutput },
)); ));
pub const __RICHCMP__: SlotDef = SlotDef::new("Py_tp_richcompare", "richcmpfunc") pub const __RICHCMP__: SlotDef = SlotDef::new("Py_tp_richcompare", "richcmpfunc")
.extract_error_mode(ExtractErrorMode::NotImplemented) .extract_error_mode(ExtractErrorMode::NotImplemented)
@ -796,14 +836,16 @@ const __GET__: SlotDef = SlotDef::new("Py_tp_descr_get", "descrgetfunc")
const __ITER__: SlotDef = SlotDef::new("Py_tp_iter", "getiterfunc"); const __ITER__: SlotDef = SlotDef::new("Py_tp_iter", "getiterfunc");
const __NEXT__: SlotDef = SlotDef::new("Py_tp_iternext", "iternextfunc") const __NEXT__: SlotDef = SlotDef::new("Py_tp_iternext", "iternextfunc")
.return_specialized_conversion( .return_specialized_conversion(
TokenGenerator(|| quote! { IterBaseKind, IterOptionKind, IterResultOptionKind }), TokenGenerator(|_| quote! { IterBaseKind, IterOptionKind, IterResultOptionKind }),
TokenGenerator(|| quote! { iter_tag }), TokenGenerator(|_| quote! { iter_tag }),
); );
const __AWAIT__: SlotDef = SlotDef::new("Py_am_await", "unaryfunc"); const __AWAIT__: SlotDef = SlotDef::new("Py_am_await", "unaryfunc");
const __AITER__: SlotDef = SlotDef::new("Py_am_aiter", "unaryfunc"); const __AITER__: SlotDef = SlotDef::new("Py_am_aiter", "unaryfunc");
const __ANEXT__: SlotDef = SlotDef::new("Py_am_anext", "unaryfunc").return_specialized_conversion( const __ANEXT__: SlotDef = SlotDef::new("Py_am_anext", "unaryfunc").return_specialized_conversion(
TokenGenerator(|| quote! { AsyncIterBaseKind, AsyncIterOptionKind, AsyncIterResultOptionKind }), TokenGenerator(
TokenGenerator(|| quote! { async_iter_tag }), |_| quote! { AsyncIterBaseKind, AsyncIterOptionKind, AsyncIterResultOptionKind },
),
TokenGenerator(|_| quote! { async_iter_tag }),
); );
const __LEN__: SlotDef = SlotDef::new("Py_mp_length", "lenfunc").ret_ty(Ty::PySsizeT); const __LEN__: SlotDef = SlotDef::new("Py_mp_length", "lenfunc").ret_ty(Ty::PySsizeT);
const __CONTAINS__: SlotDef = SlotDef::new("Py_sq_contains", "objobjproc") const __CONTAINS__: SlotDef = SlotDef::new("Py_sq_contains", "objobjproc")
@ -905,16 +947,17 @@ enum Ty {
} }
impl Ty { impl Ty {
fn ffi_type(self) -> TokenStream { fn ffi_type(self, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
match self { match self {
Ty::Object | Ty::MaybeNullObject => quote! { *mut _pyo3::ffi::PyObject }, Ty::Object | Ty::MaybeNullObject => quote! { *mut #pyo3_path::ffi::PyObject },
Ty::NonNullObject => quote! { ::std::ptr::NonNull<_pyo3::ffi::PyObject> }, Ty::NonNullObject => quote! { ::std::ptr::NonNull<#pyo3_path::ffi::PyObject> },
Ty::IPowModulo => quote! { _pyo3::impl_::pymethods::IPowModulo }, Ty::IPowModulo => quote! { #pyo3_path::impl_::pymethods::IPowModulo },
Ty::Int | Ty::CompareOp => quote! { ::std::os::raw::c_int }, Ty::Int | Ty::CompareOp => quote! { ::std::os::raw::c_int },
Ty::PyHashT => quote! { _pyo3::ffi::Py_hash_t }, Ty::PyHashT => quote! { #pyo3_path::ffi::Py_hash_t },
Ty::PySsizeT => quote! { _pyo3::ffi::Py_ssize_t }, Ty::PySsizeT => quote! { #pyo3_path::ffi::Py_ssize_t },
Ty::Void => quote! { () }, Ty::Void => quote! { () },
Ty::PyBuffer => quote! { *mut _pyo3::ffi::Py_buffer }, Ty::PyBuffer => quote! { *mut #pyo3_path::ffi::Py_buffer },
} }
} }
@ -924,14 +967,16 @@ impl Ty {
arg: &FnArg<'_>, arg: &FnArg<'_>,
extract_error_mode: ExtractErrorMode, extract_error_mode: ExtractErrorMode,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let name_str = arg.name.unraw().to_string(); let name_str = arg.name.unraw().to_string();
match self { match self {
Ty::Object => extract_object( Ty::Object => extract_object(
extract_error_mode, extract_error_mode,
holders, holders,
&name_str, &name_str,
quote! { #ident }, quote! { #ident },ctx
), ),
Ty::MaybeNullObject => extract_object( Ty::MaybeNullObject => extract_object(
extract_error_mode, extract_error_mode,
@ -939,36 +984,36 @@ impl Ty {
&name_str, &name_str,
quote! { quote! {
if #ident.is_null() { if #ident.is_null() {
_pyo3::ffi::Py_None() #pyo3_path::ffi::Py_None()
} else { } else {
#ident #ident
} }
}, },ctx
), ),
Ty::NonNullObject => extract_object( Ty::NonNullObject => extract_object(
extract_error_mode, extract_error_mode,
holders, holders,
&name_str, &name_str,
quote! { #ident.as_ptr() }, quote! { #ident.as_ptr() },ctx
), ),
Ty::IPowModulo => extract_object( Ty::IPowModulo => extract_object(
extract_error_mode, extract_error_mode,
holders, holders,
&name_str, &name_str,
quote! { #ident.as_ptr() }, quote! { #ident.as_ptr() },ctx
), ),
Ty::CompareOp => extract_error_mode.handle_error( Ty::CompareOp => extract_error_mode.handle_error(
quote! { quote! {
_pyo3::class::basic::CompareOp::from_raw(#ident) #pyo3_path::class::basic::CompareOp::from_raw(#ident)
.ok_or_else(|| _pyo3::exceptions::PyValueError::new_err("invalid comparison operator")) .ok_or_else(|| #pyo3_path::exceptions::PyValueError::new_err("invalid comparison operator"))
}, },ctx
), ),
Ty::PySsizeT => { Ty::PySsizeT => {
let ty = arg.ty; let ty = arg.ty;
extract_error_mode.handle_error( extract_error_mode.handle_error(
quote! { quote! {
::std::convert::TryInto::<#ty>::try_into(#ident).map_err(|e| _pyo3::exceptions::PyValueError::new_err(e.to_string())) ::std::convert::TryInto::<#ty>::try_into(#ident).map_err(|e| #pyo3_path::exceptions::PyValueError::new_err(e.to_string()))
}, },ctx
) )
} }
// Just pass other types through unmodified // Just pass other types through unmodified
@ -982,19 +1027,24 @@ fn extract_object(
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
name: &str, name: &str,
source_ptr: TokenStream, source_ptr: TokenStream,
ctx: &Ctx,
) -> TokenStream { ) -> TokenStream {
let Ctx { pyo3_path } = ctx;
let holder = syn::Ident::new(&format!("holder_{}", holders.len()), Span::call_site()); let holder = syn::Ident::new(&format!("holder_{}", holders.len()), Span::call_site());
holders.push(quote! { holders.push(quote! {
#[allow(clippy::let_unit_value)] #[allow(clippy::let_unit_value)]
let mut #holder = _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT; let mut #holder = #pyo3_path::impl_::extract_argument::FunctionArgumentHolder::INIT;
}); });
extract_error_mode.handle_error(quote! { extract_error_mode.handle_error(
_pyo3::impl_::extract_argument::extract_argument( quote! {
&_pyo3::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr), #pyo3_path::impl_::extract_argument::extract_argument(
&mut #holder, &#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr),
#name &mut #holder,
) #name
}) )
},
ctx,
)
} }
enum ReturnMode { enum ReturnMode {
@ -1004,21 +1054,29 @@ enum ReturnMode {
} }
impl ReturnMode { impl ReturnMode {
fn return_call_output(&self, call: TokenStream) -> TokenStream { fn return_call_output(&self, call: TokenStream, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
match self { match self {
ReturnMode::Conversion(conversion) => quote! { ReturnMode::Conversion(conversion) => {
let _result: _pyo3::PyResult<#conversion> = _pyo3::callback::convert(py, #call); let conversion = TokenGeneratorCtx(*conversion, ctx);
_pyo3::callback::convert(py, _result) quote! {
}, let _result: #pyo3_path::PyResult<#conversion> = #pyo3_path::callback::convert(py, #call);
ReturnMode::SpecializedConversion(traits, tag) => quote! { #pyo3_path::callback::convert(py, _result)
let _result = #call; }
use _pyo3::impl_::pymethods::{#traits}; }
(&_result).#tag().convert(py, _result) ReturnMode::SpecializedConversion(traits, tag) => {
}, let traits = TokenGeneratorCtx(*traits, ctx);
let tag = TokenGeneratorCtx(*tag, ctx);
quote! {
let _result = #call;
use #pyo3_path::impl_::pymethods::{#traits};
(&_result).#tag().convert(py, _result)
}
}
ReturnMode::ReturnSelf => quote! { ReturnMode::ReturnSelf => quote! {
let _result: _pyo3::PyResult<()> = _pyo3::callback::convert(py, #call); let _result: #pyo3_path::PyResult<()> = #pyo3_path::callback::convert(py, #call);
_result?; _result?;
_pyo3::ffi::Py_XINCREF(_raw_slf); #pyo3_path::ffi::Py_XINCREF(_raw_slf);
::std::result::Result::Ok(_raw_slf) ::std::result::Result::Ok(_raw_slf)
}, },
} }
@ -1094,7 +1152,9 @@ impl SlotDef {
cls: &syn::Type, cls: &syn::Type,
spec: &FnSpec<'_>, spec: &FnSpec<'_>,
method_name: &str, method_name: &str,
ctx: &Ctx,
) -> Result<MethodAndSlotDef> { ) -> Result<MethodAndSlotDef> {
let Ctx { pyo3_path } = ctx;
let SlotDef { let SlotDef {
slot, slot,
func_ty, func_ty,
@ -1110,12 +1170,12 @@ impl SlotDef {
spec.name.span() => format!("`{}` must be `unsafe fn`", method_name) spec.name.span() => format!("`{}` must be `unsafe fn`", method_name)
); );
} }
let arg_types: &Vec<_> = &arguments.iter().map(|arg| arg.ffi_type()).collect(); let arg_types: &Vec<_> = &arguments.iter().map(|arg| arg.ffi_type(ctx)).collect();
let arg_idents: &Vec<_> = &(0..arguments.len()) let arg_idents: &Vec<_> = &(0..arguments.len())
.map(|i| format_ident!("arg{}", i)) .map(|i| format_ident!("arg{}", i))
.collect(); .collect();
let wrapper_ident = format_ident!("__pymethod_{}__", method_name); let wrapper_ident = format_ident!("__pymethod_{}__", method_name);
let ret_ty = ret_ty.ffi_type(); let ret_ty = ret_ty.ffi_type(ctx);
let mut holders = Vec::new(); let mut holders = Vec::new();
let body = generate_method_body( let body = generate_method_body(
cls, cls,
@ -1124,14 +1184,15 @@ impl SlotDef {
*extract_error_mode, *extract_error_mode,
&mut holders, &mut holders,
return_mode.as_ref(), return_mode.as_ref(),
ctx,
)?; )?;
let name = spec.name; let name = spec.name;
let associated_method = quote! { let associated_method = quote! {
unsafe fn #wrapper_ident( unsafe fn #wrapper_ident(
py: _pyo3::Python<'_>, py: #pyo3_path::Python<'_>,
_raw_slf: *mut _pyo3::ffi::PyObject, _raw_slf: *mut #pyo3_path::ffi::PyObject,
#(#arg_idents: #arg_types),* #(#arg_idents: #arg_types),*
) -> _pyo3::PyResult<#ret_ty> { ) -> #pyo3_path::PyResult<#ret_ty> {
let function = #cls::#name; // Shadow the method name to avoid #3017 let function = #cls::#name; // Shadow the method name to avoid #3017
let _slf = _raw_slf; let _slf = _raw_slf;
#( #holders )* #( #holders )*
@ -1140,20 +1201,20 @@ impl SlotDef {
}; };
let slot_def = quote! {{ let slot_def = quote! {{
unsafe extern "C" fn trampoline( unsafe extern "C" fn trampoline(
_slf: *mut _pyo3::ffi::PyObject, _slf: *mut #pyo3_path::ffi::PyObject,
#(#arg_idents: #arg_types),* #(#arg_idents: #arg_types),*
) -> #ret_ty ) -> #ret_ty
{ {
_pyo3::impl_::trampoline:: #func_ty ( #pyo3_path::impl_::trampoline:: #func_ty (
_slf, _slf,
#(#arg_idents,)* #(#arg_idents,)*
#cls::#wrapper_ident #cls::#wrapper_ident
) )
} }
_pyo3::ffi::PyType_Slot { #pyo3_path::ffi::PyType_Slot {
slot: _pyo3::ffi::#slot, slot: #pyo3_path::ffi::#slot,
pfunc: trampoline as _pyo3::ffi::#func_ty as _ pfunc: trampoline as #pyo3_path::ffi::#func_ty as _
} }
}}; }};
Ok(MethodAndSlotDef { Ok(MethodAndSlotDef {
@ -1170,15 +1231,19 @@ fn generate_method_body(
extract_error_mode: ExtractErrorMode, extract_error_mode: ExtractErrorMode,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
return_mode: Option<&ReturnMode>, return_mode: Option<&ReturnMode>,
ctx: &Ctx,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let self_arg = spec.tp.self_arg(Some(cls), extract_error_mode, holders); let Ctx { pyo3_path } = ctx;
let self_arg = spec
.tp
.self_arg(Some(cls), extract_error_mode, holders, ctx);
let rust_name = spec.name; let rust_name = spec.name;
let args = extract_proto_arguments(spec, arguments, extract_error_mode, holders)?; let args = extract_proto_arguments(spec, arguments, extract_error_mode, holders, ctx)?;
let call = quote! { #cls::#rust_name(#self_arg #(#args),*) }; let call = quote! { #cls::#rust_name(#self_arg #(#args),*) };
Ok(if let Some(return_mode) = return_mode { Ok(if let Some(return_mode) = return_mode {
return_mode.return_call_output(call) return_mode.return_call_output(call, ctx)
} else { } else {
quote! { _pyo3::callback::convert(py, #call) } quote! { #pyo3_path::callback::convert(py, #call) }
}) })
} }
@ -1209,7 +1274,13 @@ impl SlotFragmentDef {
self self
} }
fn generate_pyproto_fragment(&self, cls: &syn::Type, spec: &FnSpec<'_>) -> Result<TokenStream> { fn generate_pyproto_fragment(
&self,
cls: &syn::Type,
spec: &FnSpec<'_>,
ctx: &Ctx,
) -> Result<TokenStream> {
let Ctx { pyo3_path } = ctx;
let SlotFragmentDef { let SlotFragmentDef {
fragment, fragment,
arguments, arguments,
@ -1219,7 +1290,7 @@ impl SlotFragmentDef {
let fragment_trait = format_ident!("PyClass{}SlotFragment", fragment); let fragment_trait = format_ident!("PyClass{}SlotFragment", fragment);
let method = syn::Ident::new(fragment, Span::call_site()); let method = syn::Ident::new(fragment, Span::call_site());
let wrapper_ident = format_ident!("__pymethod_{}__", fragment); let wrapper_ident = format_ident!("__pymethod_{}__", fragment);
let arg_types: &Vec<_> = &arguments.iter().map(|arg| arg.ffi_type()).collect(); let arg_types: &Vec<_> = &arguments.iter().map(|arg| arg.ffi_type(ctx)).collect();
let arg_idents: &Vec<_> = &(0..arguments.len()) let arg_idents: &Vec<_> = &(0..arguments.len())
.map(|i| format_ident!("arg{}", i)) .map(|i| format_ident!("arg{}", i))
.collect(); .collect();
@ -1231,30 +1302,31 @@ impl SlotFragmentDef {
*extract_error_mode, *extract_error_mode,
&mut holders, &mut holders,
None, None,
ctx,
)?; )?;
let ret_ty = ret_ty.ffi_type(); let ret_ty = ret_ty.ffi_type(ctx);
Ok(quote! { Ok(quote! {
impl #cls { impl #cls {
unsafe fn #wrapper_ident( unsafe fn #wrapper_ident(
py: _pyo3::Python, py: #pyo3_path::Python,
_raw_slf: *mut _pyo3::ffi::PyObject, _raw_slf: *mut #pyo3_path::ffi::PyObject,
#(#arg_idents: #arg_types),* #(#arg_idents: #arg_types),*
) -> _pyo3::PyResult<#ret_ty> { ) -> #pyo3_path::PyResult<#ret_ty> {
let _slf = _raw_slf; let _slf = _raw_slf;
#( #holders )* #( #holders )*
#body #body
} }
} }
impl _pyo3::impl_::pyclass::#fragment_trait<#cls> for _pyo3::impl_::pyclass::PyClassImplCollector<#cls> { impl #pyo3_path::impl_::pyclass::#fragment_trait<#cls> for #pyo3_path::impl_::pyclass::PyClassImplCollector<#cls> {
#[inline] #[inline]
unsafe fn #method( unsafe fn #method(
self, self,
py: _pyo3::Python, py: #pyo3_path::Python,
_raw_slf: *mut _pyo3::ffi::PyObject, _raw_slf: *mut #pyo3_path::ffi::PyObject,
#(#arg_idents: #arg_types),* #(#arg_idents: #arg_types),*
) -> _pyo3::PyResult<#ret_ty> { ) -> #pyo3_path::PyResult<#ret_ty> {
#cls::#wrapper_ident(py, _raw_slf, #(#arg_idents),*) #cls::#wrapper_ident(py, _raw_slf, #(#arg_idents),*)
} }
} }
@ -1341,6 +1413,7 @@ fn extract_proto_arguments(
proto_args: &[Ty], proto_args: &[Ty],
extract_error_mode: ExtractErrorMode, extract_error_mode: ExtractErrorMode,
holders: &mut Vec<TokenStream>, holders: &mut Vec<TokenStream>,
ctx: &Ctx,
) -> Result<Vec<TokenStream>> { ) -> Result<Vec<TokenStream>> {
let mut args = Vec::with_capacity(spec.signature.arguments.len()); let mut args = Vec::with_capacity(spec.signature.arguments.len());
let mut non_python_args = 0; let mut non_python_args = 0;
@ -1352,7 +1425,7 @@ fn extract_proto_arguments(
let ident = syn::Ident::new(&format!("arg{}", non_python_args), Span::call_site()); let ident = syn::Ident::new(&format!("arg{}", non_python_args), Span::call_site());
let conversions = proto_args.get(non_python_args) let conversions = proto_args.get(non_python_args)
.ok_or_else(|| err_spanned!(arg.ty.span() => format!("Expected at most {} non-python arguments", proto_args.len())))? .ok_or_else(|| err_spanned!(arg.ty.span() => format!("Expected at most {} non-python arguments", proto_args.len())))?
.extract(&ident, arg, extract_error_mode, holders); .extract(&ident, arg, extract_error_mode, holders, ctx);
non_python_args += 1; non_python_args += 1;
args.push(conversions); args.push(conversions);
} }
@ -1372,10 +1445,14 @@ impl ToTokens for StaticIdent {
} }
} }
struct TokenGenerator(fn() -> TokenStream); #[derive(Clone, Copy)]
struct TokenGenerator(fn(&Ctx) -> TokenStream);
impl ToTokens for TokenGenerator { struct TokenGeneratorCtx<'ctx>(TokenGenerator, &'ctx Ctx);
impl ToTokens for TokenGeneratorCtx<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
self.0().to_tokens(tokens) let Self(TokenGenerator(gen), ctx) = self;
(gen)(ctx).to_tokens(tokens)
} }
} }

View File

@ -1,21 +1,25 @@
use crate::utils::Ctx;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
pub(crate) fn some_wrap(obj: TokenStream) -> TokenStream { pub(crate) fn some_wrap(obj: TokenStream, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
quote! { quote! {
_pyo3::impl_::wrap::SomeWrap::wrap(#obj) #pyo3_path::impl_::wrap::SomeWrap::wrap(#obj)
} }
} }
pub(crate) fn ok_wrap(obj: TokenStream) -> TokenStream { pub(crate) fn ok_wrap(obj: TokenStream, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
quote! { quote! {
_pyo3::impl_::wrap::OkWrap::wrap(#obj) #pyo3_path::impl_::wrap::OkWrap::wrap(#obj)
.map_err(::core::convert::Into::<_pyo3::PyErr>::into) .map_err(::core::convert::Into::<#pyo3_path::PyErr>::into)
} }
} }
pub(crate) fn map_result_into_ptr(result: TokenStream) -> TokenStream { pub(crate) fn map_result_into_ptr(result: TokenStream, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path } = ctx;
quote! { quote! {
_pyo3::impl_::wrap::map_result_into_ptr(py, #result) #pyo3_path::impl_::wrap::map_result_into_ptr(py, #result)
} }
} }

View File

@ -144,11 +144,41 @@ pub fn unwrap_ty_group(mut ty: &syn::Type) -> &syn::Type {
ty ty
} }
/// Extract the path to the pyo3 crate, or use the default (`::pyo3`). pub struct Ctx {
pub(crate) fn get_pyo3_crate(attr: &Option<CrateAttribute>) -> syn::Path { pub pyo3_path: PyO3CratePath,
match attr { }
Some(attr) => attr.value.0.clone(),
None => syn::parse_str("::pyo3").unwrap(), impl Ctx {
pub(crate) fn new(attr: &Option<CrateAttribute>) -> Self {
let pyo3_path = match attr {
Some(attr) => PyO3CratePath::Given(attr.value.0.clone()),
None => PyO3CratePath::Default,
};
Self { pyo3_path }
}
}
pub enum PyO3CratePath {
Given(syn::Path),
Default,
}
impl PyO3CratePath {
pub fn to_tokens_spanned(&self, span: Span) -> TokenStream {
match self {
Self::Given(path) => quote::quote_spanned! { span => #path },
Self::Default => quote::quote_spanned! { span => ::pyo3 },
}
}
}
impl quote::ToTokens for PyO3CratePath {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Self::Given(path) => path.to_tokens(tokens),
Self::Default => quote::quote! { ::pyo3 }.to_tokens(tokens),
}
} }
} }

View File

@ -31,4 +31,4 @@ error[E0592]: duplicate definitions with name `__pymethod___richcmp____`
| duplicate definitions for `__pymethod___richcmp____` | duplicate definitions for `__pymethod___richcmp____`
| other definition for `__pymethod___richcmp____` | other definition for `__pymethod___richcmp____`
| |
= note: this error originates in the macro `_pyo3::impl_::pyclass::generate_pyclass_richcompare_slot` which comes from the expansion of the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `::pyo3::impl_::pyclass::generate_pyclass_richcompare_slot` which comes from the expansion of the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)