Struct pyembed::MainPythonInterpreter
source · pub struct MainPythonInterpreter<'interpreter, 'resources: 'interpreter> { /* private fields */ }
Expand description
Manages an embedded Python interpreter.
Python interpreters have global state and there can only be a single
instance of this type per process. There exists a global lock enforcing
this. Calling new()
will block waiting for this lock. The lock is
released when the instance is dropped.
Instances must only be constructed through MainPythonInterpreter::new()
.
This type and its various functionality is a glorified wrapper around the Python C API. But there’s a lot of added functionality on top of what the C API provides.
Usage
Construct instances via MainPythonInterpreter::new(). This will acquire a global lock and initialize the main Python interpreter in the current process.
Python code can then be executed in the interpreter in any number of different ways.
If you want to run whatever was configured to run via the
OxidizedPythonInterpreterConfig used to construct the instance, call
MainPythonInterpreter::run() or MainPythonInterpreter::py_runmain().
The former will honor “multiprocessing worker” and is necessary for
multiprocessing
to work. MainPythonInterpreter::py_runmain() bypasses
multiprocessing mode checks.
If you want to execute arbitrary Python code or want to run Rust code with the GIL held, call MainPythonInterpreter::with_gil(). The provided function will be provided a pyo3::Python, which represents a handle on the Python interpreter. This function is just a wrapper around pyo3::Python::with_gil(). But since the function holds a reference to self, it prevents MainPythonInterpreter from being dropped prematurely.
Safety
Dropping a MainPythonInterpreter instance will call Py_FinalizeEx()
to
finalize the Python interpreter and prevent it from running any more Python
code.
If a Python C API is called after interpreter finalization, a segfault can occur.
If you use pyo3 APIs like Python::with_gil() directly, you may inadvertently attempt to operate on a finalized interpreter. Therefore it is recommended to always go through a method on an MainPythonInterpreter instance in order to interact with the Python interpreter.
Implementations§
source§impl<'interpreter, 'resources> MainPythonInterpreter<'interpreter, 'resources>
impl<'interpreter, 'resources> MainPythonInterpreter<'interpreter, 'resources>
sourcepub fn new(
config: OxidizedPythonInterpreterConfig<'resources>
) -> Result<MainPythonInterpreter<'interpreter, 'resources>, NewInterpreterError>
pub fn new(
config: OxidizedPythonInterpreterConfig<'resources>
) -> Result<MainPythonInterpreter<'interpreter, 'resources>, NewInterpreterError>
Construct a Python interpreter from a configuration.
The Python interpreter is initialized as a side-effect. The GIL is held.
sourcepub fn with_gil<F, R>(&self, f: F) -> Rwhere
F: for<'py> FnOnce(Python<'py>) -> R,
pub fn with_gil<F, R>(&self, f: F) -> Rwhere
F: for<'py> FnOnce(Python<'py>) -> R,
Proxy for Python::with_gil().
This allows running Python code via the PyO3 Rust APIs. Alternatively, this can be used to run code when the Python GIL is held.
sourcepub fn py_runmain(self) -> i32
pub fn py_runmain(self) -> i32
Runs Py_RunMain()
and finalizes the interpreter.
This will execute whatever is configured by the Python interpreter config and return an integer suitable for use as a process exit code.
Calling this function will finalize the interpreter and only gives you an exit code: there is no opportunity to inspect the return value or handle an uncaught exception. If you want to keep the interpreter alive or inspect the evaluation result, consider calling a function on the interpreter handle that executes code.
sourcepub fn run_multiprocessing(&self) -> PyResult<i32>
pub fn run_multiprocessing(&self) -> PyResult<i32>
Run in “multiprocessing worker” mode.
This should be called when sys.argv[1] == "--multiprocessing-fork"
. It
will parse arguments for the worker from sys.argv
and call into the
multiprocessing
module to perform work.
sourcepub fn is_multiprocessing(&self) -> bool
pub fn is_multiprocessing(&self) -> bool
Whether the Python interpreter is in “multiprocessing worker” mode.
The multiprocessing
module can work by spawning new processes
with arguments --multiprocessing-fork [key=value] ...
. This function
detects if the current Python interpreter is configured for said execution.
sourcepub fn run(self) -> i32
pub fn run(self) -> i32
Runs the Python interpreter.
If multiprocessing dispatch is enabled, this will check if the current process invocation appears to be a spawned multiprocessing worker and dispatch to multiprocessing accordingly.
Otherwise, this delegates to Self::py_runmain.