add `PyModule::new_bound` and `PyModule::import_bound` (#3775)

* add `PyModule::new` and `PyModule::import_bound`

* review: Icxolu feedback
This commit is contained in:
David Hewitt 2024-02-22 09:35:47 +00:00 committed by GitHub
parent c4f66657c5
commit 9e74c858c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 229 additions and 190 deletions

View File

@ -27,8 +27,8 @@ fn maturin_starter(py: Python<'_>, m: &PyModule) -> PyResult<()> {
// Inserting to sys.modules allows importing submodules nicely from Python // Inserting to sys.modules allows importing submodules nicely from Python
// e.g. from maturin_starter.submodule import SubmoduleClass // e.g. from maturin_starter.submodule import SubmoduleClass
let sys = PyModule::import(py, "sys")?; let sys = PyModule::import_bound(py, "sys")?;
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
sys_modules.set_item("maturin_starter.submodule", m.getattr("submodule")?)?; sys_modules.set_item("maturin_starter.submodule", m.getattr("submodule")?)?;
Ok(()) Ok(())

View File

@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Now we can load our python_plugin/gadget_init_plugin.py file. // Now we can load our python_plugin/gadget_init_plugin.py file.
// It can in turn import other stuff as it deems appropriate // It can in turn import other stuff as it deems appropriate
let plugin = PyModule::import(py, "gadget_init_plugin")?; let plugin = PyModule::import_bound(py, "gadget_init_plugin")?;
// and call start function there, which will return a python reference to Gadget. // and call start function there, which will return a python reference to Gadget.
// Gadget here is a "pyclass" object reference // Gadget here is a "pyclass" object reference
let gadget = plugin.getattr("start")?.call0()?; let gadget = plugin.getattr("start")?.call0()?;

View File

@ -27,8 +27,8 @@ fn _setuptools_rust_starter(py: Python<'_>, m: &PyModule) -> PyResult<()> {
// Inserting to sys.modules allows importing submodules nicely from Python // Inserting to sys.modules allows importing submodules nicely from Python
// e.g. from setuptools_rust_starter.submodule import SubmoduleClass // e.g. from setuptools_rust_starter.submodule import SubmoduleClass
let sys = PyModule::import(py, "sys")?; let sys = PyModule::import_bound(py, "sys")?;
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
sys_modules.set_item("setuptools_rust_starter.submodule", m.getattr("submodule")?)?; sys_modules.set_item("setuptools_rust_starter.submodule", m.getattr("submodule")?)?;
Ok(()) Ok(())

View File

@ -941,8 +941,8 @@ impl MyClass {
# #
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# Python::with_gil(|py| { # Python::with_gil(|py| {
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?; # let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let module = PyModule::new(py, "my_module")?; # let module = PyModule::new_bound(py, "my_module")?;
# module.add_class::<MyClass>()?; # module.add_class::<MyClass>()?;
# let class = module.getattr("MyClass")?; # let class = module.getattr("MyClass")?;
# #
@ -951,7 +951,7 @@ impl MyClass {
# assert_eq!(doc, ""); # assert_eq!(doc, "");
# #
# let sig: String = inspect # let sig: String = inspect
# .call1((class,))? # .call1((&class,))?
# .call_method0("__str__")? # .call_method0("__str__")?
# .extract()?; # .extract()?;
# assert_eq!(sig, "(c, d)"); # assert_eq!(sig, "(c, d)");
@ -959,7 +959,7 @@ impl MyClass {
# let doc: String = class.getattr("__doc__")?.extract()?; # let doc: String = class.getattr("__doc__")?.extract()?;
# assert_eq!(doc, ""); # assert_eq!(doc, "");
# #
# inspect.call1((class,)).expect_err("`text_signature` on classes is not compatible with compilation in `abi3` mode until Python 3.10 or greater"); # inspect.call1((&class,)).expect_err("`text_signature` on classes is not compatible with compilation in `abi3` mode until Python 3.10 or greater");
# } # }
# #
# { # {

View File

@ -386,7 +386,7 @@ fn my_module(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
# #
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> { # Python::with_gil(|py| -> PyResult<()> {
# let globals = PyModule::import(py, "__main__")?.dict().as_borrowed(); # let globals = PyModule::import_bound(py, "__main__")?.dict();
# globals.set_item("Number", Number::type_object_bound(py))?; # globals.set_item("Number", Number::type_object_bound(py))?;
# #
# py.run_bound(SCRIPT, Some(&globals), None)?; # py.run_bound(SCRIPT, Some(&globals), None)?;

View File

@ -54,7 +54,7 @@ struct RustyStruct {
# #
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> { # Python::with_gil(|py| -> PyResult<()> {
# let module = PyModule::from_code( # let module = PyModule::from_code_bound(
# py, # py,
# "class Foo: # "class Foo:
# def __init__(self): # def __init__(self):
@ -111,7 +111,7 @@ struct RustyStruct {
# #
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> { # Python::with_gil(|py| -> PyResult<()> {
# let module = PyModule::from_code( # let module = PyModule::from_code_bound(
# py, # py,
# "class Foo(dict): # "class Foo(dict):
# def __init__(self): # def __init__(self):
@ -339,7 +339,7 @@ enum RustyEnum<'a> {
# ); # );
# } # }
# { # {
# let module = PyModule::from_code( # let module = PyModule::from_code_bound(
# py, # py,
# "class Foo(dict): # "class Foo(dict):
# def __init__(self): # def __init__(self):
@ -364,7 +364,7 @@ enum RustyEnum<'a> {
# } # }
# #
# { # {
# let module = PyModule::from_code( # let module = PyModule::from_code_bound(
# py, # py,
# "class Foo(dict): # "class Foo(dict):
# def __init__(self): # def __init__(self):

View File

@ -138,7 +138,7 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
# Python::with_gil(|py| { # Python::with_gil(|py| {
# let fun = pyo3::wrap_pyfunction!(increment, py)?; # let fun = pyo3::wrap_pyfunction!(increment, py)?;
# #
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?; # let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect # let sig: String = inspect
# .call1((fun,))? # .call1((fun,))?
# .call_method0("__str__")? # .call_method0("__str__")?
@ -166,7 +166,7 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
# Python::with_gil(|py| { # Python::with_gil(|py| {
# let fun = pyo3::wrap_pyfunction!(increment, py)?; # let fun = pyo3::wrap_pyfunction!(increment, py)?;
# #
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?; # let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect # let sig: String = inspect
# .call1((fun,))? # .call1((fun,))?
# .call_method0("__str__")? # .call_method0("__str__")?
@ -209,7 +209,7 @@ fn add(a: u64, b: u64) -> u64 {
# let doc: String = fun.getattr("__doc__")?.extract()?; # let doc: String = fun.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "This function adds two unsigned 64-bit integers."); # assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
# #
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?; # let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect # let sig: String = inspect
# .call1((fun,))? # .call1((fun,))?
# .call_method0("__str__")? # .call_method0("__str__")?
@ -257,7 +257,7 @@ fn add(a: u64, b: u64) -> u64 {
# let doc: String = fun.getattr("__doc__")?.extract()?; # let doc: String = fun.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "This function adds two unsigned 64-bit integers."); # assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
# #
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?; # let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect # let sig: String = inspect
# .call1((fun,))? # .call1((fun,))?
# .call_method0("__str__")? # .call_method0("__str__")?

View File

@ -78,9 +78,9 @@ fn parent_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
} }
fn register_child_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> { fn register_child_module(py: Python<'_>, parent_module: &PyModule) -> PyResult<()> {
let child_module = PyModule::new(py, "child_module")?; let child_module = PyModule::new_bound(py, "child_module")?;
child_module.add_function(wrap_pyfunction!(func, child_module)?)?; child_module.add_function(&wrap_pyfunction!(func, child_module.as_gil_ref())?.as_borrowed())?;
parent_module.add_submodule(child_module)?; parent_module.add_submodule(child_module.as_gil_ref())?;
Ok(()) Ok(())
} }

View File

@ -32,7 +32,7 @@ fn main() -> PyResult<()> {
let arg3 = "arg3"; let arg3 = "arg3";
Python::with_gil(|py| { Python::with_gil(|py| {
let fun: Py<PyAny> = PyModule::from_code( let fun: Py<PyAny> = PyModule::from_code_bound(
py, py,
"def example(*args, **kwargs): "def example(*args, **kwargs):
if args != (): if args != ():
@ -78,7 +78,7 @@ fn main() -> PyResult<()> {
let val2 = 2; let val2 = 2;
Python::with_gil(|py| { Python::with_gil(|py| {
let fun: Py<PyAny> = PyModule::from_code( let fun: Py<PyAny> = PyModule::from_code_bound(
py, py,
"def example(*args, **kwargs): "def example(*args, **kwargs):
if args != (): if args != ():
@ -134,7 +134,7 @@ use pyo3::prelude::*;
fn main() -> PyResult<()> { fn main() -> PyResult<()> {
Python::with_gil(|py| { Python::with_gil(|py| {
let builtins = PyModule::import(py, "builtins")?; let builtins = PyModule::import_bound(py, "builtins")?;
let total: i32 = builtins let total: i32 = builtins
.getattr("sum")? .getattr("sum")?
.call1((vec![1, 2, 3],))? .call1((vec![1, 2, 3],))?
@ -233,7 +233,7 @@ use pyo3::{
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
Python::with_gil(|py| { Python::with_gil(|py| {
let activators = PyModule::from_code( let activators = PyModule::from_code_bound(
py, py,
r#" r#"
def relu(x): def relu(x):
@ -253,7 +253,7 @@ def leaky_relu(x, slope=0.01):
let kwargs = [("slope", 0.2)].into_py_dict_bound(py); let kwargs = [("slope", 0.2)].into_py_dict_bound(py);
let lrelu_result: f64 = activators let lrelu_result: f64 = activators
.getattr("leaky_relu")? .getattr("leaky_relu")?
.call((-1.0,), Some(kwargs.as_gil_ref()))? .call((-1.0,), Some(&kwargs))?
.extract()?; .extract()?;
assert_eq!(lrelu_result, -0.2); assert_eq!(lrelu_result, -0.2);
# Ok(()) # Ok(())
@ -310,12 +310,12 @@ pub fn add_one(x: i64) -> i64 {
fn main() -> PyResult<()> { fn main() -> PyResult<()> {
Python::with_gil(|py| { Python::with_gil(|py| {
// Create new module // Create new module
let foo_module = PyModule::new(py, "foo")?; let foo_module = PyModule::new_bound(py, "foo")?;
foo_module.add_function(wrap_pyfunction!(add_one, foo_module)?)?; foo_module.add_function(&wrap_pyfunction!(add_one, foo_module.as_gil_ref())?.as_borrowed())?;
// Import and get sys.modules // Import and get sys.modules
let sys = PyModule::import(py, "sys")?; let sys = PyModule::import_bound(py, "sys")?;
let py_modules: &PyDict = sys.getattr("modules")?.downcast()?; let py_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
// Insert foo into sys.modules // Insert foo into sys.modules
py_modules.set_item("foo", foo_module)?; py_modules.set_item("foo", foo_module)?;
@ -381,8 +381,8 @@ fn main() -> PyResult<()> {
)); ));
let py_app = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/python_app/app.py")); let py_app = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/python_app/app.py"));
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> { let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
PyModule::from_code(py, py_foo, "utils.foo", "utils.foo")?; PyModule::from_code_bound(py, py_foo, "utils.foo", "utils.foo")?;
let app: Py<PyAny> = PyModule::from_code(py, py_app, "", "")? let app: Py<PyAny> = PyModule::from_code_bound(py, py_app, "", "")?
.getattr("run")? .getattr("run")?
.into(); .into();
app.call0(py) app.call0(py)
@ -416,7 +416,7 @@ fn main() -> PyResult<()> {
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> { let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let syspath = py.import_bound("sys")?.getattr("path")?.downcast_into::<PyList>()?; let syspath = py.import_bound("sys")?.getattr("path")?.downcast_into::<PyList>()?;
syspath.insert(0, &path)?; syspath.insert(0, &path)?;
let app: Py<PyAny> = PyModule::from_code(py, &py_app, "", "")? let app: Py<PyAny> = PyModule::from_code_bound(py, &py_app, "", "")?
.getattr("run")? .getattr("run")?
.into(); .into();
app.call0(py) app.call0(py)
@ -440,7 +440,7 @@ use pyo3::prelude::*;
fn main() { fn main() {
Python::with_gil(|py| { Python::with_gil(|py| {
let custom_manager = PyModule::from_code( let custom_manager = PyModule::from_code_bound(
py, py,
r#" r#"
class House(object): class House(object):

View File

@ -1,10 +1,13 @@
use std::hint::black_box;
use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion}; use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion};
use pyo3::prelude::*; use pyo3::prelude::*;
macro_rules! test_module { macro_rules! test_module {
($py:ident, $code:literal) => { ($py:ident, $code:literal) => {
PyModule::from_code($py, $code, file!(), "test_module").expect("module creation failed") PyModule::from_code_bound($py, $code, file!(), "test_module")
.expect("module creation failed")
}; };
} }
@ -12,11 +15,11 @@ fn bench_call_0(b: &mut Bencher<'_>) {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = test_module!(py, "def foo(): pass"); let module = test_module!(py, "def foo(): pass");
let foo_module = module.getattr("foo").unwrap(); let foo_module = &module.getattr("foo").unwrap();
b.iter(|| { b.iter(|| {
for _ in 0..1000 { for _ in 0..1000 {
foo_module.call0().unwrap(); black_box(foo_module).call0().unwrap();
} }
}); });
}) })
@ -33,11 +36,11 @@ class Foo:
" "
); );
let foo_module = module.getattr("Foo").unwrap().call0().unwrap(); let foo_module = &module.getattr("Foo").unwrap().call0().unwrap();
b.iter(|| { b.iter(|| {
for _ in 0..1000 { for _ in 0..1000 {
foo_module.call_method0("foo").unwrap(); black_box(foo_module).call_method0("foo").unwrap();
} }
}); });
}) })

View File

@ -1,3 +1,5 @@
use std::hint::black_box;
use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion}; use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion};
use pyo3::prelude::*; use pyo3::prelude::*;
@ -6,17 +8,17 @@ use pyo3::intern;
fn getattr_direct(b: &mut Bencher<'_>) { fn getattr_direct(b: &mut Bencher<'_>) {
Python::with_gil(|py| { Python::with_gil(|py| {
let sys = py.import_bound("sys").unwrap(); let sys = &py.import_bound("sys").unwrap();
b.iter(|| sys.getattr("version").unwrap()); b.iter(|| black_box(sys).getattr("version").unwrap());
}); });
} }
fn getattr_intern(b: &mut Bencher<'_>) { fn getattr_intern(b: &mut Bencher<'_>) {
Python::with_gil(|py| { Python::with_gil(|py| {
let sys = py.import_bound("sys").unwrap(); let sys = &py.import_bound("sys").unwrap();
b.iter(|| sys.getattr(intern!(py, "version")).unwrap()); b.iter(|| black_box(sys).getattr(intern!(py, "version")).unwrap());
}); });
} }

View File

@ -39,8 +39,8 @@ fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
// Inserting to sys.modules allows importing submodules nicely from Python // Inserting to sys.modules allows importing submodules nicely from Python
// e.g. import pyo3_pytests.buf_and_str as bas // e.g. import pyo3_pytests.buf_and_str as bas
let sys = PyModule::import(py, "sys")?; let sys = PyModule::import_bound(py, "sys")?;
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; let sys_modules = sys.getattr("modules")?.downcast_into::<PyDict>()?;
sys_modules.set_item("pyo3_pytests.awaitable", m.getattr("awaitable")?)?; sys_modules.set_item("pyo3_pytests.awaitable", m.getattr("awaitable")?)?;
sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?; sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?;
sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?; sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?;

View File

@ -75,7 +75,7 @@
//! // could call inside an application... //! // could call inside an application...
//! // This might return a `PyErr`. //! // This might return a `PyErr`.
//! let res = Python::with_gil(|py| { //! let res = Python::with_gil(|py| {
//! let zlib = PyModule::import(py, "zlib")?; //! let zlib = PyModule::import_bound(py, "zlib")?;
//! let decompress = zlib.getattr("decompress")?; //! let decompress = zlib.getattr("decompress")?;
//! let bytes = PyBytes::new_bound(py, bytes); //! let bytes = PyBytes::new_bound(py, bytes);
//! let value = decompress.call1((bytes,))?; //! let value = decompress.call1((bytes,))?;

View File

@ -564,7 +564,7 @@ fn timezone_utc_bound(py: Python<'_>) -> Bound<'_, PyAny> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{types::PyTuple, Py}; use crate::{types::PyTuple, Bound, Py};
use std::{cmp::Ordering, panic}; use std::{cmp::Ordering, panic};
#[test] #[test]

View File

@ -69,6 +69,8 @@ impl FromPyObject<'_> for Tz {
#[cfg(all(test, not(windows)))] // Troubles loading timezones on Windows #[cfg(all(test, not(windows)))] // Troubles loading timezones on Windows
mod tests { mod tests {
use crate::{types::any::PyAnyMethods, Bound};
use super::*; use super::*;
#[test] #[test]

View File

@ -74,7 +74,7 @@
//! // could call inside an application... //! // could call inside an application...
//! // This might return a `PyErr`. //! // This might return a `PyErr`.
//! let res = Python::with_gil(|py| { //! let res = Python::with_gil(|py| {
//! let zlib = PyModule::import(py, "zlib")?; //! let zlib = PyModule::import_bound(py, "zlib")?;
//! let decompress = zlib.getattr("decompress")?; //! let decompress = zlib.getattr("decompress")?;
//! let bytes = PyBytes::new_bound(py, bytes); //! let bytes = PyBytes::new_bound(py, bytes);
//! let value = decompress.call1((bytes,))?; //! let value = decompress.call1((bytes,))?;

View File

@ -262,7 +262,10 @@ fn int_n_bits(long: &Bound<'_, PyLong>) -> PyResult<usize> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::types::{PyDict, PyModule}; use crate::{
types::{PyDict, PyModule},
Bound,
};
use indoc::indoc; use indoc::indoc;
fn rust_fib<T>() -> impl Iterator<Item = T> fn rust_fib<T>() -> impl Iterator<Item = T>
@ -323,7 +326,7 @@ mod tests {
}); });
} }
fn python_index_class(py: Python<'_>) -> &PyModule { fn python_index_class(py: Python<'_>) -> Bound<'_, PyModule> {
let index_code = indoc!( let index_code = indoc!(
r#" r#"
class C: class C:
@ -333,7 +336,7 @@ mod tests {
return self.x return self.x
"# "#
); );
PyModule::from_code(py, index_code, "index.py", "index").unwrap() PyModule::from_code_bound(py, index_code, "index.py", "index").unwrap()
} }
#[test] #[test]

View File

@ -27,7 +27,7 @@
//! ```ignore //! ```ignore
//! # // not tested because nalgebra isn't supported on msrv //! # // not tested because nalgebra isn't supported on msrv
//! # // please file an issue if it breaks! //! # // please file an issue if it breaks!
//! use nalgebra::base::{dimension::Const, storage::Storage, Matrix}; //! use nalgebra::base::{dimension::Const, Matrix};
//! use num_complex::Complex; //! use num_complex::Complex;
//! use pyo3::prelude::*; //! use pyo3::prelude::*;
//! //!
@ -55,9 +55,9 @@
//! # //! #
//! # fn main() -> PyResult<()> { //! # fn main() -> PyResult<()> {
//! # Python::with_gil(|py| -> PyResult<()> { //! # Python::with_gil(|py| -> PyResult<()> {
//! # let module = PyModule::new(py, "my_module")?; //! # let module = PyModule::new_bound(py, "my_module")?;
//! # //! #
//! # module.add_function(wrap_pyfunction!(get_eigenvalues, module)?)?; //! # module.add_function(&wrap_pyfunction!(get_eigenvalues, module.as_gil_ref())?.as_borrowed())?;
//! # //! #
//! # let m11 = PyComplex::from_doubles_bound(py, 0_f64, -1_f64); //! # let m11 = PyComplex::from_doubles_bound(py, 0_f64, -1_f64);
//! # let m12 = PyComplex::from_doubles_bound(py, 1_f64, 0_f64); //! # let m12 = PyComplex::from_doubles_bound(py, 1_f64, 0_f64);
@ -199,8 +199,7 @@ complex_conversion!(f64);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::types::complex::PyComplexMethods; use crate::types::{any::PyAnyMethods, complex::PyComplexMethods, PyModule};
use crate::types::PyModule;
#[test] #[test]
fn from_complex() { fn from_complex() {
@ -229,7 +228,7 @@ mod tests {
#[test] #[test]
fn from_python_magic() { fn from_python_magic() {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::from_code( let module = PyModule::from_code_bound(
py, py,
r#" r#"
class A: class A:
@ -267,7 +266,7 @@ class C:
#[test] #[test]
fn from_python_inherited_magic() { fn from_python_inherited_magic() {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::from_code( let module = PyModule::from_code_bound(
py, py,
r#" r#"
class First: pass class First: pass
@ -311,7 +310,7 @@ class C(First, IndexMixin): pass
// `type(inst).attr(inst)` equivalent to `inst.attr()` for methods, but this isn't the only // `type(inst).attr(inst)` equivalent to `inst.attr()` for methods, but this isn't the only
// way the descriptor protocol might be implemented. // way the descriptor protocol might be implemented.
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::from_code( let module = PyModule::from_code_bound(
py, py,
r#" r#"
class A: class A:
@ -334,7 +333,7 @@ class A:
fn from_python_nondescriptor_magic() { fn from_python_nondescriptor_magic() {
// Magic methods don't need to implement the descriptor protocol, if they're callable. // Magic methods don't need to implement the descriptor protocol, if they're callable.
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::from_code( let module = PyModule::from_code_bound(
py, py,
r#" r#"
class MyComplex: class MyComplex:

View File

@ -722,12 +722,12 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
/// # /// #
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| { /// # Python::with_gil(|py| {
/// # let m = pyo3::types::PyModule::new(py, "test")?; /// # let m = pyo3::types::PyModule::new_bound(py, "test")?;
/// # m.add_class::<Foo>()?; /// # m.add_class::<Foo>()?;
/// # /// #
/// # let foo: &PyCell<Foo> = m.getattr("Foo")?.call0()?.downcast()?; /// # let foo: Bound<'_, Foo> = m.getattr("Foo")?.call0()?.downcast_into()?;
/// # let dict = &foo.borrow().inner; /// # let dict = &foo.borrow().inner;
/// # let dict: &PyDict = dict.as_ref(py); /// # let dict: &Bound<'_, PyDict> = dict.bind(py);
/// # /// #
/// # Ok(()) /// # Ok(())
/// # }) /// # })
@ -759,10 +759,10 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
/// # /// #
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| { /// # Python::with_gil(|py| {
/// # let m = pyo3::types::PyModule::new(py, "test")?; /// # let m = pyo3::types::PyModule::new_bound(py, "test")?;
/// # m.add_class::<Foo>()?; /// # m.add_class::<Foo>()?;
/// # /// #
/// # let foo: &PyCell<Foo> = m.getattr("Foo")?.call0()?.downcast()?; /// # let foo: Bound<'_, Foo> = m.getattr("Foo")?.call0()?.downcast_into()?;
/// # let bar = &foo.borrow().inner; /// # let bar = &foo.borrow().inner;
/// # let bar: &Bar = &*bar.borrow(py); /// # let bar: &Bar = &*bar.borrow(py);
/// # /// #
@ -1357,7 +1357,7 @@ impl<T> Py<T> {
/// } /// }
/// # /// #
/// # Python::with_gil(|py| { /// # Python::with_gil(|py| {
/// # let ob = PyModule::new(py, "empty").unwrap().into_py(py); /// # let ob = PyModule::new_bound(py, "empty").unwrap().into_py(py);
/// # set_answer(ob, py).unwrap(); /// # set_answer(ob, py).unwrap();
/// # }); /// # });
/// ``` /// ```
@ -1905,6 +1905,7 @@ impl PyObject {
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))] #[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
mod tests { mod tests {
use super::{Bound, Py, PyObject}; use super::{Bound, Py, PyObject};
use crate::types::any::PyAnyMethods;
use crate::types::PyCapsule; use crate::types::PyCapsule;
use crate::types::{dict::IntoPyDict, PyDict, PyString}; use crate::types::{dict::IntoPyDict, PyDict, PyString};
use crate::{ffi, Borrowed, PyAny, PyNativeType, PyResult, Python, ToPyObject}; use crate::{ffi, Borrowed, PyAny, PyNativeType, PyResult, Python, ToPyObject};
@ -1978,7 +1979,7 @@ class A:
pass pass
a = A() a = A()
"#; "#;
let module = PyModule::from_code(py, CODE, "", "")?; let module = PyModule::from_code_bound(py, CODE, "", "")?;
let instance: Py<PyAny> = module.getattr("a")?.into(); let instance: Py<PyAny> = module.getattr("a")?.into();
instance.getattr(py, "foo").unwrap_err(); instance.getattr(py, "foo").unwrap_err();
@ -2005,7 +2006,7 @@ class A:
pass pass
a = A() a = A()
"#; "#;
let module = PyModule::from_code(py, CODE, "", "")?; let module = PyModule::from_code_bound(py, CODE, "", "")?;
let instance: Py<PyAny> = module.getattr("a")?.into(); let instance: Py<PyAny> = module.getattr("a")?.into();
let foo = crate::intern!(py, "foo"); let foo = crate::intern!(py, "foo");

View File

@ -764,7 +764,7 @@ impl<'py> Python<'py> {
where where
N: IntoPy<Py<PyString>>, N: IntoPy<Py<PyString>>,
{ {
PyModule::import(self, name) Self::import_bound(self, name).map(Bound::into_gil_ref)
} }
/// Imports the Python module with the specified name. /// Imports the Python module with the specified name.
@ -772,11 +772,7 @@ impl<'py> Python<'py> {
where where
N: IntoPy<Py<PyString>>, N: IntoPy<Py<PyString>>,
{ {
// FIXME: This should be replaced by `PyModule::import_bound` once thats PyModule::import_bound(self, name)
// implemented.
PyModule::import(self, name)
.map(PyNativeType::as_borrowed)
.map(crate::Borrowed::to_owned)
} }
/// Gets the Python builtin value `None`. /// Gets the Python builtin value `None`.

View File

@ -184,7 +184,7 @@ impl<T: PyClass> PyClassInitializer<T> {
/// ///
/// fn main() -> PyResult<()> { /// fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let m = PyModule::new(py, "example")?; /// let m = PyModule::new_bound(py, "example")?;
/// m.add_class::<SubClass>()?; /// m.add_class::<SubClass>()?;
/// m.add_class::<BaseClass>()?; /// m.add_class::<BaseClass>()?;
/// ///

View File

@ -146,16 +146,16 @@ impl PyAny {
/// # Example: `intern!`ing the attribute name /// # Example: `intern!`ing the attribute name
/// ///
/// ``` /// ```
/// # use pyo3::{intern, pyfunction, types::PyModule, PyAny, Python, PyResult}; /// # use pyo3::{prelude::*, intern};
/// # /// #
/// #[pyfunction] /// #[pyfunction]
/// fn set_answer(ob: &PyAny) -> PyResult<()> { /// fn set_answer(ob: &Bound<'_, PyAny>) -> PyResult<()> {
/// ob.setattr(intern!(ob.py(), "answer"), 42) /// ob.setattr(intern!(ob.py(), "answer"), 42)
/// } /// }
/// # /// #
/// # Python::with_gil(|py| { /// # Python::with_gil(|py| {
/// # let ob = PyModule::new(py, "empty").unwrap(); /// # let ob = PyModule::new_bound(py, "empty").unwrap();
/// # set_answer(ob).unwrap(); /// # set_answer(&ob).unwrap();
/// # }); /// # });
/// ``` /// ```
pub fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()> pub fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
@ -346,7 +346,7 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// let builtins = PyModule::import(py, "builtins")?; /// let builtins = PyModule::import_bound(py, "builtins")?;
/// let print = builtins.getattr("print")?; /// let print = builtins.getattr("print")?;
/// assert!(print.is_callable()); /// assert!(print.is_callable());
/// Ok(()) /// Ok(())
@ -385,12 +385,12 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let fun = module.getattr("function")?; /// let fun = module.getattr("function")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let kwargs = PyDict::new_bound(py); /// let kwargs = PyDict::new_bound(py);
/// kwargs.set_item("cruel", "world")?; /// kwargs.set_item("cruel", "world")?;
/// let result = fun.call(args, Some(kwargs.as_gil_ref()))?; /// let result = fun.call(args, Some(&kwargs))?;
/// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs");
/// Ok(()) /// Ok(())
/// }) /// })
@ -417,7 +417,7 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::import(py, "builtins")?; /// let module = PyModule::import_bound(py, "builtins")?;
/// let help = module.getattr("help")?; /// let help = module.getattr("help")?;
/// help.call0()?; /// help.call0()?;
/// Ok(()) /// Ok(())
@ -448,7 +448,7 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let fun = module.getattr("function")?; /// let fun = module.getattr("function")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let result = fun.call1(args)?; /// let result = fun.call1(args)?;
@ -485,12 +485,12 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let instance = module.getattr("a")?; /// let instance = module.getattr("a")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let kwargs = PyDict::new_bound(py); /// let kwargs = PyDict::new_bound(py);
/// kwargs.set_item("cruel", "world")?; /// kwargs.set_item("cruel", "world")?;
/// let result = instance.call_method("method", args, Some(kwargs.as_gil_ref()))?; /// let result = instance.call_method("method", args, Some(&kwargs))?;
/// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs");
/// Ok(()) /// Ok(())
/// }) /// })
@ -529,7 +529,7 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let instance = module.getattr("a")?; /// let instance = module.getattr("a")?;
/// let result = instance.call_method0("method")?; /// let result = instance.call_method0("method")?;
/// assert_eq!(result.extract::<&str>()?, "called with no arguments"); /// assert_eq!(result.extract::<&str>()?, "called with no arguments");
@ -569,7 +569,7 @@ impl PyAny {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let instance = module.getattr("a")?; /// let instance = module.getattr("a")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let result = instance.call_method1("method", args)?; /// let result = instance.call_method1("method", args)?;
@ -1008,16 +1008,16 @@ pub trait PyAnyMethods<'py> {
/// # Example: `intern!`ing the attribute name /// # Example: `intern!`ing the attribute name
/// ///
/// ``` /// ```
/// # use pyo3::{intern, pyfunction, types::PyModule, PyAny, Python, PyResult}; /// # use pyo3::{prelude::*, intern};
/// # /// #
/// #[pyfunction] /// #[pyfunction]
/// fn set_answer(ob: &PyAny) -> PyResult<()> { /// fn set_answer(ob: &Bound<'_, PyAny>) -> PyResult<()> {
/// ob.setattr(intern!(ob.py(), "answer"), 42) /// ob.setattr(intern!(ob.py(), "answer"), 42)
/// } /// }
/// # /// #
/// # Python::with_gil(|py| { /// # Python::with_gil(|py| {
/// # let ob = PyModule::new(py, "empty").unwrap(); /// # let ob = PyModule::new_bound(py, "empty").unwrap();
/// # set_answer(ob).unwrap(); /// # set_answer(&ob).unwrap();
/// # }); /// # });
/// ``` /// ```
fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()> fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
@ -1228,7 +1228,7 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// let builtins = PyModule::import(py, "builtins")?; /// let builtins = PyModule::import_bound(py, "builtins")?;
/// let print = builtins.getattr("print")?; /// let print = builtins.getattr("print")?;
/// assert!(print.is_callable()); /// assert!(print.is_callable());
/// Ok(()) /// Ok(())
@ -1265,12 +1265,12 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let fun = module.getattr("function")?; /// let fun = module.getattr("function")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let kwargs = PyDict::new_bound(py); /// let kwargs = PyDict::new_bound(py);
/// kwargs.set_item("cruel", "world")?; /// kwargs.set_item("cruel", "world")?;
/// let result = fun.call(args, Some(kwargs.as_gil_ref()))?; /// let result = fun.call(args, Some(&kwargs))?;
/// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs");
/// Ok(()) /// Ok(())
/// }) /// })
@ -1293,7 +1293,7 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::import(py, "builtins")?; /// let module = PyModule::import_bound(py, "builtins")?;
/// let help = module.getattr("help")?; /// let help = module.getattr("help")?;
/// help.call0()?; /// help.call0()?;
/// Ok(()) /// Ok(())
@ -1322,7 +1322,7 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let fun = module.getattr("function")?; /// let fun = module.getattr("function")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let result = fun.call1(args)?; /// let result = fun.call1(args)?;
@ -1357,12 +1357,12 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let instance = module.getattr("a")?; /// let instance = module.getattr("a")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let kwargs = PyDict::new_bound(py); /// let kwargs = PyDict::new_bound(py);
/// kwargs.set_item("cruel", "world")?; /// kwargs.set_item("cruel", "world")?;
/// let result = instance.call_method("method", args, Some(kwargs.as_gil_ref()))?; /// let result = instance.call_method("method", args, Some(&kwargs))?;
/// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs");
/// Ok(()) /// Ok(())
/// }) /// })
@ -1401,7 +1401,7 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let instance = module.getattr("a")?; /// let instance = module.getattr("a")?;
/// let result = instance.call_method0("method")?; /// let result = instance.call_method0("method")?;
/// assert_eq!(result.extract::<&str>()?, "called with no arguments"); /// assert_eq!(result.extract::<&str>()?, "called with no arguments");
@ -1436,7 +1436,7 @@ pub trait PyAnyMethods<'py> {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?; /// let module = PyModule::from_code_bound(py, CODE, "", "")?;
/// let instance = module.getattr("a")?; /// let instance = module.getattr("a")?;
/// let args = ("hello",); /// let args = ("hello",);
/// let result = instance.call_method1("method", args)?; /// let result = instance.call_method1("method", args)?;
@ -2326,13 +2326,13 @@ mod tests {
use crate::{ use crate::{
basic::CompareOp, basic::CompareOp,
types::{any::PyAnyMethods, IntoPyDict, PyAny, PyBool, PyList, PyLong, PyModule}, types::{any::PyAnyMethods, IntoPyDict, PyAny, PyBool, PyList, PyLong, PyModule},
PyNativeType, PyTypeInfo, Python, ToPyObject, Bound, PyNativeType, PyTypeInfo, Python, ToPyObject,
}; };
#[test] #[test]
fn test_lookup_special() { fn test_lookup_special() {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::from_code( let module = PyModule::from_code_bound(
py, py,
r#" r#"
class CustomCallable: class CustomCallable:
@ -2371,13 +2371,8 @@ class NonHeapNonDescriptorInt:
.unwrap(); .unwrap();
let int = crate::intern!(py, "__int__"); let int = crate::intern!(py, "__int__");
let eval_int = |obj: &PyAny| { let eval_int =
obj.as_borrowed() |obj: Bound<'_, PyAny>| obj.lookup_special(int)?.unwrap().call0()?.extract::<u32>();
.lookup_special(int)?
.unwrap()
.call0()?
.extract::<u32>()
};
let simple = module.getattr("SimpleInt").unwrap().call0().unwrap(); let simple = module.getattr("SimpleInt").unwrap().call0().unwrap();
assert_eq!(eval_int(simple).unwrap(), 1); assert_eq!(eval_int(simple).unwrap(), 1);
@ -2430,7 +2425,7 @@ class NonHeapNonDescriptorInt:
#[test] #[test]
fn test_call_method0() { fn test_call_method0() {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::from_code( let module = PyModule::from_code_bound(
py, py,
r#" r#"
class SimpleClass: class SimpleClass:

View File

@ -31,7 +31,7 @@ use std::os::raw::{c_char, c_int, c_void};
/// ///
/// let capsule = PyCapsule::new_bound(py, foo, Some(name.clone()))?; /// let capsule = PyCapsule::new_bound(py, foo, Some(name.clone()))?;
/// ///
/// let module = PyModule::import(py, "builtins")?; /// let module = PyModule::import_bound(py, "builtins")?;
/// module.add("capsule", capsule)?; /// module.add("capsule", capsule)?;
/// ///
/// let cap: &Foo = unsafe { PyCapsule::import(py, name.as_ref())? }; /// let cap: &Foo = unsafe { PyCapsule::import(py, name.as_ref())? };
@ -441,11 +441,13 @@ fn name_ptr_ignore_error(slf: &Bound<'_, PyCapsule>) -> *const c_char {
} }
#[cfg(test)] #[cfg(test)]
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
mod tests { mod tests {
use libc::c_void; use libc::c_void;
use crate::prelude::PyModule; use crate::prelude::PyModule;
use crate::types::capsule::PyCapsuleMethods; use crate::types::capsule::PyCapsuleMethods;
use crate::types::module::PyModuleMethods;
use crate::{types::PyCapsule, Py, PyResult, Python}; use crate::{types::PyCapsule, Py, PyResult, Python};
use std::ffi::CString; use std::ffi::CString;
use std::sync::mpsc::{channel, Sender}; use std::sync::mpsc::{channel, Sender};
@ -528,7 +530,7 @@ mod tests {
let capsule = PyCapsule::new_bound(py, foo, Some(name.clone()))?; let capsule = PyCapsule::new_bound(py, foo, Some(name.clone()))?;
let module = PyModule::import(py, "builtins")?; let module = PyModule::import_bound(py, "builtins")?;
module.add("capsule", capsule)?; module.add("capsule", capsule)?;
// check error when wrong named passed for capsule. // check error when wrong named passed for capsule.

View File

@ -1,11 +1,12 @@
use crate::callback::IntoPyCallbackOutput; use crate::callback::IntoPyCallbackOutput;
use crate::err::{PyErr, PyResult}; use crate::err::{PyErr, PyResult};
use crate::ffi_ptr_ext::FfiPtrExt; use crate::ffi_ptr_ext::FfiPtrExt;
use crate::py_result_ext::PyResultExt;
use crate::pyclass::PyClass; use crate::pyclass::PyClass;
use crate::types::{ use crate::types::{
any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString, any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString,
}; };
use crate::{exceptions, ffi, Bound, FromPyObject, IntoPy, Py, PyNativeType, PyObject, Python}; use crate::{exceptions, ffi, Bound, IntoPy, Py, PyNativeType, PyObject, Python};
use std::ffi::CString; use std::ffi::CString;
use std::str; use std::str;
@ -22,6 +23,19 @@ pub struct PyModule(PyAny);
pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::PyModule_Type), #checkfunction=ffi::PyModule_Check); pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::PyModule_Type), #checkfunction=ffi::PyModule_Check);
impl PyModule { impl PyModule {
/// Deprecated form of [`PyModule::new_bound`].
#[inline]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "`PyModule::new` will be replaced by `PyModule::new_bound` in a future PyO3 version"
)
)]
pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<&'py PyModule> {
Self::new_bound(py, name).map(Bound::into_gil_ref)
}
/// Creates a new module object with the `__name__` attribute set to `name`. /// Creates a new module object with the `__name__` attribute set to `name`.
/// ///
/// # Examples /// # Examples
@ -31,22 +45,39 @@ impl PyModule {
/// ///
/// # fn main() -> PyResult<()> { /// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::new(py, "my_module")?; /// let module = PyModule::new_bound(py, "my_module")?;
/// ///
/// assert_eq!(module.name()?, "my_module"); /// assert_eq!(module.name()?.to_cow()?, "my_module");
/// Ok(()) /// Ok(())
/// })?; /// })?;
/// # Ok(())} /// # Ok(())}
/// ``` /// ```
pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> { pub fn new_bound<'py>(py: Python<'py>, name: &str) -> PyResult<Bound<'py, PyModule>> {
// Could use PyModule_NewObject, but it doesn't exist on PyPy. // Could use PyModule_NewObject, but it doesn't exist on PyPy.
let name = CString::new(name)?; let name = CString::new(name)?;
#[allow(deprecated)]
unsafe { unsafe {
py.from_owned_ptr_or_err(ffi::PyModule_New(name.as_ptr())) ffi::PyModule_New(name.as_ptr())
.assume_owned_or_err(py)
.downcast_into_unchecked()
} }
} }
/// Deprecated form of [`PyModule::import_bound`].
#[inline]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "`PyModule::import` will be replaced by `PyModule::import_bound` in a future PyO3 version"
)
)]
pub fn import<N>(py: Python<'_>, name: N) -> PyResult<&PyModule>
where
N: IntoPy<Py<PyString>>,
{
Self::import_bound(py, name).map(Bound::into_gil_ref)
}
/// Imports the Python module with the specified name. /// Imports the Python module with the specified name.
/// ///
/// # Examples /// # Examples
@ -56,7 +87,7 @@ impl PyModule {
/// use pyo3::prelude::*; /// use pyo3::prelude::*;
/// ///
/// Python::with_gil(|py| { /// Python::with_gil(|py| {
/// let module = PyModule::import(py, "antigravity").expect("No flying for you."); /// let module = PyModule::import_bound(py, "antigravity").expect("No flying for you.");
/// }); /// });
/// # } /// # }
/// ``` /// ```
@ -65,17 +96,36 @@ impl PyModule {
/// ```python /// ```python
/// import antigravity /// import antigravity
/// ``` /// ```
pub fn import<N>(py: Python<'_>, name: N) -> PyResult<&PyModule> pub fn import_bound<N>(py: Python<'_>, name: N) -> PyResult<Bound<'_, PyModule>>
where where
N: IntoPy<Py<PyString>>, N: IntoPy<Py<PyString>>,
{ {
let name: Py<PyString> = name.into_py(py); let name: Py<PyString> = name.into_py(py);
#[allow(deprecated)]
unsafe { unsafe {
py.from_owned_ptr_or_err(ffi::PyImport_Import(name.as_ptr())) ffi::PyImport_Import(name.as_ptr())
.assume_owned_or_err(py)
.downcast_into_unchecked()
} }
} }
/// Deprecated form of [`PyModule::from_code_bound`].
#[inline]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "`PyModule::from_code` will be replaced by `PyModule::from_code_bound` in a future PyO3 version"
)
)]
pub fn from_code<'py>(
py: Python<'py>,
code: &str,
file_name: &str,
module_name: &str,
) -> PyResult<&'py PyModule> {
Self::from_code_bound(py, code, file_name, module_name).map(Bound::into_gil_ref)
}
/// Creates and loads a module named `module_name`, /// Creates and loads a module named `module_name`,
/// containing the Python code passed to `code` /// containing the Python code passed to `code`
/// and pretending to live at `file_name`. /// and pretending to live at `file_name`.
@ -105,7 +155,7 @@ impl PyModule {
/// let code = include_str!("../../assets/script.py"); /// let code = include_str!("../../assets/script.py");
/// ///
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// PyModule::from_code(py, code, "example.py", "example")?; /// PyModule::from_code_bound(py, code, "example.py", "example")?;
/// Ok(()) /// Ok(())
/// })?; /// })?;
/// # Ok(()) /// # Ok(())
@ -124,36 +174,29 @@ impl PyModule {
/// let code = std::fs::read_to_string("assets/script.py")?; /// let code = std::fs::read_to_string("assets/script.py")?;
/// ///
/// Python::with_gil(|py| -> PyResult<()> { /// Python::with_gil(|py| -> PyResult<()> {
/// PyModule::from_code(py, &code, "example.py", "example")?; /// PyModule::from_code_bound(py, &code, "example.py", "example")?;
/// Ok(()) /// Ok(())
/// })?; /// })?;
/// Ok(()) /// Ok(())
/// # } /// # }
/// ``` /// ```
pub fn from_code<'p>( pub fn from_code_bound<'py>(
py: Python<'p>, py: Python<'py>,
code: &str, code: &str,
file_name: &str, file_name: &str,
module_name: &str, module_name: &str,
) -> PyResult<&'p PyModule> { ) -> PyResult<Bound<'py, PyModule>> {
let data = CString::new(code)?; let data = CString::new(code)?;
let filename = CString::new(file_name)?; let filename = CString::new(file_name)?;
let module = CString::new(module_name)?; let module = CString::new(module_name)?;
unsafe { unsafe {
let cptr = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input); let code = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input)
if cptr.is_null() { .assume_owned_or_err(py)?;
return Err(PyErr::fetch(py));
}
let mptr = ffi::PyImport_ExecCodeModuleEx(module.as_ptr(), cptr, filename.as_ptr()); ffi::PyImport_ExecCodeModuleEx(module.as_ptr(), code.as_ptr(), filename.as_ptr())
ffi::Py_DECREF(cptr); .assume_owned_or_err(py)
if mptr.is_null() { .downcast_into()
return Err(PyErr::fetch(py));
}
#[allow(deprecated)]
<&PyModule as FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?)
} }
} }
@ -293,10 +336,10 @@ impl PyModule {
/// ///
/// #[pymodule] /// #[pymodule]
/// fn my_module(py: Python<'_>, module: &PyModule) -> PyResult<()> { /// fn my_module(py: Python<'_>, module: &PyModule) -> PyResult<()> {
/// let submodule = PyModule::new(py, "submodule")?; /// let submodule = PyModule::new_bound(py, "submodule")?;
/// submodule.add("super_useful_constant", "important")?; /// submodule.add("super_useful_constant", "important")?;
/// ///
/// module.add_submodule(submodule)?; /// module.add_submodule(submodule.as_gil_ref())?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
@ -487,10 +530,10 @@ pub trait PyModuleMethods<'py> {
/// ///
/// #[pymodule] /// #[pymodule]
/// fn my_module(py: Python<'_>, module: &PyModule) -> PyResult<()> { /// fn my_module(py: Python<'_>, module: &PyModule) -> PyResult<()> {
/// let submodule = PyModule::new(py, "submodule")?; /// let submodule = PyModule::new_bound(py, "submodule")?;
/// submodule.add("super_useful_constant", "important")?; /// submodule.add("super_useful_constant", "important")?;
/// ///
/// module.add_submodule(submodule)?; /// module.add_submodule(submodule.as_gil_ref())?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
@ -580,8 +623,6 @@ impl<'py> PyModuleMethods<'py> for Bound<'py, PyModule> {
fn name(&self) -> PyResult<Bound<'py, PyString>> { fn name(&self) -> PyResult<Bound<'py, PyString>> {
#[cfg(not(PyPy))] #[cfg(not(PyPy))]
{ {
use crate::py_result_ext::PyResultExt;
unsafe { unsafe {
ffi::PyModule_GetNameObject(self.as_ptr()) ffi::PyModule_GetNameObject(self.as_ptr())
.assume_owned_or_err(self.py()) .assume_owned_or_err(self.py())
@ -601,8 +642,6 @@ impl<'py> PyModuleMethods<'py> for Bound<'py, PyModule> {
#[cfg(not(PyPy))] #[cfg(not(PyPy))]
fn filename(&self) -> PyResult<Bound<'py, PyString>> { fn filename(&self) -> PyResult<Bound<'py, PyString>> {
use crate::py_result_ext::PyResultExt;
unsafe { unsafe {
ffi::PyModule_GetFilenameObject(self.as_ptr()) ffi::PyModule_GetFilenameObject(self.as_ptr())
.assume_owned_or_err(self.py()) .assume_owned_or_err(self.py())
@ -676,14 +715,21 @@ fn __name__(py: Python<'_>) -> &Bound<'_, PyString> {
} }
#[cfg(test)] #[cfg(test)]
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
mod tests { mod tests {
use crate::{types::PyModule, Python}; use crate::{
types::{module::PyModuleMethods, string::PyStringMethods, PyModule},
Python,
};
#[test] #[test]
fn module_import_and_name() { fn module_import_and_name() {
Python::with_gil(|py| { Python::with_gil(|py| {
let builtins = PyModule::import(py, "builtins").unwrap(); let builtins = PyModule::import_bound(py, "builtins").unwrap();
assert_eq!(builtins.name().unwrap(), "builtins"); assert_eq!(
builtins.name().unwrap().to_cow().unwrap().as_ref(),
"builtins"
);
}) })
} }
@ -691,8 +737,13 @@ mod tests {
#[cfg(not(PyPy))] #[cfg(not(PyPy))]
fn module_filename() { fn module_filename() {
Python::with_gil(|py| { Python::with_gil(|py| {
let site = PyModule::import(py, "site").unwrap(); let site = PyModule::import_bound(py, "site").unwrap();
assert!(site.filename().unwrap().ends_with("site.py")); assert!(site
.filename()
.unwrap()
.to_cow()
.unwrap()
.ends_with("site.py"));
}) })
} }
} }

View File

@ -1,11 +1,8 @@
use crate::err::{error_on_minusone, PyResult}; use crate::err::{error_on_minusone, PyResult};
use crate::types::PyString; use crate::types::{any::PyAnyMethods, string::PyStringMethods, PyString};
use crate::{ffi, Bound}; use crate::{ffi, Bound};
use crate::{PyAny, PyNativeType}; use crate::{PyAny, PyNativeType};
use super::any::PyAnyMethods;
use super::string::PyStringMethods;
/// Represents a Python traceback. /// Represents a Python traceback.
#[repr(transparent)] #[repr(transparent)]
pub struct PyTraceback(PyAny); pub struct PyTraceback(PyAny);

View File

@ -154,7 +154,7 @@ struct EmptyClassInModule {}
#[ignore] #[ignore]
fn empty_class_in_module() { fn empty_class_in_module() {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::new(py, "test_module.nested").unwrap(); let module = PyModule::new_bound(py, "test_module.nested").unwrap();
module.add_class::<EmptyClassInModule>().unwrap(); module.add_class::<EmptyClassInModule>().unwrap();
let ty = module.getattr("EmptyClassInModule").unwrap(); let ty = module.getattr("EmptyClassInModule").unwrap();

View File

@ -169,10 +169,7 @@ c = Class()
assert c.from_rust is False assert c.from_rust is False
"# "#
); );
let globals = PyModule::import(py, "__main__") let globals = PyModule::import_bound(py, "__main__").unwrap().dict();
.unwrap()
.dict()
.as_borrowed();
globals.set_item("SuperClass", super_cls).unwrap(); globals.set_item("SuperClass", super_cls).unwrap();
py.run_bound(source, Some(&globals), None) py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py)) .map_err(|e| e.display(py))

View File

@ -354,7 +354,7 @@ fn module_add_class_inherit_bool_fails() {
struct ExtendsBool; struct ExtendsBool;
Python::with_gil(|py| { Python::with_gil(|py| {
let m = PyModule::new(py, "test_module").unwrap(); let m = PyModule::new_bound(py, "test_module").unwrap();
let err = m.add_class::<ExtendsBool>().unwrap_err(); let err = m.add_class::<ExtendsBool>().unwrap_err();
assert_eq!( assert_eq!(

View File

@ -135,9 +135,9 @@ fn test_module_renaming() {
} }
#[test] #[test]
fn test_module_from_code() { fn test_module_from_code_bound() {
Python::with_gil(|py| { Python::with_gil(|py| {
let adder_mod = PyModule::from_code( let adder_mod = PyModule::from_code_bound(
py, py,
"def add(a,b):\n\treturn a+b", "def add(a,b):\n\treturn a+b",
"adder_mod.py", "adder_mod.py",
@ -239,8 +239,8 @@ fn subfunction() -> String {
"Subfunction".to_string() "Subfunction".to_string()
} }
fn submodule(module: &PyModule) -> PyResult<()> { fn submodule(module: &Bound<'_, PyModule>) -> PyResult<()> {
module.add_function(wrap_pyfunction!(subfunction, module)?)?; module.add_function(&wrap_pyfunction!(subfunction, module.as_gil_ref())?.as_borrowed())?;
Ok(()) Ok(())
} }
@ -258,12 +258,12 @@ fn superfunction() -> String {
#[pymodule] #[pymodule]
fn supermodule(py: Python<'_>, module: &PyModule) -> PyResult<()> { fn supermodule(py: Python<'_>, module: &PyModule) -> PyResult<()> {
module.add_function(wrap_pyfunction!(superfunction, module)?)?; module.add_function(wrap_pyfunction!(superfunction, module)?)?;
let module_to_add = PyModule::new(py, "submodule")?; let module_to_add = PyModule::new_bound(py, "submodule")?;
submodule(module_to_add)?; submodule(&module_to_add)?;
module.add_submodule(module_to_add)?; module.add_submodule(module_to_add.as_gil_ref())?;
let module_to_add = PyModule::new(py, "submodule_with_init_fn")?; let module_to_add = PyModule::new_bound(py, "submodule_with_init_fn")?;
submodule_with_init_fn(py, module_to_add)?; submodule_with_init_fn(py, module_to_add.as_gil_ref())?;
module.add_submodule(module_to_add)?; module.add_submodule(module_to_add.as_gil_ref())?;
Ok(()) Ok(())
} }

View File

@ -697,10 +697,7 @@ if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
asyncio.run(main()) asyncio.run(main())
"#; "#;
let globals = PyModule::import(py, "__main__") let globals = PyModule::import_bound(py, "__main__").unwrap().dict();
.unwrap()
.dict()
.as_borrowed();
globals.set_item("Once", once).unwrap(); globals.set_item("Once", once).unwrap();
py.run_bound(source, Some(&globals), None) py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py)) .map_err(|e| e.display(py))
@ -754,10 +751,7 @@ if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
asyncio.run(main()) asyncio.run(main())
"#; "#;
let globals = PyModule::import(py, "__main__") let globals = PyModule::import_bound(py, "__main__").unwrap().dict();
.unwrap()
.dict()
.as_borrowed();
globals.set_item("Once", once).unwrap(); globals.set_item("Once", once).unwrap();
globals globals
.set_item("AsyncIterator", py.get_type_bound::<AsyncIterator>()) .set_item("AsyncIterator", py.get_type_bound::<AsyncIterator>())
@ -829,10 +823,7 @@ del c.counter
assert c.counter.count == 1 assert c.counter.count == 1
"# "#
); );
let globals = PyModule::import(py, "__main__") let globals = PyModule::import_bound(py, "__main__").unwrap().dict();
.unwrap()
.dict()
.as_borrowed();
globals.set_item("Counter", counter).unwrap(); globals.set_item("Counter", counter).unwrap();
py.run_bound(source, Some(&globals), None) py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py)) .map_err(|e| e.display(py))

View File

@ -133,8 +133,8 @@ impl PickleSupport {
} }
} }
fn add_module(py: Python<'_>, module: &PyModule) -> PyResult<()> { fn add_module(module: Bound<'_, PyModule>) -> PyResult<()> {
py.import_bound("sys")? PyModule::import_bound(module.py(), "sys")?
.dict() .dict()
.get_item("modules") .get_item("modules")
.unwrap() .unwrap()
@ -147,9 +147,9 @@ fn add_module(py: Python<'_>, module: &PyModule) -> PyResult<()> {
#[cfg_attr(all(Py_LIMITED_API, not(Py_3_10)), ignore)] #[cfg_attr(all(Py_LIMITED_API, not(Py_3_10)), ignore)]
fn test_pickle() { fn test_pickle() {
Python::with_gil(|py| { Python::with_gil(|py| {
let module = PyModule::new(py, "test_module").unwrap(); let module = PyModule::new_bound(py, "test_module").unwrap();
module.add_class::<PickleSupport>().unwrap(); module.add_class::<PickleSupport>().unwrap();
add_module(py, module).unwrap(); add_module(module).unwrap();
let inst = Py::new(py, PickleSupport {}).unwrap(); let inst = Py::new(py, PickleSupport {}).unwrap();
py_run!( py_run!(
py, py,