Starting Python quickly with uv

This article is written as an addition to Learn Python programming language in Y minutes.

It describes how to quickly install and start Python on Mac with uv Python package and project manager. Installations on Linux and Windows are not covered. They differ mostly in how uv is installed, which is described at docs.astral.sh/uv/getting-started/installation/.

Mac OS might have Python preinstalled already:

% which python
python not found
% which python3
/usr/bin/python3
% python3 -V
Python 3.9.6

Python 3.9 is an old version with security support ending in October 2025.

That particular version came with Xcode Command Line Tools:

% python3
Python 3.9.6 (default, Nov 11 2024, 03:15:38)
[Clang 16.0.0 (clang-1600.0.26.6)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, pprint
>>> pprint.pprint(sys.path)
['',
 '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python39.zip',
 '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9',
 '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/lib-dynload',
 '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site-packages']

It's better not to use OS Python installations, because system scripts may depend on particular versions of Python packages and can be easily broken by installation of the different package versions.

uv provides the simplest and the fastest way to have different Python installations at the moment. It can be installed with homebrew:

% brew install uv

There's also uv Python package available, which can be used in already existing Python installations.

Docker files can either use pre-installed uv Docker images or distroless Docker image (see docs.astral.sh/uv/guides/integration/docker/):

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

The latest Python version can be installed with:

% uv python install
Installed Python 3.13.2 in 1.47s
 + cpython-3.13.2-macos-aarch64-none

It is also possible to provide specific Python versions for installation:

uv python install 3.14
Installed Python 3.14.0a5 in 1.64s
 + cpython-3.14.0a5-macos-aarch64-none

Available and installed Python versions can be listed using:

% uv python list
cpython-3.14.0a5+freethreaded-macos-aarch64-none    <download available>
cpython-3.14.0a5-macos-aarch64-none                 .local/share/uv/python/cpython-3.14.0a5-macos-aarch64-none/bin/python3.14
cpython-3.13.2+freethreaded-macos-aarch64-none      <download available>
cpython-3.13.2-macos-aarch64-none                   .local/share/uv/python/cpython-3.13.2-macos-aarch64-none/bin/python3.13
cpython-3.12.9-macos-aarch64-none                   <download available>
cpython-3.11.11-macos-aarch64-none                  <download available>
cpython-3.10.16-macos-aarch64-none                  <download available>
cpython-3.9.21-macos-aarch64-none                   <download available>
cpython-3.9.6-macos-aarch64-none                    /Library/Developer/CommandLineTools/usr/bin/python3 -> ../../Library/Frameworks/Python3.framework/Versions/3.9/bin/python3
cpython-3.8.20-macos-aarch64-none                   <download available>
pypy-3.11.11-macos-aarch64-none                     <download available>
pypy-3.10.16-macos-aarch64-none                     <download available>
pypy-3.9.19-macos-aarch64-none                      <download available>
pypy-3.8.16-macos-aarch64-none                      <download available>

uv installs Python by default in .local/share/uv/python directory. It can be overridden with --install-dir option or UV_PYTHON_INSTALL_DIR environment variable.

Once Python interpreter is installed, it can be started with:

% uv run python
Python 3.13.2 (main, Feb 12 2025, 14:59:08) [Clang 19.1.6 ] on darwin

Python packages can be found at https://pypi.org/ and Python is bundled with Python package installer pip:

% uv run pip -V
pip 24.3.1 from /Users/user/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/site-packages/pip (python 3.13)

It installs packages in site-packages directory of the active Python installation.

Different project may need different versions of the packages. Isolation of project dependencies in Python is achieved through virtual environments.

They can be created using Python built-in venv package:

user@vm ~ % time uv run python -m venv pyvenv
uv run python -m venv pyvenv  1.13s user 0.18s system 97% cpu 1.336 total
# virtual environment can be activated with
user@vm ~ % source pyvenv/bin/activate
# notice the change of the shell prompt to venv name and python path
(pyvenv) user@vm ~ % which python
/Users/user/pyvenv/bin/python
# virtual environment site-packages are added to import search paths
(pyvenv) user@vm ~  % python -c 'import sys; from pprint import pprint; pprint(sys.path)'
['',
 '/Users/user/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python313.zip',
 '/Users/user/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13',
 '/Users/user/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/lib-dynload',
 '/Users/user/pyvenv/lib/python3.13/site-packages']
# deactivate virtual environment with
(pyvenv) user@vm ~  % deactivate

Built-in venv package is a subset of virtualenv package.

uv package manager has a built-in venv command for manual creation of virtual environments. It also provides a subset of virtualenv functionality, but is much faster than built-in venv or standalone virtualenv:

user@vm ~ % time uv venv uvvenv              
Using CPython 3.13.2
Creating virtual environment at: uvvenv
Activate with: source uvvenv/bin/activate
uv venv uvvenv  0.01s user 0.01s system 60% cpu 0.030 total

It took uv venv 0.030 seconds to create virtual environment (44 times faster) compared to 1.336 seconds by uv run python -m venv above!

There's also pip command in uv, providing subset of pip package functionality. However, there's a better way of setting up a Python project with virtual environment and isolated dependencies:

user@vm ~ % uv init myproj
Initialized project `myproj` at `/Users/user/myproj`
user@vm ~ % cd myproj 
# uv automatically creates pyproject.toml, readme and main module, intilises git repository including .gitignore file
user@vm myproj % ls -1a
.git
.gitignore
.python-version
README.md
main.py
pyproject.toml

Let's add all unstaged files and check the contents of them:

% git add .
% git diff --cached
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..505a3b1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+# Python-generated files
+__pycache__/
+*.py[oc]
+build/
+dist/
+wheels/
+*.egg-info
+
+# Virtual environments
+.venv
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000..24ee5b1
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+3.13
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..6618285
--- /dev/null
+++ b/main.py
@@ -0,0 +1,6 @@
+def main():
+    print("Hello from myproj!")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..7b5ee05
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,7 @@
+[project]
+name = "myproj"
+version = "0.1.0"
+description = "Add your description here"
+readme = "README.md"
+requires-python = ">=3.13"
+dependencies = []

Project dependencies can be added with uv add:

% uv add ipython ipdb pandas jupyter

Added dependencies are recorded in pyproject.toml, their versions are locked in uv.lock and installed in automatically created .venv virtual environment.

% git diff
diff --git a/pyproject.toml b/pyproject.toml
index 7b5ee05..8f47326 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,4 +4,9 @@ version = "0.1.0"
 description = "Add your description here"
 readme = "README.md"
 requires-python = ">=3.13"
-dependencies = []
+dependencies = [
+    "ipdb>=0.13.13",
+    "ipython>=9.0.2",
+    "jupyter>=1.1.1",
+    "pandas>=2.2.3",
+]

uv.lock is missing in git diff output above, because it's not to git yet.

% git add uv.lock pyproject.toml
% git commit -m 'myproj init'

ipython is a better interactive shell, which has a simpler introspection of objects, integration with shell and much more.

It can be started with:

% uv run ipython
In [1]: ? # follow the prompt and type in to see ipython help

# supports simple capturing of shell commands
In [2]: project_files = !ls -a

In [3]: project_files
Out[3]:
['.',
 '..',
 '.git',
 '.gitignore',
 '.python-version',
 '.venv',
 'README.md',
 'main.py',
 'pyproject.toml',
 'uv.lock']

In [4]: import this
The Zen of Python, by Tim Peters
...

# has handy introspection of any Python object and other handy features
In [5]: this?
Type:        module
String form: <module 'this' from '/Users/user/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/this.py'>
File:        ~/.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/this.py
Docstring:   <no docstring>

Jupyter notebook is another possibility to have interactive Python shell sessions, which can be persisted as documents with support of Markdown. It's popular in Data Science and Machine Learning.

Let's start jupyter lab server and create the first notebook:

% uv run jupyter lab

Once server is started, the browser is launched with Jupyter Lab UI, which allows to create Python notebook or console (interactive shell), terminal or files (text, markdown or Python).

Python Notebooks are just JSON files. They can be rendered in Github (e.g. https://github.com/jupyter-naas/awesome-notebooks/blob/master/generate_readme.ipynb) or edited with Visual Studio Code.

It is also possible to quickly launch commands provided by Python packages without creating the project by using uvx alias for uv tool run command:

% uvx ruff format

Command above would run ruff formatter in the current directory.

See uv tools guide discussing using tools in more details.

It is worth to mention, that uv is still new. Existing Python projects may use different tooling for management of Python versions and packages, for example pyenv and poetry. New projects is easier and faster to start with uv.

links

social