#pyo3 #cpython #python #api-bindings

pyo3-commonize

Allow PyO3 classes to be passed between different PyO3 crates

5 releases

0.1.4 Sep 13, 2024
0.1.3 Sep 5, 2024
0.1.2 Sep 3, 2024
0.1.1 Sep 2, 2024
0.1.0 Aug 26, 2024

#142 in FFI

Download history 180/week @ 2024-08-26 552/week @ 2024-09-02 166/week @ 2024-09-09 58/week @ 2024-09-16 50/week @ 2024-09-23 10/week @ 2024-09-30 1/week @ 2024-10-07

328 downloads per month

MIT license

16KB
286 lines

pyo3-commonize Latest Version Documentation GitHub Actions

Using this crate, the classes defined using #[pyclass] can be passed between multiple Python native extensions built with PyO3.

ABI safetyness

When using this crate, it is essential to pay strict attention to ABI compatibility. To define ABI-compatible classes, it is recommended to use crates like abi_stable. (In the future, this crate may require the implementation of abi_stable::StableAbi.)

To mitigate this issue, pyo3-commonize checks the following points: the last modified date of the source code for the specified crate and all of its dependency crates, as well as the build environment (target and host versions, Rust flags, optimization levels, etc.).

Quick setup

Example to pass MyClass class defined in acceptor crate from donor to acceptor.

acceptor crate

  • in Cargo.toml
[package]
name = "acceptor"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["rlib", "cdylib"]
[dependencies]
pyo3-commonize = "0.1.0"
pyo3 = "*"  # pyo3-commonize fixes pyo3 version
  • in pyproject.toml
[build-system]
requires = ["poetry-core>=1.0.0", "maturin>=1.0,<2.0"]
build-backend = "maturin"
[project]
name = "acceptor"
version = "0.1.0"
license = { text = "MIT" }
  • in src/lib.rs
use pyo3::prelude::*;
use pyo3_commonize::{commonize, Commonized};

#[pyclass]
#[derive(Commonized)]
pub struct MyClass;

#[pyfunction]
fn accept(_my_class: Py<MyClass>) {}

#[pymodule]
fn acceptor(py: Python<'_>, m: Bound<'_, PyModule>) -> PyResult<()> {
    // This function should be called at first
    commonize::<MyClass>(py)?;
    m.add_function(wrap_pyfunction!(accept, &m)?)?;
    Ok(())
}

donor crate

  • in Cargo.toml
[package]
name = "donor"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["rlib", "cdylib"]
[dependencies]
pyo3-commonize = "0.1.0"
pyo3 = "*"  # pyo3-commonize fixes pyo3 version
acceptor = { path = "<path>" }
  • in pyproject.toml
[build-system]
requires = ["poetry-core>=1.0.0", "maturin>=1.0,<2.0"]
build-backend = "maturin"
[project]
name = "donor"
version = "0.1.0"
license = { text = "MIT" }
  • in src/lib.rs
use acceptor::MyClass;
use pyo3::prelude::*;
use pyo3_commonize::commonize;

#[pyfunction]
fn generate() -> MyClass { MyClass }

#[pymodule]
fn donor(py: Python<'_>, m: Bound<'_, PyModule>) -> PyResult<()> {
    commonize::<MyClass>(py)?;
    m.add_function(wrap_pyfunction!(generate, &m)?)?;
    Ok(())
}

Dependencies

~3–13MB
~263K SLoC