Skip to content

Commit 01d11e1

Browse files
committed
Merge branch 'main' into tpt/dynamic-type
# Conflicts: # src/types/sequence.rs
2 parents f5fbe62 + 6a6ed99 commit 01d11e1

35 files changed

+802
-347
lines changed

README.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,18 @@ pyo3 = { version = "0.26.0", features = ["extension-module"] }
7777
**`src/lib.rs`**
7878

7979
```rust
80-
use pyo3::prelude::*;
81-
82-
/// Formats the sum of two numbers as string.
83-
#[pyfunction]
84-
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
85-
Ok((a + b).to_string())
86-
}
87-
88-
/// A Python module implemented in Rust. The name of this function must match
80+
/// A Python module implemented in Rust. The name of this module must match
8981
/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to
9082
/// import the module.
91-
#[pymodule]
92-
fn string_sum(m: &Bound<'_, PyModule>) -> PyResult<()> {
93-
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
94-
Ok(())
83+
#[pyo3::pymodule]
84+
mod string_sum {
85+
use pyo3::prelude::*;
86+
87+
/// Formats the sum of two numbers as string.
88+
#[pyfunction]
89+
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
90+
Ok((a + b).to_string())
91+
}
9592
}
9693
```
9794

emscripten/pybuilddir.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

guide/src/module.md

Lines changed: 67 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
You can create a module using `#[pymodule]`:
44

55
```rust,no_run
6+
# mod declarative_module_basic_test {
67
use pyo3::prelude::*;
78
89
#[pyfunction]
@@ -12,18 +13,28 @@ fn double(x: usize) -> usize {
1213
1314
/// This module is implemented in Rust.
1415
#[pymodule]
15-
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
16-
m.add_function(wrap_pyfunction!(double, m)?)
16+
mod my_extension {
17+
use pyo3::prelude::*;
18+
19+
#[pymodule_export]
20+
use super::double; // The double function is made available from Python, works also with classes
21+
22+
#[pyfunction] // Inline definition of a pyfunction, also made availlable to Python
23+
fn triple(x: usize) -> usize {
24+
x * 3
25+
}
1726
}
27+
# }
1828
```
1929

20-
The `#[pymodule]` procedural macro takes care of exporting the initialization function of your
21-
module to Python.
30+
The `#[pymodule]` procedural macro takes care of creating the initialization function of your
31+
module and exposing it to Python.
2232

23-
The module's name defaults to the name of the Rust function. You can override the module name by
33+
The module's name defaults to the name of the Rust module. You can override the module name by
2434
using `#[pyo3(name = "custom_name")]`:
2535

2636
```rust,no_run
37+
# mod declarative_module_custom_name_test {
2738
use pyo3::prelude::*;
2839
2940
#[pyfunction]
@@ -32,9 +43,11 @@ fn double(x: usize) -> usize {
3243
}
3344
3445
#[pymodule(name = "custom_name")]
35-
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
36-
m.add_function(wrap_pyfunction!(double, m)?)
46+
mod my_extension {
47+
#[pymodule_export]
48+
use super::double;
3749
}
50+
# }
3851
```
3952

4053
The name of the module must match the name of the `.so` or `.pyd`
@@ -48,8 +61,7 @@ To import the module, either:
4861

4962
## Documentation
5063

51-
The [Rust doc comments](https://doc.rust-lang.org/stable/book/ch03-04-comments.html) of the module
52-
initialization function will be applied automatically as the Python docstring of your module.
64+
The [Rust doc comments](https://doc.rust-lang.org/stable/book/ch03-04-comments.html) of the Rust module will be applied automatically as the Python docstring of your module.
5365

5466
For example, building off of the above code, this will print `This module is implemented in Rust.`:
5567

@@ -61,75 +73,66 @@ print(my_extension.__doc__)
6173

6274
## Python submodules
6375

64-
You can create a module hierarchy within a single extension module by using
65-
[`Bound<'_, PyModule>::add_submodule()`]({{#PYO3_DOCS_URL}}/pyo3/prelude/trait.PyModuleMethods.html#tymethod.add_submodule).
66-
For example, you could define the modules `parent_module` and `parent_module.child_module`.
76+
You can create a module hierarchy within a single extension module by just `use`ing modules like functions or classes.
77+
For example, you could define the modules `parent_module` and `parent_module.child_module`:
6778

6879
```rust
6980
use pyo3::prelude::*;
7081

7182
#[pymodule]
72-
fn parent_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
73-
register_child_module(m)?;
74-
Ok(())
83+
mod parent_module {
84+
#[pymodule_export]
85+
use super::child_module;
7586
}
7687

77-
fn register_child_module(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
78-
let child_module = PyModule::new(parent_module.py(), "child_module")?;
79-
child_module.add_function(wrap_pyfunction!(func, &child_module)?)?;
80-
parent_module.add_submodule(&child_module)
88+
#[pymodule]
89+
mod child_module {
90+
#[pymodule_export]
91+
use super::func;
8192
}
8293

8394
#[pyfunction]
8495
fn func() -> String {
8596
"func".to_string()
8697
}
87-
88-
# Python::attach(|py| {
89-
# use pyo3::wrap_pymodule;
90-
# use pyo3::types::IntoPyDict;
91-
# use pyo3::ffi::c_str;
92-
# let parent_module = wrap_pymodule!(parent_module)(py);
93-
# let ctx = [("parent_module", parent_module)].into_py_dict(py).unwrap();
9498
#
95-
# py.run(c_str!("assert parent_module.child_module.func() == 'func'"), None, Some(&ctx)).unwrap();
96-
# })
99+
# fn main() {
100+
# Python::attach(|py| {
101+
# use pyo3::wrap_pymodule;
102+
# use pyo3::types::IntoPyDict;
103+
# use pyo3::ffi::c_str;
104+
# let parent_module = wrap_pymodule!(parent_module)(py);
105+
# let ctx = [("parent_module", parent_module)].into_py_dict(py).unwrap();
106+
#
107+
# py.run(c_str!("assert parent_module.child_module.func() == 'func'"), None, Some(&ctx)).unwrap();
108+
# })
109+
}
97110
```
98111

99112
Note that this does not define a package, so this won’t allow Python code to directly import
100113
submodules by using `from parent_module import child_module`. For more information, see
101114
[#759](https://github.com/PyO3/pyo3/issues/759) and
102115
[#1517](https://github.com/PyO3/pyo3/issues/1517#issuecomment-808664021).
103116

104-
It is not necessary to add `#[pymodule]` on nested modules, which is only required on the top-level module.
117+
You can provide the `submodule` argument to `#[pymodule()]` for modules that are not top-level modules in order for them to properly generate the `#[pyclass]` `module` attribute automatically.
105118

106-
## Declarative modules
119+
## Inline declaration
107120

108-
Another syntax based on Rust inline modules is also available to declare modules.
121+
It is possible to declare functions, classes, sub-modules and constants inline in a module:
109122

110123
For example:
111124
```rust,no_run
112125
# mod declarative_module_test {
113-
use pyo3::prelude::*;
114-
115-
#[pyfunction]
116-
fn double(x: usize) -> usize {
117-
x * 2
118-
}
119-
120-
#[pymodule]
126+
#[pyo3::pymodule]
121127
mod my_extension {
122-
use super::*;
123-
124-
#[pymodule_export]
125-
use super::double; // Exports the double function as part of the module
128+
use pyo3::prelude::*;
126129
127130
#[pymodule_export]
128131
const PI: f64 = std::f64::consts::PI; // Exports PI constant as part of the module
129132
130133
#[pyfunction] // This will be part of the module
131-
fn triple(x: usize) -> usize {
132-
x * 3
134+
fn double(x: usize) -> usize {
135+
x * 2
133136
}
134137
135138
#[pyclass] // This will be part of the module
@@ -138,47 +141,38 @@ mod my_extension {
138141
#[pymodule]
139142
mod submodule {
140143
// This is a submodule
141-
}
144+
use pyo3::prelude::*;
142145
143-
#[pymodule_init]
144-
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
145-
// Arbitrary code to run at the module initialization
146-
m.add("double2", m.getattr("double")?)
146+
#[pyclass]
147+
struct Nested;
147148
}
148149
}
149150
# }
150151
```
151152

152-
The `#[pymodule]` macro automatically sets the `module` attribute of the `#[pyclass]` macros declared inside of it with its name.
153+
In this case, `#[pymodule]` macro automatically sets the `module` attribute of the `#[pyclass]` macros declared inside of it with its name.
153154
For nested modules, the name of the parent module is automatically added.
154-
In the following example, the `Unit` class will have for `module` `my_extension.submodule` because it is properly nested
155-
but the `Ext` class will have for `module` the default `builtins` because it not nested.
156-
157-
```rust,no_run
158-
# mod declarative_module_module_attr_test {
159-
use pyo3::prelude::*;
155+
In the previous example, the `Nested` class will have for `module` `my_extension.submodule`.
160156

161-
#[pyclass]
162-
struct Ext;
157+
## Procedural initialization
163158

164-
#[pymodule]
159+
If the macros provided by PyO3 are not enough, it is possible to run code at the module initialization:
160+
```rust,no_run
161+
# mod procedural_module_test {
162+
#[pyo3::pymodule]
165163
mod my_extension {
166-
use super::*;
167-
168-
#[pymodule_export]
169-
use super::Ext;
164+
use pyo3::prelude::*;
170165
171-
#[pymodule]
172-
mod submodule {
173-
use super::*;
174-
// This is a submodule
166+
#[pyfunction]
167+
fn double(x: usize) -> usize {
168+
x * 2
169+
}
175170
176-
#[pyclass] // This will be part of the module
177-
struct Unit;
171+
#[pymodule_init]
172+
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
173+
// Arbitrary code to run at the module initialization
174+
m.add("double2", m.getattr("double")?)
178175
}
179176
}
180177
# }
181178
```
182-
It is possible to customize the `module` value for a `#[pymodule]` with the `#[pyo3(module = "MY_MODULE")]` option.
183-
184-
You can provide the `submodule` argument to `pymodule()` for modules that are not top-level modules -- it is automatically set for modules nested inside of a `#[pymodule]`.

newsfragments/5244.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Optimize `FromPyObject` implementations for `Vec<u8>` and `[u8; N]` from `bytes` and `bytearray`

newsfragments/5437.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add PyString::from_bytes. This saves a redundant UTF-8 validation check because Python internally validates the bytes again.

newsfragments/5442.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve `Debug` representation of `PyBuffer<T>`.

newsfragments/5444.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fix `OsStr` conversion for non-utf8 strings on windows

newsfragments/5445.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement `AsRef<[u8]>` for `PyBytes`

newsfragments/5450.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Introspection: change the way introspection data is emitted in the binaries to avoid a pointer indirection and simplify parsing.

newsfragments/5456.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix issue with `cargo vendor` caused by gitignored build artifact `emscripten/pybuilddir.txt`.

0 commit comments

Comments
 (0)