Module 03 — First PyO3 Binding
Goal
Expose a pure Rust function to Python so that:
from open_engineering_kernel import normalize_identifier
assert normalize_identifier(" OE.PICO.LAMP ") == "oe.pico.lamp"Conceptual flow
Python
│ function call
▼
PyO3
│
▼
Rust
The binding (simplified)
use pyo3::prelude::*;
use pyo3::types::PyModule;
use pyo3::PyResult;
#[pyfunction]
fn normalize_identifier(value: &str) -> String {
value.trim().to_lowercase()
}
#[pymodule]
fn open_engineering_kernel(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(normalize_identifier, m)?)?;
Ok(())
}(The actual course kernel uses the current stable PyO3 API; see kernel/src/lib.rs.)
What you should understand
- The domain function can be tested in Rust before any Python binding exists.
- PyO3 is the bridge, not the place where domain rules live.
- From the Python side the result looks like an ordinary function.
Exercise
- Locate
normalize_identifierin the kernel. - Call it from a small Python script after
maturin develop. - Confirm the Rust unit test for the same logic still passes with
cargo test.