Skip to content

Commit 9e74c85

Browse files
authored
add PyModule::new_bound and PyModule::import_bound (#3775)
* add `PyModule::new` and `PyModule::import_bound` * review: Icxolu feedback
1 parent c4f6665 commit 9e74c85

32 files changed

+229
-190
lines changed

examples/maturin-starter/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ fn maturin_starter(py: Python<'_>, m: &PyModule) -> PyResult<()> {
2727
// Inserting to sys.modules allows importing submodules nicely from Python
2828
// e.g. from maturin_starter.submodule import SubmoduleClass
2929

30-
let sys = PyModule::import(py, "sys")?;
31-
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?;
30+
let sys = PyModule::import_bound(py, "sys")?;
31+
let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
3232
sys_modules.set_item("maturin_starter.submodule", m.getattr("submodule")?)?;
3333

3434
Ok(())

examples/plugin/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
1919

2020
// Now we can load our python_plugin/gadget_init_plugin.py file.
2121
// It can in turn import other stuff as it deems appropriate
22-
let plugin = PyModule::import(py, "gadget_init_plugin")?;
22+
let plugin = PyModule::import_bound(py, "gadget_init_plugin")?;
2323
// and call start function there, which will return a python reference to Gadget.
2424
// Gadget here is a "pyclass" object reference
2525
let gadget = plugin.getattr("start")?.call0()?;

examples/setuptools-rust-starter/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ fn _setuptools_rust_starter(py: Python<'_>, m: &PyModule) -> PyResult<()> {
2727
// Inserting to sys.modules allows importing submodules nicely from Python
2828
// e.g. from setuptools_rust_starter.submodule import SubmoduleClass
2929

30-
let sys = PyModule::import(py, "sys")?;
31-
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?;
30+
let sys = PyModule::import_bound(py, "sys")?;
31+
let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
3232
sys_modules.set_item("setuptools_rust_starter.submodule", m.getattr("submodule")?)?;
3333

3434
Ok(())

guide/src/class.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -941,8 +941,8 @@ impl MyClass {
941941
#
942942
# fn main() -> PyResult<()> {
943943
# Python::with_gil(|py| {
944-
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
945-
# let module = PyModule::new(py, "my_module")?;
944+
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
945+
# let module = PyModule::new_bound(py, "my_module")?;
946946
# module.add_class::<MyClass>()?;
947947
# let class = module.getattr("MyClass")?;
948948
#
@@ -951,15 +951,15 @@ impl MyClass {
951951
# assert_eq!(doc, "");
952952
#
953953
# let sig: String = inspect
954-
# .call1((class,))?
954+
# .call1((&class,))?
955955
# .call_method0("__str__")?
956956
# .extract()?;
957957
# assert_eq!(sig, "(c, d)");
958958
# } else {
959959
# let doc: String = class.getattr("__doc__")?.extract()?;
960960
# assert_eq!(doc, "");
961961
#
962-
# inspect.call1((class,)).expect_err("`text_signature` on classes is not compatible with compilation in `abi3` mode until Python 3.10 or greater");
962+
# inspect.call1((&class,)).expect_err("`text_signature` on classes is not compatible with compilation in `abi3` mode until Python 3.10 or greater");
963963
# }
964964
#
965965
# {

guide/src/class/numeric.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ fn my_module(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
386386
#
387387
# fn main() -> PyResult<()> {
388388
# Python::with_gil(|py| -> PyResult<()> {
389-
# let globals = PyModule::import(py, "__main__")?.dict().as_borrowed();
389+
# let globals = PyModule::import_bound(py, "__main__")?.dict();
390390
# globals.set_item("Number", Number::type_object_bound(py))?;
391391
#
392392
# py.run_bound(SCRIPT, Some(&globals), None)?;

guide/src/conversions/traits.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct RustyStruct {
5454
#
5555
# fn main() -> PyResult<()> {
5656
# Python::with_gil(|py| -> PyResult<()> {
57-
# let module = PyModule::from_code(
57+
# let module = PyModule::from_code_bound(
5858
# py,
5959
# "class Foo:
6060
# def __init__(self):
@@ -111,7 +111,7 @@ struct RustyStruct {
111111
#
112112
# fn main() -> PyResult<()> {
113113
# Python::with_gil(|py| -> PyResult<()> {
114-
# let module = PyModule::from_code(
114+
# let module = PyModule::from_code_bound(
115115
# py,
116116
# "class Foo(dict):
117117
# def __init__(self):
@@ -339,7 +339,7 @@ enum RustyEnum<'a> {
339339
# );
340340
# }
341341
# {
342-
# let module = PyModule::from_code(
342+
# let module = PyModule::from_code_bound(
343343
# py,
344344
# "class Foo(dict):
345345
# def __init__(self):
@@ -364,7 +364,7 @@ enum RustyEnum<'a> {
364364
# }
365365
#
366366
# {
367-
# let module = PyModule::from_code(
367+
# let module = PyModule::from_code_bound(
368368
# py,
369369
# "class Foo(dict):
370370
# def __init__(self):

guide/src/function/signature.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
138138
# Python::with_gil(|py| {
139139
# let fun = pyo3::wrap_pyfunction!(increment, py)?;
140140
#
141-
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
141+
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
142142
# let sig: String = inspect
143143
# .call1((fun,))?
144144
# .call_method0("__str__")?
@@ -166,7 +166,7 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
166166
# Python::with_gil(|py| {
167167
# let fun = pyo3::wrap_pyfunction!(increment, py)?;
168168
#
169-
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
169+
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
170170
# let sig: String = inspect
171171
# .call1((fun,))?
172172
# .call_method0("__str__")?
@@ -209,7 +209,7 @@ fn add(a: u64, b: u64) -> u64 {
209209
# let doc: String = fun.getattr("__doc__")?.extract()?;
210210
# assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
211211
#
212-
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
212+
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
213213
# let sig: String = inspect
214214
# .call1((fun,))?
215215
# .call_method0("__str__")?
@@ -257,7 +257,7 @@ fn add(a: u64, b: u64) -> u64 {
257257
# let doc: String = fun.getattr("__doc__")?.extract()?;
258258
# assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
259259
#
260-
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
260+
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
261261
# let sig: String = inspect
262262
# .call1((fun,))?
263263
# .call_method0("__str__")?

guide/src/module.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ fn parent_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
7878
}
7979

8080
fn register_child_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> {
81-
let child_module = PyModule::new(py, "child_module")?;
82-
child_module.add_function(wrap_pyfunction!(func, child_module)?)?;
83-
parent_module.add_submodule(child_module)?;
81+
let child_module = PyModule::new_bound(py, "child_module")?;
82+
child_module.add_function(&wrap_pyfunction!(func, child_module.as_gil_ref())?.as_borrowed())?;
83+
parent_module.add_submodule(child_module.as_gil_ref())?;
8484
Ok(())
8585
}
8686

guide/src/python_from_rust.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn main() -> PyResult<()> {
3232
let arg3 = "arg3";
3333

3434
Python::with_gil(|py| {
35-
let fun: Py<PyAny> = PyModule::from_code(
35+
let fun: Py<PyAny> = PyModule::from_code_bound(
3636
py,
3737
"def example(*args, **kwargs):
3838
if args != ():
@@ -78,7 +78,7 @@ fn main() -> PyResult<()> {
7878
let val2 = 2;
7979

8080
Python::with_gil(|py| {
81-
let fun: Py<PyAny> = PyModule::from_code(
81+
let fun: Py<PyAny> = PyModule::from_code_bound(
8282
py,
8383
"def example(*args, **kwargs):
8484
if args != ():
@@ -134,7 +134,7 @@ use pyo3::prelude::*;
134134

135135
fn main() -> PyResult<()> {
136136
Python::with_gil(|py| {
137-
let builtins = PyModule::import(py, "builtins")?;
137+
let builtins = PyModule::import_bound(py, "builtins")?;
138138
let total: i32 = builtins
139139
.getattr("sum")?
140140
.call1((vec![1, 2, 3],))?
@@ -233,7 +233,7 @@ use pyo3::{
233233

234234
# fn main() -> PyResult<()> {
235235
Python::with_gil(|py| {
236-
let activators = PyModule::from_code(
236+
let activators = PyModule::from_code_bound(
237237
py,
238238
r#"
239239
def relu(x):
@@ -253,7 +253,7 @@ def leaky_relu(x, slope=0.01):
253253
let kwargs = [("slope", 0.2)].into_py_dict_bound(py);
254254
let lrelu_result: f64 = activators
255255
.getattr("leaky_relu")?
256-
.call((-1.0,), Some(kwargs.as_gil_ref()))?
256+
.call((-1.0,), Some(&kwargs))?
257257
.extract()?;
258258
assert_eq!(lrelu_result, -0.2);
259259
# Ok(())
@@ -310,12 +310,12 @@ pub fn add_one(x: i64) -> i64 {
310310
fn main() -> PyResult<()> {
311311
Python::with_gil(|py| {
312312
// Create new module
313-
let foo_module = PyModule::new(py, "foo")?;
314-
foo_module.add_function(wrap_pyfunction!(add_one, foo_module)?)?;
313+
let foo_module = PyModule::new_bound(py, "foo")?;
314+
foo_module.add_function(&wrap_pyfunction!(add_one, foo_module.as_gil_ref())?.as_borrowed())?;
315315

316316
// Import and get sys.modules
317-
let sys = PyModule::import(py, "sys")?;
318-
let py_modules: &PyDict = sys.getattr("modules")?.downcast()?;
317+
let sys = PyModule::import_bound(py, "sys")?;
318+
let py_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
319319

320320
// Insert foo into sys.modules
321321
py_modules.set_item("foo", foo_module)?;
@@ -381,8 +381,8 @@ fn main() -> PyResult<()> {
381381
));
382382
let py_app = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/python_app/app.py"));
383383
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
384-
PyModule::from_code(py, py_foo, "utils.foo", "utils.foo")?;
385-
let app: Py<PyAny> = PyModule::from_code(py, py_app, "", "")?
384+
PyModule::from_code_bound(py, py_foo, "utils.foo", "utils.foo")?;
385+
let app: Py<PyAny> = PyModule::from_code_bound(py, py_app, "", "")?
386386
.getattr("run")?
387387
.into();
388388
app.call0(py)
@@ -416,7 +416,7 @@ fn main() -> PyResult<()> {
416416
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
417417
let syspath = py.import_bound("sys")?.getattr("path")?.downcast_into::<PyList>()?;
418418
syspath.insert(0, &path)?;
419-
let app: Py<PyAny> = PyModule::from_code(py, &py_app, "", "")?
419+
let app: Py<PyAny> = PyModule::from_code_bound(py, &py_app, "", "")?
420420
.getattr("run")?
421421
.into();
422422
app.call0(py)
@@ -440,7 +440,7 @@ use pyo3::prelude::*;
440440

441441
fn main() {
442442
Python::with_gil(|py| {
443-
let custom_manager = PyModule::from_code(
443+
let custom_manager = PyModule::from_code_bound(
444444
py,
445445
r#"
446446
class House(object):

pyo3-benches/benches/bench_call.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1+
use std::hint::black_box;
2+
13
use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion};
24

35
use pyo3::prelude::*;
46

57
macro_rules! test_module {
68
($py:ident, $code:literal) => {
7-
PyModule::from_code($py, $code, file!(), "test_module").expect("module creation failed")
9+
PyModule::from_code_bound($py, $code, file!(), "test_module")
10+
.expect("module creation failed")
811
};
912
}
1013

1114
fn bench_call_0(b: &mut Bencher<'_>) {
1215
Python::with_gil(|py| {
1316
let module = test_module!(py, "def foo(): pass");
1417

15-
let foo_module = module.getattr("foo").unwrap();
18+
let foo_module = &module.getattr("foo").unwrap();
1619

1720
b.iter(|| {
1821
for _ in 0..1000 {
19-
foo_module.call0().unwrap();
22+
black_box(foo_module).call0().unwrap();
2023
}
2124
});
2225
})
@@ -33,11 +36,11 @@ class Foo:
3336
"
3437
);
3538

36-
let foo_module = module.getattr("Foo").unwrap().call0().unwrap();
39+
let foo_module = &module.getattr("Foo").unwrap().call0().unwrap();
3740

3841
b.iter(|| {
3942
for _ in 0..1000 {
40-
foo_module.call_method0("foo").unwrap();
43+
black_box(foo_module).call_method0("foo").unwrap();
4144
}
4245
});
4346
})

pyo3-benches/benches/bench_intern.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::hint::black_box;
2+
13
use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion};
24

35
use pyo3::prelude::*;
@@ -6,17 +8,17 @@ use pyo3::intern;
68

79
fn getattr_direct(b: &mut Bencher<'_>) {
810
Python::with_gil(|py| {
9-
let sys = py.import_bound("sys").unwrap();
11+
let sys = &py.import_bound("sys").unwrap();
1012

11-
b.iter(|| sys.getattr("version").unwrap());
13+
b.iter(|| black_box(sys).getattr("version").unwrap());
1214
});
1315
}
1416

1517
fn getattr_intern(b: &mut Bencher<'_>) {
1618
Python::with_gil(|py| {
17-
let sys = py.import_bound("sys").unwrap();
19+
let sys = &py.import_bound("sys").unwrap();
1820

19-
b.iter(|| sys.getattr(intern!(py, "version")).unwrap());
21+
b.iter(|| black_box(sys).getattr(intern!(py, "version")).unwrap());
2022
});
2123
}
2224

pytests/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
3939
// Inserting to sys.modules allows importing submodules nicely from Python
4040
// e.g. import pyo3_pytests.buf_and_str as bas
4141

42-
let sys = PyModule::import(py, "sys")?;
43-
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?;
42+
let sys = PyModule::import_bound(py, "sys")?;
43+
let sys_modules = sys.getattr("modules")?.downcast_into::<PyDict>()?;
4444
sys_modules.set_item("pyo3_pytests.awaitable", m.getattr("awaitable")?)?;
4545
sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?;
4646
sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?;

src/conversions/anyhow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
//! // could call inside an application...
7676
//! // This might return a `PyErr`.
7777
//! let res = Python::with_gil(|py| {
78-
//! let zlib = PyModule::import(py, "zlib")?;
78+
//! let zlib = PyModule::import_bound(py, "zlib")?;
7979
//! let decompress = zlib.getattr("decompress")?;
8080
//! let bytes = PyBytes::new_bound(py, bytes);
8181
//! let value = decompress.call1((bytes,))?;

src/conversions/chrono.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ fn timezone_utc_bound(py: Python<'_>) -> Bound<'_, PyAny> {
564564
#[cfg(test)]
565565
mod tests {
566566
use super::*;
567-
use crate::{types::PyTuple, Py};
567+
use crate::{types::PyTuple, Bound, Py};
568568
use std::{cmp::Ordering, panic};
569569

570570
#[test]

src/conversions/chrono_tz.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ impl FromPyObject<'_> for Tz {
6969

7070
#[cfg(all(test, not(windows)))] // Troubles loading timezones on Windows
7171
mod tests {
72+
use crate::{types::any::PyAnyMethods, Bound};
73+
7274
use super::*;
7375

7476
#[test]

src/conversions/eyre.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
//! // could call inside an application...
7575
//! // This might return a `PyErr`.
7676
//! let res = Python::with_gil(|py| {
77-
//! let zlib = PyModule::import(py, "zlib")?;
77+
//! let zlib = PyModule::import_bound(py, "zlib")?;
7878
//! let decompress = zlib.getattr("decompress")?;
7979
//! let bytes = PyBytes::new_bound(py, bytes);
8080
//! let value = decompress.call1((bytes,))?;

src/conversions/num_bigint.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,10 @@ fn int_n_bits(long: &Bound<'_, PyLong>) -> PyResult<usize> {
262262
#[cfg(test)]
263263
mod tests {
264264
use super::*;
265-
use crate::types::{PyDict, PyModule};
265+
use crate::{
266+
types::{PyDict, PyModule},
267+
Bound,
268+
};
266269
use indoc::indoc;
267270

268271
fn rust_fib<T>() -> impl Iterator<Item = T>
@@ -323,7 +326,7 @@ mod tests {
323326
});
324327
}
325328

326-
fn python_index_class(py: Python<'_>) -> &PyModule {
329+
fn python_index_class(py: Python<'_>) -> Bound<'_, PyModule> {
327330
let index_code = indoc!(
328331
r#"
329332
class C:
@@ -333,7 +336,7 @@ mod tests {
333336
return self.x
334337
"#
335338
);
336-
PyModule::from_code(py, index_code, "index.py", "index").unwrap()
339+
PyModule::from_code_bound(py, index_code, "index.py", "index").unwrap()
337340
}
338341

339342
#[test]

0 commit comments

Comments
 (0)