Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reintroduce PyModule constructors #4404

Merged
merged 6 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/maturin-starter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn maturin_starter(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
// Inserting to sys.modules allows importing submodules nicely from Python
// e.g. from maturin_starter.submodule import SubmoduleClass

let sys = PyModule::import_bound(py, "sys")?;
let sys = PyModule::import(py, "sys")?;
let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
sys_modules.set_item("maturin_starter.submodule", m.getattr("submodule")?)?;

Expand Down
2 changes: 1 addition & 1 deletion examples/plugin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

// Now we can load our python_plugin/gadget_init_plugin.py file.
// It can in turn import other stuff as it deems appropriate
let plugin = PyModule::import_bound(py, "gadget_init_plugin")?;
let plugin = PyModule::import(py, "gadget_init_plugin")?;
// and call start function there, which will return a python reference to Gadget.
// Gadget here is a "pyclass" object reference
let gadget = plugin.getattr("start")?.call0()?;
Expand Down
2 changes: 1 addition & 1 deletion examples/setuptools-rust-starter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn _setuptools_rust_starter(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult
// Inserting to sys.modules allows importing submodules nicely from Python
// e.g. from setuptools_rust_starter.submodule import SubmoduleClass

let sys = PyModule::import_bound(py, "sys")?;
let sys = PyModule::import(py, "sys")?;
let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;
sys_modules.set_item("setuptools_rust_starter.submodule", m.getattr("submodule")?)?;

Expand Down
4 changes: 2 additions & 2 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -968,8 +968,8 @@ impl MyClass {
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| {
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let module = PyModule::new_bound(py, "my_module")?;
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let module = PyModule::new(py, "my_module")?;
# module.add_class::<MyClass>()?;
# let class = module.getattr("MyClass")?;
#
Expand Down
2 changes: 1 addition & 1 deletion guide/src/class/numeric.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ fn my_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let globals = PyModule::import_bound(py, "__main__")?.dict();
# let globals = PyModule::import(py, "__main__")?.dict();
# globals.set_item("Number", Number::type_object_bound(py))?;
#
# py.run_bound(SCRIPT, Some(&globals), None)?;
Expand Down
43 changes: 23 additions & 20 deletions guide/src/conversions/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ the Python object, i.e. `obj.getattr("my_string")`, and call `extract()` on the

```rust
use pyo3::prelude::*;
use pyo3_ffi::c_str;

#[derive(FromPyObject)]
struct RustyStruct {
Expand All @@ -54,13 +55,13 @@ struct RustyStruct {
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let module = PyModule::from_code_bound(
# let module = PyModule::from_code(
# py,
# "class Foo:
# c_str!("class Foo:
# def __init__(self):
# self.my_string = 'test'",
# "",
# "",
# self.my_string = 'test'"),
# c_str!(""),
# c_str!(""),
# )?;
#
# let class = module.getattr("Foo")?;
Expand Down Expand Up @@ -100,6 +101,7 @@ The argument passed to `getattr` and `get_item` can also be configured:

```rust
use pyo3::prelude::*;
use pyo3_ffi::c_str;

#[derive(FromPyObject)]
struct RustyStruct {
Expand All @@ -111,14 +113,14 @@ struct RustyStruct {
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let module = PyModule::from_code_bound(
# let module = PyModule::from_code(
# py,
# "class Foo(dict):
# c_str!("class Foo(dict):
# def __init__(self):
# self.name = 'test'
# self['key'] = 'test2'",
# "",
# "",
# self['key'] = 'test2'"),
# c_str!(""),
# c_str!(""),
# )?;
#
# let class = module.getattr("Foo")?;
Expand Down Expand Up @@ -262,6 +264,7 @@ attribute can be applied to single-field-variants.

```rust
use pyo3::prelude::*;
use pyo3_ffi::c_str;

#[derive(FromPyObject)]
# #[derive(Debug)]
Expand Down Expand Up @@ -339,15 +342,15 @@ enum RustyEnum<'py> {
# );
# }
# {
# let module = PyModule::from_code_bound(
# let module = PyModule::from_code(
# py,
# "class Foo(dict):
# c_str!("class Foo(dict):
# def __init__(self):
# self.x = 0
# self.y = 1
# self.z = 2",
# "",
# "",
# self.z = 2"),
# c_str!(""),
# c_str!(""),
# )?;
#
# let class = module.getattr("Foo")?;
Expand All @@ -364,14 +367,14 @@ enum RustyEnum<'py> {
# }
#
# {
# let module = PyModule::from_code_bound(
# let module = PyModule::from_code(
# py,
# "class Foo(dict):
# c_str!("class Foo(dict):
# def __init__(self):
# self.x = 3
# self.y = 4",
# "",
# "",
# self.y = 4"),
# c_str!(""),
# c_str!(""),
# )?;
#
# let class = module.getattr("Foo")?;
Expand Down
8 changes: 4 additions & 4 deletions guide/src/function/signature.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
# Python::with_gil(|py| {
# let fun = pyo3::wrap_pyfunction!(increment, py)?;
#
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect
# .call1((fun,))?
# .call_method0("__str__")?
Expand Down Expand Up @@ -178,7 +178,7 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
# Python::with_gil(|py| {
# let fun = pyo3::wrap_pyfunction!(increment, py)?;
#
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect
# .call1((fun,))?
# .call_method0("__str__")?
Expand Down Expand Up @@ -221,7 +221,7 @@ fn add(a: u64, b: u64) -> u64 {
# let doc: String = fun.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
#
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect
# .call1((fun,))?
# .call_method0("__str__")?
Expand Down Expand Up @@ -269,7 +269,7 @@ fn add(a: u64, b: u64) -> u64 {
# let doc: String = fun.getattr("__doc__")?.extract()?;
# assert_eq!(doc, "This function adds two unsigned 64-bit integers.");
#
# let inspect = PyModule::import_bound(py, "inspect")?.getattr("signature")?;
# let inspect = PyModule::import(py, "inspect")?.getattr("signature")?;
# let sig: String = inspect
# .call1((fun,))?
# .call_method0("__str__")?
Expand Down
2 changes: 1 addition & 1 deletion guide/src/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn parent_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
}

fn register_child_module(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
let child_module = PyModule::new_bound(parent_module.py(), "child_module")?;
let child_module = PyModule::new(parent_module.py(), "child_module")?;
child_module.add_function(wrap_pyfunction!(func, &child_module)?)?;
parent_module.add_submodule(&child_module)
}
Expand Down
57 changes: 31 additions & 26 deletions guide/src/python-from-rust/calling-existing-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

If you already have some existing Python code that you need to execute from Rust, the following FAQs can help you select the right PyO3 functionality for your situation:

## Want to access Python APIs? Then use `PyModule::import_bound`.
## Want to access Python APIs? Then use `PyModule::import`.

[`PyModule::import_bound`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.import_bound) can
[`PyModule::import`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.import) can
be used to get handle to a Python module from Rust. You can use this to import and use any Python
module available in your environment.

Expand All @@ -13,7 +13,7 @@ use pyo3::prelude::*;

fn main() -> PyResult<()> {
Python::with_gil(|py| {
let builtins = PyModule::import_bound(py, "builtins")?;
let builtins = PyModule::import(py, "builtins")?;
let total: i32 = builtins
.getattr("sum")?
.call1((vec![1, 2, 3],))?
Expand Down Expand Up @@ -95,9 +95,9 @@ assert userdata.as_tuple() == userdata_as_tuple
# }
```

## You have a Python file or code snippet? Then use `PyModule::from_code_bound`.
## You have a Python file or code snippet? Then use `PyModule::from_code`.

[`PyModule::from_code_bound`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.from_code_bound)
[`PyModule::from_code`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.from_code)
can be used to generate a Python module which can then be used just as if it was imported with
`PyModule::import`.

Expand All @@ -106,21 +106,22 @@ to this function!

```rust
use pyo3::{prelude::*, types::IntoPyDict};
use pyo3_ffi::c_str;

# fn main() -> PyResult<()> {
Python::with_gil(|py| {
let activators = PyModule::from_code_bound(
let activators = PyModule::from_code(
py,
r#"
c_str!(r#"
def relu(x):
"""see https://en.wikipedia.org/wiki/Rectifier_(neural_networks)"""
return max(0.0, x)
def leaky_relu(x, slope=0.01):
return x if x >= 0 else x * slope
"#,
"activators.py",
"activators",
"#),
c_str!("activators.py"),
c_str!("activators"),
)?;

let relu_result: f64 = activators.getattr("relu")?.call1((-1.0,))?.extract()?;
Expand Down Expand Up @@ -171,7 +172,7 @@ fn main() -> PyResult<()> {
```

If `append_to_inittab` cannot be used due to constraints in the program,
an alternative is to create a module using [`PyModule::new_bound`]
an alternative is to create a module using [`PyModule::new`]
and insert it manually into `sys.modules`:

```rust
Expand All @@ -186,11 +187,11 @@ pub fn add_one(x: i64) -> i64 {
fn main() -> PyResult<()> {
Python::with_gil(|py| {
// Create new module
let foo_module = PyModule::new_bound(py, "foo")?;
let foo_module = PyModule::new(py, "foo")?;
foo_module.add_function(wrap_pyfunction!(add_one, &foo_module)?)?;

// Import and get sys.modules
let sys = PyModule::import_bound(py, "sys")?;
let sys = PyModule::import(py, "sys")?;
let py_modules: Bound<'_, PyDict> = sys.getattr("modules")?.downcast_into()?;

// Insert foo into sys.modules
Expand Down Expand Up @@ -249,16 +250,17 @@ The example below shows:
`src/main.rs`:
```rust,ignore
use pyo3::prelude::*;
use pyo3_ffi::c_str;
fn main() -> PyResult<()> {
let py_foo = include_str!(concat!(
let py_foo = c_str!(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/python_app/utils/foo.py"
));
let py_app = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/python_app/app.py"));
)));
let py_app = c_str!(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/python_app/app.py")));
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
PyModule::from_code_bound(py, py_foo, "utils.foo", "utils.foo")?;
let app: Py<PyAny> = PyModule::from_code_bound(py, py_app, "", "")?
PyModule::from_code(py, py_foo, c_str!("utils.foo"), c_str!("utils.foo"))?;
let app: Py<PyAny> = PyModule::from_code(py, py_app, c_str!(""), c_str!(""))?
.getattr("run")?
.into();
app.call0(py)
Expand All @@ -283,19 +285,21 @@ that directory is `/usr/share/python_app`).
```rust,no_run
use pyo3::prelude::*;
use pyo3::types::PyList;
use pyo3_ffi::c_str;
use std::fs;
use std::path::Path;
use std::ffi::CString;
fn main() -> PyResult<()> {
let path = Path::new("/usr/share/python_app");
let py_app = fs::read_to_string(path.join("app.py"))?;
let py_app = CString::new(fs::read_to_string(path.join("app.py"))?)?;
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let syspath = py
.import("sys")?
.getattr("path")?
.downcast_into::<PyList>()?;
syspath.insert(0, &path)?;
let app: Py<PyAny> = PyModule::from_code_bound(py, &py_app, "", "")?
let app: Py<PyAny> = PyModule::from_code(py, py_app.as_c_str(), c_str!(""), c_str!(""))?
.getattr("run")?
.into();
app.call0(py)
Expand All @@ -316,12 +320,13 @@ Use context managers by directly invoking `__enter__` and `__exit__`.

```rust
use pyo3::prelude::*;
use pyo3_ffi::c_str;

fn main() {
Python::with_gil(|py| {
let custom_manager = PyModule::from_code_bound(
let custom_manager = PyModule::from_code(
py,
r#"
c_str!(r#"
class House(object):
def __init__(self, address):
self.address = address
Expand All @@ -333,9 +338,9 @@ class House(object):
else:
print(f"Thank you for visiting {self.address}, come again soon!")
"#,
"house.py",
"house",
"#),
c_str!("house.py"),
c_str!("house"),
)
.unwrap();

Expand Down Expand Up @@ -394,4 +399,4 @@ Python::with_gil(|py| -> PyResult<()> {
```


[`PyModule::new_bound`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.new_bound
[`PyModule::new`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.new
Loading
Loading