How to Create a Python Virtual Environment with uv
Table of Contents
Imagine you have a Python 3.10 backend application with packages a2.1, b2.2, and c2.3 installed system-wide. Everything works fine until you start a new project that also uses Python 3.10 but needs a1.2, b2.2, and c2.1. Installing these new packages causes dependency issues with your first project because a2.1 and c2.3 are no longer available. If you start a third project requiring Python 3.8, you would need to downgrade Python, causing further conflicts.
Virtual environments solve these problems by isolating dependencies for each project, allowing you to maintain different packages and Python versions without conflict. A virtual environment is an independent environment created on top of an existing Python installation. It has its own independent set of Python packages installed in its site directories and only contains packages from its base environment (the system-wide Python installation) if explicitly specified. The environment is disposable and can be easily deleted and recreated as required.
In this tutorial, you’ll learn how to set up and use virtual environments using uv, a package installer that’s easy to use and performs 10 to 100 times better than pip.
Installing uv
To create a virtual environment with uv, you need to start by installing it. There are multiple ways to do so, depending on your device. If you’re using Linux or Mac, you can run the following command to install uv:
curl -LsSf https://astral.sh/uv/install.sh | sh
On Mac, you also have the option to install uv via Homebrew:
brew install uv
On Windows, you can run the following:
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Or you can install uv with pip:
pip install uv
After installation, verify uv on your device by running the following command:
uv --version
You will get an output like this:
uv 0.1.44
The rest of this tutorial assumes you’re operating on a Linux or Mac operating system.
Creating a Project and a Virtual Environment Using uv
Once uv is installed, you need to create a project and install the necessary dependencies:
mkdir my_uv_project
Then, change into this directory via cd my_uv_project
.
Creating a virtual environment for your project is fairly simple. Run the following command:
uv venv my_env
You should get a similar output to this:
user@guest-MacBook-Air my_uv_project % uv venv my_env
Using Python 3.9.6 interpreter at: /Library/Developer/CommandLineTools/usr/bin/python3
Creating virtualenv at: my_env
Activate with: source my_env/bin/activate
You can see that a Python 3.9 environment has been created.
Activating Your Environment
Once you’ve created your virtual environment, you need to activate it by running the following command:
source my_env/bin/activate
To verify that the environment you created doesn’t contain any packages, run the following command:
uv pip list
Your output will not list anything, and any packages or dependencies you install in this environment will be isolated from the rest of the system.
Note: If you’re using a different shell than Bash, such as cmd, you’ll have different activate scripts, such as my_envScriptsactivate.bat
.
Installing Packages in Your Environment
Once you’ve activated your environment, it’s time to install some packages. First, install pandas with the following command:
uv pip install pandas
You’ll get an output similar to this:
(my_env) user@guest-MacBook-Air my_uv_project % uv pip install pandas
Resolved 6 packages in 143ms
Installed 6 packages in 76ms
+ numpy==1.26.4
+ pandas==2.2.2
+ python-dateutil==2.9.0.post0
+ pytz==2024.1
+ six==1.16.0
As you can see, pandas version 2.2.2 has been installed. When you install pandas, other supporting packages are also installed.
Verify your package installation by running the following command:
uv pip list
You’ll get an output similar to this:
(my_env) user@guest-MacBook-Air my_uv_project % uv pip list
Package Version
--------------- -----------
numpy 1.26.4
pandas 2.2.2
python-dateutil 2.9.0.post0
pytz 2024.1
six 1.16.0
tzdata 2024.1
Creating a Second Virtual Environment
To test the isolation of environments, you’ll create a second environment and install a different version of pandas with another package. To do so, perform the same steps as above to create a virtual environment named my_second_env
:
user@guest-MacBook-Air my_uv_project % uv venv my_second_env
Using Python 3.9.6 interpreter at: /Library/Developer/CommandLineTools/usr/bin/python3
Creating virtualenv at: my_second_env
Activate with: source my_second_env/bin/activate
Next, install Flask and pandas version 2.1.0 by running this command:
my_uv_project % uv pip install pandas==2.1.0 flask
Upon installation, you’ll get an output similar to this:
(my_second_env) user@guest-MacBook-Air my_uv_project % uv pip install pandas==2.1.0 flask
Resolved 15 packages in 195ms
Downloaded 2 packages in 4.48s
Installed 15 packages in 93ms
+ blinker==1.8.2
+ click==8.1.7
+ flask==3.0.3
+ importlib-metadata==7.1.0
+ itsdangerous==2.2.0
+ jinja2==3.1.4
+ markupsafe==2.1.5
+ numpy==1.26.4
+ pandas==2.1.0
+ python-dateutil==2.9.0.post0
+ pytz==2024.1
+ six==1.16.0
+ tzdata==2024.1
+ werkzeug==3.0.3
+ zipp==3.19.1
As you can see, it does not contain the pandas package version 2.2.2 that you installed in the my_env
virtual environment.
Creating a Virtual Environment with a Different Python Version
You can also create a virtual environment with a different Python version. The earlier environments you created had Python 3.9. Let’s now create one that has Python 3.11. To do so, execute the following command:
uv venv 3rd_env --python 3.11
You’ll get a similar output to this:
Using Python 3.11.5 interpreter at: /Library/Developer/CommandLineTools/usr/bin/python3.11
Creating virtualenv at: 3rd_env
Activate with: source 3rd_env/bin/activate
You can once again install pandas here:
user@guest-MacBook-Air my_uv_project % source 3rd_env/bin/activate
(3rd_env) user@guest-MacBook-Air my_uv_project % uv pip install pandas
Resolved 6 packages in 215ms
Downloaded 2 packages in 2.59s
Installed 6 packages in 72ms
+ numpy==1.26.4
+ pandas==2.2.2
+ python-dateutil==2.9.0.post0
+ pytz==2024.1
+ six==1.16.0
+ tzdata==2024.1
Switching between Virtual Environments and Removing a Virtual Environment
To switch between different virtual environments, you can deactivate the first one by running this command:
deactivate
Follow it by running this command:
source my_second_env/bin/activate
If you now run the ls
command in your project directory, you’ll see all the environments listed:
user@guest-MacBook-Air my_uv_project % ls
3rd_env my_env my_second_env
As you can see, these environments are created like regular directories under your project. If you want to remove one, you can delete the environment folder like this:
rm -rf my_second_env
This will delete the second environment you created.
Overcoming the Limitations of uv
While uv can act as a great replacement for pip, it only manages dependencies related to Python.
Let’s say your projects involve installing packages system-wide, meaning they affect all users and applications on the system. For instance, you may want to install the libpq-dev package for your PostgreSQL backend server. uv is not designed to manage such system-wide package installations.
Another limitation of uv is that it lacks containerization capabilities. It has no caching mechanism to help speed up the build process by reusing identical dependencies in different virtual environments. If you use multiple virtual environments for a single project (for example, to test the project in different Python versions), uv will install every dependency in each virtual environment, even if some of them are identical. This can be inefficient and take up a lot of space and time for a large project.
These limitations make it cumbersome for larger Python projects or those with many dependencies.
Earthly helps address these issues by simplifying the dependency management process, ensuring consistency across different environments, and streamlining the build and deployment process.
For instance, you can use Earthly to install your Python-related dependencies (like pandas) as usual. If you also need to install system-wide dependencies like libpq-dev, you can do so within the same environment.
Earthly is designed to work like a Docker container. It uses an Earthfile
, which is very similar to a Dockerfile
. You can add and install all your Python and system-wide dependencies in a single Earthfile
, and your project is good to go.
It also offers fast build speed and supports caching, which reuses intermediate build steps when dependencies or code haven’t changed. Other notable features include dependency management, maintaining virtual environments, managing language-agnostic builds, and multiplatform deployments and CI/CD integrations.
Conclusion
In this article, you saw how to use virtual environments to help isolate development environments to avoid package-related issues and conflicts in Python with uv.
Even though uv works well for this use case, it has limitations. It only works for Python environments, so you can’t use it to install system-wide dependencies. It also doesn’t offer containerization capabilities.
If you need these features, consider Earthly, a simple build tool that helps you manage dependencies and maintain virtual environments. Similar to Docker containers, it offers many familiar features like containerization, caching and reusing builds, and installing dependencies that can span system-wide. It can easily manage large projects involving many dependencies and provides a great development experience.
Earthly Cloud: Consistent, Fast Builds, Any CI
Consistent, repeatable builds across all environments. Advanced caching for faster builds. Easy integration with any CI. 6,000 build minutes per month included.