Stabilize declarative modules (#4257)
This commit is contained in:
parent
baae9291cc
commit
ddff8bea25
|
@ -75,9 +75,6 @@ experimental-async = ["macros", "pyo3-macros/experimental-async"]
|
||||||
# and IntoPy traits
|
# and IntoPy traits
|
||||||
experimental-inspect = []
|
experimental-inspect = []
|
||||||
|
|
||||||
# Enables annotating Rust inline modules with #[pymodule] to build Python modules declaratively
|
|
||||||
experimental-declarative-modules = ["pyo3-macros/experimental-declarative-modules", "macros"]
|
|
||||||
|
|
||||||
# Enables macros: #[pyclass], #[pymodule], #[pyfunction] etc.
|
# Enables macros: #[pyclass], #[pymodule], #[pyfunction] etc.
|
||||||
macros = ["pyo3-macros", "indoc", "unindent"]
|
macros = ["pyo3-macros", "indoc", "unindent"]
|
||||||
|
|
||||||
|
@ -125,7 +122,6 @@ full = [
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"either",
|
"either",
|
||||||
"experimental-async",
|
"experimental-async",
|
||||||
"experimental-declarative-modules",
|
|
||||||
"experimental-inspect",
|
"experimental-inspect",
|
||||||
"eyre",
|
"eyre",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
|
|
@ -57,12 +57,6 @@ This feature adds support for `async fn` in `#[pyfunction]` and `#[pymethods]`.
|
||||||
|
|
||||||
The feature has some unfinished refinements and performance improvements. To help finish this off, see [issue #1632](https://github.com/PyO3/pyo3/issues/1632) and its associated draft PRs.
|
The feature has some unfinished refinements and performance improvements. To help finish this off, see [issue #1632](https://github.com/PyO3/pyo3/issues/1632) and its associated draft PRs.
|
||||||
|
|
||||||
### `experimental-declarative-modules`
|
|
||||||
|
|
||||||
This feature allows to declare Python modules using `#[pymodule] mod my_module { ... }` syntax.
|
|
||||||
|
|
||||||
The feature has some unfinished refinements and edge cases. To help finish this off, see [issue #3900](https://github.com/PyO3/pyo3/issues/3900).
|
|
||||||
|
|
||||||
### `experimental-inspect`
|
### `experimental-inspect`
|
||||||
|
|
||||||
This feature adds the `pyo3::inspect` module, as well as `IntoPy::type_output` and `FromPyObject::type_input` APIs to produce Python type "annotations" for Rust types.
|
This feature adds the `pyo3::inspect` module, as well as `IntoPy::type_output` and `FromPyObject::type_input` APIs to produce Python type "annotations" for Rust types.
|
||||||
|
|
|
@ -106,14 +106,12 @@ submodules by using `from parent_module import child_module`. For more informati
|
||||||
|
|
||||||
It is not necessary to add `#[pymodule]` on nested modules, which is only required on the top-level module.
|
It is not necessary to add `#[pymodule]` on nested modules, which is only required on the top-level module.
|
||||||
|
|
||||||
## Declarative modules (experimental)
|
## Declarative modules
|
||||||
|
|
||||||
Another syntax based on Rust inline modules is also available to declare modules.
|
Another syntax based on Rust inline modules is also available to declare modules.
|
||||||
The `experimental-declarative-modules` feature must be enabled to use it.
|
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```rust
|
```rust
|
||||||
# #[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
# mod declarative_module_test {
|
# mod declarative_module_test {
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
@ -157,7 +155,6 @@ For nested modules, the name of the parent module is automatically added.
|
||||||
In the following example, the `Unit` class will have for `module` `my_extension.submodule` because it is properly nested
|
In the following example, the `Unit` class will have for `module` `my_extension.submodule` because it is properly nested
|
||||||
but the `Ext` class will have for `module` the default `builtins` because it not nested.
|
but the `Ext` class will have for `module` the default `builtins` because it not nested.
|
||||||
```rust
|
```rust
|
||||||
# #[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
# mod declarative_module_module_attr_test {
|
# mod declarative_module_module_attr_test {
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
@ -184,7 +181,3 @@ mod my_extension {
|
||||||
```
|
```
|
||||||
It is possible to customize the `module` value for a `#[pymodule]` with the `#[pyo3(module = "MY_MODULE")]` option.
|
It is possible to customize the `module` value for a `#[pymodule]` with the `#[pyo3(module = "MY_MODULE")]` option.
|
||||||
|
|
||||||
Some changes are planned to this feature before stabilization, like automatically
|
|
||||||
filling submodules into `sys.modules` to allow easier imports (see [issue #759](https://github.com/PyO3/pyo3/issues/759)).
|
|
||||||
Macro names might also change.
|
|
||||||
See [issue #3900](https://github.com/PyO3/pyo3/issues/3900) to track this feature progress.
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
The `experimental-declarative-modules` feature is now stabilized and available by default
|
|
@ -16,7 +16,6 @@ proc-macro = true
|
||||||
[features]
|
[features]
|
||||||
multiple-pymethods = []
|
multiple-pymethods = []
|
||||||
experimental-async = ["pyo3-macros-backend/experimental-async"]
|
experimental-async = ["pyo3-macros-backend/experimental-async"]
|
||||||
experimental-declarative-modules = []
|
|
||||||
gil-refs = ["pyo3-macros-backend/gil-refs"]
|
gil-refs = ["pyo3-macros-backend/gil-refs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -37,14 +37,7 @@ use syn::{parse::Nothing, parse_macro_input, Item};
|
||||||
pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
parse_macro_input!(args as Nothing);
|
parse_macro_input!(args as Nothing);
|
||||||
match parse_macro_input!(input as Item) {
|
match parse_macro_input!(input as Item) {
|
||||||
Item::Mod(module) => if cfg!(feature = "experimental-declarative-modules") {
|
Item::Mod(module) => pymodule_module_impl(module),
|
||||||
pymodule_module_impl(module)
|
|
||||||
} else {
|
|
||||||
Err(syn::Error::new_spanned(
|
|
||||||
module,
|
|
||||||
"#[pymodule] requires the 'experimental-declarative-modules' feature to be used on Rust modules.",
|
|
||||||
))
|
|
||||||
},
|
|
||||||
Item::Fn(function) => pymodule_function_impl(function),
|
Item::Fn(function) => pymodule_function_impl(function),
|
||||||
unsupported => Err(syn::Error::new_spanned(
|
unsupported => Err(syn::Error::new_spanned(
|
||||||
unsupported,
|
unsupported,
|
||||||
|
|
|
@ -13,7 +13,6 @@ fn module_fn_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
mod module_mod_with_functions {
|
mod module_mod_with_functions {
|
||||||
#[pymodule_export]
|
#[pymodule_export]
|
||||||
|
@ -27,7 +26,6 @@ fn test_module_append_to_inittab() {
|
||||||
|
|
||||||
append_to_inittab!(module_fn_with_functions);
|
append_to_inittab!(module_fn_with_functions);
|
||||||
|
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
append_to_inittab!(module_mod_with_functions);
|
append_to_inittab!(module_mod_with_functions);
|
||||||
|
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
|
@ -43,7 +41,6 @@ assert module_fn_with_functions.foo() == 123
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
py.run_bound(
|
py.run_bound(
|
||||||
r#"
|
r#"
|
||||||
|
|
|
@ -52,13 +52,9 @@ fn test_compile_errors() {
|
||||||
t.compile_fail("tests/ui/not_send2.rs");
|
t.compile_fail("tests/ui/not_send2.rs");
|
||||||
t.compile_fail("tests/ui/get_set_all.rs");
|
t.compile_fail("tests/ui/get_set_all.rs");
|
||||||
t.compile_fail("tests/ui/traverse.rs");
|
t.compile_fail("tests/ui/traverse.rs");
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
t.compile_fail("tests/ui/invalid_pymodule_in_root.rs");
|
t.compile_fail("tests/ui/invalid_pymodule_in_root.rs");
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
t.compile_fail("tests/ui/invalid_pymodule_glob.rs");
|
t.compile_fail("tests/ui/invalid_pymodule_glob.rs");
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
t.compile_fail("tests/ui/invalid_pymodule_trait.rs");
|
t.compile_fail("tests/ui/invalid_pymodule_trait.rs");
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
t.compile_fail("tests/ui/invalid_pymodule_two_pymodule_init.rs");
|
t.compile_fail("tests/ui/invalid_pymodule_two_pymodule_init.rs");
|
||||||
#[cfg(feature = "experimental-async")]
|
#[cfg(feature = "experimental-async")]
|
||||||
#[cfg(any(not(Py_LIMITED_API), Py_3_10))] // to avoid PyFunctionArgument for &str
|
#[cfg(any(not(Py_LIMITED_API), Py_3_10))] // to avoid PyFunctionArgument for &str
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![cfg(feature = "experimental-declarative-modules")]
|
#![cfg(feature = "macros")]
|
||||||
|
|
||||||
use pyo3::create_exception;
|
use pyo3::create_exception;
|
||||||
use pyo3::exceptions::PyException;
|
use pyo3::exceptions::PyException;
|
||||||
|
|
|
@ -9,7 +9,6 @@ pub fn python_module(_m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "experimental-declarative-modules")]
|
|
||||||
/// Some module documentation
|
/// Some module documentation
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
pub mod declarative_python_module {}
|
pub mod declarative_python_module {}
|
||||||
|
|
Loading…
Reference in New Issue