Merge pull request #2022 from PyO3/pyo3_path

Hygiene: offer a way to set path to pyo3 crate
This commit is contained in:
David Hewitt 2021-12-09 20:27:48 +00:00 committed by GitHub
commit 469d72a001
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 649 additions and 481 deletions

View file

@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `Py::setattr` method. [#2009](https://github.com/PyO3/pyo3/pull/2009)
- Add `PyCapsule`, exposing the [Capsule API](https://docs.python.org/3/c-api/capsule.html#capsules). [#1980](https://github.com/PyO3/pyo3/pull/1980)
- All PyO3 proc-macros except the deprecated `#[pyproto]` now accept a supplemental attribute `#[pyo3(crate = "some::path")]` that specifies
where to find the `pyo3` crate, in case it has been renamed or is re-exported and not found at the crate root. [#2022](https://github.com/PyO3/pyo3/pull/2022)
### Changed

View file

@ -139,3 +139,23 @@ a: <builtins.Inner object at 0x0000020044FCC670>
b: <builtins.Inner object at 0x0000020044FCC670>
```
The downside to this approach is that any Rust code working on the `Outer` struct now has to acquire the GIL to do anything with its field.
## I want to use the `pyo3` crate re-exported from from dependency but the proc-macros fail!
All PyO3 proc-macros (`#[pyclass]`, `#[pyfunction]`, `#[derive(FromPyObject)]`
and so on) expect the `pyo3` crate to be available under that name in your crate
root, which is the normal situation when `pyo3` is a direct dependency of your
crate.
However, when the dependency is renamed, or your crate only indirectly depends
on `pyo3`, you need to let the macro code know where to find the crate. This is
done with the `crate` attribute:
```rust
# use pyo3::prelude::*;
# pub extern crate pyo3;
# mod reexported { pub use ::pyo3; }
#[pyclass]
#[pyo3(crate = "reexported::pyo3")]
struct MyClass;
```

View file

@ -2,7 +2,7 @@ use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
token::Comma,
Attribute, ExprPath, Ident, LitStr, Result, Token,
Attribute, ExprPath, Ident, LitStr, Path, Result, Token,
};
pub mod kw {
@ -43,6 +43,19 @@ impl Parse for NameAttribute {
}
}
/// For specifying the path to the pyo3 crate.
#[derive(Clone, Debug, PartialEq)]
pub struct CrateAttribute(pub Path);
impl Parse for CrateAttribute {
fn parse(input: ParseStream) -> Result<Self> {
let _: Token![crate] = input.parse()?;
let _: Token![=] = input.parse()?;
let string_literal: LitStr = input.parse()?;
string_literal.parse().map(CrateAttribute)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TextSignatureAttribute {
pub kw: kw::text_signature,

View file

@ -33,7 +33,7 @@ impl ToTokens for Deprecations {
let ident = deprecation.ident(*span);
quote_spanned!(
*span =>
let _ = ::pyo3::impl_::deprecations::#ident;
let _ = _pyo3::impl_::deprecations::#ident;
)
.to_tokens(tokens)
}

View file

@ -1,4 +1,7 @@
use crate::attributes::{self, get_pyo3_options, FromPyWithAttribute};
use crate::{
attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute},
utils::get_pyo3_crate,
};
use proc_macro2::TokenStream;
use quote::quote;
use syn::{
@ -55,14 +58,14 @@ impl<'a> Enum<'a> {
for (i, var) in self.variants.iter().enumerate() {
let struct_derive = var.build();
let ext = quote!(
let maybe_ret = || -> ::pyo3::PyResult<Self> {
let maybe_ret = || -> _pyo3::PyResult<Self> {
#struct_derive
}();
match maybe_ret {
ok @ ::std::result::Result::Ok(_) => return ok,
::std::result::Result::Err(err) => {
let py = ::pyo3::PyNativeType::py(obj);
let py = _pyo3::PyNativeType::py(obj);
err_reasons.push_str(&::std::format!("{}\n", err.value(py).str()?));
}
}
@ -82,7 +85,7 @@ impl<'a> Enum<'a> {
#ty_name,
#error_names,
&err_reasons);
::std::result::Result::Err(::pyo3::exceptions::PyTypeError::new_err(err_msg))
::std::result::Result::Err(_pyo3::exceptions::PyTypeError::new_err(err_msg))
)
}
}
@ -207,8 +210,8 @@ impl<'a> Container<'a> {
);
quote!(
::std::result::Result::Ok(#self_ty{#ident: obj.extract().map_err(|inner| {
let py = ::pyo3::PyNativeType::py(obj);
let new_err = ::pyo3::exceptions::PyTypeError::new_err(#error_msg);
let py = _pyo3::PyNativeType::py(obj);
let new_err = _pyo3::exceptions::PyTypeError::new_err(#error_msg);
new_err.set_cause(py, ::std::option::Option::Some(inner));
new_err
})?})
@ -222,11 +225,11 @@ impl<'a> Container<'a> {
};
quote!(
::std::result::Result::Ok(#self_ty(obj.extract().map_err(|err| {
let py = ::pyo3::PyNativeType::py(obj);
let py = _pyo3::PyNativeType::py(obj);
let err_msg = ::std::format!("{}: {}",
#error_msg,
err.value(py).str().unwrap());
::pyo3::exceptions::PyTypeError::new_err(err_msg)
_pyo3::exceptions::PyTypeError::new_err(err_msg)
})?))
)
}
@ -238,9 +241,9 @@ impl<'a> Container<'a> {
for i in 0..len {
let error_msg = format!("failed to extract field {}.{}", quote!(#self_ty), i);
fields.push(quote!(
s.get_item(#i).and_then(::pyo3::types::PyAny::extract).map_err(|inner| {
let py = ::pyo3::PyNativeType::py(obj);
let new_err = ::pyo3::exceptions::PyTypeError::new_err(#error_msg);
s.get_item(#i).and_then(_pyo3::types::PyAny::extract).map_err(|inner| {
let py = _pyo3::PyNativeType::py(obj);
let new_err = _pyo3::exceptions::PyTypeError::new_err(#error_msg);
new_err.set_cause(py, ::std::option::Option::Some(inner));
new_err
})?));
@ -255,9 +258,9 @@ impl<'a> Container<'a> {
quote!("")
};
quote!(
let s = <::pyo3::types::PyTuple as ::pyo3::conversion::PyTryFrom>::try_from(obj)?;
let s = <_pyo3::types::PyTuple as _pyo3::conversion::PyTryFrom>::try_from(obj)?;
if s.len() != #len {
return ::std::result::Result::Err(::pyo3::exceptions::PyValueError::new_err(#msg))
return ::std::result::Result::Err(_pyo3::exceptions::PyValueError::new_err(#msg))
}
::std::result::Result::Ok(#self_ty(#fields))
)
@ -279,15 +282,15 @@ impl<'a> Container<'a> {
let extractor = match &attrs.from_py_with {
None => quote!(
#get_field.extract().map_err(|inner| {
let py = ::pyo3::PyNativeType::py(obj);
let new_err = ::pyo3::exceptions::PyTypeError::new_err(#conversion_error_msg);
let py = _pyo3::PyNativeType::py(obj);
let new_err = _pyo3::exceptions::PyTypeError::new_err(#conversion_error_msg);
new_err.set_cause(py, ::std::option::Option::Some(inner));
new_err
})?),
Some(FromPyWithAttribute(expr_path)) => quote! (
#expr_path(#get_field).map_err(|inner| {
let py = ::pyo3::PyNativeType::py(obj);
let new_err = ::pyo3::exceptions::PyTypeError::new_err(#conversion_error_msg);
let py = _pyo3::PyNativeType::py(obj);
let new_err = _pyo3::exceptions::PyTypeError::new_err(#conversion_error_msg);
new_err.set_cause(py, ::std::option::Option::Some(inner));
new_err
})?
@ -300,20 +303,25 @@ impl<'a> Container<'a> {
}
}
#[derive(Default)]
struct ContainerOptions {
/// Treat the Container as a Wrapper, directly extract its fields from the input object.
transparent: bool,
/// Change the name of an enum variant in the generated error message.
annotation: Option<syn::LitStr>,
/// Change the path for the pyo3 crate
krate: Option<CrateAttribute>,
}
/// Attributes for deriving FromPyObject scoped on containers.
#[derive(Clone, Debug, PartialEq)]
#[derive(Debug)]
enum ContainerPyO3Attribute {
/// Treat the Container as a Wrapper, directly extract its fields from the input object.
Transparent(attributes::kw::transparent),
/// Change the name of an enum variant in the generated error message.
ErrorAnnotation(LitStr),
/// Change the path for the pyo3 crate
Crate(CrateAttribute),
}
impl Parse for ContainerPyO3Attribute {
@ -326,6 +334,8 @@ impl Parse for ContainerPyO3Attribute {
let _: attributes::kw::annotation = input.parse()?;
let _: Token![=] = input.parse()?;
input.parse().map(ContainerPyO3Attribute::ErrorAnnotation)
} else if lookahead.peek(Token![crate]) {
input.parse().map(ContainerPyO3Attribute::Crate)
} else {
Err(lookahead.error())
}
@ -334,10 +344,8 @@ impl Parse for ContainerPyO3Attribute {
impl ContainerOptions {
fn from_attrs(attrs: &[Attribute]) -> Result<Self> {
let mut options = ContainerOptions {
transparent: false,
annotation: None,
};
let mut options = ContainerOptions::default();
for attr in attrs {
if let Some(pyo3_attrs) = get_pyo3_options(attr)? {
for pyo3_attr in pyo3_attrs {
@ -356,6 +364,13 @@ impl ContainerOptions {
);
options.annotation = Some(lit_str);
}
ContainerPyO3Attribute::Crate(path) => {
ensure_spanned!(
options.krate.is_none(),
path.0.span() => "`crate` may only be provided once"
);
options.krate = Some(path);
}
}
}
}
@ -499,13 +514,18 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
.predicates
.push(parse_quote!(#gen_ident: FromPyObject<#lt_param>))
}
let options = ContainerOptions::from_attrs(&tokens.attrs)?;
let krate = get_pyo3_crate(&options.krate);
let derives = match &tokens.data {
syn::Data::Enum(en) => {
if options.transparent || options.annotation.is_some() {
bail_spanned!(tokens.span() => "`transparent` or `annotation` is not supported \
at top level for enums");
}
let en = Enum::new(en, &tokens.ident)?;
en.build()
}
syn::Data::Struct(st) => {
let options = ContainerOptions::from_attrs(&tokens.attrs)?;
if let Some(lit_str) = &options.annotation {
bail_spanned!(lit_str.span() => "`annotation` is unsupported for structs");
}
@ -520,11 +540,15 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
let ident = &tokens.ident;
Ok(quote!(
#[automatically_derived]
impl#trait_generics ::pyo3::FromPyObject<#lt_param> for #ident#generics #where_clause {
fn extract(obj: &#lt_param ::pyo3::PyAny) -> ::pyo3::PyResult<Self> {
#derives
const _: () = {
use #krate as _pyo3;
#[automatically_derived]
impl#trait_generics _pyo3::FromPyObject<#lt_param> for #ident#generics #where_clause {
fn extract(obj: &#lt_param _pyo3::PyAny) -> _pyo3::PyResult<Self> {
#derives
}
}
}
};
))
}

View file

@ -5,7 +5,7 @@ use crate::deprecations::Deprecation;
use crate::params::{accept_args_kwargs, impl_arg_params};
use crate::pyfunction::PyFunctionOptions;
use crate::pyfunction::{PyFunctionArgPyO3Attributes, PyFunctionSignature};
use crate::utils::{self, PythonDoc};
use crate::utils::{self, get_pyo3_crate, PythonDoc};
use crate::{deprecations::Deprecations, pyfunction::Argument};
use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
@ -106,12 +106,12 @@ impl FnType {
}
FnType::FnClass => {
quote! {
let _slf = ::pyo3::types::PyType::from_type_ptr(_py, _slf as *mut ::pyo3::ffi::PyTypeObject);
let _slf = _pyo3::types::PyType::from_type_ptr(_py, _slf as *mut _pyo3::ffi::PyTypeObject);
}
}
FnType::FnModule => {
quote! {
let _slf = _py.from_borrowed_ptr::<::pyo3::types::PyModule>(_slf);
let _slf = _py.from_borrowed_ptr::<_pyo3::types::PyModule>(_slf);
}
}
}
@ -141,13 +141,13 @@ impl SelfType {
pub fn receiver(&self, cls: &syn::Type, error_mode: ExtractErrorMode) -> TokenStream {
let cell = match error_mode {
ExtractErrorMode::Raise => {
quote! { _py.from_borrowed_ptr::<::pyo3::PyAny>(_slf).downcast::<::pyo3::PyCell<#cls>>()? }
quote! { _py.from_borrowed_ptr::<_pyo3::PyAny>(_slf).downcast::<_pyo3::PyCell<#cls>>()? }
}
ExtractErrorMode::NotImplemented => {
quote! {
match _py.from_borrowed_ptr::<::pyo3::PyAny>(_slf).downcast::<::pyo3::PyCell<#cls>>() {
match _py.from_borrowed_ptr::<_pyo3::PyAny>(_slf).downcast::<_pyo3::PyCell<#cls>>() {
::std::result::Result::Ok(cell) => cell,
::std::result::Result::Err(_) => return ::pyo3::callback::convert(_py, _py.NotImplemented()),
::std::result::Result::Err(_) => return _pyo3::callback::convert(_py, _py.NotImplemented()),
}
}
}
@ -228,6 +228,7 @@ pub struct FnSpec<'a> {
pub deprecations: Deprecations,
pub convention: CallingConvention,
pub text_signature: Option<TextSignatureAttribute>,
pub krate: syn::Path,
}
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
@ -254,12 +255,14 @@ pub fn parse_method_receiver(arg: &syn::FnArg) -> Result<SelfType> {
impl<'a> FnSpec<'a> {
/// Parser function signature and function attributes
pub fn parse(
// Signature is mutable to remove the `Python` argument.
sig: &'a mut syn::Signature,
meth_attrs: &mut Vec<syn::Attribute>,
options: PyFunctionOptions,
) -> Result<FnSpec<'a>> {
let PyFunctionOptions {
text_signature,
krate,
name,
mut deprecations,
..
@ -278,6 +281,7 @@ impl<'a> FnSpec<'a> {
let name = &sig.ident;
let ty = get_return_info(&sig.output);
let python_name = python_name.as_ref().unwrap_or(name).unraw();
let krate = get_pyo3_crate(&krate);
let doc = utils::get_doc(
meth_attrs,
@ -311,6 +315,7 @@ impl<'a> FnSpec<'a> {
doc,
deprecations,
text_signature,
krate,
})
}
@ -471,17 +476,19 @@ impl<'a> FnSpec<'a> {
quote!(#func_name)
};
let rust_call =
quote! { ::pyo3::callback::convert(#py, #rust_name(#self_arg #(#arg_names),*)) };
quote! { _pyo3::callback::convert(#py, #rust_name(#self_arg #(#arg_names),*)) };
let krate = &self.krate;
Ok(match self.convention {
CallingConvention::Noargs => {
quote! {
unsafe extern "C" fn #ident (
_slf: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
) -> *mut ::pyo3::ffi::PyObject
_slf: *mut #krate::ffi::PyObject,
_args: *mut #krate::ffi::PyObject,
) -> *mut #krate::ffi::PyObject
{
use #krate as _pyo3;
#deprecations
::pyo3::callback::handle_panic(|#py| {
_pyo3::callback::handle_panic(|#py| {
#self_conversion
#rust_call
})
@ -492,17 +499,18 @@ impl<'a> FnSpec<'a> {
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, true)?;
quote! {
unsafe extern "C" fn #ident (
_slf: *mut ::pyo3::ffi::PyObject,
_args: *const *mut ::pyo3::ffi::PyObject,
_nargs: ::pyo3::ffi::Py_ssize_t,
_kwnames: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
_slf: *mut #krate::ffi::PyObject,
_args: *const *mut #krate::ffi::PyObject,
_nargs: #krate::ffi::Py_ssize_t,
_kwnames: *mut #krate::ffi::PyObject) -> *mut #krate::ffi::PyObject
{
use #krate as _pyo3;
#deprecations
::pyo3::callback::handle_panic(|#py| {
_pyo3::callback::handle_panic(|#py| {
#self_conversion
let _kwnames: ::std::option::Option<&::pyo3::types::PyTuple> = #py.from_borrowed_ptr_or_opt(_kwnames);
let _kwnames: ::std::option::Option<&_pyo3::types::PyTuple> = #py.from_borrowed_ptr_or_opt(_kwnames);
// Safety: &PyAny has the same memory layout as `*mut ffi::PyObject`
let _args = _args as *const &::pyo3::PyAny;
let _args = _args as *const &_pyo3::PyAny;
let _kwargs = if let ::std::option::Option::Some(kwnames) = _kwnames {
::std::slice::from_raw_parts(_args.offset(_nargs), kwnames.len())
} else {
@ -519,15 +527,16 @@ impl<'a> FnSpec<'a> {
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?;
quote! {
unsafe extern "C" fn #ident (
_slf: *mut ::pyo3::ffi::PyObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
_slf: *mut #krate::ffi::PyObject,
_args: *mut #krate::ffi::PyObject,
_kwargs: *mut #krate::ffi::PyObject) -> *mut #krate::ffi::PyObject
{
use #krate as _pyo3;
#deprecations
::pyo3::callback::handle_panic(|#py| {
_pyo3::callback::handle_panic(|#py| {
#self_conversion
let _args = #py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args);
let _kwargs: ::std::option::Option<&::pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
let _args = #py.from_borrowed_ptr::<_pyo3::types::PyTuple>(_args);
let _kwargs: ::std::option::Option<&_pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
#arg_convert_and_rust_call
})
@ -539,20 +548,21 @@ impl<'a> FnSpec<'a> {
let arg_convert_and_rust_call = impl_arg_params(self, cls, rust_call, &py, false)?;
quote! {
unsafe extern "C" fn #ident (
subtype: *mut ::pyo3::ffi::PyTypeObject,
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
subtype: *mut #krate::ffi::PyTypeObject,
_args: *mut #krate::ffi::PyObject,
_kwargs: *mut #krate::ffi::PyObject) -> *mut #krate::ffi::PyObject
{
use #krate as _pyo3;
#deprecations
use ::pyo3::callback::IntoPyCallbackOutput;
::pyo3::callback::handle_panic(|#py| {
let _args = #py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args);
let _kwargs: ::std::option::Option<&::pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
use _pyo3::callback::IntoPyCallbackOutput;
_pyo3::callback::handle_panic(|#py| {
let _args = #py.from_borrowed_ptr::<_pyo3::types::PyTuple>(_args);
let _kwargs: ::std::option::Option<&_pyo3::types::PyDict> = #py.from_borrowed_ptr_or_opt(_kwargs);
let result = #arg_convert_and_rust_call;
let initializer: ::pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
let cell = initializer.create_cell_from_subtype(#py, subtype)?;
::std::result::Result::Ok(cell as *mut ::pyo3::ffi::PyObject)
::std::result::Result::Ok(cell as *mut _pyo3::ffi::PyObject)
})
}
}
@ -567,23 +577,23 @@ impl<'a> FnSpec<'a> {
let doc = &self.doc;
match self.convention {
CallingConvention::Noargs => quote! {
::pyo3::class::methods::PyMethodDef::noargs(
_pyo3::class::methods::PyMethodDef::noargs(
#python_name,
::pyo3::class::methods::PyCFunction(#wrapper),
_pyo3::class::methods::PyCFunction(#wrapper),
#doc,
)
},
CallingConvention::Fastcall => quote! {
::pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords(
_pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords(
#python_name,
::pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper),
_pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper),
#doc,
)
},
CallingConvention::Varargs => quote! {
::pyo3::class::methods::PyMethodDef::cfunction_with_keywords(
_pyo3::class::methods::PyMethodDef::cfunction_with_keywords(
#python_name,
::pyo3::class::methods::PyCFunctionWithKeywords(#wrapper),
_pyo3::class::methods::PyCFunctionWithKeywords(#wrapper),
#doc,
)
},

View file

@ -2,9 +2,11 @@
//! Code generation for the function that initializes a python module and adds classes and function.
use crate::{
attributes::{self, is_attribute_ident, take_attributes, take_pyo3_options, NameAttribute},
attributes::{
self, is_attribute_ident, take_attributes, take_pyo3_options, CrateAttribute, NameAttribute,
},
pyfunction::{impl_wrap_pyfunction, PyFunctionOptions},
utils::PythonDoc,
utils::{get_pyo3_crate, PythonDoc},
};
use proc_macro2::{Span, TokenStream};
use quote::quote;
@ -16,17 +18,20 @@ use syn::{
Ident, Path, Result,
};
#[derive(Default)]
pub struct PyModuleOptions {
krate: Option<CrateAttribute>,
name: Option<syn::Ident>,
}
impl PyModuleOptions {
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> Result<Self> {
let mut options: PyModuleOptions = PyModuleOptions { name: None };
let mut options: PyModuleOptions = Default::default();
for option in take_pyo3_options(attrs)? {
match option {
PyModulePyO3Option::Name(name) => options.set_name(name.0)?,
PyModulePyO3Option::Crate(path) => options.set_crate(path)?,
}
}
@ -42,12 +47,23 @@ impl PyModuleOptions {
self.name = Some(name);
Ok(())
}
fn set_crate(&mut self, path: CrateAttribute) -> Result<()> {
ensure_spanned!(
self.krate.is_none(),
path.0.span() => "`crate` may only be specified once"
);
self.krate = Some(path);
Ok(())
}
}
/// Generates the function that is called by the python interpreter to initialize the native
/// module
pub fn py_init(fnname: &Ident, options: PyModuleOptions, doc: PythonDoc) -> TokenStream {
let name = options.name.unwrap_or_else(|| fnname.unraw());
let krate = get_pyo3_crate(&options.krate);
let cb_name = Ident::new(&format!("PyInit_{}", name), Span::call_site());
quote! {
@ -55,13 +71,14 @@ pub fn py_init(fnname: &Ident, options: PyModuleOptions, doc: PythonDoc) -> Toke
#[allow(non_snake_case)]
/// This autogenerated function is called by the python interpreter when importing
/// the module.
pub unsafe extern "C" fn #cb_name() -> *mut ::pyo3::ffi::PyObject {
use ::pyo3::derive_utils::ModuleDef;
pub unsafe extern "C" fn #cb_name() -> *mut #krate::ffi::PyObject {
use #krate as _pyo3;
use _pyo3::derive_utils::ModuleDef;
static NAME: &str = concat!(stringify!(#name), "\0");
static DOC: &str = #doc;
static MODULE_DEF: ModuleDef = unsafe { ModuleDef::new(NAME, DOC) };
::pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(_py, #fnname) })
_pyo3::callback::handle_panic(|_py| { MODULE_DEF.make_module(_py, #fnname) })
}
}
}
@ -143,6 +160,7 @@ fn get_pyfn_attr(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Option<PyFnArgs
}
enum PyModulePyO3Option {
Crate(CrateAttribute),
Name(NameAttribute),
}
@ -151,6 +169,8 @@ impl Parse for PyModulePyO3Option {
let lookahead = input.lookahead1();
if lookahead.peek(attributes::kw::name) {
input.parse().map(PyModulePyO3Option::Name)
} else if lookahead.peek(syn::Token![crate]) {
input.parse().map(PyModulePyO3Option::Crate)
} else {
Err(lookahead.error())
}

View file

@ -95,7 +95,7 @@ pub fn impl_arg_params(
if kwonly {
keyword_only_parameters.push(quote! {
::pyo3::derive_utils::KeywordOnlyParameterDescription {
_pyo3::derive_utils::KeywordOnlyParameterDescription {
name: #name,
required: #required,
}
@ -136,7 +136,7 @@ pub fn impl_arg_params(
let (accept_args, accept_kwargs) = accept_args_kwargs(&spec.attrs);
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::type_object::PyTypeInfo>::NAME) }
} else {
quote! { ::std::option::Option::None }
};
@ -163,7 +163,7 @@ pub fn impl_arg_params(
// create array of arguments, and then parse
Ok(quote! {{
const DESCRIPTION: ::pyo3::derive_utils::FunctionDescription = ::pyo3::derive_utils::FunctionDescription {
const DESCRIPTION: _pyo3::derive_utils::FunctionDescription = _pyo3::derive_utils::FunctionDescription {
cls_name: #cls_name,
func_name: stringify!(#python_name),
positional_parameter_names: &[#(#positional_parameter_names),*],
@ -214,7 +214,7 @@ fn impl_arg_param(
let ty = arg.ty;
let name = arg.name;
let transform_error = quote! {
|e| ::pyo3::derive_utils::argument_extraction_error(#py, stringify!(#name), e)
|e| _pyo3::derive_utils::argument_extraction_error(#py, stringify!(#name), e)
};
if is_args(&spec.attrs, name) {
@ -283,7 +283,7 @@ fn impl_arg_param(
let (target_ty, borrow_tmp) = if arg.optional.is_some() {
// Get Option<&T> from Option<PyRef<T>>
(
quote_arg_span! { ::std::option::Option<<#tref as ::pyo3::derive_utils::ExtractExt<'_>>::Target> },
quote_arg_span! { ::std::option::Option<<#tref as _pyo3::derive_utils::ExtractExt<'_>>::Target> },
if mut_.is_some() {
quote_arg_span! { _tmp.as_deref_mut() }
} else {
@ -293,7 +293,7 @@ fn impl_arg_param(
} else {
// Get &T from PyRef<T>
(
quote_arg_span! { <#tref as ::pyo3::derive_utils::ExtractExt<'_>>::Target },
quote_arg_span! { <#tref as _pyo3::derive_utils::ExtractExt<'_>>::Target },
quote_arg_span! { &#mut_ *_tmp },
)
};

View file

@ -1,11 +1,13 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::attributes::{self, take_pyo3_options, NameAttribute, TextSignatureAttribute};
use crate::attributes::{
self, take_pyo3_options, CrateAttribute, NameAttribute, TextSignatureAttribute,
};
use crate::deprecations::Deprecations;
use crate::konst::{ConstAttributes, ConstSpec};
use crate::pyimpl::{gen_default_slot_impls, gen_py_const, PyClassMethodsType};
use crate::pymethod::{impl_py_getter_def, impl_py_setter_def, PropertyType};
use crate::utils::{self, unwrap_group, PythonDoc};
use crate::utils::{self, get_pyo3_crate, unwrap_group, PythonDoc};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::ext::IdentExt;
@ -58,7 +60,7 @@ impl PyClassArgs {
freelist: None,
name: None,
module: None,
base: parse_quote! { ::pyo3::PyAny },
base: parse_quote! { _pyo3::PyAny },
has_dict: false,
has_weaklist: false,
is_gc: false,
@ -186,10 +188,12 @@ impl PyClassArgs {
pub struct PyClassPyO3Options {
pub text_signature: Option<TextSignatureAttribute>,
pub deprecations: Deprecations,
pub krate: Option<CrateAttribute>,
}
enum PyClassPyO3Option {
TextSignature(TextSignatureAttribute),
Crate(CrateAttribute),
}
impl Parse for PyClassPyO3Option {
@ -197,6 +201,8 @@ impl Parse for PyClassPyO3Option {
let lookahead = input.lookahead1();
if lookahead.peek(attributes::kw::text_signature) {
input.parse().map(PyClassPyO3Option::TextSignature)
} else if lookahead.peek(Token![crate]) {
input.parse().map(PyClassPyO3Option::Crate)
} else {
Err(lookahead.error())
}
@ -211,6 +217,9 @@ impl PyClassPyO3Options {
PyClassPyO3Option::TextSignature(text_signature) => {
options.set_text_signature(text_signature)?;
}
PyClassPyO3Option::Crate(path) => {
options.set_crate(path)?;
}
}
}
Ok(options)
@ -227,6 +236,15 @@ impl PyClassPyO3Options {
self.text_signature = Some(text_signature);
Ok(())
}
pub fn set_crate(&mut self, path: CrateAttribute) -> syn::Result<()> {
ensure_spanned!(
self.krate.is_none(),
path.0.span() => "`text_signature` may only be specified once"
);
self.krate = Some(path);
Ok(())
}
}
pub fn build_py_class(
@ -242,6 +260,7 @@ pub fn build_py_class(
.as_ref()
.map(|attr| (get_class_python_name(&class.ident, args), attr)),
);
let krate = get_pyo3_crate(&options.krate);
ensure_spanned!(
class.generics.params.is_empty(),
@ -278,6 +297,7 @@ pub fn build_py_class(
field_options,
methods_type,
options.deprecations,
krate,
)
}
@ -358,6 +378,7 @@ fn impl_class(
field_options: Vec<(&syn::Field, FieldPyO3Options)>,
methods_type: PyClassMethodsType,
deprecations: Deprecations,
krate: syn::Path,
) -> syn::Result<TokenStream> {
let pytypeinfo_impl = impl_pytypeinfo(cls, attr, Some(&deprecations));
@ -368,11 +389,15 @@ fn impl_class(
let descriptors = impl_descriptors(cls, field_options)?;
Ok(quote! {
#pytypeinfo_impl
const _: () = {
use #krate as _pyo3;
#py_class_impl
#pytypeinfo_impl
#descriptors
#py_class_impl
#descriptors
};
})
}
@ -382,10 +407,12 @@ struct PyClassEnumVariant<'a> {
}
pub fn build_py_enum(
enum_: &syn::ItemEnum,
args: PyClassArgs,
enum_: &mut syn::ItemEnum,
args: &PyClassArgs,
method_type: PyClassMethodsType,
) -> syn::Result<TokenStream> {
let options = PyClassPyO3Options::take_pyo3_options(&mut enum_.attrs)?;
if enum_.variants.is_empty() {
bail_spanned!(enum_.brace_token.span => "Empty enums can't be #[pyclass].");
}
@ -394,33 +421,38 @@ pub fn build_py_enum(
.iter()
.map(extract_variant_data)
.collect::<syn::Result<_>>()?;
impl_enum(enum_, args, variants, method_type)
impl_enum(enum_, args, variants, method_type, options)
}
fn impl_enum(
enum_: &syn::ItemEnum,
attrs: PyClassArgs,
args: &PyClassArgs,
variants: Vec<PyClassEnumVariant>,
methods_type: PyClassMethodsType,
options: PyClassPyO3Options,
) -> syn::Result<TokenStream> {
let enum_name = &enum_.ident;
let doc = utils::get_doc(&enum_.attrs, None);
let enum_cls = impl_enum_class(enum_name, &attrs, variants, doc, methods_type)?;
Ok(quote! {
#enum_cls
})
let doc = utils::get_doc(
&enum_.attrs,
options
.text_signature
.as_ref()
.map(|attr| (get_class_python_name(&enum_.ident, args), attr)),
);
let krate = get_pyo3_crate(&options.krate);
impl_enum_class(enum_name, args, variants, doc, methods_type, krate)
}
fn impl_enum_class(
cls: &syn::Ident,
attr: &PyClassArgs,
args: &PyClassArgs,
variants: Vec<PyClassEnumVariant>,
doc: PythonDoc,
methods_type: PyClassMethodsType,
krate: syn::Path,
) -> syn::Result<TokenStream> {
let pytypeinfo = impl_pytypeinfo(cls, attr, None);
let pyclass_impls = PyClassImplsBuilder::new(cls, attr, methods_type)
let pytypeinfo = impl_pytypeinfo(cls, args, None);
let pyclass_impls = PyClassImplsBuilder::new(cls, args, methods_type)
.doc(doc)
.impl_all();
let descriptors = unit_variants_as_descriptors(cls, variants.iter().map(|v| v.ident));
@ -447,15 +479,17 @@ fn impl_enum_class(
let default_impls = gen_default_slot_impls(cls, vec![default_repr_impl]);
Ok(quote! {
const _: () = {
use #krate as _pyo3;
#pytypeinfo
#pytypeinfo
#pyclass_impls
#pyclass_impls
#descriptors
#default_impls
#default_impls
#descriptors
};
})
}
@ -477,11 +511,11 @@ fn unit_variants_as_descriptors<'a>(
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)));
quote! {
impl ::pyo3::class::impl_::PyClassDescriptors<#cls>
for ::pyo3::class::impl_::PyClassImplCollector<#cls>
impl _pyo3::class::impl_::PyClassDescriptors<#cls>
for _pyo3::class::impl_::PyClassImplCollector<#cls>
{
fn py_class_descriptors(self) -> &'static [::pyo3::class::methods::PyMethodDefType] {
static METHODS: &[::pyo3::class::methods::PyMethodDefType] = &[#(#py_methods),*];
fn py_class_descriptors(self) -> &'static [_pyo3::class::methods::PyMethodDefType] {
static METHODS: &[_pyo3::class::methods::PyMethodDefType] = &[#(#py_methods),*];
METHODS
}
}
@ -540,11 +574,11 @@ fn impl_descriptors(
.collect::<syn::Result<_>>()?;
Ok(quote! {
impl ::pyo3::class::impl_::PyClassDescriptors<#cls>
for ::pyo3::class::impl_::PyClassImplCollector<#cls>
impl _pyo3::class::impl_::PyClassDescriptors<#cls>
for _pyo3::class::impl_::PyClassImplCollector<#cls>
{
fn py_class_descriptors(self) -> &'static [::pyo3::class::methods::PyMethodDefType] {
static METHODS: &[::pyo3::class::methods::PyMethodDefType] = &[#(#py_methods),*];
fn py_class_descriptors(self) -> &'static [_pyo3::class::methods::PyMethodDefType] {
static METHODS: &[_pyo3::class::methods::PyMethodDefType] = &[#(#py_methods),*];
METHODS
}
}
@ -565,17 +599,17 @@ fn impl_pytypeinfo(
};
quote! {
unsafe impl ::pyo3::type_object::PyTypeInfo for #cls {
type AsRefTarget = ::pyo3::PyCell<Self>;
unsafe impl _pyo3::type_object::PyTypeInfo for #cls {
type AsRefTarget = _pyo3::PyCell<Self>;
const NAME: &'static str = #cls_name;
const MODULE: ::std::option::Option<&'static str> = #module;
#[inline]
fn type_object_raw(py: ::pyo3::Python<'_>) -> *mut ::pyo3::ffi::PyTypeObject {
fn type_object_raw(py: _pyo3::Python<'_>) -> *mut _pyo3::ffi::PyTypeObject {
#deprecations
use ::pyo3::type_object::LazyStaticType;
use _pyo3::type_object::LazyStaticType;
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
TYPE_OBJECT.get_or_init::<Self>(py)
}
@ -629,29 +663,29 @@ impl<'a> PyClassImplsBuilder<'a> {
let cls = self.cls;
let attr = self.attr;
let dict = if attr.has_dict {
quote! { ::pyo3::pyclass_slots::PyClassDictSlot }
quote! { _pyo3::pyclass_slots::PyClassDictSlot }
} else if attr.has_extends {
quote! { <Self::BaseType as ::pyo3::class::impl_::PyClassBaseType>::Dict }
quote! { <Self::BaseType as _pyo3::class::impl_::PyClassBaseType>::Dict }
} else {
quote! { ::pyo3::pyclass_slots::PyClassDummySlot }
quote! { _pyo3::pyclass_slots::PyClassDummySlot }
};
// insert space for weak ref
let weakref = if attr.has_weaklist {
quote! { ::pyo3::pyclass_slots::PyClassWeakRefSlot }
quote! { _pyo3::pyclass_slots::PyClassWeakRefSlot }
} else if attr.has_extends {
quote! { <Self::BaseType as ::pyo3::class::impl_::PyClassBaseType>::WeakRef }
quote! { <Self::BaseType as _pyo3::class::impl_::PyClassBaseType>::WeakRef }
} else {
quote! { ::pyo3::pyclass_slots::PyClassDummySlot }
quote! { _pyo3::pyclass_slots::PyClassDummySlot }
};
let base_nativetype = if attr.has_extends {
quote! { <Self::BaseType as ::pyo3::class::impl_::PyClassBaseType>::BaseNativeType }
quote! { <Self::BaseType as _pyo3::class::impl_::PyClassBaseType>::BaseNativeType }
} else {
quote! { ::pyo3::PyAny }
quote! { _pyo3::PyAny }
};
quote! {
impl ::pyo3::PyClass for #cls {
impl _pyo3::PyClass for #cls {
type Dict = #dict;
type WeakRef = #weakref;
type BaseNativeType = #base_nativetype;
@ -661,14 +695,14 @@ impl<'a> PyClassImplsBuilder<'a> {
fn impl_extractext(&self) -> TokenStream {
let cls = self.cls;
quote! {
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a #cls
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
{
type Target = ::pyo3::PyRef<'a, #cls>;
type Target = _pyo3::PyRef<'a, #cls>;
}
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
{
type Target = ::pyo3::PyRefMut<'a, #cls>;
type Target = _pyo3::PyRefMut<'a, #cls>;
}
}
}
@ -679,9 +713,9 @@ impl<'a> PyClassImplsBuilder<'a> {
// If #cls is not extended type, we allow Self->PyObject conversion
if !attr.has_extends {
quote! {
impl ::pyo3::IntoPy<::pyo3::PyObject> for #cls {
fn into_py(self, py: ::pyo3::Python) -> ::pyo3::PyObject {
::pyo3::IntoPy::into_py(::pyo3::Py::new(py, self).unwrap(), py)
impl _pyo3::IntoPy<_pyo3::PyObject> for #cls {
fn into_py(self, py: _pyo3::Python) -> _pyo3::PyObject {
_pyo3::IntoPy::into_py(_pyo3::Py::new(py, self).unwrap(), py)
}
}
}
@ -698,13 +732,13 @@ impl<'a> PyClassImplsBuilder<'a> {
let is_subclass = self.attr.has_extends;
let thread_checker = if self.attr.has_unsendable {
quote! { ::pyo3::class::impl_::ThreadCheckerImpl<#cls> }
quote! { _pyo3::class::impl_::ThreadCheckerImpl<#cls> }
} else if self.attr.has_extends {
quote! {
::pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as ::pyo3::class::impl_::PyClassImpl>::BaseType>
_pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as _pyo3::class::impl_::PyClassImpl>::BaseType>
}
} else {
quote! { ::pyo3::class::impl_::ThreadCheckerStub<#cls> }
quote! { _pyo3::class::impl_::ThreadCheckerStub<#cls> }
};
let (for_each_py_method, methods_protos, inventory, inventory_class) = match self
@ -724,13 +758,13 @@ impl<'a> PyClassImplsBuilder<'a> {
);
(
quote! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(::pyo3::class::impl_::PyClassInventory::methods(inventory));
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(_pyo3::class::impl_::PyClassInventory::methods(inventory));
}
},
quote! {
for inventory in ::pyo3::inventory::iter::<<Self as ::pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(::pyo3::class::impl_::PyClassInventory::slots(inventory));
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::class::impl_::PyClassImpl>::Inventory>() {
visitor(_pyo3::class::impl_::PyClassInventory::slots(inventory));
}
},
Some(quote! { type Inventory = #inventory_class_name; }),
@ -739,19 +773,19 @@ impl<'a> PyClassImplsBuilder<'a> {
}
};
quote! {
impl ::pyo3::class::impl_::PyClassImpl for #cls {
impl _pyo3::class::impl_::PyClassImpl for #cls {
const DOC: &'static str = #doc;
const IS_GC: bool = #is_gc;
const IS_BASETYPE: bool = #is_basetype;
const IS_SUBCLASS: bool = #is_subclass;
type Layout = ::pyo3::PyCell<Self>;
type Layout = _pyo3::PyCell<Self>;
type BaseType = #base;
type ThreadChecker = #thread_checker;
#inventory
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[::pyo3::class::PyMethodDefType])) {
use ::pyo3::class::impl_::*;
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::class::PyMethodDefType])) {
use _pyo3::class::impl_::*;
let collector = PyClassImplCollector::<Self>::new();
#for_each_py_method;
visitor(collector.py_class_descriptors());
@ -761,25 +795,25 @@ impl<'a> PyClassImplsBuilder<'a> {
visitor(collector.mapping_protocol_methods());
visitor(collector.number_protocol_methods());
}
fn get_new() -> ::std::option::Option<::pyo3::ffi::newfunc> {
use ::pyo3::class::impl_::*;
fn get_new() -> ::std::option::Option<_pyo3::ffi::newfunc> {
use _pyo3::class::impl_::*;
let collector = PyClassImplCollector::<Self>::new();
collector.new_impl()
}
fn get_alloc() -> ::std::option::Option<::pyo3::ffi::allocfunc> {
use ::pyo3::class::impl_::*;
fn get_alloc() -> ::std::option::Option<_pyo3::ffi::allocfunc> {
use _pyo3::class::impl_::*;
let collector = PyClassImplCollector::<Self>::new();
collector.alloc_impl()
}
fn get_free() -> ::std::option::Option<::pyo3::ffi::freefunc> {
use ::pyo3::class::impl_::*;
fn get_free() -> ::std::option::Option<_pyo3::ffi::freefunc> {
use _pyo3::class::impl_::*;
let collector = PyClassImplCollector::<Self>::new();
collector.free_impl()
}
fn for_each_proto_slot(visitor: &mut dyn ::std::ops::FnMut(&[::pyo3::ffi::PyType_Slot])) {
fn for_each_proto_slot(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::ffi::PyType_Slot])) {
// Implementation which uses dtolnay specialization to load all slots.
use ::pyo3::class::impl_::*;
use _pyo3::class::impl_::*;
let collector = PyClassImplCollector::<Self>::new();
// This depends on Python implementation detail;
// an old slot entry will be overriden by newer ones.
@ -796,8 +830,8 @@ impl<'a> PyClassImplsBuilder<'a> {
#methods_protos
}
fn get_buffer() -> ::std::option::Option<&'static ::pyo3::class::impl_::PyBufferProcs> {
use ::pyo3::class::impl_::*;
fn get_buffer() -> ::std::option::Option<&'static _pyo3::class::impl_::PyBufferProcs> {
use _pyo3::class::impl_::*;
let collector = PyClassImplCollector::<Self>::new();
collector.buffer_procs()
}
@ -812,31 +846,31 @@ impl<'a> PyClassImplsBuilder<'a> {
self.attr.freelist.as_ref().map_or(quote!{}, |freelist| {
quote! {
impl ::pyo3::class::impl_::PyClassWithFreeList for #cls {
impl _pyo3::class::impl_::PyClassWithFreeList for #cls {
#[inline]
fn get_free_list(_py: ::pyo3::Python<'_>) -> &mut ::pyo3::impl_::freelist::FreeList<*mut ::pyo3::ffi::PyObject> {
static mut FREELIST: *mut ::pyo3::impl_::freelist::FreeList<*mut ::pyo3::ffi::PyObject> = 0 as *mut _;
fn get_free_list(_py: _pyo3::Python<'_>) -> &mut _pyo3::impl_::freelist::FreeList<*mut _pyo3::ffi::PyObject> {
static mut FREELIST: *mut _pyo3::impl_::freelist::FreeList<*mut _pyo3::ffi::PyObject> = 0 as *mut _;
unsafe {
if FREELIST.is_null() {
FREELIST = ::std::boxed::Box::into_raw(::std::boxed::Box::new(
::pyo3::impl_::freelist::FreeList::with_capacity(#freelist)));
_pyo3::impl_::freelist::FreeList::with_capacity(#freelist)));
}
&mut *FREELIST
}
}
}
impl ::pyo3::class::impl_::PyClassAllocImpl<#cls> for ::pyo3::class::impl_::PyClassImplCollector<#cls> {
impl _pyo3::class::impl_::PyClassAllocImpl<#cls> for _pyo3::class::impl_::PyClassImplCollector<#cls> {
#[inline]
fn alloc_impl(self) -> ::std::option::Option<::pyo3::ffi::allocfunc> {
::std::option::Option::Some(::pyo3::class::impl_::alloc_with_freelist::<#cls>)
fn alloc_impl(self) -> ::std::option::Option<_pyo3::ffi::allocfunc> {
::std::option::Option::Some(_pyo3::class::impl_::alloc_with_freelist::<#cls>)
}
}
impl ::pyo3::class::impl_::PyClassFreeImpl<#cls> for ::pyo3::class::impl_::PyClassImplCollector<#cls> {
impl _pyo3::class::impl_::PyClassFreeImpl<#cls> for _pyo3::class::impl_::PyClassImplCollector<#cls> {
#[inline]
fn free_impl(self) -> ::std::option::Option<::pyo3::ffi::freefunc> {
::std::option::Option::Some(::pyo3::class::impl_::free_with_freelist::<#cls>)
fn free_impl(self) -> ::std::option::Option<_pyo3::ffi::freefunc> {
::std::option::Option::Some(_pyo3::class::impl_::free_with_freelist::<#cls>)
}
}
}
@ -851,9 +885,9 @@ impl<'a> PyClassImplsBuilder<'a> {
let closure_token = syn::Ident::new(&closure_name, Span::call_site());
quote! {
fn #closure_token() {
use ::pyo3::class;
use _pyo3::class;
fn _assert_implements_protocol<'p, T: ::pyo3::class::PyGCProtocol<'p>>() {}
fn _assert_implements_protocol<'p, T: _pyo3::class::PyGCProtocol<'p>>() {}
_assert_implements_protocol::<#cls>();
}
}
@ -867,23 +901,23 @@ fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream {
quote! {
#[doc(hidden)]
pub struct #inventory_class_name {
methods: &'static [::pyo3::class::PyMethodDefType],
slots: &'static [::pyo3::ffi::PyType_Slot],
methods: &'static [_pyo3::class::PyMethodDefType],
slots: &'static [_pyo3::ffi::PyType_Slot],
}
impl #inventory_class_name {
const fn new(
methods: &'static [::pyo3::class::PyMethodDefType],
slots: &'static [::pyo3::ffi::PyType_Slot],
methods: &'static [_pyo3::class::PyMethodDefType],
slots: &'static [_pyo3::ffi::PyType_Slot],
) -> Self {
Self { methods, slots }
}
}
impl ::pyo3::class::impl_::PyClassInventory for #inventory_class_name {
fn methods(&'static self) -> &'static [::pyo3::class::PyMethodDefType] {
impl _pyo3::class::impl_::PyClassInventory for #inventory_class_name {
fn methods(&'static self) -> &'static [_pyo3::class::PyMethodDefType] {
self.methods
}
fn slots(&'static self) -> &'static [::pyo3::ffi::PyType_Slot] {
fn slots(&'static self) -> &'static [_pyo3::ffi::PyType_Slot] {
self.slots
}
}
@ -892,6 +926,6 @@ fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream {
unsafe impl ::std::marker::Send for #inventory_class_name {}
unsafe impl ::std::marker::Sync for #inventory_class_name {}
::pyo3::inventory::collect!(#inventory_class_name);
_pyo3::inventory::collect!(#inventory_class_name);
}
}

View file

@ -2,13 +2,13 @@
use crate::{
attributes::{
self, get_pyo3_options, take_attributes, take_pyo3_options, FromPyWithAttribute,
NameAttribute, TextSignatureAttribute,
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
FromPyWithAttribute, NameAttribute, TextSignatureAttribute,
},
deprecations::Deprecations,
method::{self, CallingConvention, FnArg},
pymethod::check_generic,
utils::{self, ensure_not_async_fn},
utils::{self, ensure_not_async_fn, get_pyo3_crate},
};
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
@ -239,17 +239,12 @@ pub struct PyFunctionOptions {
pub signature: Option<PyFunctionSignature>,
pub text_signature: Option<TextSignatureAttribute>,
pub deprecations: Deprecations,
pub krate: Option<CrateAttribute>,
}
impl Parse for PyFunctionOptions {
fn parse(input: ParseStream) -> Result<Self> {
let mut options = PyFunctionOptions {
pass_module: None,
name: None,
signature: None,
text_signature: None,
deprecations: Deprecations::new(),
};
let mut options = PyFunctionOptions::default();
while !input.is_empty() {
let lookahead = input.lookahead1();
@ -262,6 +257,9 @@ impl Parse for PyFunctionOptions {
if !input.is_empty() {
let _: Comma = input.parse()?;
}
} else if lookahead.peek(syn::Token![crate]) {
// TODO needs duplicate check?
options.krate = Some(input.parse()?);
} else {
// If not recognised attribute, this is "legacy" pyfunction syntax #[pyfunction(a, b)]
//
@ -280,6 +278,7 @@ pub enum PyFunctionOption {
PassModule(attributes::kw::pass_module),
Signature(PyFunctionSignature),
TextSignature(TextSignatureAttribute),
Crate(CrateAttribute),
}
impl Parse for PyFunctionOption {
@ -293,6 +292,8 @@ impl Parse for PyFunctionOption {
input.parse().map(PyFunctionOption::Signature)
} else if lookahead.peek(attributes::kw::text_signature) {
input.parse().map(PyFunctionOption::TextSignature)
} else if lookahead.peek(syn::Token![crate]) {
input.parse().map(PyFunctionOption::Crate)
} else {
Err(lookahead.error())
}
@ -335,6 +336,13 @@ impl PyFunctionOptions {
);
self.text_signature = Some(text_signature);
}
PyFunctionOption::Crate(path) => {
ensure_spanned!(
self.krate.is_none(),
path.0.span() => "`crate` may only be specified once"
);
self.krate = Some(path);
}
}
}
Ok(())
@ -410,6 +418,7 @@ pub fn impl_wrap_pyfunction(
);
let function_wrapper_ident = function_wrapper_ident(&func.sig.ident);
let krate = get_pyo3_crate(&options.krate);
let spec = method::FnSpec {
tp: if options.pass_module.is_some() {
@ -426,6 +435,7 @@ pub fn impl_wrap_pyfunction(
doc,
deprecations: options.deprecations,
text_signature: options.text_signature,
krate: krate.clone(),
};
let wrapper_ident = format_ident!("__pyo3_raw_{}", spec.name);
@ -434,10 +444,12 @@ pub fn impl_wrap_pyfunction(
let wrapped_pyfunction = quote! {
#wrapper
pub(crate) fn #function_wrapper_ident<'a>(
args: impl ::std::convert::Into<::pyo3::derive_utils::PyFunctionArguments<'a>>
) -> ::pyo3::PyResult<&'a ::pyo3::types::PyCFunction> {
::pyo3::types::PyCFunction::internal_new(#methoddef, args.into())
args: impl ::std::convert::Into<#krate::derive_utils::PyFunctionArguments<'a>>
) -> #krate::PyResult<&'a #krate::types::PyCFunction> {
use #krate as _pyo3;
_pyo3::types::PyCFunction::internal_new(#methoddef, args.into())
}
};
Ok((function_wrapper_ident, wrapped_pyfunction))

View file

@ -3,14 +3,20 @@
use std::collections::HashSet;
use crate::{
attributes::{take_pyo3_options, CrateAttribute},
konst::{ConstAttributes, ConstSpec},
pyfunction::PyFunctionOptions,
pymethod::{self, is_proto_method},
utils::get_pyo3_crate,
};
use proc_macro2::TokenStream;
use pymethod::GeneratedPyMethod;
use quote::quote;
use syn::spanned::Spanned;
use syn::{
parse::{Parse, ParseStream},
spanned::Spanned,
Result,
};
/// The mechanism used to collect `#[pymethods]` into the type object
#[derive(Copy, Clone)]
@ -19,6 +25,50 @@ pub enum PyClassMethodsType {
Inventory,
}
enum PyImplPyO3Option {
Crate(CrateAttribute),
}
impl Parse for PyImplPyO3Option {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(syn::Token![crate]) {
input.parse().map(PyImplPyO3Option::Crate)
} else {
Err(lookahead.error())
}
}
}
#[derive(Default)]
pub struct PyImplOptions {
krate: Option<CrateAttribute>,
}
impl PyImplOptions {
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> Result<Self> {
let mut options: PyImplOptions = Default::default();
for option in take_pyo3_options(attrs)? {
match option {
PyImplPyO3Option::Crate(path) => options.set_crate(path)?,
}
}
Ok(options)
}
fn set_crate(&mut self, path: CrateAttribute) -> Result<()> {
ensure_spanned!(
self.krate.is_none(),
path.0.span() => "`crate` may only be specified once"
);
self.krate = Some(path);
Ok(())
}
}
pub fn build_py_methods(
ast: &mut syn::ItemImpl,
methods_type: PyClassMethodsType,
@ -31,7 +81,8 @@ pub fn build_py_methods(
"#[pymethods] cannot be used with lifetime parameters or generics"
);
} else {
impl_methods(&ast.self_ty, &mut ast.items, methods_type)
let options = PyImplOptions::from_attrs(&mut ast.attrs)?;
impl_methods(&ast.self_ty, &mut ast.items, methods_type, options)
}
}
@ -39,6 +90,7 @@ pub fn impl_methods(
ty: &syn::Type,
impls: &mut Vec<syn::ImplItem>,
methods_type: PyClassMethodsType,
options: PyImplOptions,
) -> syn::Result<TokenStream> {
let mut trait_impls = Vec::new();
let mut proto_impls = Vec::new();
@ -49,8 +101,9 @@ pub fn impl_methods(
for iimpl in impls.iter_mut() {
match iimpl {
syn::ImplItem::Method(meth) => {
let options = PyFunctionOptions::from_attrs(&mut meth.attrs)?;
match pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs, options)? {
let mut fun_options = PyFunctionOptions::from_attrs(&mut meth.attrs)?;
fun_options.krate = fun_options.krate.or_else(|| options.krate.clone());
match pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs, fun_options)? {
GeneratedPyMethod::Method(token_stream) => {
let attrs = get_cfg_attributes(&meth.attrs);
methods.push(quote!(#(#attrs)* #token_stream));
@ -95,25 +148,35 @@ pub fn impl_methods(
add_shared_proto_slots(ty, &mut proto_impls, implemented_proto_fragments);
let krate = get_pyo3_crate(&options.krate);
Ok(match methods_type {
PyClassMethodsType::Specialization => {
let methods_registration = impl_py_methods(ty, methods);
let protos_registration = impl_protos(ty, proto_impls);
quote! {
#(#trait_impls)*
const _: () = {
use #krate as _pyo3;
#protos_registration
#(#trait_impls)*
#methods_registration
#protos_registration
#methods_registration
};
}
}
PyClassMethodsType::Inventory => {
let inventory = submit_methods_inventory(ty, methods, proto_impls);
quote! {
#(#trait_impls)*
const _: () = {
use #krate as _pyo3;
#inventory
#(#trait_impls)*
#inventory
};
}
}
})
@ -124,13 +187,13 @@ pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec) -> TokenStream {
let deprecations = &spec.attributes.deprecations;
let python_name = &spec.null_terminated_python_name();
quote! {
::pyo3::class::PyMethodDefType::ClassAttribute({
::pyo3::class::PyClassAttributeDef::new(
_pyo3::class::PyMethodDefType::ClassAttribute({
_pyo3::class::PyClassAttributeDef::new(
#python_name,
::pyo3::class::methods::PyClassAttributeFactory({
fn __wrap(py: ::pyo3::Python<'_>) -> ::pyo3::PyObject {
_pyo3::class::methods::PyClassAttributeFactory({
fn __wrap(py: _pyo3::Python<'_>) -> _pyo3::PyObject {
#deprecations
::pyo3::IntoPy::into_py(#cls::#member, py)
_pyo3::IntoPy::into_py(#cls::#member, py)
}
__wrap
})
@ -182,11 +245,11 @@ pub fn gen_default_slot_impls(cls: &syn::Ident, method_defs: Vec<TokenStream>) -
fn impl_py_methods(ty: &syn::Type, methods: Vec<TokenStream>) -> TokenStream {
quote! {
impl ::pyo3::class::impl_::PyMethods<#ty>
for ::pyo3::class::impl_::PyClassImplCollector<#ty>
impl _pyo3::class::impl_::PyMethods<#ty>
for _pyo3::class::impl_::PyClassImplCollector<#ty>
{
fn py_methods(self) -> &'static [::pyo3::class::methods::PyMethodDefType] {
static METHODS: &[::pyo3::class::methods::PyMethodDefType] = &[#(#methods),*];
fn py_methods(self) -> &'static [_pyo3::class::methods::PyMethodDefType] {
static METHODS: &[_pyo3::class::methods::PyMethodDefType] = &[#(#methods),*];
METHODS
}
}
@ -203,7 +266,7 @@ fn add_shared_proto_slots(
let first_implemented = implemented_proto_fragments.remove($first);
let second_implemented = implemented_proto_fragments.remove($second);
if first_implemented || second_implemented {
proto_impls.push(quote! { ::pyo3::$slot!(#ty) })
proto_impls.push(quote! { _pyo3::class::impl_::$slot!(#ty) })
}
}};
}
@ -235,10 +298,10 @@ fn add_shared_proto_slots(
fn impl_protos(ty: &syn::Type, proto_impls: Vec<TokenStream>) -> TokenStream {
quote! {
impl ::pyo3::class::impl_::PyMethodsProtocolSlots<#ty>
for ::pyo3::class::impl_::PyClassImplCollector<#ty>
impl _pyo3::class::impl_::PyMethodsProtocolSlots<#ty>
for _pyo3::class::impl_::PyClassImplCollector<#ty>
{
fn methods_protocol_slots(self) -> &'static [::pyo3::ffi::PyType_Slot] {
fn methods_protocol_slots(self) -> &'static [_pyo3::ffi::PyType_Slot] {
&[#(#proto_impls),*]
}
}
@ -251,8 +314,8 @@ fn submit_methods_inventory(
proto_impls: Vec<TokenStream>,
) -> TokenStream {
quote! {
::pyo3::inventory::submit! {
type Inventory = <#ty as ::pyo3::class::impl_::PyClassImpl>::Inventory;
_pyo3::inventory::submit! {
type Inventory = <#ty as _pyo3::class::impl_::PyClassImpl>::Inventory;
Inventory::new(&[#(#methods),*], &[#(#proto_impls),*])
}
}

View file

@ -120,12 +120,12 @@ pub fn gen_py_method(
(_, FnType::FnClass) => GeneratedPyMethod::Method(impl_py_method_def(
cls,
spec,
Some(quote!(::pyo3::ffi::METH_CLASS)),
Some(quote!(_pyo3::ffi::METH_CLASS)),
)?),
(_, FnType::FnStatic) => GeneratedPyMethod::Method(impl_py_method_def(
cls,
spec,
Some(quote!(::pyo3::ffi::METH_STATIC)),
Some(quote!(_pyo3::ffi::METH_STATIC)),
)?),
// special prototypes
(_, FnType::FnNew) => GeneratedPyMethod::TraitImpl(impl_py_method_def_new(cls, spec)?),
@ -186,7 +186,7 @@ pub fn impl_py_method_def(
};
let methoddef = spec.get_methoddef(quote! {{ #wrapper_def #wrapper_ident }});
Ok(quote! {
::pyo3::class::PyMethodDefType::#methoddef_type(#methoddef #add_flags)
_pyo3::class::PyMethodDefType::#methoddef_type(#methoddef #add_flags)
})
}
@ -194,8 +194,8 @@ fn impl_py_method_def_new(cls: &syn::Type, spec: &FnSpec) -> Result<TokenStream>
let wrapper_ident = syn::Ident::new("__wrap", Span::call_site());
let wrapper = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
Ok(quote! {
impl ::pyo3::class::impl_::PyClassNewImpl<#cls> for ::pyo3::class::impl_::PyClassImplCollector<#cls> {
fn new_impl(self) -> ::std::option::Option<::pyo3::ffi::newfunc> {
impl _pyo3::class::impl_::PyClassNewImpl<#cls> for _pyo3::class::impl_::PyClassImplCollector<#cls> {
fn new_impl(self) -> ::std::option::Option<_pyo3::ffi::newfunc> {
::std::option::Option::Some({
#wrapper
#wrapper_ident
@ -214,9 +214,9 @@ fn impl_call_slot(cls: &syn::Type, mut spec: FnSpec) -> Result<TokenStream> {
let wrapper = spec.get_wrapper_function(&wrapper_ident, Some(cls))?;
Ok(quote! {{
#wrapper
::pyo3::ffi::PyType_Slot {
slot: ::pyo3::ffi::Py_tp_call,
pfunc: __wrap as ::pyo3::ffi::ternaryfunc as _
_pyo3::ffi::PyType_Slot {
slot: _pyo3::ffi::Py_tp_call,
pfunc: __wrap as _pyo3::ffi::ternaryfunc as _
}
}})
}
@ -226,13 +226,13 @@ fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec) -> TokenStream {
let deprecations = &spec.deprecations;
let python_name = spec.null_terminated_python_name();
quote! {
::pyo3::class::PyMethodDefType::ClassAttribute({
::pyo3::class::PyClassAttributeDef::new(
_pyo3::class::PyMethodDefType::ClassAttribute({
_pyo3::class::PyClassAttributeDef::new(
#python_name,
::pyo3::class::methods::PyClassAttributeFactory({
fn __wrap(py: ::pyo3::Python<'_>) -> ::pyo3::PyObject {
_pyo3::class::methods::PyClassAttributeFactory({
fn __wrap(py: _pyo3::Python<'_>) -> _pyo3::PyObject {
#deprecations
::pyo3::IntoPy::into_py(#cls::#name(), py)
_pyo3::IntoPy::into_py(#cls::#name(), py)
}
__wrap
})
@ -295,26 +295,26 @@ pub fn impl_py_setter_def(cls: &syn::Type, property_type: PropertyType) -> Resul
}
};
Ok(quote! {
::pyo3::class::PyMethodDefType::Setter({
_pyo3::class::PyMethodDefType::Setter({
#deprecations
::pyo3::class::PySetterDef::new(
_pyo3::class::PySetterDef::new(
#python_name,
::pyo3::class::methods::PySetter({
_pyo3::class::methods::PySetter({
unsafe extern "C" fn __wrap(
_slf: *mut ::pyo3::ffi::PyObject,
_value: *mut ::pyo3::ffi::PyObject,
_slf: *mut _pyo3::ffi::PyObject,
_value: *mut _pyo3::ffi::PyObject,
_: *mut ::std::os::raw::c_void
) -> ::std::os::raw::c_int {
::pyo3::callback::handle_panic(|_py| {
_pyo3::callback::handle_panic(|_py| {
#slf
let _value = _py
.from_borrowed_ptr_or_opt(_value)
.ok_or_else(|| {
::pyo3::exceptions::PyAttributeError::new_err("can't delete attribute")
_pyo3::exceptions::PyAttributeError::new_err("can't delete attribute")
})?;
let _val = ::pyo3::FromPyObject::extract(_value)?;
let _val = _pyo3::FromPyObject::extract(_value)?;
::pyo3::callback::convert(_py, #setter_impl)
_pyo3::callback::convert(_py, #setter_impl)
})
}
__wrap
@ -375,18 +375,18 @@ pub fn impl_py_getter_def(cls: &syn::Type, property_type: PropertyType) -> Resul
}
};
Ok(quote! {
::pyo3::class::PyMethodDefType::Getter({
_pyo3::class::PyMethodDefType::Getter({
#deprecations
::pyo3::class::PyGetterDef::new(
_pyo3::class::PyGetterDef::new(
#python_name,
::pyo3::class::methods::PyGetter({
_pyo3::class::methods::PyGetter({
unsafe extern "C" fn __wrap(
_slf: *mut ::pyo3::ffi::PyObject,
_slf: *mut _pyo3::ffi::PyObject,
_: *mut ::std::os::raw::c_void
) -> *mut ::pyo3::ffi::PyObject {
::pyo3::callback::handle_panic(|_py| {
) -> *mut _pyo3::ffi::PyObject {
_pyo3::callback::handle_panic(|_py| {
#slf
::pyo3::callback::convert(_py, #getter_impl)
_pyo3::callback::convert(_py, #getter_impl)
})
}
__wrap
@ -459,10 +459,10 @@ const __GETATTR__: SlotDef = SlotDef::new("Py_tp_getattro", "getattrofunc")
quote! {
// Behave like python's __getattr__ (as opposed to __getattribute__) and check
// for existing fields and methods first
let existing = ::pyo3::ffi::PyObject_GenericGetAttr(_slf, arg0);
let existing = _pyo3::ffi::PyObject_GenericGetAttr(_slf, arg0);
if existing.is_null() {
// PyObject_HasAttr also tries to get an object and clears the error if it fails
::pyo3::ffi::PyErr_Clear();
_pyo3::ffi::PyErr_Clear();
} else {
return existing;
}
@ -473,7 +473,7 @@ const __REPR__: SlotDef = SlotDef::new("Py_tp_repr", "reprfunc");
const __HASH__: SlotDef = SlotDef::new("Py_tp_hash", "hashfunc")
.ret_ty(Ty::PyHashT)
.return_conversion(TokenGenerator(
|| quote! { ::pyo3::callback::HashCallbackOutput },
|| quote! { _pyo3::callback::HashCallbackOutput },
));
const __RICHCMP__: SlotDef = SlotDef::new("Py_tp_richcompare", "richcmpfunc")
.extract_error_mode(ExtractErrorMode::NotImplemented)
@ -482,12 +482,12 @@ const __GET__: SlotDef = SlotDef::new("Py_tp_descr_get", "descrgetfunc")
.arguments(&[Ty::MaybeNullObject, Ty::MaybeNullObject]);
const __ITER__: SlotDef = SlotDef::new("Py_tp_iter", "getiterfunc");
const __NEXT__: SlotDef = SlotDef::new("Py_tp_iternext", "iternextfunc").return_conversion(
TokenGenerator(|| quote! { ::pyo3::class::iter::IterNextOutput::<_, _> }),
TokenGenerator(|| quote! { _pyo3::class::iter::IterNextOutput::<_, _> }),
);
const __AWAIT__: SlotDef = SlotDef::new("Py_am_await", "unaryfunc");
const __AITER__: SlotDef = SlotDef::new("Py_am_aiter", "unaryfunc");
const __ANEXT__: SlotDef = SlotDef::new("Py_am_anext", "unaryfunc").return_conversion(
TokenGenerator(|| quote! { ::pyo3::class::pyasync::IterANextOutput::<_, _> }),
TokenGenerator(|| quote! { _pyo3::class::pyasync::IterANextOutput::<_, _> }),
);
const __LEN__: SlotDef = SlotDef::new("Py_mp_length", "lenfunc").ret_ty(Ty::PySsizeT);
const __CONTAINS__: SlotDef = SlotDef::new("Py_sq_contains", "objobjproc")
@ -613,11 +613,11 @@ enum Ty {
impl Ty {
fn ffi_type(self) -> TokenStream {
match self {
Ty::Object | Ty::MaybeNullObject => quote! { *mut ::pyo3::ffi::PyObject },
Ty::NonNullObject => quote! { ::std::ptr::NonNull<::pyo3::ffi::PyObject> },
Ty::Object | Ty::MaybeNullObject => quote! { *mut _pyo3::ffi::PyObject },
Ty::NonNullObject => quote! { ::std::ptr::NonNull<_pyo3::ffi::PyObject> },
Ty::Int | Ty::CompareOp => quote! { ::std::os::raw::c_int },
Ty::PyHashT => quote! { ::pyo3::ffi::Py_hash_t },
Ty::PySsizeT => quote! { ::pyo3::ffi::Py_ssize_t },
Ty::PyHashT => quote! { _pyo3::ffi::Py_hash_t },
Ty::PySsizeT => quote! { _pyo3::ffi::Py_ssize_t },
Ty::Void => quote! { () },
}
}
@ -636,7 +636,7 @@ impl Ty {
extract_error_mode,
py,
quote! {
#py.from_borrowed_ptr::<::pyo3::PyAny>(#ident).extract()
#py.from_borrowed_ptr::<_pyo3::PyAny>(#ident).extract()
},
);
extract_object(cls, arg.ty, ident, extract)
@ -646,9 +646,9 @@ impl Ty {
extract_error_mode,
py,
quote! {
#py.from_borrowed_ptr::<::pyo3::PyAny>(
#py.from_borrowed_ptr::<_pyo3::PyAny>(
if #ident.is_null() {
::pyo3::ffi::Py_None()
_pyo3::ffi::Py_None()
} else {
#ident
}
@ -662,7 +662,7 @@ impl Ty {
extract_error_mode,
py,
quote! {
#py.from_borrowed_ptr::<::pyo3::PyAny>(#ident.as_ptr()).extract()
#py.from_borrowed_ptr::<_pyo3::PyAny>(#ident.as_ptr()).extract()
},
);
extract_object(cls, arg.ty, ident, extract)
@ -672,8 +672,8 @@ impl Ty {
extract_error_mode,
py,
quote! {
::pyo3::class::basic::CompareOp::from_raw(#ident)
.ok_or_else(|| ::pyo3::exceptions::PyValueError::new_err("invalid comparison operator"))
_pyo3::class::basic::CompareOp::from_raw(#ident)
.ok_or_else(|| _pyo3::exceptions::PyValueError::new_err("invalid comparison operator"))
},
);
quote! {
@ -695,7 +695,7 @@ fn handle_error(
ExtractErrorMode::NotImplemented => quote! {
match #extract {
::std::result::Result::Ok(value) => value,
::std::result::Result::Err(_) => { return ::pyo3::callback::convert(#py, #py.NotImplemented()); },
::std::result::Result::Err(_) => { return _pyo3::callback::convert(#py, #py.NotImplemented()); },
}
},
}
@ -712,7 +712,7 @@ fn extract_object(
replace_self(&mut tref.elem, cls);
let mut_ = tref.mutability;
quote! {
let #mut_ #ident: <#tref as ::pyo3::derive_utils::ExtractExt<'_>>::Target = #extract;
let #mut_ #ident: <#tref as _pyo3::derive_utils::ExtractExt<'_>>::Target = #extract;
let #ident = &#mut_ *#ident;
}
} else {
@ -731,13 +731,13 @@ impl ReturnMode {
fn return_call_output(&self, py: &syn::Ident, call: TokenStream) -> TokenStream {
match self {
ReturnMode::Conversion(conversion) => quote! {
let _result: ::pyo3::PyResult<#conversion> = #call;
::pyo3::callback::convert(#py, _result)
let _result: _pyo3::PyResult<#conversion> = #call;
_pyo3::callback::convert(#py, _result)
},
ReturnMode::ReturnSelf => quote! {
let _result: ::pyo3::PyResult<()> = #call;
let _result: _pyo3::PyResult<()> = #call;
_result?;
::pyo3::ffi::Py_XINCREF(_raw_slf);
_pyo3::ffi::Py_XINCREF(_raw_slf);
::std::result::Result::Ok(_raw_slf)
},
}
@ -821,16 +821,16 @@ impl SlotDef {
return_mode.as_ref(),
)?;
Ok(quote!({
unsafe extern "C" fn __wrap(_raw_slf: *mut ::pyo3::ffi::PyObject, #(#method_arguments),*) -> #ret_ty {
unsafe extern "C" fn __wrap(_raw_slf: *mut _pyo3::ffi::PyObject, #(#method_arguments),*) -> #ret_ty {
let _slf = _raw_slf;
#before_call_method
::pyo3::callback::handle_panic(|#py| {
_pyo3::callback::handle_panic(|#py| {
#body
})
}
::pyo3::ffi::PyType_Slot {
slot: ::pyo3::ffi::#slot,
pfunc: __wrap as ::pyo3::ffi::#func_ty as _
_pyo3::ffi::PyType_Slot {
slot: _pyo3::ffi::#slot,
pfunc: __wrap as _pyo3::ffi::#func_ty as _
}
}))
}
@ -858,7 +858,7 @@ fn generate_method_body(
let rust_name = spec.name;
let (arg_idents, conversions) =
extract_proto_arguments(cls, py, &spec.args, arguments, extract_error_mode)?;
let call = quote! { ::pyo3::callback::convert(#py, #cls::#rust_name(_slf, #(#arg_idents),*)) };
let call = quote! { _pyo3::callback::convert(#py, #cls::#rust_name(_slf, #(#arg_idents),*)) };
let body = if let Some(return_mode) = return_mode {
return_mode.return_call_output(py, call)
} else {
@ -912,15 +912,15 @@ impl SlotFragmentDef {
let body = generate_method_body(cls, spec, &py, arguments, *extract_error_mode, None)?;
let ret_ty = ret_ty.ffi_type();
Ok(quote! {
impl ::pyo3::class::impl_::#fragment_trait<#cls> for ::pyo3::class::impl_::PyClassImplCollector<#cls> {
impl _pyo3::class::impl_::#fragment_trait<#cls> for _pyo3::class::impl_::PyClassImplCollector<#cls> {
#[inline]
unsafe fn #method(
self,
#py: ::pyo3::Python,
_raw_slf: *mut ::pyo3::ffi::PyObject,
#py: _pyo3::Python,
_raw_slf: *mut _pyo3::ffi::PyObject,
#(#method_arguments),*
) -> ::pyo3::PyResult<#ret_ty> {
) -> _pyo3::PyResult<#ret_ty> {
let _slf = _raw_slf;
#body
}

View file

@ -67,7 +67,7 @@ fn impl_proto_impl(
let flags = if m.can_coexist {
// We need METH_COEXIST here to prevent __add__ from overriding __radd__
Some(quote!(::pyo3::ffi::METH_COEXIST))
Some(quote!(_pyo3::ffi::METH_COEXIST))
} else {
None
};
@ -86,10 +86,14 @@ fn impl_proto_impl(
}
let normal_methods = impl_normal_methods(py_methods, ty, proto);
let protocol_methods = impl_proto_methods(method_names, ty, proto);
Ok(quote! {
#trait_impls
#normal_methods
#protocol_methods
const _: () = {
use ::pyo3 as _pyo3; // pyproto doesn't support specifying #[pyo3(crate)]
#trait_impls
#normal_methods
#protocol_methods
};
})
}
@ -105,11 +109,11 @@ fn impl_normal_methods(
let methods_trait = proto.methods_trait();
let methods_trait_methods = proto.methods_trait_methods();
quote! {
impl ::pyo3::class::impl_::#methods_trait<#ty>
for ::pyo3::class::impl_::PyClassImplCollector<#ty>
impl _pyo3::class::impl_::#methods_trait<#ty>
for _pyo3::class::impl_::PyClassImplCollector<#ty>
{
fn #methods_trait_methods(self) -> &'static [::pyo3::class::methods::PyMethodDefType] {
static METHODS: &[::pyo3::class::methods::PyMethodDefType] =
fn #methods_trait_methods(self) -> &'static [_pyo3::class::methods::PyMethodDefType] {
static METHODS: &[_pyo3::class::methods::PyMethodDefType] =
&[#(#py_methods),*];
METHODS
}
@ -138,16 +142,16 @@ fn impl_proto_methods(
if build_config.version <= PY39 && proto.name == "Buffer" {
maybe_buffer_methods = Some(quote! {
impl ::pyo3::class::impl_::PyBufferProtocolProcs<#ty>
for ::pyo3::class::impl_::PyClassImplCollector<#ty>
impl _pyo3::class::impl_::PyBufferProtocolProcs<#ty>
for _pyo3::class::impl_::PyClassImplCollector<#ty>
{
fn buffer_procs(
self
) -> ::std::option::Option<&'static ::pyo3::class::impl_::PyBufferProcs> {
static PROCS: ::pyo3::class::impl_::PyBufferProcs
= ::pyo3::class::impl_::PyBufferProcs {
bf_getbuffer: ::std::option::Option::Some(::pyo3::class::buffer::getbuffer::<#ty>),
bf_releasebuffer: ::std::option::Option::Some(::pyo3::class::buffer::releasebuffer::<#ty>),
) -> ::std::option::Option<&'static _pyo3::class::impl_::PyBufferProcs> {
static PROCS: _pyo3::class::impl_::PyBufferProcs
= _pyo3::class::impl_::PyBufferProcs {
bf_getbuffer: ::std::option::Option::Some(_pyo3::class::buffer::getbuffer::<#ty>),
bf_releasebuffer: ::std::option::Option::Some(_pyo3::class::buffer::releasebuffer::<#ty>),
};
::std::option::Option::Some(&PROCS)
}
@ -161,8 +165,8 @@ fn impl_proto_methods(
let slot = syn::Ident::new(def.slot, Span::call_site());
let slot_impl = syn::Ident::new(def.slot_impl, Span::call_site());
quote! {{
::pyo3::ffi::PyType_Slot {
slot: ::pyo3::ffi::#slot,
_pyo3::ffi::PyType_Slot {
slot: _pyo3::ffi::#slot,
pfunc: #module::#slot_impl::<#ty> as _
}
}}
@ -176,10 +180,10 @@ fn impl_proto_methods(
quote! {
#maybe_buffer_methods
impl ::pyo3::class::impl_::#slots_trait<#ty>
for ::pyo3::class::impl_::PyClassImplCollector<#ty>
impl _pyo3::class::impl_::#slots_trait<#ty>
for _pyo3::class::impl_::PyClassImplCollector<#ty>
{
fn #slots_trait_slots(self) -> &'static [::pyo3::ffi::PyType_Slot] {
fn #slots_trait_slots(self) -> &'static [_pyo3::ffi::PyType_Slot] {
&[#(#tokens),*]
}
}

View file

@ -3,7 +3,7 @@ use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use syn::spanned::Spanned;
use crate::attributes::TextSignatureAttribute;
use crate::attributes::{CrateAttribute, TextSignatureAttribute};
/// Macro inspired by `anyhow::anyhow!` to create a compiler error with the given span.
macro_rules! err_spanned {
@ -189,3 +189,10 @@ pub(crate) fn replace_self(ty: &mut syn::Type, cls: &syn::Type) {
_ => {}
}
}
/// Extract the path to the pyo3 crate, or use the default (`::pyo3`).
pub(crate) fn get_pyo3_crate(attr: &Option<CrateAttribute>) -> syn::Path {
attr.as_ref()
.map(|p| p.0.clone())
.unwrap_or_else(|| syn::parse_str("::pyo3").unwrap())
}

View file

@ -216,16 +216,16 @@ fn pyclass_impl(
}
fn pyclass_enum_impl(
attr: TokenStream,
enum_: syn::ItemEnum,
attrs: TokenStream,
mut ast: syn::ItemEnum,
methods_type: PyClassMethodsType,
) -> TokenStream {
let args = parse_macro_input!(attr with PyClassArgs::parse_enum_args);
let args = parse_macro_input!(attrs with PyClassArgs::parse_enum_args);
let expanded =
build_py_enum(&enum_, args, methods_type).unwrap_or_else(|e| e.into_compile_error());
build_py_enum(&mut ast, &args, methods_type).unwrap_or_else(|e| e.into_compile_error());
quote!(
#enum_
#ast
#expanded
)
.into()

View file

@ -183,6 +183,7 @@ macro_rules! define_pyclass_setattr_slot {
}
}};
}
pub use $generate_macro;
};
}
@ -292,6 +293,7 @@ macro_rules! define_pyclass_binary_operator_slot {
}
}};
}
pub use $generate_macro;
};
}
@ -484,6 +486,7 @@ macro_rules! generate_pyclass_pow_slot {
}
}};
}
pub use generate_pyclass_pow_slot;
pub trait PyClassAllocImpl<T> {
fn alloc_impl(self) -> Option<ffi::allocfunc>;

View file

@ -360,6 +360,11 @@ pub use pyo3_macros::{pyclass, pyfunction, pymethods, pymodule, pyproto, FromPyO
#[macro_use]
mod macros;
/// Test macro hygiene - this is in the crate since we won't have
/// `pyo3` available in the crate root.
#[cfg(all(test, feature = "macros"))]
mod test_hygiene;
/// Test readme and user guide
#[cfg(doctest)]
pub mod doc_test {

29
src/test_hygiene/misc.rs Normal file
View file

@ -0,0 +1,29 @@
#![no_implicit_prelude]
#[derive(crate::FromPyObject)]
#[pyo3(crate = "crate")]
struct Derive1(i32); // newtype case
#[derive(crate::FromPyObject)]
#[pyo3(crate = "crate")]
#[allow(dead_code)]
struct Derive2(i32, i32); // tuple case
#[derive(crate::FromPyObject)]
#[pyo3(crate = "crate")]
#[allow(dead_code)]
struct Derive3 {
f: i32,
g: i32,
} // struct case
#[derive(crate::FromPyObject)]
#[pyo3(crate = "crate")]
#[allow(dead_code)]
enum Derive4 {
A(i32),
B { f: i32 },
} // enum case
crate::create_exception!(mymodule, CustomError, crate::exceptions::PyException);
crate::import_exception!(socket, gaierror);

5
src/test_hygiene/mod.rs Normal file
View file

@ -0,0 +1,5 @@
mod misc;
mod pyclass;
mod pyfunction;
mod pymethods;
mod pymodule;

View file

@ -1,27 +1,30 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[::pyo3::pyclass]
#[crate::pyclass]
#[pyo3(crate = "crate")]
#[derive(::std::clone::Clone)]
pub struct Foo;
#[::pyo3::pyclass]
#[crate::pyclass]
#[pyo3(crate = "crate")]
pub struct Foo2;
#[::pyo3::pyclass(
#[crate::pyclass(
name = "ActuallyBar",
freelist = 8,
weakref,
unsendable,
subclass,
extends = ::pyo3::types::PyAny,
extends = crate::types::PyAny,
module = "Spam"
)]
#[pyo3(crate = "crate")]
pub struct Bar {
#[pyo3(get, set)]
a: u8,
#[pyo3(get, set)]
b: Foo,
#[pyo3(get, set)]
c: ::std::option::Option<::pyo3::Py<Foo2>>,
c: ::std::option::Option<crate::Py<Foo2>>,
}

View file

@ -0,0 +1,16 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[crate::pyfunction]
#[pyo3(crate = "crate")]
fn do_something(x: i32) -> crate::PyResult<i32> {
::std::result::Result::Ok(x)
}
#[test]
fn invoke_wrap_pyfunction() {
crate::Python::with_gil(|py| {
let func = crate::wrap_pyfunction!(do_something)(py).unwrap();
crate::py_run!(py, func, r#"func(5)"#);
});
}

View file

@ -1,13 +1,16 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[::pyo3::pyclass]
#[crate::pyclass]
#[pyo3(crate = "crate")]
pub struct Dummy;
#[::pyo3::pyclass]
#[crate::pyclass]
#[pyo3(crate = "crate")]
pub struct DummyIter;
#[::pyo3::pymethods]
#[crate::pymethods]
#[pyo3(crate = "crate")]
impl Dummy {
//////////////////////
// Basic customization
@ -20,8 +23,8 @@ impl Dummy {
"Dummy"
}
fn __bytes__<'py>(&self, py: ::pyo3::Python<'py>) -> &'py ::pyo3::types::PyBytes {
::pyo3::types::PyBytes::new(py, &[0])
fn __bytes__<'py>(&self, py: crate::Python<'py>) -> &'py crate::types::PyBytes {
crate::types::PyBytes::new(py, &[0])
}
fn __format__(&self, format_spec: ::std::string::String) -> ::std::string::String {
@ -60,11 +63,11 @@ impl Dummy {
// Customizing attribute access
//////////////////////
fn __getattr__(&self, name: ::std::string::String) -> &::pyo3::PyAny {
fn __getattr__(&self, name: ::std::string::String) -> &crate::PyAny {
::std::panic!("unimplemented isn't hygienic before 1.50")
}
fn __getattribute__(&self, name: ::std::string::String) -> &::pyo3::PyAny {
fn __getattribute__(&self, name: ::std::string::String) -> &crate::PyAny {
::std::panic!("unimplemented isn't hygienic before 1.50")
}
@ -72,8 +75,8 @@ impl Dummy {
fn __delattr__(&mut self, name: ::std::string::String) {}
fn __dir__<'py>(&self, py: ::pyo3::Python<'py>) -> &'py ::pyo3::types::PyList {
::pyo3::types::PyList::new(py, ::std::vec![0_u8])
fn __dir__<'py>(&self, py: crate::Python<'py>) -> &'py crate::types::PyList {
crate::types::PyList::new(py, ::std::vec![0_u8])
}
//////////////////////
@ -82,17 +85,17 @@ impl Dummy {
fn __get__(
&self,
instance: &::pyo3::PyAny,
owner: &::pyo3::PyAny,
) -> ::pyo3::PyResult<&::pyo3::PyAny> {
instance: &crate::PyAny,
owner: &crate::PyAny,
) -> crate::PyResult<&crate::PyAny> {
::std::panic!("unimplemented isn't hygienic before 1.50")
}
fn __set__(&self, instance: &::pyo3::PyAny, owner: &::pyo3::PyAny) {}
fn __set__(&self, instance: &crate::PyAny, owner: &crate::PyAny) {}
fn __delete__(&self, instance: &::pyo3::PyAny) {}
fn __delete__(&self, instance: &crate::PyAny) {}
fn __set_name__(&self, owner: &::pyo3::PyAny, name: &::pyo3::PyAny) {}
fn __set_name__(&self, owner: &crate::PyAny, name: &crate::PyAny) {}
//////////////////////
// Implementing Descriptors
@ -102,24 +105,24 @@ impl Dummy {
0
}
fn __getitem__(&self, key: u32) -> ::pyo3::PyResult<u32> {
::std::result::Result::Err(::pyo3::exceptions::PyKeyError::new_err("boo"))
fn __getitem__(&self, key: u32) -> crate::PyResult<u32> {
::std::result::Result::Err(crate::exceptions::PyKeyError::new_err("boo"))
}
fn __setitem__(&self, key: u32, value: u32) {}
fn __delitem__(&self, key: u32) {}
fn __iter__(_: ::pyo3::pycell::PyRef<Self>, py: ::pyo3::Python) -> ::pyo3::Py<DummyIter> {
::pyo3::Py::new(py, DummyIter {}).unwrap()
fn __iter__(_: crate::pycell::PyRef<Self>, py: crate::Python) -> crate::Py<DummyIter> {
crate::Py::new(py, DummyIter {}).unwrap()
}
fn __next__(&mut self) -> ::std::option::Option<()> {
::std::option::Option::None
}
fn __reversed__(slf: ::pyo3::pycell::PyRef<Self>, py: ::pyo3::Python) -> ::pyo3::Py<DummyIter> {
::pyo3::Py::new(py, DummyIter {}).unwrap()
fn __reversed__(slf: crate::pycell::PyRef<Self>, py: crate::Python) -> crate::Py<DummyIter> {
crate::Py::new(py, DummyIter {}).unwrap()
}
fn __contains__(&self, item: u32) -> bool {
@ -142,12 +145,12 @@ impl Dummy {
Dummy {}
}
fn __truediv__(&self, _other: &Self) -> ::pyo3::PyResult<()> {
::std::result::Result::Err(::pyo3::exceptions::PyZeroDivisionError::new_err("boo"))
fn __truediv__(&self, _other: &Self) -> crate::PyResult<()> {
::std::result::Result::Err(crate::exceptions::PyZeroDivisionError::new_err("boo"))
}
fn __floordiv__(&self, _other: &Self) -> ::pyo3::PyResult<()> {
::std::result::Result::Err(::pyo3::exceptions::PyZeroDivisionError::new_err("boo"))
fn __floordiv__(&self, _other: &Self) -> crate::PyResult<()> {
::std::result::Result::Err(crate::exceptions::PyZeroDivisionError::new_err("boo"))
}
fn __mod__(&self, _other: &Self) -> u32 {
@ -194,12 +197,12 @@ impl Dummy {
Dummy {}
}
fn __rtruediv__(&self, _other: &Self) -> ::pyo3::PyResult<()> {
::std::result::Result::Err(::pyo3::exceptions::PyZeroDivisionError::new_err("boo"))
fn __rtruediv__(&self, _other: &Self) -> crate::PyResult<()> {
::std::result::Result::Err(crate::exceptions::PyZeroDivisionError::new_err("boo"))
}
fn __rfloordiv__(&self, _other: &Self) -> ::pyo3::PyResult<()> {
::std::result::Result::Err(::pyo3::exceptions::PyZeroDivisionError::new_err("boo"))
fn __rfloordiv__(&self, _other: &Self) -> crate::PyResult<()> {
::std::result::Result::Err(crate::exceptions::PyZeroDivisionError::new_err("boo"))
}
fn __rmod__(&self, _other: &Self) -> u32 {
@ -258,24 +261,24 @@ impl Dummy {
fn __ior__(&mut self, other: &Self) {}
fn __neg__(slf: ::pyo3::pycell::PyRef<Self>) -> ::pyo3::pycell::PyRef<Self> {
fn __neg__(slf: crate::pycell::PyRef<Self>) -> crate::pycell::PyRef<Self> {
slf
}
fn __pos__(slf: ::pyo3::pycell::PyRef<Self>) -> ::pyo3::pycell::PyRef<Self> {
fn __pos__(slf: crate::pycell::PyRef<Self>) -> crate::pycell::PyRef<Self> {
slf
}
fn __abs__(slf: ::pyo3::pycell::PyRef<Self>) -> ::pyo3::pycell::PyRef<Self> {
fn __abs__(slf: crate::pycell::PyRef<Self>) -> crate::pycell::PyRef<Self> {
slf
}
fn __invert__(slf: ::pyo3::pycell::PyRef<Self>) -> ::pyo3::pycell::PyRef<Self> {
fn __invert__(slf: crate::pycell::PyRef<Self>) -> crate::pycell::PyRef<Self> {
slf
}
fn __complex__<'py>(&self, py: ::pyo3::Python<'py>) -> &'py ::pyo3::types::PyComplex {
::pyo3::types::PyComplex::from_doubles(py, 0.0, 0.0)
fn __complex__<'py>(&self, py: crate::Python<'py>) -> &'py crate::types::PyComplex {
crate::types::PyComplex::from_doubles(py, 0.0, 0.0)
}
fn __int__(&self) -> u32 {
@ -314,9 +317,9 @@ impl Dummy {
fn __exit__(
&mut self,
exc_type: &::pyo3::PyAny,
exc_value: &::pyo3::PyAny,
traceback: &::pyo3::PyAny,
exc_type: &crate::PyAny,
exc_value: &crate::PyAny,
traceback: &crate::PyAny,
) {
}
@ -324,7 +327,7 @@ impl Dummy {
// Awaitable Objects
//////////////////////
fn __await__(slf: ::pyo3::pycell::PyRef<Self>) -> ::pyo3::pycell::PyRef<Self> {
fn __await__(slf: crate::pycell::PyRef<Self>) -> crate::pycell::PyRef<Self> {
slf
}
@ -333,8 +336,8 @@ impl Dummy {
// Asynchronous Iterators
//////////////////////
fn __aiter__(slf: ::pyo3::pycell::PyRef<Self>, py: ::pyo3::Python) -> ::pyo3::Py<DummyIter> {
::pyo3::Py::new(py, DummyIter {}).unwrap()
fn __aiter__(slf: crate::pycell::PyRef<Self>, py: crate::Python) -> crate::Py<DummyIter> {
crate::Py::new(py, DummyIter {}).unwrap()
}
fn __anext__(&mut self) -> ::std::option::Option<()> {
@ -349,9 +352,9 @@ impl Dummy {
fn __aexit__(
&mut self,
exc_type: &::pyo3::PyAny,
exc_value: &::pyo3::PyAny,
traceback: &::pyo3::PyAny,
exc_type: &crate::PyAny,
exc_value: &crate::PyAny,
traceback: &crate::PyAny,
) {
}
@ -362,13 +365,13 @@ impl Dummy {
#[staticmethod]
fn staticmethod() {}
#[classmethod]
fn clsmethod(_: &::pyo3::types::PyType) {}
fn clsmethod(_: &crate::types::PyType) {}
#[args(args = "*", kwds = "**")]
fn __call__(
&self,
_args: &::pyo3::types::PyTuple,
_kwds: ::std::option::Option<&::pyo3::types::PyDict>,
) -> ::pyo3::PyResult<i32> {
_args: &crate::types::PyTuple,
_kwds: ::std::option::Option<&crate::types::PyDict>,
) -> crate::PyResult<i32> {
::std::panic!("unimplemented isn't hygienic before 1.50")
}
#[new]
@ -391,8 +394,8 @@ impl Dummy {
fn __richcmp__(
&self,
other: &Self,
op: ::pyo3::class::basic::CompareOp,
) -> ::pyo3::PyResult<bool> {
op: crate::class::basic::CompareOp,
) -> crate::PyResult<bool> {
::std::result::Result::Ok(false)
}
// PyGcProtocol

View file

@ -0,0 +1,23 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[crate::pyfunction]
#[pyo3(crate = "crate")]
fn do_something(x: i32) -> crate::PyResult<i32> {
::std::result::Result::Ok(x)
}
#[crate::pymodule]
#[pyo3(crate = "crate")]
fn foo(_py: crate::Python, _m: &crate::types::PyModule) -> crate::PyResult<()> {
::std::result::Result::Ok(())
}
#[crate::pymodule]
#[pyo3(crate = "crate")]
fn my_module(_py: crate::Python, m: &crate::types::PyModule) -> crate::PyResult<()> {
m.add_function(crate::wrap_pyfunction!(do_something, m)?)?;
m.add_wrapped(crate::wrap_pymodule!(foo))?;
::std::result::Result::Ok(())
}

View file

@ -1,25 +0,0 @@
#![no_implicit_prelude]
#[derive(::pyo3::FromPyObject)]
struct Derive1(i32); // newtype case
#[derive(::pyo3::FromPyObject)]
#[allow(dead_code)]
struct Derive2(i32, i32); // tuple case
#[derive(::pyo3::FromPyObject)]
#[allow(dead_code)]
struct Derive3 {
f: i32,
g: i32,
} // struct case
#[derive(::pyo3::FromPyObject)]
#[allow(dead_code)]
enum Derive4 {
A(i32),
B { f: i32 },
} // enum case
::pyo3::create_exception!(mymodule, CustomError, ::pyo3::exceptions::PyException);
::pyo3::import_exception!(socket, gaierror);

View file

@ -1,15 +0,0 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[::pyo3::pyfunction]
fn do_something(x: i32) -> ::pyo3::PyResult<i32> {
::std::result::Result::Ok(x)
}
#[test]
fn invoke_wrap_pyfunction() {
::pyo3::Python::with_gil(|py| {
let func = ::pyo3::wrap_pyfunction!(do_something)(py).unwrap();
::pyo3::py_run!(py, func, r#"func(5)"#);
});
}

View file

@ -1,20 +0,0 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[::pyo3::pyfunction]
fn do_something(x: i32) -> ::pyo3::PyResult<i32> {
::std::result::Result::Ok(x)
}
#[::pyo3::pymodule]
fn foo(_py: ::pyo3::Python, _m: &::pyo3::types::PyModule) -> ::pyo3::PyResult<()> {
::std::result::Result::Ok(())
}
#[::pyo3::pymodule]
fn my_module(_py: ::pyo3::Python, m: &::pyo3::types::PyModule) -> ::pyo3::PyResult<()> {
m.add_function(::pyo3::wrap_pyfunction!(do_something, m)?)?;
m.add_wrapped(::pyo3::wrap_pymodule!(foo))?;
::std::result::Result::Ok(())
}

View file

@ -1,58 +0,0 @@
#![no_implicit_prelude]
#![allow(unused_variables)]
#[::pyo3::pyclass]
#[derive(::std::clone::Clone)]
pub struct Foo;
#[::pyo3::pyclass]
pub struct Foo2;
#[::pyo3::pyclass(
name = "ActuallyBar",
freelist = 8,
weakref,
unsendable,
gc,
subclass,
extends = ::pyo3::types::PyAny,
module = "Spam"
)]
pub struct Bar {
#[pyo3(get, set)]
a: u8,
#[pyo3(get, set)]
b: Foo,
#[pyo3(get, set)]
c: ::std::option::Option<::pyo3::Py<Foo2>>,
}
#[::pyo3::pyproto]
impl ::pyo3::class::gc::PyGCProtocol for Bar {
fn __traverse__(
&self,
visit: ::pyo3::class::gc::PyVisit,
) -> ::std::result::Result<(), ::pyo3::class::gc::PyTraverseError> {
if let ::std::option::Option::Some(obj) = &self.c {
visit.call(obj)?
}
::std::result::Result::Ok(())
}
fn __clear__(&mut self) {
self.c = ::std::option::Option::None;
}
}
#[cfg(not(Py_LIMITED_API))]
#[::pyo3::pyproto]
impl ::pyo3::class::PyBufferProtocol for Bar {
fn bf_getbuffer(
_s: ::pyo3::PyRefMut<Self>,
_v: *mut ::pyo3::ffi::Py_buffer,
_f: ::std::os::raw::c_int,
) -> ::pyo3::PyResult<()> {
::std::panic!("unimplemented isn't hygienic before 1.50")
}
fn bf_releasebuffer(_s: ::pyo3::PyRefMut<Self>, _v: *mut ::pyo3::ffi::Py_buffer) {}
}

View file

@ -1,10 +0,0 @@
#![cfg(feature = "macros")]
mod hygiene {
mod misc;
mod pyclass;
mod pyfunction;
mod pymethods;
mod pymodule;
mod pyproto;
}

View file

@ -132,7 +132,7 @@ error: only one of `attribute` or `item` can be provided
118 | #[pyo3(item, attribute)]
| ^
error: expected `transparent` or `annotation`
error: expected one of: `transparent`, `annotation`, `crate`
--> tests/ui/invalid_frompy_derive.rs:123:8
|
123 | #[pyo3(unknown = "should not work")]