Running Python scripts with uv

Python
scripts
automation
uv
An introduction to running Python scripts with the uv library, what problems it solves, and how to use it for self-contained scripts, massively simplifying the process of running your scripts.

In this tutorial, we are going to migrate from the process of running Python scripts using the command line tool python (or python3) to running them with uv. It is assumed that you are familiar with Python environments, requirements, and running scripts in general.

What is uv?

Many things actually, it’s a fairly large library concerned with making managing and working Python a streamlined process. We will only focus on one thing in this tutorial which is running scripts.

Why use uv instead of regular Python?

Traditionally, in order to run a Python script you need the following:

  • A Python installation on your machine
  • A virtual environment for that installation (highly recommended though not required)
  • A set of third party libraries installed in the environment (pinned to certain versions), and typically in a requirements.txt file
  • Activating the environment

When all this is available, you can now run:

python myscript.py

How is running scripts with uv different?

What you need is the same script, but with the requirements declared at the top, something like this:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "advertools",
# ]
# ///

if __name__ == "__main__":
    print("Hello, world!")

That’s it.

Now you can run:

uv run myscript.py
Reading inline script metadata from `hello.py`
hello, world!

As you can see, we aren’t handling or managing Python or the libraries. We are simply declaring them at the top of the file, and once run with uv, it will handle all the required details for us. Using this script and it metadata at the top, uv does the following:

  • Create a virtual environment using the declared Python version (3.13 in this case)
  • Install (or get from cache) the packages listed under dependencies
  • Within this fully functional and active environment, it runs the Python code

Here is a more complete example right from the beginning.

A complete example of building and running a Python script with uv

We start by installing uv.

  • Install uv

Installation is fairly easy, and quick, as with everything uv:

For Windows:

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

For Linux/MacOS:

curl -LsSf https://astral.sh/uv/install.sh | sh

Once you install the script, you will need to restart your shell in order to activate the uv command (or source the shell config file).

  • Initialize an empty script

The commented parts declaring dependencies at the beginning might seem a little daunting to create (and the syntax is quite strict), but uv has tools to help us create, manage, update, and of course run this script.

Let’s start by creating an empty script:

Note

Note that if you run this command without the --script flag, uv will create a project (a pyproject.toml file, initialize a git repo, and a few other things), so make sure you set this option

uv init --script hello.py
Initialized script at `hello.py`

We get a message that confirms that the script was created. We can now take a look at its contents:

cat hello.py

# /// script
# requires-python = ">=3.12"
# dependencies = []
# ///


def main() -> None:
    print("Hello from hello.py!")


if __name__ == "__main__":
    main()

As you can see we have all the requirements section created for us. It’s a good practice not to edit this by hand and run it with uv, because one missed space might cause the whole thing to break.

We can see that it created a main function, so we can now try running the script in its current form:

uv run hello.py
Reading inline script metadata from `hello.py`
Hello from hello.py!

Note that traditionally we would run this with python hello.py, but now we are running everything with uv.

  • Add library dependencies

    • Python: By default we got requires-python = ">=3.12", which we can change:
    uv init --script hello.py --python 3.13
    We can also change the Python version when running the script: bash uv run --script hello.py --python 3.12
    • Third party libraries: We might also want to add libraries to our dependencies list:
    uv add --script hello.py advertools plotly
    Updated `hello.py`
    You can also set specific versions if you want just like you would with pip, for example:
uv add --script hello.py "advertools>=0.16.4"

Let’s take a look at contents of our script:

cat hello.py

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "advertools",
#     "plotly",
# ]
# ///


def main() -> None:
    print("Hello from hello.py!")


if __name__ == "__main__":
    main()

Our dependencies list was updated as you can see.

Now we can write something a bit more useful.

  • Write the Python code

Here is a simple script that takes the URL of a robots.txt URL, downloads the file, converts it to a DataFrame, and prints it to the console:

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "advertools",
#     "plotly",
# ]
# ///

import sys

import advertools as adv
import pandas as pd
pd.options.display.max_columns = None


if __name__ == "__main__":
    robots_url = sys.argv[1]
    robots_df = adv.robotstxt_to_df(robots_url)
    print(robots_df)
  • Run the script

uv run hello.py https://brightonseo.com/robots.txt
Reading inline script metadata from `hello.py`
2024-12-22 23:59:20,181 | INFO | robotstxt.py:394 | robotstxt_to_df | Getting: https://brightonseo.com/robots.txt
    directive                              content  \
0  User-Agent                                    *   
1       Allow                                    /   
2    Disallow                            /private/   
3     Sitemap  https://brightonseo.com/sitemap.xml   

                                 etag                       robotstxt_url  \
0  "5a38b7feaa7fad84c24093fb04aaaf6b"  https://brightonseo.com/robots.txt   
1  "5a38b7feaa7fad84c24093fb04aaaf6b"  https://brightonseo.com/robots.txt   
2  "5a38b7feaa7fad84c24093fb04aaaf6b"  https://brightonseo.com/robots.txt   
3  "5a38b7feaa7fad84c24093fb04aaaf6b"  https://brightonseo.com/robots.txt   

                     download_date  
0 2024-12-22 23:59:20.329679+00:00  
1 2024-12-22 23:59:20.329679+00:00  
2 2024-12-22 23:59:20.329679+00:00  
3 2024-12-22 23:59:20.329679+00:00

Running Python scripts remotely

A very interesting feature is that you can run scripts that are hosted online using http(s). This makes it even easier to distribute your scripts. You can host them on your server, or on some hosting/SCM service like GitHub for example and ask your users to run the script remotely. One advantage is that they would get the latest version of the script which would have fewer bugs and/or better features:

uv run https://example.com/my_script.py ARG1 ARG2 ...

Conclusion

We went through the process of installing uv, and then using it to create a script, change/edit its dependencies (Python as well as third party libraries), we then wrote Python code that does something practical, and now we can repeat the process as many times as we want.

We didn’t have to install Python, create a virtual environment, install dependencies, or even activate the virtual environment, not mention resolving the dependencies that we declared. All this was handled by uv, making our life much easier, and allowing us to focus more on the Python code than the environment in which we are running it.