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 sharing 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.
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.
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/uv_script on main
% tree
.
├── README.md
└── cc3_info.py
1 directory, 2 files
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 3rd party Python module dependencies but notice it is missing a requirements.txt file (and any other kind of dependency requirements or management file like project.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
- 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)
Bottom line, 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".
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.
# /// 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. This is the command I used to have uv embed the version of python I wanted along with the three 3rd party 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 which is nice.
It is also worth noting that this standalone idea is not very scalable, so lets look at a more common use case.
In either case, 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]
Traditional Python Repository
Clone or Download the uv_script 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.
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)
- Creates a default .gitignore file
- Creates and empty README.md file for you to update
- Creates 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)
- Creates a sample main.py for quick tests
- Creates 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 Dropbox/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 should copy the .env_sample and cc3_info.py script into the directory.
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 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",
]
Step 4: Execute the cc3_info.py script
We execute the script in the repo the same way we executed the standalone 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.