uv as a system-wide Python environment manager

python
Published

December 22, 2024

Creating new virtual environments for each project during quick prototyping, data analysis, or machine learning can be cumbersome. While managing a global environment with pip is simpler, it often leads to dependency conflicts and version mismatches, especially as the number of installed packages grows.

Tools like poetry excel at managing project dependencies, but they can also effectively manage global environments.

uv is a modern Python environment manager written in Rust. Here’s a brief overview of using uv to manage a global environment. Note that this approach works with poetry as well.

1 Installing uv

uv is available via multiple sources, just a few examples:

macOS (and Linuxbrew)

brew install uv

Fedora (41+)

sudo dnf install uv

pipx

pipx install uv

When installed, uv provides a set of commands to manage Python environments, packages, and dependencies.

2 Creating a virtual environment

Global virtual environments should be stored in the home directory:

cd ~

Create a virtual environment with Python 3.12 (or other version):

uv init --python 3.12 --no-package --vcs none --no-readme --no-workspace

This initializes a project named after your home directory (you can modify it later). uv generates two files and a directory:

  • A sample Python script:

    hello.py
     def main():
      print("Hello from sheg!")
    
    
     if __name__ == "__main__":
        main()

    You can delete it:

    rm hello.py
  • A configuration file where uv stores general information and will store all explicitly required packages:

    pyproject.toml
    [project]
    name = "sheg"
    version = "0.1.0"
    description = "Add your description here"
    requires-python = ">=3.12"
    dependencies = []
    1
    The project name defaults to your home directory. You can change it to any name you prefer.
    2
    As of this writing, tis is required and can’t be deleted, but the version number is arbitrary.
    3
    Optional.
    4
    The minimum Python version.
    5
    Where all required packages will be listed.
  • A .venv directory containing the virtual environment.

You can customize pyproject.toml using any text editor to change details such as the environment name or description. For example:

pyproject.toml (example)
[project]
name = "global-env"
version = "6.6.6"
requires-python = ">=3.12"
dependencies = []

If something breaks, delete pyproject.toml and start over.

3 Installing packages

To install packages, use the uv add command followed by the package name (multiple packages can be added at once):

uv add scikit-learn seaborn

This updates pyproject.toml as follows:

pyproject.toml
[project]
name = "sheg"
version = "0.1.0"
dependencies = [
    "scikit-learn>=1.6.0",
    "seaborn>=0.13.2",
]

Additionally, uv generates a uv.lock file which stores the exact versions of the installed packages to ensure reproducibility, e.g. for later installations or on another machine.

To remove a package:

uv remove seaborn

4 Modifying package versions

pyproject.toml does not store the exact package versions, only some constraints (e.g., seaborn>=0.13.2). uv uses pyproject.toml to check with packages and their versions are required by the environment and then automatically resolves the exact versions and stores them in uv.lock.

You can modify the version constraints in pyproject.toml, e.g. to lower the minimum version of scikit-learn:

pyproject.toml (example)
[project]
name = "sheg"
version = "0.1.0"
dependencies = [
    "scikit-learn>=1.4.0",
    "seaborn>=0.13.2",
]
1
This was changed from 1.6.0 to 1.4.0.

Then, to apply the changes (resolve the exact versions and install/remove packages) run:

uv sync

This updates the uv.lock file with the new specifications.

5 Hiding environment files (Optional)

To declutter your home directory, you can hide pyproject.toml and uv.lock files:

macOS:

chflags hidden pyproject.toml uv.lock

Windows:

Right-click the file, select Properties, and check the Hidden box.

GNOME (Ubuntu, Fedora, etc.):

Create a .hidden file listing the files to hide:

nano .hidden

Add:

.hidden
pyproject.toml
uv.lock

6 Running Python interpreter and commands

To execute commands within your environment, prefix them with uv run.

For example, to run a Python shell:

uv run python

To run a Python script:

uv run python script.py

To run any command within the environment:

uv run echo "Hello, world!"

Do this if the command requires Python interpreter or packages from the environment.

7 Using VS Code notebooks

To use VS Code for Jupyter notebooks install ipykernel:

uv add ipykernel

Register the kernel:

uv run python -m ipykernel install --user

Select your environment in VS Code:

VS Code has persistent issues with Jupyter extensions. Refreshing, restarting, or troubleshooting for half an hour may occasionally be necessary. Sometimes, it just works (or doesn’t).

8 Using Jupyter

To use Jupyter, you need to install it:

uv add jupyter

Then, run it with uv:

uv run jupyter lab

This opens the Jupyter Lab interface in your browser:

9 Checking the active environment

uv resolves the current environment based on your working directory. If you’re in a directory without .venv, pyproject.toml, or uv.lock (i.e., not in a uv project), it looks for an environment in the parent directories.

To explicitly check which environment uv will use, run:

uv python find
/Users/sheg/.venv/bin/python3