DEV Community

Cover image for Embrace the Power of Nix for Your Python + Rust Workflow
Hussain Sultan for LETSQL

Posted on

Embrace the Power of Nix for Your Python + Rust Workflow

Hello Dev.to community!

At LETSQL, we're passionate about delivering the best tools for data scientists and ML engineers. As part of our journey, we leverage Nix to streamline our development workflows. If you're working with Python and Rust, or simply curious about why Nix is a game-changer, read on!

Why Nix?

Nix is a powerful package manager that offers reproducibility, reliability, and isolation. Here’s why we think it’s great:

  1. Reproducible Builds: Nix ensures that your development environment is consistent across different machines. With Nix, you can avoid the infamous "works on my machine" problem. Every developer and CI pipeline gets the same environment, leading to fewer surprises and smoother collaborations.

  2. Declarative Configuration: Nix uses a declarative approach to specify dependencies. This means you can define your environment in a single configuration file, making it easy to version control and share. Whether you're working on a small script or a large project, managing dependencies becomes straightforward.

  3. Isolation: Nix provides isolated environments, preventing conflicts between dependencies. This is particularly useful when working on multiple projects with different requirements. No more worrying about version clashes or dependency hell!

Nix for Python + Rust Workflow

Combining Python and Rust in a single project can be challenging, but Nix simplifies this process. Here’s how:

  1. Single Source of Truth: With Nix, you can manage both Python and Rust dependencies in a unified way. Define your dependencies in a flake.nix file and let Nix handle the rest. This ensures that your Python packages and Rust crates are compatible and work seamlessly together.

  2. Easy Setup: Setting up a development environment with Nix is as simple as running a single command. Once your configuration is in place, you can quickly spin up environments with all the necessary dependencies, saving valuable setup time.

  3. Consistent Development and Deployment: By using Nix, you ensure that your development, testing, and production environments are identical. This reduces the risk of bugs caused by environmental discrepancies and makes deployments more predictable and reliable.

Crane Lib: Incremental Artifact Caching for Rust Projects

We use Crane, a Nix library for building Cargo projects. One of Crane’s standout features is incremental artifact caching, which ensures you never build the same artifact twice. This greatly speeds up the build process and reduces redundant work.

Here's how Crane fits into our flake.nix:

  • Crane Library Integration: We use Crane to manage our Rust builds. It allows for fine-grained control over the build process and ensures efficient use of cached artifacts.

  • Cargo Configuration: The cargo.toml and Cargo.lock files define our Rust dependencies. Crane leverages these files to manage the build process.

  • Build Command: We use a custom build command for Maturin, integrated into our Nix build script to create Python wheels from our Rust code. This command ensures that all necessary artifacts are built and cached.

Maturin Build: Bridging Rust and Python

Maturin is a fantastic tool for building and publishing Rust crates as Python packages. With Nix, integrating Maturin into our workflow is straightforward. Here's a snippet from our flake.nix demonstrating the Maturin build setup:

buildPhaseCargoCommand = ''
  ${pkgs.maturin}/bin/maturin build \
    --offline \
    --target-dir target \
    --manylinux off \
    --strip \
    --release
'';
Enter fullscreen mode Exit fullscreen mode

This command ensures that our Rust crate is built and packaged as a Python wheel, ready for distribution.

Poetry2nix: Seamless Python Dependency Management

We also utilize Poetry2nix to manage our Python dependencies. Poetry2nix translates pyproject.toml and poetry.lock files into Nix expressions, allowing us to maintain our Python dependencies declaratively.

Here’s how Poetry2nix is configured in our flake.nix:

inputs = {
  poetry2nix = {
    url = "github:nix-community/poetry2nix";
    inputs.nixpkgs.follows = "nixpkgs";
  };
};

...

commonPoetryArgs = {
  projectDir = ./.;
  src = pySrc;
  preferWheels = true;
  python = python';
  groups = [ "dev" "test" "docs" ];
};

myapp = (mkPoetryApplication (commonPoetryArgs // {
  buildInputs = pkgs.lib.optionals pkgs.stdenv.isDarwin [
    pkgs.libiconv
  ];
})).overridePythonAttrs maturinOverride;
Enter fullscreen mode Exit fullscreen mode

Explore Our Configuration

For a full example of how we set up our development environment using Nix, check out our flake.nix file. This configuration includes everything from Crane for Rust builds to Poetry2nix for Python dependencies, ensuring a seamless and reproducible development workflow.

Join Us on GitHub!

We're always looking for contributors and feedback. If you find Nix as exciting as we do, check out our LETSQL GitHub repository and give us a star! 🌟 Your support helps us continue building great tools for the community.

Let's Connect!

Have questions or want to share your experience with Nix? Drop a comment below, or reach out to us on Twitter. We love hearing from you!

Happy coding!

Top comments (2)

Collapse
 
gersom_ramos_8a83ea5b199a profile image
Gersom Ramos

Having recently celebrated my birthday, I wanted to share my excitement about the amazing content on this site! A friend introduced me to SEVlaser, and I was thrilled to reserve some time as a special gift. Reading through others' positive experiences inspired me to comment too. The information here is top-notch, and it’s wonderful to see such genuine feedback from everyone. Check out the great services at Laser Hair Removal in Glendale

Collapse
 
carlos_christiangil_452d profile image
carlos christian gil