Installing and Working with uv (Python) in VSCode

Featured image

I will discuss uv as a replacement for pip, Poetry, PDM, and others, using Windows and VSCode as examples.

📖 Contents ⬇️

Contents

Until very recently, I was advocating for Rye over pip, Pipenv, Hatch, Poetry, and PDM. But the author of Rye has handed over his project to the creators of uv and is advocating for the switch to uv.

However, the work is very much similar to working in Rye. It's no coincidence that these programs have merged. Although, as of now, not everything is as simple as in Rye: Ruff needs to be installed separately, there's no built-in test support, etc.

In Brief

For instance, let's create a project test-uv.

  • Install uv.
  • uv init test-uv — create the test-uv project.
  • Open the test-uv project folder in VSCode.
  • uv sync — create a virtual environment.
  • Select the created virtual environment in VSCode.
  • Write code in hello.py and run it.
  • To deploy the project on another machine, install uv and apply uv sync.

Commands for work:

  • uv init example — create a folder example with uv project files.
  • uv init — create a uv project in the current folder.
  • uv init --package example-pkg — create a package project that will later be published.
  • uv add cowsay — add a new library.
  • uv add --dev isort — add a new library for development mode.
  • ruff format — format Python files of the project (after uv add --dev ruff).
  • ruff check — check Python files of the project.
  • uv self update — update uv itself.
  • uv sync — lock libraries and update virtual environment files according to .lock files.
  • uv sync --upgrade — update all project libraries.
  • uv sync --upgrade-package cowsay — update a specific library.
  • uv remove cowsay — remove a library.
  • pytest — runs tests based on pytest (after uv add --dev pytest).
  • uv python install 3.13 + uv python pin 3.13 + uv sync — switch to another version of Python.
  • pyinstaller -F hello.py — generates an EXE file (after uv add --dev pyinstaller).
  • uv build — builds a library.
  • uv publish --token <pypi-token> — publishes a library on PyPI.

Ссылки

Preparation

Installation of programs and creating a folder for projects

Python is not mandatory since uv can install and manage Python by itself.

VSCode is required.

You need the Python extension in VSCode:

Installing the Python extension

Figure 1: Installing the Python extension

Don't forget to switch to the file section:

Explorer section

Figure 2: Explorer section

Create a folder on your computer where the projects will be located, for example, C:\python-projects, if you don't already have a folder for Python projects (for example, using the command mkdir C:\python_projects\ or simply via the file explorer). Open this folder via File → Open Folder... (you can also create the necessary folder through the folder opening window):

Opening a folder

Figure 3: Opening a folder

You will be asked if you trust the authors of this folder. But didn't you just create this folder? So, we trust:

Confirming folder access

Figure 4: Confirming folder access

And enable the auto-save mode so you don't forget to save changes to the file:

Auto Save mode

Figure 5: Auto Save mode

Installing uv

Go to the installation page https://docs.astral.sh/uv/getting-started/installation/. There, find the installation section for Windows. We are offered to install not via the standard EXE, but through PowerShell:

Installation command for Windows

Figure 6: Installation command for Windows

Open Windows Terminal, PowerShell, or even VSCode (you will need a terminal there) and enter the command:

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

Start of Installation

Figure 7: Start of Installation

After this, you are given the option to either reboot the computer or add the path to uv to the system variable PATH using a command:

Prompt to Add Path to PATH

Figure 8: Prompt to Add Path to PATH

I chose to add the path using a command and entered $env:Path = "C:\Users\sergi\.local\bin;$env:Path", but you will have a different command since your username will be different!

Install Python, which will be managed using uv (the latest version will be installed):

uv python install

Installing Python

Figure 9: Installing Python

If you need a different version of Python, you can install it using a similar command: uv python install 3.12.

Creating a project

Close VSCode and reopen it if you didn't close it during the installation of uv.

Open the terminal in VSCode using Ctrl → ` (Ctrl → ~), and enter the command to create a new project (don't forget to press Enter after entering the command). Replace test-uv with the name of your project (do not use an underscore instead of a hyphen):

uv init test-uv

Project Initialization

Figure 10: Project Initialization

By the way, you can initialize a project in any current folder in the terminal with the command uv init, and the current folder will become the project folder (I believe this wasn't available in Rye, and I like this feature).

As a result, a folder with all the necessary files appeared. Note that a complex project structure with a src/test_uv folder is not created, unlike in Rye, because according to uv, a complex structure is not needed for simple applications. The test file hello.py is created in the root of our project. To create a package, you would need to create the project with uv init --package test-uv.

You can use the command cd test-uv to navigate to the project folder. But it's better to directly open the newly created folder C:/python-projects/test-uv through File → Open Folder... and open the terminal with Ctrl → ` (Ctrl → ~). From this point onward in the article, I will assume that the folder is open in VSCode:

Opened project folder test-uv

Figure 11: Opened project folder test-uv

Creating a Virtual Environment

Now you need to create a virtual environment using the command:

uv sync

The virtual environment folder will be created in the project folder:

Created Virtual Environment

Figure 12: Created Virtual Environment

In other systems, when working with a virtual environment, you need to ensure that the name of the virtual environment is displayed in parentheses in the terminal, which indicates that the virtual environment is activated:

Display of Virtual Environment Name in Terminal

Figure 13: Display of Virtual Environment Name in Terminal

In uv, this is not necessary, as it automatically ensures that scripts are run in the correct virtual environment. You can verify this by entering a command in the terminal:

python -c "import sys; print(sys.prefix)"

Path to the Current Virtual Environment

Figure 14: Path to the Current Virtual Environment

It will be evident that the virtual environment of our project is being used.

However, VSCode still needs to be configured to automatically activate the appropriate virtual environment when it runs Python scripts. More on that in the next section. But as seen in the screenshot above, VSCode has detected the virtual environment, and you can agree to use it.

The main project settings are located in the pyproject.toml file, and there is also a lock file for the project's libraries, uv.lock.

Writing and Running Code

Let's open the created hello.py file to test running a Python script (the second line is to check the activation of the correct virtual environment):

print(2+2)

import sys; print(sys.prefix)

Let's verify that VSCode has correctly picked up the .venv virtual environment. To do this, look at the bottom right of the VSCode status bar. If a general virtual environment is displayed there (as shown in the figure), click on it and select our .venv environment:

Selecting a Virtual Environment in VSCode

Figure 15: Selecting a Virtual Environment in VSCode

Run the script using the run button at the top right:

Running Python Code

Figure 16: Running Python Code

If you get the expected output, everything is working. Also, check that the path to the virtual environment is displayed correctly.

Adding Libraries

Packages can be added using a command like:

uv add cowsay

Adding a Library

Figure 17: Adding a Library

For example, in main.py, we can write the following code:

import cowsay

cowsay.cow('Hello World')

Running Code with Installed Library

Figure 18: Running Code with Installed Library

Let's also add the matplotlib library as an example:

uv add matplotlib

In main.py, write the following code:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-5, 5, 200)
y = x ** 2

fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()

Displaying a Plot

Figure 19: Displaying a Plot

If you need libraries for development in your project, meaning they won't be needed by the user of your library when it's published, you should install them with the --dev parameter. For example, if you need to sort imports in your project using isort, this library is needed for you as a developer but not for the users of your project. You can install it like this:

uv add --dev isort

Installing isort Package

Figure 20: Installing isort Package

Code Formatting

Rye includes a library called Ruff for code formatting. However, uv does not, even though this package is also their creation. So, you need to install it, and it can be used for all project files right away:

uv add --dev ruff

Then, you can use the library like this:

ruff format

The code was like this:

import matplotlib.pyplot as plt
import    numpy as   np

x =    np.linspace( -5, 5,    200)
y = x**2
fig, ax =    plt.subplots()
ax.plot(x,    y)
plt.show()

And it became like this:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-5, 5, 200)
y = x**2
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()

Formatting Python Code

Figure 21: Formatting Python Code

To format code with a line length of 120 characters, you can insert the following lines into pyproject.toml, and then you can use ruff format:

[tool.ruff]
line-length = 120

Figure 22 — Error Finding ruff

Additional Commands for uv

To update uv to the latest version, use the command:

uv self update

Updating uv

Figure 22: Updating uv

To lock libraries and update virtual environment files based on .lock files, use the uv sync command (you can also use uv lock):

uv sync

To update all libraries in the project, do the following:

uv sync --upgrade

If you need to update a specific library, such as cowsay, you can do it with the following command:

uv sync --upgrade-package cowsay

If a package is no longer needed, remove it like this:

uv remove cowsay

Removing a Library

Figure 23: Removing a Library

To check your code for errors, you can use the linter with ruff, which we installed earlier (uv add --dev ruff):

ruff check

Example of an Error Message

Figure 24: Example of an Error Message

Testing

Since pytest was the default testing package in Rye, we'll also use it with uv:

uv add --dev pytest

Installing pytest

Figure 25: Installing pytest

Now in the hello.py file (of course, you can rename this file or move it to the src folder), write some functions you want to test, for example:

def multiply_2(x):
    return x * 2

def multiply_10(x):
    return x * 10

def multiply_20(x):
    return x * 20

def multiply_30(x):
    return x * 30

Create a tests folder in the root of your project:

Creating the tests folder via right-click in explorer

Figure 26: Creating the tests folder via right-click in explorer

Inside it, create a file, for example, test_hello.py:

Created file

Figure 27: Created file test_hello.py

Note that the file should start with test_. So if you name the file, for example, test.py, tests.py, testhello.py, or for_test.py, pytest won't detect the tests (it can be configured, but it's better not to do so).

The pytest package needs to know where our main code is located. To do this, add the following configuration lines for pytest at the end of the pyproject.toml file:

[tool.pytest.ini_options]
pythonpath = "."

If your code is located in the src folder or any other folder, not in the root of the project as it is now, use similar settings (don't miss the space after the dot):

[tool.pytest.ini_options]
pythonpath = ". src"

Now in the test_hello.py file, we can write simple tests for our functions:

from hello import *


def test_multiply_2():
    re = multiply_2(2)
    assert re == 4


def test_multiply_10():
    re = multiply_10(2)
    assert re == 20


def test_multiply_20():
    re = multiply_20(2)
    assert re == 40


def test_multiply_30():
    re = multiply_30(2)
    assert re == 60

If your hello.py file was located in the src\test_uv\ folder, the first line would look like from src.test_uv.hello import *.

Test functions should also start with test_.

Now, in the terminal, run the command to execute the tests:

pytest

If everything is set up correctly, the tests should pass successfully:

Successful Test Execution

Figure 28: Successful Test Execution

Deploying a Project on a New Machine

Now let's assume you've successfully completed your project and want to run it on another machine. How do you proceed?

To deploy the project on another machine, install uv and use uv sync.

Transfer the test-uv project folder (or whatever it's named) to the other computer. For the example above, you need the following files from the original folder:

Project Files

Figure 29: Project Files

Folders like .pytest_cache, __pycache__, .ruff_cache, .venv are not needed. They are specific to your local version of the project. If you use Git, thanks to the .gitignore file, unnecessary folders won't be included in the transferred folder.

On the computer, install uv and VSCode again, and open the test-uv folder in VSCode:

Project Opened in VSCode

Figure 30: Project Opened in VSCode

Run the command to create a virtual environment with the same libraries that were in the project. This is specified in the uv.lock files:

uv sync

Project Opened in VSCode

Figure 31: Project Opened in VSCode

Select the virtual environment from the .venv folder in VSCode (VSCode will likely prompt you to change the virtual environment automatically).

Now you can run the code. For example, I inserted the code above for testing matplotlib:

Restored Project on Another Machine

Figure 32: Restored Project on Another Machine

Choosing a Different Python Version

First, download the desired Python version (for example, to check its operation on an older or newer Python):

uv python install 3.11

Downloading a New Python Version

Figure 33: Downloading a New Python Version

If you're rolling back to an earlier Python version, don't forget to change the Python version to a lower one in pyproject.toml:

Lowered Python Version

Figure 34: Lowered Python Version

Then, indicate that you want to switch to a different Python version. This command will change the .python-version file:

uv python pin 3.11.11

Then, recreate the virtual environment for the new Python version:

uv sync

That's it. Now a different Python version is displayed in VSCode. You can also check it through code:

import sys
print(sys.version)

Downloading a New Python Version

Figure 35: Downloading a New Python Version

To switch back to the old Python version, change it similarly, but without downloading the version:

uv python pin 3.13
uv sync

The same approach applies to updating the current Python version. For example, if you have Python 3.11.8, and version 3.11.9 is released. I didn't find a simple command, but you can do it using the same method:

uv python install 3.11.9
uv python pin 3.11.9
uv sync

To see the latest Python version you want to update to, visit Python.org or python-build-standalone.

Building an EXE File

Let's try to build a console application with the following code:

a = int(input())
b = int(input())
print(a + b)

input("Press enter to exit.")

For this, install the pyinstaller package in --dev mode:

uv add --dev pyinstaller

After that, run pyinstaller:

pyinstaller -F hello.py

If the file was located in the src\test_uv\ folder, the command would look like this:

pyinstaller -F src\test_uv\hello.py

Generating an EXE File

Figure 36: Generating an EXE File

A dist folder will be created with the main.exe file.

Run it, enter numbers, and you'll see:

Program Output Result

Figure 37: Program Output Result

The execution of EXE files was tested on a clean Windows 11.

If a single file is not needed, do not use the -F flag, and if you need a console application without a console (i.e., it should run in the background without creating a black terminal window), use the --windowed flag, for example, pyinstaller -F --windowed hello.py.

Creating Packages

Read the separate article Creating packages in Python with uv | ↗️.