AI generated image (GPT-4o / DALL-E)

Saying Goodbye to Anaconda?

Finding a replacement for Conda

Robert McDermott
9 min readOct 6, 2024

--

Background

Like many Python users at research organizations, I recently became aware that Anaconda had changed their licensing after they contacted the non-profit research institution where I work. They had updated their licensing so non-profits with more than 200 staff had to acquire a paid license for each user that not only install the full Anaconda distribution, but also those that pull packages from their default package repository. I’ve been using miniconda (which itself is free and open-source) but by default it pulls packages from the “defaults” channel that now requires a license.

I could just update my miniconda configuration to use the community supported and still free ‘conda-forge’ repository, or switch to miniforge and continue working as I had before, but I used this as an opportunity to look around and see what the other options are. Python is a free and open-source language; the Python community created the packages even in the Anaconda “defaults” repository, so why pay a company for access to free software they didn’t create?

Note: If your organization decides to block access to repo.anaconda.com to prevent staff from using the “defaults” channel, it’s worth noting that the ‘base’ environment in miniconda still pulls packages from defaults, so you might not be able to install or update miniconda anymore.

After looking around, I decided to give both UV and Pixi a closer look. Both UV and Pixi differ from Conda in a significant way. With Conda, it creates environments in a central registry that can be activated and used anywhere, while UV and Pixi are project focused and create their virtual environments in the same folder as your project.

UV

The first alternative I looked at was UV that positions itself as:

“An extremely fast Python package installer and resolver, written in Rust, and designed as a drop-in replacement for pip and pip-tools workflows.”

Astral, the company behind UV is the same company behind both Rye and Ruff and from what I’ve read, it appears that the functionally of Rye is being added to UV and UV will eventually make Rye redundant. Installing UV on all common platforms is as simple as a single command.

Installing UV

Command to install UV on Linux, MacOS or WSL:

curl -LsSf https://astral.sh/uv/install.sh | sh

Command to installing UV on Windows:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Alternatively, the installer or binaries can be downloaded directly from GitHub.

Installing UV on my MacBook Pro took just a few seconds

Installing UV on MacOS

After you restart your shell, the uv command should be ready to use.

Installing Python with UV

Unlike conda, or miniconda UV doesn’t install a base Python environment as part of its installation process. To install a version of Python run the following command replacing <version> with the version of python you desire:

uv python install <version>

Here I installed Python 3.12 in under two seconds. That’s almost impossibly fast, to the point it was hard to believe based on what I’ve come to expect from conda:

Installing Python 3.12 with UV

Creating a new project

To create a new project, use the uv init command, which will create a new project folder. You can specify a specific version of Python to use when initializing the new project (named ‘dad jokes’ in the examples below):

uv init -p 3.12 dad-jokes

Installing dependencies

To install the Python package dependencies for your project, change to the new project directory and use the uv add command:

cd dad-jokes
uv add requests

Example creating a new UV project, virtual environment and installing dependencies:

Creating a new Python project and adding dependencies

The result of the example above is the directory structure shown below. It created an empty README.md, a Python specific .gitignore, a Python virtual environment using the Python version specified, dependency version lock file and standard pyproject.toml file. It even initialized the project folder as a git repository:

dad-jokes
├── .git
├── .gitignore
├── .python-version
├── .venv
├── README.md
├── dad-jokes.py
├── pyproject.toml
└── uv.lock

You many have noticed that the common ‘requirements.txt’ file is missing. If you are going to share your project with others, you can easily create a requirements.txt file with the following command:

uv pip compile pyproject.toml -o requirements.txt

Example creating a requirements.txt file

Creating a requirements.txt file for your UV project

Opening an interactive Python session

If you want to run an interactive Python shell using the virtual environment inside your project you can use the uv run python command from within your project directory:

uv run python
Spawning an interactive Python shell with UV

Adding a script to your project

Let’s create a simple python script to test running some code in this UV created virtual environment. I’ve updated the ‘dad-jokes.py’ file as shown below:

import requests

def get_dad_joke():
url = "https://icanhazdadjoke.com/"
headers = {
"Accept": "application/json"
}
response = requests.get(url, headers=headers)

if response.status_code == 200:
joke = response.json().get('joke')
return joke
else:
return "Failed to fetch a joke."

if __name__ == "__main__":
print(get_dad_joke())

Running a script with UV

To run this script, rather than just calling “python <script-name>” you use the uv run command:

uv run dad-jokes.py

Example getting a new dad joke:

Running our script with UV to get a dad joke

Committing your changes

Since UV initialized your project folder as a git repository during creation, you are ready to commit your changes, and push to GitHub:

git add .
git commit -m "inital commit"

Overall UV seems like a great tool. It’s very fast and has absolutely no dependencies on Anaconda or their packages. UV uses PyPI as the source for all of its packages.

Pixi

Next, I explored Pixi, which is targeting Conda users specifically.

“Pixi is a versatile developer workflow tool designed to streamline the management of your project’s dependencies, tasks, and environments. Built on top of the Conda ecosystem, Pixi offers seamless integration with the PyPI ecosystem.”

It’s worth noting the Pixi actually uses UV as package resolver/installer when using packages from PyPI: https://prefix.dev/blog/uv_in_pixi

It’s also worth noting that by default, Pixi uses conda packages and pulls them from the free ‘conda-forge’ channel. If you are looking to completely avoid the entire Conda ecosystem, Pixi might not be the right choice.

Installing Pixi

Installing Pixi on Linux, MacOS and WSL:

curl -fsSL https://pixi.sh/install.sh | bash

Installing Pixi on Windows:

powershell -ExecutionPolicy ByPass -c "iwr -useb https://pixi.sh/install.ps1 | iex"

Alternatively, the installer or binaries can be downloaded directly from GitHub.

Installing Pixi on my MacBook Pro was a little slower than UV, but still much faster than conda:

Creating a new project

To create a new project, you use the pixi init command, which will create a new project folder. You can specify a specific version of Python to use when initializing the new project (again, named ‘dad-jokes’).

pixi init dad-jokes

Installing dependencies

To install the Python package dependencies for your project, change to the new project directory and use the pixi add command. Unlike UV, with Pixi we also have to add your desired version of Python as a dependency:

cd dad-jokes
pixi add python=3.12
pixi add requests

An example creating a new Pixi project, Python virtual environment and installing the ‘requests’ dependency for our dad jokes script:

Creating a new Python project and adding dependencies

The result of the example above is the directory structure shown below. It’s much sparser than UV, no git repo, no README.md or pyproject.toml. Instead of a pyproject.toml it provides a pixi.toml by default:

dad-jokes
├── .gitattributes
├── .gitignore
├── .pixi
├── pixi.lock
└── pixi.toml

You can tell it to use the pyproject.toml style project with the following command. It will create a different folder layout as well, setting it up to create a package named dad-jokes complete with and empty ‘__init__.py’ under the a ‘src’ folder:

pixi init dad-jokes --format pyproject

Using PyPI rather than conda-forge

As I mentioned before, Pixi defaults to pulling all dependencies from conda-forge:

Checking where Pixi is pulling conda packages from

If you would like to install some packages from PyPI you can use the pypi flag when adding dependencies:

pixi add --pypi black
Installing packages from PyPI rather than conda-forge

How to generate a requirements.txt file?

I couldn’t figure out how to create a standard requirements.txt file. I even created a new project with a Pixi generated pyproject.toml file then tried to use the uv’s ‘pip compile’ command that I used in the UV section above against the Pixi generated pyproject.toml file, but it didn’t work. Perhaps I’m missing something obvious?

Opening an interactive Python session

If you want to run an interactive Python shell using the virtual environment inside your Pixi project, you can use the pixi shell command followed by python from within your project directory:

pixi shell
python

An example starting a Pixi shell and interactive Python session:

Spawning an interactive Python shell in a Pixi project

Running a script with Pixi

After adding the same ‘dad-jokes.py’ script used previously, you can run it by using the pixi run python command:

pixi run python dad-jokes.py
Running our script with UV to get a new dad joke

Unlike UV, you’ll have to use git to initialize your project as git repo before checking in, committing and pushing your code if that’s what you are planning.

Overall Pixi also seems like a great tool, with a very similar user experience and workflow to UV, but with the ability to use conda packages if that’s important to you.

Conclusion

I don’t think there was a clear winner between UV and Pixi, they are both worthy, fast, modern replacements for Conda. Both use a project focused approach rather than global environments like Conda, that provide better (forced?) dependency isolation between projects, and both are much faster. They also avoid the useless “base” environment that is required with Conda. I think both tools will suit experienced users well, but the project-based approach might make it more confusing for a beginner just trying to learn Python.

Pixi’s use of Conda packages might make installing some packages (pytorch/cuda) easier to install (just speculation at this point), but I like to provide requirement.txt files for folks that aren’t running the same tool chain as me. There’s probably a way to create requirements.txt files, but I couldn’t figure it out in the little time I spent looking for a solution.

UV avoids Conda packages altogether, so it’s more in the spirit of moving away from Anaconda, uses a standard pyproject.toml project file by default and I can easily generate a requirements.txt file.

So, in the end I’m going to give UV a real try. I say “try” because I haven’t used it for a real project yet, so I might encounter problems later on. Pixi is also great looking tool that I might revisit in the future.

--

--

Responses (13)