Talking to python with rust
Tags: programming, rust, python
Published: 2022-08-15 05:46:00

## A few words about Rust

Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.

## Why write Python modules in Rust?

Python is undoubtedly one of the more powerful programming languages, but there are situations when a faster and more low-level tool is required. For example, calculations in which we care about the fastest possible code execution

## Getting started 

---

**1. Install Rust and Cargo**

On Linux and macOS systems, this is done as follows:
```sh
$ curl https://sh.rustup.rs -sSf | sh
```

On Windows, download and run rustup-init.exe. It will start the installation in a console and present the above message on success.

**2. Create new project and edit Cargo.toml**
```sh
$ cargo new pyrustlib --lib
```
To your Cargo.toml file you should add cpython dependency, this file should looks like
```toml
[package]
name = "pyrustlib"
version = "0.1.0"
edition = "2021"

[lib]
name = "pyrust"
crate-type = ["dylib"]

[dependencies.cpython]
version = "0.7"
features = ["extension-module"]
```

## Let's talk to Python

Next, we’re going to open src/lib.rs and begin editing; this is where the actual code of our library lives.

```rust

#[macro_use]
extern crate cpython;

use cpython::{Python, PyResult, PyString};

fn hello_from_rust(_py: Python) -> PyResult<PyString> {
    Ok(PyString::new(_py, "Hello from Rust!"))
}

py_module_initializer!(libpyrust, libpyrust, PyInit_libpyrust, |py, m | {
    m.add(py, "__doc__", "This module is implemented in Rust")?;
    m.add(py, "hello_world", py_fn!(py, hello_from_rust()))?;
    Ok(())
});
```
`py_module_initializer` is a macro defined by the cpython crate we imported at the top of our library. The first parameter (‘status’) is the name of our module, the second parameter is the Python2 naming for our module, while the third parameter is for Python3. The last segment of code on the first line (py, m) allows the modification of received module objects.

We then add a docstring and use the py_fn! macro to build the Python version of our function. That’s all there is to it! Save and exit.

### Compile the code
Make sure you are in the root directory of the project (where the Cargo.toml file is).
Run the following command to compile the code:

```sh
cargo build --release 
```

If the compilation went successfully you will see a new `target` directory in the main project directory. You can find the library in target/release, it's named `pyrustlib.so`.

### Test in python interpreter

The name for import this module in python is name given in `py_module_initializer` which in my case is `libpyrust`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmgk5mwr3kxxpub2w8wt.png)

As you can see, our module works properly.

## Additional Information 

For more advanced usage of cpython I recommend looking through the [rust-cpython](https://github.com/dgrunwald/rust-cpython) repo

## Conclusion

I really hope you found this tutorial helpful in some way! If you notice any errors or inaccuracies, please drop me a message. I want  to invite you to my [github](https://github.com/sectasy0), maybe you found something interesting. Thanks for reading!