What is UV?
Astral's uv is a fast, all-in-one Python package and project manager written in Rust that unifies and accelerates Python development workflows by replacing multiple tools and actions including:
- pip,
- pip-tools,
- poetry,
- pipx,
- pyenv,
- virtualenv, and
- twine
- initializing a git repository
- creating base files like .gitignore and pyproject.toml (think of this as requirements.txt PLUS)
... with a single, high-performance utility.
Uv handles package installation, dependency resolution, virtual environments, project and Python version management, script execution, and package publishing, all with a familiar CLI and dramatic speed improvements. By consolidating these capabilities, uv simplifies and streamlines Python development for everything from individual scripts to complex multi-workspace projects.
Our focus in these examples will be:
- python installation and
- virtual environment creation
(Two actions which are essential to executing your network automation!)
I am a network engineer! I am not building python packages...why do I care?
You may be a network engineer just starting to dabble with network automation and Python, and looking at scripts to make your life easier or you may be a network engineer well versed in pip and virtual environments.
Either way, you will eventually want to share your scripts so they can be used by others.
A challenging aspect of sharing your scripts is building the execution environment (the required version of Python and the virtual environment with the required modules), particularly if you use third party modules like netmiko, nornir, jinja2, suzieq, pandas, etc.
What if there was a way to create the required virtual environment (venv) dynamically and on-demand right down to the installation of the specific Python version you wanted to use?
Lets look at two examples of this in two separate GitHub Repositories.
Standalone Script
Lets look at the uv_script repository first.
Clone or Download the uv_script repository, open a PowerShell (Windows) or terminal window (Linux/MacOS), and cd into the repository directory.
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025
% cd uv_script
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025/uv_script on main
% ls
README.md cc3_info.py images
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025/uv_script on main
% tree -L 1
.
├── README.md
├── cc3_info.py
└── images
2 directories, 2 file
The cc3_info.py script uses
pycountry
module to get a list of three letter country codesrequests
module to get country information about a country using its three letter country code and it can also be used to the a list of three letter country codespython-dotenv
module to load environment variables, specifically the token requred by the RestfulCountries.com API (There is one additional hidden file in the repository.env_sample
which can be renamed to .env and used to store the API token)
The script has three external Python module dependencies but notice it is missing a requirements.txt file (and any other kind of dependency requirements or management file like pyproject.toml).
Regardless, this script can be executed with the following command as long as as uv has been installed.
uv run cc3_info.py
What are you saying?
I am saying that the command above:
- installs the required Python version if needed
- creates an on demand virtual environment
- activates the virtual environment
- installs the required 3rd party modules
- executes the Python script within that environment
- deactivates the virtual environment
What is this witchery you speak of?
It does seem like magic. If you have gone thought the heavy lifting of getting your teammates to install the version of Python you need and then create the virtual environment and then install the necessary modules across whichever operating system they are using (and then deal with the one or two installations that just won't work) you know this can be challenging.
Perhaps more importantly, if your teammates are not familiar with Python and virtual environments, this is a HUGE distraction from this thing of beauty you have created (your Python script).
"Hey guys...lets go for a ride in my fabulous new automobile!!"
But first, can we put air in the tires, and then rotate and balance the tires, and lets make sure the transmission is in good working order, and lets check all the fluids, and that the brakes work, and lets upgrade the navigation system, and the system software.
By the time you get to the good stuff -- showing them what your script actually does and how it can benefit them -- most have glazed over eyes and some have passed out. Worst of all, some will be discouraged by so many unfamiliar steps required to just execute a script. This inhibits adoption.
Lets Pop The Hood
Step 1: Installing uv
Uv is available for Linux/MacOS and Windows with very simple instructions from the Astral web site.
We have tried it on:
- Windows 10 (with and without administrator privileges)
- Windows 11 (with and without administrator privileges)
- Ubuntu
- WSL2/Default Ubuntu
- MacOS (Mostly Sequoia 15.2, 15.3, 15.4)
So far, no one on the team has had an issue with the uv installation.
Step 2: Script Execution
uv run cc3_info.py
It should not be too surprising that executing the script involves uv run script.py rather than the more familiar python script.py . This and a small bit of configuration in the Python script itself is the magic.
uv is effectively turning your Python scripts into "executables" suitable for multiple operating systems.
In January of 2024, Inline script metadata was implemented. The PEP 723 – Inline script metadata document is a very good read and walks you though the rationale for this feature and its specific implementation.
These 8 lines in the cc3_info.py script coupled with uv run is how uv installs the right version of Python (if not already there), creates and activates the virtual environment, and executes the script within this dynamically created virtual environment.
There are many more options but this should give you the basic idea. The requirements are defined but rather than in a separate document (requirements.txt), they are embedded in your script.
The script itself has the information uv needs to create its execution environment.
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "pycountry>=24.2.0",
# "requests>=2.31.0",
# "python-dotenv>=1.0.0",
# ]
# ///
How does this metadata get into your script?
You can type it in yourself or you can have uv do it for you. The uv add command will embed the version of python required along with the three Python modules required to run the script.
uv add --script cc3_info.py --python 3.11 requests pycountry python-dotenv
In the absence of specific versions, uv will assume you mean "the latest and anything greater" thus defining the "minimum" versions your script should use. You can be much more dictatorial and in fact you can lock your environment in a way not possible with pip and requirements.txt.
It is worth highlighting that one of the tools uv can replace is pyenv which helps you run different versions of Python. As with pyenv these versions of Python are managed by uv and are separate from your system Python thus avoiding conflicts.
Note:
If you want to actually get data back from the script, you will need to:
- get an API Key from Restful Countries API
- rename .env_sample to .env and add your key
OR
provide your key via the CLI using the -k option.
% uv run cc3_info.py -h
usage: cc3_info.py [-h] [-s] [-a] [-k API_KEY]
See the repository README for more details.
Now, lets take a look at a more realistic workflow.
Traditional Python Repository
Clone or Download the uv_repo repository, open a PowerShell (Windows) or terminal window (Linux/MacOS), and cd into the repository directory.
The uv_script repository was not initialized by uv but rather everything uv needed to execute was embedded in the Python script itself. That is good for an example (and to know that you can do this just at the file level) but lets look at the more common approach. This workflow works for both new repositories and existing repositories. We are going to take our uv_script repository and build it out using uv.
- Install uv
- Use uv to initialize the new (at the top level) or existing repository by executing uv init in the repository directory.
- Add dependencies using uv add
- Execute the cc3_info.py script using uv run
Other than Step 2, this is the same workflow we followed with the standalone script.
Step 1: Installing uv
Instructions from the Astral web site
Step 2: Initialize a new repository
In this example, I have started with a new repository, uv_repo. I am calling it a repository but it is just an empty directory at this stage.
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025/uv_repo
% tree
.
0 directories, 0 files
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025/uv_repo
% ls -al
total 8
drwxr-xr-x@ 4 claudiadeluna staff 128 Apr 21 08:58 .
drwxr-xr-x@ 24 claudiadeluna staff 768 Apr 21 05:17 ..
Initialize the Repository with uv init
.
Executing this step will:
- Initialize git thus putting your directory under revision control with git (replaces git init)
- Create a default .gitignore file
- Create an empty README.md file for you to update
- Create a generic pyproject.toml file (replaces/augments requirements.txt) (Note: for existing repositories you can actually build the dependenies using your existing requirements.txt file)
- Create a sample main.py for initial scaffolding
- Create a hidden .python-version which sets the default Python version
Directory after executing uv init
% uv init
Initialized project `uv-repo`
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025/uv_repo on main
% tree
.
├── README.md
├── main.py
└── pyproject.toml
1 directory, 3 files
The hidden files:
% ls -al
total 48
drwxr-xr-x@ 10 claudiadeluna staff 320 Apr 21 09:00 .
drwxr-xr-x@ 24 claudiadeluna staff 768 Apr 21 05:17 ..
-rw-r--r--@ 1 claudiadeluna staff 69 Apr 21 06:56 .env_sample
drwxr-xr-x@ 9 claudiadeluna staff 288 Apr 21 08:59 .git
-rw-r--r--@ 1 claudiadeluna staff 109 Apr 21 08:59 .gitignore
drwxr-xr-x@ 9 claudiadeluna staff 288 Apr 21 08:57 .idea
-rw-r--r--@ 1 claudiadeluna staff 5 Apr 21 08:59 .python-version
-rw-r--r--@ 1 claudiadeluna staff 745 Apr 21 09:00 README.md
-rw-r--r--@ 1 claudiadeluna staff 85 Apr 21 08:59 main.py
-rw-r--r--@ 1 claudiadeluna staff 153 Apr 21 08:59 pyproject.toml
The .python-version file contents:
% cat .python-version
3.11
At this point you can start your normal coding activities. Your repository is ready.
For this repository I copied the .env_sample and cc3_info.py files into the directory. I updated the README.md file and commited my changes as I normally would with git add and git commit.
Step3: Add dependencies
Dependencies need to be documented in the pyproject.toml file. As with the standalone script, this can be done manually by editing the file directly (the pyproject.toml file rather than the script itself) or via the uv add command.
Here is the default pyproject.toml created via the uv init command.
% cat pyproject.toml
[project]
name = "uv-repo"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
Lets add the same three dependencies we know our cc3_info.py script requires.
% uv add requests pycountry python-dotenv
Resolved 8 packages in 4ms
Prepared 2 packages in 1.13s
Installed 2 packages in 10ms
+ pycountry==24.6.1
+ python-dotenv==1.1.0
claudiadeluna in ~/Indigo Wire Networks/Claudia de Luna/scripts/python/2025/uv_repo on no-inline-metadata
Notice that the pyproject.toml file has been updated.
% cat pyproject.toml
[project]
name = "uv-repo"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"pycountry>=24.6.1",
"python-dotenv>=1.1.0",
"requests>=2.30.0",
]
Note:
Steps 2 and 3 walk you through how the repository was crated and updated. You don't need to execute these steps as they have already been completed and you have cloned or downloaded the end result.
Step 4: Execute the cc3_info.py script
We execute the script the same way we executed the standalone script with the uv run.
In this case our script does not have the inline metadata embedded within the Python script itself. That data is now in the pyproject.toml file.
% uv run cc3_info.py
Using CPython 3.12.9 interpreter at: /Users/claudiadeluna/.pyenv/versions/3.12.9/bin/python3.12
Creating virtual environment at: .venv
<script output>
One of the most important things to notice here is in line 3 which tells you that uv created the virtual environment as part of running the scrip!
Conclusion
Uv isn’t just great for package management—it also makes sharing and running scripts a lot easier.
If you have gotten this far (Thanks!) and some of these activities apply to you, then I urge you to continue your investment in learning about uv so you can add it to your network automation toolkit.