### Verify Tool Installation Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/00_welcome.md Check if Cargo and uv are installed and accessible in your terminal. ```bash cargo --version uv --version ``` -------------------------------- ### Run the Workshop Runner Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/00_welcome.md Start the course and verify exercise solutions using the 'wr' CLI tool. Ensure you are in the top-level repository folder. ```bash wr ``` -------------------------------- ### Python Threading Example Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/03_releasing_the_gil.md Example of using Python's threading module to run a Rust function and other Python work concurrently. Without GIL release, these will not run in parallel. ```python from threading import Thread def other_work(): print("I'm doing other work!") t = Thread(target=fibonacci, args=(10,)) t.start() other_work() t.join() ``` -------------------------------- ### Install Maturin using uv Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/01_setup.md Installs the `maturin` build tool, which is essential for building and packaging Python extensions written in Rust. Ensure `maturin` is version 1.8 or higher. ```bash uv tool install "maturin>=1.8" ``` -------------------------------- ### Process Creation Example Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/01_python_threads.md Illustrates the creation of a new process using `multiprocessing.Process`. This line is key to understanding how processes are spawned and the arguments they receive. ```python p = Process(target=word_count_task, args=(chunk, result_queue)) ``` -------------------------------- ### Python Example of Circumventing Constructor Constraint Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/03_setters.md Illustrates how the default setter can bypass constraints set in the constructor. ```Python wallet = Wallet(0) wallet.balance = -200 # This should not be allowed, but it is! ``` -------------------------------- ### Defining the Python Module Entry Point Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/02_modules.md Use the `#[pymodule]` macro to define the entry point for your Python extension module. The annotated function `setup` is called when Python loads the extension. ```rust #[pymodule] fn setup(m: &Bound<'_, PyModule>) -> PyResult<()> { // [...] } ``` -------------------------------- ### Update Rust Toolchain Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/00_welcome.md Update your Rust installation to the latest stable toolchain using rustup. ```bash # If you installed Rust using `rustup`, the recommended way, you can update to the latest stable toolchain with: rustup update stable ``` -------------------------------- ### Expose Rust Struct Fields as Python Attributes (Getter and Setter) Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/00_pyclass.md Use both `#[pyo3(get)]` and `#[pyo3(set)]` attributes on a struct field to allow Python callers to both read and modify the field. This example makes the `balance` field fully accessible. ```rust #[pyclass] struct Wallet { // Both getter and setter #[pyo3(get, set)] balance: i32, } ``` -------------------------------- ### Python Class Inheritance Example Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/05_inheritance.md Demonstrates a simple inheritance structure in Python where a Child class inherits from a Parent class. Shows how to call parent methods from a child instance. ```python class Parent: def __init__(self, name): self.name = name def greet(self): print(f"Hello, {self.name}!") # Declare `Child` as a subclass of `Parent` class Child(Parent): def __init__(self, name, age): # Call the parent class's constructor super().__init__(name) self.age = age child = Child("Alice", 7) # `Child` inherits the `greet` method from `Parent`, so we can call it child.greet() # Prints "Hello, Alice!" ``` -------------------------------- ### Update Shell for uv Tools Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/01_setup.md Updates your shell environment to ensure that tools installed via `uv`, such as `maturin`, are accessible in your PATH. Run this command after installing new tools. ```bash uv tool update-shell ``` -------------------------------- ### Default Getter and Setter in PyO3 Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/03_setters.md Demonstrates the basic usage of `#[pyo3(get, set)]` to attach default getter and setter to a field in a `#[pyclass]`. ```Rust use pyo3::prelude::*; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } ``` -------------------------------- ### Python Example of Custom Setter Enforcement Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/03_setters.md Shows how the custom setter prevents setting a value below the overdraft limit, raising a `ValueError`. ```Python wallet = Wallet(0) wallet.balance = -200 # Now raises a `ValueError` ``` -------------------------------- ### Custom Newtype Implementing IntoPyObject Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/06_output.md Example of implementing IntoPyObject for a custom Rust newtype (MyType) to represent it as a Python integer. It delegates the conversion of the inner u64 value. ```rust use std::convert::Infallible; use pyo3::prelude::*; use pyo3::types::PyInt; struct MyType { value: u64, } impl<'py> IntoPyObject<'py> for MyType { /// `Target` is the **concrete** Python type we want to use /// to represent our Rust value. /// The underlying Rust type is a `u64`, so we'll convert it to a `PyInt`, /// a Python integer. type Target = PyInt; /// `Output`, instead, is a **wrapper** around the concrete type. /// It captures the ownership relationship between the Python object /// and the Python runtime. /// In this case, we're using a `Bound` smart pointer to a `PyInt`. /// The `'py` lifetime ensures that the Python object is owned /// by the Python runtime. type Output = Bound<'py, PyInt>; /// Since the conversion can fail, we need to specify an error type. /// We can't fail to convert a `u64` into a Python integer, /// so we'll use `Infallible` as the error type. type Error = Infallible; fn into_pyobject(self, py: Python<'py>) -> Result { // `u64` already implements `IntoPyObject`, so we delegate // to its implementation to do the actual conversion. self.value.into_pyobject(py) } } ``` -------------------------------- ### Define a Python Class in Rust Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/00_pyclass.md Use the `#[pyclass]` attribute to define a new Python class in Rust. This example defines a `Wallet` class with a `balance` field. ```rust use pyo3::prelude::*; #[pyclass] struct Wallet { balance: i32, } ``` -------------------------------- ### Rust Function with No Arguments Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/04_arguments.md A simple Rust function exposed to Python that takes no arguments. This serves as a basic example before introducing argument passing. ```rust use pyo3::prelude::* #[pyfunction] fn no_op() { // Do nothing } ``` -------------------------------- ### Overriding Parent Method in Rust Child Class Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/06_parent.md Demonstrates how to override a method from the parent class in a Rust child class. This example defines a `greet` method within the `Child`'s `impl` block. ```rust #[pymethods] impl Child { #[new] fn new(name: String, age: u8) -> PyClassInitializer { // [...] } fn greet(&self) { println!("Hi, I'm {} and I'm {} years old!", self.name, self.age); } } ``` -------------------------------- ### Define a Python Callable Rust Function Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/03_functions.md Use the `#[pyfunction]` macro to define a Rust function that can be called from Python. This example defines a simple boolean returning function. ```rust use pyo3::prelude::*; // 👇 A Python function defined in Rust #[pyfunction] fn it_works() -> bool { true } ``` -------------------------------- ### Expose Rust Struct Fields as Python Attributes (Getter) Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/00_pyclass.md Use the `#[pyo3(get)]` attribute on a struct field to make it accessible as an attribute from Python. This allows Python callers to read the `balance` field. ```rust #[pyclass] struct Wallet { #[pyo3(get)] balance: i32, } ``` -------------------------------- ### Rust pyo3 Frozen Type Constraint Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/05_immutable_types.md Shows the type constraint `T: PyClass + Sync` required by `Py::get`. This highlights that `get()` can only be called on frozen classes, enforcing immutability. ```rust impl Py where T: PyClass, { pub fn get(&self) -> &T where // `Frozen = True` is where the magic happens! T: PyClass + Sync, { /* ... */ } } ``` -------------------------------- ### Accessing Parent Fields in Overridden Method using PyRef and as_super Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/06_parent.md Shows how to access parent class fields within an overridden method in a child class. It uses `PyRef` to get an immutable reference to `self` and `as_super()` to obtain a reference to the parent instance, allowing access to fields like `name`. ```rust #[pymethods] impl Child { // [...] fn greet(self_: PyRef<'_, Self>) { // This is now a reference to a `Parent` instance! let parent = self_.as_super(); println!("Hi, I'm {} and I'm {} years old!", parent.name, self_.age); } } ``` -------------------------------- ### Create a Solutions Branch Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/00_welcome.md Navigate into the cloned repository and create a new branch to track your solutions. ```bash cd rust-python-interoperability git checkout -b my-solutions ``` -------------------------------- ### Clone the Course Repository Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/00_welcome.md Clone the course repository from GitHub. Use SSH if you have keys set up, otherwise use HTTPS. ```bash # If you have an SSH key set up with GitHub git clone git@github.com:mainmatter/rust-python-interoperability.git # Otherwise, use the HTTPS URL: # # git clone https://github.com/mainmatter/rust-python-interoperability.git ``` -------------------------------- ### Call PyO3 Class Methods from Python Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/02_methods.md Instantiate and interact with Rust-defined classes from Python. Methods defined with `#[pymethods]` are available as standard Python methods. ```python wallet = Wallet(0) wallet.deposit(100) wallet.withdraw(50) assert wallet.balance == 50 ``` -------------------------------- ### Thread Creation in Python Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/02_gil.md This snippet shows how a thread is created in Python, targeting a specific function and passing arguments. This is a fundamental step in Python's threading model, but is subject to the GIL. ```python t = Thread(target=word_count_task, args=(chunk, result_queue)) ``` -------------------------------- ### pyproject.toml Configuration for Maturin Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/01_setup.md This TOML file configures the build system for a Python extension module using maturin. It specifies build requirements, project metadata, and maturin-specific settings like features. ```toml [build-system] requires = ["maturin>=1.8,<2.0"] build-backend = "maturin" [project] name = "setup" # [...] requires-python = ">=3.13" [tool.maturin] features = ["pyo3/extension-module"] ``` -------------------------------- ### Using Bound<'_, PyList> as a Function Argument in Rust Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/05_gil.md Demonstrates the correct way to use PyList as a function argument in Rust by employing the Bound<'_, PyList> type, which ensures the GIL is held when interacting with the Python object. ```rust use pyo3::prelude::* #[pyfunction] fn print_number_list(list: Bound<'_, PyList>) { todo!() } ``` -------------------------------- ### Rust Constructor for a Child Class with Inheritance Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/05_inheritance.md Implements the constructor for the `Child` class in Rust. It initializes the parent `Parent` class first and then the `Child` specific fields using `PyClassInitializer`. ```rust #[pymethods] impl Child { #[new] fn new(name: String, age: u8) -> PyClassInitializer { let parent = Parent::new(name); let child = Self { age }; PyClassInitializer::from(parent).add_subclass(child) } } ``` -------------------------------- ### Rust Cargo.toml for Python Extension Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/01_setup.md Configures a Rust project as a Python extension module. Sets the crate type to `cdylib` for dynamic linking and includes `pyo3` as a dependency for Python integration. ```toml [package] name = "setup" version = "0.1.0" edition = "2021" [lib] name = "setup" crate-type = ["cdylib"] [dependencies] pyo3 = "0.23.0" ``` -------------------------------- ### Define Methods for a PyO3 Class Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/02_methods.md Use the `#[pymethods]` attribute on an `impl` block to expose Rust methods to Python. Methods like `deposit` and `withdraw` can be called directly on the Python object. ```rust use pyo3::prelude::*; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> Self { Wallet { balance } } fn deposit(&mut self, amount: i32) { self.balance += amount; } fn withdraw(&mut self, amount: i32) { self.balance -= amount; } } ``` -------------------------------- ### Enforcing Constraints in Constructor Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/03_setters.md Shows how to enforce constraints, like an overdraft limit, within the constructor of a `#[pyclass]`. ```Rust use pyo3::prelude::*; use pyo3::exceptions::PyValueError; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } const OVERDRAFT_LIMIT: i32 = -100; #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> PyResult { if balance < OVERDRAFT_LIMIT { return Err(PyValueError::new_err("Balance cannot be below overdraft limit")); } Ok(Wallet { balance }) } } ``` -------------------------------- ### Register a Rust Class with a Python Module Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/00_pyclass.md Register the `Wallet` class with a Python module using `m.add_class::()?` to make it visible to Python. This is required for `#[pyclass]` definitions. ```rust #[pymodule] fn my_module(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; Ok(()) } ``` -------------------------------- ### Using PyList as a Function Argument in Rust Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/05_gil.md Demonstrates attempting to use PyList directly as a function argument, which fails because Py* types do not implement FromPyObject. ```rust use pyo3::prelude::* fn print_number_list(list: &PyList) { todo!() } ``` -------------------------------- ### Defining Parent and Child Classes in Rust for PyO3 Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/06_parent.md This snippet shows the basic structure for defining a parent class with a `#[pyclass(subclass)]` attribute and a child class that extends it using `#[pyclass(extends=Parent)]`. It includes a constructor and a method for the parent class. ```rust use pyo3::prelude::*; #[pyclass(subclass)] struct Parent { name: String, } #[pymethods] impl Parent { #[new] fn new(name: String) -> Self { // [...] } fn greet(&self) { println!("Hello, {}!", self.name); } } #[pyclass(extends=Parent)] struct Child { age: u8, } #[pymethods] impl Child { #[new] fn new(name: String, age: u8) -> PyClassInitializer { // [...] } } ``` -------------------------------- ### Configuring Rust Library Name for Python Module Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/02_modules.md Ensure the `name` in your `Cargo.toml`'s `[lib]` section matches the Python module name. If not specified, it defaults to the package name. ```toml [lib] name = "name_of_your_rust_library" ``` -------------------------------- ### Rust PyO3 Class with Static Method (Correct) Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/04_static_methods.md Defines a PyO3 Rust struct `Wallet` with a correctly implemented static `default` method using the `#[staticmethod]` attribute. ```rust use pyo3::prelude::*; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> Self { Wallet { balance } } // Notice the `#[staticmethod]` attribute here! #[staticmethod] fn default() -> Self { Wallet { balance: 0 } } } ``` -------------------------------- ### Rust Struct with Default Static Method Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/04_static_methods.md Defines a basic Rust struct `Wallet` with a static `default` method. ```rust pub struct Wallet { balance: i32, } impl Wallet { pub fn default() -> Self { Wallet { balance: 0 } } } ``` -------------------------------- ### Expose Rust Function to Python Module Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/03_functions.md Use the `#[pymodule]` macro and `m.add_function(wrap_pyfunction!(...))` to make Rust functions available in a Python module. Ensure the function name matches. ```rust #[pymodule] fn setup(m: &Bound<'_, PyModule>) -> PyResult<()> { // 👇 Expose the function to Python m.add_function(wrap_pyfunction!(it_works, m)?) Ok(()) } ``` -------------------------------- ### Return Rust Structs as Python Objects Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/00_pyclass.md Rust types annotated with `#[pyclass]` automatically implement `IntoPyObject`, allowing them to be returned from `#[pyfunction]`s. This function creates and returns a new `Wallet` instance. ```rust #[pyfunction] fn new_wallet(balance: i32) -> Wallet { Wallet { balance } } ``` -------------------------------- ### Python Frozen Dataclass - Adding Attributes Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/05_immutable_types.md Illustrates that adding new attributes to an instance of a frozen dataclass is also prohibited and will result in a `FrozenInstanceError`. ```python # This will raise a `FrozenInstanceError` exception # But would work if `frozen=False` or for a "normal" # class without the `@dataclass` decorator p.z = 3 ``` -------------------------------- ### Define PyClass Constructor with #[new] Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/01_constructors.md Use the #[new] attribute on a Rust method within a #[pymethods] impl block to define the constructor for a #[pyclass]. This method is equivalent to Python's __new__. ```rust use pyo3::prelude::*; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> Self { Wallet { balance } } } ``` -------------------------------- ### Word Count using Multiprocessing Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/01_python_threads.md This function demonstrates a word count task using multiple processes. It highlights the overhead associated with inter-process communication due to lack of shared memory. ```python from multiprocessing import Process, Queue def word_count(text: str, n_processes: int) -> int: result_queue = Queue() processes = [] for chunk in split_into_chunks(text, n_processes): p = Process(target=word_count_task, args=(chunk, result_queue)) p.start() processes.append(p) for p in processes: p.join() results = [result_queue.get() for _ in range(len(processes))] return sum(results) ``` -------------------------------- ### Thread-based Word Count in Python Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/02_gil.md This Python code demonstrates a multithreaded approach to word counting. It uses threading and a queue to distribute work across threads. Note that due to the GIL, this will not achieve true parallelism on multi-core CPUs. ```python from threading import Thread from queue import Queue def word_count(text: str, n_threads: int) -> int: result_queue = Queue() threads = [] for chunk in split_into_chunks(text, n_threads): t = Thread(target=word_count_task, args=(chunk, result_queue)) t.start() threads.append(t) for t in threads: t.join() results = [result_queue.get() for _ in range(len(threads))] return sum(results) ``` -------------------------------- ### Rust PyO3 Class with Class Method Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/04_static_methods.md Defines a PyO3 Rust struct `Wallet` with a class method `from_str` that accepts `cls` as the first argument. ```rust use pyo3::prelude::*; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> Self { Wallet { balance } } // Notice the `cls` argument here! #[classmethod] fn from_str(_cls: &Bound<'_, PyType>, balance: &str) -> PyResult { let balance = balance.parse::()?; Ok(Wallet { balance }) } } ``` -------------------------------- ### Custom Setter Implementation with `#[setter]` Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/03_setters.md Demonstrates overriding the default setter for a field using the `#[setter]` attribute to enforce validation logic. ```Rust use pyo3::prelude::*; #[pyclass] struct Wallet { // We keep using the default getter, no issues there #[pyo3(get)] balance: i32, } const OVERDRAFT_LIMIT: i32 = -100; #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> PyResult { Wallet::check_balance(balance)?; Ok(Wallet { balance }) } #[setter] fn set_balance(&mut self, value: i32) { Wallet::check_balance(value)?; self.balance = value; } } impl Wallet { // We put this method in a separate `impl` block to avoid exposing it to Python fn check_balance(balance: i32) -> PyResult<()> { if balance < OVERDRAFT_LIMIT { return Err(PyValueError::new_err("Balance cannot be below overdraft limit")); } Ok(()) } } ``` -------------------------------- ### Rust PyO3 Class with Static Method (Incorrect) Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/04_static_methods.md An attempt to define a static method on a PyO3 class without the `#[staticmethod]` attribute, which will not compile. ```rust use pyo3::prelude::*; #[pyclass] struct Wallet { #[pyo3(get, set)] balance: i32, } #[pymethods] impl Wallet { #[new] fn new(balance: i32) -> Self { Wallet { balance } } fn default() -> Self { Wallet { balance: 0 } } } ``` -------------------------------- ### Rust Function Returning PyResult Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/07_exceptions.md Use PyResult<()> in #[pyfunction]s to allow Rust functions to return errors that pyo3 will translate into Python exceptions. The `?` operator propagates errors. ```rust use pyo3::prelude::*; use pyo3::types::PyAny; #[pyfunction] fn print_if_number(item: Bound<'_, PyAny>) -> PyResult<()> { let number = item.extract::()?; println!("{}", number); Ok(()) } ``` -------------------------------- ### Rust Code for a Simple Python Function Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/01_setup.md Defines a basic Rust function `it_works` that returns a boolean. This function will be exposed to Python via the `pyo3` crate. ```rust use pyo3::prelude::*; #[pyfunction] fn it_works() -> bool { todo!() } /// A Python module implemented in Rust. #[pymodule] fn setup(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(it_works, m)?) Ok(()) } ``` -------------------------------- ### Python Integer Immutability Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/05_immutable_types.md Demonstrates that modifying an integer in Python actually creates a new object, leaving the original reference unchanged. This behavior is characteristic of immutable types. ```python a = 1 b = a a += 1 assert a == 2 # a is a new object, # b is still 1 assert b == 1 ``` -------------------------------- ### Rust Definition of a Grandchild Class with Nested Inheritance Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/05_inheritance.md Demonstrates nested inheritance in Rust by defining a `Grandchild` class that extends `Child`, which in turn extends `Parent`. Uses `PyClassInitializer` to manage the multi-level inheritance chain. ```rust #[pyclass(extends=Child)] struct Grandchild { hobby: String, } #[pymethods] impl Grandchild { #[new] fn new(name: String, age: u8, hobby: String) -> PyClassInitializer { let child = Child::new(name, age); let grandchild = Self { hobby }; PyClassInitializer::from(child).add_subclass(grandchild) } } ``` -------------------------------- ### Rust Function with Explicit Python<'py> Token Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/05_gil.md Shows a Rust function that explicitly accepts a Python<'py> token as an argument, indicating it requires the GIL to be held. pyo3 automatically provides this token when the function is called from Python. ```rust use pyo3::prelude::* #[pyfunction] fn print_number_list(_py: Python<'_>, list: Vec) { todo!() } ``` -------------------------------- ### Rust Function Implicitly Requiring Python<'py> Token Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/05_gil.md Illustrates a Rust function where the Python<'py> token is not explicitly passed as an argument. pyo3 still ensures the GIL is held when this function is invoked from Python. ```rust use pyo3::prelude::* #[pyfunction] fn print_number_list2(list: Vec) { todo!() } ``` -------------------------------- ### Rust pyo3 Accessing Frozen Fields without GIL Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/05_immutable_types.md Demonstrates how to access fields of a frozen `pyo3` class (`Point`) from Rust without holding the Python Global Interpreter Lock (GIL). This is achieved using `Py` and `Python::detach`. ```rust #[pyfunction] fn print_point<'py>(python: Python<'py>, point: Bound<'py, Point>) { let point: Py = point.unbind(); python.detach(|| { // We can now access the fields of the Point struct // even though we are not holding the GIL let point: &Point = point.get(); println!("({}, {})", point.x, point.y); }); } ``` -------------------------------- ### Manually Re-acquire GIL with Attach Inside Detach Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/04_minimize_gil_locking.md Re-acquire the GIL within a detached closure using `Python::attach` to access and modify Python objects iteratively. This avoids creating large intermediate data structures. ```rust #[pyfunction] fn update_in_place<'py>( python: Python<'py>, numbers: Bound<'py, PyList> ) -> PyResult<()> { let n_numbers = numbers.len(); let numbers_ref = numbers.unbind(); // Release the GIL python.detach(|| -> PyResult<()> { for i in 0..n_numbers { // Acquire the GIL again, to access the // i-th element of the list let n = Python::attach(|inner_py| { numbers_ref .bind(inner_py) .get_item(i)? .extract::() })?; // Run the computation without holding the GIL let result = expensive_computation(n); // Re-acquire the GIL to update the list in place Python::attach(|inner_py| { numbers_ref.bind(inner_py).set_item(i, result) })?; } Ok(() }) } ``` -------------------------------- ### Python ImportError for Mismatched Module/Library Names Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/02_modules.md This error occurs when the Python interpreter cannot find the expected module export function due to a mismatch between the dynamic library name and the expected module name. ```text ImportError: dynamic module does not define module export function (PyInit_name_of_your_module) ``` -------------------------------- ### Python Frozen Dataclass Definition Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/05_immutable_types.md Shows how to define an immutable class in Python using the `dataclass` decorator with `frozen=True`. Attempting to modify attributes of an instance of this class will raise a `FrozenInstanceError`. ```python from dataclasses import dataclass @dataclass(frozen=True) class Point: x: int y: int p = Point(1, 2) # This will raise a `FrozenInstanceError` exception p.x = 3 ``` -------------------------------- ### Python Test for Rust Function Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/01_setup.md A Python test function that imports and asserts the behavior of the `it_works` function exposed from the Rust extension module. This verifies the integration. ```python from setup import it_works def test_works(): assert it_works() ``` -------------------------------- ### Explicitly Setting the Module Name Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/02_modules.md You can explicitly define the Python module's name using the `#[pyo3(name = "...")]` attribute on the `#[pymodule]` macro, overriding the function name. ```rust #[pymodule] #[pyo3(name = "setup")] fn random_name(m: &Bound<'_, PyModule>) -> PyResult<()> { // [...] } ``` -------------------------------- ### Basic Rust Fibonacci Function Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/03_releasing_the_gil.md A simple Rust function to calculate the nth Fibonacci number. This function does not interact with Python objects. ```rust #[pyfunction] fn fibonacci(n: u64) -> u64 { let mut a = 0; let mut b = 1; for _ in 0..n { let tmp = a; a = b; b = tmp + b; } a } ``` -------------------------------- ### Isolate GIL-Free Section with Detach Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/04_minimize_gil_locking.md Release the GIL before a long-running computation and re-acquire it to update Python objects. This strategy creates a new Rust vector to decouple GIL-holding and GIL-free operations. ```rust #[pyfunction] fn update_in_place<'py>( python: Python<'py>, numbers: Bound<'py, PyList> ) -> PyResult<()> { // Holding the GIL let v: Vec = numbers.extract()?; let updated_v: Vec<_> = python.detach(|| { v.iter().map(|&n| expensive_computation(n)).collect() }); // Back to holding the GIL for (i, &n) in updated_v.iter().enumerate() { numbers.set_item(i, n)?; } Ok(() } fn expensive_computation(n: i32) -> i32 { // Some heavy number crunching // [...] } ``` -------------------------------- ### FromPyObject Trait Definition Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/04_arguments.md The `FromPyObject` trait definition from pyo3, which outlines the contract for converting Python objects into Rust types. This is fundamental for enabling Rust functions to accept arguments from Python. ```rust pub trait FromPyObject<'py>: Sized { fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult; } ``` -------------------------------- ### Rust Definition of a Subclassable Parent Class Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/05_inheritance.md Defines a Rust struct `Parent` marked with `#[pyclass(subclass)]` to indicate it can be inherited by Python classes. Includes a constructor and a greet method. ```rust use pyo3::prelude::*; #[pyclass(subclass)] struct Parent { name: String, } #[pymethods] impl Parent { #[new] fn new(name: String) -> Self { Parent { name } } fn greet(&self) { println!("Hello, {}!", self.name); } } ``` -------------------------------- ### Rust Fibonacci Function Releasing GIL Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/03_releasing_the_gil.md A Rust function that calculates the nth Fibonacci number, explicitly releasing the GIL using `Python::detach` to allow concurrent Python execution. ```rust #[pyfunction] fn fibonacci(py: Python<'_>, n: u64) -> u64 { py.detach(|| { let mut a = 0; let mut b = 1; for _ in 0..n { let tmp = a; a = b; b = tmp + b; } a }) } ``` -------------------------------- ### Rust pyo3 Frozen Class Definition Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/05_immutable_types.md Defines a basic immutable struct `Point` in Rust using `pyo3`'s `#[pyclass(frozen)]` attribute. This makes the class immutable and allows for GIL-free field access. ```rust use pyo3::prelude::*; #[pyclass(frozen)] struct Point { x: i32, y: i32, } ``` -------------------------------- ### Rust Definition of a Child Class Extending Parent Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/02_classes/05_inheritance.md Defines a Rust struct `Child` that extends the `Parent` class using `#[pyclass(extends=Parent)]`. This enables Python to recognize `Child` as a subclass of `Parent`. ```rust #[pyclass(extends=Parent)] struct Child { age: u8, } ``` -------------------------------- ### IntoPyObject Trait Definition Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/01_intro/06_output.md The IntoPyObject trait defines the interface for converting Rust values into Python objects. The output type must implement this trait. ```rust pub trait IntoPyObject<'py>: Sized { type Target; type Output: BoundObject<'py, Self::Target>; type Error: Into; fn into_pyobject(self, py: Python<'py>) -> Result; } ``` -------------------------------- ### Python::detach Signature with Ungil Trait Source: https://github.com/mainmatter/rust-python-interoperability/blob/main/book/src/03_concurrency/03_releasing_the_gil.md The signature for `Python::detach` constrained by the `Ungil` marker trait. This trait aims to ensure that only types safe to access without the GIL can be used with this method. ```rust pub fn detach(self, f: F) -> T where F: Ungil + FnOnce() -> T, T: Ungil, { // ... } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.