allow `#[pymodule(...)]` to accept all relevant `#[pyo3(...)]` options (#4330)
This commit is contained in:
parent
6be80647cb
commit
a5a3f3f7f2
|
@ -75,8 +75,7 @@ impl ExampleContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "getitem")]
|
||||||
#[pyo3(name = "getitem")]
|
|
||||||
fn example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
// ? -https://github.com/PyO3/maturin/issues/475
|
// ? -https://github.com/PyO3/maturin/issues/475
|
||||||
m.add_class::<ExampleContainer>()?;
|
m.add_class::<ExampleContainer>()?;
|
||||||
|
|
|
@ -31,8 +31,7 @@ fn double(x: usize) -> usize {
|
||||||
x * 2
|
x * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "custom_name")]
|
||||||
#[pyo3(name = "custom_name")]
|
|
||||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(double, m)?)
|
m.add_function(wrap_pyfunction!(double, m)?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
`#[pymodule(...)]` now directly accepts all relevant `#[pyo3(...)]` options.
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attributes::{
|
attributes::{
|
||||||
self, take_attributes, take_pyo3_options, CrateAttribute, ModuleAttribute, NameAttribute,
|
self, kw, take_attributes, take_pyo3_options, CrateAttribute, ModuleAttribute,
|
||||||
SubmoduleAttribute,
|
NameAttribute, SubmoduleAttribute,
|
||||||
},
|
},
|
||||||
get_doc,
|
get_doc,
|
||||||
pyclass::PyClassPyO3Option,
|
pyclass::PyClassPyO3Option,
|
||||||
|
@ -16,7 +16,7 @@ use std::ffi::CString;
|
||||||
use syn::{
|
use syn::{
|
||||||
ext::IdentExt,
|
ext::IdentExt,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_quote,
|
parse_quote, parse_quote_spanned,
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::Comma,
|
token::Comma,
|
||||||
|
@ -26,105 +26,89 @@ use syn::{
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PyModuleOptions {
|
pub struct PyModuleOptions {
|
||||||
krate: Option<CrateAttribute>,
|
krate: Option<CrateAttribute>,
|
||||||
name: Option<syn::Ident>,
|
name: Option<NameAttribute>,
|
||||||
module: Option<ModuleAttribute>,
|
module: Option<ModuleAttribute>,
|
||||||
is_submodule: bool,
|
submodule: Option<kw::submodule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyModuleOptions {
|
impl Parse for PyModuleOptions {
|
||||||
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> Result<Self> {
|
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||||
let mut options: PyModuleOptions = Default::default();
|
let mut options: PyModuleOptions = Default::default();
|
||||||
|
|
||||||
for option in take_pyo3_options(attrs)? {
|
options.add_attributes(
|
||||||
match option {
|
Punctuated::<PyModulePyO3Option, syn::Token![,]>::parse_terminated(input)?,
|
||||||
PyModulePyO3Option::Name(name) => options.set_name(name.value.0)?,
|
)?;
|
||||||
PyModulePyO3Option::Crate(path) => options.set_crate(path)?,
|
|
||||||
PyModulePyO3Option::Module(module) => options.set_module(module)?,
|
|
||||||
PyModulePyO3Option::Submodule(submod) => options.set_submodule(submod)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(options)
|
Ok(options)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_name(&mut self, name: syn::Ident) -> Result<()> {
|
impl PyModuleOptions {
|
||||||
ensure_spanned!(
|
fn take_pyo3_options(&mut self, attrs: &mut Vec<syn::Attribute>) -> Result<()> {
|
||||||
self.name.is_none(),
|
self.add_attributes(take_pyo3_options(attrs)?)
|
||||||
name.span() => "`name` may only be specified once"
|
|
||||||
);
|
|
||||||
|
|
||||||
self.name = Some(name);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_crate(&mut self, path: CrateAttribute) -> Result<()> {
|
fn add_attributes(
|
||||||
ensure_spanned!(
|
&mut self,
|
||||||
self.krate.is_none(),
|
attrs: impl IntoIterator<Item = PyModulePyO3Option>,
|
||||||
path.span() => "`crate` may only be specified once"
|
) -> Result<()> {
|
||||||
);
|
macro_rules! set_option {
|
||||||
|
($key:ident $(, $extra:literal)?) => {
|
||||||
self.krate = Some(path);
|
{
|
||||||
Ok(())
|
ensure_spanned!(
|
||||||
}
|
self.$key.is_none(),
|
||||||
|
$key.span() => concat!("`", stringify!($key), "` may only be specified once" $(, $extra)?)
|
||||||
fn set_module(&mut self, name: ModuleAttribute) -> Result<()> {
|
);
|
||||||
ensure_spanned!(
|
self.$key = Some($key);
|
||||||
self.module.is_none(),
|
}
|
||||||
name.span() => "`module` may only be specified once"
|
};
|
||||||
);
|
}
|
||||||
|
for attr in attrs {
|
||||||
self.module = Some(name);
|
match attr {
|
||||||
Ok(())
|
PyModulePyO3Option::Crate(krate) => set_option!(krate),
|
||||||
}
|
PyModulePyO3Option::Name(name) => set_option!(name),
|
||||||
|
PyModulePyO3Option::Module(module) => set_option!(module),
|
||||||
fn set_submodule(&mut self, submod: SubmoduleAttribute) -> Result<()> {
|
PyModulePyO3Option::Submodule(submodule) => set_option!(
|
||||||
ensure_spanned!(
|
submodule,
|
||||||
!self.is_submodule,
|
" (it is implicitly always specified for nested modules)"
|
||||||
submod.span() => "`submodule` may only be specified once (it is implicitly always specified for nested modules)"
|
),
|
||||||
);
|
}
|
||||||
|
}
|
||||||
self.is_submodule = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pymodule_module_impl(
|
pub fn pymodule_module_impl(
|
||||||
mut module: syn::ItemMod,
|
module: &mut syn::ItemMod,
|
||||||
mut is_submodule: bool,
|
mut options: PyModuleOptions,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let syn::ItemMod {
|
let syn::ItemMod {
|
||||||
attrs,
|
attrs,
|
||||||
vis,
|
vis,
|
||||||
unsafety: _,
|
unsafety: _,
|
||||||
ident,
|
ident,
|
||||||
mod_token: _,
|
mod_token,
|
||||||
content,
|
content,
|
||||||
semi: _,
|
semi: _,
|
||||||
} = &mut module;
|
} = module;
|
||||||
let items = if let Some((_, items)) = content {
|
let items = if let Some((_, items)) = content {
|
||||||
items
|
items
|
||||||
} else {
|
} else {
|
||||||
bail_spanned!(module.span() => "`#[pymodule]` can only be used on inline modules")
|
bail_spanned!(mod_token.span() => "`#[pymodule]` can only be used on inline modules")
|
||||||
};
|
};
|
||||||
let options = PyModuleOptions::from_attrs(attrs)?;
|
options.take_pyo3_options(attrs)?;
|
||||||
let ctx = &Ctx::new(&options.krate, None);
|
let ctx = &Ctx::new(&options.krate, None);
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let doc = get_doc(attrs, None, ctx);
|
let doc = get_doc(attrs, None, ctx);
|
||||||
let name = options.name.unwrap_or_else(|| ident.unraw());
|
let name = options
|
||||||
|
.name
|
||||||
|
.map_or_else(|| ident.unraw(), |name| name.value.0);
|
||||||
let full_name = if let Some(module) = &options.module {
|
let full_name = if let Some(module) = &options.module {
|
||||||
format!("{}.{}", module.value.value(), name)
|
format!("{}.{}", module.value.value(), name)
|
||||||
} else {
|
} else {
|
||||||
name.to_string()
|
name.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
is_submodule = match (is_submodule, options.is_submodule) {
|
|
||||||
(true, true) => {
|
|
||||||
bail_spanned!(module.span() => "`submodule` may only be specified once (it is implicitly always specified for nested modules)")
|
|
||||||
}
|
|
||||||
(false, false) => false,
|
|
||||||
(true, false) | (false, true) => true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut module_items = Vec::new();
|
let mut module_items = Vec::new();
|
||||||
let mut module_items_cfg_attrs = Vec::new();
|
let mut module_items_cfg_attrs = Vec::new();
|
||||||
|
|
||||||
|
@ -280,7 +264,9 @@ pub fn pymodule_module_impl(
|
||||||
)? {
|
)? {
|
||||||
set_module_attribute(&mut item_mod.attrs, &full_name);
|
set_module_attribute(&mut item_mod.attrs, &full_name);
|
||||||
}
|
}
|
||||||
item_mod.attrs.push(parse_quote!(#[pyo3(submodule)]));
|
item_mod
|
||||||
|
.attrs
|
||||||
|
.push(parse_quote_spanned!(item_mod.mod_token.span()=> #[pyo3(submodule)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item::ForeignMod(item) => {
|
Item::ForeignMod(item) => {
|
||||||
|
@ -358,10 +344,11 @@ pub fn pymodule_module_impl(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
let initialization = module_initialization(&name, ctx, module_def, is_submodule);
|
let initialization = module_initialization(&name, ctx, module_def, options.submodule.is_some());
|
||||||
|
|
||||||
Ok(quote!(
|
Ok(quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#vis mod #ident {
|
#vis #mod_token #ident {
|
||||||
#(#items)*
|
#(#items)*
|
||||||
|
|
||||||
#initialization
|
#initialization
|
||||||
|
@ -381,13 +368,18 @@ pub fn pymodule_module_impl(
|
||||||
|
|
||||||
/// Generates the function that is called by the python interpreter to initialize the native
|
/// Generates the function that is called by the python interpreter to initialize the native
|
||||||
/// module
|
/// module
|
||||||
pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream> {
|
pub fn pymodule_function_impl(
|
||||||
let options = PyModuleOptions::from_attrs(&mut function.attrs)?;
|
function: &mut syn::ItemFn,
|
||||||
process_functions_in_module(&options, &mut function)?;
|
mut options: PyModuleOptions,
|
||||||
|
) -> Result<TokenStream> {
|
||||||
|
options.take_pyo3_options(&mut function.attrs)?;
|
||||||
|
process_functions_in_module(&options, function)?;
|
||||||
let ctx = &Ctx::new(&options.krate, None);
|
let ctx = &Ctx::new(&options.krate, None);
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let ident = &function.sig.ident;
|
let ident = &function.sig.ident;
|
||||||
let name = options.name.unwrap_or_else(|| ident.unraw());
|
let name = options
|
||||||
|
.name
|
||||||
|
.map_or_else(|| ident.unraw(), |name| name.value.0);
|
||||||
let vis = &function.vis;
|
let vis = &function.vis;
|
||||||
let doc = get_doc(&function.attrs, None, ctx);
|
let doc = get_doc(&function.attrs, None, ctx);
|
||||||
|
|
||||||
|
@ -402,7 +394,6 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
|
||||||
.push(quote!(::std::convert::Into::into(#pyo3_path::impl_::pymethods::BoundRef(module))));
|
.push(quote!(::std::convert::Into::into(#pyo3_path::impl_::pymethods::BoundRef(module))));
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#function
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#vis mod #ident {
|
#vis mod #ident {
|
||||||
#initialization
|
#initialization
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
|
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use pyo3_macros_backend::{
|
use pyo3_macros_backend::{
|
||||||
build_derive_from_pyobject, build_py_class, build_py_enum, build_py_function, build_py_methods,
|
build_derive_from_pyobject, build_py_class, build_py_enum, build_py_function, build_py_methods,
|
||||||
pymodule_function_impl, pymodule_module_impl, PyClassArgs, PyClassMethodsType,
|
pymodule_function_impl, pymodule_module_impl, PyClassArgs, PyClassMethodsType,
|
||||||
PyFunctionOptions,
|
PyFunctionOptions, PyModuleOptions,
|
||||||
};
|
};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse::Nothing, parse_macro_input, Item};
|
use syn::{parse_macro_input, Item};
|
||||||
|
|
||||||
/// A proc macro used to implement Python modules.
|
/// A proc macro used to implement Python modules.
|
||||||
///
|
///
|
||||||
|
@ -24,6 +24,9 @@ use syn::{parse::Nothing, parse_macro_input, Item};
|
||||||
/// | Annotation | Description |
|
/// | Annotation | Description |
|
||||||
/// | :- | :- |
|
/// | :- | :- |
|
||||||
/// | `#[pyo3(name = "...")]` | Defines the name of the module in Python. |
|
/// | `#[pyo3(name = "...")]` | Defines the name of the module in Python. |
|
||||||
|
/// | `#[pyo3(submodule)]` | Skips adding a `PyInit_` FFI symbol to the compiled binary. |
|
||||||
|
/// | `#[pyo3(module = "...")]` | Defines the Python `dotted.path` to the parent module for use in introspection. |
|
||||||
|
/// | `#[pyo3(crate = "pyo3")]` | Defines the path to PyO3 to use code generated by the macro. |
|
||||||
///
|
///
|
||||||
/// For more on creating Python modules see the [module section of the guide][1].
|
/// For more on creating Python modules see the [module section of the guide][1].
|
||||||
///
|
///
|
||||||
|
@ -35,32 +38,29 @@ use syn::{parse::Nothing, parse_macro_input, Item};
|
||||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/module.html")]
|
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/module.html")]
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
match parse_macro_input!(input as Item) {
|
let options = parse_macro_input!(args as PyModuleOptions);
|
||||||
|
|
||||||
|
let mut ast = parse_macro_input!(input as Item);
|
||||||
|
let expanded = match &mut ast {
|
||||||
Item::Mod(module) => {
|
Item::Mod(module) => {
|
||||||
let is_submodule = match parse_macro_input!(args as Option<syn::Ident>) {
|
match pymodule_module_impl(module, options) {
|
||||||
Some(i) if i == "submodule" => true,
|
// #[pymodule] on a module will rebuild the original ast, so we don't emit it here
|
||||||
Some(_) => {
|
Ok(expanded) => return expanded.into(),
|
||||||
return syn::Error::new(
|
Err(e) => Err(e),
|
||||||
Span::call_site(),
|
}
|
||||||
"#[pymodule] only accepts submodule as an argument",
|
|
||||||
)
|
|
||||||
.into_compile_error()
|
|
||||||
.into();
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
};
|
|
||||||
pymodule_module_impl(module, is_submodule)
|
|
||||||
}
|
|
||||||
Item::Fn(function) => {
|
|
||||||
parse_macro_input!(args as Nothing);
|
|
||||||
pymodule_function_impl(function)
|
|
||||||
}
|
}
|
||||||
|
Item::Fn(function) => pymodule_function_impl(function, options),
|
||||||
unsupported => Err(syn::Error::new_spanned(
|
unsupported => Err(syn::Error::new_spanned(
|
||||||
unsupported,
|
unsupported,
|
||||||
"#[pymodule] only supports modules and functions.",
|
"#[pymodule] only supports modules and functions.",
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
.unwrap_or_compile_error()
|
.unwrap_or_compile_error();
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
#ast
|
||||||
|
#expanded
|
||||||
|
)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,7 @@ create_exception!(
|
||||||
"Some description."
|
"Some description."
|
||||||
);
|
);
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(submodule)]
|
||||||
#[pyo3(submodule)]
|
|
||||||
mod external_submodule {}
|
mod external_submodule {}
|
||||||
|
|
||||||
/// A module written using declarative syntax.
|
/// A module written using declarative syntax.
|
||||||
|
@ -144,8 +143,7 @@ mod declarative_submodule {
|
||||||
use super::{double, double_value};
|
use super::{double, double_value};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "declarative_module_renamed")]
|
||||||
#[pyo3(name = "declarative_module_renamed")]
|
|
||||||
mod declarative_module2 {
|
mod declarative_module2 {
|
||||||
#[pymodule_export]
|
#[pymodule_export]
|
||||||
use super::double;
|
use super::double;
|
||||||
|
|
|
@ -138,8 +138,7 @@ fn test_module_with_explicit_py_arg() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "other_name")]
|
||||||
#[pyo3(name = "other_name")]
|
|
||||||
fn some_name(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn some_name(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add("other_name", "other_name")?;
|
m.add("other_name", "other_name")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -4,8 +4,14 @@ error: `submodule` may only be specified once (it is implicitly always specified
|
||||||
4 | mod submod {}
|
4 | mod submod {}
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error[E0433]: failed to resolve: use of undeclared crate or module `submod`
|
error[E0425]: cannot find value `_PYO3_DEF` in module `submod`
|
||||||
--> tests/ui/duplicate_pymodule_submodule.rs:4:6
|
--> tests/ui/duplicate_pymodule_submodule.rs:1:1
|
||||||
|
|
|
||||||
|
1 | #[pyo3::pymodule]
|
||||||
|
| ^^^^^^^^^^^^^^^^^ not found in `submod`
|
||||||
|
|
|
||||||
|
= note: this error originates in the attribute macro `pyo3::pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider importing this static
|
||||||
|
|
|
||||||
|
3 + use crate::mymodule::_PYO3_DEF;
|
||||||
|
|
|
|
||||||
4 | mod submod {}
|
|
||||||
| ^^^^^^ use of undeclared crate or module `submod`
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
// see invalid_pymodule_in_root.rs
|
|
@ -1,4 +1,4 @@
|
||||||
error: unexpected token
|
error: expected one of: `name`, `crate`, `module`, `submodule`
|
||||||
--> tests/ui/invalid_pymodule_args.rs:3:12
|
--> tests/ui/invalid_pymodule_args.rs:3:12
|
||||||
|
|
|
|
||||||
3 | #[pymodule(some_arg)]
|
3 | #[pymodule(some_arg)]
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: #[pymodule] cannot import glob statements
|
error: #[pymodule] cannot import glob statements
|
||||||
--> tests/ui/invalid_pymodule_glob.rs:11:16
|
--> tests/ui/invalid_pymodule_glob.rs:13:16
|
||||||
|
|
|
|
||||||
11 | use super::*;
|
13 | use super::*;
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
|
#[path = "empty.rs"] // to silence error related to missing file
|
||||||
mod invalid_pymodule_in_root_module;
|
mod invalid_pymodule_in_root_module;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
error[E0658]: non-inline modules in proc macro input are unstable
|
error[E0658]: non-inline modules in proc macro input are unstable
|
||||||
--> tests/ui/invalid_pymodule_in_root.rs:4:1
|
--> tests/ui/invalid_pymodule_in_root.rs:5:1
|
||||||
|
|
|
|
||||||
4 | mod invalid_pymodule_in_root_module;
|
5 | mod invalid_pymodule_in_root_module;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information
|
= note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information
|
||||||
|
|
||||||
error: `#[pymodule]` can only be used on inline modules
|
error: `#[pymodule]` can only be used on inline modules
|
||||||
--> tests/ui/invalid_pymodule_in_root.rs:4:1
|
--> tests/ui/invalid_pymodule_in_root.rs:5:1
|
||||||
|
|
|
|
||||||
4 | mod invalid_pymodule_in_root_module;
|
5 | mod invalid_pymodule_in_root_module;
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
@ -3,3 +3,9 @@ error: `#[pymodule_export]` may only be used on `use` statements
|
||||||
|
|
|
|
||||||
5 | #[pymodule_export]
|
5 | #[pymodule_export]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: cannot find attribute `pymodule_export` in this scope
|
||||||
|
--> tests/ui/invalid_pymodule_trait.rs:5:7
|
||||||
|
|
|
||||||
|
5 | #[pymodule_export]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -2,13 +2,15 @@ use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
mod module {
|
mod module {
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pymodule_init]
|
#[pymodule_init]
|
||||||
fn init(m: &PyModule) -> PyResult<()> {
|
fn init(_m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule_init]
|
#[pymodule_init]
|
||||||
fn init2(m: &PyModule) -> PyResult<()> {
|
fn init2(_m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: only one `#[pymodule_init]` may be specified
|
error: only one `#[pymodule_init]` may be specified
|
||||||
--> tests/ui/invalid_pymodule_two_pymodule_init.rs:11:5
|
--> tests/ui/invalid_pymodule_two_pymodule_init.rs:13:5
|
||||||
|
|
|
|
||||||
11 | fn init2(m: &PyModule) -> PyResult<()> {
|
13 | fn init2(_m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
| ^^
|
| ^^
|
||||||
|
|
Loading…
Reference in New Issue