How to use picamera2 and GPIO with uv on Raspberry Pi
picamera2, libcamera, and gpiozero ship through apt on Raspberry Pi OS, not through PyPI. A clean uv venv cannot import them, and pip install picamera2 inside that venv fails on the missing libcamera module. The workaround is to install the system packages with apt, then build a uv venv against /usr/bin/python3 that inherits the system site-packages. This guide walks through that setup and the constraints it brings.
It assumes uv is already installed on the Pi. If not, start with How to run Python scripts on a Raspberry Pi with uv.
Install the apt packages
Install the Pi-specific bindings through the system package manager:
sudo apt update
sudo apt install -y python3-picamera2 python3-libcamera python3-gpiozeroThese packages register themselves under /usr/lib/python3/dist-packages/, which is only visible to /usr/bin/python3 and to venvs that explicitly opt in.
Create a uv venv that sees the apt packages
In your project directory, point uv at the system Python and pass --system-site-packages:
uv venv --python /usr/bin/python3 --system-site-packagesThen install pip-installable dependencies into the same venv:
uv pip install adafruit-circuitpython-dhtThe venv now has both stacks. Confirm:
uv run python -c "from picamera2 import Picamera2; print(Picamera2.global_camera_info())"The command prints the connected camera’s info, importing both the apt-installed picamera2 and any pip-installed dependencies from the same interpreter.
Constraints to plan around
A few things behave differently with this setup:
uv initanduv addignore apt packages. They resolve againstpyproject.tomland don’t know aboutpython3-picamera2. Add an explicitimport picamera2check at the top of your script so a missing apt package fails loudly.uv syncwon’t reinstall the apt packages on another Pi. Document thesudo apt installstep in your project’s README, or wrap it in a smallsetup.sh.uv python installcan’t manage the Pi-bound Python. Thepicamera2package binds to/usr/bin/python3specifically; staying on system Python is required for projects that need it.- Newer Python versions break this path. If your project needs a Python newer than the one Raspberry Pi OS ships, the apt + system-site-packages approach won’t work. Either downgrade to the system Python or accept that the project can’t use the apt-only libraries.
Run as a systemd service on boot
systemd needs an absolute path to the interpreter. For a project venv, point ExecStart directly at the venv’s Python:
[Unit]
Description=Camera logger
After=network.target
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/camera-logger
ExecStart=/home/pi/camera-logger/.venv/bin/python main.py
Restart=on-failure
[Install]
WantedBy=multi-user.target/home/pi/camera-logger/.venv/bin/python resolves through the system-site-packages venv, so it sees picamera2 and any pip-installed deps. Keep User=pi matched to the user that ran uv venv; ~/.cache/uv and ~/.local/share/uv need to be readable by the service user.
For a single-file script that uses inline metadata, set ExecStart=/home/pi/.local/bin/uv run /home/pi/script.py. The inline-metadata path doesn’t combine with --system-site-packages, though, so picamera2 / GPIO projects should use a venv-based project rather than an inline-metadata script.
Learn More
- How to run Python scripts on a Raspberry Pi with uv covers the install and the inline-metadata / project flows.
- How to fix the externally-managed-environment error explains why pip can’t install into the system Python on Bookworm.
- picamera2 manual from Raspberry Pi.
- gpiozero documentation.
uv venv --system-site-packagesreference in the uv docs.