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

How can I generate my own code instead of a third-party library? #21

Closed
wuxinfashi687 opened this issue Apr 23, 2024 · 2 comments
Closed

Comments

@wuxinfashi687
Copy link

Thanks to the author's efforts, I successfully converted some of the standard Python libraries into Rust code, and I thought that I could only convert the Python code I wrote into Rust code, and if I could, this library would be very easy to use。

@AndrejOrsula
Copy link
Owner

AndrejOrsula commented Apr 23, 2024

Hello @wuxinfashi687,

Just for clarification, this project does not convert Python code into native Rust code. With pyo3_bindgen, you can generate bindings for calling Python from Rust. During runtime, the Python code must still be available to the underlying Python interpreter.

Option 1 (generate from Python module) [recommended]: If you wish to generate bindings to your own code, you could install it as a module in your local Python environment. You can do that in several ways, such as python -m pip install <path/to/my_module> if you use pip, or you can even directly modify the PYTHONPATH environment variable such that it includes a path to your module. Then, you can generate the bindings as usual:

let bindings = pyo3_bindgen::Codegen::default()
    .module_name("my_module")
    .unwrap()
    .generate()
    .unwrap();

Note

See the message below for simplified usage

Option 2 (generate from source code string): To quickly see the generated Rust bindings for any single-file Python code, you could use Codegen::module_from_str(). However — as mentioned above, the Python code must still be available to the underlying Python interpreter during runtime.

const PYTHON_SOURCE_CODE: &str = include_str!("path/to/python/source_code.py");

let bindings = pyo3_bindgen::Codegen::default()
    .module_from_str(PYTHON_SOURCE_CODE, "my_module")
    .unwrap()
    .generate()
    .unwrap();

Runtime embedding of Python source code: If using Python modules is not an option (e.g. you wish to make your Rust code more portable), you could try embedding your single-file Python source code within your runtime Rust binary. You must make the module available to Python under the same name that you used to generate the bindings. This can be done in multiple ways, e.g. with sys.modules. However, I have not tested this workflow yet.

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

const PYTHON_SOURCE_CODE: &str = include_str!("path/to/python/source_code.py");

pyo3::prepare_freethreaded_python();
pyo3::Python::with_gil(|py| {
    let my_module = pyo3::types::PyModule::from_code(
        py,
        PYTHON_SOURCE_CODE,
        "my_module/__init__.py",
        "my_module",
    )
    .unwrap();

    py.import("sys")
        .unwrap()
        .getattr("modules")
        .unwrap()
        .set_item("my_module", my_module)
        .unwrap();
});

@AndrejOrsula
Copy link
Owner

Since 0.5.0 (#20), function pyo3_embed_python_source_code() is now automatically included in all Rust modules generated from Python code via Codegen::module_from_str(). Therefore, you do not need to manually embed the Python code yourself, but you can instead use this convenience function instead. Below is an example of how the code above can be simplified.

Generate the bindings (same as before):

const PYTHON_SOURCE_CODE: &str = include_str!("path/to/python/source_code.py");

let bindings = pyo3_bindgen::Codegen::default()
    .module_from_str(PYTHON_SOURCE_CODE, "my_module")
    .unwrap()
    .generate()
    .unwrap();
}

Use the generated bindings:

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

pyo3::prepare_freethreaded_python();
pyo3::Python::with_gil(|py| {
    // Embed the Python source code for the module `my_module` into the underlying Python interpreter
    my_module::pyo3_embed_python_source_code(py)?;

    // Use the module `my_module` (e.g. call a function from it)
    my_module::my_function(py)?;
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants