rustimport

repository·master·Indexed 43 days ago

https://github.com/mityax/rustimport

A tool that allows developers to import Rust code directly into Python with zero manual boilerplate. It automates compilation, Cargo configuration, and PyO3 bindings, enabling the integration of high-performance Rust logic via a Python import hook, explicit functions like rustimport.imp, or Jupyter Notebook cell magics.

Tokens
2.1K
Snippets
13
Records
15
Agent score
5%

What's inside rustimport

  1. Opt-in to the rustimport import hook

    master

    To prevent rustimport from interfering with other Python imports, it uses an "opt-in" system. You must signal that a file or crate is intended for rustimport using one of the following methods:

    1. For single .rs files: Add a # rustimport comment to the first line of the file.
    2. For Rust crates:
      • Create a .rustimport file in the crate's root folder (next to Cargo.toml).
      • OR add a # rustimport comment to the first line of Cargo.toml.
  2. How rustimport manages compilation and dependencies

    master

    rustimport automates the Edit -> Compile -> Test cycle by combining compilation and importing into a single import statement.

    Compilation Logic

    • Incremental Compilation: Compilation only occurs when necessary. rustimport compares the Rust source against a checksum on each import.
    • Dependency Tracking: By default, rustimport tracks all *.rs files, Cargo.toml, and Cargo.lock for crates. For single-file extensions, it tracks no additional dependencies.
    • Manual Dependency Tracking: You can track additional files by adding //d: comments to the top of your Rust file:
    //d: ../myothercrate/**/*.rs
    //d: ../myothercrate/Cargo.toml
  3. How to opt-in and use the PyO3 template

    master

    To use rustimport with the PyO3 template, you must include the following comment on the very first line of your .rs file:

    // rustimport:pyo3

    This tells rustimport to automatically generate a Cargo.toml with the necessary pyo3 dependencies and a #[pymodule] block to export your functions to Python.

    // rustimport:pyo3
    
    use pyo3::prelude::*;
    
    #[pyfunction]
    fn square(x: i32) -> i32 {
        x * x
    }
  4. Install rustimport via pip

    master

    Install rustimport using pip to enable importing Rust code directly into Python without manual compilation or binding steps.

    pip install rustimport
  5. Use rustimport in Jupyter Notebooks

    master

    To use rustimport within a Jupyter notebook, load the extension using a magic command. You can then use the %%rustimport cell magic to compile Rust code directly in a cell.

    Setup:

    %load_ext rustimport

    Usage:

    %%rustimport --release --force
    use pyo3::prelude::*;
    
    #[pyfunction]
    fn square(x: i32) -> i32 {
        x * x
    }
  6. Track additional source files for recompilation

    master

    By default, rustimport recompiles when the primary .rs file changes. To trigger a recompile when other files change, use the //d: comment syntax to specify file patterns or paths.

    // rustimport:pyo3
    //d: ../other-folder/somefile.rs
    //d: ../*.rs
    //d: ./my-directory/**/*.json
    
    // ... code ...
  7. Import Rust code using the import hook

    master

    To import a Rust file (e.g., somecode.rs) as a Python module, you must first load the rustimport.import_hook. The Rust file must contain the opt-in comment // rustimport:pyo3 on the first line to use the PyO3 template.

    When you perform the import, rustimport will automatically compile the Rust code into a Python extension module.

    import rustimport.import_hook
    import somecode  # This will pause for a moment to compile the module
    print(somecode.square(9))
  8. Customize Cargo.toml using comments

    master

    You can extend the automatically generated Cargo.toml by using the //: comment syntax at the top of your .rs file. This allows you to set the package version or add additional dependencies.

    // rustimport:pyo3
    
    // Set the library's version and add a dependency:
    //: [package]
    //: version = "1.2.3"
    //:
    //: [dependencies]
    //: rand = "0.8.5"
    
    use rand::Rng;
    
    #[pyfunction]
    fn myfunc() {
        println!("{}", rand::thread_rng().gen_range(0..10))
    }
  9. Pre-compile Rust extensions for production

    master

    To avoid requiring a Rust toolchain in production environments, use the build command to pre-compile your extensions into release-optimized binaries. This is ideal for CI/CD pipelines.

    Build all eligible files in current directory:

    python -m rustimport build --release

    Build specific files or directories:

    python -m rustimport build --release ./my/root/folder/ ./my/single/file.rs ./my/crate/

    Note: When specifying a direct file path, the // rustimport header check is skipped.

  10. Enable verbose logging for rustimport

    master

    Since rustimport uses standard Python logging, you can inspect its internal processes by configuring the logging module.

    import logging
    logging.basicConfig(level=logging.DEBUG)  # or logging.INFO
    # ... do some rustimport stuff here
  11. Configure rustimport settings via Python or Environment Variables

    master

    You can customize the behavior of rustimport using the rustimport.settings object in Python or via environment variables.

    FeaturePython SettingEnvironment Variable
    Release Binariesrustimport.settings.compile_release_binaries = TrueRUSTIMPORT_RELEASE_BINARIES=true
    Force Rebuildrustimport.settings.force_rebuild = TrueRUSTIMPORT_FORCE_REBUILD=true
    Custom Cache Dirrustimport.settings.cache_dir = "path/to/dir"RUSTIMPORT_CACHE_DIR="path/to/dir"
    import rustimport
    import os
    
    # Enable release optimizations
    rustimport.settings.compile_release_binaries = True
    
    # Force a rebuild even if checksums match
    rustimport.settings.force_rebuild = True
    
    # Set a permanent cache directory to speed up subsequent runs
    rustimport.settings.cache_dir = os.path.realpath("./.rust-cache")
  12. Configure rustimport with environment variables

    master

    You can control rustimport behavior using environment variables. Common use cases include forcing a rebuild or enabling release-mode optimizations during development.

    • RUSTIMPORT_FORCE_REBUILD=true: Forces recompilation.
    • RUSTIMPORT_RELEASE_BINARIES=true: Instructs the compiler to optimize binaries.
    RUSTIMPORT_FORCE_REBUILD=true python my_script.py