Modules
In Python, just like in Rust, your code is organized into modules.
Your entire extension is a module!
That module is defined using pyo3
's #[pymodule]
procedural macro, as
you've seen in the previous section:
#![allow(unused)] fn main() { #[pymodule] fn setup(m: &Bound<'_, PyModule>) -> PyResult<()> { // [...] } }
setup
becomes the entry point for the Python interpreter to load your extension.
Naming matters
The name of the annotated function is important: there must be at least one module with a name that matches the name of
the dynamic library artifact that Python will try to load.
This is the name of the library target specified in your Cargo.toml
file:
[lib]
name = "name_of_your_rust_library"
If you don't have a [lib]
section, it defaults to the name of your package,
specified in the [package]
section.
If the module name and the library name don't match, Python will raise an error when trying to import the module:
ImportError: dynamic module does not define
module export function (PyInit_name_of_your_module)
The name
argument
You can also specify the name of the module explicitly using the name
argument,
rather than relying on the name of the annotated function:
#![allow(unused)] fn main() { #[pymodule] #[pyo3(name = "setup")] fn random_name(m: &Bound<'_, PyModule>) -> PyResult<()> { // [...] } }
Mysterious types?
You might be wondering: what's up with &Bound<'_, PyModule>
? What about PyResult
?
Don't worry, we'll cover these types in due time later in the course.
Go with the flow for now!
Exercise
The exercise for this section is located in 01_intro/02_modules