diff --git a/Cargo.lock b/Cargo.lock index 76a9513..de2aa6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -567,7 +567,7 @@ dependencies = [ [[package]] name = "pyo3_bindgen" -version = "0.3.0" +version = "0.3.1" dependencies = [ "pyo3_bindgen_engine", "pyo3_bindgen_macros", @@ -575,7 +575,7 @@ dependencies = [ [[package]] name = "pyo3_bindgen_cli" -version = "0.3.0" +version = "0.3.1" dependencies = [ "assert_cmd", "clap", @@ -587,7 +587,7 @@ dependencies = [ [[package]] name = "pyo3_bindgen_engine" -version = "0.3.0" +version = "0.3.1" dependencies = [ "criterion", "indoc", @@ -605,12 +605,10 @@ dependencies = [ [[package]] name = "pyo3_bindgen_macros" -version = "0.3.0" +version = "0.3.1" dependencies = [ - "proc-macro2", "pyo3", "pyo3_bindgen_engine", - "quote", "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 178b4d2..caf2e89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,12 @@ license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/AndrejOrsula/pyo3_bindgen" rust-version = "1.74" -version = "0.3.0" +version = "0.3.1" [workspace.dependencies] -pyo3_bindgen = { path = "pyo3_bindgen", version = "0.3.0" } -pyo3_bindgen_engine = { path = "pyo3_bindgen_engine", version = "0.3.0" } -pyo3_bindgen_macros = { path = "pyo3_bindgen_macros", version = "0.3.0" } +pyo3_bindgen = { path = "pyo3_bindgen", version = "0.3.1" } +pyo3_bindgen_engine = { path = "pyo3_bindgen_engine", version = "0.3.1" } +pyo3_bindgen_macros = { path = "pyo3_bindgen_macros", version = "0.3.1" } assert_cmd = { version = "2" } clap = { version = "4.5", features = ["derive"] } diff --git a/README.md b/README.md index 2d0103e..4ed0a9b 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,6 @@ fn main() -> Result<(), Box> { // Generate Rust bindings to Python modules Codegen::new(Config::default())? .module_name("py_module")? - .module_names(&["other_module.core", "other_module.utils.io"])? .build(std::path::Path::new(&std::env::var("OUT_DIR")?).join("bindings.rs"))?; Ok(()) } @@ -132,7 +131,7 @@ Afterwards, run the `pyo3_bindgen` executable while passing the name of the targ ```bash # Pass `--help` to show the usage and available options -pyo3_bindgen -m py_module other_module.core -o bindings.rs +pyo3_bindgen -m py_module -o bindings.rs ``` ### Option 3 \[Experimental\]: Procedural macros diff --git a/pyo3_bindgen/Cargo.toml b/pyo3_bindgen/Cargo.toml index c33215d..7d286af 100644 --- a/pyo3_bindgen/Cargo.toml +++ b/pyo3_bindgen/Cargo.toml @@ -16,7 +16,7 @@ pyo3_bindgen_engine = { workspace = true } pyo3_bindgen_macros = { workspace = true, optional = true } [features] -default = ["macros"] +default = [] macros = ["pyo3_bindgen_macros"] [lib] diff --git a/pyo3_bindgen/src/lib.rs b/pyo3_bindgen/src/lib.rs index c337265..44fc354 100644 --- a/pyo3_bindgen/src/lib.rs +++ b/pyo3_bindgen/src/lib.rs @@ -1,4 +1,81 @@ -#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../README.md"))] +//!

+//! crates.io +//! docs.rs +//! Rust +//! deps.rs +//! codecov.io +//!

+//! +//! Automatic generation of Rust FFI bindings to Python modules via [PyO3](https://pyo3.rs). Python modules are analyzed recursively to generate Rust bindings with an identical structure for all public classes, functions, properties, and constants. Any available docstrings and type annotations are also preserved in their Rust equivalents. +//! +//! ## Instructions +//! +//! Add `pyo3` as a dependency and `pyo3_bindgen` as a build dependency to your [`Cargo.toml`](https://doc.rust-lang.org/cargo/reference/manifest.html) manifest (`auto-initialize` feature of `pyo3` is optional and shown here for your convenience). +//! +//! ```toml +//! [dependencies] +//! pyo3 = { version = "0.20", features = ["auto-initialize"] } +//! +//! [build-dependencies] +//! pyo3_bindgen = { version = "0.3" } +//! ``` +//! +//! ### Option 1: Build script +//! +//! Create a [`build.rs`](https://doc.rust-lang.org/cargo/reference/build-scripts.html) script in the root of your crate that generates bindings to the `py_module` Python module. +//! +//! ```no_run +//! // build.rs +//! use pyo3_bindgen::{Codegen, Config}; +//! +//! fn main() -> Result<(), Box> { +//! // Generate Rust bindings to Python modules +//! Codegen::new(Config::default())? +//! .module_name("py_module")? +//! .build(std::path::Path::new(&std::env::var("OUT_DIR")?).join("bindings.rs"))?; +//! Ok(()) +//! } +//! ``` +//! +//! Afterwards, include the generated bindings anywhere in your crate. +//! +//! ```ignore +//! include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +//! pub use py_module::*; +//! ``` +//! +//! ### Option 2: CLI tool +//! +//! Install the `pyo3_bindgen` executable with `cargo`. +//! +//! ```bash +//! cargo install --locked pyo3_bindgen_cli +//! ``` +//! +//! Afterwards, run the `pyo3_bindgen` executable while passing the name of the target Python module. +//! +//! ```bash +//! # Pass `--help` to show the usage and available options +//! pyo3_bindgen -m py_module -o bindings.rs +//! ``` +//! +//! ### Option 3 \[Experimental\]: Procedural macros +//! +//! > **Note:** This feature is experimental and will probably fail in many cases. It is recommended to use build scripts instead. +//! +//! Enable the `macros` feature of `pyo3_bindgen`. +//! +//! ```toml +//! [build-dependencies] +//! pyo3_bindgen = { version = "0.3", features = ["macros"] } +//! ``` +//! +//! Then, you can call the `import_python!` macro anywhere in your crate. +//! +//! ```ignore +//! pyo3_bindgen::import_python!("py_module"); +//! pub use py_module::*; +//! ``` // Public API re-exports from engine pub use pyo3_bindgen_engine::{pyo3, Codegen, Config, PyBindgenError, PyBindgenResult}; diff --git a/pyo3_bindgen_engine/src/codegen.rs b/pyo3_bindgen_engine/src/codegen.rs index 241ff48..7b641c5 100644 --- a/pyo3_bindgen_engine/src/codegen.rs +++ b/pyo3_bindgen_engine/src/codegen.rs @@ -26,15 +26,16 @@ use rustc_hash::FxHashSet as HashSet; /// ``` /// /// For more focused generation, paths to specific submodules can be provided. -/// In the following example, only the `core` and `utils.io` submodules of the -/// `other_module` module will be included in the generated bindings alongside -/// their respective submodules, classes, functions, and parameters. +/// In the following example, only the `entities` and `parser` submodules of the +/// `html` module will be included in the generated bindings alongside their +/// respective submodules, classes, functions, and parameters. No direct attributes +/// or submodules of the `html` top-level module will be included. /// /// ```no_run /// # use pyo3_bindgen_engine::{Codegen, Config}; /// fn main() -> Result<(), Box> { /// Codegen::new(Config::default())? -/// .module_names(&["other_module.core", "other_module.utils.io"])? +/// .module_names(&["html.entities", "html.parser"])? /// .generate()?; /// Ok(()) /// } diff --git a/pyo3_bindgen_macros/Cargo.toml b/pyo3_bindgen_macros/Cargo.toml index 36da026..904f1fa 100644 --- a/pyo3_bindgen_macros/Cargo.toml +++ b/pyo3_bindgen_macros/Cargo.toml @@ -12,9 +12,7 @@ rust-version.workspace = true version.workspace = true [dependencies] -proc-macro2 = { workspace = true } pyo3_bindgen_engine = { workspace = true } -quote = { workspace = true } syn = { workspace = true } [dev-dependencies] diff --git a/pyo3_bindgen_macros/src/lib.rs b/pyo3_bindgen_macros/src/lib.rs index fe6954b..caa40d4 100644 --- a/pyo3_bindgen_macros/src/lib.rs +++ b/pyo3_bindgen_macros/src/lib.rs @@ -13,6 +13,7 @@ mod parser; /// Here is a simple example of how to use the macro to generate bindings for the `sys` module. /// /// ```ignore +/// # use pyo3_bindgen_macros::import_python; /// import_python!("sys"); /// pub use sys::*; /// ``` @@ -20,13 +21,15 @@ mod parser; /// For consistency, the top-level package is always included in the generated bindings. /// /// ```ignore -/// import_python!("mod.submod.subsubmod"); -/// pub use mod::submod::subsubmod::*; +/// # use pyo3_bindgen_macros::import_python; +/// import_python!("html.parser"); +/// pub use html::parser::*; /// ``` /// /// Furthermore, the actual name of the package is always used regardless of how it is aliased. /// /// ```ignore +/// # use pyo3_bindgen_macros::import_python; /// import_python!("os.path"); /// pub use posixpath::*; /// ```