Controlling Python from Rust Code¶
Initializing a Python Interpreter¶
Initializing an embedded Python interpreter in your Rust process is as simple
as calling
pyembed::MainPythonInterpreter::new(config: OxidizedPythonInterpreterConfig).
The hardest part about this is constructing the
pyembed::OxidizedPythonInterpreterConfig instance.
Using a Python Interpreter¶
Once you’ve constructed a pyembed::MainPythonInterpreter instance, you
can obtain a pyo3::Python instance via .with_gil() and then
use it:
fn do_it(interpreter: &MainPythonInterpreter) -> {
interpreter.with_gil(|py| {
match py.eval("print('hello, world')") {
Ok(_) => print("python code executed successfully"),
Err(e) => print("python error: {:?}", e),
}
});
}
Since CPython’s API relies on static variables (sadly), if you really wanted
to, you could call out to CPython C APIs directly (probably via the
bindings in the pyo3 crate) and they would interact with the
interpreter started by the pyembed crate. This is all unsafe, of course,
so tread at your own peril.
Finalizing the Interpreter¶
pyembed::MainPythonInterpreter implements Drop and it will call
Py_FinalizeEx() when called. So to terminate the Python interpreter, simply
have the MainPythonInterpreter instance go out of scope or drop it
explicitly.
A Note on the pyembed APIs¶
The pyembed crate is highly tailored towards PyOxidizer’s default use
cases and the APIs are not considered extremely well polished.
While the functionality should work, the ergonomics may not be great.
It is a goal of the PyOxidizer project to support Rust programmers who want
to embed Python in Rust applications. So contributions to improve the quality
of the pyembed crate will likely be greatly appreciated!