Packaging your code is the most reliable way to ensure
reproducibility and reusability. Instead of relying on loose scripts,
packaging encourages you to organize your functions, document them, and
test them. This vignette demonstrates how to create packages in R and
Python within a Nix environment managed by {rix}.
We will cover: 1. Creating an R package using {devtools}
and {usethis}. 2. Creating a Python package using
uv. 3. Defining the correct Nix environments to develop and
use these packages.
{usethis} and
{devtools}The R ecosystem provides excellent tools for package development. We
will use {usethis} to set up the package structure and
{devtools} for documentation and testing.
Start by generating a default.nix that includes the
necessary development tools:
library(rix)
rix(
r_ver = "frozen-edge",
r_pkgs = c("devtools", "usethis", "roxygen2", "testthat"),
ide = "rstudio", # or "code", "none"
project_path = ".",
overwrite = TRUE
)Build the environment with nix-shell.
From inside your Nix shell (or RStudio started from Nix), create a new package:
This creates the standard R package directory structure
(R/, DESCRIPTION, NAMESPACE).
Create a function:
Add your function to R/clean_names.R and use
roxygen2 comments (#') for
documentation.
Document:
This generates the man/*.Rd files and updates
NAMESPACE.
Test:
Write unit tests in tests/testthat/test-clean_names.R,
then run them:
Check:
This runs the standard R package check to ensure everything is correct.
Once your package is hosted on GitHub, you can use it in other
project-specific Nix environments by adding it to the
git_pkgs argument in rix():
uvFor Python, we will use uv to manage the project
configuration (pyproject.toml) and build process, while Nix
manages the actual Python interpreter and environment.
Generate a default.nix with Python, uv, and
your package’s dependencies:
Inside the Nix shell, create a directory and initialize the project components:
uv init --bare creates a pyproject.toml
without creating a virtual environment (since we are using Nix).
pyproject.tomlEdit pyproject.toml to define dependencies and test
configuration. Critical sections include:
Write Code: Add functions to
src/pyclean/.
Write Tests: Add tests to
tests/.
Run Tests:
Build:
This produces a wheel in dist/.
When developing a Python package locally within a Nix shell, you want
changes to be reflected immediately. Update your
default.nix shellHook to add your source
directory to PYTHONPATH.
rix (>= 0.17.4) makes this easy with the
py_src_dir argument:
rix(
date = "2025-10-07",
py_conf = list(
py_version = "3.12",
py_pkgs = c("pytest", "pandas"),
py_src_dir = "src" # Adds src/ to PYTHONPATH automatically
),
system_pkgs = "uv",
# ...
)This injects export PYTHONPATH=$PWD/src:$PYTHONPATH into
the shell hook, allowing you to import pyclean and run
tests against the live source code.
To use your Python package in another Nix environment (e.g., for an
analysis project), use
pkgs.python3Packages.buildPythonPackage in your
default.nix. You can point to a GitHub repository:
pyclean = pkgs.python313Packages.buildPythonPackage rec {
pname = "pyclean";
version = "0.1.0";
src = pkgs.fetchgit {
url = "https://github.com/yourusername/pyclean";
rev = "commit_hash";
sha256 = "sha256-hash";
};
pyproject = true;
propagatedBuildInputs = [
pkgs.python313Packages.pandas
];
};Then add pyclean to the buildInputs list
alongside your other Python packages.