Rust crates for Conda environments

rattler & py-rattler

The rattler crates can be used to build custom applications leveraging Conda packages. Download repodata, solve for package specs and install packages in a few lines of code. The powerful Python bindings allow for even more flexible use cases.

Rust docsPython docs

A little Rust is all you need

Solve, create and install environments

main.rs
pub async fn create(opt: Opt) -> anyhow::Result<()> {
    let channel_config = ChannelConfig::default_with_root_dir(env::current_dir()?);
    let current_dir = env::current_dir()?;
    let target_prefix = opt
        .target_prefix
        .unwrap_or_else(|| current_dir.join(".prefix"));

    // Make the target prefix absolute
    let target_prefix = std::path::absolute(target_prefix)?;
    println!("Target prefix: {}", target_prefix.display());

    // Determine the platform we're going to install for
    let install_platform = if let Some(platform) = opt.platform {
        Platform::from_str(&platform)?
    } else {
        Platform::current()
    };

    println!("Installing for platform: {install_platform:?}");

    // Parse the specs from the command line. We do this explicitly instead of allow
    // clap to deal with this because we need to parse the `channel_config` when
    // parsing matchspecs.
    let specs = opt
        .specs
        .iter()
        .map(|spec| MatchSpec::from_str(spec, ParseStrictness::Strict))
        .collect::<Result<Vec<_>, _>>()?;

Python bindings

Powerful Python bindings

solver.py
import asyncio
import tempfile

from rattler import solve, install, VirtualPackage


async def main() -> None:
    # Start by solving the environment.
    #
    # Solving is the process of going from specifications of package and their
    # version requirements to a list of concrete packages.
    print("started solving the environment")
    solved_records = await solve(
        # Channels to use for solving
        channels=["conda-forge"],
        # The specs to solve for
        specs=["python ~=3.12.0", "pip", "requests 2.31.0"],
        # Virtual packages define the specifications of the environment
        virtual_packages=VirtualPackage.detect(),
    )
    print("solved required dependencies")

    # Install the packages into a new environment (or updates it if it already
    # existed).
    env_path = tempfile.mkdtemp()
    await install(
        records=solved_records,
        target_prefix=env_path,
    )

    print(f"created environment: {env_path}")


if __name__ == "__main__":
    asyncio.run(main())