TL;DR: You can use uv
for everything now. Just brew install uv
and then you can forget about brew
, pyenv
, pipx
, pip
, and all the others.
Where we are today
The Python ecosystem has changed a lot over the past few years. What used to be best practices are quickly becoming anti-patterns. The biggest challenge I see with folks using Python today is that they are stuck in old patterns that cost them both time and pain.
The Outlawed Patterns List
If you are using any of these patterns, please stop immediately.
- Everything related to
pyenv
. - Calling
pip
directly, for any reason. - Calling
python
directly, and/or expectingpython
onPATH
to be a specific version. - Anything related to
venv
,virtualenv
, oractivate
, or manually creating or activating virtual environments in any way.
The Modern Way to Install Python
Note: You probably don't actually need to install Python before you start. In less than 2 seconds, the uv
tool (as you'll see below) can install Python versions on-demand for apps, projects, and scripts. So you can probably skip this step entirely. But if not:
# Install uv or update it if it's already installed:
brew install uv
# Show the versions of Python available and/or installed:
uv python list
# Install a couple Python versions
uv python install 3.13
uv python install 3.12
# Set your global python version (`python` on `PATH`)
uv python install 3.13 --global --preview
The Modern Way to Manage Virtual Environments
You should never need to manually create a virtual environment again. The manner in which you create your virtual environment will depend on whether you are running an app, writing code for a project, or writing a script. But for all of the below patterns, the virtual environment is created automatically, with no way to mess up, and no way to forget to activate or deactivate an environment.
Identify your use case from one of these three patterns, and apply the suggested pattern:
1. Installing a Python App
Simply uv tool install my-tool
and then you'll have my-tool
on your PATH.
2. Running a Python App
Skip the install step and use uvx
: uvx my-tool --version
This works from anywhere you have uv
installed.
You can optionally set the python version to something explicit and uv
will lightning-fast bootstrap that version of Python if it isn't already installed:
uvx --python=3.12 my-tool --version
You can also pin to a specific version of your tool or force the "latest" on each run:
uvx my-tool@latest --version
uvx my-tool@3.2.1 --version
3. Write Python Code for a Project
Simply use uv init
to create a new project directory, uv add
to add dependencies, and uv run
to run them. Unlike it's predecessor, Poetry, you don't even have to explicitly install anything, since uv run
implies uv sync
.
# Create a `repos` directory if you don't have one yet:
mkdir ~/repos
cd ~/repos
# Create the `uv` project scaffold:
uv init my-new-project
cd my-new-project
# Optionally set the Python version you want for this project:
uv python pin 3.13
# You can immediately run the sample without any extra steps
uv run main.py
# You can add dependencies (replaces `pip install`):
uv add my-other-dependency-a my-other-depedency-b
# Dependencies are auto-installed whenever you call `uv run`:
uv run main.py
Write a Portable Python Script
Sometimes you don't want a full project, or you need to have many scripts each with their own dependencies. This is easy to do with uv
.
Take this example my_helper_script.py
:
#!/usr/bin/env -S uv run --script
#
# Inline dependency declaration (PEP 723):
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "my-dependency-a",
# "my-dependency-b",
# ]
# ///
#
# Usage with uv CLI:
# uv run --script ./my_helper_script.py
#
# With the custom shebang, you can also invoke directly:
# ./my_helper_script.py
#
import my_dep_a
import my_dep_b
def main()
print("Hi, there!")
if __name__ == "__main__":
main()
Now you have a script that can run anywhere, on any version of Python (no Python install necessary), with your dependencies automatically bootstrapped and fully isolated from other Python environments and potential version conflicts. 🎉
What did I miss?
I'll update the article with any tips or tricks that others share in comments. Comment down below if I missed anything.
Top comments (0)